From ac99413d45b8a02b22c8b1e510eb9cdbe9804a54 Mon Sep 17 00:00:00 2001 From: patchzyy <64382339+patchzyy@users.noreply.github.com> Date: Fri, 23 Oct 2026 18:00:55 +0200 Subject: [PATCH] v0.9.0 (v1.0 beta) (#338) * move aurora to the aurora-wiicompiled submodule (#315) * Update settings_overlay.cpp (#257) * Simplify controller settings menu (#317) * simplify controller settings menu * platform pairing hint * build for x86-64-v2 on older linux cpus (#319) * Real Wii Remote support over Bluetooth (#323) * pass real wii remotes through emulated bluetooth * build bluetooth tests on macos ci * address review comments * cancel replaced bluetooth reads * Run GX on its own thread (#325) * NTSC-U and NTSC-J support (#326) * add ntsc-u and ntsc-j support Co-authored-by: DarthMDev Co-authored-by: rooklz * hash inc files and require project for shards * port remaining stale rr us hooks * drop map report generation * drop one-off region porters --------- Co-authored-by: DarthMDev Co-authored-by: rooklz * Keyboard input for friend code entry (#327) * keyboard input for friend code entry * add new guest imports to synthetic test * replace per-address region table with range map (#328) * paste friend codes from clipboard (#329) * Verify dependency archive hashes (#330) * verify dependency archive hashes * verify cached cppwinrt tool * check dependency path types * Check CPU support before building (#331) * check cpu support before building * build for x86-64-v2 on windows and intel macs * bump aurora for fog fsel fix * add vsync option (#333) * Add exe icons (#334) * add exe icons * rebuild icon resource on ico change * drop icon rebuild tracking * Fix bugs found in forks (#336) * port fixes found in forks * fill whole disk id * dump kamek overlay on crash (#335) * bump aurora and version to 0.9.0 --------- Co-authored-by: DarthMDev Co-authored-by: rooklz --- .gitattributes | 6 + .github/workflows/build.yml | 2 + .github/workflows/package.yml | 4 + .github/workflows/recomp-test.yml | 1 + .gitignore | 3 +- .gitmodules | 4 + Launcher/Build-Installer.ps1 | 46 +- Launcher/Directory.Build.props | 2 +- Launcher/LocalBuild.ps1 | 36 +- Launcher/NativeBuildFlags.ps1 | 41 +- Launcher/Prepare-Dependencies.ps1 | 110 +- Launcher/Prepare-NativePrebuilt.sh | 2 +- Launcher/Test-PinnedFacts.ps1 | 65 +- Launcher/Test-Recompilation.ps1 | 40 +- .../HostCpuRequirement.cs | 99 + .../RetroWfcPayload.cs | 74 +- Launcher/WiiCompiled.Setup.Linux/DiscTool.cs | 47 +- Launcher/WiiCompiled.Setup.Linux/Program.cs | 16 +- .../ProjectManifest.cs | 19 +- .../ConsoleCommands.cs | 4 +- .../InputValidation.cs | 38 +- .../WiiCompiled.Setup.Windows/Installation.cs | 26 +- .../InstallerEngine.cs | 102 +- .../LocalBuildService.cs | 11 +- Launcher/WiiCompiled.Setup.Windows/Models.cs | 15 +- .../PayloadArchive.cs | 39 +- .../ProductRepairService.cs | 27 +- Launcher/WiiCompiled.Setup.Windows/Program.cs | 2 + .../WiiCompiled.Setup.Windows/SelfTests.cs | 309 +- .../ToolkitFingerprint.cs | 12 +- Launcher/build-appimage.sh | 2 + Launcher/build-cache.sh | 67 +- Launcher/local-build-macos.command | 31 +- Launcher/local-build.sh | 40 +- Launcher/macos/build-setup-pkg.command | 4 + Launcher/macos/extract-disc.command | 39 +- Launcher/macos/setup.command | 49 +- aurora-main | 1 + aurora-main/.clang-format | 29 - aurora-main/.gitignore | 10 - aurora-main/CMakeLists.txt | 93 - aurora-main/LICENSE | 21 - aurora-main/README.md | 46 - aurora-main/assets/aurora.png | Bin 19227 -> 0 bytes aurora-main/cmake/AuroraCopyRuntimeDLLs.cmake | 57 - aurora-main/cmake/AuroraDawnProvider.cmake | 280 - aurora-main/cmake/AuroraLibUSB.cmake | 43 - aurora-main/cmake/AuroraNodProvider.cmake | 150 - aurora-main/cmake/AuroraSDL3Patches.cmake | 388 - aurora-main/cmake/AuroraSDL3Provider.cmake | 164 - aurora-main/cmake/aurora_card.cmake | 17 - aurora-main/cmake/aurora_core.cmake | 77 - aurora-main/cmake/aurora_dvd.cmake | 10 - aurora-main/cmake/aurora_gd.cmake | 16 - aurora-main/cmake/aurora_gx.cmake | 47 - aurora-main/cmake/aurora_main.cmake | 6 - aurora-main/cmake/aurora_ms.cmake | 7 - aurora-main/cmake/aurora_mtx.cmake | 12 - aurora-main/cmake/aurora_os.cmake | 14 - aurora-main/cmake/aurora_pad.cmake | 7 - aurora-main/cmake/aurora_si.cmake | 7 - aurora-main/cmake/aurora_vi.cmake | 7 - aurora-main/cmake/libusb/config.h | 8 - aurora-main/docs/building.md | 55 - aurora-main/examples/CMakeLists.txt | 4 - aurora-main/examples/simple.c | 90 - aurora-main/extern/CMakeLists.txt | 360 - aurora-main/include/aurora/aurora.h | 195 - aurora-main/include/aurora/dvd.h | 27 - aurora-main/include/aurora/event.h | 44 - aurora-main/include/aurora/gfx.h | 97 - aurora-main/include/aurora/imgui.h | 20 - aurora-main/include/aurora/imgui_config.h | 13 - aurora-main/include/aurora/main.h | 16 - aurora-main/include/aurora/math.hpp | 254 - .../include/aurora/render_size_limits.hpp | 81 - aurora-main/include/dolphin/ai.h | 50 - aurora-main/include/dolphin/ar.h | 79 - aurora-main/include/dolphin/base/PPCArch.h | 542 - aurora-main/include/dolphin/card.h | 340 - aurora-main/include/dolphin/db.h | 22 - aurora-main/include/dolphin/db/DBInterface.h | 31 - aurora-main/include/dolphin/dolphin.h | 24 - aurora-main/include/dolphin/dsp.h | 57 - aurora-main/include/dolphin/dtk.h | 56 - aurora-main/include/dolphin/dvd.h | 237 - aurora-main/include/dolphin/exi.h | 103 - aurora-main/include/dolphin/gd.h | 15 - aurora-main/include/dolphin/gd/GDAurora.h | 22 - aurora-main/include/dolphin/gd/GDBase.h | 177 - aurora-main/include/dolphin/gd/GDFile.h | 31 - aurora-main/include/dolphin/gd/GDGeometry.h | 525 - aurora-main/include/dolphin/gd/GDIndirect.h | 91 - aurora-main/include/dolphin/gd/GDLight.h | 65 - aurora-main/include/dolphin/gd/GDPixel.h | 95 - aurora-main/include/dolphin/gd/GDTev.h | 133 - aurora-main/include/dolphin/gd/GDTexture.h | 127 - aurora-main/include/dolphin/gd/GDTransform.h | 56 - aurora-main/include/dolphin/gf.h | 9 - aurora-main/include/dolphin/gf/GFGeometry.h | 41 - aurora-main/include/dolphin/gf/GFLight.h | 8 - aurora-main/include/dolphin/gf/GFPixel.h | 13 - aurora-main/include/dolphin/gf/GFTev.h | 8 - aurora-main/include/dolphin/gx.h | 34 - aurora-main/include/dolphin/gx/GXAurora.h | 149 - aurora-main/include/dolphin/gx/GXBump.h | 32 - .../include/dolphin/gx/GXCommandList.h | 41 - aurora-main/include/dolphin/gx/GXCpu2Efb.h | 22 - aurora-main/include/dolphin/gx/GXCull.h | 18 - aurora-main/include/dolphin/gx/GXDispList.h | 25 - aurora-main/include/dolphin/gx/GXDraw.h | 24 - aurora-main/include/dolphin/gx/GXEnum.h | 915 - aurora-main/include/dolphin/gx/GXExtra.h | 30 - aurora-main/include/dolphin/gx/GXFifo.h | 37 - .../include/dolphin/gx/GXFrameBuffer.h | 60 - aurora-main/include/dolphin/gx/GXGeometry.h | 43 - aurora-main/include/dolphin/gx/GXGet.h | 40 - aurora-main/include/dolphin/gx/GXLighting.h | 32 - aurora-main/include/dolphin/gx/GXManage.h | 28 - aurora-main/include/dolphin/gx/GXPerf.h | 16 - aurora-main/include/dolphin/gx/GXPixel.h | 28 - aurora-main/include/dolphin/gx/GXStruct.h | 120 - aurora-main/include/dolphin/gx/GXTev.h | 35 - aurora-main/include/dolphin/gx/GXTexture.h | 49 - aurora-main/include/dolphin/gx/GXTransform.h | 37 - aurora-main/include/dolphin/gx/GXVert.h | 150 - aurora-main/include/dolphin/hio.h | 28 - aurora-main/include/dolphin/hio2.h | 45 - aurora-main/include/dolphin/hw_regs.h | 116 - aurora-main/include/dolphin/ms.h | 35 - aurora-main/include/dolphin/mtx.h | 385 - aurora-main/include/dolphin/mtx/GeoTypes.h | 40 - aurora-main/include/dolphin/mtx/mtx44ext.h | 106 - aurora-main/include/dolphin/os.h | 311 - aurora-main/include/dolphin/os/OSAlarm.h | 36 - aurora-main/include/dolphin/os/OSAlloc.h | 34 - aurora-main/include/dolphin/os/OSCache.h | 38 - aurora-main/include/dolphin/os/OSContext.h | 177 - aurora-main/include/dolphin/os/OSDC.h | 23 - aurora-main/include/dolphin/os/OSError.h | 39 - aurora-main/include/dolphin/os/OSException.h | 61 - aurora-main/include/dolphin/os/OSExec.h | 35 - aurora-main/include/dolphin/os/OSFastCast.h | 40 - aurora-main/include/dolphin/os/OSFont.h | 58 - aurora-main/include/dolphin/os/OSIC.h | 20 - aurora-main/include/dolphin/os/OSInterrupt.h | 119 - aurora-main/include/dolphin/os/OSL2.h | 20 - aurora-main/include/dolphin/os/OSLC.h | 19 - aurora-main/include/dolphin/os/OSMemory.h | 28 - aurora-main/include/dolphin/os/OSMessage.h | 33 - aurora-main/include/dolphin/os/OSModule.h | 117 - aurora-main/include/dolphin/os/OSMutex.h | 33 - aurora-main/include/dolphin/os/OSReboot.h | 19 - aurora-main/include/dolphin/os/OSReset.h | 44 - aurora-main/include/dolphin/os/OSResetSW.h | 20 - aurora-main/include/dolphin/os/OSRtc.h | 84 - aurora-main/include/dolphin/os/OSSemaphore.h | 25 - aurora-main/include/dolphin/os/OSSerial.h | 6 - aurora-main/include/dolphin/os/OSThread.h | 113 - aurora-main/include/dolphin/os/OSTime.h | 49 - aurora-main/include/dolphin/os/OSTimer.h | 21 - aurora-main/include/dolphin/os/OSUtf.h | 23 - aurora-main/include/dolphin/pad.h | 316 - aurora-main/include/dolphin/perf.h | 99 - aurora-main/include/dolphin/ppc_math.h | 136 - aurora-main/include/dolphin/si.h | 72 - aurora-main/include/dolphin/thp.h | 154 - aurora-main/include/dolphin/types.h | 110 - aurora-main/include/dolphin/vi.h | 66 - aurora-main/include/magic_enum.hpp | 1135 - aurora-main/lib/aurora.cpp | 2105 -- aurora-main/lib/card/BlockAllocationTable.cpp | 106 - aurora-main/lib/card/BlockAllocationTable.hpp | 39 - aurora-main/lib/card/CardGciFolder.cpp | 431 - aurora-main/lib/card/CardGciFolder.hpp | 77 - aurora-main/lib/card/CardRawFile.cpp | 817 - aurora-main/lib/card/CardRawFile.hpp | 438 - aurora-main/lib/card/CommonData.h | 59 - aurora-main/lib/card/Constants.hpp | 109 - aurora-main/lib/card/Directory.cpp | 142 - aurora-main/lib/card/Directory.hpp | 45 - aurora-main/lib/card/DolphinCardPath.cpp | 118 - aurora-main/lib/card/DolphinCardPath.hpp | 9 - aurora-main/lib/card/File.cpp | 28 - aurora-main/lib/card/File.hpp | 48 - aurora-main/lib/card/FileIO.cpp | 124 - aurora-main/lib/card/FileIO.hpp | 35 - aurora-main/lib/card/ICard.hpp | 45 - aurora-main/lib/card/SRAM.cpp | 29 - aurora-main/lib/card/SRAM.hpp | 73 - aurora-main/lib/card/Util.cpp | 41 - aurora-main/lib/card/Util.hpp | 74 - aurora-main/lib/dawn/BackendBinding.cpp | 46 - aurora-main/lib/dawn/BackendBinding.hpp | 12 - aurora-main/lib/dawn/MetalBinding.mm | 44 - aurora-main/lib/dolphin/AR.cpp | 115 - aurora-main/lib/dolphin/card.cpp | 742 - aurora-main/lib/dolphin/dvd/dvd.cpp | 1100 - aurora-main/lib/dolphin/gd/GDAurora.cpp | 32 - aurora-main/lib/dolphin/gd/GDBase.cpp | 46 - aurora-main/lib/dolphin/gd/GDGeometry.cpp | 435 - aurora-main/lib/dolphin/gd/GDIndirect.cpp | 270 - aurora-main/lib/dolphin/gd/GDLight.cpp | 216 - aurora-main/lib/dolphin/gd/GDPixel.cpp | 118 - aurora-main/lib/dolphin/gd/GDTev.cpp | 159 - aurora-main/lib/dolphin/gd/GDTexture.cpp | 104 - aurora-main/lib/dolphin/gd/GDTransform.cpp | 127 - aurora-main/lib/dolphin/gd/gd.hpp | 5 - aurora-main/lib/dolphin/gx/GXAurora.cpp | 176 - aurora-main/lib/dolphin/gx/GXBump.cpp | 213 - aurora-main/lib/dolphin/gx/GXCpu2Efb.cpp | 20 - aurora-main/lib/dolphin/gx/GXCull.cpp | 60 - aurora-main/lib/dolphin/gx/GXDispList.cpp | 89 - aurora-main/lib/dolphin/gx/GXDraw.cpp | 549 - aurora-main/lib/dolphin/gx/GXExtra.cpp | 27 - aurora-main/lib/dolphin/gx/GXFifo.cpp | 50 - aurora-main/lib/dolphin/gx/GXFrameBuffer.cpp | 595 - aurora-main/lib/dolphin/gx/GXGeometry.cpp | 455 - aurora-main/lib/dolphin/gx/GXGet.cpp | 337 - aurora-main/lib/dolphin/gx/GXLighting.cpp | 291 - aurora-main/lib/dolphin/gx/GXManage.cpp | 502 - aurora-main/lib/dolphin/gx/GXPixel.cpp | 247 - aurora-main/lib/dolphin/gx/GXTev.cpp | 267 - aurora-main/lib/dolphin/gx/GXTexture.cpp | 484 - aurora-main/lib/dolphin/gx/GXTransform.cpp | 216 - aurora-main/lib/dolphin/gx/GXVert.cpp | 733 - aurora-main/lib/dolphin/gx/__gx.h | 179 - aurora-main/lib/dolphin/gx/gx.hpp | 10 - aurora-main/lib/dolphin/ms/mouse.cpp | 33 - aurora-main/lib/dolphin/mtx/mtx.c | 618 - aurora-main/lib/dolphin/mtx/mtx44.c | 34 - aurora-main/lib/dolphin/mtx/mtxstack.c | 108 - aurora-main/lib/dolphin/mtx/mtxvec.c | 95 - aurora-main/lib/dolphin/mtx/quat.c | 313 - aurora-main/lib/dolphin/mtx/vec.c | 191 - aurora-main/lib/dolphin/os/OSAddress.cpp | 41 - aurora-main/lib/dolphin/os/OSAlloc.cpp | 564 - aurora-main/lib/dolphin/os/OSArena.cpp | 58 - aurora-main/lib/dolphin/os/OSBootInfo.cpp | 12 - aurora-main/lib/dolphin/os/OSInit.cpp | 18 - aurora-main/lib/dolphin/os/OSMemory.cpp | 148 - aurora-main/lib/dolphin/os/OSTime.cpp | 178 - aurora-main/lib/dolphin/os/internal.hpp | 16 - aurora-main/lib/dolphin/pad/pad.cpp | 1860 - aurora-main/lib/dolphin/si/si.cpp | 20 - aurora-main/lib/dolphin/vi/vi.cpp | 111 - aurora-main/lib/dolphin/vi/vi_internal.hpp | 14 - aurora-main/lib/fs_helper.hpp | 19 - aurora-main/lib/gfx/clear.cpp | 162 - aurora-main/lib/gfx/clear.hpp | 31 - aurora-main/lib/gfx/common.cpp | 1770 - aurora-main/lib/gfx/common.hpp | 422 - aurora-main/lib/gfx/dds_io.cpp | 256 - aurora-main/lib/gfx/dds_io.hpp | 17 - aurora-main/lib/gfx/depth_peek.cpp | 475 - aurora-main/lib/gfx/depth_peek.hpp | 34 - aurora-main/lib/gfx/efb_ram_copy.cpp | 493 - aurora-main/lib/gfx/efb_ram_copy.hpp | 28 - aurora-main/lib/gfx/efb_ram_encoder.cpp | 211 - aurora-main/lib/gfx/efb_ram_encoder.hpp | 24 - aurora-main/lib/gfx/pipeline_cache.cpp | 1304 - aurora-main/lib/gfx/pipeline_cache.hpp | 36 - aurora-main/lib/gfx/png_io.cpp | 102 - aurora-main/lib/gfx/png_io.hpp | 10 - aurora-main/lib/gfx/staging_capacity.hpp | 33 - aurora-main/lib/gfx/staging_map.hpp | 61 - aurora-main/lib/gfx/tex_copy_conv.cpp | 616 - aurora-main/lib/gfx/tex_copy_conv.hpp | 30 - .../lib/gfx/tex_copy_format_contract.hpp | 23 - aurora-main/lib/gfx/tex_palette_conv.cpp | 260 - aurora-main/lib/gfx/tex_palette_conv.hpp | 24 - aurora-main/lib/gfx/texture.cpp | 303 - aurora-main/lib/gfx/texture.hpp | 147 - aurora-main/lib/gfx/texture_convert.cpp | 726 - aurora-main/lib/gfx/texture_convert.hpp | 34 - aurora-main/lib/gfx/texture_replacement.cpp | 800 - aurora-main/lib/gfx/texture_replacement.hpp | 13 - aurora-main/lib/gx/command_processor.cpp | 2515 -- aurora-main/lib/gx/command_processor.hpp | 18 - aurora-main/lib/gx/fifo.cpp | 110 - aurora-main/lib/gx/fifo.hpp | 93 - aurora-main/lib/gx/frame_interpolation.cpp | 1536 - aurora-main/lib/gx/frame_interpolation.hpp | 89 - aurora-main/lib/gx/gx.cpp | 2158 -- aurora-main/lib/gx/gx.hpp | 776 - aurora-main/lib/gx/gx_fmt.hpp | 952 - aurora-main/lib/gx/pipeline.cpp | 96 - aurora-main/lib/gx/pipeline.hpp | 80 - aurora-main/lib/gx/shader.cpp | 2109 -- aurora-main/lib/gx/shader_info.cpp | 746 - aurora-main/lib/gx/shader_info.hpp | 19 - .../lib/gx/texture_bind_group_cache_key.hpp | 31 - aurora-main/lib/imgui.cpp | 266 - aurora-main/lib/imgui.hpp | 23 - aurora-main/lib/imgui_config.cpp | 61 - aurora-main/lib/input.cpp | 622 - aurora-main/lib/input.hpp | 76 - aurora-main/lib/internal.hpp | 200 - aurora-main/lib/logging.cpp | 78 - aurora-main/lib/logging.hpp | 68 - aurora-main/lib/main.cpp | 6 - aurora-main/lib/sqlite_utils.hpp | 77 - aurora-main/lib/system_info.cpp | 368 - aurora-main/lib/system_info.hpp | 13 - aurora-main/lib/system_info_mac.mm | 10 - aurora-main/lib/webgpu/gpu.cpp | 987 - aurora-main/lib/webgpu/gpu.hpp | 100 - aurora-main/lib/webgpu/gpu_cache.cpp | 452 - aurora-main/lib/webgpu/metalfx.hpp | 41 - aurora-main/lib/webgpu/metalfx.mm | 326 - aurora-main/lib/webgpu/metalfx_stub.cpp | 11 - aurora-main/lib/webgpu/wgpu.hpp | 14 - aurora-main/lib/window.cpp | 844 - aurora-main/lib/window.hpp | 65 - aurora-main/tests/CMakeLists.txt | 108 - aurora-main/tests/gpu_readback_test.cpp | 363 - aurora-main/tests/gx_fifo_test.cpp | 5029 --- aurora-main/tests/gx_test_common.hpp | 99 - aurora-main/tests/gx_test_stubs.cpp | 585 - .../tests/metalfx_interop/CMakeLists.txt | 28 - aurora-main/tests/metalfx_interop/README.md | 124 - aurora-main/tests/metalfx_interop/main.mm | 269 - .../metalfx_interop/presentation_test.cpp | 124 - .../tests/metalfx_interop/stub_test.cpp | 9 - aurora-main/tests/os_alloc_test.cpp | 106 - aurora-main/tests/os_test_globals.cpp | 5 - .../tests/renderer_regression_test.cpp | 199 - aurora-main/tests/test_dvd.cpp | 288 - .../texture_bind_group_cache_key_test.cpp | 44 - projects/mkwii-ntsc-j/MAP.txt | 29432 ++++++++++++++++ projects/mkwii-ntsc-j/data_addresses.txt | 150 + projects/mkwii-ntsc-j/recomp.yml | 72 + projects/mkwii-ntsc-j/region_port.json | 591 + projects/mkwii-ntsc-u/MAP.txt | 29412 +++++++++++++++ projects/mkwii-ntsc-u/data_addresses.txt | 243 + projects/mkwii-ntsc-u/recomp.yml | 72 + projects/mkwii-ntsc-u/region_port.json | 1826 + runtime/CMakeLists.txt | 27 +- .../assets/pipeline/initial_pipeline_cache.db | Bin 3866624 -> 4567040 bytes runtime/cmake/PlatformTests.cmake | 10 + runtime/cmake/PublicProducts.cmake | 25 +- runtime/cmake/RuntimeLibrary.cmake | 4 +- runtime/game/guest_region.cpp | 9 + runtime/include/abi_bridge.h | 12 +- runtime/include/aurora_events.h | 31 + runtime/include/bluetooth/bt_bytes.h | 19 + runtime/include/bluetooth/bt_controller.h | 153 + runtime/include/bluetooth/bt_remote_link.h | 107 + runtime/include/bluetooth/bt_sdp.h | 19 + runtime/include/friend_code_keyboard.h | 8 + runtime/include/guest_abi/abi_version.h | 2 +- runtime/include/guest_abi/dispatch.h | 13 +- runtime/include/guest_abi/guest_region.h | 166 + runtime/include/guest_abi/guest_versions.inc | 416 + .../include/guest_abi/native_cpu_calls.inc | 80 +- runtime/include/guest_function_imports.h | 21 + runtime/include/gx_worker.h | 114 + runtime/include/hle/bluetooth_hle.h | 22 + .../include/hle/controller_status_contract.h | 39 - runtime/include/hle/hollywood_gpio.h | 10 + runtime/include/hle_stubs.h | 6 +- runtime/include/nand_path.h | 5 +- runtime/include/nand_settings.h | 33 +- runtime/include/runtime_config.h | 162 +- runtime/include/system_bridge.h | 3 +- runtime/include/wii_remote_input.h | 111 - runtime/include/wiimote_ext_crypto.h | 24 + runtime/include/wiimote_extension.h | 40 + runtime/include/wiimote_host.h | 52 + runtime/include/wiimote_platform.h | 43 + runtime/resources/RetroRewind.ico | Bin 0 -> 51368 bytes runtime/resources/RetroRewind.rc | 1 + runtime/resources/WiiCompiled.ico | Bin 0 -> 110751 bytes runtime/resources/WiiCompiled.rc | 1 + runtime/src/abi_bridge.cpp | 26 + runtime/src/dynamic_aspect.cpp | 24 +- runtime/src/fiber_manager.cpp | 10 +- runtime/src/friend_code_keyboard.cpp | 168 + runtime/src/guest_region.cpp | 15 + runtime/src/hle/audio/audio.cpp | 16 +- runtime/src/hle/audio/ax_dsp.h | 3 + runtime/src/hle/audio/ax_effects.cpp | 11 +- runtime/src/hle/audio/ax_internal.h | 27 +- runtime/src/hle/audio/ax_memory.cpp | 2 +- runtime/src/hle/audio/ax_mix.cpp | 30 +- runtime/src/hle/bluetooth/bt_controller.cpp | 951 + runtime/src/hle/bluetooth/bt_remote_link.cpp | 567 + runtime/src/hle/bluetooth/bt_sdp.cpp | 438 + runtime/src/hle/bluetooth/bt_sysconf.cpp | 126 + runtime/src/hle/bluetooth/bt_usb_device.cpp | 270 + runtime/src/hle/esp.cpp | 3 +- runtime/src/hle/gx/gx_copy.cpp | 49 +- runtime/src/hle/gx/gx_dl.cpp | 140 +- runtime/src/hle/gx/gx_egg.cpp | 32 +- runtime/src/hle/gx/gx_fatal_stubs.cpp | 2 +- runtime/src/hle/gx/gx_fifo.cpp | 25 +- runtime/src/hle/gx/gx_frame.cpp | 46 + runtime/src/hle/gx/gx_indirect.cpp | 12 +- runtime/src/hle/gx/gx_init.cpp | 82 +- runtime/src/hle/gx/gx_internal.h | 26 +- runtime/src/hle/gx/gx_lighting.cpp | 10 +- runtime/src/hle/gx/gx_objects.cpp | 79 +- runtime/src/hle/gx/gx_pixel.cpp | 22 +- runtime/src/hle/gx/gx_stubs.cpp | 32 +- runtime/src/hle/gx/gx_tev.cpp | 21 +- runtime/src/hle/gx/gx_texture.cpp | 288 +- runtime/src/hle/gx/gx_transform.cpp | 65 +- runtime/src/hle/gx/gx_vertex.cpp | 57 +- runtime/src/hle/gx/gx_worker.cpp | 371 + runtime/src/hle/hollywood_gpio.cpp | 32 + runtime/src/hle/input/kpad.cpp | 268 - runtime/src/hle/input/pad.cpp | 7 - runtime/src/hle/input/wpad.cpp | 217 - runtime/src/hle/ios.cpp | 19 + runtime/src/hle/net/network_config.cpp | 8 +- runtime/src/hle/net/network_deferred.cpp | 3 +- runtime/src/hle/os/os_alarm.cpp | 23 +- runtime/src/hle/os/os_init.cpp | 66 +- runtime/src/hle/os/os_internal.h | 18 +- runtime/src/hle/os/os_interrupt.cpp | 19 +- runtime/src/hle/os/os_reset.cpp | 3 + runtime/src/hle/os/os_scheduler.cpp | 4 +- runtime/src/hle/os/os_thread.cpp | 18 +- runtime/src/hle/sc.cpp | 8 +- runtime/src/hle/storage/dvd.cpp | 76 +- runtime/src/hle/storage/nand_api.cpp | 4 +- runtime/src/hle/storage/nand_fs.cpp | 2 +- runtime/src/hle/storage/nand_internal.h | 3 +- runtime/src/hle/storage/nand_isfs.cpp | 87 +- runtime/src/hle/storage/riivolution.cpp | 7 +- runtime/src/hle/task_thread.cpp | 44 +- runtime/src/hle/vi.cpp | 35 +- runtime/src/main.cpp | 26 +- runtime/src/memory.cpp | 7 + runtime/src/music_attenuation.cpp | 3 +- runtime/src/recomp_mod_loader.cpp | 5 +- runtime/src/settings_overlay.cpp | 575 +- runtime/src/system_bridge.cpp | 43 +- runtime/src/wii_remote_input.cpp | 1069 - runtime/src/wiimote/wiimote_ext_crypto.cpp | 260 + runtime/src/wiimote/wiimote_extension.cpp | 146 + runtime/src/wiimote/wiimote_host.cpp | 828 + runtime/src/wiimote/wiimote_platform_unix.cpp | 496 + .../src/wiimote/wiimote_platform_windows.cpp | 300 + runtime/tests/bluetooth_controller_tests.cpp | 368 + runtime/tests/nand_settings_tests.cpp | 26 +- translator/src/Translator.Cli/Program.cs | 51 +- .../Build/TranslatedBuildShardEmitter.cs | 6 +- .../CxxLinearCodeGenerator.EmitInstruction.cs | 7 + .../CxxLinearCodeGenerator.FlatGuestMemory.cs | 8 + .../CodeGen/CxxLinearCodeGenerator.Locals.cs | 18 +- .../Disassembly/JumpTableDetector.cs | 121 +- .../src/Translator.Core/GuestAddressTable.cs | 111 + .../Mods/Mkwii/RetroRewindRegionPatches.cs | 103 + .../src/Translator.Core/RuntimeNativeIndex.cs | 16 + .../tests/Translator.Tests/CodeGenTests.cs | 35 + .../FunctionTranslatorCoverageTests.cs | 118 + .../GuestAddressTableTests.cs | 191 + .../Translator.Tests/KamekPulFileTests.cs | 13 +- .../PairedFlowCodeGenTests.cs | 65 + .../RegionalRetroRewindTests.cs | 114 + .../RetroRewindRegionPatchesTests.cs | 162 + .../RetroWfcPayloadLoweringTests.cs | 37 +- .../binary/payload.RMCED00.bin | Bin 0 -> 28992 bytes .../binary/payload.RMCJD00.bin | Bin 0 -> 28992 bytes .../TranslatedBuildShardEmitterTests.cs | 4 +- .../Translator.Tests/Translator.Tests.csproj | 2 +- 467 files changed, 72272 insertions(+), 65657 deletions(-) create mode 100644 .gitmodules create mode 100644 Launcher/WiiCompiled.Setup.Common/HostCpuRequirement.cs create mode 160000 aurora-main delete mode 100644 aurora-main/.clang-format delete mode 100644 aurora-main/.gitignore delete mode 100644 aurora-main/CMakeLists.txt delete mode 100644 aurora-main/LICENSE delete mode 100644 aurora-main/README.md delete mode 100644 aurora-main/assets/aurora.png delete mode 100644 aurora-main/cmake/AuroraCopyRuntimeDLLs.cmake delete mode 100644 aurora-main/cmake/AuroraDawnProvider.cmake delete mode 100644 aurora-main/cmake/AuroraLibUSB.cmake delete mode 100644 aurora-main/cmake/AuroraNodProvider.cmake delete mode 100644 aurora-main/cmake/AuroraSDL3Patches.cmake delete mode 100644 aurora-main/cmake/AuroraSDL3Provider.cmake delete mode 100644 aurora-main/cmake/aurora_card.cmake delete mode 100644 aurora-main/cmake/aurora_core.cmake delete mode 100644 aurora-main/cmake/aurora_dvd.cmake delete mode 100644 aurora-main/cmake/aurora_gd.cmake delete mode 100644 aurora-main/cmake/aurora_gx.cmake delete mode 100644 aurora-main/cmake/aurora_main.cmake delete mode 100644 aurora-main/cmake/aurora_ms.cmake delete mode 100644 aurora-main/cmake/aurora_mtx.cmake delete mode 100644 aurora-main/cmake/aurora_os.cmake delete mode 100644 aurora-main/cmake/aurora_pad.cmake delete mode 100644 aurora-main/cmake/aurora_si.cmake delete mode 100644 aurora-main/cmake/aurora_vi.cmake delete mode 100644 aurora-main/cmake/libusb/config.h delete mode 100644 aurora-main/docs/building.md delete mode 100644 aurora-main/examples/CMakeLists.txt delete mode 100644 aurora-main/examples/simple.c delete mode 100644 aurora-main/extern/CMakeLists.txt delete mode 100644 aurora-main/include/aurora/aurora.h delete mode 100644 aurora-main/include/aurora/dvd.h delete mode 100644 aurora-main/include/aurora/event.h delete mode 100644 aurora-main/include/aurora/gfx.h delete mode 100644 aurora-main/include/aurora/imgui.h delete mode 100644 aurora-main/include/aurora/imgui_config.h delete mode 100644 aurora-main/include/aurora/main.h delete mode 100644 aurora-main/include/aurora/math.hpp delete mode 100644 aurora-main/include/aurora/render_size_limits.hpp delete mode 100644 aurora-main/include/dolphin/ai.h delete mode 100644 aurora-main/include/dolphin/ar.h delete mode 100644 aurora-main/include/dolphin/base/PPCArch.h delete mode 100644 aurora-main/include/dolphin/card.h delete mode 100644 aurora-main/include/dolphin/db.h delete mode 100644 aurora-main/include/dolphin/db/DBInterface.h delete mode 100644 aurora-main/include/dolphin/dolphin.h delete mode 100644 aurora-main/include/dolphin/dsp.h delete mode 100644 aurora-main/include/dolphin/dtk.h delete mode 100644 aurora-main/include/dolphin/dvd.h delete mode 100644 aurora-main/include/dolphin/exi.h delete mode 100644 aurora-main/include/dolphin/gd.h delete mode 100644 aurora-main/include/dolphin/gd/GDAurora.h delete mode 100644 aurora-main/include/dolphin/gd/GDBase.h delete mode 100644 aurora-main/include/dolphin/gd/GDFile.h delete mode 100644 aurora-main/include/dolphin/gd/GDGeometry.h delete mode 100644 aurora-main/include/dolphin/gd/GDIndirect.h delete mode 100644 aurora-main/include/dolphin/gd/GDLight.h delete mode 100644 aurora-main/include/dolphin/gd/GDPixel.h delete mode 100644 aurora-main/include/dolphin/gd/GDTev.h delete mode 100644 aurora-main/include/dolphin/gd/GDTexture.h delete mode 100644 aurora-main/include/dolphin/gd/GDTransform.h delete mode 100644 aurora-main/include/dolphin/gf.h delete mode 100644 aurora-main/include/dolphin/gf/GFGeometry.h delete mode 100644 aurora-main/include/dolphin/gf/GFLight.h delete mode 100644 aurora-main/include/dolphin/gf/GFPixel.h delete mode 100644 aurora-main/include/dolphin/gf/GFTev.h delete mode 100644 aurora-main/include/dolphin/gx.h delete mode 100644 aurora-main/include/dolphin/gx/GXAurora.h delete mode 100644 aurora-main/include/dolphin/gx/GXBump.h delete mode 100644 aurora-main/include/dolphin/gx/GXCommandList.h delete mode 100644 aurora-main/include/dolphin/gx/GXCpu2Efb.h delete mode 100644 aurora-main/include/dolphin/gx/GXCull.h delete mode 100644 aurora-main/include/dolphin/gx/GXDispList.h delete mode 100644 aurora-main/include/dolphin/gx/GXDraw.h delete mode 100644 aurora-main/include/dolphin/gx/GXEnum.h delete mode 100644 aurora-main/include/dolphin/gx/GXExtra.h delete mode 100644 aurora-main/include/dolphin/gx/GXFifo.h delete mode 100644 aurora-main/include/dolphin/gx/GXFrameBuffer.h delete mode 100644 aurora-main/include/dolphin/gx/GXGeometry.h delete mode 100644 aurora-main/include/dolphin/gx/GXGet.h delete mode 100644 aurora-main/include/dolphin/gx/GXLighting.h delete mode 100644 aurora-main/include/dolphin/gx/GXManage.h delete mode 100644 aurora-main/include/dolphin/gx/GXPerf.h delete mode 100644 aurora-main/include/dolphin/gx/GXPixel.h delete mode 100644 aurora-main/include/dolphin/gx/GXStruct.h delete mode 100644 aurora-main/include/dolphin/gx/GXTev.h delete mode 100644 aurora-main/include/dolphin/gx/GXTexture.h delete mode 100644 aurora-main/include/dolphin/gx/GXTransform.h delete mode 100644 aurora-main/include/dolphin/gx/GXVert.h delete mode 100644 aurora-main/include/dolphin/hio.h delete mode 100644 aurora-main/include/dolphin/hio2.h delete mode 100644 aurora-main/include/dolphin/hw_regs.h delete mode 100644 aurora-main/include/dolphin/ms.h delete mode 100644 aurora-main/include/dolphin/mtx.h delete mode 100644 aurora-main/include/dolphin/mtx/GeoTypes.h delete mode 100644 aurora-main/include/dolphin/mtx/mtx44ext.h delete mode 100644 aurora-main/include/dolphin/os.h delete mode 100644 aurora-main/include/dolphin/os/OSAlarm.h delete mode 100644 aurora-main/include/dolphin/os/OSAlloc.h delete mode 100644 aurora-main/include/dolphin/os/OSCache.h delete mode 100644 aurora-main/include/dolphin/os/OSContext.h delete mode 100644 aurora-main/include/dolphin/os/OSDC.h delete mode 100644 aurora-main/include/dolphin/os/OSError.h delete mode 100644 aurora-main/include/dolphin/os/OSException.h delete mode 100644 aurora-main/include/dolphin/os/OSExec.h delete mode 100644 aurora-main/include/dolphin/os/OSFastCast.h delete mode 100644 aurora-main/include/dolphin/os/OSFont.h delete mode 100644 aurora-main/include/dolphin/os/OSIC.h delete mode 100644 aurora-main/include/dolphin/os/OSInterrupt.h delete mode 100644 aurora-main/include/dolphin/os/OSL2.h delete mode 100644 aurora-main/include/dolphin/os/OSLC.h delete mode 100644 aurora-main/include/dolphin/os/OSMemory.h delete mode 100644 aurora-main/include/dolphin/os/OSMessage.h delete mode 100644 aurora-main/include/dolphin/os/OSModule.h delete mode 100644 aurora-main/include/dolphin/os/OSMutex.h delete mode 100644 aurora-main/include/dolphin/os/OSReboot.h delete mode 100644 aurora-main/include/dolphin/os/OSReset.h delete mode 100644 aurora-main/include/dolphin/os/OSResetSW.h delete mode 100644 aurora-main/include/dolphin/os/OSRtc.h delete mode 100644 aurora-main/include/dolphin/os/OSSemaphore.h delete mode 100644 aurora-main/include/dolphin/os/OSSerial.h delete mode 100644 aurora-main/include/dolphin/os/OSThread.h delete mode 100644 aurora-main/include/dolphin/os/OSTime.h delete mode 100644 aurora-main/include/dolphin/os/OSTimer.h delete mode 100644 aurora-main/include/dolphin/os/OSUtf.h delete mode 100644 aurora-main/include/dolphin/pad.h delete mode 100644 aurora-main/include/dolphin/perf.h delete mode 100644 aurora-main/include/dolphin/ppc_math.h delete mode 100644 aurora-main/include/dolphin/si.h delete mode 100644 aurora-main/include/dolphin/thp.h delete mode 100644 aurora-main/include/dolphin/types.h delete mode 100644 aurora-main/include/dolphin/vi.h delete mode 100644 aurora-main/include/magic_enum.hpp delete mode 100644 aurora-main/lib/aurora.cpp delete mode 100644 aurora-main/lib/card/BlockAllocationTable.cpp delete mode 100644 aurora-main/lib/card/BlockAllocationTable.hpp delete mode 100644 aurora-main/lib/card/CardGciFolder.cpp delete mode 100644 aurora-main/lib/card/CardGciFolder.hpp delete mode 100644 aurora-main/lib/card/CardRawFile.cpp delete mode 100644 aurora-main/lib/card/CardRawFile.hpp delete mode 100644 aurora-main/lib/card/CommonData.h delete mode 100644 aurora-main/lib/card/Constants.hpp delete mode 100644 aurora-main/lib/card/Directory.cpp delete mode 100644 aurora-main/lib/card/Directory.hpp delete mode 100644 aurora-main/lib/card/DolphinCardPath.cpp delete mode 100644 aurora-main/lib/card/DolphinCardPath.hpp delete mode 100644 aurora-main/lib/card/File.cpp delete mode 100644 aurora-main/lib/card/File.hpp delete mode 100644 aurora-main/lib/card/FileIO.cpp delete mode 100644 aurora-main/lib/card/FileIO.hpp delete mode 100644 aurora-main/lib/card/ICard.hpp delete mode 100644 aurora-main/lib/card/SRAM.cpp delete mode 100644 aurora-main/lib/card/SRAM.hpp delete mode 100644 aurora-main/lib/card/Util.cpp delete mode 100644 aurora-main/lib/card/Util.hpp delete mode 100644 aurora-main/lib/dawn/BackendBinding.cpp delete mode 100644 aurora-main/lib/dawn/BackendBinding.hpp delete mode 100644 aurora-main/lib/dawn/MetalBinding.mm delete mode 100644 aurora-main/lib/dolphin/AR.cpp delete mode 100644 aurora-main/lib/dolphin/card.cpp delete mode 100644 aurora-main/lib/dolphin/dvd/dvd.cpp delete mode 100644 aurora-main/lib/dolphin/gd/GDAurora.cpp delete mode 100644 aurora-main/lib/dolphin/gd/GDBase.cpp delete mode 100644 aurora-main/lib/dolphin/gd/GDGeometry.cpp delete mode 100644 aurora-main/lib/dolphin/gd/GDIndirect.cpp delete mode 100644 aurora-main/lib/dolphin/gd/GDLight.cpp delete mode 100644 aurora-main/lib/dolphin/gd/GDPixel.cpp delete mode 100644 aurora-main/lib/dolphin/gd/GDTev.cpp delete mode 100644 aurora-main/lib/dolphin/gd/GDTexture.cpp delete mode 100644 aurora-main/lib/dolphin/gd/GDTransform.cpp delete mode 100644 aurora-main/lib/dolphin/gd/gd.hpp delete mode 100644 aurora-main/lib/dolphin/gx/GXAurora.cpp delete mode 100644 aurora-main/lib/dolphin/gx/GXBump.cpp delete mode 100644 aurora-main/lib/dolphin/gx/GXCpu2Efb.cpp delete mode 100644 aurora-main/lib/dolphin/gx/GXCull.cpp delete mode 100644 aurora-main/lib/dolphin/gx/GXDispList.cpp delete mode 100644 aurora-main/lib/dolphin/gx/GXDraw.cpp delete mode 100644 aurora-main/lib/dolphin/gx/GXExtra.cpp delete mode 100644 aurora-main/lib/dolphin/gx/GXFifo.cpp delete mode 100644 aurora-main/lib/dolphin/gx/GXFrameBuffer.cpp delete mode 100644 aurora-main/lib/dolphin/gx/GXGeometry.cpp delete mode 100644 aurora-main/lib/dolphin/gx/GXGet.cpp delete mode 100644 aurora-main/lib/dolphin/gx/GXLighting.cpp delete mode 100644 aurora-main/lib/dolphin/gx/GXManage.cpp delete mode 100644 aurora-main/lib/dolphin/gx/GXPixel.cpp delete mode 100644 aurora-main/lib/dolphin/gx/GXTev.cpp delete mode 100644 aurora-main/lib/dolphin/gx/GXTexture.cpp delete mode 100644 aurora-main/lib/dolphin/gx/GXTransform.cpp delete mode 100644 aurora-main/lib/dolphin/gx/GXVert.cpp delete mode 100644 aurora-main/lib/dolphin/gx/__gx.h delete mode 100644 aurora-main/lib/dolphin/gx/gx.hpp delete mode 100644 aurora-main/lib/dolphin/ms/mouse.cpp delete mode 100644 aurora-main/lib/dolphin/mtx/mtx.c delete mode 100644 aurora-main/lib/dolphin/mtx/mtx44.c delete mode 100644 aurora-main/lib/dolphin/mtx/mtxstack.c delete mode 100644 aurora-main/lib/dolphin/mtx/mtxvec.c delete mode 100644 aurora-main/lib/dolphin/mtx/quat.c delete mode 100644 aurora-main/lib/dolphin/mtx/vec.c delete mode 100644 aurora-main/lib/dolphin/os/OSAddress.cpp delete mode 100644 aurora-main/lib/dolphin/os/OSAlloc.cpp delete mode 100644 aurora-main/lib/dolphin/os/OSArena.cpp delete mode 100644 aurora-main/lib/dolphin/os/OSBootInfo.cpp delete mode 100644 aurora-main/lib/dolphin/os/OSInit.cpp delete mode 100644 aurora-main/lib/dolphin/os/OSMemory.cpp delete mode 100644 aurora-main/lib/dolphin/os/OSTime.cpp delete mode 100644 aurora-main/lib/dolphin/os/internal.hpp delete mode 100644 aurora-main/lib/dolphin/pad/pad.cpp delete mode 100644 aurora-main/lib/dolphin/si/si.cpp delete mode 100644 aurora-main/lib/dolphin/vi/vi.cpp delete mode 100644 aurora-main/lib/dolphin/vi/vi_internal.hpp delete mode 100644 aurora-main/lib/fs_helper.hpp delete mode 100644 aurora-main/lib/gfx/clear.cpp delete mode 100644 aurora-main/lib/gfx/clear.hpp delete mode 100644 aurora-main/lib/gfx/common.cpp delete mode 100644 aurora-main/lib/gfx/common.hpp delete mode 100644 aurora-main/lib/gfx/dds_io.cpp delete mode 100644 aurora-main/lib/gfx/dds_io.hpp delete mode 100644 aurora-main/lib/gfx/depth_peek.cpp delete mode 100644 aurora-main/lib/gfx/depth_peek.hpp delete mode 100644 aurora-main/lib/gfx/efb_ram_copy.cpp delete mode 100644 aurora-main/lib/gfx/efb_ram_copy.hpp delete mode 100644 aurora-main/lib/gfx/efb_ram_encoder.cpp delete mode 100644 aurora-main/lib/gfx/efb_ram_encoder.hpp delete mode 100644 aurora-main/lib/gfx/pipeline_cache.cpp delete mode 100644 aurora-main/lib/gfx/pipeline_cache.hpp delete mode 100644 aurora-main/lib/gfx/png_io.cpp delete mode 100644 aurora-main/lib/gfx/png_io.hpp delete mode 100644 aurora-main/lib/gfx/staging_capacity.hpp delete mode 100644 aurora-main/lib/gfx/staging_map.hpp delete mode 100644 aurora-main/lib/gfx/tex_copy_conv.cpp delete mode 100644 aurora-main/lib/gfx/tex_copy_conv.hpp delete mode 100644 aurora-main/lib/gfx/tex_copy_format_contract.hpp delete mode 100644 aurora-main/lib/gfx/tex_palette_conv.cpp delete mode 100644 aurora-main/lib/gfx/tex_palette_conv.hpp delete mode 100644 aurora-main/lib/gfx/texture.cpp delete mode 100644 aurora-main/lib/gfx/texture.hpp delete mode 100644 aurora-main/lib/gfx/texture_convert.cpp delete mode 100644 aurora-main/lib/gfx/texture_convert.hpp delete mode 100644 aurora-main/lib/gfx/texture_replacement.cpp delete mode 100644 aurora-main/lib/gfx/texture_replacement.hpp delete mode 100644 aurora-main/lib/gx/command_processor.cpp delete mode 100644 aurora-main/lib/gx/command_processor.hpp delete mode 100644 aurora-main/lib/gx/fifo.cpp delete mode 100644 aurora-main/lib/gx/fifo.hpp delete mode 100644 aurora-main/lib/gx/frame_interpolation.cpp delete mode 100644 aurora-main/lib/gx/frame_interpolation.hpp delete mode 100644 aurora-main/lib/gx/gx.cpp delete mode 100644 aurora-main/lib/gx/gx.hpp delete mode 100644 aurora-main/lib/gx/gx_fmt.hpp delete mode 100644 aurora-main/lib/gx/pipeline.cpp delete mode 100644 aurora-main/lib/gx/pipeline.hpp delete mode 100644 aurora-main/lib/gx/shader.cpp delete mode 100644 aurora-main/lib/gx/shader_info.cpp delete mode 100644 aurora-main/lib/gx/shader_info.hpp delete mode 100644 aurora-main/lib/gx/texture_bind_group_cache_key.hpp delete mode 100644 aurora-main/lib/imgui.cpp delete mode 100644 aurora-main/lib/imgui.hpp delete mode 100644 aurora-main/lib/imgui_config.cpp delete mode 100644 aurora-main/lib/input.cpp delete mode 100644 aurora-main/lib/input.hpp delete mode 100644 aurora-main/lib/internal.hpp delete mode 100644 aurora-main/lib/logging.cpp delete mode 100644 aurora-main/lib/logging.hpp delete mode 100644 aurora-main/lib/main.cpp delete mode 100644 aurora-main/lib/sqlite_utils.hpp delete mode 100644 aurora-main/lib/system_info.cpp delete mode 100644 aurora-main/lib/system_info.hpp delete mode 100644 aurora-main/lib/system_info_mac.mm delete mode 100644 aurora-main/lib/webgpu/gpu.cpp delete mode 100644 aurora-main/lib/webgpu/gpu.hpp delete mode 100644 aurora-main/lib/webgpu/gpu_cache.cpp delete mode 100644 aurora-main/lib/webgpu/metalfx.hpp delete mode 100644 aurora-main/lib/webgpu/metalfx.mm delete mode 100644 aurora-main/lib/webgpu/metalfx_stub.cpp delete mode 100644 aurora-main/lib/webgpu/wgpu.hpp delete mode 100644 aurora-main/lib/window.cpp delete mode 100644 aurora-main/lib/window.hpp delete mode 100644 aurora-main/tests/CMakeLists.txt delete mode 100644 aurora-main/tests/gpu_readback_test.cpp delete mode 100644 aurora-main/tests/gx_fifo_test.cpp delete mode 100644 aurora-main/tests/gx_test_common.hpp delete mode 100644 aurora-main/tests/gx_test_stubs.cpp delete mode 100644 aurora-main/tests/metalfx_interop/CMakeLists.txt delete mode 100644 aurora-main/tests/metalfx_interop/README.md delete mode 100644 aurora-main/tests/metalfx_interop/main.mm delete mode 100644 aurora-main/tests/metalfx_interop/presentation_test.cpp delete mode 100644 aurora-main/tests/metalfx_interop/stub_test.cpp delete mode 100644 aurora-main/tests/os_alloc_test.cpp delete mode 100644 aurora-main/tests/os_test_globals.cpp delete mode 100644 aurora-main/tests/renderer_regression_test.cpp delete mode 100644 aurora-main/tests/test_dvd.cpp delete mode 100644 aurora-main/tests/texture_bind_group_cache_key_test.cpp create mode 100644 projects/mkwii-ntsc-j/MAP.txt create mode 100644 projects/mkwii-ntsc-j/data_addresses.txt create mode 100644 projects/mkwii-ntsc-j/recomp.yml create mode 100644 projects/mkwii-ntsc-j/region_port.json create mode 100644 projects/mkwii-ntsc-u/MAP.txt create mode 100644 projects/mkwii-ntsc-u/data_addresses.txt create mode 100644 projects/mkwii-ntsc-u/recomp.yml create mode 100644 projects/mkwii-ntsc-u/region_port.json create mode 100644 runtime/game/guest_region.cpp create mode 100644 runtime/include/bluetooth/bt_bytes.h create mode 100644 runtime/include/bluetooth/bt_controller.h create mode 100644 runtime/include/bluetooth/bt_remote_link.h create mode 100644 runtime/include/bluetooth/bt_sdp.h create mode 100644 runtime/include/friend_code_keyboard.h create mode 100644 runtime/include/guest_abi/guest_region.h create mode 100644 runtime/include/guest_abi/guest_versions.inc create mode 100644 runtime/include/guest_function_imports.h create mode 100644 runtime/include/gx_worker.h create mode 100644 runtime/include/hle/bluetooth_hle.h create mode 100644 runtime/include/hle/hollywood_gpio.h delete mode 100644 runtime/include/wii_remote_input.h create mode 100644 runtime/include/wiimote_ext_crypto.h create mode 100644 runtime/include/wiimote_extension.h create mode 100644 runtime/include/wiimote_host.h create mode 100644 runtime/include/wiimote_platform.h create mode 100644 runtime/resources/RetroRewind.ico create mode 100644 runtime/resources/RetroRewind.rc create mode 100644 runtime/resources/WiiCompiled.ico create mode 100644 runtime/resources/WiiCompiled.rc create mode 100644 runtime/src/friend_code_keyboard.cpp create mode 100644 runtime/src/guest_region.cpp create mode 100644 runtime/src/hle/bluetooth/bt_controller.cpp create mode 100644 runtime/src/hle/bluetooth/bt_remote_link.cpp create mode 100644 runtime/src/hle/bluetooth/bt_sdp.cpp create mode 100644 runtime/src/hle/bluetooth/bt_sysconf.cpp create mode 100644 runtime/src/hle/bluetooth/bt_usb_device.cpp create mode 100644 runtime/src/hle/gx/gx_worker.cpp create mode 100644 runtime/src/hle/hollywood_gpio.cpp delete mode 100644 runtime/src/hle/input/kpad.cpp delete mode 100644 runtime/src/hle/input/wpad.cpp delete mode 100644 runtime/src/wii_remote_input.cpp create mode 100644 runtime/src/wiimote/wiimote_ext_crypto.cpp create mode 100644 runtime/src/wiimote/wiimote_extension.cpp create mode 100644 runtime/src/wiimote/wiimote_host.cpp create mode 100644 runtime/src/wiimote/wiimote_platform_unix.cpp create mode 100644 runtime/src/wiimote/wiimote_platform_windows.cpp create mode 100644 runtime/tests/bluetooth_controller_tests.cpp create mode 100644 translator/src/Translator.Core/GuestAddressTable.cs create mode 100644 translator/src/Translator.Core/Mods/Mkwii/RetroRewindRegionPatches.cs create mode 100644 translator/tests/Translator.Tests/GuestAddressTableTests.cs create mode 100644 translator/tests/Translator.Tests/RegionalRetroRewindTests.cs create mode 100644 translator/tests/Translator.Tests/RetroRewindRegionPatchesTests.cs create mode 100644 translator/tests/Translator.Tests/TestAssets/RetroWfcPayload/binary/payload.RMCED00.bin create mode 100644 translator/tests/Translator.Tests/TestAssets/RetroWfcPayload/binary/payload.RMCJD00.bin diff --git a/.gitattributes b/.gitattributes index 6344b3b..8650aaa 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,3 +4,9 @@ # Patch files must stay LF: git apply matches context bytes against LF upstream sources *.patch -text translator/tests/Translator.Tests/TestAssets/**/*.bin binary + +# Region tables +projects/mkwii-ntsc-*/MAP.txt linguist-generated=true +projects/mkwii-ntsc-*/region_port.json linguist-generated=true +projects/mkwii-ntsc-j/data_addresses.txt linguist-generated=true +runtime/include/guest_abi/guest_versions.inc linguist-generated=true diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e781fa7..b204551 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -77,6 +77,7 @@ jobs: - uses: actions/checkout@v7 with: persist-credentials: false + submodules: recursive - name: Test macOS app dependency packaging shell: bash @@ -101,6 +102,7 @@ jobs: mkw_nand_settings_tests \ mkw_sc_serial_tests \ mkw_input_expr_tests \ + mkw_bluetooth_controller_tests \ mkw_macos_native_compile \ mkw_macos_context_abi_tests \ mkw_macos_host_context_tests \ diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 00ce054..b091334 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -44,6 +44,7 @@ jobs: - uses: actions/checkout@v7 with: persist-credentials: false + submodules: recursive - uses: actions/setup-dotnet@v6 with: @@ -79,6 +80,7 @@ jobs: - uses: actions/checkout@v7 with: persist-credentials: false + submodules: recursive - uses: actions/setup-dotnet@v6 with: @@ -102,6 +104,7 @@ jobs: - uses: actions/checkout@v7 with: persist-credentials: false + submodules: recursive - uses: actions/setup-dotnet@v6 with: @@ -235,6 +238,7 @@ jobs: - uses: actions/checkout@v7 with: persist-credentials: false + submodules: recursive # Wheel Wizard runs the downloaded setup with --version and refuses it when the reported # version differs from the release tag, so a tag that was pushed without bumping the pinned diff --git a/.github/workflows/recomp-test.yml b/.github/workflows/recomp-test.yml index fe35888..6ae6eb8 100644 --- a/.github/workflows/recomp-test.yml +++ b/.github/workflows/recomp-test.yml @@ -16,6 +16,7 @@ jobs: - uses: actions/checkout@v7 with: persist-credentials: false + submodules: recursive - uses: actions/setup-dotnet@v6 with: diff --git a/.gitignore b/.gitignore index 7be3ef6..704d29c 100644 --- a/.gitignore +++ b/.gitignore @@ -66,7 +66,8 @@ project.lock.json /.vs/ /.vscode/ /.idea/ -/tools/ +/tools/* +__pycache__/ /TEMP/ /tmp/ /test_output/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..d0ad13c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "aurora-main"] + path = aurora-main + url = https://github.com/patchzyy/aurora-wiicompiled.git + branch = main diff --git a/Launcher/Build-Installer.ps1 b/Launcher/Build-Installer.ps1 index 6f6eaa5..faeb12d 100644 --- a/Launcher/Build-Installer.ps1 +++ b/Launcher/Build-Installer.ps1 @@ -23,12 +23,23 @@ $publish = Join-Path $workRoot 'publish' $payloadRoot = Join-Path $workRoot 'payload' $setupProject = Join-Path $PSScriptRoot 'WiiCompiled.Setup.Windows\WiiCompiled.Setup.Windows.csproj' $translatorProject = Join-Path $repoRoot 'translator\src\Translator.Cli\Translator.Cli.csproj' -$projectFile = Join-Path $repoRoot 'projects\mkwii\recomp.yml' -# Everything Mario-Kart-specific in the manifest below is read from the project file rather than -# restated here, and Test-PinnedFacts.ps1 checks the copies that cannot read it (the C++ entry -# address, the C# endpoint constant, the lists this script and the installed host both carry). -$pins = Get-MkwProjectPins $projectFile +# Every supported release is one projects//recomp.yml. Everything Mario-Kart-specific in the +# manifest below is read from those files rather than restated here, and Test-PinnedFacts.ps1 +# checks the copies that cannot read them (the C++ entry address, the C# Retro-WFC table, the +# lists this script and the installed host both carry). +$releaseProjects = @(Get-ChildItem -LiteralPath (Join-Path $repoRoot 'projects') -Directory | + Where-Object { Test-Path -LiteralPath (Join-Path $_.FullName 'recomp.yml') -PathType Leaf } | + Sort-Object Name) +if ($releaseProjects.Count -eq 0) { throw 'No translation project defines a supported release.' } +$supportedReleases = @(foreach ($releaseProject in $releaseProjects) { + $pins = Get-MkwProjectPins (Join-Path $releaseProject.FullName 'recomp.yml') + [ordered]@{ GameId = $pins.GameId; DolSha256 = $pins.DolSha256; RelSha256 = $pins.RelSha256 } +}) +foreach ($key in @('GameId', 'DolSha256')) { + $duplicates = @($supportedReleases | Group-Object { $_[$key] } | Where-Object Count -gt 1) + if ($duplicates.Count -gt 0) { throw "Two translation projects pin the same $($key): $($duplicates[0].Name)." } +} # The audit reports by throwing, which aborts this run; nothing native has been invoked yet, so # there is no exit code to inspect. & (Join-Path $PSScriptRoot 'Test-PinnedFacts.ps1') -RepositoryRoot $repoRoot @@ -73,7 +84,16 @@ function Resolve-VcRuntimeDirectory([string]$RequestedPath) { function Copy-Directory([string]$Source, [string]$Destination) { Assert-Directory $Source "Source directory" [IO.Directory]::CreateDirectory($Destination) | Out-Null - Copy-Item -Path (Join-Path $Source '*') -Destination $Destination -Recurse -Force + # Source payloads are materialized trees, independent of Git checkout metadata. + foreach ($entry in Get-ChildItem -LiteralPath $Source -Force) { + if ($entry.Name -eq '.git') { continue } + $target = Join-Path $Destination $entry.Name + if ($entry.PSIsContainer) { + Copy-Directory $entry.FullName $target + } else { + Copy-Item -LiteralPath $entry.FullName -Destination $target -Force + } + } } function Compress-Zip([string]$Source, [string]$Destination, [string[]]$Entries) { $tar = Join-Path $env:SystemRoot 'System32\tar.exe' @@ -234,7 +254,9 @@ if (Test-Path -LiteralPath $runtimeDeveloperBuild) { } $auroraExtern = Join-Path $workspace 'aurora-main\extern' Get-ChildItem -LiteralPath $auroraExtern -Directory -Force | Remove-Item -Recurse -Force -Copy-Directory (Join-Path $repoRoot 'projects\mkwii') (Join-Path $workspace 'projects\mkwii') +foreach ($releaseProject in $releaseProjects) { + Copy-Directory $releaseProject.FullName (Join-Path $workspace "projects\$($releaseProject.Name)") +} Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'LocalBuild.ps1') -Destination (Join-Path $workspace 'LocalBuild.ps1') # LocalBuild.ps1 dot-sources the canonical configure flags from this sibling. Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'NativeBuildFlags.ps1') -Destination (Join-Path $workspace 'NativeBuildFlags.ps1') @@ -317,22 +339,20 @@ foreach ($required in @('ToolkitFingerprint','TranslationFingerprint','NativeToo $productVersion = ((& $setupHost --version) -join '').Trim() if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($productVersion)) { throw 'The setup host did not report its version.' } +# Schema 3 replaced schema 2's single Expected* release fields with SupportedReleases. $manifest = [ordered]@{ - SchemaVersion = 2 + SchemaVersion = 3 ProductVersion = $productVersion - ExpectedGameId = $pins.GameId - ExpectedDolSha256 = $pins.DolSha256 - ExpectedRelSha256 = $pins.RelSha256 + SupportedReleases = $supportedReleases ToolkitReleaseTag = if ($ToolkitReleaseTag) { $ToolkitReleaseTag } else { '' } BuildModel = 'local-translation-and-compilation' - RetroWfcPayloadUri = $pins.RetroWfcPayloadUri ToolkitFingerprint = $identities.ToolkitFingerprint ToolkitPackageFingerprint = $identities.ToolkitPackageFingerprint RuntimeAssetsFingerprint = $identities.RuntimeAssetsFingerprint TranslationFingerprint = $identities.TranslationFingerprint NativeToolchainFingerprint = $identities.NativeToolchainFingerprint } -$manifest | ConvertTo-Json | Set-Content (Join-Path $payloadRoot 'payload-manifest.json') -Encoding UTF8 +$manifest | ConvertTo-Json -Depth 4 | Set-Content (Join-Path $payloadRoot 'payload-manifest.json') -Encoding UTF8 Write-Host '[4/6] Enforcing the copyright and generated-code boundary...' # Both audits are PowerShell scripts that throw directly on failure (Test-PayloadBoundary.ps1 diff --git a/Launcher/Directory.Build.props b/Launcher/Directory.Build.props index bd8c660..12f7347 100644 --- a/Launcher/Directory.Build.props +++ b/Launcher/Directory.Build.props @@ -1,7 +1,7 @@ - 0.2.36 + 0.9.0 false diff --git a/Launcher/LocalBuild.ps1 b/Launcher/LocalBuild.ps1 index 2a36909..e319eb6 100644 --- a/Launcher/LocalBuild.ps1 +++ b/Launcher/LocalBuild.ps1 @@ -21,7 +21,8 @@ param( # Discards every cache first. Used when a product was reported broken/blocked, so a possibly # corrupted translation or build directory can never contribute to the repaired product. [switch]$ForceCleanBuild, - [int]$Parallel = 0 + [int]$Parallel = 0, + [ValidateSet('v2', 'v3')] [string]$X86CpuProfile = 'v3' ) $ErrorActionPreference = 'Stop' @@ -166,7 +167,6 @@ $toolchainBin = Join-Path $toolchain 'llvm-mingw\bin' $cc = Join-Path $toolchainBin 'x86_64-w64-mingw32-clang.exe' $cxx = Join-Path $toolchainBin 'x86_64-w64-mingw32-clang++.exe' $windres = Join-Path $toolchainBin 'x86_64-w64-mingw32-windres.exe' -$project = Join-Path $Workspace 'projects\mkwii\recomp.yml' $assets = Join-Path $Workspace 'Assets' $generated = Join-Path $Workspace 'generated' $functions = Join-Path $generated 'functions' @@ -183,14 +183,18 @@ $retroRoot = if ([string]::IsNullOrWhiteSpace($RetroRewindPackageDirectory)) { foreach ($required in @( @($translator, 'Bundled translator'), @($cmake, 'Bundled CMake'), @($ninja, 'Bundled Ninja'), - @($cc, 'Bundled C compiler'), @($cxx, 'Bundled C++ compiler'), @($windres, 'Bundled resource compiler'), @($project, 'Translation project'), + @($cc, 'Bundled C compiler'), @($cxx, 'Bundled C++ compiler'), @($windres, 'Bundled resource compiler'), @((Join-Path $assets 'main.dol'), 'Extracted main.dol'), @((Join-Path $assets 'StaticR.rel'), 'Extracted StaticR.rel') )) { Assert-File $required[0] $required[1] } # Everything Mario-Kart-specific this script needs is read from the project file rather than # restated here: the translation entry point below, and (through the retro-rewind profile the -# translator loads itself) the module guest/link bases the mod translation uses. -$pins = Get-MkwProjectPins $project +# translator loads itself) the module guest/link bases the mod translation uses. The project is +# the one pinned to the extracted main.dol, which decides the region. +$selectedProject = Resolve-MkwProjectForAssets $Workspace $assets +$project = $selectedProject.Path +$pins = $selectedProject.Pins +$retroWfcPayloadFile = "binary\payload.$(($pins.RetroWfcPayloadUri -split 'g=')[-1]).bin" # Three independent knobs: $translatorThreads (the translator's own worker threads; peak memory is # one heap that barely moves with thread count, so clamping it only slows translation), $translatedJobs @@ -243,7 +247,8 @@ try { # outputs plus --prune-stale mean Ninja only recompiles shards whose bytes actually moved. $reuseBase = $false if (-not $ForceCleanBuild -and -not [string]::IsNullOrWhiteSpace($TranslationFingerprint) -and - (Get-RecordedFingerprint $translationProvenance 'TranslationFingerprint') -eq $TranslationFingerprint) { + (Get-RecordedFingerprint $translationProvenance 'TranslationFingerprint') -eq $TranslationFingerprint -and + (Get-RecordedFingerprint $translationProvenance 'DolSha256') -eq $pins.DolSha256) { $artifacts = @($baseMetadata, $baseManifest, (Join-Path $generated 'base_translation_sources.bin'), (Join-Path $generated 'base_translation_mod_awareness.json')) $reuseBase = -not ($artifacts | Where-Object { -not (Test-Path -LiteralPath $_ -PathType Leaf) }) @@ -312,11 +317,11 @@ try { Invoke-Checked $translator @( 'emit-base-manifest', '--project', $project, '--out', $baseManifestDir, - '--functions-dir', $functions, '--translation-output-metadata', $baseMetadata, '--region', 'P' + '--functions-dir', $functions, '--translation-output-metadata', $baseMetadata, '--region', $pins.Region ) 'Creating the local base translation manifest' -StepId 'emit-base-manifest' if (-not [string]::IsNullOrWhiteSpace($TranslationFingerprint)) { - [ordered]@{ SchemaVersion = 1; TranslationFingerprint = $TranslationFingerprint } | + [ordered]@{ SchemaVersion = 1; TranslationFingerprint = $TranslationFingerprint; DolSha256 = $pins.DolSha256 } | ConvertTo-Json | Set-Content -LiteralPath $translationProvenance -Encoding UTF8 } } @@ -329,14 +334,14 @@ try { 'translate-mod', '--project', $project, '--profile', 'retro-rewind', '--base-manifest', $baseManifest, '--base-translation-output-metadata', $baseMetadata, '--code-pul', $codePul, '--mod-root', $retroRoot, '--mod-name', 'Retro Rewind', - '--region', 'P', '--out', $retroOut, '--prefer-cached-inputs', '--emit-cpp', + '--region', $pins.Region, '--out', $retroOut, '--prefer-cached-inputs', '--emit-cpp', '--threads', $translatorThreads ) if ($SkipRetroWfcPayload) { $translateModArguments += '--skip-retro-wfc' } elseif (-not [string]::IsNullOrWhiteSpace($RetroWfcOfflineDirectory)) { $offlineRoot = [IO.Path]::GetFullPath($RetroWfcOfflineDirectory) - $offlinePayload = Join-Path $offlineRoot 'binary\payload.RMCPD00.bin' + $offlinePayload = Join-Path $offlineRoot $retroWfcPayloadFile Assert-File $offlinePayload 'Offline Retro-WFC shared payload' $translateModArguments += @('--retro-wfc-payload', $offlinePayload) } else { @@ -393,11 +398,14 @@ try { $dependencies = Join-Path $Workspace 'Dependencies' $nativePrebuilt = Resolve-NativePrebuiltDirectory $dependencies $toolchainBin ` (Join-Path $Workspace 'aurora-main') (Join-Path $Workspace 'runtime\third_party') + if ($X86CpuProfile -eq 'v2') { + Write-Host 'MKWCBUILD: This CPU does not support x86-64-v3; building for x86-64-v2' + } $configure = Get-MkwNativeConfigureArguments ` -SourceDirectory (Join-Path $Workspace 'runtime') -BuildDirectory $build ` -Ninja $ninja -CCompiler $cc -CxxCompiler $cxx -ResourceCompiler $windres ` -DependenciesDirectory $dependencies -NativePrebuiltDirectory $nativePrebuilt ` - -AdditionalArguments @("-DMKW_TRANSLATED_COMPILE_JOBS=$translatedJobs") + -AdditionalArguments @("-DMKW_TRANSLATED_COMPILE_JOBS=$translatedJobs", "-DMKW_X86_CPU_PROFILE=$X86CpuProfile") Invoke-Checked $cmake $configure 'Configuring the bundled native toolchain' -StepId 'configure-native' if (-not [string]::IsNullOrWhiteSpace($NativeToolchainFingerprint)) { [ordered]@{ SchemaVersion = 1; NativeToolchainFingerprint = $NativeToolchainFingerprint } | @@ -423,7 +431,7 @@ try { $exe = Join-Path $build "$Target.exe" Assert-File $exe 'Locally compiled game executable' Copy-Item -LiteralPath $exe -Destination (Join-Path $Destination "$Target.exe") - foreach ($name in @('dxcompiler.dll','dxil.dll','libc++.dll','libpng16.dll','libunwind.dll','libz.dll','SDL3.dll','sqlite3.dll','webgpu_dawn.dll','z.dll','noshaders.zip','dsp_coef.bin','initial_pipeline_cache.db')) { + foreach ($name in @('dxcompiler.dll','dxil.dll','libc++.dll','libpng16.dll','libunwind.dll','libz.dll','libzlib1.dll','SDL3.dll','sqlite3.dll','webgpu_dawn.dll','z.dll','noshaders.zip','dsp_coef.bin','initial_pipeline_cache.db')) { $file = Join-Path $build $name if (Test-Path -LiteralPath $file -PathType Leaf) { Copy-Item -LiteralPath $file -Destination $Destination } } @@ -447,8 +455,8 @@ try { RelSha256 = $relSha CodePulSha256 = if ($isRetro) { Get-MkwFileSha256 (Join-Path $retroRoot 'Binaries\Code.pul') } else { $null } RetroWfcPayloadMode = if (-not $isRetro) { $null } elseif ($SkipRetroWfcPayload) { 'skipped' } else { $RetroWfcPayloadOrigin } - RetroWfcPayloadSha256 = if ($isRetro -and -not $SkipRetroWfcPayload) { Get-MkwFileSha256 (Join-Path $RetroWfcOfflineDirectory 'binary\payload.RMCPD00.bin') } else { $null } - RetroWfcPayloadLength = if ($isRetro -and -not $SkipRetroWfcPayload) { (Get-Item -LiteralPath (Join-Path $RetroWfcOfflineDirectory 'binary\payload.RMCPD00.bin')).Length } else { $null } + RetroWfcPayloadSha256 = if ($isRetro -and -not $SkipRetroWfcPayload) { Get-MkwFileSha256 (Join-Path $RetroWfcOfflineDirectory $retroWfcPayloadFile) } else { $null } + RetroWfcPayloadLength = if ($isRetro -and -not $SkipRetroWfcPayload) { (Get-Item -LiteralPath (Join-Path $RetroWfcOfflineDirectory $retroWfcPayloadFile)).Length } else { $null } Compiler = "llvm-mingw clang-22 sha256:$compilerSha" } $provenance | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $Destination 'local-build.json') -Encoding UTF8 diff --git a/Launcher/NativeBuildFlags.ps1 b/Launcher/NativeBuildFlags.ps1 index 6aa628a..9e8ad39 100644 --- a/Launcher/NativeBuildFlags.ps1 +++ b/Launcher/NativeBuildFlags.ps1 @@ -93,7 +93,7 @@ function Get-MkwBuildSafePath([string]$Path, [string]$Kind, [string]$MarkerFile) function Get-MkwProjectPins([string]$ProjectFile) { <# - The Mario Kart Wii facts pinned by projects/mkwii/recomp.yml (game identity, clean input + The Mario Kart Wii facts pinned by a projects/*/recomp.yml (game identity, clean input digests, translation entry point, Retro-WFC endpoint), read from one place instead of being restated; Test-PinnedFacts.ps1 checks the copies that can't read YAML (C++ header, C# constants) against these values. Parsing is literal, not a YAML dependency, since the file is @@ -101,7 +101,7 @@ function Get-MkwProjectPins([string]$ProjectFile) { #> Assert-File $ProjectFile 'Translation project file' $pins = [ordered]@{ - GameId = ''; DolSha256 = ''; RelSha256 = ''; EntryPoint = ''; RetroWfcPayloadUri = '' + GameId = ''; Region = ''; DolSha256 = ''; RelSha256 = ''; EntryPoint = ''; RetroWfcPayloadUri = '' } $section = '' $inputKey = '' @@ -112,6 +112,8 @@ function Get-MkwProjectPins([string]$ProjectFile) { if ($section -eq 'inputs' -and $line -match '^\s{2}([A-Za-z0-9_]+):\s*$') { $inputKey = $Matches[1]; continue } if ($section -eq 'project' -and $line -match '^\s*game_id:\s*(\S+)\s*$') { $pins.GameId = $Matches[1] + } elseif ($section -eq 'project' -and $line -match '^\s*region:\s*(\S+)\s*$') { + $pins.Region = $Matches[1] } elseif ($section -eq 'inputs' -and $line -match '^\s*sha256:\s*([0-9a-fA-F]{64})\s*$') { if ($inputKey -eq 'dol') { $pins.DolSha256 = $Matches[1].ToLowerInvariant() } elseif ($inputKey -eq 'rel') { $pins.RelSha256 = $Matches[1].ToLowerInvariant() } @@ -130,6 +132,30 @@ function Get-MkwProjectPins([string]$ProjectFile) { return $pins } +function Resolve-MkwProjectForAssets([string]$Workspace, [string]$AssetsDirectory) { + <# + The translation project pinned to the main.dol in AssetsDirectory, after checking that + StaticR.rel and any extracted disc data belong to the same release. + #> + $dolSha = Get-MkwFileSha256 (Join-Path $AssetsDirectory 'main.dol') + foreach ($file in Get-ChildItem -LiteralPath (Join-Path $Workspace 'projects') -Filter 'recomp.yml' -Recurse -File) { + $pins = Get-MkwProjectPins $file.FullName + if ($pins.DolSha256 -ne $dolSha) { continue } + if ((Get-MkwFileSha256 (Join-Path $AssetsDirectory 'StaticR.rel')) -ne $pins.RelSha256) { + throw "StaticR.rel does not match the clean $($pins.GameId) release of main.dol." + } + $bootBin = Join-Path $AssetsDirectory 'DATA\sys\boot.bin' + if (Test-Path -LiteralPath $bootBin -PathType Leaf) { + $discId = [Text.Encoding]::ASCII.GetString([IO.File]::ReadAllBytes($bootBin), 0, 6) + if ($discId -ne $pins.GameId) { + throw "The extracted game data is $discId but main.dol is $($pins.GameId); extract the game again." + } + } + return [pscustomobject]@{ Path = $file.FullName; Pins = $pins } + } + throw "main.dol (sha256 $dolSha) is not a supported clean Mario Kart Wii release." +} + function Invoke-Checked([string]$FilePath, [string[]]$Arguments, [string]$Description, [string]$LogPrefix = 'MKWCBUILD', [string]$StepId = '', [bool]$WaitForProcessTree = $true) { <# @@ -153,8 +179,15 @@ function Invoke-Checked([string]$FilePath, [string[]]$Arguments, [string]$Descri -NoNewWindow -Wait -PassThru $exitCode = $process.ExitCode } else { - & $FilePath @Arguments - $exitCode = $LASTEXITCODE + # Tools report progress on stderr (CMake message()); only the exit code decides failure. + $previousPreference = $ErrorActionPreference + $ErrorActionPreference = 'Continue' + try { + & $FilePath @Arguments + $exitCode = $LASTEXITCODE + } finally { + $ErrorActionPreference = $previousPreference + } } $global:LASTEXITCODE = $exitCode if ($exitCode -ne 0) { throw "$Description failed with exit code $exitCode." } diff --git a/Launcher/Prepare-Dependencies.ps1 b/Launcher/Prepare-Dependencies.ps1 index 18a8e9a..227f974 100644 --- a/Launcher/Prepare-Dependencies.ps1 +++ b/Launcher/Prepare-Dependencies.ps1 @@ -21,35 +21,45 @@ $auroraExtern = Join-Path $repoRoot 'aurora-main\extern\CMakeLists.txt' $auroraDawn = Join-Path $repoRoot 'aurora-main\cmake\AuroraDawnProvider.cmake' $auroraLibUsb = Join-Path $repoRoot 'aurora-main\cmake\AuroraLibUSB.cmake' $auroraSdl = Join-Path $repoRoot 'aurora-main\cmake\AuroraSDL3Provider.cmake' +$auroraVersions = Join-Path $repoRoot 'aurora-main\cmake\AuroraDependencyVersions.cmake' +$auroraImgui = Join-Path $repoRoot 'aurora-main\cmake\AuroraDearImguiProvider.cmake' +if (-not (Test-Path -LiteralPath $auroraCMake -PathType Leaf)) { + throw 'Aurora sources are missing. Run git submodule update --init --recursive from the repository root first.' +} # Name = directory under the destination; FetchContent maps it back through # FETCHCONTENT_SOURCE_DIR_ (NativeBuildFlags.ps1), so the names are the declared # FetchContent names, not the upstream project names. $packages = @( [pscustomobject]@{ - Name = 'SDL'; File = 'SDL3-3.4.4.tar.gz' - Uris = @('https://github.com/libsdl-org/SDL/releases/download/release-3.4.4/SDL3-3.4.4.tar.gz') - Pins = @(@{ File = $auroraCMake; Text = 'set(AURORA_SDL3_VERSION "3.4.4"' }, - @{ File = $auroraSdl; Text = 'releases/download/release-${AURORA_SDL3_VERSION}/SDL3-${AURORA_SDL3_VERSION}.tar.gz' }) + Name = 'SDL'; File = 'SDL3-3.4.10.tar.gz' + Sha256 = '12b34280415ec8418c864408b93d008a20a6530687ee613d60bfbd20411f2785' + Uris = @('https://github.com/libsdl-org/SDL/releases/download/release-3.4.10/SDL3-3.4.10.tar.gz') + Pins = @(@{ File = $auroraVersions; Text = '_aurora_dependency_version(AURORA_SDL3_REF "refs/tags/release-3.4.10"' }, + @{ File = $auroraSdl; Text = 'URL "https://github.com/libsdl-org/SDL/archive/${AURORA_SDL3_REF}.tar.gz"' }) }, [pscustomobject]@{ Name = 'abseil-cpp'; File = 'abseil-cpp-20240722.0.tar.gz' + Sha256 = 'f50e5ac311a81382da7fa75b97310e4b9006474f9560ac46f54a9967f07d4ae3' Uris = @('https://github.com/abseil/abseil-cpp/archive/refs/tags/20240722.0.tar.gz') Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/abseil/abseil-cpp/archive/refs/tags/20240722.0.tar.gz' }) }, [pscustomobject]@{ - Name = 'dawn_prebuilt'; File = 'dawn-v20260603.191052-windows-amd64.tar.gz' - Uris = @('https://github.com/theofficialgman/dawn-build/releases/download/v20260603.191052/dawn-windows-amd64.tar.gz') - Pins = @(@{ File = $auroraCMake; Text = 'set(AURORA_DAWN_VERSION "v20260603.191052"' }, - @{ File = $auroraDawn; Text = 'SHA256=13be9cff8b9b179c42dcd16aeabb6effcc8f0dfdcc14463eda2a5caeda225142' }) + Name = 'dawn_prebuilt'; File = 'dawn-v20260807.225922-windows-amd64.tar.gz' + Sha256 = '42a7a295c87b2e8a36312e2f84a5823aac63325e8e1d271bc7ced6f83bfb075f' + Uris = @('https://github.com/encounter/dawn/releases/download/v20260807.225922/dawn-windows-amd64.tar.gz') + Pins = @(@{ File = $auroraVersions; Text = '_aurora_dependency_version(AURORA_DAWN_VERSION "v20260807.225922"' }, + @{ File = $auroraDawn; Text = 'SHA256=42a7a295c87b2e8a36312e2f84a5823aac63325e8e1d271bc7ced6f83bfb075f' }) }, [pscustomobject]@{ - Name = 'fmt'; File = 'fmt-11.1.4.tar.gz' - Uris = @('https://github.com/fmtlib/fmt/archive/refs/tags/11.1.4.tar.gz') - Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/fmtlib/fmt/archive/refs/tags/11.1.4.tar.gz' }) + Name = 'fmt'; File = 'fmt-12.1.0.tar.gz' + Sha256 = 'ea7de4299689e12b6dddd392f9896f08fb0777ac7168897a244a6d6085043fea' + Uris = @('https://github.com/fmtlib/fmt/archive/refs/tags/12.1.0.tar.gz') + Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/fmtlib/fmt/archive/refs/tags/12.1.0.tar.gz' }) }, [pscustomobject]@{ Name = 'freetype'; File = 'freetype-2.14.3.tar.gz' + Sha256 = 'e61b31ab26358b946e767ed7eb7f4bb2e507da1cfefeb7a8861ace7fd5c899a1' Uris = @('https://files.twilitrealm.dev/freetype-2.14.3.tar.gz', 'https://download.savannah.gnu.org/releases/freetype/freetype-2.14.3.tar.gz', 'https://downloads.sourceforge.net/project/freetype/freetype2/2.14.3/freetype-2.14.3.tar.gz') @@ -57,42 +67,50 @@ $packages = @( }, [pscustomobject]@{ Name = 'imgui'; File = 'imgui-1.91.9b-docking.tar.gz' + Sha256 = '466fdef9b18de15f0bb6e288e3d00ffa3d82200ec458ce5e4f724a161d9528a5' Uris = @('https://github.com/ocornut/imgui/archive/refs/tags/v1.91.9b-docking.tar.gz') - Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/ocornut/imgui/archive/refs/tags/v1.91.9b-docking.tar.gz' }) + Pins = @(@{ File = $auroraImgui; Text = 'https://github.com/ocornut/imgui/archive/refs/tags/v1.91.9b-docking.tar.gz' }) }, [pscustomobject]@{ Name = 'libusb'; File = 'libusb-1.0.30.tar.bz2' + Sha256 = 'fea36f34f9156400209595e300840767ab1a385ede1dc7ee893015aea9c6dbaf' Uris = @('https://github.com/libusb/libusb/releases/download/v1.0.30/libusb-1.0.30.tar.bz2') - Pins = @(@{ File = $auroraCMake; Text = 'set(AURORA_LIBUSB_VERSION "1.0.30"' }, + Pins = @(@{ File = $auroraVersions; Text = '_aurora_dependency_version(AURORA_LIBUSB_VERSION "1.0.30"' }, @{ File = $auroraLibUsb; Text = 'releases/download/v${AURORA_LIBUSB_VERSION}/libusb-${AURORA_LIBUSB_VERSION}.tar.bz2' }) }, [pscustomobject]@{ Name = 'png'; File = 'libpng-1.6.58.tar.gz' + Sha256 = 'a9d4df463d36a6e5f9c29bd6f4967312d17e996c1854f3511f833924eb1993cf' Uris = @('https://github.com/pnggroup/libpng/archive/refs/tags/v1.6.58.tar.gz') Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/pnggroup/libpng/archive/refs/tags/v1.6.58.tar.gz' }) }, [pscustomobject]@{ Name = 'sqlite3'; File = 'sqlite-amalgamation-3510300.zip' + Sha256 = 'acb1e6f5d832484bf6d32b681e858c38add8b2acdfd42ac5df24b8afb46552b4' Uris = @('https://sqlite.org/2026/sqlite-amalgamation-3510300.zip') Pins = @(@{ File = $auroraExtern; Text = 'https://sqlite.org/2026/sqlite-amalgamation-3510300.zip' }) }, [pscustomobject]@{ - Name = 'tracy'; File = 'tracy-a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz' - Uris = @('https://github.com/wolfpld/tracy/archive/a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz') - Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/wolfpld/tracy/archive/a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz' }) + Name = 'tracy'; File = 'tracy-0.14.1.zip' + Sha256 = '908f3a2917fa86a247abfcf85dcf04bad1db6986a4d40f94b70512f3e9e98d5b' + Uris = @('https://github.com/wolfpld/tracy/archive/refs/tags/v0.14.1.zip') + Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/wolfpld/tracy/archive/refs/tags/v0.14.1.zip' }) }, [pscustomobject]@{ Name = 'xxhash'; File = 'xxHash-0.8.4.tar.gz' + Sha256 = '5738270935e7c3d38a79b3adf7c9692566ce7895a25f67de43ad52ab504acd32' Uris = @('https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.4.tar.gz') Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.4.tar.gz' }) }, [pscustomobject]@{ - Name = 'zlib'; File = 'zlib-1.3.2.tar.gz' - Uris = @('https://github.com/madler/zlib/releases/download/v1.3.2/zlib-1.3.2.tar.gz') - Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/madler/zlib/releases/download/v1.3.2/zlib-1.3.2.tar.gz' }) + Name = 'zlib'; File = 'zlib-ng-2.3.3.tar.gz' + Sha256 = 'f9c65aa9c852eb8255b636fd9f07ce1c406f061ec19a2e7d508b318ca0c907d1' + Uris = @('https://github.com/zlib-ng/zlib-ng/archive/refs/tags/2.3.3.tar.gz') + Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/zlib-ng/zlib-ng/archive/refs/tags/2.3.3.tar.gz' }) }, [pscustomobject]@{ Name = 'zstd'; File = 'zstd-1.5.7.tar.gz' + Sha256 = 'eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3' Uris = @('https://github.com/facebook/zstd/releases/download/v1.5.7/zstd-1.5.7.tar.gz') Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/facebook/zstd/releases/download/v1.5.7/zstd-1.5.7.tar.gz' }) } @@ -101,6 +119,7 @@ $packages = @( # The C++/WinRT compiler (NuGet package = zip) that generates the projection headers. $cppWinRtTool = [pscustomobject]@{ Name = 'cppwinrt-tool'; File = 'Microsoft.Windows.CppWinRT.3.0.260818.1.nupkg' + Sha256 = 'a8993608ae9263a8288e1a1d9ee2684a5632f4acc59e1e89ddd86b3b889a7367' Uris = @('https://www.nuget.org/api/v2/package/Microsoft.Windows.CppWinRT/3.0.260818.1') Pins = @() } @@ -123,11 +142,20 @@ function Assert-Pinned($Package) { } } +function Get-Sha256([string]$Path) { (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant() } + +# Every archive this returns, cached or downloaded, matches its pinned Sha256. function Get-Archive($Package) { $archive = Join-Path $downloads $Package.File - if (Test-Path -LiteralPath $archive -PathType Leaf) { return $archive } + if (Test-Path -LiteralPath $archive -PathType Leaf) { + $actual = Get-Sha256 $archive + if ($actual -eq $Package.Sha256) { return $archive } + Write-Warning "$($Package.Name): cached $archive has SHA-256 $actual, expected $($Package.Sha256); discarding it and downloading again." + Remove-Item -LiteralPath $archive -Force + } $temporary = $archive + '.partial' $failures = @() + $mismatch = $false foreach ($uri in $Package.Uris) { Remove-Item -LiteralPath $temporary -Force -ErrorAction SilentlyContinue Write-Host "Downloading $($Package.Name) from $uri..." @@ -137,11 +165,21 @@ function Get-Archive($Package) { $failures += "$uri ($($_.Exception.Message))" continue } + $actual = Get-Sha256 $temporary + if ($actual -ne $Package.Sha256) { + $failures += "$uri (SHA-256 $actual, expected $($Package.Sha256))" + $mismatch = $true + continue + } Move-Item -LiteralPath $temporary -Destination $archive -Force return $archive } Remove-Item -LiteralPath $temporary -Force -ErrorAction SilentlyContinue - throw "$($Package.Name) could not be fetched: $($failures -join '; ')" + $hint = '' + if ($mismatch) { + $hint = ' If upstream republished this archive, check the new file against an upstream-published checksum before updating its Sha256 in Prepare-Dependencies.ps1.' + } + throw "$($Package.Name) could not be fetched: $($failures -join '; ').$hint" } function Expand-Package([string]$Archive, [string]$Target) { @@ -165,21 +203,34 @@ function Expand-Package([string]$Archive, [string]$Target) { if (Test-Path -LiteralPath $extract) { Remove-Item -LiteralPath $extract -Recurse -Force } } +# Records which archive a tree came from, so a pin change replaces a stale tree. +function Get-Stamp($Package) { "$($Package.File) $($Package.Sha256)" } + +function Test-Stamp([string]$Target, [string]$Text) { + $stamp = $Target + '.source' + (Test-Path -LiteralPath $stamp -PathType Leaf) -and ([IO.File]::ReadAllText($stamp) -eq $Text) +} + +function Install-Package($Package, [string]$Target, [string]$RequiredFile) { + $ready = if ($RequiredFile) { Test-Path -LiteralPath $RequiredFile -PathType Leaf } else { Test-Path -LiteralPath $Target -PathType Container } + if ($ready -and (Test-Stamp $Target (Get-Stamp $Package))) { return } + Expand-Package (Get-Archive $Package) $Target + [IO.File]::WriteAllText($Target + '.source', (Get-Stamp $Package)) + Write-Host "Prepared $($Package.Name)" +} + foreach ($package in $packages) { Assert-Pinned $package - $target = Join-Path $Destination $package.Name - if (Test-Path -LiteralPath $target -PathType Container) { continue } - Expand-Package (Get-Archive $package) $target - Write-Host "Prepared $($package.Name)" + Install-Package $package (Join-Path $Destination $package.Name) } $cppWinRt = Join-Path $Destination 'cppwinrt' -if (-not (Test-Path -LiteralPath (Join-Path $cppWinRt 'winrt\base.h') -PathType Leaf)) { +$cppWinRtCurrent = (Test-Path -LiteralPath (Join-Path $cppWinRt 'winrt\base.h') -PathType Leaf) -and + (Test-Stamp $cppWinRt (Get-Stamp $cppWinRtTool)) +if (-not $cppWinRtCurrent) { $toolRoot = Join-Path $PSScriptRoot 'artifacts\cppwinrt-tool' $compiler = Join-Path $toolRoot 'bin\cppwinrt.exe' - if (-not (Test-Path -LiteralPath $compiler -PathType Leaf)) { - Expand-Package (Get-Archive $cppWinRtTool) $toolRoot - } + Install-Package $cppWinRtTool $toolRoot $compiler if (-not (Test-Path -LiteralPath $compiler -PathType Leaf)) { throw "cppwinrt.exe is missing: $compiler" } if (Test-Path -LiteralPath $cppWinRt) { Remove-Item -LiteralPath $cppWinRt -Recurse -Force } [IO.Directory]::CreateDirectory($cppWinRt) | Out-Null @@ -190,6 +241,7 @@ if (-not (Test-Path -LiteralPath (Join-Path $cppWinRt 'winrt\base.h') -PathType throw "cppwinrt.exe produced no winrt\base.h under $cppWinRt" } Copy-Item -LiteralPath (Join-Path $toolRoot 'LICENSE') -Destination (Join-Path $cppWinRt 'LICENSE.txt') + [IO.File]::WriteAllText($cppWinRt + '.source', (Get-Stamp $cppWinRtTool)) Write-Host 'Prepared cppwinrt' } diff --git a/Launcher/Prepare-NativePrebuilt.sh b/Launcher/Prepare-NativePrebuilt.sh index ebe7050..ed3b7c1 100755 --- a/Launcher/Prepare-NativePrebuilt.sh +++ b/Launcher/Prepare-NativePrebuilt.sh @@ -118,7 +118,7 @@ fingerprint_tree() { local root=$1; shift root=$(normalize "$root") [[ -d "$root" ]] || return 0 - local find_args=("$root") + local find_args=("$root" -name .git -prune -o) local ex for ex in "$@"; do find_args+=(-path "$root/$ex" -prune -o); done find_args+=(-type f -print) diff --git a/Launcher/Test-PinnedFacts.ps1 b/Launcher/Test-PinnedFacts.ps1 index 5280993..d88867a 100644 --- a/Launcher/Test-PinnedFacts.ps1 +++ b/Launcher/Test-PinnedFacts.ps1 @@ -1,7 +1,8 @@ # Fails the release build when a fact duplicated across the repo stops agreeing with the copy -# that owns it (recomp.yml). Scripts read pinned facts through Get-MkwProjectPins, but three -# consumers can't read YAML (the C++ runtime header, the C# constants, shell scripts, and hand-written lists on -# both sides of the C#/PowerShell boundary), so those are checked here instead. +# that owns it (each projects/*/recomp.yml). Scripts read pinned facts through Get-MkwProjectPins +# or build-cache.sh's mkw_project_pin, but some consumers can't read YAML (the C++ runtime header, +# the C# Retro-WFC table, and hand-written lists on both sides of the C#/PowerShell boundary), so +# those are checked here instead. [CmdletBinding()] param([string]$RepositoryRoot) @@ -46,32 +47,36 @@ function Compare-Set([string[]]$Expected, [string[]]$Actual, [string]$ExpectedNa if ($extra.Count -gt 0) { Add-Failure "$ActualName has entries $ExpectedName does not: $($extra -join ', ')." } } -$pins = Get-MkwProjectPins (Join-Path $repoRoot 'projects\mkwii\recomp.yml') +# Every supported release is one projects//recomp.yml, the same set Build-Installer.ps1 ships. +$releases = @(Get-ChildItem -LiteralPath (Join-Path $repoRoot 'projects') -Directory | Sort-Object Name | + ForEach-Object { Join-Path $_.FullName 'recomp.yml' } | Where-Object { Test-Path -LiteralPath $_ -PathType Leaf } | + ForEach-Object { $pins = Get-MkwProjectPins $_; $pins.Project = $_; [pscustomobject]$pins }) +if ($releases.Count -eq 0) { throw 'No projects/*/recomp.yml was found; update Test-PinnedFacts.ps1.' } -# --- The Retro-WFC endpoint: recomp.yml owns it; the installer host pins the same string so a -# --- redirected or rewritten endpoint cannot be fetched from. The literal lives in -# --- WiiCompiled.Setup.Common (shared with WiiCompiled.Setup.Linux) - InputValidation.cs only -# --- re-exports it as `= RetroWfcPayload.CurrentRetroWfcPayloadUri;`, no literal to capture there. +# --- The Retro-WFC endpoints: each recomp.yml owns its release's; the host derives the same URL +# --- from its game table so a redirected or rewritten endpoint cannot be fetched from. $retroWfcPayload = Read-SourceFile (Join-Path $common 'RetroWfcPayload.cs') 'RetroWfcPayload.cs' -$hostUri = Get-CapturedValue $retroWfcPayload 'CurrentRetroWfcPayloadUri\s*=\s*"([^"]+)"' ` - 'The host Retro-WFC endpoint constant' -if ($hostUri -cne $pins.RetroWfcPayloadUri) { - Add-Failure "InputValidation.CurrentRetroWfcPayloadUri is '$hostUri' but recomp.yml pins '$($pins.RetroWfcPayloadUri)'." +$payloadGames = @{} +foreach ($entry in [regex]::Matches((Get-CapturedValue $retroWfcPayload ` + '(?s)PayloadGames\s*=\s*new\([^)]*\)\s*\{(.*?)\};' 'The host Retro-WFC game table'), + '\["([^"]+)"\]\s*=\s*"([^"]+)"')) { + $payloadGames[$entry.Groups[1].Value] = $entry.Groups[2].Value } -$macosSetup = Read-SourceFile (Join-Path $launcher 'macos\setup.command') 'macOS setup.command' -$macosUri = Get-CapturedValue $macosSetup "'([^']*/api/wfc/payload\?g=RMCPD00)'" ` - 'The macOS Retro-WFC endpoint' -if ($macosUri -cne $pins.RetroWfcPayloadUri) { - Add-Failure "macOS setup.command downloads '$macosUri' but recomp.yml pins '$($pins.RetroWfcPayloadUri)'." +$uriTemplate = Get-CapturedValue $retroWfcPayload 'PayloadUri\(string gameId\)\s*=>\s*\$"([^"]+)"' ` + 'The host Retro-WFC endpoint template' +Compare-Set ([string[]]@($releases.GameId)) ([string[]]@($payloadGames.Keys)) ` + 'projects/*/recomp.yml' 'RetroWfcPayload.PayloadGames' +foreach ($release in $releases) { + if (-not $payloadGames.ContainsKey($release.GameId)) { continue } + $hostUri = $uriTemplate.Replace('{PayloadGame(gameId)}', $payloadGames[$release.GameId]) + if ($hostUri -cne $release.RetroWfcPayloadUri) { + Add-Failure "RetroWfcPayload.PayloadUri($($release.GameId)) is '$hostUri' but $($release.Project) pins '$($release.RetroWfcPayloadUri)'." + } } - -# --- The game identity: the manifest carries it, but the host also compiles a fallback for a -# --- manifest that predates the field, and that fallback decides which disc is accepted. -$models = Read-SourceFile (Join-Path $setup 'Models.cs') 'Models.cs' -$hostGameId = Get-CapturedValue $models 'ExpectedGameId\s*\{\s*get;\s*set;\s*\}\s*=\s*"([^"]+)"' ` - 'The host expected game id' -if ($hostGameId -cne $pins.GameId) { - Add-Failure "PayloadManifest.ExpectedGameId defaults to '$hostGameId' but recomp.yml pins '$($pins.GameId)'." +foreach ($key in @('GameId', 'DolSha256')) { + foreach ($duplicate in @($releases | Group-Object $key | Where-Object Count -gt 1)) { + Add-Failure "Several projects pin the same $($key) $($duplicate.Name)." + } } # --- The translation entry point: the translator is told it by LocalBuild.ps1 (which reads @@ -79,8 +84,10 @@ if ($hostGameId -cne $pins.GameId) { $systemBridge = Read-SourceFile (Join-Path $repoRoot 'runtime\include\system_bridge.h') 'system_bridge.h' $runtimeEntry = (Get-CapturedValue $systemBridge 'kDefaultEntryAddress\s*=\s*(0[xX][0-9a-fA-F]+)' ` 'The runtime default entry address').ToLowerInvariant() -if ($runtimeEntry -ne $pins.EntryPoint) { - Add-Failure "system_bridge.h enters at $runtimeEntry but recomp.yml translates from $($pins.EntryPoint)." +foreach ($release in $releases) { + if ($runtimeEntry -ne $release.EntryPoint) { + Add-Failure "system_bridge.h enters at $runtimeEntry but $($release.Project) translates from $($release.EntryPoint)." + } } # --- The pinned dependency set: Build-Installer.ps1 stages it, the installed host requires it. @@ -137,6 +144,6 @@ Compare-Set $knownSteps $emittedSteps 'BuildStepIds' 'the steps LocalBuild.ps1 e if ($failures.Count -gt 0) { throw "Pinned facts disagree between their copies:`n $($failures -join "`n ")" } -Write-Host ("Pinned-fact audit passed: game {0}, entry {1}, endpoint {2}; dependency, runtime-asset, " -f - $pins.GameId, $pins.EntryPoint, $pins.RetroWfcPayloadUri) -NoNewline +Write-Host ("Pinned-fact audit passed: games {0}, entry {1}; Retro-WFC endpoint, dependency, runtime-asset, " -f + ($releases.GameId -join ', '), $runtimeEntry) -NoNewline Write-Host 'build-step, and build-script parameter contracts all agree.' diff --git a/Launcher/Test-Recompilation.ps1 b/Launcher/Test-Recompilation.ps1 index 789e4dd..6d06cf8 100644 --- a/Launcher/Test-Recompilation.ps1 +++ b/Launcher/Test-Recompilation.ps1 @@ -5,7 +5,8 @@ param( [string]$PortableToolsDirectory = 'Launcher/artifacts/portable-tools', [string]$DependencySourceDirectory = 'Launcher/artifacts/dependencies', [string]$StageDirectory = 'build/recomp-test', - [ValidateRange(1, 64)] [int]$Parallel = 3 + [ValidateRange(1, 64)] [int]$Parallel = 3, + [ValidateSet('v2', 'v3')] [string]$X86CpuProfile = 'v3' ) $ErrorActionPreference = 'Stop' @@ -36,8 +37,17 @@ Write-Host "Synthetic recompilation workspace: $stage" # Copy current sources, including uncommitted edits, but no ignored build output. # An isolated workspace preserves the developer's real generated/ directory. -$sourceFiles = & git -C $repoRoot -c core.quotepath=false ls-files --cached --others --exclude-standard -- runtime aurora-main -if ($LASTEXITCODE -ne 0) { throw 'Could not enumerate runtime and Aurora sources.' } +$auroraRoot = Join-Path $repoRoot 'aurora-main' +if (-not (Test-Path -LiteralPath (Join-Path $auroraRoot '.git'))) { + throw 'Aurora submodule is not initialized. Run git submodule update --init --recursive first.' +} +# The parent tracks Aurora as one gitlink; enumerate its repository separately. +# Retain untracked source files so local development edits are still tested. +$sourceFiles = @(& git -C $repoRoot -c core.quotepath=false ls-files --cached --others --exclude-standard -- runtime) +if ($LASTEXITCODE -ne 0) { throw 'Could not enumerate runtime sources.' } +$auroraFiles = @(& git -C $auroraRoot -c core.quotepath=false ls-files --cached --others --exclude-standard) +if ($LASTEXITCODE -ne 0) { throw 'Could not enumerate Aurora sources.' } +$sourceFiles += @($auroraFiles | ForEach-Object { "aurora-main/$_" }) foreach ($relative in $sourceFiles | Sort-Object -Unique) { $destination = Join-Path $stage $relative [IO.Directory]::CreateDirectory([IO.Path]::GetDirectoryName($destination)) | Out-Null @@ -45,15 +55,10 @@ foreach ($relative in $sourceFiles | Sort-Object -Unique) { } # One synthetic text section: li r3,40; addi r3,r3,2; nop; blr. -# Native HLE wrappers also call these eight guest symbols directly. Give each -# its own generated blr function so the real product can link without game code. -# Keep this list explicit: a new unresolved guest dependency must fail the test. +# Guest functions the runtime calls directly resolve through the registry at run time, so the +# product links without any game code. [uint32]$entry = 0x80001000L -[uint32[]]$guestCallbacks = @( - 0x8012B830L, 0x801A0620L, 0x801A1ED8L, 0x801A961CL, - 0x801AADE0L, 0x801D8D30L, 0x801D9E94L, 0x8055531CL -) -$textSize = [int]($guestCallbacks[-1] - $entry + 4) +$textSize = 0x10 $dataOffset = 0x100 + $textSize $dol = [byte[]]::new($dataOffset + 4) function Write-BigEndian32([int]$Offset, [uint32]$Value) { @@ -64,7 +69,7 @@ function Write-BigEndian32([int]$Offset, [uint32]$Value) { } Write-BigEndian32 0x00 0x100 # text[0] file offset Write-BigEndian32 0x48 $entry # text[0] guest address -Write-BigEndian32 0x90 $textSize # text[0] length (unreachable gaps are zero) +Write-BigEndian32 0x90 $textSize # text[0] length Write-BigEndian32 0x1C $dataOffset # data[0] file offset Write-BigEndian32 0x64 0x80600000L # data[0] guest address Write-BigEndian32 0xAC 4 # data[0] length @@ -75,13 +80,10 @@ Write-BigEndian32 0x100 0x38600028 # li r3,40 Write-BigEndian32 0x104 0x38630002 # addi r3,r3,2 Write-BigEndian32 0x108 0x60000000 # nop Write-BigEndian32 0x10C 0x4E800020 # blr -foreach ($address in $guestCallbacks) { - Write-BigEndian32 ([int](0x100 + $address - $entry)) 0x4E800020 -} Write-BigEndian32 $dataOffset 0x12345678 [IO.File]::WriteAllBytes((Join-Path $stage 'synthetic.dol'), $dol) -$entryPoints = (@($entry) + $guestCallbacks | ForEach-Object { '0x{0:X8}' -f $_ }) -join ', ' -$functionMap = (@($entry) + $guestCallbacks | ForEach-Object { '{0:X8} func_{0:X8}' -f $_ }) -join "`n" +$entryPoints = '0x{0:X8}' -f $entry +$functionMap = '{0:X8} func_{0:X8}' -f $entry [IO.File]::WriteAllText((Join-Path $stage 'synthetic-functions.txt'), $functionMap) $manifest = Join-Path $stage 'recomp.yml' [IO.File]::WriteAllText($manifest, @" @@ -119,7 +121,7 @@ Invoke-Checked $dotnet @($translator, 'translate-recursive', '0x80001000', '--pr 'Translating the synthetic DOL' # Function-map seeds can be skipped by discovery; do not accept a partial fixture. $translated = Get-Content -LiteralPath $metadata -Raw | ConvertFrom-Json -foreach ($address in @($entry) + $guestCallbacks) { +foreach ($address in @($entry)) { if ($address -notin $translated.functions.entryPoint) { throw ('Synthetic function 0x{0:X8} was not translated.' -f $address) } @@ -135,7 +137,7 @@ try { -Ninja $ninja -CCompiler (Join-Path $compilerBin 'x86_64-w64-mingw32-clang.exe') ` -CxxCompiler (Join-Path $compilerBin 'x86_64-w64-mingw32-clang++.exe') ` -ResourceCompiler (Join-Path $compilerBin 'x86_64-w64-mingw32-windres.exe') ` - -DependenciesDirectory $dependencies -AdditionalArguments @('-DMKW_BUILD_PRODUCTS=ON') + -DependenciesDirectory $dependencies -AdditionalArguments @('-DMKW_BUILD_PRODUCTS=ON', "-DMKW_X86_CPU_PROFILE=$X86CpuProfile") Invoke-Checked $cmake $configure 'Configuring the production Windows runtime' ` -WaitForProcessTree $false Invoke-Checked $cmake @('--build', $nativeBuild, '--target', 'WiiCompiled', '--parallel', "$Parallel") ` diff --git a/Launcher/WiiCompiled.Setup.Common/HostCpuRequirement.cs b/Launcher/WiiCompiled.Setup.Common/HostCpuRequirement.cs new file mode 100644 index 0000000..fc8c45c --- /dev/null +++ b/Launcher/WiiCompiled.Setup.Common/HostCpuRequirement.cs @@ -0,0 +1,99 @@ +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; + +namespace WiiCompiled.Setup.Common; + +public enum X86CpuProfile +{ + V2, + V3 +} + +// Setup-time copy of runtime/src/host_cpu_baseline.cpp, checked before anything is built. +public static class HostCpuRequirement +{ + private readonly record struct Feature(string Name, uint Leaf, int Register, int Bit, X86CpuProfile Profile); + + // Same table and order as the runtime: register 0..3 = eax, ebx, ecx, edx. + private static readonly Feature[] Features = + [ + new("SSE3", 1, 2, 0, X86CpuProfile.V2), + new("SSSE3", 1, 2, 9, X86CpuProfile.V2), + new("CMPXCHG16B", 1, 2, 13, X86CpuProfile.V2), + new("SSE4.1", 1, 2, 19, X86CpuProfile.V2), + new("SSE4.2", 1, 2, 20, X86CpuProfile.V2), + new("POPCNT", 1, 2, 23, X86CpuProfile.V2), + new("LAHF-SAHF", 0x80000001u, 2, 0, X86CpuProfile.V2), + new("FMA", 1, 2, 12, X86CpuProfile.V3), + new("MOVBE", 1, 2, 22, X86CpuProfile.V3), + new("OSXSAVE", 1, 2, 27, X86CpuProfile.V3), + new("AVX", 1, 2, 28, X86CpuProfile.V3), + new("F16C", 1, 2, 29, X86CpuProfile.V3), + new("BMI1", 7, 1, 3, X86CpuProfile.V3), + new("AVX2", 7, 1, 5, X86CpuProfile.V3), + new("BMI2", 7, 1, 8, X86CpuProfile.V3), + new("LZCNT", 0x80000001u, 2, 5, X86CpuProfile.V3), + ]; + + public static void EnsureSupported(X86CpuProfile profile) + { + if (RuntimeInformation.ProcessArchitecture != Architecture.X64) + return; + + // The JIT only reports AVX when the OS also saves the YMM state (XCR0), which is the + // runtime's last check; there is no managed XGETBV. + var missing = FindMissingFeatures(profile, CpuId, Avx.IsSupported); + if (missing.Count > 0) + throw new PlatformNotSupportedException(Describe(profile, missing)); + } + + // The highest profile this machine runs; builds fall back to v2 when v3 is missing. + public static X86CpuProfile SelectBuildProfile() => + RuntimeInformation.ProcessArchitecture != Architecture.X64 + ? X86CpuProfile.V3 + : SelectBuildProfile(CpuId, Avx.IsSupported); + + public static X86CpuProfile SelectBuildProfile(Func cpuid, bool osSavesAvxState) => + FindMissingFeatures(X86CpuProfile.V3, cpuid, osSavesAvxState).Count == 0 + ? X86CpuProfile.V3 + : X86CpuProfile.V2; + + public static IReadOnlyList FindMissingFeatures(X86CpuProfile profile, + Func cpuid, bool osSavesAvxState) + { + var maxBasic = cpuid(0)[0]; + var maxExtended = cpuid(0x80000000u)[0]; + var missing = new List(); + foreach (var feature in Features) + { + if (feature.Profile > profile) + continue; + var leafAvailable = (feature.Leaf & 0x80000000u) != 0 + ? feature.Leaf <= maxExtended + : feature.Leaf <= maxBasic; + if (!leafAvailable || (cpuid(feature.Leaf)[feature.Register] & (1u << feature.Bit)) == 0) + missing.Add(feature.Name); + } + + if (missing.Count == 0 && profile >= X86CpuProfile.V3 && !osSavesAvxState) + missing.Add("operating system support for AVX register state (XCR0 YMM bits)"); + return missing; + } + + public static string Describe(X86CpuProfile profile, IReadOnlyList missing) => + profile == X86CpuProfile.V2 + ? "This build needs a processor that supports the x86-64-v2 instruction set.\n\n" + + "Missing on this machine: " + string.Join(", ", missing) + "\n\n" + + "x86-64-v2 covers Intel Core processors from Nehalem (2008) onward and AMD processors " + + "from Jaguar (2013) onward." + : "This build needs a processor that supports the x86-64-v3 instruction set.\n\n" + + "Missing on this machine: " + string.Join(", ", missing) + "\n\n" + + "x86-64-v3 covers Intel Core processors from Haswell (4th generation, 2013) onward " + + "and AMD processors from Excavator (2015) onward."; + + private static uint[] CpuId(uint leaf) + { + var (eax, ebx, ecx, edx) = X86Base.CpuId(unchecked((int)leaf), 0); + return [unchecked((uint)eax), unchecked((uint)ebx), unchecked((uint)ecx), unchecked((uint)edx)]; + } +} diff --git a/Launcher/WiiCompiled.Setup.Common/RetroWfcPayload.cs b/Launcher/WiiCompiled.Setup.Common/RetroWfcPayload.cs index 258fb85..482e0af 100644 --- a/Launcher/WiiCompiled.Setup.Common/RetroWfcPayload.cs +++ b/Launcher/WiiCompiled.Setup.Common/RetroWfcPayload.cs @@ -11,22 +11,39 @@ namespace WiiCompiled.Setup.Common; public sealed record RetroWfcPayloadSnapshot(string Directory, string Sha256, long ByteLength); /// -/// Downloads and verifies the Retro-WFC payload (a small, RSA-signed blob served from a single -/// fixed endpoint). Shared by both installers - moved here from WiiCompiled.Setup.Windows's -/// InputValidation.cs, which keeps every one of these method names as thin forwarding wrappers so -/// its many existing call sites (ProductRepairService.cs, LocalBuildService.cs, Installation.cs, -/// SelfTests.cs) needed no changes. +/// Downloads and verifies the Retro-WFC payload (a small, RSA-signed blob served from one fixed +/// endpoint per game release). Shared by both installers and the translator. /// public static class RetroWfcPayload { private const long MaximumRetroWfcPayloadBytes = 16L * 1024 * 1024; - // The payload is tens of kilobytes from a single fixed endpoint 30s is good. + // The payload is tens of kilobytes from a fixed regional endpoint; allow 30 seconds. private static readonly TimeSpan RetroWfcDownloadTimeout = TimeSpan.FromSeconds(30); private static readonly TimeSpan RetroWfcRetryDelay = TimeSpan.FromSeconds(1); - public const string CurrentRetroWfcPayloadUri = "https://rwfc.net/api/wfc/payload?g=RMCPD00"; - private static readonly string RetroWfcOfflinePayloadFile = - Path.Combine("binary", "payload.RMCPD00.bin"); + /// + /// Base game id to Retro-WFC payload game. Test-PinnedFacts.ps1 checks this table against the + /// retro_wfc_payload every projects/*/recomp.yml pins. + /// + private static readonly Dictionary PayloadGames = new(StringComparer.Ordinal) + { + ["RMCP01"] = "RMCPD00", + ["RMCE01"] = "RMCED00", + ["RMCJ01"] = "RMCJD00", + }; + + public static IReadOnlyCollection SupportedGameIds => PayloadGames.Keys; + + public static string PayloadGame(string gameId) => + PayloadGames.TryGetValue(gameId, out var payloadGame) + ? payloadGame + : throw new InvalidDataException($"Unsupported Retro-WFC base game '{gameId}'."); + + public static string PayloadRelativePath(string gameId) => + Path.Combine("binary", $"payload.{PayloadGame(gameId)}.bin"); + + public static string PayloadUri(string gameId) => + $"https://rwfc.net/api/wfc/payload?g={PayloadGame(gameId)}"; /// Retro-WFC production payload signing key (PROD PayloadPublicKey). Verifies /// the payload past the 0x110 header; on-console stage1 pins the same key, so @@ -45,47 +62,48 @@ public static class RetroWfcPayload private const int RetroWfcPayloadSignatureOffset = 0x10; private const int RetroWfcPayloadMinimumBytes = 0x130; - public static string ValidateStagedRetroWfcPayloadDirectory(string stagedDirectory, + public static string ValidateStagedRetroWfcPayloadDirectory(string stagedDirectory, string gameId, RSAParameters? signingKey = null) { if (string.IsNullOrWhiteSpace(stagedDirectory)) throw new InvalidDataException("The staged Retro-WFC payload directory is missing."); var root = Path.GetFullPath(stagedDirectory); - var payload = Path.Combine(root, RetroWfcOfflinePayloadFile); + var relativePath = PayloadRelativePath(gameId); + var payload = Path.Combine(root, relativePath); try { if ((File.GetAttributes(payload) & FileAttributes.Directory) != 0) throw new InvalidDataException( - "The staged Retro-WFC payload directory does not contain binary\\payload.RMCPD00.bin."); + $"The staged Retro-WFC payload directory does not contain {relativePath}."); } catch (FileNotFoundException) { throw new InvalidDataException( - "The staged Retro-WFC payload directory does not contain binary\\payload.RMCPD00.bin."); + $"The staged Retro-WFC payload directory does not contain {relativePath}."); } catch (DirectoryNotFoundException) { throw new InvalidDataException( - "The staged Retro-WFC payload directory does not contain binary\\payload.RMCPD00.bin."); + $"The staged Retro-WFC payload directory does not contain {relativePath}."); } - ValidateRetroWfcPayloadFile(payload, signingKey); + ValidateRetroWfcPayloadFile(payload, PayloadGame(gameId), signingKey); return root; } - public static string ResolveRetroWfcPayloadFile(string stagedDirectory, + public static string ResolveRetroWfcPayloadFile(string stagedDirectory, string gameId, RSAParameters? signingKey = null) => - Path.Combine(ValidateStagedRetroWfcPayloadDirectory(stagedDirectory, signingKey), - RetroWfcOfflinePayloadFile); + Path.Combine(ValidateStagedRetroWfcPayloadDirectory(stagedDirectory, gameId, signingKey), + PayloadRelativePath(gameId)); - public static string ComputeRetroWfcPayloadSha256(string stagedDirectory, + public static string ComputeRetroWfcPayloadSha256(string stagedDirectory, string gameId, RSAParameters? signingKey = null) => - Sha256File(ResolveRetroWfcPayloadFile(stagedDirectory, signingKey)); + Sha256File(ResolveRetroWfcPayloadFile(stagedDirectory, gameId, signingKey)); public static void ValidateRetroWfcPayloadUri(string uriText) { - if (!string.Equals(uriText, CurrentRetroWfcPayloadUri, StringComparison.Ordinal)) - throw new InvalidDataException("The installer does not define the fixed Retro-WFC payload endpoint."); + if (!PayloadGames.Keys.Any(gameId => string.Equals(uriText, PayloadUri(gameId), StringComparison.Ordinal))) + throw new InvalidDataException("The installer does not define this fixed Retro-WFC payload endpoint."); } public static async Task DownloadRetroWfcPayloadAsync(string uriText, @@ -96,7 +114,8 @@ public static class RetroWfcPayload var uri = new Uri(uriText, UriKind.Absolute); var root = Path.GetFullPath(destinationDirectory); - var destination = Path.Combine(root, RetroWfcOfflinePayloadFile); + var payloadGame = uri.Query[3..]; // ValidateRetroWfcPayloadUri accepts only the exact ?g= form. + var destination = Path.Combine(root, "binary", $"payload.{payloadGame}.bin"); Directory.CreateDirectory(Path.GetDirectoryName(destination)!); using var handler = new HttpClientHandler { AllowAutoRedirect = false }; using var client = new HttpClient(handler) { Timeout = Timeout.InfiniteTimeSpan }; @@ -154,7 +173,7 @@ public static class RetroWfcPayload } actualSha256 = Convert.ToHexString(hash.GetHashAndReset()).ToLowerInvariant(); } - ValidateRetroWfcPayloadFile(temporary); + ValidateRetroWfcPayloadFile(temporary, uri.Query[3..]); File.Move(temporary, destination, overwrite: true); return new RetroWfcPayloadSnapshot(root, actualSha256, total); } @@ -181,7 +200,8 @@ public static class RetroWfcPayload request.StatusCode is { } status && (int)status >= 500; } - private static void ValidateRetroWfcPayloadFile(string payload, RSAParameters? signingKey = null) + private static void ValidateRetroWfcPayloadFile(string payload, string expectedGame, + RSAParameters? signingKey = null) { byte[] image; using (var stream = File.OpenRead(payload)) @@ -201,6 +221,10 @@ public static class RetroWfcPayload throw new InvalidDataException( $"The Retro-WFC payload declares {declaredSize} bytes but contains {image.Length}."); + if (image.Length < 0x144 || + System.Text.Encoding.ASCII.GetString(image, 0x138, 12).TrimEnd('\0') != expectedGame) + throw new InvalidDataException($"The Retro-WFC payload is not for {expectedGame}."); + using var rsa = RSA.Create(); rsa.ImportParameters(signingKey ?? new RSAParameters { diff --git a/Launcher/WiiCompiled.Setup.Linux/DiscTool.cs b/Launcher/WiiCompiled.Setup.Linux/DiscTool.cs index 4b0cab0..3279895 100644 --- a/Launcher/WiiCompiled.Setup.Linux/DiscTool.cs +++ b/Launcher/WiiCompiled.Setup.Linux/DiscTool.cs @@ -11,29 +11,30 @@ namespace WiiCompiled.Setup.Linux; /// internal static class DiscTool { - public static async Task ValidateAndExtractAsync( - string isoPath, ProjectManifest manifest, string assetsDirectory, string workspace, + /// Validates and extracts the disc, returning the supported release it is. + public static async Task ValidateAndExtractAsync( + string isoPath, IReadOnlyList releases, string assetsDirectory, string workspace, string? nodToolBin, IInstallReporter reporter, CancellationToken cancellationToken) { - if (IsAlreadyExtracted(manifest, assetsDirectory)) - { - reporter.Progress(InstallStages.ExtractDisc, "Reusing the verified extracted disc", 6); - return; - } - var nodTool = nodToolBin ?? await NodToolProvider.ResolveAsync(workspace, cancellationToken); // `nodtool info` only decodes the disc/partition headers (milliseconds); `nodtool extract` // copies the whole data partition to disk (tens of seconds for a custom-track-heavy MKWii - // ISO). Checking the game ID first, before extracting, means a wrong disc fails fast - - // matching the original dolphin-tool `header` step this replaces. + // ISO). The game ID picks the release, so a wrong disc fails fast and an existing + // extraction is only reused for the same release. reporter.Progress(InstallStages.ExtractDisc, "Reading the disc header", 2); var info = NodToolInfoParser.Parse(await RunInfoAsync(nodTool, isoPath, cancellationToken)); - if (!string.Equals(info.GameId, manifest.GameId, StringComparison.Ordinal)) + var manifest = releases.FirstOrDefault(release => + string.Equals(info.GameId, release.GameId, StringComparison.Ordinal)) + ?? throw new InvalidOperationException( + $"This disc is '{info.GameId}', which is not a supported Mario Kart Wii release " + + $"({ProjectManifest.Describe(releases)}). " + + "Only your own legally-owned copy of a supported game/region can be used."); + + if (IsAlreadyExtracted(manifest, assetsDirectory)) { - throw new InvalidOperationException( - $"This disc is '{info.GameId}', not the expected '{manifest.GameId}' (Mario Kart Wii, region {manifest.Region}). " + - "Only your own legally-owned copy of that exact game/region can be used."); + reporter.Progress(InstallStages.ExtractDisc, "Reusing the verified extracted disc", 6); + return manifest; } // Extracted straight into Assets/DATA (kept, not a scratch dir) - the runtime reads course/ @@ -71,6 +72,22 @@ internal static class DiscTool File.Copy(relPath, Path.Combine(assetsDirectory, "StaticR.rel"), overwrite: true); File.WriteAllText(Path.Combine(assetsDirectory, ExtractionMarker), ExtractionRecord(dolSha, dataDir)); reporter.Progress(InstallStages.ExtractDisc, "Disc validated and extracted", 6); + return manifest; + } + + /// The release already extracted into Assets, chosen by its main.dol like local-build.sh. + public static ProjectManifest SelectExtracted(IReadOnlyList releases, string assetsDirectory) + { + var dolSha = Sha256Of(Path.Combine(assetsDirectory, "main.dol")); + var manifest = releases.FirstOrDefault(release => string.Equals(dolSha, release.DolSha256, StringComparison.Ordinal)) + ?? throw new InvalidOperationException( + $"Assets/main.dol (sha256 {dolSha}) is not a supported clean Mario Kart Wii release " + + $"({ProjectManifest.Describe(releases)})."); + var relSha = Sha256Of(Path.Combine(assetsDirectory, "StaticR.rel")); + if (!string.Equals(relSha, manifest.RelSha256, StringComparison.Ordinal)) + throw new InvalidOperationException( + $"Assets/StaticR.rel does not match the clean {manifest.GameId} release of Assets/main.dol."); + return manifest; } private static async Task RunInfoAsync(string nodTool, string isoPath, CancellationToken cancellationToken) @@ -97,7 +114,7 @@ internal static class DiscTool private const string ExtractionMarker = ".disc-extracted"; - // Only one disc revision is accepted, so a completed, verified extraction is identical to a fresh one. + // Each release has one accepted revision, so a completed, verified extraction is identical to a fresh one. private static bool IsAlreadyExtracted(ProjectManifest manifest, string assetsDirectory) { var marker = Path.Combine(assetsDirectory, ExtractionMarker); diff --git a/Launcher/WiiCompiled.Setup.Linux/Program.cs b/Launcher/WiiCompiled.Setup.Linux/Program.cs index 2ce7b3a..75cc9de 100644 --- a/Launcher/WiiCompiled.Setup.Linux/Program.cs +++ b/Launcher/WiiCompiled.Setup.Linux/Program.cs @@ -74,6 +74,8 @@ internal static class Program private static async Task InstallAsync(Dictionary flags, IInstallReporter reporter, CancellationToken token) { + // local-build.sh falls back to an x86-64-v2 build when this CPU lacks v3. + HostCpuRequirement.EnsureSupported(X86CpuProfile.V2); var retroDir = flags.GetValueOrDefault("retro-dir"); var installsRetro = !string.IsNullOrEmpty(retroDir); var downloadPayload = flags.ContainsKey("download-retro-wfc-payload"); @@ -95,13 +97,14 @@ internal static class Program if (installsRetro) retroDir = RetroRewindSource.ResolveRetroRewind6(retroDir!); var workspace = flags.GetValueOrDefault("workspace") ?? WorkspaceLocator.FindFrom(AppContext.BaseDirectory); - var manifest = ProjectManifest.Load(Path.Combine(workspace, "projects", "mkwii", "recomp.yml")); + var releases = ProjectManifest.LoadAll(workspace); var assetsDir = Path.Combine(workspace, "Assets"); reporter.Progress(InstallStages.Validate, "Checking prerequisites", 1); + ProjectManifest release; if (flags.TryGetValue("game", out var isoPath) && !string.IsNullOrEmpty(isoPath)) { - await DiscTool.ValidateAndExtractAsync(isoPath, manifest, assetsDir, workspace, + release = await DiscTool.ValidateAndExtractAsync(isoPath, releases, assetsDir, workspace, flags.GetValueOrDefault("disc-tool-bin"), reporter, token); } else @@ -114,6 +117,7 @@ internal static class Program "No --game ISO was given and Assets/main.dol + Assets/StaticR.rel are not already present. " + "Either pass --game , or extract them yourself first (see translator/README.md)."); } + release = DiscTool.SelectExtracted(releases, assetsDir); } var state = JsonState.TryRead(StatePath) ?? new InstallState { Workspace = workspace }; @@ -133,10 +137,10 @@ internal static class Program try { // A valid signature authenticates a payload, but does not prove it is the latest - // signed revision. Always ask the fixed endpoint for the current snapshot; the - // downloader verifies it before atomically replacing the cache. + // signed revision. Always ask the release's fixed endpoint for the current snapshot; + // the downloader verifies it before atomically replacing the cache. await RetroWfcPayload.DownloadRetroWfcPayloadAsync( - RetroWfcPayload.CurrentRetroWfcPayloadUri, cacheDir, token); + RetroWfcPayload.PayloadUri(release.GameId), cacheDir, token); } catch (Exception downloadFailure) when (!token.IsCancellationRequested && downloadFailure is HttpRequestException or TimeoutException @@ -147,7 +151,7 @@ internal static class Program // that must remain a hard failure instead of hiding possible endpoint tampering. try { - RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(cacheDir); + RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(cacheDir, gameId: release.GameId); } catch (Exception cacheFailure) when (cacheFailure is IOException or UnauthorizedAccessException or InvalidDataException) diff --git a/Launcher/WiiCompiled.Setup.Linux/ProjectManifest.cs b/Launcher/WiiCompiled.Setup.Linux/ProjectManifest.cs index 43b9a21..953fd01 100644 --- a/Launcher/WiiCompiled.Setup.Linux/ProjectManifest.cs +++ b/Launcher/WiiCompiled.Setup.Linux/ProjectManifest.cs @@ -3,7 +3,7 @@ using System.Text.RegularExpressions; namespace WiiCompiled.Setup.Linux; /// -/// The handful of facts this tool needs out of projects/mkwii/recomp.yml. Parsed literally line by +/// The handful of facts this tool needs out of a projects/*/recomp.yml. Parsed literally line by /// line - the same approach Launcher/NativeBuildFlags.ps1's Get-MkwProjectPins and /// Launcher/local-build.sh already use - rather than pulling in a YAML library, since the manifest /// is machine-written with a fixed shape. @@ -67,4 +67,21 @@ internal sealed class ProjectManifest return new ProjectManifest { GameId = gameId, Region = region, DolSha256 = dolSha, RelSha256 = relSha }; } + + /// Every supported release: one per projects/*/recomp.yml, as local-build.sh selects them. + public static IReadOnlyList LoadAll(string workspace) + { + var projects = Directory.EnumerateDirectories(Path.Combine(workspace, "projects")) + .Select(directory => Path.Combine(directory, "recomp.yml")) + .Where(File.Exists) + .Order(StringComparer.Ordinal) + .Select(Load) + .ToList(); + if (projects.Count == 0) + throw new InvalidOperationException($"No projects/*/recomp.yml was found under {workspace}."); + return projects; + } + + public static string Describe(IEnumerable projects) => + string.Join(", ", projects.Select(project => $"{project.GameId} (region {project.Region})")); } diff --git a/Launcher/WiiCompiled.Setup.Windows/ConsoleCommands.cs b/Launcher/WiiCompiled.Setup.Windows/ConsoleCommands.cs index acabbef..02ab9a2 100644 --- a/Launcher/WiiCompiled.Setup.Windows/ConsoleCommands.cs +++ b/Launcher/WiiCompiled.Setup.Windows/ConsoleCommands.cs @@ -64,9 +64,7 @@ internal static class ConsoleCommands { using var payload = PayloadArchive.OpenCurrent(); var manifest = payload.ReadManifest(); - var tool = Path.Combine(temp, "nodtool.exe"); - payload.ExtractEntry(InstalledLayout.ToolkitEntryPrefix + "nodtool.exe", tool); - payload.ExtractDirectory(InstalledLayout.ToolkitEntryPrefix + "Redist", temp); + var tool = payload.ExtractDiscTool(temp); reporter?.Progress(InstallStages.Validate, "Checking the Wii disc image...", 10); var header = InputValidation.ReadDiscHeaderAsync(tool, command.GamePath!).GetAwaiter().GetResult(); InputValidation.EnsureCompatibleDisc(header, manifest); diff --git a/Launcher/WiiCompiled.Setup.Windows/InputValidation.cs b/Launcher/WiiCompiled.Setup.Windows/InputValidation.cs index 5ca7558..3e9a14f 100644 --- a/Launcher/WiiCompiled.Setup.Windows/InputValidation.cs +++ b/Launcher/WiiCompiled.Setup.Windows/InputValidation.cs @@ -54,33 +54,29 @@ internal static class InputValidation } : "Unknown"; - public static void EnsureCompatibleDisc(DiscHeader header, PayloadManifest manifest) - { - if (!header.GameId.Equals(manifest.ExpectedGameId, StringComparison.OrdinalIgnoreCase)) - { - throw new InvalidDataException( - $"This build supports Mario Kart Wii PAL ({manifest.ExpectedGameId}). " + - $"The selected image is {header.GameId} ({header.InternalName}, {header.Region})."); - } - } + /// The supported release this disc is, or a clear rejection naming every supported one. + public static GameRelease EnsureCompatibleDisc(DiscHeader header, PayloadManifest manifest) => + manifest.SupportedReleases.FirstOrDefault(release => + release.GameId.Equals(header.GameId, StringComparison.OrdinalIgnoreCase)) + ?? throw new InvalidDataException( + "This build supports Mario Kart Wii " + + string.Join(", ", manifest.SupportedReleases.Select(release => + $"{RegionFromGameId(release.GameId)} ({release.GameId})")) + + $". The selected image is {header.GameId} ({header.InternalName}, {header.Region})."); - // Thin forwarding wrappers: the actual download/RSA-verification logic lives in - // WiiCompiled.Setup.Common.RetroWfcPayload (shared with WiiCompiled.Setup.Linux) so there's one - // copy of it, not two. Kept under these names so every existing call site here - // (ProductRepairService.cs, LocalBuildService.cs, Installation.cs, SelfTests.cs) is unchanged. - public const string CurrentRetroWfcPayloadUri = RetroWfcPayload.CurrentRetroWfcPayloadUri; - - public static string ValidateStagedRetroWfcPayloadDirectory(string stagedDirectory, + // Forwarding wrappers over WiiCompiled.Setup.Common.RetroWfcPayload that require the game id, + // so no caller here can silently fall back to one region's payload. + public static string ValidateStagedRetroWfcPayloadDirectory(string stagedDirectory, string gameId, RSAParameters? signingKey = null) => - RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(stagedDirectory, signingKey); + RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(stagedDirectory, gameId, signingKey); - public static string ResolveRetroWfcPayloadFile(string stagedDirectory, + public static string ResolveRetroWfcPayloadFile(string stagedDirectory, string gameId, RSAParameters? signingKey = null) => - RetroWfcPayload.ResolveRetroWfcPayloadFile(stagedDirectory, signingKey); + RetroWfcPayload.ResolveRetroWfcPayloadFile(stagedDirectory, gameId, signingKey); - public static string ComputeRetroWfcPayloadSha256(string stagedDirectory, + public static string ComputeRetroWfcPayloadSha256(string stagedDirectory, string gameId, RSAParameters? signingKey = null) => - RetroWfcPayload.ComputeRetroWfcPayloadSha256(stagedDirectory, signingKey); + RetroWfcPayload.ComputeRetroWfcPayloadSha256(stagedDirectory, gameId, signingKey); public static void ValidateRetroWfcPayloadUri(string uriText) => RetroWfcPayload.ValidateRetroWfcPayloadUri(uriText); diff --git a/Launcher/WiiCompiled.Setup.Windows/Installation.cs b/Launcher/WiiCompiled.Setup.Windows/Installation.cs index de600c9..d1e7040 100644 --- a/Launcher/WiiCompiled.Setup.Windows/Installation.cs +++ b/Launcher/WiiCompiled.Setup.Windows/Installation.cs @@ -131,6 +131,8 @@ internal sealed class Installation Workspace + "LocalBuild.ps1", Workspace + "NativeBuildFlags.ps1", Workspace + @"projects\mkwii\recomp.yml", + Workspace + @"projects\mkwii-ntsc-u\recomp.yml", + Workspace + @"projects\mkwii-ntsc-j\recomp.yml", Workspace + @"runtime\CMakeLists.txt", Workspace + @"runtime\assets\dsp\dsp_coef.bin" ]; @@ -168,6 +170,26 @@ internal sealed class Installation public InstallState? ReadInstallState() => JsonState.TryRead(InstallStatePath); + /// The game id of the installed disc, which selects its region's Retro-WFC payload. + public string ReadGameId() + { + try { return ReadDiscGameId(GameDataDirectory); } + catch (IOException ex) + { + throw new InvalidDataException( + "The installed game data has no readable disc header. Apply setup again with the disc image.", ex); + } + } + + /// The six-character game id in an extracted disc's sys/boot.bin. + internal static string ReadDiscGameId(string dataRoot) + { + using var stream = File.OpenRead(Path.Combine(dataRoot, "sys", "boot.bin")); + var id = new byte[6]; + stream.ReadExactly(id); + return System.Text.Encoding.ASCII.GetString(id); + } + internal ToolkitState? ReadToolkitState() => JsonState.TryRead(ToolkitStatePath); /// @@ -396,7 +418,7 @@ internal sealed class Installation try { - var payload = InputValidation.ResolveRetroWfcPayloadFile(WorkspaceRetroWfcPayload); + var payload = InputValidation.ResolveRetroWfcPayloadFile(WorkspaceRetroWfcPayload, ReadGameId()); if (!InputValidation.Sha256File(payload).Equals(fingerprint.RetroWfcPayloadSha256, StringComparison.OrdinalIgnoreCase) || new FileInfo(payload).Length != fingerprint.RetroWfcPayloadLength) @@ -581,7 +603,7 @@ internal sealed class Installation { try { - var payload = InputValidation.ResolveRetroWfcPayloadFile(WorkspaceRetroWfcPayload); + var payload = InputValidation.ResolveRetroWfcPayloadFile(WorkspaceRetroWfcPayload, ReadGameId()); return new FileInfo(payload).Length == snapshot.ByteLength && InputValidation.Sha256File(payload).Equals(snapshot.Sha256, StringComparison.Ordinal); } diff --git a/Launcher/WiiCompiled.Setup.Windows/InstallerEngine.cs b/Launcher/WiiCompiled.Setup.Windows/InstallerEngine.cs index f69e4f9..d4467b7 100644 --- a/Launcher/WiiCompiled.Setup.Windows/InstallerEngine.cs +++ b/Launcher/WiiCompiled.Setup.Windows/InstallerEngine.cs @@ -40,6 +40,28 @@ internal sealed class InstallerEngine var toolkit = InstalledLayout.Toolkit(staging); var workspace = InstalledLayout.Workspace(staging); + // The disc decides which release's inputs everything below expects, so it is identified + // before any reuse decision or toolkit extraction. + _reporter.Progress(InstallStages.Validate, "Checking the Wii disc image...", 1); + var nodTool = payload.ExtractDiscTool(Path.Combine(staging, "disc-tool")); + var header = await InputValidation.ReadDiscHeaderAsync(nodTool, options.GamePath, + cancellationToken); + var release = InputValidation.EnsureCompatibleDisc(header, manifest); + var canonicalRetroRoot = options.RetroDirectoryPath is null + ? null + : RetroRewindSource.ResolveRetroRewind6(options.RetroDirectoryPath); + ValidateRetroOptions(canonicalRetroRoot, options.RetroWfcPayloadMode); + + var retroCompileInputs = canonicalRetroRoot is null + ? null + : SnapshotRetroRewindCompileInputs(canonicalRetroRoot, + Path.Combine(staging, "compile-inputs"), cancellationToken); + if (options.Portable) + { + var portableRoot = PortableRoot.Create(parent); + _reporter.Diagnostic($"Installing as a portable installation under {portableRoot}."); + } + var candidateToolkitFingerprint = manifest.ToolkitFingerprint; var candidateToolkitPackageFingerprint = manifest.ToolkitPackageFingerprint; var candidateRuntimeAssetsFingerprint = manifest.RuntimeAssetsFingerprint; @@ -49,7 +71,7 @@ internal sealed class InstallerEngine var installedToolkitPackageFingerprint = existing.IsPresent ? existing.ResolveToolkitPackageFingerprint() : ""; - var reusableGameAssets = FindReusableGameAssets(existing, manifest); + var reusableGameAssets = FindReusableGameAssets(existing, release); var sameToolkit = existing.IsPresent && reusableGameAssets is not null && installedToolkitFingerprint.Equals(candidateToolkitFingerprint, @@ -68,7 +90,7 @@ internal sealed class InstallerEngine var extractWorkspace = !sameToolkit || !runtimeAssetsCurrent; _reporter.Progress(InstallStages.ExtractToolkit, - "Inspecting the release's local recompilation toolkit...", 1); + "Inspecting the release's local recompilation toolkit...", 4); if (extractToolkit) payload.ExtractDirectory(InstalledLayout.ToolkitDirectoryName, toolkit); if (extractWorkspace) { @@ -82,30 +104,10 @@ internal sealed class InstallerEngine payload.ExtractEntry(InstalledLayout.PayloadManifestFileName, Path.Combine(staging, InstalledLayout.PayloadManifestFileName)); - var nodTool = extractToolkit ? Path.Combine(toolkit, "nodtool.exe") : installedNodTool; - _reporter.Progress(InstallStages.Validate, "Checking the Wii disc image...", 2); - var header = await InputValidation.ReadDiscHeaderAsync(nodTool, options.GamePath, - cancellationToken); - InputValidation.EnsureCompatibleDisc(header, manifest); - var canonicalRetroRoot = options.RetroDirectoryPath is null - ? null - : RetroRewindSource.ResolveRetroRewind6(options.RetroDirectoryPath); - ValidateRetroOptions(canonicalRetroRoot, options.RetroWfcPayloadMode, manifest); - - var retroCompileInputs = canonicalRetroRoot is null - ? null - : SnapshotRetroRewindCompileInputs(canonicalRetroRoot, - Path.Combine(staging, "compile-inputs"), cancellationToken); - if (options.Portable) - { - var portableRoot = PortableRoot.Create(parent); - _reporter.Diagnostic($"Installing as a portable installation under {portableRoot}."); - } - if (sameToolkit) { var desiredInputDrift = ProductRepairService.FindDesiredInputDrift(existing, - candidateToolkitFingerprint, manifest.ExpectedDolSha256, manifest.ExpectedRelSha256); + candidateToolkitFingerprint, release.DolSha256, release.RelSha256); if (desiredInputDrift.Retro && retroCompileInputs is null) throw new InvalidOperationException( "This release changes the clean game inputs used by the installed Retro Rewind product. " + @@ -113,7 +115,7 @@ internal sealed class InstallerEngine var reconciliation = await ReconcileSameToolkitAsync(existing, retroCompileInputs, canonicalRetroRoot, options.RetroWfcPayloadMode, Path.Combine(staging, "repair"), - manifest.ExpectedDolSha256, manifest.ExpectedRelSha256, cancellationToken); + release.DolSha256, release.RelSha256, cancellationToken); var remainingCancellation = reconciliation.PublicationCommitted ? CancellationToken.None : cancellationToken; @@ -125,11 +127,10 @@ internal sealed class InstallerEngine remainingCancellation.ThrowIfCancellationRequested(); EnsureReconciliationCurrent(existing, candidateToolkitFingerprint, retroCompileInputs, - manifest.ExpectedDolSha256, manifest.ExpectedRelSha256, - reconciliation.CachedRetroWfcPayloadMatches); + release.DolSha256, release.RelSha256, reconciliation.CachedRetroWfcPayloadMatches); var updatedState = BuildInstallState(existing.ReadInstallState(), installDirectory, manifest, - retroCompileInputs, canonicalRetroRoot, options.RetroWfcPayloadMode); + release, retroCompileInputs, canonicalRetroRoot, options.RetroWfcPayloadMode); PrepareMetadata(staging, manifest, updatedState); remainingCancellation.ThrowIfCancellationRequested(); @@ -159,11 +160,11 @@ internal sealed class InstallerEngine if (reusableGameAssets is null) { await ExtractGameAssetsAsync(nodTool, options.GamePath, - Path.Combine(staging, "GameAssets"), manifest, cancellationToken); + Path.Combine(staging, "GameAssets"), release, cancellationToken); } await PublishToolkitAndReconcileProductsAsync(existing, staging, workspace, manifest, - previousState, options, canonicalRetroRoot, retroCompileInputs, + release, previousState, options, canonicalRetroRoot, retroCompileInputs, publishGameAssets: reusableGameAssets is null, createShortcuts: firstInstall, cancellationToken: cancellationToken); } @@ -187,7 +188,7 @@ internal sealed class InstallerEngine ["generated", "build", "native-build", "Assets", "PulsarPacks"]; private async Task PublishToolkitAndReconcileProductsAsync(Installation existing, string staging, - string stagedWorkspace, PayloadManifest manifest, InstallState? previousState, + string stagedWorkspace, PayloadManifest manifest, GameRelease release, InstallState? previousState, InstallOptions options, string? canonicalRetroRoot, RetroRewindCompileInputs? retroCompileInputs, bool publishGameAssets, bool createShortcuts, CancellationToken cancellationToken) @@ -206,7 +207,7 @@ internal sealed class InstallerEngine } - var state = BuildInstallState(previousState, installDirectory, manifest, + var state = BuildInstallState(previousState, installDirectory, manifest, release, compileInputs: null, canonicalRetroRoot, options.RetroWfcPayloadMode); PrepareMetadata(staging, manifest, state); @@ -226,10 +227,9 @@ internal sealed class InstallerEngine var reconciliation = await ReconcileSameToolkitAsync(existing, retroCompileInputs, canonicalRetroRoot, options.RetroWfcPayloadMode, repairScratch: null, - manifest.ExpectedDolSha256, manifest.ExpectedRelSha256, cancellationToken); + release.DolSha256, release.RelSha256, cancellationToken); EnsureReconciliationCurrent(existing, manifest.ToolkitFingerprint, retroCompileInputs, - manifest.ExpectedDolSha256, manifest.ExpectedRelSha256, - reconciliation.CachedRetroWfcPayloadMatches); + release.DolSha256, release.RelSha256, reconciliation.CachedRetroWfcPayloadMatches); } private Task ReconcileSameToolkitAsync(Installation existing, @@ -354,7 +354,8 @@ internal sealed class InstallerEngine } private static InstallState BuildInstallState(InstallState? previousState, string installDirectory, - PayloadManifest manifest, RetroRewindCompileInputs? compileInputs, string? canonicalRetroRoot, + PayloadManifest manifest, GameRelease release, RetroRewindCompileInputs? compileInputs, + string? canonicalRetroRoot, RetroWfcPayloadMode payloadMode, RetroWfcPayloadSnapshot? retroWfcPayloadSnapshot = null) { @@ -368,8 +369,8 @@ internal sealed class InstallerEngine InstalledUtc = previousState?.InstalledUtc ?? DateTime.UtcNow, RetroRewindInstalled = previousState?.RetroRewindInstalled ?? false, ToolkitReleaseTag = manifest.ToolkitReleaseTag, - DolSha256 = manifest.ExpectedDolSha256, - RelSha256 = manifest.ExpectedRelSha256, + DolSha256 = release.DolSha256, + RelSha256 = release.RelSha256, RetroRewindCodePulSha256 = previousState?.RetroRewindCodePulSha256 ?? "", RetroRewindCompileInputsSha256 = previousState?.RetroRewindCompileInputsSha256 ?? "", RetroWfcPayloadMode = previousState?.RetroWfcPayloadMode ?? "", @@ -444,8 +445,7 @@ internal sealed class InstallerEngine Path.Combine(InstalledLayout.Workspace(installDirectory), "runtime", "assets"))); } - private static void ValidateRetroOptions(string? canonicalRetroRoot, RetroWfcPayloadMode mode, - PayloadManifest manifest) + private static void ValidateRetroOptions(string? canonicalRetroRoot, RetroWfcPayloadMode mode) { if (canonicalRetroRoot is null && mode != RetroWfcPayloadMode.NotApplicable) throw new InvalidOperationException( @@ -453,11 +453,9 @@ internal sealed class InstallerEngine if (canonicalRetroRoot is not null && mode == RetroWfcPayloadMode.NotApplicable) throw new InvalidOperationException( "Download the Retro-WFC payload, or explicitly skip the optional payload."); - if (canonicalRetroRoot is not null && mode == RetroWfcPayloadMode.Online) - InputValidation.ValidateRetroWfcPayloadUri(manifest.RetroWfcPayloadUri); } - private string? FindReusableGameAssets(Installation existing, PayloadManifest manifest) + private string? FindReusableGameAssets(Installation existing, GameRelease release) { var dataRoot = existing.GameDataDirectory; // No fst.bin simply means nothing was extracted here before; anything past that gate is an @@ -466,7 +464,7 @@ internal sealed class InstallerEngine if (!File.Exists(Path.Combine(dataRoot, "sys", "fst.bin"))) return null; try { - ValidateExtractedGame(dataRoot, manifest); + ValidateExtractedGame(dataRoot, release); return dataRoot; } catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or InvalidDataException) @@ -478,7 +476,7 @@ internal sealed class InstallerEngine } private async Task ExtractGameAssetsAsync(string nodTool, string gamePath, string destination, - PayloadManifest manifest, CancellationToken cancellationToken) + GameRelease release, CancellationToken cancellationToken) { _reporter.Progress(InstallStages.ExtractDisc, "Extracting the game disc. This is the longest preparation step...", 6); @@ -493,15 +491,16 @@ internal sealed class InstallerEngine cancellationToken); if (extraction.ExitCode != 0) throw new InvalidDataException("Game extraction failed. " + extraction.CombinedOutput.Trim()); - ValidateExtractedGame(dataRoot, manifest); + ValidateExtractedGame(dataRoot, release); } - private static void ValidateExtractedGame(string dataRoot, PayloadManifest manifest) + internal static void ValidateExtractedGame(string dataRoot, GameRelease release) { var dol = Path.Combine(dataRoot, "sys", "main.dol"); var rel = Path.Combine(dataRoot, "files", "rel", "StaticR.rel"); var fst = Path.Combine(dataRoot, "sys", "fst.bin"); - var missing = new[] { dol, rel, fst }.Where(path => !File.Exists(path)) + var boot = Path.Combine(dataRoot, "sys", "boot.bin"); + var missing = new[] { dol, rel, fst, boot }.Where(path => !File.Exists(path)) .Select(path => Path.GetRelativePath(dataRoot, path)).ToList(); if (missing.Count > 0) throw new InvalidDataException( @@ -509,10 +508,13 @@ internal sealed class InstallerEngine string.Join(", ", missing) + "."); var mismatches = new List(); + var discGameId = Installation.ReadDiscGameId(dataRoot); + if (!discGameId.Equals(release.GameId, StringComparison.Ordinal)) + mismatches.Add($"sys/boot.bin names {discGameId}"); foreach (var (name, path, expected) in new[] { - ("main.dol", dol, manifest.ExpectedDolSha256), - ("StaticR.rel", rel, manifest.ExpectedRelSha256) + ("main.dol", dol, release.DolSha256), + ("StaticR.rel", rel, release.RelSha256) }) { var actual = InputValidation.Sha256File(path); @@ -523,7 +525,7 @@ internal sealed class InstallerEngine if (mismatches.Count > 0) throw new InvalidDataException( - "The disc is RMCP01 but its game code does not match the supported clean PAL revision: " + + $"The disc is {release.GameId} but its game data does not match the supported clean revision: " + string.Join("; ", mismatches) + ". " + "Patched or otherwise modified game code cannot be installed safely."); } diff --git a/Launcher/WiiCompiled.Setup.Windows/LocalBuildService.cs b/Launcher/WiiCompiled.Setup.Windows/LocalBuildService.cs index 1347c1e..4a390ea 100644 --- a/Launcher/WiiCompiled.Setup.Windows/LocalBuildService.cs +++ b/Launcher/WiiCompiled.Setup.Windows/LocalBuildService.cs @@ -23,7 +23,8 @@ internal sealed class LocalBuildService /// public async Task BuildAsync(string installStaging, BuildProfile profile, string outputDirectory, RetroWfcPayloadMode retroWfcPayloadMode, string? retroWfcOfflinePayloadDirectory, - CancellationToken cancellationToken, ToolkitFingerprintComponents? toolkitComponents = null, + string? retroWfcGameId, CancellationToken cancellationToken, + ToolkitFingerprintComponents? toolkitComponents = null, bool forceCleanBuild = false, BuildProgressWindow? progress = null, string? retroRewindPackageDirectory = null, string? baseOutputDirectory = null) { @@ -45,8 +46,9 @@ internal sealed class LocalBuildService retroRewindPackageDirectory = RetroRewindSource.ResolveRetroRewind6( retroRewindPackageDirectory); if (retroWfcPayloadMode == RetroWfcPayloadMode.Online) - retroWfcOfflinePayloadDirectory = - InputValidation.ValidateStagedRetroWfcPayloadDirectory(retroWfcOfflinePayloadDirectory!); + retroWfcOfflinePayloadDirectory = InputValidation.ValidateStagedRetroWfcPayloadDirectory( + retroWfcOfflinePayloadDirectory!, + retroWfcGameId ?? throw new ArgumentException("The Retro-WFC payload needs its game id.")); var arguments = new List { @@ -58,7 +60,8 @@ internal sealed class LocalBuildService BuildProfile.RetroRewind => "retro-rewind", _ => "both" }, - "-OutputDirectory", outputDirectory + "-OutputDirectory", outputDirectory, + "-X86CpuProfile", HostCpuRequirement.SelectBuildProfile() == X86CpuProfile.V2 ? "v2" : "v3" }; if (baseOutputDirectory is not null) { diff --git a/Launcher/WiiCompiled.Setup.Windows/Models.cs b/Launcher/WiiCompiled.Setup.Windows/Models.cs index e62b261..f945693 100644 --- a/Launcher/WiiCompiled.Setup.Windows/Models.cs +++ b/Launcher/WiiCompiled.Setup.Windows/Models.cs @@ -33,16 +33,23 @@ internal sealed class InstallOptions public bool HasRetroRewind => RetroDirectoryPath is not null; } +/// A clean retail release the payload installs, as pinned by its projects/*/recomp.yml. +internal sealed class GameRelease +{ + public string GameId { get; set; } = ""; + public string DolSha256 { get; set; } = ""; + public string RelSha256 { get; set; } = ""; +} + internal sealed class PayloadManifest { + public const int CurrentSchemaVersion = 3; + public int SchemaVersion { get; set; } public string ProductVersion { get; set; } = ""; - public string ExpectedGameId { get; set; } = "RMCP01"; - public string ExpectedDolSha256 { get; set; } = ""; - public string ExpectedRelSha256 { get; set; } = ""; + public List SupportedReleases { get; set; } = []; public string ToolkitReleaseTag { get; set; } = ""; public string BuildModel { get; set; } = ""; - public string RetroWfcPayloadUri { get; set; } = ""; /// /// Content identities computed once at release-build time (Build-Installer.ps1 --emit-payload-identities) diff --git a/Launcher/WiiCompiled.Setup.Windows/PayloadArchive.cs b/Launcher/WiiCompiled.Setup.Windows/PayloadArchive.cs index d85f1fa..8f9b1b4 100644 --- a/Launcher/WiiCompiled.Setup.Windows/PayloadArchive.cs +++ b/Launcher/WiiCompiled.Setup.Windows/PayloadArchive.cs @@ -54,10 +54,21 @@ internal sealed class PayloadArchive : IDisposable var entry = FindEntry(InstalledLayout.PayloadManifestFileName) ?? throw new InvalidDataException("The payload manifest is missing."); using var stream = entry.Open(); + return ParseManifest(stream); + } + + internal static PayloadManifest ParseManifest(Stream stream) + { var manifest = JsonSerializer.Deserialize(stream, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }) ?? throw new InvalidDataException("The payload manifest is invalid."); - if (manifest.SchemaVersion != 2) + ValidateManifest(manifest); + return manifest; + } + + internal static void ValidateManifest(PayloadManifest manifest) + { + if (manifest.SchemaVersion != PayloadManifest.CurrentSchemaVersion) throw new InvalidDataException($"Unsupported payload schema {manifest.SchemaVersion}."); // The payload identities are the release-computed replacement for hashing the whole // toolkit on the user's machine; a payload without them was packaged incorrectly. @@ -65,8 +76,30 @@ internal sealed class PayloadArchive : IDisposable string.IsNullOrWhiteSpace(manifest.ToolkitPackageFingerprint) || string.IsNullOrWhiteSpace(manifest.RuntimeAssetsFingerprint)) throw new InvalidDataException("The payload manifest is missing its content identities."); - InputValidation.ValidateRetroWfcPayloadUri(manifest.RetroWfcPayloadUri); - return manifest; + if (manifest.SupportedReleases is not { Count: > 0 }) + throw new InvalidDataException("The payload manifest names no supported game release."); + foreach (var release in manifest.SupportedReleases) + { + if (!RetroWfcPayload.SupportedGameIds.Contains(release.GameId) || + !IsSha256(release.DolSha256) || !IsSha256(release.RelSha256)) + throw new InvalidDataException( + $"The payload manifest describes an unsupported or incomplete release '{release.GameId}'."); + } + if (manifest.SupportedReleases.DistinctBy(release => release.GameId).Count() != + manifest.SupportedReleases.Count) + throw new InvalidDataException("The payload manifest lists a game release twice."); + } + + private static bool IsSha256(string value) => + value.Length == 64 && value.All(char.IsAsciiHexDigit); + + /// Extracts nodtool and the runtime DLLs it loads; returns the nodtool path. + public string ExtractDiscTool(string directory) + { + var tool = Path.Combine(directory, "nodtool.exe"); + ExtractEntry(InstalledLayout.ToolkitEntryPrefix + "nodtool.exe", tool); + ExtractDirectory(InstalledLayout.ToolkitEntryPrefix + "Redist", directory); + return tool; } public void ExtractEntry(string entryName, string destination) diff --git a/Launcher/WiiCompiled.Setup.Windows/ProductRepairService.cs b/Launcher/WiiCompiled.Setup.Windows/ProductRepairService.cs index 815890e..c7e4e6b 100644 --- a/Launcher/WiiCompiled.Setup.Windows/ProductRepairService.cs +++ b/Launcher/WiiCompiled.Setup.Windows/ProductRepairService.cs @@ -99,7 +99,11 @@ internal sealed class ProductRepairService Directory.CreateDirectory(scratchRoot); RetroWfcPayloadSnapshot? payloadSnapshot = null; - if (requestedPayloadMode == RetroWfcPayloadMode.Online) + // The installed disc's region decides which Retro-WFC payload the product embeds. + var payloadGameId = requestedPayloadMode == RetroWfcPayloadMode.Online + ? _installation.ReadGameId() + : null; + if (payloadGameId is not null) { _reporter.Progress(InstallStages.PrepareRetro, "Downloading the current shared Retro-WFC payload snapshot...", 3); @@ -107,12 +111,12 @@ internal sealed class ProductRepairService try { payloadSnapshot = await InputValidation.DownloadRetroWfcPayloadAsync( - InputValidation.CurrentRetroWfcPayloadUri, payloadScratch, cancellationToken); + RetroWfcPayload.PayloadUri(payloadGameId), payloadScratch, cancellationToken); } catch (Exception ex) when (!cancellationToken.IsCancellationRequested && ex is HttpRequestException or TimeoutException or IOException) { - payloadSnapshot = RecoverInstalledRetroWfcPayload(toolkitFingerprint, + payloadSnapshot = RecoverInstalledRetroWfcPayload(toolkitFingerprint, payloadGameId, Path.Combine(scratchRoot, "retro-wfc-payload-recovered"), ex, cancellationToken); } } @@ -236,7 +240,7 @@ internal sealed class ProductRepairService "Recompiling Mario Kart Wii and Retro Rewind with the installed toolkit...", 5); await BuildWithCleanRetryAsync(forceCleanBuild, clean => builder.BuildAsync(_installation.Root, BuildProfile.Both, retroOutput, - requestedPayloadMode, payloadSnapshot?.Directory, cancellationToken, + requestedPayloadMode, payloadSnapshot?.Directory, payloadGameId, cancellationToken, toolkitComponents, clean, progress: new BuildProgressWindow(_reporter, InstallStages.BuildBase, 5, 92), retroRewindPackageDirectory: compileInputs.RetroRewindRoot, @@ -255,7 +259,7 @@ internal sealed class ProductRepairService "Recompiling Mario Kart Wii with the installed toolkit...", 5); await BuildWithCleanRetryAsync(forceCleanBuild, clean => builder.BuildAsync(_installation.Root, BuildProfile.Base, baseOutput, - RetroWfcPayloadMode.NotApplicable, null, cancellationToken, + RetroWfcPayloadMode.NotApplicable, null, null, cancellationToken, toolkitComponents, clean, progress: new BuildProgressWindow(_reporter, InstallStages.BuildBase, 5, 92))); LocalBuildService.WriteFingerprint(baseOutput, BuildProfile.Base, toolkitFingerprint, @@ -270,7 +274,7 @@ internal sealed class ProductRepairService "Recompiling Retro Rewind for the canonical Code.pul...", 5); await BuildWithCleanRetryAsync(forceCleanBuild, clean => builder.BuildAsync(_installation.Root, BuildProfile.RetroRewind, retroOutput, - requestedPayloadMode, payloadSnapshot?.Directory, cancellationToken, + requestedPayloadMode, payloadSnapshot?.Directory, payloadGameId, cancellationToken, toolkitComponents, clean, progress: new BuildProgressWindow(_reporter, InstallStages.BuildRetro, 5, 92), retroRewindPackageDirectory: compileInputs.RetroRewindRoot)); @@ -310,7 +314,8 @@ internal sealed class ProductRepairService private RetroWfcPayloadSnapshot RecoverInstalledRetroWfcPayload(string toolkitFingerprint, - string destinationDirectory, Exception downloadFailure, CancellationToken cancellationToken) + string gameId, string destinationDirectory, Exception downloadFailure, + CancellationToken cancellationToken) { InvalidOperationException Unavailable(string reason) => new( "The Retro-WFC payload service is unavailable" + @@ -334,7 +339,7 @@ internal sealed class ProductRepairService try { cachedFile = InputValidation.ResolveRetroWfcPayloadFile( - _installation.WorkspaceRetroWfcPayload); + _installation.WorkspaceRetroWfcPayload, gameId); cancellationToken.ThrowIfCancellationRequested(); if (new FileInfo(cachedFile).Length != fingerprint.RetroWfcPayloadLength || !InputValidation.Sha256File(cachedFile).Equals(fingerprint.RetroWfcPayloadSha256, @@ -343,11 +348,11 @@ internal sealed class ProductRepairService throw Unavailable("the installed payload snapshot no longer matches its recorded identity."); } - var destination = Path.Combine(Path.GetFullPath(destinationDirectory), "binary", - "payload.RMCPD00.bin"); + var destination = Path.Combine(Path.GetFullPath(destinationDirectory), + RetroWfcPayload.PayloadRelativePath(gameId)); Directory.CreateDirectory(Path.GetDirectoryName(destination)!); File.Copy(cachedFile, destination, overwrite: true); - var root = InputValidation.ValidateStagedRetroWfcPayloadDirectory(destinationDirectory); + var root = InputValidation.ValidateStagedRetroWfcPayloadDirectory(destinationDirectory, gameId); _reporter.Diagnostic( "The Retro-WFC payload service is unavailable; reusing the installation's verified " + $"payload snapshot (sha256 {fingerprint.RetroWfcPayloadSha256[..12]}..., " + diff --git a/Launcher/WiiCompiled.Setup.Windows/Program.cs b/Launcher/WiiCompiled.Setup.Windows/Program.cs index 97e5125..761f39a 100644 --- a/Launcher/WiiCompiled.Setup.Windows/Program.cs +++ b/Launcher/WiiCompiled.Setup.Windows/Program.cs @@ -64,6 +64,8 @@ internal static class Program if (command.Mode is AppMode.SilentInstall or AppMode.RepairProducts) { + // CPUs without x86-64-v3 get an x86-64-v2 build. + HostCpuRequirement.EnsureSupported(X86CpuProfile.V2); using var cancellationSignal = CancellationSignal.ObserveEnvironment(); return command.Mode == AppMode.SilentInstall ? ConsoleCommands.Install(command, cancellationSignal.Token).GetAwaiter().GetResult() diff --git a/Launcher/WiiCompiled.Setup.Windows/SelfTests.cs b/Launcher/WiiCompiled.Setup.Windows/SelfTests.cs index a20577a..f688a8a 100644 --- a/Launcher/WiiCompiled.Setup.Windows/SelfTests.cs +++ b/Launcher/WiiCompiled.Setup.Windows/SelfTests.cs @@ -28,24 +28,15 @@ internal static class SelfTests } finally { File.Delete(path); } }, failures); - Test("Disc compatibility", () => - InputValidation.EnsureCompatibleDisc(new DiscHeader { GameId = "RMCP01" }, - new PayloadManifest { ExpectedGameId = "RMCP01" }), failures); - Test("Disc rejection", () => - { - try - { - InputValidation.EnsureCompatibleDisc(new DiscHeader { GameId = "RMCJ01" }, - new PayloadManifest { ExpectedGameId = "RMCP01" }); - throw new Exception("Wrong region was accepted."); - } - catch (InvalidDataException) { } - }, failures); + Test("Disc compatibility", TestDiscCompatibility, failures); + Test("Payload manifest releases", TestPayloadManifestReleases, failures); + Test("Extracted game release validation", TestExtractedGameRelease, failures); Test("Payload timestamp normalization", TestPayloadTimestampNormalization, failures); Test("Workspace timestamp reconciliation", TestWorkspaceTimestampReconciliation, failures); Test("Toolkit accompanies the workspace", TestToolkitRefreshDecision, failures); Test("Retro-WFC payload snapshot reconciliation", TestRetroWfcPayloadSnapshotReconciliation, failures); Test("Retro-WFC transient retry policy", TestRetroWfcTransientRetryPolicy, failures); + Test("Host CPU requirement", TestHostCpuRequirement, failures); Test("Shared runtime configuration", () => TestPathSettingRoundTrip("dvd_root", RuntimeConfiguration.SetDvdRoot, RuntimeConfiguration.RemoveDvdRootIfOwned), failures); Test("Canonical Retro Rewind configuration", () => TestPathSettingRoundTrip("retro_rewind_root", @@ -77,6 +68,152 @@ internal static class SelfTests return failures.Count == 0 ? 0 : 1; } + private static PayloadManifest MultiReleaseManifest() => new() + { + SchemaVersion = PayloadManifest.CurrentSchemaVersion, + ToolkitFingerprint = "toolkit", ToolkitPackageFingerprint = "package", RuntimeAssetsFingerprint = "assets", + SupportedReleases = + [ + new GameRelease { GameId = "RMCP01", DolSha256 = new string('1', 64), RelSha256 = new string('2', 64) }, + new GameRelease { GameId = "RMCE01", DolSha256 = new string('3', 64), RelSha256 = new string('4', 64) }, + new GameRelease { GameId = "RMCJ01", DolSha256 = new string('5', 64), RelSha256 = new string('6', 64) } + ] + }; + + private static void TestDiscCompatibility() + { + var manifest = MultiReleaseManifest(); + foreach (var release in manifest.SupportedReleases) + { + var selected = InputValidation.EnsureCompatibleDisc( + new DiscHeader { GameId = release.GameId.ToLowerInvariant() }, manifest); + if (!ReferenceEquals(selected, release)) + throw new Exception($"{release.GameId} did not select its own release."); + } + + foreach (var unsupported in new[] { "RMCK01", "RMCP02", "RSBE01" }) + { + try + { + InputValidation.EnsureCompatibleDisc(new DiscHeader { GameId = unsupported }, manifest); + throw new Exception($"{unsupported} was accepted."); + } + catch (InvalidDataException ex) when (ex.Message.Contains("NTSC-U (RMCE01)", StringComparison.Ordinal) && + ex.Message.Contains(unsupported, StringComparison.Ordinal)) { } + } + } + + private static void TestPayloadManifestReleases() + { + PayloadArchive.ValidateManifest(MultiReleaseManifest()); + + // The shape Build-Installer.ps1 writes (PowerShell's ConvertTo-Json of the ordered manifest). + var dol = new string('a', 64); + var rel = new string('b', 64); + var json = $$""" + { + "SchemaVersion": 3, + "ProductVersion": "1.0.0", + "SupportedReleases": [ + { "GameId": "RMCP01", "DolSha256": "{{dol}}", "RelSha256": "{{rel}}" }, + { "GameId": "RMCE01", "DolSha256": "{{rel}}", "RelSha256": "{{dol}}" } + ], + "ToolkitReleaseTag": "", + "BuildModel": "local-translation-and-compilation", + "ToolkitFingerprint": "toolkit", + "ToolkitPackageFingerprint": "package", + "RuntimeAssetsFingerprint": "assets", + "TranslationFingerprint": "translation", + "NativeToolchainFingerprint": "native" + } + """; + using (var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(json))) + { + var parsed = PayloadArchive.ParseManifest(stream); + if (parsed.SupportedReleases.Count != 2 || parsed.SupportedReleases[1].GameId != "RMCE01" || + parsed.SupportedReleases[1].DolSha256 != rel) + throw new Exception("The packaged release list was not read back exactly."); + } + + void Reject(string description, Action corrupt) + { + var manifest = MultiReleaseManifest(); + corrupt(manifest); + try + { + PayloadArchive.ValidateManifest(manifest); + throw new Exception($"A manifest with {description} was accepted."); + } + catch (InvalidDataException) { } + } + + Reject("the previous single-release schema", manifest => manifest.SchemaVersion = 2); + Reject("no releases", manifest => manifest.SupportedReleases.Clear()); + Reject("an unsupported release", manifest => manifest.SupportedReleases[0].GameId = "RMCK01"); + Reject("a missing input digest", manifest => manifest.SupportedReleases[1].RelSha256 = ""); + Reject("a duplicated release", manifest => + manifest.SupportedReleases.Add(new GameRelease + { + GameId = "RMCE01", DolSha256 = new string('7', 64), RelSha256 = new string('8', 64) + })); + } + + private static void TestExtractedGameRelease() + { + var root = Path.Combine(Path.GetTempPath(), "mkwc-release-" + Guid.NewGuid().ToString("N")); + try + { + var data = Path.Combine(root, "GameAssets", "DATA"); + Directory.CreateDirectory(Path.Combine(data, "sys")); + Directory.CreateDirectory(Path.Combine(data, "files", "rel")); + File.WriteAllText(Path.Combine(data, "sys", "main.dol"), "ntsc-u dol"); + File.WriteAllText(Path.Combine(data, "sys", "fst.bin"), "fst"); + File.WriteAllText(Path.Combine(data, "files", "rel", "StaticR.rel"), "ntsc-u rel"); + File.WriteAllText(Path.Combine(data, "sys", "boot.bin"), "RMCE01" + new string('\0', 26)); + var release = new GameRelease + { + GameId = "RMCE01", + DolSha256 = InputValidation.Sha256File(Path.Combine(data, "sys", "main.dol")), + RelSha256 = InputValidation.Sha256File(Path.Combine(data, "files", "rel", "StaticR.rel")) + }; + + InstallerEngine.ValidateExtractedGame(data, release); + if (new Installation(root).ReadGameId() != "RMCE01") + throw new Exception("The installed game id was not read from the extracted disc header."); + + void Reject(string description, GameRelease expected) + { + try + { + InstallerEngine.ValidateExtractedGame(data, expected); + throw new Exception($"{description} was accepted."); + } + catch (InvalidDataException) { } + } + + Reject("Another release's digests", new GameRelease + { + GameId = "RMCE01", DolSha256 = new string('1', 64), RelSha256 = release.RelSha256 + }); + Reject("A disc header of another region", new GameRelease + { + GameId = "RMCJ01", DolSha256 = release.DolSha256, RelSha256 = release.RelSha256 + }); + File.Delete(Path.Combine(data, "sys", "boot.bin")); + Reject("An extraction without a disc header", release); + try + { + _ = new Installation(root).ReadGameId(); + throw new Exception("A missing disc header produced a game id."); + } + catch (InvalidDataException) { } + } + finally + { + if (Directory.Exists(root)) Directory.Delete(root, recursive: true); + } + } + private static void TestAcceptedExtension(string extension) { var path = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + extension); @@ -694,42 +831,91 @@ internal static class SelfTests private static void TestRetroWfcPayloadSnapshotReconciliation() { - // The endpoint is pinned in exactly one place; this test must not restate it. - const string endpoint = InputValidation.CurrentRetroWfcPayloadUri; const string shaB = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; var root = Path.Combine(Path.GetTempPath(), "mkwc-wfc-snapshot-" + Guid.NewGuid().ToString("N")); try { - InputValidation.ValidateRetroWfcPayloadUri(endpoint); + using var signingRsa = RSA.Create(2048); + var signingKey = signingRsa.ExportParameters(includePrivateParameters: false); + byte[] SignedPayload(string payloadGame) + { + var image = new byte[0x150]; + "WWFC/Payload"u8.CopyTo(image); + BinaryPrimitives.WriteUInt32BigEndian(image.AsSpan(0x0C), (uint)image.Length); + System.Text.Encoding.ASCII.GetBytes(payloadGame).CopyTo(image, 0x138); + image[^1] = 0x5A; + signingRsa.SignData(image.AsSpan(0x110), HashAlgorithmName.SHA256, + RSASignaturePadding.Pkcs1).CopyTo(image.AsSpan(0x10)); + return image; + } + + // Every supported release has its own endpoint and staged file, and a payload staged for + // one region never validates as another region's. + var endpoints = new HashSet(StringComparer.Ordinal); + foreach (var gameId in RetroWfcPayload.SupportedGameIds) + { + var endpoint = RetroWfcPayload.PayloadUri(gameId); + InputValidation.ValidateRetroWfcPayloadUri(endpoint); + if (!endpoints.Add(endpoint)) + throw new Exception($"{gameId} shares another release's Retro-WFC endpoint."); + try + { + InputValidation.ValidateRetroWfcPayloadUri(endpoint + "&extra=1"); + throw new Exception("A non-canonical Retro-WFC endpoint was accepted."); + } + catch (InvalidDataException) { } + + var regionalRoot = Path.Combine(root, "regional-" + gameId); + var regionalPath = Path.Combine(regionalRoot, RetroWfcPayload.PayloadRelativePath(gameId)); + Directory.CreateDirectory(Path.GetDirectoryName(regionalPath)!); + File.WriteAllBytes(regionalPath, SignedPayload(RetroWfcPayload.PayloadGame(gameId))); + if (InputValidation.ResolveRetroWfcPayloadFile(regionalRoot, gameId, signingKey) != regionalPath) + throw new Exception($"{gameId} did not resolve its own staged payload file."); + foreach (var otherGameId in RetroWfcPayload.SupportedGameIds.Where(other => other != gameId)) + { + var foreignRoot = Path.Combine(root, $"foreign-{gameId}-{otherGameId}"); + var foreignPath = Path.Combine(foreignRoot, RetroWfcPayload.PayloadRelativePath(otherGameId)); + Directory.CreateDirectory(Path.GetDirectoryName(foreignPath)!); + File.WriteAllBytes(foreignPath, SignedPayload(RetroWfcPayload.PayloadGame(gameId))); + try + { + _ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(foreignRoot, otherGameId, + signingKey); + throw new Exception($"A {gameId} payload was accepted for {otherGameId}."); + } + catch (InvalidDataException) { } + try + { + _ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(regionalRoot, otherGameId, + signingKey); + throw new Exception($"{otherGameId} accepted a directory staged only for {gameId}."); + } + catch (InvalidDataException) { } + } + } try { - InputValidation.ValidateRetroWfcPayloadUri(endpoint + "&extra=1"); - throw new Exception("A non-canonical Retro-WFC endpoint was accepted."); + _ = RetroWfcPayload.PayloadUri("RMCK01"); + throw new Exception("An unsupported release has a Retro-WFC endpoint."); } catch (InvalidDataException) { } + const string gameUnderTest = "RMCE01"; var installation = new Installation(root); Directory.CreateDirectory(installation.RetroDirectory); var payloadRoot = Path.Combine(root, "download"); - var payloadPath = Path.Combine(payloadRoot, "binary", "payload.RMCPD00.bin"); + var payloadPath = Path.Combine(payloadRoot, RetroWfcPayload.PayloadRelativePath(gameUnderTest)); Directory.CreateDirectory(Path.GetDirectoryName(payloadPath)!); - using var signingRsa = RSA.Create(2048); - var signingKey = signingRsa.ExportParameters(includePrivateParameters: false); - var bytes = new byte[0x140]; - "WWFC/Payload"u8.CopyTo(bytes); - BinaryPrimitives.WriteUInt32BigEndian(bytes.AsSpan(0x0C), (uint)bytes.Length); - bytes[^1] = 0x5A; - signingRsa.SignData(bytes.AsSpan(0x110), HashAlgorithmName.SHA256, - RSASignaturePadding.Pkcs1).CopyTo(bytes.AsSpan(0x10)); + var bytes = SignedPayload(RetroWfcPayload.PayloadGame(gameUnderTest)); File.WriteAllBytes(payloadPath, bytes); - _ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, signingKey); + _ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, gameUnderTest, signingKey); try { - _ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot); + _ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, gameUnderTest); throw new Exception("A payload signed by a foreign key passed the pinned production key."); } catch (InvalidDataException) { } - var shaA = InputValidation.ComputeRetroWfcPayloadSha256(payloadRoot, signingKey); + var shaA = InputValidation.ComputeRetroWfcPayloadSha256(payloadRoot, gameUnderTest, signingKey); var snapshot = new RetroWfcPayloadSnapshot(payloadRoot, shaA, bytes.Length); JsonState.Write(Path.Combine(installation.RetroDirectory, ProductFingerprint.FileName), new ProductFingerprint @@ -764,7 +950,7 @@ internal static class SelfTests File.WriteAllBytes(payloadPath, bytes); try { - _ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, signingKey); + _ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, gameUnderTest, signingKey); throw new Exception("A payload with a malformed declared length was accepted."); } catch (InvalidDataException) { } @@ -774,7 +960,7 @@ internal static class SelfTests File.WriteAllBytes(payloadPath, bytes); try { - _ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, signingKey); + _ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, gameUnderTest, signingKey); throw new Exception("A payload with tampered signed content was accepted."); } catch (InvalidDataException) { } @@ -784,7 +970,7 @@ internal static class SelfTests File.WriteAllBytes(payloadPath, bytes); try { - _ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, signingKey); + _ = InputValidation.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, gameUnderTest, signingKey); throw new Exception("A payload with a malformed header was accepted."); } catch (InvalidDataException) { } @@ -809,6 +995,57 @@ internal static class SelfTests throw new Exception("A non-I/O failure would be retried."); } + private static void TestHostCpuRequirement() + { + // Leaf 1 ecx, leaf 7 ebx, leaf 0x80000001 ecx of a v2-only and a v3 processor. + const uint v2Leaf1 = (1u << 0) | (1u << 9) | (1u << 13) | (1u << 19) | (1u << 20) | (1u << 23); + const uint v3Leaf1 = v2Leaf1 | (1u << 12) | (1u << 22) | (1u << 27) | (1u << 28) | (1u << 29); + const uint v3Leaf7 = (1u << 3) | (1u << 5) | (1u << 8); + Func Cpu(uint maxBasic, uint leaf1, uint leaf7, uint extended) => leaf => leaf switch + { + 0 => [maxBasic, 0, 0, 0], + 1 => [0, 0, leaf1, 0], + 7 => [0, leaf7, 0, 0], + 0x80000000u => [0x80000001u, 0, 0, 0], + 0x80000001u => [0, 0, extended, 0], + _ => [0, 0, 0, 0] + }; + var nehalem = Cpu(11, v2Leaf1, 0, 1u); + var haswell = Cpu(13, v3Leaf1, v3Leaf7, 1u | (1u << 5)); + + void Expect(IReadOnlyList actual, string expected, string what) + { + if (string.Join(", ", actual) != expected) + throw new Exception($"{what}: expected [{expected}], got [{string.Join(", ", actual)}]."); + } + + Expect(HostCpuRequirement.FindMissingFeatures(X86CpuProfile.V2, nehalem, false), "", + "A v2 processor was rejected for the v2 build"); + Expect(HostCpuRequirement.FindMissingFeatures(X86CpuProfile.V3, nehalem, false), + "FMA, MOVBE, OSXSAVE, AVX, F16C, BMI1, AVX2, BMI2, LZCNT", "A v2 processor for the v3 build"); + Expect(HostCpuRequirement.FindMissingFeatures(X86CpuProfile.V3, haswell, true), "", + "A v3 processor was rejected"); + Expect(HostCpuRequirement.FindMissingFeatures(X86CpuProfile.V2, haswell, false), "", + "A v3 processor was rejected for the v2 build"); + Expect(HostCpuRequirement.FindMissingFeatures(X86CpuProfile.V3, haswell, false), + "operating system support for AVX register state (XCR0 YMM bits)", "Disabled AVX state"); + Expect(HostCpuRequirement.FindMissingFeatures(X86CpuProfile.V3, Cpu(6, v3Leaf1, v3Leaf7, 1u | (1u << 5)), true), + "BMI1, AVX2, BMI2", "Unavailable leaf 7"); + Expect(HostCpuRequirement.FindMissingFeatures(X86CpuProfile.V2, Cpu(11, v2Leaf1, 0, 0), false), + "LAHF-SAHF", "Missing LAHF/SAHF"); + + if (HostCpuRequirement.SelectBuildProfile(nehalem, false) != X86CpuProfile.V2) + throw new Exception("A v2 processor was not given the v2 build."); + if (HostCpuRequirement.SelectBuildProfile(haswell, true) != X86CpuProfile.V3) + throw new Exception("A v3 processor was not given the v3 build."); + if (HostCpuRequirement.SelectBuildProfile(haswell, false) != X86CpuProfile.V2) + throw new Exception("A v3 processor without AVX state was given the v3 build."); + + var message = HostCpuRequirement.Describe(X86CpuProfile.V3, ["AVX2"]); + if (!message.Contains("x86-64-v3") || !message.Contains("Missing on this machine: AVX2")) + throw new Exception("The unsupported-processor message lost its detail."); + } + private static void TestRetroWfcTransientRetryPolicy() { if (!InputValidation.IsTransientRetroWfcDownloadFailure( @@ -1261,7 +1498,8 @@ internal static class SelfTests Directory.CreateDirectory(Path.Combine(root, "Toolkit", "CMake", "bin")); Directory.CreateDirectory(Path.Combine(root, "Toolkit", "Ninja")); Directory.CreateDirectory(Path.Combine(root, "Toolkit", "llvm-mingw", "bin")); - Directory.CreateDirectory(Path.Combine(root, "BuildWorkspace", "projects", "mkwii")); + foreach (var project in new[] { "mkwii", "mkwii-ntsc-u", "mkwii-ntsc-j" }) + Directory.CreateDirectory(Path.Combine(root, "BuildWorkspace", "projects", project)); Directory.CreateDirectory(Path.Combine(root, "BuildWorkspace", "runtime", "src")); Directory.CreateDirectory(Path.Combine(root, "BuildWorkspace", "runtime", "assets", "wii", "shared2", "wc24")); @@ -1288,7 +1526,8 @@ internal static class SelfTests File.WriteAllText(Path.Combine(root, "Toolkit", "nodtool.exe"), "tool"); File.WriteAllText(Path.Combine(root, "BuildWorkspace", "LocalBuild.ps1"), "# build"); File.WriteAllText(Path.Combine(root, "BuildWorkspace", "NativeBuildFlags.ps1"), "# flags"); - File.WriteAllText(Path.Combine(root, "BuildWorkspace", "projects", "mkwii", "recomp.yml"), "profiles: {}"); + foreach (var project in new[] { "mkwii", "mkwii-ntsc-u", "mkwii-ntsc-j" }) + File.WriteAllText(Path.Combine(root, "BuildWorkspace", "projects", project, "recomp.yml"), "profiles: {}"); File.WriteAllText(Path.Combine(root, "BuildWorkspace", "runtime", "CMakeLists.txt"), "cmake_minimum_required(VERSION 3.20)"); File.WriteAllText(Path.Combine(root, "BuildWorkspace", "runtime", "src", "main.cpp"), "int main();"); File.WriteAllText(Path.Combine(root, "BuildWorkspace", "runtime", "assets", "wii", "shared2", "wc24", diff --git a/Launcher/WiiCompiled.Setup.Windows/ToolkitFingerprint.cs b/Launcher/WiiCompiled.Setup.Windows/ToolkitFingerprint.cs index 61b1e6c..d7c83b4 100644 --- a/Launcher/WiiCompiled.Setup.Windows/ToolkitFingerprint.cs +++ b/Launcher/WiiCompiled.Setup.Windows/ToolkitFingerprint.cs @@ -16,15 +16,15 @@ internal static class ToolkitFingerprint // v6/native-toolchain v2 forces one clean rebuild past a Ninja stale-object bug. // translation v2 added runtime/src, which the translator regex-scans for native overrides; // v3 replaced it with the native index extracted from it, whenever that index is current. - private const string Version = "mkwc-toolkit-compile-v6"; - private const string TranslationVersion = "mkwc-toolkit-translation-v3"; + private const string Version = "mkwc-toolkit-compile-v7"; + private const string TranslationVersion = "mkwc-toolkit-translation-v4"; private const string NativeToolchainVersion = "mkwc-toolkit-native-toolchain-v2"; private const string PackageVersion = "mkwc-toolkit-package-v1"; private const string RuntimeAssetsVersion = "mkwc-product-runtime-assets-v3"; private const string RuntimeAssetsDescription = "The product runtime assets"; private static readonly string[] SourceExtensions = - [".c", ".cc", ".cpp", ".cxx", ".h", ".hh", ".hpp", ".inl", ".s", ".asm", + [".c", ".cc", ".cpp", ".cxx", ".h", ".hh", ".hpp", ".inl", ".inc", ".s", ".asm", ".cmake", ".txt", ".yml", ".yaml", ".toml", ".json", ".ps1", ".in", ".def", ".patch"]; /// @@ -40,7 +40,11 @@ internal static class ToolkitFingerprint ]; private static readonly string[] TranslationFiles = - [InstalledLayout.WorkspaceEntryPrefix + "LocalBuild.ps1"]; + [ + InstalledLayout.WorkspaceEntryPrefix + "LocalBuild.ps1", + // Maps the PAL-keyed native index to the installed release's addresses. + InstalledLayout.WorkspaceEntryPrefix + "runtime/include/guest_abi/guest_versions.inc" + ]; private const string NativeSourcePrefix = InstalledLayout.WorkspaceEntryPrefix + "runtime/src/"; private const string NativeIndexEntry = InstalledLayout.WorkspaceEntryPrefix + "runtime/native-index.json"; diff --git a/Launcher/build-appimage.sh b/Launcher/build-appimage.sh index 6280cf2..2f6b2bb 100755 --- a/Launcher/build-appimage.sh +++ b/Launcher/build-appimage.sh @@ -169,6 +169,8 @@ echo "Staging the bundled workspace snapshot..." for dir in runtime aurora-main projects; do cp -r "$workspace/$dir" "$appdir/workspace/$dir" done +# Ship source bytes, never submodule checkout pointers or embedded Git databases. +find "$appdir/workspace" -name .git -prune -exec rm -rf {} + # Mirrors Build-Installer.ps1's own staging exclusions exactly: aurora-main/extern/CMakeLists.txt # is the real FetchContent driver and must ship, but any already-fetched dependency *subdirectory* # a developer's local checkout accumulated under extern/ is stale/large build output, not a diff --git a/Launcher/build-cache.sh b/Launcher/build-cache.sh index f88d1b0..55cc070 100644 --- a/Launcher/build-cache.sh +++ b/Launcher/build-cache.sh @@ -1,5 +1,6 @@ -# Shared incremental-build logic for the Unix setups (Linux AppImage and macOS), sourced by -# local-build.sh, local-build-macos.command, the AppImage's AppRun and macos/setup.command. +# Shared incremental-build and release-selection logic for the Unix setups (Linux AppImage and +# macOS), sourced by local-build.sh, local-build-macos.command, macos/extract-disc.command, the +# AppImage's AppRun and macos/setup.command. # Mirrors the Windows installer's translation/toolchain identities and timestamp preservation. # Must stay compatible with macOS's bash 3.2. @@ -76,6 +77,7 @@ mkw_translation_identity() { printf 'rel %s\n' "$(mkw_digest_path "$workspace/Assets/StaticR.rel")" printf 'translator %s\n' "$(mkw_digest_path "$translator")" printf 'script %s\n' "$(mkw_digest_path "$script")" + printf 'regions %s\n' "$(mkw_digest_path "$workspace/runtime/include/guest_abi/guest_versions.inc")" mkw_digest_tree "$workspace" projects mkw_native_index_identity "$workspace" } | mkw_sha256 @@ -99,6 +101,67 @@ mkw_toolchain_identity() { } | mkw_sha256 } +# Prints one fact a projects/*/recomp.yml pins: game_id, region, dol, rel or retro_wfc_payload. +# Literal line matching against the fixed shape, like NativeBuildFlags.ps1's Get-MkwProjectPins. +# $1 = recomp.yml, $2 = fact. +mkw_project_pin() { + awk -v want="$2" ' + { sub(/\r$/, ""); sub(/#.*/, "") } + /^[A-Za-z0-9_]+:/ { section = $1; sub(/:.*/, "", section); input = ""; next } + section == "inputs" && /^ [A-Za-z0-9_]+:[[:space:]]*$/ { input = $1; sub(/:$/, "", input); next } + section == "project" && $1 == (want ":") { print $2; exit } + section == "inputs" && input == want && $1 == "sha256:" { print tolower($2); exit } + want == "retro_wfc_payload" && $1 == "retro_wfc_payload:" { print $2; exit } + ' "$1" +} + +# Prints the recomp.yml of the supported release whose game id is $2. $1 = workspace. +mkw_project_for_game() { + local project + for project in "$1"/projects/*/recomp.yml; do + if [[ -f "$project" && "$(mkw_project_pin "$project" game_id)" == "$2" ]]; then + printf '%s\n' "$project" + return 0 + fi + done + return 1 +} + +# Prints the recomp.yml pinned to $2/main.dol after checking StaticR.rel and any extracted disc +# header against it, like NativeBuildFlags.ps1's Resolve-MkwProjectForAssets. +# $1 = workspace, $2 = assets directory. +mkw_resolve_project() { + local project dol_sha game_id disc_id + dol_sha=$(mkw_sha256 "$2/main.dol") + for project in "$1"/projects/*/recomp.yml; do + [[ -f "$project" && "$(mkw_project_pin "$project" dol)" == "$dol_sha" ]] || continue + game_id=$(mkw_project_pin "$project" game_id) + if [[ "$(mkw_sha256 "$2/StaticR.rel")" != "$(mkw_project_pin "$project" rel)" ]]; then + printf 'StaticR.rel does not match the clean %s release of main.dol.\n' "$game_id" >&2 + return 1 + fi + if [[ -f "$2/DATA/sys/boot.bin" ]]; then + disc_id=$(head -c 6 "$2/DATA/sys/boot.bin") + if [[ "$disc_id" != "$game_id" ]]; then + printf 'The extracted game data is %s but main.dol is %s; extract the game again.\n' "$disc_id" "$game_id" >&2 + return 1 + fi + fi + printf '%s\n' "$project" + return 0 + done + printf 'main.dol (sha256 %s) is not a supported clean Mario Kart Wii release.\n' "$dol_sha" >&2 + return 1 +} + +# The offline file name the translator expects for a release's Retro-WFC payload. $1 = recomp.yml. +mkw_retro_wfc_payload_file() { + local uri + uri=$(mkw_project_pin "$1" retro_wfc_payload) + [[ -n "$uri" ]] || return 1 + printf 'binary/payload.%s.bin\n' "${uri##*g=}" +} + # $1 = JSON file, $2 = key. Prints the recorded string value, or nothing. mkw_read_identity() { [[ -f "$1" ]] || return 0 diff --git a/Launcher/local-build-macos.command b/Launcher/local-build-macos.command index fc57f41..a775b31 100755 --- a/Launcher/local-build-macos.command +++ b/Launcher/local-build-macos.command @@ -19,9 +19,9 @@ Usage: local-build-macos.command --output-dir DIR [options] --profile {base|retro-rewind|both} Product to build (default: base) --output-dir DIR Output .app directory (required; Retro Rewind for both) --base-output-dir DIR Base .app directory (required with --profile both) - --game IMAGE --nodtool PATH Extract and verify a clean PAL RMCP01 disc image first + --game IMAGE --nodtool PATH Extract and verify a clean supported disc image first --retro-rewind-package-dir DIR RetroRewind6 directory (required for Retro Rewind) - --retro-wfc-offline-dir DIR Directory containing binary/payload.RMCPD00.bin + --retro-wfc-offline-dir DIR Directory containing the release's binary/payload..bin --skip-retro-wfc-payload Build Retro Rewind without the shared Retro-WFC payload --force-clean-build Delete local generated and current-architecture native build caches --parallel N Pin translation and build parallelism @@ -82,13 +82,26 @@ if (( builds_retro )); then fi for tool in "$cmake_bin" "$ninja_bin" clang clang++ shasum; do command -v "$tool" >/dev/null || fail "required tool not found: $tool"; done -project="$workspace/projects/mkwii/recomp.yml"; assets="$workspace/Assets"; generated="$workspace/generated" +assets="$workspace/Assets"; generated="$workspace/generated" functions="$generated/functions"; metadata="$generated/base_translation_output.json"; manifest_dir="$workspace/build/base" manifest="$manifest_dir/mkwii_base_manifest.json"; shards="$generated/build_shards" native_build="$workspace/native-build-macos-$macos_arch" -assert_file "$project" 'translation project' -if [[ -n "$game" ]]; then "$script_dir/macos/extract-disc.command" --game "$game" --assets-dir "$assets" --nodtool "$nodtool"; fi +x86_cpu_profile=v3 +if [[ "$macos_arch" == x86_64 ]]; then + native_macros=$(clang -march=native -dM -E -x c /dev/null 2>/dev/null || true) + for macro in __AVX__ __AVX2__ __BMI__ __BMI2__ __F16C__ __FMA__ __LZCNT__ __MOVBE__; do + if ! grep -q "^#define $macro " <<<"$native_macros"; then + x86_cpu_profile=v2 + printf 'MKWCBUILD: This CPU does not support x86-64-v3; building for x86-64-v2\n' + break + fi + done +fi +if [[ -n "$game" ]]; then "$script_dir/macos/extract-disc.command" --workspace "$workspace" --game "$game" --assets-dir "$assets" --nodtool "$nodtool"; fi assert_file "$assets/main.dol" 'extracted main.dol'; assert_file "$assets/StaticR.rel" 'extracted StaticR.rel' +# The translation project is the one pinned to the extracted main.dol, which decides the region. +project=$(mkw_resolve_project "$workspace" "$assets") || fail 'the extracted game cannot be translated' +region=$(mkw_project_pin "$project" region); [[ -n "$region" ]] || fail "could not find the region of $project" if (( force_clean )); then step force-clean 'Discarding translation and native build caches' @@ -148,12 +161,12 @@ else step translate-base 'Translating the user-owned base game' translator translate-recursive "$entry_point" --project "$project" --outdir "$functions" --output-metadata "$metadata" --production-source-bundle "$generated/base_translation_sources.bin" --no-function-files --prune-stale --threads "$translator_threads" step emit-base-manifest 'Creating the local base translation manifest' - translator emit-base-manifest --project "$project" --out "$manifest_dir" --functions-dir "$functions" --translation-output-metadata "$metadata" --region P + translator emit-base-manifest --project "$project" --out "$manifest_dir" --functions-dir "$functions" --translation-output-metadata "$metadata" --region "$region" mkw_write_identity "$translation_provenance" TranslationFingerprint "$translation_fingerprint" fi if (( builds_retro )); then - mod_out="$workspace/build/mods/retro_rewind_full_cpp"; args=(translate-mod --project "$project" --profile retro-rewind --base-manifest "$manifest" --base-translation-output-metadata "$metadata" --code-pul "$retro_root/Binaries/Code.pul" --mod-root "$retro_root" --mod-name 'Retro Rewind' --region P --out "$mod_out" --prefer-cached-inputs --emit-cpp --threads "$translator_threads") - if (( skip_retro_wfc )); then args+=(--skip-retro-wfc); else offline_payload="$retro_wfc/binary/payload.RMCPD00.bin"; assert_file "$offline_payload" 'Offline Retro-WFC payload'; args+=(--retro-wfc-payload "$offline_payload"); fi + mod_out="$workspace/build/mods/retro_rewind_full_cpp"; args=(translate-mod --project "$project" --profile retro-rewind --base-manifest "$manifest" --base-translation-output-metadata "$metadata" --code-pul "$retro_root/Binaries/Code.pul" --mod-root "$retro_root" --mod-name 'Retro Rewind' --region "$region" --out "$mod_out" --prefer-cached-inputs --emit-cpp --threads "$translator_threads") + if (( skip_retro_wfc )); then args+=(--skip-retro-wfc); else payload_file=$(mkw_retro_wfc_payload_file "$project") || fail "$project pins no Retro-WFC payload"; offline_payload="$retro_wfc/$payload_file"; assert_file "$offline_payload" 'Offline Retro-WFC payload'; args+=(--retro-wfc-payload "$offline_payload"); fi step translate-mod 'Translating Retro Rewind'; translator "${args[@]}" fi step generate-data-init 'Generating local game data initialization'; translator generate-data-init --project "$project" @@ -170,7 +183,7 @@ fi step configure-native 'Configuring the native toolchain' # Use Aurora's pinned SDL3 source on macOS. A system SDL3 can be older than # Aurora's required API even when find_package() succeeds. -"$cmake_bin" -S "$workspace/runtime" -B "$native_build" -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_MAKE_PROGRAM="$ninja_bin" -DCMAKE_OSX_ARCHITECTURES="$macos_arch" -DCMAKE_OSX_DEPLOYMENT_TARGET="$macos_deployment_target" -DMKW_TRANSLATED_COMPILE_JOBS="$translated_jobs" -DAURORA_SDL3_PROVIDER=vendor -DMKW_SETUP_VERSION="$setup_version" +"$cmake_bin" -S "$workspace/runtime" -B "$native_build" -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_MAKE_PROGRAM="$ninja_bin" -DCMAKE_OSX_ARCHITECTURES="$macos_arch" -DCMAKE_OSX_DEPLOYMENT_TARGET="$macos_deployment_target" -DMKW_TRANSLATED_COMPILE_JOBS="$translated_jobs" -DMKW_X86_CPU_PROFILE="$x86_cpu_profile" -DAURORA_SDL3_PROVIDER=vendor -DMKW_SETUP_VERSION="$setup_version" mkw_write_identity "$toolchain_provenance" ToolchainFingerprint "$toolchain_fingerprint" targets=(); [[ "$profile" != retro-rewind ]] && targets+=(WiiCompiled); [[ "$profile" != base ]] && targets+=(RetroRewind) step compile "Compiling ${targets[*]} locally"; "$cmake_bin" --build "$native_build" --target "${targets[@]}" --parallel "$global_jobs" diff --git a/Launcher/local-build.sh b/Launcher/local-build.sh index a4ae6dc..e26b258 100755 --- a/Launcher/local-build.sh +++ b/Launcher/local-build.sh @@ -69,6 +69,7 @@ fuse_ld_override="" native_prebuilt_dir="" sysroot="" setup_version="" +x86_cpu_profile=auto usage() { cat <<'EOF' @@ -95,6 +96,8 @@ Usage: local-build.sh --output-dir DIR [options] standard headers/startup files --setup-version VERSION Version recorded in the runtime log (default: in Launcher/Directory.Build.props when present) + --x86-cpu-profile {auto|v2|v3} x86-64 instruction set to build for (default: auto, v3 when + this machine supports it) EOF } @@ -120,6 +123,7 @@ while [[ $# -gt 0 ]]; do --native-prebuilt-dir) native_prebuilt_dir=$2; shift 2 ;; --sysroot) sysroot=$2; shift 2 ;; --setup-version) setup_version=$2; shift 2 ;; + --x86-cpu-profile) x86_cpu_profile=$2; shift 2 ;; -h|--help) usage; exit 0 ;; *) fail "unknown argument: $1" ;; esac @@ -135,6 +139,10 @@ case "$profile" in base|retro-rewind|both) ;; *) fail "--profile must be base, retro-rewind, or both" ;; esac +case "$x86_cpu_profile" in + auto|v2|v3) ;; + *) fail "--x86-cpu-profile must be auto, v2, or v3" ;; +esac builds_retro=0 [[ "$profile" == "retro-rewind" || "$profile" == "both" ]] && builds_retro=1 @@ -184,7 +192,22 @@ if [[ -n "$native_prebuilt_dir" ]]; then assert_file "$native_prebuilt_dir/native_prebuilt.cmake" "Native prebuilt package" fi -project=$workspace/projects/mkwii/recomp.yml +host_supports_x86_64_v3() { + local macros macro + macros=$("$cc_bin" -march=native -dM -E -x c /dev/null 2>/dev/null) || return 1 + for macro in __AVX__ __AVX2__ __BMI__ __BMI2__ __F16C__ __FMA__ __LZCNT__ __MOVBE__; do + grep -q "^#define $macro " <<<"$macros" || return 1 + done +} + +if [[ "$x86_cpu_profile" == "auto" ]]; then + x86_cpu_profile=v3 + if [[ "$(uname -m)" == "x86_64" ]] && ! host_supports_x86_64_v3; then + x86_cpu_profile=v2 + echo "MKWCBUILD: This CPU does not support x86-64-v3; building for x86-64-v2" + fi +fi + assets=$workspace/Assets generated=$workspace/generated functions=$generated/functions @@ -197,9 +220,12 @@ translation_provenance=$generated/translation-provenance.json toolchain_provenance=$build/toolchain-provenance.json retro_root=${retro_rewind_package_dir:-$workspace/PulsarPacks/completed/RetroRewind/RetroRewind6} -assert_file "$project" "Translation project" assert_file "$assets/main.dol" "Extracted main.dol (see translator/README.md - owning the game is required)" assert_file "$assets/StaticR.rel" "Extracted StaticR.rel (see translator/README.md - owning the game is required)" +# The translation project is the one pinned to the extracted main.dol, which decides the region. +project=$(mkw_resolve_project "$workspace" "$assets") || fail "the extracted game cannot be translated" +region=$(mkw_project_pin "$project" region) +[[ -n "$region" ]] || fail "Could not find the region of $project" # The AppImage bundles Clang, but Linux startup objects and the C/C++ link runtimes # still come from the host. Check them before the expensive translation so a missing @@ -338,7 +364,7 @@ else log_step emit-base-manifest "Creating the local base translation manifest" translator emit-base-manifest --project "$project" --out "$base_manifest_dir" \ - --functions-dir "$functions" --translation-output-metadata "$base_metadata" --region P + --functions-dir "$functions" --translation-output-metadata "$base_metadata" --region "$region" mkw_write_identity "$translation_provenance" TranslationFingerprint "$translation_fingerprint" fi @@ -350,12 +376,13 @@ if (( builds_retro )); then translate_mod_args=(translate-mod --project "$project" --profile retro-rewind --base-manifest "$base_manifest" --base-translation-output-metadata "$base_metadata" --code-pul "$code_pul" --mod-root "$retro_root" --mod-name "Retro Rewind" - --region P --out "$retro_out" --prefer-cached-inputs --emit-cpp + --region "$region" --out "$retro_out" --prefer-cached-inputs --emit-cpp --threads "$translator_threads") if (( skip_retro_wfc_payload )); then translate_mod_args+=(--skip-retro-wfc) else - offline_payload=$retro_wfc_offline_dir/binary/payload.RMCPD00.bin + payload_file=$(mkw_retro_wfc_payload_file "$project") || fail "$project pins no Retro-WFC payload" + offline_payload=$retro_wfc_offline_dir/$payload_file assert_file "$offline_payload" "Offline Retro-WFC shared payload" translate_mod_args+=(--retro-wfc-payload "$offline_payload") fi @@ -434,7 +461,8 @@ configure_args=(-S "$workspace/runtime" -B "$build" -G Ninja -DCMAKE_C_COMPILER="$cc_bin" -DCMAKE_CXX_COMPILER="$cxx_bin" -DCMAKE_MAKE_PROGRAM="$ninja_bin" -DMKW_TRANSLATED_COMPILE_JOBS="$translated_jobs" - -DMKW_SETUP_VERSION="$setup_version") + -DMKW_SETUP_VERSION="$setup_version" + -DMKW_X86_CPU_PROFILE="$x86_cpu_profile") # CMAKE_C_COMPILER/CXX_COMPILER stay stable across AppImage runs on their own (they're exactly # what's passed via -D above, and AppRun points --cc/--cxx at a symlink it re-targets at the # current mount every launch - see build-appimage.sh). CMAKE_AR/RANLIB/LINKER/ASM_COMPILER do NOT diff --git a/Launcher/macos/build-setup-pkg.command b/Launcher/macos/build-setup-pkg.command index 396d6f2..ee2972e 100755 --- a/Launcher/macos/build-setup-pkg.command +++ b/Launcher/macos/build-setup-pkg.command @@ -148,8 +148,12 @@ copy_clean "$script_dir/setup.command" "$resources/setup.command"; chmod +x "$re mkdir -p "$resources/workspace" for source in aurora-main projects runtime translator; do [[ -d "$workspace/$source" ]] || fail "required workspace directory is missing: $source" + [[ "$source" != aurora-main || -f "$workspace/$source/CMakeLists.txt" ]] || + fail "aurora-main is empty; run git submodule update --init --recursive" copy_clean "$workspace/$source" "$resources/workspace/$source" done +# Setup bundles contain materialized sources and must work without Git. +find "$resources/workspace" -name .git -prune -exec rm -rf {} + # The translation identity (build-cache.sh) covers the runtime's native registrations through this # index, so it is extracted from exactly the packaged runtime sources. if [[ "$host_arch" == arm64 ]]; then host_translator=$translator_arm64; else host_translator=$translator_x86_64; fi diff --git a/Launcher/macos/extract-disc.command b/Launcher/macos/extract-disc.command index fb3fc05..7aaf384 100755 --- a/Launcher/macos/extract-disc.command +++ b/Launcher/macos/extract-disc.command @@ -1,30 +1,35 @@ #!/usr/bin/env bash -# Extract a user-owned Mario Kart Wii PAL (RMCP01) disc image for a local build. +# Extract a user-owned Mario Kart Wii disc image of a supported release for a local build. # This script deliberately contains no game data and is intended for the macOS # setup application and for maintainers testing that setup path. set -euo pipefail -readonly EXPECTED_DOL_SHA256=80d18895b39c63bd80f457398bfcbb91b7d16ac116a41a88967e954080155b05 -readonly EXPECTED_REL_SHA256=16d9d146112541fefea701ecb5bc1a496f9d50e4a752fbb5b6778e7c6399f67d +script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +# shellcheck source=../build-cache.sh +source "$script_dir/../build-cache.sh" fail() { printf 'extract-disc.command: error: %s\n' "$*" >&2; exit 1; } sha256() { shasum -a 256 "$1" | awk '{ print $1 }'; } usage() { cat <<'EOF' -Usage: extract-disc.command --game IMAGE --assets-dir DIR --nodtool PATH +Usage: extract-disc.command --game IMAGE --assets-dir DIR --nodtool PATH [--workspace DIR] -Extracts a user-owned Mario Kart Wii PAL RMCP01 image into DIR. The final -layout is DIR/main.dol, DIR/StaticR.rel, and DIR/DATA. Existing data is left -untouched unless the complete new extraction passes both content hash checks. +Extracts a user-owned Mario Kart Wii image into DIR. The image must be a release +a projects/*/recomp.yml in the workspace (default: this script's repository) +pins. The final layout is DIR/main.dol, DIR/StaticR.rel, and DIR/DATA. Existing +data is left untouched unless the complete new extraction passes both content +hash checks. EOF } game="" assets_dir="" nodtool="" +workspace=$(cd "$script_dir/../.." && pwd) while (($#)); do case "$1" in + --workspace) workspace=${2:-}; shift 2 ;; --game) game=${2:-}; shift 2 ;; --assets-dir) assets_dir=${2:-}; shift 2 ;; --nodtool) nodtool=${2:-}; shift 2 ;; @@ -39,11 +44,21 @@ done assets_dir=$(mkdir -p "$assets_dir" && cd "$assets_dir" && pwd) +# The disc's game ID selects the release, so an existing extraction is only reused for the same one. +printf 'MKWCBUILD:STEP:validate-disc Checking the selected disc image\n' +disc_info=$("$nodtool" info "$game") || fail 'nodtool could not read the disc image' +game_id=$(awk '/^Game ID: / { print $3; exit }' <<<"$disc_info") +[[ -n "$game_id" ]] || fail 'nodtool did not report the disc game ID' +project=$(mkw_project_for_game "$workspace" "$game_id") || fail "disc $game_id is not a supported Mario Kart Wii release" +expected_dol_sha256=$(mkw_project_pin "$project" dol) +expected_rel_sha256=$(mkw_project_pin "$project" rel) +[[ -n "$expected_dol_sha256" && -n "$expected_rel_sha256" ]] || fail "$project does not pin the clean $game_id digests" + # Sorted " " of every extracted file; recorded at extraction, compared on reuse. data_manifest() { (cd "$1" && find . -type f -print0 | LC_ALL=C sort -z | xargs -0 stat -f '%z %N'); } if [[ -d "$assets_dir/DATA/files" && -f "$assets_dir/.data-manifest" && -f "$assets_dir/main.dol" && -f "$assets_dir/StaticR.rel" ]] && \ - [[ $(sha256 "$assets_dir/main.dol") == "$EXPECTED_DOL_SHA256" && $(sha256 "$assets_dir/StaticR.rel") == "$EXPECTED_REL_SHA256" ]] && \ + [[ $(sha256 "$assets_dir/main.dol") == "$expected_dol_sha256" && $(sha256 "$assets_dir/StaticR.rel") == "$expected_rel_sha256" ]] && \ [[ "$(data_manifest "$assets_dir/DATA")" == "$(cat "$assets_dir/.data-manifest")" ]]; then printf 'MKWCBUILD:STEP:disc-ready Reusing the verified extracted game assets\n' exit 0 @@ -52,8 +67,6 @@ scratch=$(mktemp -d "${TMPDIR:-/tmp}/wiicompiled-disc.XXXXXX") cleanup() { rm -rf "$scratch"; } trap cleanup EXIT -printf 'MKWCBUILD:STEP:validate-disc Checking the selected disc image\n' -"$nodtool" info "$game" >/dev/null printf 'MKWCBUILD:STEP:extract-disc Extracting the user-owned disc image\n' "$nodtool" extract "$game" "$scratch/extracted" @@ -63,8 +76,8 @@ rel=$(find "$scratch/extracted" -type f -path '*/files/rel/StaticR.rel' -print - [[ -n "$rel" ]] || fail 'nodtool extraction did not contain files/rel/StaticR.rel' dol_sha=$(sha256 "$dol") rel_sha=$(sha256 "$rel") -[[ $dol_sha == "$EXPECTED_DOL_SHA256" ]] || fail "main.dol does not match the clean PAL RMCP01 image (expected $EXPECTED_DOL_SHA256, got $dol_sha)" -[[ $rel_sha == "$EXPECTED_REL_SHA256" ]] || fail "StaticR.rel does not match the clean PAL RMCP01 image (expected $EXPECTED_REL_SHA256, got $rel_sha)" +[[ $dol_sha == "$expected_dol_sha256" ]] || fail "main.dol does not match the clean $game_id image (expected $expected_dol_sha256, got $dol_sha)" +[[ $rel_sha == "$expected_rel_sha256" ]] || fail "StaticR.rel does not match the clean $game_id image (expected $expected_rel_sha256, got $rel_sha)" data_root=$(dirname "$(dirname "$dol")") [[ -d "$data_root/files" ]] || fail 'nodtool extraction did not contain the Wii files directory' @@ -92,4 +105,4 @@ mv "$stage/StaticR.rel" "$assets_dir/StaticR.rel" rmdir "$stage" rm -rf "$backup" -printf 'MKWCBUILD:STEP:disc-ready Verified and extracted clean PAL RMCP01 game assets\n' +printf 'MKWCBUILD:STEP:disc-ready Verified and extracted clean %s game assets\n' "$game_id" diff --git a/Launcher/macos/setup.command b/Launcher/macos/setup.command index e9d2b17..a839ad3 100755 --- a/Launcher/macos/setup.command +++ b/Launcher/macos/setup.command @@ -41,6 +41,28 @@ done host_arch=$(uname -m) case "$host_arch" in arm64|x86_64) ;; *) fail "unsupported macOS architecture: $host_arch" ;; esac +# Same x86-64-v2 check as runtime/src/host_cpu_baseline.cpp, before anything is built; +# local-build-macos.command builds for v2 when the CPU lacks v3. +if [[ "$host_arch" == x86_64 ]]; then + cpu_features=$(/usr/sbin/sysctl -n machdep.cpu.features machdep.cpu.extfeatures 2>/dev/null | tr '\n' ' ' || true) + if [[ -n "${cpu_features// /}" ]]; then + missing_features="" + for feature in SSE3=SSE3 SSSE3=SSSE3 CX16=CMPXCHG16B SSE4.1=SSE4.1 SSE4.2=SSE4.2 POPCNT=POPCNT \ + LAHF=LAHF-SAHF; do + [[ " $cpu_features " == *" ${feature%%=*} "* ]] || missing_features+="${missing_features:+, }${feature#*=}" + done + if [[ -n "$missing_features" ]]; then + message="This build needs a processor that supports the x86-64-v2 instruction set. + +Missing on this machine: $missing_features + +x86-64-v2 covers Intel Core processors from Nehalem (2008) onward and AMD processors from Jaguar (2013) onward." + printf 'WiiCompiled Setup: %s\n' "$message" >&2 + notice "$message" + exit 1 + fi + fi +fi host_tools="$resources/tools/$host_arch" nodtool="$host_tools/nodtool" translator="$host_tools/Translator.Cli" @@ -48,7 +70,7 @@ ninja_bin="$host_tools/ninja" if [[ -z "$game" ]]; then game=$(/usr/bin/osascript <<'APPLESCRIPT' -set selectedFile to choose file with prompt "Choose your clean Mario Kart Wii PAL (RMCP01) disc image" +set selectedFile to choose file with prompt "Choose your clean Mario Kart Wii disc image" POSIX path of selectedFile APPLESCRIPT ) || exit 0 @@ -100,18 +122,28 @@ if (( needs_workspace_refresh )); then fi fi +# The extracted disc decides the release, and with it the region's Retro-WFC payload. +# shellcheck source=../build-cache.sh +source "$workspace/Launcher/build-cache.sh" +"$workspace/Launcher/macos/extract-disc.command" --workspace "$workspace" --game "$game" \ + --assets-dir "$workspace/Assets" --nodtool "$nodtool" +project=$(mkw_resolve_project "$workspace" "$workspace/Assets") || fail 'the extracted game cannot be built' + profile=base -build_args=(--workspace "$workspace" --game "$game" --nodtool "$nodtool" --output-dir "$products") +build_args=(--workspace "$workspace" --output-dir "$products") if [[ -n "$retro_dir" ]]; then profile=both # Online play needs the shared Retro-WFC payload. Keep it in the per-user # support directory rather than the packaged app or build workspace, then # verify its pinned signature before publishing it into the local cache. + game_id=$(mkw_project_pin "$project" game_id) + payload_uri=$(mkw_project_pin "$project" retro_wfc_payload) + payload_file=$(mkw_retro_wfc_payload_file "$project") || fail "$project pins no Retro-WFC payload" retro_wfc_dir="$support_root/RetroWfcPayload" - retro_wfc_payload="$retro_wfc_dir/binary/payload.RMCPD00.bin" + retro_wfc_payload="$retro_wfc_dir/$payload_file" cached_payload_valid=0 if [[ -f "$retro_wfc_payload" ]]; then - if "$translator" validate-retro-wfc-payload --directory "$retro_wfc_dir"; then + if "$translator" validate-retro-wfc-payload --directory "$retro_wfc_dir" --game-id "$game_id"; then cached_payload_valid=1 else printf 'Discarding an invalid cached Retro-WFC payload...\n' >&2 @@ -125,15 +157,14 @@ if [[ -n "$retro_dir" ]]; then printf 'Downloading the current Retro-WFC payload needed for online play...\n' mkdir -p "$retro_wfc_dir" payload_stage=$(mktemp -d "$retro_wfc_dir/.payload-download.XXXXXX") - temporary_payload="$payload_stage/binary/payload.RMCPD00.bin" + temporary_payload="$payload_stage/$payload_file" mkdir -p "$(dirname "$temporary_payload")" trap 'rm -rf "$payload_stage"' EXIT if /usr/bin/curl --fail --silent --show-error --connect-timeout 10 --max-time 30 \ - --retry 1 --output "$temporary_payload" \ - 'https://rwfc.net/api/wfc/payload?g=RMCPD00'; then - "$translator" validate-retro-wfc-payload --directory "$payload_stage" || \ + --retry 1 --output "$temporary_payload" "$payload_uri"; then + "$translator" validate-retro-wfc-payload --directory "$payload_stage" --game-id "$game_id" || \ fail 'downloaded Retro-WFC payload failed signature validation' - mkdir -p "$retro_wfc_dir/binary" + mkdir -p "$(dirname "$retro_wfc_payload")" mv "$temporary_payload" "$retro_wfc_payload" rmdir "$payload_stage/binary" "$payload_stage" trap - EXIT diff --git a/aurora-main b/aurora-main new file mode 160000 index 0000000..dd39941 --- /dev/null +++ b/aurora-main @@ -0,0 +1 @@ +Subproject commit dd399416be6346b34450ba37901fbdca9514b0ba diff --git a/aurora-main/.clang-format b/aurora-main/.clang-format deleted file mode 100644 index c144259..0000000 --- a/aurora-main/.clang-format +++ /dev/null @@ -1,29 +0,0 @@ ---- -BasedOnStyle: LLVM -ColumnLimit: 120 -UseTab: Never -TabWidth: 2 ---- -Language: Cpp -DerivePointerAlignment: false -PointerAlignment: Left -AlignAfterOpenBracket: Align -AlignConsecutiveAssignments: false -IndentCaseLabels: false -AllowShortBlocksOnASingleLine: Always -AlignOperands: true -AlignTrailingComments: true -AlwaysBreakBeforeMultilineStrings: true -AlwaysBreakTemplateDeclarations: Yes -BreakConstructorInitializersBeforeComma: true -AlwaysBreakAfterReturnType: None -AlwaysBreakAfterDefinitionReturnType: None -AllowShortFunctionsOnASingleLine: All -Cpp11BracedListStyle: true -NamespaceIndentation: None -BinPackArguments: true -BinPackParameters: true -SortIncludes: false -AccessModifierOffset: -2 -ConstructorInitializerIndentWidth: 0 -ConstructorInitializerAllOnOneLineOrOnePerLine: true diff --git a/aurora-main/.gitignore b/aurora-main/.gitignore deleted file mode 100644 index 5418932..0000000 --- a/aurora-main/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -.buildcache/ -.DS_Store -.idea/ -.cache/ -.vscode/ -.vs/ -build/ -cmake-build-*/ -CMakeUserPresets.json -out/ diff --git a/aurora-main/CMakeLists.txt b/aurora-main/CMakeLists.txt deleted file mode 100644 index 6a0ef53..0000000 --- a/aurora-main/CMakeLists.txt +++ /dev/null @@ -1,93 +0,0 @@ -cmake_minimum_required(VERSION 3.25) -project(aurora LANGUAGES C CXX) -if (APPLE) - enable_language(OBJC) - enable_language(OBJCXX) -endif() -set(CMAKE_C_STANDARD 11) -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_POSITION_INDEPENDENT_CODE ON) - -option(AURORA_ENABLE_GX "Enable GX implementation and WebGPU renderer" ON) -option(AURORA_ENABLE_DVD "Enable DVD implementation backed by nod" OFF) # TODO: need to fix tests -option(AURORA_ENABLE_CARD "Enable CARD implementation based on kabufuda" ON) -option(AURORA_CACHE_USE_ZSTD "Compress WebGPU cache entries with zstd" ON) - -# Dependency versions -set(AURORA_DAWN_VERSION "v20260603.191052" CACHE STRING "Dawn version tag (https://github.com/encounter/dawn-build/releases)") -set(AURORA_SDL3_VERSION "3.4.4" CACHE STRING "SDL3 version tag (https://github.com/libsdl-org/SDL/releases)") -set(AURORA_NOD_VERSION "v2.0.0-alpha.8" CACHE STRING "nod version tag (https://github.com/encounter/nod/releases)") -set(AURORA_LIBUSB_VERSION "1.0.30" CACHE STRING "libusb version tag (https://github.com/libusb/libusb/releases)") - -# Platform-specific defaults -if (CMAKE_CROSSCOMPILING) - # Cross-compiling: vendor everything, don't use system packages - set(_default_provider "vendor") - set(_default_linkage "static") -else () - set(_default_provider "auto") - if (WIN32) - set(_default_linkage "shared") - else () - set(_default_linkage "static") - endif () -endif () - -# Dawn/WebGPU (if AURORA_ENABLE_GX) -set(AURORA_DAWN_PROVIDER "${_default_provider}" CACHE STRING - "How to provide Dawn: auto, vendor (build from source), system (find_package/imported), package (download prebuilt)") -set_property(CACHE AURORA_DAWN_PROVIDER PROPERTY STRINGS auto vendor system package) -set(AURORA_DAWN_LINKAGE "${_default_linkage}" CACHE STRING "Dawn linkage type preference") -set_property(CACHE AURORA_DAWN_LINKAGE PROPERTY STRINGS shared static) - -# SDL3 -set(AURORA_SDL3_PROVIDER "${_default_provider}" CACHE STRING - "How to provide SDL3: auto, vendor (build from source), system (find_package/imported), or package (download prebuilt)") -set_property(CACHE AURORA_SDL3_PROVIDER PROPERTY STRINGS auto vendor system package) -set(AURORA_SDL3_LINKAGE "${_default_linkage}" CACHE STRING "SDL3 linkage type preference") -set_property(CACHE AURORA_SDL3_LINKAGE PROPERTY STRINGS shared static) -option(AURORA_SDL3_LIBUSB "Build the vendored SDL3 with libusb on Windows (official GameCube adapter support)" ON) - -# nod (if AURORA_ENABLE_DVD) -set(AURORA_NOD_PROVIDER "${_default_provider}" CACHE STRING - "How to provide nod: auto, vendor (build from source), system (find_package/imported), package (download prebuilt)") -set_property(CACHE AURORA_NOD_PROVIDER PROPERTY STRINGS auto vendor system package) -set(AURORA_NOD_LINKAGE "${_default_linkage}" CACHE STRING "nod linkage type preference") -set_property(CACHE AURORA_NOD_LINKAGE PROPERTY STRINGS shared static) - -add_subdirectory(extern) - -include(cmake/aurora_core.cmake) -include(cmake/aurora_os.cmake) -if (AURORA_ENABLE_GX) - include(cmake/aurora_gx.cmake) - include(cmake/aurora_gd.cmake) -endif () -include(cmake/aurora_pad.cmake) -include(cmake/aurora_ms.cmake) -include(cmake/aurora_si.cmake) -include(cmake/aurora_main.cmake) -include(cmake/aurora_mtx.cmake) -include(cmake/aurora_vi.cmake) -if(AURORA_ENABLE_CARD) - include(cmake/aurora_card.cmake) -endif() -if (AURORA_ENABLE_DVD) - include(cmake/aurora_dvd.cmake) -endif () - -if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) - add_subdirectory(examples) -endif () - -if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR AND NOT CMAKE_CROSSCOMPILING) - enable_testing() - add_subdirectory(tests) -endif () - -option(AURORA_BUILD_METALFX_PRESENTATION_TEST "Build the macOS MetalFX presentation test" OFF) -if (AURORA_BUILD_METALFX_PRESENTATION_TEST AND APPLE AND AURORA_ENABLE_GX AND DAWN_ENABLE_METAL AND AURORA_METALFX_FRAMEWORK) - add_executable(metalfx_presentation_test tests/metalfx_interop/presentation_test.cpp) - target_include_directories(metalfx_presentation_test PRIVATE lib) - target_link_libraries(metalfx_presentation_test PRIVATE aurora::core aurora::gx aurora::vi dawn::webgpu_dawn) -endif () diff --git a/aurora-main/LICENSE b/aurora-main/LICENSE deleted file mode 100644 index baf2790..0000000 --- a/aurora-main/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License - -Copyright (c) 2022 Luke Street - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/aurora-main/README.md b/aurora-main/README.md deleted file mode 100644 index 9d16c77..0000000 --- a/aurora-main/README.md +++ /dev/null @@ -1,46 +0,0 @@ -
- Logo -
-
- -Aurora is a source-level GameCube & Wii compatibility layer intended for use with game decompilation projects. - -Originally developed for use in [Metaforce](https://github.com/AxioDL/metaforce), a Metroid Prime reverse engineering project. -It now powers several completed source ports, including [Dusklight](https://github.com/TwilitRealm/dusklight). - -### Features - -- Application layer using SDL3 - - Runs on Windows, Linux, macOS, iOS, tvOS, Android -- GX compatibility layer - - Graphics API support: D3D12, Vulkan, Metal - - Highly accurate and performant GX implementation - - Robust pipeline cache system with "transferable" cache support for releases - - Dolphin-compatible texture pack support - - Widescreen & resolution scaling support - - Custom APIs for offscreen rendering -- PAD compatibility layer - - Utilizes `SDL_Gamepad` for wide controller support, including GameCube controller adapters - - Automatically saves and loads controller bindings and port mappings - - Gyro & mouse support -- DVD compatibility layer - - Utilizes [nod](https://github.com/encounter/nod) to support all GameCube/Wii disc image types, including RVZ -- CARD compatibility layer - - Full compatibility with Dolphin `.gci` and `.raw` for game saves -- [Dear ImGui](https://github.com/ocornut/imgui) built-in for simple debug UIs - -### Graphics - -The GX compatibility layer is built on top of [WebGPU](https://www.w3.org/TR/webgpu/), a cross-platform graphics API -abstraction layer. WebGPU allows targeting all major platforms simultaneously with minimal overhead. The WebGPU -implementation used is Chromium's [Dawn](https://dawn.googlesource.com/dawn/). - -![Screenshot](assets/screenshot.png) - -### Building - -See [docs/building.md](docs/building.md) for build instructions, CMake integration, and configuration options. - -### License - -Aurora is licensed under the [MIT License](LICENSE). diff --git a/aurora-main/assets/aurora.png b/aurora-main/assets/aurora.png deleted file mode 100644 index ac897bbe07f185bb3d7002ce08cbc4ef4c5ac273..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19227 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 W2zi=MU&$Xvgqj**4NLXUM*M#q#*n7~ diff --git a/aurora-main/cmake/AuroraCopyRuntimeDLLs.cmake b/aurora-main/cmake/AuroraCopyRuntimeDLLs.cmake deleted file mode 100644 index 66710f0..0000000 --- a/aurora-main/cmake/AuroraCopyRuntimeDLLs.cmake +++ /dev/null @@ -1,57 +0,0 @@ -include_guard(GLOBAL) - -# aurora_copy_runtime_dlls( [...]) -# -# POST_BUILD command that copies all TARGET_RUNTIME_DLLS from the given targets -# next to the executable, plus any extra DLLs that Dawn loads dynamically -# (dxcompiler.dll, dxil.dll). -function(aurora_copy_runtime_dlls target) - if (NOT WIN32) - return() - endif () - - # Copy TARGET_RUNTIME_DLLS for each target - foreach (_t IN ITEMS ${target} ${ARGN}) - add_custom_command(TARGET ${target} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ - COMMAND_EXPAND_LISTS - VERBATIM - ) - endforeach () - - # Copy DXC DLLs that Dawn loads via LoadLibrary at runtime - if (TARGET dawn::webgpu_dawn) - get_target_property(_dawn_loc dawn::webgpu_dawn IMPORTED_LOCATION) - if (NOT _dawn_loc) - get_target_property(_dawn_loc dawn::webgpu_dawn IMPORTED_LOCATION_RELEASE) - endif () - if (_dawn_loc) - cmake_path(GET _dawn_loc PARENT_PATH _dawn_bin_dir) - foreach (_dll IN ITEMS dxcompiler.dll dxil.dll) - if (EXISTS "${_dawn_bin_dir}/${_dll}") - add_custom_command(TARGET ${target} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_dawn_bin_dir}/${_dll}" $ - VERBATIM - ) - endif () - endforeach () - endif () - endif () -endfunction() - -# aurora_install_runtime_dlls( ) -# -# INSTALL rule that copies all DLLs already placed next to the built target -# into the install destination. -function(aurora_install_runtime_dlls target install_destination) - if (NOT WIN32) - return() - endif () - - install(CODE - "file(GLOB _aurora_runtime_dlls \"$/*.dll\")\n\ -if(_aurora_runtime_dlls)\n\ - file(INSTALL DESTINATION \"${install_destination}\" TYPE FILE FILES \${_aurora_runtime_dlls})\n\ -endif()" - ) -endfunction() diff --git a/aurora-main/cmake/AuroraDawnProvider.cmake b/aurora-main/cmake/AuroraDawnProvider.cmake deleted file mode 100644 index 9b28126..0000000 --- a/aurora-main/cmake/AuroraDawnProvider.cmake +++ /dev/null @@ -1,280 +0,0 @@ -include_guard(GLOBAL) - -# Resolve Dawn/WebGPU dependency based on AURORA_DAWN_PROVIDER and AURORA_DAWN_LINKAGE. -# -# After this module runs: -# - dawn::webgpu_dawn target is available -# - dawn::dawncpp_headers target is available (for tests) -# - DAWN_ENABLE_* backend variables are set for the target platform -# - AURORA_DAWN_IS_SHARED is set to TRUE/FALSE - -# When using a non-vendored Dawn, we don't get DAWN_ENABLE_* from its build. -# Infer from the target platform instead. -function(_aurora_dawn_set_platform_backends) - if (WIN32) - set(DAWN_ENABLE_D3D12 ON CACHE INTERNAL "") - # Disable D3D11 because this Aurora fork does not support it. - set(DAWN_ENABLE_D3D11 OFF CACHE INTERNAL "") - set(DAWN_ENABLE_VULKAN ON CACHE INTERNAL "") - set(DAWN_ENABLE_METAL OFF CACHE INTERNAL "") - set(DAWN_ENABLE_DESKTOP_GL OFF CACHE INTERNAL "") - set(DAWN_ENABLE_OPENGLES OFF CACHE INTERNAL "") - set(DAWN_ENABLE_NULL ON CACHE INTERNAL "") - elseif (APPLE) - set(DAWN_ENABLE_D3D12 OFF CACHE INTERNAL "") - set(DAWN_ENABLE_D3D11 OFF CACHE INTERNAL "") - set(DAWN_ENABLE_VULKAN OFF CACHE INTERNAL "") - set(DAWN_ENABLE_METAL ON CACHE INTERNAL "") - set(DAWN_ENABLE_DESKTOP_GL OFF CACHE INTERNAL "") - set(DAWN_ENABLE_OPENGLES OFF CACHE INTERNAL "") - set(DAWN_ENABLE_NULL ON CACHE INTERNAL "") - else () # Linux / other - set(DAWN_ENABLE_D3D12 OFF CACHE INTERNAL "") - set(DAWN_ENABLE_D3D11 OFF CACHE INTERNAL "") - set(DAWN_ENABLE_VULKAN ON CACHE INTERNAL "") - set(DAWN_ENABLE_METAL OFF CACHE INTERNAL "") - set(DAWN_ENABLE_DESKTOP_GL OFF CACHE INTERNAL "") - set(DAWN_ENABLE_OPENGLES OFF CACHE INTERNAL "") - set(DAWN_ENABLE_NULL ON CACHE INTERNAL "") - endif () -endfunction() - -# ── Auto: resolve provider based on platform availability ── -set(_aurora_dawn_provider "${AURORA_DAWN_PROVIDER}") -if (_aurora_dawn_provider STREQUAL "auto") - # Prebuilt Dawn packages available for: windows-{amd64,arm64}, linux-{x86_64,aarch64}, darwin-{arm64,x86_64} - set(_has_package FALSE) - if (WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(AMD64|x86_64|ARM64|aarch64)$") - set(_has_package TRUE) - elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|aarch64)$") - set(_has_package TRUE) - elseif (APPLE AND (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|x86_64)$" OR CMAKE_OSX_ARCHITECTURES MATCHES "^(arm64|x86_64)$")) - set(_has_package TRUE) - endif () - - if (_has_package) - set(_aurora_dawn_provider "package") - else () - set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL ON) - find_package(Dawn QUIET) - set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL OFF) - if (Dawn_FOUND) - set(_aurora_dawn_provider "system") - else () - set(_aurora_dawn_provider "vendor") - endif () - endif () - set(AURORA_DAWN_PROVIDER "${_aurora_dawn_provider}" CACHE STRING "" FORCE) - message(STATUS "aurora: Dawn auto-resolved provider: ${_aurora_dawn_provider}") -endif () - -if (_aurora_dawn_provider STREQUAL "vendor") - # ── Vendor: FetchContent build from source ── - if (NOT TARGET webgpu_dawn) - message(STATUS "aurora: Fetching Dawn (provider=vendor, linkage=${AURORA_DAWN_LINKAGE})") - - if (AURORA_DAWN_LINKAGE STREQUAL "shared") - set(DAWN_BUILD_MONOLITHIC_LIBRARY SHARED CACHE INTERNAL - "Bundle all dawn components into a single shared library.") - else () - set(DAWN_BUILD_MONOLITHIC_LIBRARY STATIC CACHE INTERNAL - "Bundle all dawn components into a single static library.") - endif () - set(DAWN_BUILD_SAMPLES OFF CACHE INTERNAL "Disable Dawn sample applications") - set(DAWN_BUILD_BENCHMARKS OFF CACHE INTERNAL "Disable Dawn benchmarks") - set(DAWN_SUPPORTS_GLFW_FOR_WINDOWING OFF CACHE INTERNAL "Disable Dawn GLFW windowing") - set(DAWN_ENABLE_DESKTOP_GL OFF CACHE INTERNAL "Enable compilation of the OpenGL backend") - set(DAWN_ENABLE_OPENGLES OFF CACHE INTERNAL "Enable compilation of the OpenGL ES backend") - set(DAWN_FETCH_DEPENDENCIES ON CACHE INTERNAL - "Use fetch_dawn_dependencies.py as an alternative to using depot_tools") - if (CMAKE_SYSTEM_NAME STREQUAL Linux) - set(DAWN_USE_WAYLAND ON CACHE INTERNAL "Enable support for Wayland surface") - endif () - set(TINT_BUILD_TESTS OFF CACHE INTERNAL "Build tests") - set(TINT_BUILD_CMD_TOOLS OFF CACHE INTERNAL "Build the Tint command line tools") - if (NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY OR CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "DLL$") - set(ABSL_MSVC_STATIC_RUNTIME OFF CACHE INTERNAL "Link static runtime libraries") - else () - set(ABSL_MSVC_STATIC_RUNTIME ON CACHE INTERNAL "Link static runtime libraries") - endif () - - include(FetchContent) - FetchContent_Declare(dawn - URL "https://github.com/google/dawn/archive/refs/tags/${AURORA_DAWN_VERSION}.tar.gz" - DOWNLOAD_EXTRACT_TIMESTAMP FALSE - EXCLUDE_FROM_ALL - ) - FetchContent_MakeAvailable(dawn) - if (NOT TARGET webgpu_dawn) - message(FATAL_ERROR "Failed to make dawn available") - endif () - else () - message(STATUS "aurora: Using existing Dawn") - endif () - - if (AURORA_DAWN_LINKAGE STREQUAL "shared") - set(AURORA_DAWN_IS_SHARED TRUE PARENT_SCOPE) - else () - set(AURORA_DAWN_IS_SHARED FALSE PARENT_SCOPE) - endif () - -elseif (_aurora_dawn_provider STREQUAL "system") - # ── System: find_package(Dawn) ── - message(STATUS "aurora: Using system Dawn (provider=system)") - if (NOT Dawn_FOUND) - set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL ON) - find_package(Dawn REQUIRED) - set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL OFF) - endif () - if (NOT TARGET dawn::webgpu_dawn) - message(FATAL_ERROR "find_package(Dawn) succeeded but dawn::webgpu_dawn target not found") - endif () - _aurora_dawn_set_platform_backends() - - get_target_property(_dawn_type dawn::webgpu_dawn TYPE) - if (_dawn_type STREQUAL "SHARED_LIBRARY") - set(AURORA_DAWN_IS_SHARED TRUE PARENT_SCOPE) - else () - set(AURORA_DAWN_IS_SHARED FALSE PARENT_SCOPE) - endif () - -elseif (_aurora_dawn_provider STREQUAL "package") - # ── Package: download prebuilt Dawn install tree ── - if (NOT AURORA_DAWN_PACKAGE_URL) - string(TOLOWER "${CMAKE_SYSTEM_NAME}" _dawn_system) - string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" _dawn_arch) - if (APPLE AND CMAKE_OSX_ARCHITECTURES) - list(GET CMAKE_OSX_ARCHITECTURES 0 _dawn_osx_arch) - string(TOLOWER "${_dawn_osx_arch}" _dawn_arch) - endif () - if (_dawn_system STREQUAL "windows") - if (_dawn_arch STREQUAL "x86_64") - set(_dawn_arch "amd64") - elseif (_dawn_arch STREQUAL "aarch64") - set(_dawn_arch "arm64") - endif () - endif () - set(AURORA_DAWN_PACKAGE_URL - "https://github.com/theofficialgman/dawn-build/releases/download/${AURORA_DAWN_VERSION}/dawn-${_dawn_system}-${_dawn_arch}.tar.gz") - - # A release asset is mutable: the same tag has already served two different windows-amd64 archives, - # and a cached extraction is never re-verified. Pin the digest for the combinations we ship. - if (NOT AURORA_DAWN_PACKAGE_URL_HASH AND AURORA_DAWN_VERSION STREQUAL "v20260603.191052") - if (_dawn_system STREQUAL "windows" AND _dawn_arch STREQUAL "amd64") - set(AURORA_DAWN_PACKAGE_URL_HASH - "SHA256=13be9cff8b9b179c42dcd16aeabb6effcc8f0dfdcc14463eda2a5caeda225142") - elseif (_dawn_system STREQUAL "windows" AND _dawn_arch STREQUAL "arm64") - set(AURORA_DAWN_PACKAGE_URL_HASH - "SHA256=bf2d921110f14a1d6553f673c5597988e66c02af5587e4a1fee167937d247734") - elseif (_dawn_system STREQUAL "linux" AND _dawn_arch STREQUAL "x86_64") - set(AURORA_DAWN_PACKAGE_URL_HASH - "SHA256=7adcf241bb2a24ec0c576609f2d67203e0e65db9c5a286ca2bbb6281fa644b35") - elseif (_dawn_system STREQUAL "linux" AND _dawn_arch STREQUAL "aarch64") - set(AURORA_DAWN_PACKAGE_URL_HASH - "SHA256=2415e253d46f91b2d72fc73bf6055fb31b98b67c773dc546e1991b1cf019732f") - elseif (_dawn_system STREQUAL "darwin" AND _dawn_arch STREQUAL "arm64") - set(AURORA_DAWN_PACKAGE_URL_HASH - "SHA256=0a8ea8eb0159fc0ba1083c52155d9376fb173cffe690b400464a6ad8881bb461") - elseif (_dawn_system STREQUAL "darwin" AND _dawn_arch STREQUAL "x86_64") - set(AURORA_DAWN_PACKAGE_URL_HASH - "SHA256=5fe2c7a2a8b4cb82acee4af16779a83ae333c7657b9dc1a5008f5fd1f5ad5f80") - elseif (_dawn_system STREQUAL "ios" AND _dawn_arch STREQUAL "arm64") - set(AURORA_DAWN_PACKAGE_URL_HASH - "SHA256=f97701d26fd1f25bbcc260b4c31736ede134c730c12556029e2470fde967f424") - elseif (_dawn_system STREQUAL "android" AND _dawn_arch STREQUAL "aarch64") - set(AURORA_DAWN_PACKAGE_URL_HASH - "SHA256=0e63e8cbf53551f703f582d1306f4257c0380353f66b53369d96952ce6d9f934") - endif () - endif () - endif () - message(STATUS "aurora: Fetching prebuilt Dawn package from ${AURORA_DAWN_PACKAGE_URL}") - - set(_dawn_prebuilt_hash_argument "") - if (AURORA_DAWN_PACKAGE_URL_HASH) - set(_dawn_prebuilt_hash_argument URL_HASH "${AURORA_DAWN_PACKAGE_URL_HASH}") - endif () - - include(FetchContent) - FetchContent_Declare(dawn_prebuilt - URL "${AURORA_DAWN_PACKAGE_URL}" - ${_dawn_prebuilt_hash_argument} - DOWNLOAD_EXTRACT_TIMESTAMP FALSE - ) - FetchContent_MakeAvailable(dawn_prebuilt) - - # Detect package layout: may be nested in a subdirectory - set(_dawn_pkg_dir "${dawn_prebuilt_SOURCE_DIR}") - file(GLOB _dawn_subdirs - "${dawn_prebuilt_SOURCE_DIR}/dawn-*" - "${dawn_prebuilt_SOURCE_DIR}/Dawn-*" - ) - foreach (_sd IN LISTS _dawn_subdirs) - if (IS_DIRECTORY "${_sd}") - set(_dawn_pkg_dir "${_sd}") - break() - endif () - endforeach () - if (IS_DIRECTORY "${dawn_prebuilt_SOURCE_DIR}/dawn-install") - set(_dawn_pkg_dir "${dawn_prebuilt_SOURCE_DIR}/dawn-install") - endif () - - # Static Dawn packages may link Threads::Threads - find_package(Threads QUIET) - - # Find DawnConfig.cmake in the package - set(_dawn_cmake_found FALSE) - foreach (_cmake_path - "${_dawn_pkg_dir}/lib/cmake/Dawn" - "${_dawn_pkg_dir}/lib64/cmake/Dawn" - "${_dawn_pkg_dir}/cmake/Dawn" - "${_dawn_pkg_dir}/cmake" - ) - if (EXISTS "${_cmake_path}/DawnConfig.cmake") - set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL ON) - find_package(Dawn REQUIRED CONFIG PATHS "${_cmake_path}" NO_DEFAULT_PATH) - set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL OFF) - set(_dawn_cmake_found TRUE) - break() - endif () - endforeach () - - if (NOT _dawn_cmake_found OR NOT TARGET dawn::webgpu_dawn) - message(FATAL_ERROR - "Dawn package does not contain DawnConfig.cmake.\n" - "Searched: ${_dawn_pkg_dir}/{lib,lib64,cmake}/cmake/Dawn/\n" - "The package must be a Dawn install tree built with DAWN_ENABLE_INSTALL=ON.") - endif () - - _aurora_dawn_set_platform_backends() - - get_target_property(_dawn_pkg_type dawn::webgpu_dawn TYPE) - if (_dawn_pkg_type STREQUAL "SHARED_LIBRARY") - set(AURORA_DAWN_IS_SHARED TRUE PARENT_SCOPE) - - else () - set(AURORA_DAWN_IS_SHARED FALSE PARENT_SCOPE) - endif () - -else () - message(FATAL_ERROR "Invalid AURORA_DAWN_PROVIDER: ${AURORA_DAWN_PROVIDER} " - "(must be auto, vendor, system, or package)") -endif () - -# Ensure dawn::dawncpp_headers target exists (needed by tests). -# When Dawn is vendored, this target is created by Dawn's CMake. -# For package/system providers, create it from the same include dirs. -if (NOT TARGET dawn::dawncpp_headers) - add_library(dawn_dawncpp_headers INTERFACE IMPORTED GLOBAL) - get_target_property(_dawn_inc dawn::webgpu_dawn INTERFACE_INCLUDE_DIRECTORIES) - if (NOT _dawn_inc) - if (TARGET dawn::dawn_public_config) - get_target_property(_dawn_inc dawn::dawn_public_config INTERFACE_INCLUDE_DIRECTORIES) - endif () - endif () - if (_dawn_inc) - target_include_directories(dawn_dawncpp_headers INTERFACE ${_dawn_inc}) - else () - target_link_libraries(dawn_dawncpp_headers INTERFACE dawn::webgpu_dawn) - endif () - add_library(dawn::dawncpp_headers ALIAS dawn_dawncpp_headers) -endif () diff --git a/aurora-main/cmake/AuroraLibUSB.cmake b/aurora-main/cmake/AuroraLibUSB.cmake deleted file mode 100644 index 1aaa297..0000000 --- a/aurora-main/cmake/AuroraLibUSB.cmake +++ /dev/null @@ -1,43 +0,0 @@ -# libusb for SDL3's HIDAPI joystick drivers on Windows. -# -# The official GameCube adapter (WUP-028) is a vendor-specific USB device, not HID, so SDL3 -# can only reach it through libusb - which the official SDL3 packages leave out. The vendored -# SDL3 build compiles libusb from the pinned upstream release and links it in statically. - -include(FetchContent) -FetchContent_Declare(libusb - URL "https://github.com/libusb/libusb/releases/download/v${AURORA_LIBUSB_VERSION}/libusb-${AURORA_LIBUSB_VERSION}.tar.bz2" - DOWNLOAD_EXTRACT_TIMESTAMP FALSE -) -# Upstream ships no CMakeLists.txt, so this only populates the source tree. -FetchContent_MakeAvailable(libusb) - -set(_libusb_root "${libusb_SOURCE_DIR}/libusb") -add_library(usb-1.0 STATIC - "${_libusb_root}/core.c" - "${_libusb_root}/descriptor.c" - "${_libusb_root}/hotplug.c" - "${_libusb_root}/io.c" - "${_libusb_root}/strerror.c" - "${_libusb_root}/sync.c" - "${_libusb_root}/os/events_windows.c" - "${_libusb_root}/os/threads_windows.c" - "${_libusb_root}/os/windows_common.c" - "${_libusb_root}/os/windows_usbdk.c" - "${_libusb_root}/os/windows_winusb.c" -) -target_include_directories(usb-1.0 - PUBLIC "${_libusb_root}" - PRIVATE "${CMAKE_CURRENT_LIST_DIR}/libusb" "${_libusb_root}/os" -) -set_target_properties(usb-1.0 PROPERTIES UNITY_BUILD OFF) -add_library(LibUSB::LibUSB ALIAS usb-1.0) - -# SDL's FindLibUSB expects an installed copy. Satisfy its presence checks with this target -# instead: the alias pre-empts the imported target it would otherwise create, and the link -# probe is answered up front because the archive does not exist until build time. -set(LibUSB_INCLUDE_PATH "${_libusb_root}" CACHE PATH "" FORCE) -set(LibUSB_LIBRARY "usb-1.0" CACHE STRING "" FORCE) -set(HAVE_LIBUSB_H 1 CACHE INTERNAL "" FORCE) -set(SDL_HIDAPI_LIBUSB ON CACHE BOOL "" FORCE) -set(SDL_HIDAPI_LIBUSB_SHARED OFF CACHE BOOL "" FORCE) diff --git a/aurora-main/cmake/AuroraNodProvider.cmake b/aurora-main/cmake/AuroraNodProvider.cmake deleted file mode 100644 index b112d9d..0000000 --- a/aurora-main/cmake/AuroraNodProvider.cmake +++ /dev/null @@ -1,150 +0,0 @@ -include_guard(GLOBAL) - -# Resolve nod dependency based on AURORA_NOD_PROVIDER. -# -# After this module runs: -# - nod::nod target is available -# -# AURORA_NOD_LINKAGE controls shared vs static linkage: -# - "shared" (default): prefer nod::nod_shared -# - "static": prefer nod::nod_static - -# ── Auto: resolve provider based on platform availability ── -set(_aurora_nod_provider "${AURORA_NOD_PROVIDER}") -if (_aurora_nod_provider STREQUAL "auto") - # Prebuilt nod packages available for: windows-x86_64, linux-x86_64, macos-arm64 - set(_has_package FALSE) - if (WIN32 AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(AMD64)$") - set(_has_package TRUE) - elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64)$") - set(_has_package TRUE) - elseif (APPLE AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64)$") - set(_has_package TRUE) - endif () - - if (_has_package) - set(_aurora_nod_provider "package") - else () - find_package(nod QUIET CONFIG) - if (nod_FOUND) - set(_aurora_nod_provider "system") - else () - set(_aurora_nod_provider "vendor") - endif () - endif () - set(AURORA_NOD_PROVIDER "${_aurora_nod_provider}" CACHE STRING "" FORCE) - message(STATUS "aurora: nod auto-resolved provider: ${_aurora_nod_provider}") -endif () - -if (_aurora_nod_provider STREQUAL "vendor") - # ── Vendor: FetchContent + Corrosion build from source ── - if (NOT TARGET nod::nod) - message(STATUS "aurora: Building nod (provider=vendor, linkage=${AURORA_NOD_LINKAGE})") - - # Corrosion may default to the host Rust target triple (commonly x86_64 on - # Windows). Force Rust to i686 for true Win32 builds so nod and its vendored - # compression libraries are built for the same architecture as the C/C++ build. - if (WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 4) - set(Rust_CARGO_TARGET "i686-pc-windows-msvc" CACHE STRING "Rust target triple" FORCE) - set(Rust_RUSTUP_INSTALL_MISSING_TARGET ON CACHE BOOL "Allow Corrosion to install missing Rust targets" FORCE) - message(STATUS "aurora: forcing Rust_CARGO_TARGET=${Rust_CARGO_TARGET} for Win32 nod build") - endif () - - # Control whether nod builds shared, static, or both. - # Save/restore BUILD_SHARED_LIBS to avoid leaking into other subdirectories. - set(_aurora_nod_saved_bsl "${BUILD_SHARED_LIBS}") - if (AURORA_NOD_LINKAGE STREQUAL "static") - set(BUILD_SHARED_LIBS OFF) - else () - set(BUILD_SHARED_LIBS ON) - endif () - - include(FetchContent) - FetchContent_Declare(aurora_nod - GIT_REPOSITORY "https://github.com/encounter/nod.git" - GIT_TAG "${AURORA_NOD_VERSION}" - GIT_SHALLOW TRUE - EXCLUDE_FROM_ALL - ) - - FetchContent_MakeAvailable(aurora_nod) - set(BUILD_SHARED_LIBS "${_aurora_nod_saved_bsl}") - unset(_aurora_nod_saved_bsl) - if (NOT TARGET nod::nod) - message(FATAL_ERROR "Failed to make nod available") - endif () - else () - message(STATUS "aurora: Using existing nod") - endif () - -elseif (_aurora_nod_provider STREQUAL "system") - # ── System: find preinstalled nod ── - message(STATUS "aurora: Using system nod (provider=system, linkage=${AURORA_NOD_LINKAGE})") - - if (NOT nod_FOUND) - set(_aurora_nod_saved_bsl "${BUILD_SHARED_LIBS}") - if (AURORA_NOD_LINKAGE STREQUAL "static") - set(BUILD_SHARED_LIBS OFF) - else () - set(BUILD_SHARED_LIBS ON) - endif () - - find_package(nod REQUIRED CONFIG) - set(BUILD_SHARED_LIBS "${_aurora_nod_saved_bsl}") - unset(_aurora_nod_saved_bsl) - endif () - if (NOT TARGET nod::nod) - message(FATAL_ERROR "find_package(nod) succeeded but nod::nod target not found") - endif () - message(STATUS "aurora: Found nod via find_package(nod)") - -elseif (_aurora_nod_provider STREQUAL "package") - # ── Package: download prebuilt nod library ── - if (NOT AURORA_NOD_PACKAGE_URL) - if (WIN32 AND CMAKE_SIZEOF_VOID_P EQUAL 8) - set(_nod_platform "windows-x86_64") - elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|AMD64|amd64)$") - set(_nod_platform "linux-x86_64") - elseif (APPLE AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|ARM64)$") - set(_nod_platform "macos-arm64") - else () - message(FATAL_ERROR - "AURORA_NOD_PROVIDER=package requires AURORA_NOD_PACKAGE_URL on this platform.\n" - "Prebuilt packages: https://github.com/encounter/nod/releases") - endif () - set(AURORA_NOD_PACKAGE_URL - "https://github.com/encounter/nod/releases/download/${AURORA_NOD_VERSION}/libnod-${_nod_platform}.tar.gz") - endif () - message(STATUS "aurora: Fetching prebuilt nod package (provider=package, linkage=${AURORA_NOD_LINKAGE})") - - include(FetchContent) - FetchContent_Declare(nod_prebuilt - URL "${AURORA_NOD_PACKAGE_URL}" - DOWNLOAD_EXTRACT_TIMESTAMP FALSE - EXCLUDE_FROM_ALL - ) - FetchContent_MakeAvailable(nod_prebuilt) - - # The prebuilt package ships a CMake config that creates nod::nod_shared, - # nod::nod_static, and a default nod::nod (based on BUILD_SHARED_LIBS). - # Set BUILD_SHARED_LIBS so the config selects the right default target. - set(_aurora_nod_saved_bsl "${BUILD_SHARED_LIBS}") - if (AURORA_NOD_LINKAGE STREQUAL "static") - set(BUILD_SHARED_LIBS OFF) - else () - set(BUILD_SHARED_LIBS ON) - endif () - find_package(nod REQUIRED CONFIG - PATHS "${nod_prebuilt_SOURCE_DIR}" - NO_DEFAULT_PATH - ) - set(BUILD_SHARED_LIBS "${_aurora_nod_saved_bsl}") - unset(_aurora_nod_saved_bsl) - if (NOT TARGET nod::nod) - message(FATAL_ERROR "Prebuilt nod package did not provide nod::nod target") - endif () - -else () - message(FATAL_ERROR "Invalid AURORA_NOD_PROVIDER: ${AURORA_NOD_PROVIDER} " - "(must be auto, vendor, system, or package)") -endif () diff --git a/aurora-main/cmake/AuroraSDL3Patches.cmake b/aurora-main/cmake/AuroraSDL3Patches.cmake deleted file mode 100644 index c435871..0000000 --- a/aurora-main/cmake/AuroraSDL3Patches.cmake +++ /dev/null @@ -1,388 +0,0 @@ -# Source-level fixes applied to the vendored SDL3 tree before it is built. -# -# Each patch is an exact string replacement, checked and idempotent: a tree that -# already carries the fix is left alone, a tree where the anchor text is missing -# (a different SDL version) stops the configure with a clear message instead of -# silently building without the fix. -# -# Used two ways: -# - included by AuroraSDL3Provider.cmake, which calls aurora_sdl3_apply_patches() -# on a pre-provided source tree (FETCHCONTENT_SOURCE_DIR_SDL); -# - run as `cmake -DSDL_SOURCE_DIR= -P AuroraSDL3Patches.cmake` from the -# FetchContent PATCH_COMMAND for a freshly extracted tarball. - -function(_aurora_sdl3_replace file description old new) - file(READ "${file}" _content) - string(FIND "${_content}" "${new}" _already) - if (NOT _already EQUAL -1) - return() - endif () - string(FIND "${_content}" "${old}" _anchor) - if (_anchor EQUAL -1) - message(FATAL_ERROR "aurora: SDL3 patch '${description}' does not apply to ${file}; " - "the vendored SDL version changed, review AuroraSDL3Patches.cmake") - endif () - string(REPLACE "${old}" "${new}" _content "${_content}") - file(WRITE "${file}" "${_content}") - message(STATUS "aurora: SDL3 patch applied: ${description}") -endfunction() - -function(aurora_sdl3_apply_patches sdl_source_dir) - set(_wii "${sdl_source_dir}/src/joystick/hidapi/SDL_hidapi_wii.c") - if (NOT EXISTS "${_wii}") - message(FATAL_ERROR "aurora: SDL3 source tree at ${sdl_source_dir} has no SDL_hidapi_wii.c") - endif () - set(_rumble "${sdl_source_dir}/src/joystick/hidapi/SDL_hidapi_rumble.c") - if (NOT EXISTS "${_rumble}") - message(FATAL_ERROR "aurora: SDL3 source tree at ${sdl_source_dir} has no SDL_hidapi_rumble.c") - endif () - set(_hidapi "${sdl_source_dir}/src/joystick/hidapi/SDL_hidapijoystick.c") - if (NOT EXISTS "${_hidapi}") - message(FATAL_ERROR "aurora: SDL3 source tree at ${sdl_source_dir} has no SDL_hidapijoystick.c") - endif () - - # Backport of SDL 71f4af732 (drop once SDL includes it): rumble writes must not hold dev_lock. - _aurora_sdl3_replace("${_rumble}" "HIDAPI rumble writes no longer hold the device lock" -[==[ if (request) { - SDL_LockMutex(request->device->dev_lock); - if (request->device->dev) { -#ifdef DEBUG_RUMBLE - HIDAPI_DumpPacket("Rumble packet: size = %d", request->data, request->size); -#endif - SDL_hid_write(request->device->dev, request->data, request->size); - } - SDL_UnlockMutex(request->device->dev_lock); -]==] -[==[ if (request) { - if (request->device->dev) { -#ifdef DEBUG_RUMBLE - HIDAPI_DumpPacket("Rumble packet: size = %d", request->data, request->size); -#endif - SDL_hid_write(request->device->dev, request->data, request->size); - } -]==]) - - # Without the lock, closing the handle must wait for in-flight rumble writes. - _aurora_sdl3_replace("${_hidapi}" "HIDAPI device close waits for pending rumble" -[==[ device->driver->FreeDevice(device); - device->driver = NULL; - - SDL_LockMutex(device->dev_lock); -]==] -[==[ device->driver->FreeDevice(device); - device->driver = NULL; - - while (SDL_GetAtomicInt(&device->rumble_pending) > 0) { - SDL_Delay(10); - } - - SDL_LockMutex(device->dev_lock); -]==]) - - # Wii Remote: rebuild the joystick in place after an extension change. - # - # When a Nunchuk or Classic Controller is plugged in or pulled out, the driver - # flags the joystick as disconnected so it can come back with the new name and - # capabilities. But the HID device stays open, and HIDAPI only removes a - # joystick-less device once its handle is closed, so nothing ever re-creates - # the joystick: the remote is gone for good until the application toggles the - # driver hint (which closes and re-opens the Bluetooth HID handle, something - # some Windows Bluetooth stacks answer by dropping the link). Instead, when the - # device has no joystick, probe the extension again (two bounded attempts, at - # most once a second) and connect a new joystick on the still-open handle. - _aurora_sdl3_replace("${_wii}" "Wii Remote in-place reconnect (context field)" -[==[ Uint64 m_ulNextMotionPlusCheck; - bool m_bDisconnected; -]==] -[==[ Uint64 m_ulNextMotionPlusCheck; - bool m_bDisconnected; - Uint64 m_ulNextReconnect; /* WiiCompiled: see HIDAPI_DriverWii_UpdateDevice */ -]==]) - _aurora_sdl3_replace("${_wii}" "Wii Remote in-place reconnect (bounded extension probe)" -[==[static EWiiExtensionControllerType ReadExtensionControllerType(SDL_HIDAPI_Device *device) -{ - SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)device->context; - EWiiExtensionControllerType eExtensionControllerType = k_eWiiExtensionControllerType_Unknown; - const int MAX_ATTEMPTS = 20; - int attempts = 0; -]==] -[==[static EWiiExtensionControllerType ReadExtensionControllerTypeAttempts(SDL_HIDAPI_Device *device, int MAX_ATTEMPTS) -{ - SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)device->context; - EWiiExtensionControllerType eExtensionControllerType = k_eWiiExtensionControllerType_Unknown; - int attempts = 0; -]==]) - _aurora_sdl3_replace("${_wii}" "Wii Remote in-place reconnect (probe wrapper)" -[==[static void UpdateDeviceIdentity(SDL_HIDAPI_Device *device) -{ -]==] -[==[static EWiiExtensionControllerType ReadExtensionControllerType(SDL_HIDAPI_Device *device) -{ - return ReadExtensionControllerTypeAttempts(device, 20); -} - -static void UpdateDeviceIdentity(SDL_HIDAPI_Device *device) -{ -]==]) - _aurora_sdl3_replace("${_wii}" "Wii Remote in-place reconnect (UpdateDevice)" -[==[ if (device->num_joysticks > 0) { - joystick = SDL_GetJoystickFromID(device->joysticks[0]); - } else { - return false; - } - - now = SDL_GetTicks(); -]==] -[==[ if (device->num_joysticks > 0) { - joystick = SDL_GetJoystickFromID(device->joysticks[0]); - } else { - /* WiiCompiled: the joystick was dropped (extension plugged or unplugged, - * or a failed read) but the HID device is still open, and the device - * list only removes a joystick-less device once its handle is closed. - * Rebuild the joystick in place, so an extension change behaves like it - * does on the console: the remote never goes away, it just changes - * type. If the remote does not answer, keep the device and retry. */ - now = SDL_GetTicks(); - if (ctx->m_ulNextReconnect != 0 && now < ctx->m_ulNextReconnect) { - return false; - } - ctx->m_ulNextReconnect = now + 1000; - { - EWiiExtensionControllerType type = ReadExtensionControllerTypeAttempts(device, 2); - if (type == k_eWiiExtensionControllerType_Unknown) { - return false; - } - ctx->m_bDisconnected = false; - ctx->m_ulLastInput = now; - ctx->m_ulNextReconnect = 0; - ctx->m_eExtensionControllerType = type; - UpdateDeviceIdentity(device); - SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "HIDAPI Wii: Reconnected joystick as %s", device->name); - return HIDAPI_JoystickConnected(device, NULL); - } - } - - now = SDL_GetTicks(); -]==]) - - # Classic Controller sticks: the stock path stretches each half-range by learned min/max; - # this posts WPAD's linear value (raw - first-report centre) * unit, times 64. - _aurora_sdl3_replace("${_wii}" "Wii Classic Controller linear sticks (helper)" -[==[static void HandleGamepadControllerButtonData(SDL_DriverWii_Context *ctx, SDL_Joystick *joystick, const WiiButtonData *data) -{ -]==] -[==[/* WiiCompiled: axis = (raw - centre) * unit * 64, y inverted; see AuroraSDL3Patches.cmake */ -static void PostClassicStickLinear(Uint64 timestamp, SDL_Joystick *joystick, StickCalibrationData *calibration, Uint8 axis, Uint16 data, int unit) -{ - int value; - - if (!calibration->center) { - // Center on first read - calibration->center = data; - return; - } - value = ((int)data - (int)calibration->center) * unit * 64; - if (axis == SDL_GAMEPAD_AXIS_LEFTY || axis == SDL_GAMEPAD_AXIS_RIGHTY) { - value = -value; - } - SDL_SendJoystickAxis(timestamp, joystick, axis, (Sint16)SDL_clamp(value, SDL_JOYSTICK_AXIS_MIN, SDL_JOYSTICK_AXIS_MAX)); -} - -static void HandleGamepadControllerButtonData(SDL_DriverWii_Context *ctx, SDL_Joystick *joystick, const WiiButtonData *data) -{ -]==]) - _aurora_sdl3_replace("${_wii}" "Wii Classic Controller linear sticks (axes)" -[==[ PostStickCalibrated(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[0], SDL_GAMEPAD_AXIS_LEFTX, lx); - PostStickCalibrated(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[1], SDL_GAMEPAD_AXIS_LEFTY, ly); - PostStickCalibrated(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[2], SDL_GAMEPAD_AXIS_RIGHTX, rx); - PostStickCalibrated(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[3], SDL_GAMEPAD_AXIS_RIGHTY, ry); -]==] -[==[ PostClassicStickLinear(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[0], SDL_GAMEPAD_AXIS_LEFTX, lx, 16); - PostClassicStickLinear(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[1], SDL_GAMEPAD_AXIS_LEFTY, ly, 16); - PostClassicStickLinear(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[2], SDL_GAMEPAD_AXIS_RIGHTX, rx, 32); - PostClassicStickLinear(ctx->timestamp, joystick, &ctx->m_StickCalibrationData[3], SDL_GAMEPAD_AXIS_RIGHTY, ry, 32); -]==]) - - # Wii Remote: decode the accelerometer with the factory calibration from the EEPROM. - _aurora_sdl3_replace("${_wii}" "Wii Remote accelerometer calibration (context fields)" -[==[ StickCalibrationData m_StickCalibrationData[6]; -} SDL_DriverWii_Context; -]==] -[==[ StickCalibrationData m_StickCalibrationData[6]; - - float m_fAccelZeroG[3]; - float m_fAccelPerG[3]; -} SDL_DriverWii_Context; -]==]) - _aurora_sdl3_replace("${_wii}" "Wii Remote accelerometer calibration (memory space parameter)" -[==[static bool ReadRegister(SDL_DriverWii_Context *ctx, Uint32 address, int size, bool sync) -{ - Uint8 readRequest[7]; - - readRequest[0] = k_eWiiOutputReportIDs_ReadMemory; - readRequest[1] = (Uint8)(0x04 | (Uint8)ctx->m_bRumbleActive); -]==] -[==[static bool ReadMemory(SDL_DriverWii_Context *ctx, Uint8 addressSpace, Uint32 address, int size, bool sync); - -static bool ReadRegister(SDL_DriverWii_Context *ctx, Uint32 address, int size, bool sync) -{ - return ReadMemory(ctx, 0x04, address, size, sync); -} - -static bool ReadMemory(SDL_DriverWii_Context *ctx, Uint8 addressSpace, Uint32 address, int size, bool sync) -{ - Uint8 readRequest[7]; - - readRequest[0] = k_eWiiOutputReportIDs_ReadMemory; - readRequest[1] = (Uint8)(addressSpace | (Uint8)ctx->m_bRumbleActive); -]==]) - _aurora_sdl3_replace("${_wii}" "Wii Remote accelerometer calibration (EEPROM read)" -[==[static bool HIDAPI_DriverWii_InitDevice(SDL_HIDAPI_Device *device) -{ -]==] -[==[// Nominal decode: zero-g at 0x200, 100 units per g -#define WII_ACCEL_NOMINAL_ZERO_G 512.0f -#define WII_ACCEL_NOMINAL_PER_G 100.0f - -// EEPROM calibration at 0x16, copy at 0x20: zero-g XYZ, 1 g XYZ, LSBs of both, checksum -#define WII_ACCEL_CALIBRATION_SIZE 10 -#define WII_ADDRESS_SPACE_EEPROM 0x00 - -static bool ReadAccelCalibrationBlock(SDL_DriverWii_Context *ctx, Uint8 address, Uint8 *block) -{ - if (!ReadMemory(ctx, WII_ADDRESS_SPACE_EEPROM, address, WII_ACCEL_CALIBRATION_SIZE, true)) { - return false; - } - if (ctx->m_rgucReadBuffer[5] != address || - ctx->m_rgucReadBuffer[3] != ((WII_ACCEL_CALIBRATION_SIZE - 1) << 4)) { - SDL_SetError("Unexpected EEPROM read response"); - return false; - } - SDL_memcpy(block, ctx->m_rgucReadBuffer + 6, WII_ACCEL_CALIBRATION_SIZE); - return true; -} - -static bool ParseAccelCalibration(SDL_DriverWii_Context *ctx, const Uint8 *block) -{ - int zero[3]; - int perG[3]; - Uint8 checksum = 0x55; - int i; - - for (i = 0; i < WII_ACCEL_CALIBRATION_SIZE - 1; ++i) { - checksum = (Uint8)(checksum + block[i]); - } - if (checksum != block[WII_ACCEL_CALIBRATION_SIZE - 1]) { - SDL_SetError("Bad checksum"); - return false; - } - - for (i = 0; i < 3; ++i) { - int shift = 4 - 2 * i; - int oneG = (block[4 + i] << 2) | ((block[7] >> shift) & 0x03); - - zero[i] = (block[i] << 2) | ((block[3] >> shift) & 0x03); - perG[i] = oneG - zero[i]; - - // Sanity limits around the nominal values - if (zero[i] < 384 || zero[i] > 640 || perG[i] < 60 || perG[i] > 160) { - SDL_SetError("Implausible values"); - return false; - } - } - - for (i = 0; i < 3; ++i) { - ctx->m_fAccelZeroG[i] = (float)zero[i]; - ctx->m_fAccelPerG[i] = (float)perG[i]; - } - return true; -} - -static void ReadAccelCalibration(SDL_DriverWii_Context *ctx) -{ - static const Uint8 addresses[] = { 0x16, 0x20 }; - Uint8 block[WII_ACCEL_CALIBRATION_SIZE]; - int i; - - for (i = 0; i < SDL_arraysize(addresses); ++i) { - if (ReadAccelCalibrationBlock(ctx, addresses[i], block) && - ParseAccelCalibration(ctx, block)) { - SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "HIDAPI Wii: Accelerometer calibration from EEPROM 0x%02X: zero %d/%d/%d, %d/%d/%d units per g", - addresses[i], - (int)ctx->m_fAccelZeroG[0], (int)ctx->m_fAccelZeroG[1], (int)ctx->m_fAccelZeroG[2], - (int)ctx->m_fAccelPerG[0], (int)ctx->m_fAccelPerG[1], (int)ctx->m_fAccelPerG[2]); - return; - } - SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "HIDAPI Wii: Accelerometer calibration at EEPROM 0x%02X unusable: %s", addresses[i], SDL_GetError()); - } - SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "HIDAPI Wii: Using nominal accelerometer calibration"); -} - -static bool HIDAPI_DriverWii_InitDevice(SDL_HIDAPI_Device *device) -{ -]==]) - _aurora_sdl3_replace("${_wii}" "Wii Remote accelerometer calibration (nominal defaults)" -[==[ ctx->device = device; - device->context = ctx; -]==] -[==[ ctx->device = device; - device->context = ctx; - for (int i = 0; i < 3; ++i) { - ctx->m_fAccelZeroG[i] = WII_ACCEL_NOMINAL_ZERO_G; - ctx->m_fAccelPerG[i] = WII_ACCEL_NOMINAL_PER_G; - } -]==]) - _aurora_sdl3_replace("${_wii}" "Wii Remote accelerometer calibration (read at init)" -[==[ ctx->m_eExtensionControllerType = ReadExtensionControllerType(device); -]==] -[==[ ctx->m_eExtensionControllerType = ReadExtensionControllerType(device); - ReadAccelCalibration(ctx); -]==]) - # Reports without accelerometer bytes (status, memory) decoded as garbage. - _aurora_sdl3_replace("${_wii}" "Wii Remote accelerometer guard" -[==[ } - - x = ((data->rgucAccelerometer[0] << 2) | ((data->rgucBaseButtons[0] >> 5) & 0x03))]==] -[==[ } - - if (!data->hasAccelerometer) { - return; - } - - x = ((data->rgucAccelerometer[0] << 2) | ((data->rgucBaseButtons[0] >> 5) & 0x03))]==]) - _aurora_sdl3_replace("${_wii}" "Wii Remote accelerometer calibration (nominal constant)" -[==[const WiiButtonData *data) -{ - const float ACCEL_RES_PER_G = 100.0f; - Sint16 x, y, z; -]==] -[==[const WiiButtonData *data) -{ - Sint16 x, y, z; -]==]) - _aurora_sdl3_replace("${_wii}" "Wii Remote accelerometer calibration (decode)" -[==[ x = ((data->rgucAccelerometer[0] << 2) | ((data->rgucBaseButtons[0] >> 5) & 0x03)) - 0x200; - y = ((data->rgucAccelerometer[1] << 2) | ((data->rgucBaseButtons[1] >> 4) & 0x02)) - 0x200; - z = ((data->rgucAccelerometer[2] << 2) | ((data->rgucBaseButtons[1] >> 5) & 0x02)) - 0x200; - - values[0] = -((float)x / ACCEL_RES_PER_G) * SDL_STANDARD_GRAVITY; - values[1] = ((float)z / ACCEL_RES_PER_G) * SDL_STANDARD_GRAVITY; - values[2] = ((float)y / ACCEL_RES_PER_G) * SDL_STANDARD_GRAVITY; -]==] -[==[ x = ((data->rgucAccelerometer[0] << 2) | ((data->rgucBaseButtons[0] >> 5) & 0x03)); - y = ((data->rgucAccelerometer[1] << 2) | ((data->rgucBaseButtons[1] >> 4) & 0x02)); - z = ((data->rgucAccelerometer[2] << 2) | ((data->rgucBaseButtons[1] >> 5) & 0x02)); - if (x == 0 && y == 0 && z == 0) { - return; - } - - values[0] = -(((float)x - ctx->m_fAccelZeroG[0]) / ctx->m_fAccelPerG[0]) * SDL_STANDARD_GRAVITY; - values[1] = (((float)z - ctx->m_fAccelZeroG[2]) / ctx->m_fAccelPerG[2]) * SDL_STANDARD_GRAVITY; - values[2] = (((float)y - ctx->m_fAccelZeroG[1]) / ctx->m_fAccelPerG[1]) * SDL_STANDARD_GRAVITY; -]==]) -endfunction() - -# Script mode (FetchContent PATCH_COMMAND). -if (CMAKE_SCRIPT_MODE_FILE AND DEFINED SDL_SOURCE_DIR) - aurora_sdl3_apply_patches("${SDL_SOURCE_DIR}") -endif () diff --git a/aurora-main/cmake/AuroraSDL3Provider.cmake b/aurora-main/cmake/AuroraSDL3Provider.cmake deleted file mode 100644 index 70bd28c..0000000 --- a/aurora-main/cmake/AuroraSDL3Provider.cmake +++ /dev/null @@ -1,164 +0,0 @@ -include_guard(GLOBAL) - -# Resolve SDL3 dependency based on AURORA_SDL3_PROVIDER and AURORA_SDL3_LINKAGE. -# -# After this module runs, the variable AURORA_SDL3_TARGET is set to the -# appropriate target name for use in target_link_libraries() calls. - -# Select the SDL3 target matching the requested linkage. -function(_aurora_sdl3_select_target) - if (AURORA_SDL3_LINKAGE STREQUAL "static") - if (TARGET SDL3::SDL3-static) - set(AURORA_SDL3_TARGET SDL3::SDL3-static CACHE INTERNAL "") - message(STATUS "aurora: Using static SDL3") - return() - elseif (TARGET SDL3::SDL3) - message(WARNING "aurora: Static SDL3 requested but only shared is available") - set(AURORA_SDL3_TARGET SDL3::SDL3 CACHE INTERNAL "") - message(STATUS "aurora: Using shared SDL3") - return() - endif () - else () - if (TARGET SDL3::SDL3) - set(AURORA_SDL3_TARGET SDL3::SDL3 CACHE INTERNAL "") - message(STATUS "aurora: Using shared SDL3") - return() - elseif (TARGET SDL3::SDL3-static) - message(WARNING "aurora: Shared SDL3 requested but only static is available") - set(AURORA_SDL3_TARGET SDL3::SDL3-static CACHE INTERNAL "") - message(STATUS "aurora: Using static SDL3") - return() - endif () - endif () - message(FATAL_ERROR "No SDL3 target found (looked for SDL3::SDL3 and SDL3::SDL3-static)") -endfunction() - -# ── Auto: resolve provider based on platform availability ── -set(_aurora_sdl3_provider "${AURORA_SDL3_PROVIDER}") -if (_aurora_sdl3_provider STREQUAL "auto") - # Prebuilt SDL3 packages are available for Windows (MSVC and MinGW) - if (WIN32) - set(_aurora_sdl3_provider "package") - else () - set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL ON) - # Aurora uses APIs from the SDL version pinned by AURORA_SDL3_VERSION. - # Do not silently select an older system package and fail later while - # compiling its headers. - find_package(SDL3 ${AURORA_SDL3_VERSION} QUIET) - set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL OFF) - if (SDL3_FOUND) - set(_aurora_sdl3_provider "system") - else () - set(_aurora_sdl3_provider "vendor") - endif () - endif () - set(AURORA_SDL3_PROVIDER "${_aurora_sdl3_provider}" CACHE STRING "" FORCE) - message(STATUS "aurora: SDL3 auto-resolved provider: ${_aurora_sdl3_provider}") -endif () - -if (_aurora_sdl3_provider STREQUAL "system") - # ── System: find_package(SDL3) ── - message(STATUS "aurora: Using system SDL3 (provider=system)") - if (NOT SDL3_FOUND) - set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL ON) - find_package(SDL3 ${AURORA_SDL3_VERSION} REQUIRED) - set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL OFF) - endif () - _aurora_sdl3_select_target() - -elseif (_aurora_sdl3_provider STREQUAL "package") - # ── Package: download custom build or official SDL3 development package ── - if (NOT AURORA_SDL3_PACKAGE_URL) - if (MINGW) - # WIN32 is also true for MinGW. Select the matching GNU-ABI package - # before considering Visual C++ packages. - set(AURORA_SDL3_PACKAGE_URL - "https://github.com/libsdl-org/SDL/releases/download/release-${AURORA_SDL3_VERSION}/SDL3-devel-${AURORA_SDL3_VERSION}-mingw.tar.gz") - elseif (WIN32) - # We have custom builds of SDL3 for Win32 x86/AMD64 with libusb support included - if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(AMD64|x86)$") - string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" _sdl3_arch) - set(AURORA_SDL3_PACKAGE_URL - "https://github.com/encounter/sdl3-build/releases/download/v${AURORA_SDL3_VERSION}/SDL3-windows-${_sdl3_arch}.tar.gz") - else () - set(AURORA_SDL3_PACKAGE_URL - "https://github.com/libsdl-org/SDL/releases/download/release-${AURORA_SDL3_VERSION}/SDL3-devel-${AURORA_SDL3_VERSION}-VC.zip") - endif () - else () - message(FATAL_ERROR - "AURORA_SDL3_PROVIDER=package requires AURORA_SDL3_PACKAGE_URL on non-Windows platforms.\n" - "Official SDL3 packages: https://github.com/libsdl-org/SDL/releases") - endif () - endif () - message(STATUS "aurora: Fetching prebuilt SDL3 package from ${AURORA_SDL3_PACKAGE_URL}") - - include(FetchContent) - FetchContent_Declare(sdl3_prebuilt - URL "${AURORA_SDL3_PACKAGE_URL}" - DOWNLOAD_EXTRACT_TIMESTAMP FALSE - ) - FetchContent_MakeAvailable(sdl3_prebuilt) - - set(_sdl3_search_paths - "${sdl3_prebuilt_SOURCE_DIR}/cmake" - "${sdl3_prebuilt_SOURCE_DIR}/lib/cmake/SDL3" - "${sdl3_prebuilt_SOURCE_DIR}" - ) - file(GLOB _sdl3_subdirs "${sdl3_prebuilt_SOURCE_DIR}/SDL3-*") - foreach (_sd IN LISTS _sdl3_subdirs) - list(APPEND _sdl3_search_paths - "${_sd}/cmake" - "${_sd}/lib/cmake/SDL3" - "${_sd}" - ) - endforeach () - - set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL ON) - find_package(SDL3 REQUIRED CONFIG PATHS ${_sdl3_search_paths} NO_DEFAULT_PATH) - set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL OFF) - _aurora_sdl3_select_target() - -elseif (_aurora_sdl3_provider STREQUAL "vendor") - # ── Vendor: FetchContent build from source ── - if (NOT TARGET SDL3-static AND NOT TARGET SDL3-shared) - message(STATUS "aurora: Fetching SDL3 (provider=vendor)") - - if (AURORA_SDL3_LINKAGE STREQUAL "static") - set(SDL_STATIC ON CACHE BOOL "Build SDL3 static library" FORCE) - set(SDL_SHARED OFF CACHE BOOL "Build SDL3 shared library" FORCE) - else () - set(SDL_STATIC OFF CACHE BOOL "Build SDL3 static library" FORCE) - set(SDL_SHARED ON CACHE BOOL "Build SDL3 shared library" FORCE) - endif () - if (WIN32) - set(SDL_LIBC ON CACHE BOOL "Use the system C library" FORCE) - if (AURORA_SDL3_LIBUSB) - include("${CMAKE_CURRENT_LIST_DIR}/AuroraLibUSB.cmake") - endif () - endif () - - include(FetchContent) - # Source fixes for the vendored SDL (see AuroraSDL3Patches.cmake). A freshly - # downloaded tarball is patched by the PATCH_COMMAND; a tree handed in through - # FETCHCONTENT_SOURCE_DIR_SDL skips the download steps, so patch it here. - set(_aurora_sdl3_patches "${CMAKE_CURRENT_LIST_DIR}/AuroraSDL3Patches.cmake") - include("${_aurora_sdl3_patches}") - if (DEFINED FETCHCONTENT_SOURCE_DIR_SDL AND EXISTS "${FETCHCONTENT_SOURCE_DIR_SDL}") - aurora_sdl3_apply_patches("${FETCHCONTENT_SOURCE_DIR_SDL}") - endif () - FetchContent_Declare(SDL - URL "https://github.com/libsdl-org/SDL/releases/download/release-${AURORA_SDL3_VERSION}/SDL3-${AURORA_SDL3_VERSION}.tar.gz" - DOWNLOAD_EXTRACT_TIMESTAMP FALSE - PATCH_COMMAND "${CMAKE_COMMAND}" -DSDL_SOURCE_DIR= -P "${_aurora_sdl3_patches}" - EXCLUDE_FROM_ALL - ) - FetchContent_MakeAvailable(SDL) - else () - message(STATUS "aurora: Using existing SDL3") - endif () - _aurora_sdl3_select_target() - -else () - message(FATAL_ERROR "Invalid AURORA_SDL3_PROVIDER: ${AURORA_SDL3_PROVIDER} " - "(must be auto, vendor, system, or package)") -endif () diff --git a/aurora-main/cmake/aurora_card.cmake b/aurora-main/cmake/aurora_card.cmake deleted file mode 100644 index 5eace0f..0000000 --- a/aurora-main/cmake/aurora_card.cmake +++ /dev/null @@ -1,17 +0,0 @@ -add_library(aurora_card STATIC - lib/card/BlockAllocationTable.cpp - lib/card/CardRawFile.cpp - lib/card/CardGciFolder.cpp - lib/card/Directory.cpp - lib/card/DolphinCardPath.cpp - lib/card/File.cpp - lib/card/FileIO.cpp - lib/card/SRAM.cpp - lib/card/Util.cpp - lib/dolphin/card.cpp -) -add_library(aurora::card ALIAS aurora_card) -set_target_properties(aurora_card PROPERTIES FOLDER "aurora") - -target_link_libraries(aurora_card PUBLIC aurora::core) -target_include_directories(aurora_card PRIVATE include) diff --git a/aurora-main/cmake/aurora_core.cmake b/aurora-main/cmake/aurora_core.cmake deleted file mode 100644 index 65ffaea..0000000 --- a/aurora-main/cmake/aurora_core.cmake +++ /dev/null @@ -1,77 +0,0 @@ -add_library(aurora_core STATIC - lib/aurora.cpp - lib/input.cpp - lib/window.cpp - lib/logging.cpp - lib/system_info.cpp - lib/system_info.hpp -) -add_library(aurora::core ALIAS aurora_core) -set_target_properties(aurora_core PROPERTIES FOLDER "aurora") - -target_compile_definitions(aurora_core PUBLIC AURORA TARGET_PC) -target_include_directories(aurora_core PUBLIC include) -target_link_libraries(aurora_core PUBLIC fmt::fmt ${AURORA_SDL3_TARGET} xxhash) -target_link_libraries(aurora_core PRIVATE absl::btree absl::flat_hash_map sqlite3 TracyClient) -if (AURORA_ENABLE_GX AND AURORA_CACHE_USE_ZSTD) - target_compile_definitions(aurora_core PRIVATE AURORA_CACHE_USE_ZSTD) - target_link_libraries(aurora_core PRIVATE libzstd_static) -endif () - -if (CMAKE_SYSTEM_NAME STREQUAL Windows) - # stuff for fetching system info. - target_link_libraries(aurora_core PRIVATE ntdll dxgi advapi32 user32) -elseif (APPLE) - target_sources(aurora_core PRIVATE lib/system_info_mac.mm) -endif () - -if (AURORA_ENABLE_GX) - target_sources(aurora_core PRIVATE lib/imgui.cpp) - target_link_libraries(aurora_core PUBLIC imgui) -endif () - -if (AURORA_ENABLE_GX) - target_compile_definitions(aurora_core PUBLIC AURORA_ENABLE_GX WEBGPU_DAWN) - target_sources(aurora_core PRIVATE lib/webgpu/gpu.cpp lib/webgpu/gpu_cache.cpp lib/dawn/BackendBinding.cpp) - target_link_libraries(aurora_core PRIVATE dawn::webgpu_dawn) - if (APPLE AND DAWN_ENABLE_METAL) - find_library(AURORA_METALFX_FRAMEWORK MetalFX) - endif () - if (APPLE AND DAWN_ENABLE_METAL AND AURORA_METALFX_FRAMEWORK) - target_sources(aurora_core PRIVATE lib/webgpu/metalfx.mm) - set_source_files_properties(lib/webgpu/metalfx.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) - target_link_options(aurora_core PUBLIC "LINKER:-weak_framework,MetalFX") - target_link_libraries(aurora_core PRIVATE "-framework IOSurface") - else () - target_sources(aurora_core PRIVATE lib/webgpu/metalfx_stub.cpp) - endif () - if (DAWN_ENABLE_VULKAN) - target_compile_definitions(aurora_core PRIVATE DAWN_ENABLE_BACKEND_VULKAN) - endif () - if (DAWN_ENABLE_METAL) - target_compile_definitions(aurora_core PRIVATE DAWN_ENABLE_BACKEND_METAL) - target_sources(aurora_core PRIVATE lib/dawn/MetalBinding.mm) - set_source_files_properties(lib/dawn/MetalBinding.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) - target_link_options(aurora_core PUBLIC - "LINKER:-weak_framework,Metal" - "LINKER:-U,_OBJC_CLASS_$_MTLLogStateDescriptor") - endif () - if (DAWN_ENABLE_D3D11) - target_compile_definitions(aurora_core PRIVATE DAWN_ENABLE_BACKEND_D3D11) - endif () - if (DAWN_ENABLE_D3D12) - target_compile_definitions(aurora_core PRIVATE DAWN_ENABLE_BACKEND_D3D12) - endif () - if (DAWN_ENABLE_DESKTOP_GL OR DAWN_ENABLE_OPENGLES) - target_compile_definitions(aurora_core PRIVATE DAWN_ENABLE_BACKEND_OPENGL) - if (DAWN_ENABLE_DESKTOP_GL) - target_compile_definitions(aurora_core PRIVATE DAWN_ENABLE_BACKEND_DESKTOP_GL) - endif () - if (DAWN_ENABLE_OPENGLES) - target_compile_definitions(aurora_core PRIVATE DAWN_ENABLE_BACKEND_OPENGLES) - endif () - endif () - if (DAWN_ENABLE_NULL) - target_compile_definitions(aurora_core PRIVATE DAWN_ENABLE_BACKEND_NULL) - endif () -endif () diff --git a/aurora-main/cmake/aurora_dvd.cmake b/aurora-main/cmake/aurora_dvd.cmake deleted file mode 100644 index c95f72e..0000000 --- a/aurora-main/cmake/aurora_dvd.cmake +++ /dev/null @@ -1,10 +0,0 @@ -include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/AuroraNodProvider.cmake) - -add_library(aurora_dvd STATIC lib/dolphin/dvd/dvd.cpp) -add_library(aurora::dvd ALIAS aurora_dvd) -set_target_properties(aurora_dvd PROPERTIES FOLDER "aurora") - -target_compile_definitions(aurora_dvd PUBLIC AURORA TARGET_PC) -target_include_directories(aurora_dvd PUBLIC include) -target_link_libraries(aurora_dvd PUBLIC nod::nod ${AURORA_SDL3_TARGET}) -target_link_libraries(aurora_dvd PRIVATE fmt::fmt) diff --git a/aurora-main/cmake/aurora_gd.cmake b/aurora-main/cmake/aurora_gd.cmake deleted file mode 100644 index 80bd667..0000000 --- a/aurora-main/cmake/aurora_gd.cmake +++ /dev/null @@ -1,16 +0,0 @@ -add_library(aurora_gd STATIC - lib/dolphin/gd/GDBase.cpp - lib/dolphin/gd/GDGeometry.cpp - lib/dolphin/gd/GDIndirect.cpp - lib/dolphin/gd/GDLight.cpp - lib/dolphin/gd/GDPixel.cpp - lib/dolphin/gd/GDTev.cpp - lib/dolphin/gd/GDTexture.cpp - lib/dolphin/gd/GDTransform.cpp - lib/dolphin/gd/gd.hpp - lib/dolphin/gd/GDAurora.cpp -) -add_library(aurora::gd ALIAS aurora_gd) -set_target_properties(aurora_gd PROPERTIES FOLDER "aurora") - -target_link_libraries(aurora_gd PUBLIC aurora::gx) diff --git a/aurora-main/cmake/aurora_gx.cmake b/aurora-main/cmake/aurora_gx.cmake deleted file mode 100644 index ff740a7..0000000 --- a/aurora-main/cmake/aurora_gx.cmake +++ /dev/null @@ -1,47 +0,0 @@ -add_library(aurora_gx STATIC - lib/gfx/clear.cpp - lib/gfx/common.cpp - lib/gfx/depth_peek.cpp - lib/gfx/efb_ram_copy.cpp - lib/gfx/efb_ram_encoder.cpp - lib/gfx/pipeline_cache.cpp - lib/gfx/dds_io.cpp - lib/gfx/tex_copy_conv.cpp - lib/gfx/tex_palette_conv.cpp - lib/gfx/texture.cpp - lib/gfx/texture_convert.cpp - lib/gfx/texture_replacement.cpp - lib/gx/command_processor.cpp - lib/gx/fifo.cpp - lib/gx/frame_interpolation.cpp - lib/gx/gx.cpp - lib/gx/pipeline.cpp - lib/gx/shader.cpp - lib/gx/shader_info.cpp - lib/dolphin/gx/GXBump.cpp - lib/dolphin/gx/GXCull.cpp - lib/dolphin/gx/GXCpu2Efb.cpp - lib/dolphin/gx/GXDispList.cpp - lib/dolphin/gx/GXDraw.cpp - lib/dolphin/gx/GXExtra.cpp - lib/dolphin/gx/GXFifo.cpp - lib/dolphin/gx/GXFrameBuffer.cpp - lib/dolphin/gx/GXGeometry.cpp - lib/dolphin/gx/GXGet.cpp - lib/dolphin/gx/GXLighting.cpp - lib/dolphin/gx/GXManage.cpp - lib/dolphin/gx/GXPixel.cpp - lib/dolphin/gx/GXTev.cpp - lib/dolphin/gx/GXTexture.cpp - lib/dolphin/gx/GXTransform.cpp - lib/dolphin/gx/GXVert.cpp - lib/dolphin/gx/GXAurora.cpp - lib/gfx/png_io.cpp - lib/gfx/png_io.hpp -) -add_library(aurora::gx ALIAS aurora_gx) -set_target_properties(aurora_gx PROPERTIES FOLDER "aurora") - -target_link_libraries(aurora_gx PUBLIC aurora::core xxhash) -target_link_libraries(aurora_gx PRIVATE absl::btree absl::flat_hash_map dawn::webgpu_dawn sqlite3 TracyClient PNG::PNG) -target_compile_definitions(aurora_gx PRIVATE WEBGPU_DAWN) diff --git a/aurora-main/cmake/aurora_main.cmake b/aurora-main/cmake/aurora_main.cmake deleted file mode 100644 index b712164..0000000 --- a/aurora-main/cmake/aurora_main.cmake +++ /dev/null @@ -1,6 +0,0 @@ -add_library(aurora_main STATIC lib/main.cpp) -add_library(aurora::main ALIAS aurora_main) -set_target_properties(aurora_main PROPERTIES FOLDER "aurora") - -target_include_directories(aurora_main PUBLIC include) -target_link_libraries(aurora_main PUBLIC ${AURORA_SDL3_TARGET}) diff --git a/aurora-main/cmake/aurora_ms.cmake b/aurora-main/cmake/aurora_ms.cmake deleted file mode 100644 index 9df3020..0000000 --- a/aurora-main/cmake/aurora_ms.cmake +++ /dev/null @@ -1,7 +0,0 @@ -add_library(aurora_ms STATIC lib/dolphin/ms/mouse.cpp) -add_library(aurora::ms ALIAS aurora_ms) -set_target_properties(aurora_ms PROPERTIES FOLDER "aurora") - -target_include_directories(aurora_ms PUBLIC include) -target_link_libraries(aurora_ms PUBLIC aurora::core) -target_link_libraries(aurora_ms PRIVATE absl::flat_hash_map) diff --git a/aurora-main/cmake/aurora_mtx.cmake b/aurora-main/cmake/aurora_mtx.cmake deleted file mode 100644 index 580a942..0000000 --- a/aurora-main/cmake/aurora_mtx.cmake +++ /dev/null @@ -1,12 +0,0 @@ -add_library(aurora_mtx STATIC - lib/dolphin/mtx/mtx.c - lib/dolphin/mtx/mtxstack.c - lib/dolphin/mtx/mtxvec.c - lib/dolphin/mtx/mtx44.c - lib/dolphin/mtx/vec.c - lib/dolphin/mtx/quat.c -) -add_library(aurora::mtx ALIAS aurora_mtx) -set_target_properties(aurora_mtx PROPERTIES FOLDER "aurora") - -target_include_directories(aurora_mtx PUBLIC include) diff --git a/aurora-main/cmake/aurora_os.cmake b/aurora-main/cmake/aurora_os.cmake deleted file mode 100644 index 77156f1..0000000 --- a/aurora-main/cmake/aurora_os.cmake +++ /dev/null @@ -1,14 +0,0 @@ -add_library(aurora_os STATIC lib/dolphin/os/OSInit.cpp - lib/dolphin/os/OSMemory.cpp - lib/dolphin/os/internal.hpp - lib/dolphin/os/OSBootInfo.cpp - lib/dolphin/os/OSTime.cpp - lib/dolphin/os/OSArena.cpp - lib/dolphin/os/OSAlloc.cpp - lib/dolphin/os/OSAddress.cpp - lib/dolphin/AR.cpp) -add_library(aurora::os ALIAS aurora_os) -set_target_properties(aurora_os PROPERTIES FOLDER "aurora") - -target_include_directories(aurora_os PUBLIC include) -target_link_libraries(aurora_os PRIVATE aurora::core) diff --git a/aurora-main/cmake/aurora_pad.cmake b/aurora-main/cmake/aurora_pad.cmake deleted file mode 100644 index 5790fd0..0000000 --- a/aurora-main/cmake/aurora_pad.cmake +++ /dev/null @@ -1,7 +0,0 @@ -add_library(aurora_pad STATIC lib/dolphin/pad/pad.cpp) -add_library(aurora::pad ALIAS aurora_pad) -set_target_properties(aurora_pad PROPERTIES FOLDER "aurora") - -target_include_directories(aurora_pad PUBLIC include) -target_link_libraries(aurora_pad PUBLIC aurora::core aurora::si) -target_link_libraries(aurora_pad PRIVATE absl::flat_hash_map) diff --git a/aurora-main/cmake/aurora_si.cmake b/aurora-main/cmake/aurora_si.cmake deleted file mode 100644 index 0682c62..0000000 --- a/aurora-main/cmake/aurora_si.cmake +++ /dev/null @@ -1,7 +0,0 @@ -add_library(aurora_si STATIC lib/dolphin/si/si.cpp) -add_library(aurora::si ALIAS aurora_si) -set_target_properties(aurora_si PROPERTIES FOLDER "aurora") - -target_include_directories(aurora_si PUBLIC include) -target_link_libraries(aurora_si PUBLIC aurora::core) -target_link_libraries(aurora_si PRIVATE absl::flat_hash_map) diff --git a/aurora-main/cmake/aurora_vi.cmake b/aurora-main/cmake/aurora_vi.cmake deleted file mode 100644 index 38544af..0000000 --- a/aurora-main/cmake/aurora_vi.cmake +++ /dev/null @@ -1,7 +0,0 @@ -add_library(aurora_vi STATIC - lib/dolphin/vi/vi.cpp -) -add_library(aurora::vi ALIAS aurora_vi) -set_target_properties(aurora_vi PROPERTIES FOLDER "aurora") - -target_link_libraries(aurora_vi PUBLIC aurora::core) diff --git a/aurora-main/cmake/libusb/config.h b/aurora-main/cmake/libusb/config.h deleted file mode 100644 index fb63d5b..0000000 --- a/aurora-main/cmake/libusb/config.h +++ /dev/null @@ -1,8 +0,0 @@ -/* libusb build configuration for the Windows backend (MinGW/Clang). */ -#pragma once - -#define PLATFORM_WINDOWS 1 -#define ENABLE_LOGGING 1 -#define DEFAULT_VISIBILITY -#define HAVE_STRUCT_TIMESPEC 1 -#define PRINTF_FORMAT(a, b) __attribute__((__format__(__printf__, a, b))) diff --git a/aurora-main/docs/building.md b/aurora-main/docs/building.md deleted file mode 100644 index ca1cabd..0000000 --- a/aurora-main/docs/building.md +++ /dev/null @@ -1,55 +0,0 @@ -# Building - -## Prerequisites - -- CMake 3.25 or later -- A C++20 compatible compiler (Clang, GCC, or MSVC) -- Git (for cloning) - -## Building the Examples - -To build Aurora's included examples: - -```bash -git clone https://github.com/encounter/aurora.git -cd aurora -mkdir build && cd build -cmake .. -cmake --build . --target simple -``` - -The `simple` example demonstrates a minimal Aurora application with a blue screen. The built executable will be in `build/examples/simple`. - -## Using Aurora in Your Project - -Aurora is designed to be integrated as a library in GameCube/Wii decompilation projects. - -**CMakeLists.txt example:** - -```cmake -cmake_minimum_required(VERSION 3.25) -project(your_game) - -# Add Aurora as a subdirectory -add_subdirectory(extern/aurora EXCLUDE_FROM_ALL) - -# Create your executable -add_executable(your_game src/main.c) - -# Link against Aurora components -target_link_libraries(your_game PRIVATE - aurora::core - aurora::gx - aurora::main - aurora::vi -) -``` - -See [examples/simple.c](../examples/simple.c) for a minimal application template. - -## CMake Options - -- `AURORA_ENABLE_GX` (default: ON) - Enable GX implementation and WebGPU renderer -- `AURORA_ENABLE_DVD` (default: OFF) - Enable DVD implementation backed by nod -- `AURORA_ENABLE_CARD` (default: ON) - Enable CARD implementation based on kabufuda -- `AURORA_CACHE_USE_ZSTD` (default: ON) - Compress WebGPU cache entries with zstd diff --git a/aurora-main/examples/CMakeLists.txt b/aurora-main/examples/CMakeLists.txt deleted file mode 100644 index c5977f6..0000000 --- a/aurora-main/examples/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -if (AURORA_ENABLE_GX) - add_executable(simple simple.c) - target_link_libraries(simple PRIVATE aurora::core aurora::gx aurora::main aurora::vi) -endif () diff --git a/aurora-main/examples/simple.c b/aurora-main/examples/simple.c deleted file mode 100644 index cb8a6c4..0000000 --- a/aurora-main/examples/simple.c +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include - -static void log_callback(AuroraLogLevel level, const char* module, const char* message, unsigned int len) { - const char* levelStr; - FILE* out = stdout; - switch (level) { - case LOG_DEBUG: - levelStr = "DEBUG"; - break; - case LOG_INFO: - levelStr = "INFO"; - break; - case LOG_WARNING: - levelStr = "WARNING"; - break; - case LOG_ERROR: - levelStr = "ERROR"; - out = stderr; - break; - case LOG_FATAL: - levelStr = "FATAL"; - out = stderr; - break; - } - fprintf(out, "[%s: %s;%s]\n", levelStr, module, message); - if (level == LOG_FATAL) { - fflush(out); - abort(); - } -} - -static void draw() { - GXSetCopyClear( - (GXColor){ - .r = 0, - .g = 0, - .b = 100, - .a = 255, - }, - GX_MAX_Z24); -} - -int main(int argc, char* argv[]) { - const AuroraConfig config = { - .appName = "Demo", - .logCallback = &log_callback, - }; - AuroraInfo initInfo = aurora_initialize(argc, argv, &config); - - bool exiting = false; - bool paused = false; - while (!exiting) { - const AuroraEvent* event = aurora_update(); - while (event != NULL && event->type != AURORA_NONE) { - switch (event->type) { - case AURORA_EXIT: - exiting = true; - break; - case AURORA_PAUSED: - paused = true; - break; - case AURORA_UNPAUSED: - paused = false; - break; - case AURORA_WINDOW_RESIZED: - initInfo.windowSize = event->windowSize; - break; - default: - break; - } - ++event; - } - if (exiting || paused || !aurora_begin_frame()) { - continue; - } - draw(); - aurora_end_frame(); - } - - aurora_shutdown(); - return 0; -} diff --git a/aurora-main/extern/CMakeLists.txt b/aurora-main/extern/CMakeLists.txt deleted file mode 100644 index 59eeab3..0000000 --- a/aurora-main/extern/CMakeLists.txt +++ /dev/null @@ -1,360 +0,0 @@ -include(FetchContent) - -# Don't build tests for third party dependencies -set(BUILD_TESTING OFF CACHE INTERNAL "Build tests") -set(SKIP_INSTALL_ALL ON) -if (NOT DEFINED BUILD_SHARED_LIBS) - set(_USE_SHARED ON) -else () - set(_USE_SHARED OFF) -endif () - -function(aurora_find_package_global) - set(_PREV_FIND_PACKAGE_TARGETS_GLOBAL ${CMAKE_FIND_PACKAGE_TARGETS_GLOBAL}) - set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL ON) - find_package(${ARGV}) - set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL ${_PREV_FIND_PACKAGE_TARGETS_GLOBAL}) -endfunction() - -# A macOS build for another architecture must not discover Homebrew packages -# built for its physical host. CMAKE_CROSSCOMPILING is not sufficient here: -# Apple Clang can target another architecture through CMAKE_OSX_ARCHITECTURES -# without CMake considering the configure a cross-build. -set(_AURORA_EXCLUDE_HOST_HOMEBREW FALSE) -if (APPLE AND CMAKE_OSX_ARCHITECTURES) - list(LENGTH CMAKE_OSX_ARCHITECTURES _AURORA_OSX_ARCH_COUNT) - if (_AURORA_OSX_ARCH_COUNT EQUAL 1) - list(GET CMAKE_OSX_ARCHITECTURES 0 _AURORA_TARGET_ARCH) - string(TOLOWER "${_AURORA_TARGET_ARCH}" _AURORA_TARGET_ARCH) - # hw.optional.arm64 identifies Apple Silicon even when CMake itself runs - # through Rosetta, where CMAKE_HOST_SYSTEM_PROCESSOR reports x86_64. - execute_process( - COMMAND /usr/sbin/sysctl -n hw.optional.arm64 - RESULT_VARIABLE _AURORA_ARM64_PROBE_RESULT - OUTPUT_VARIABLE _AURORA_ARM64_PROBE - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if (_AURORA_ARM64_PROBE_RESULT EQUAL 0 AND _AURORA_ARM64_PROBE STREQUAL "1") - set(_AURORA_HOST_ARCH arm64) - else () - execute_process( - COMMAND /usr/bin/uname -m - OUTPUT_VARIABLE _AURORA_HOST_ARCH - OUTPUT_STRIP_TRAILING_WHITESPACE) - string(TOLOWER "${_AURORA_HOST_ARCH}" _AURORA_HOST_ARCH) - endif () - if (_AURORA_TARGET_ARCH STREQUAL "x86_64" AND _AURORA_HOST_ARCH MATCHES "^(arm64|aarch64)$") - list(APPEND CMAKE_IGNORE_PREFIX_PATH "/opt/homebrew") - set(_AURORA_EXCLUDE_HOST_HOMEBREW TRUE) - elseif (_AURORA_TARGET_ARCH MATCHES "^(arm64|aarch64)$" AND _AURORA_HOST_ARCH MATCHES "^(x86_64|amd64)$") - list(APPEND CMAKE_IGNORE_PREFIX_PATH "/usr/local") - set(_AURORA_EXCLUDE_HOST_HOMEBREW TRUE) - endif () - endif () -endif () - -if (_AURORA_EXCLUDE_HOST_HOMEBREW) - list(REMOVE_DUPLICATES CMAKE_IGNORE_PREFIX_PATH) - message(STATUS "aurora: cross-architecture macOS build; ignoring host Homebrew prefixes") -endif () - -if (AURORA_ENABLE_GX) - include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/AuroraDawnProvider.cmake) -endif () - -# SDL's pkg-config probe can bypass CMake's prefix exclusion. macOS does not -# need libusb for the supported SDL input paths, so keep that host-only library -# out of a cross-architecture configure. -if (_AURORA_EXCLUDE_HOST_HOMEBREW) - set(SDL_HIDAPI_LIBUSB OFF CACHE BOOL "" FORCE) - set(SDL_HIDAPI_LIBUSB_SHARED OFF CACHE BOOL "" FORCE) -endif () - -# Abseil is needed for core libraries. It normally comes via Dawn's vendor build. -# Otherwise prefer a system package and only fetch it as a last resort. -if (NOT TARGET absl::flat_hash_map OR NOT TARGET absl::btree) - aurora_find_package_global(absl CONFIG QUIET GLOBAL) -endif () - -if (TARGET absl::flat_hash_map AND TARGET absl::btree) - message(STATUS "aurora: Using system/existing abseil") -else () - message(STATUS "aurora: Fetching abseil-cpp (standalone)") - if(NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY OR CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "DLL$") - set(ABSL_MSVC_STATIC_RUNTIME OFF CACHE INTERNAL "Link static runtime libraries") - else() - set(ABSL_MSVC_STATIC_RUNTIME ON CACHE INTERNAL "Link static runtime libraries") - endif() - set(ABSL_PROPAGATE_CXX_STD ON) - FetchContent_Declare(abseil-cpp - URL https://github.com/abseil/abseil-cpp/archive/refs/tags/20240722.0.tar.gz - DOWNLOAD_EXTRACT_TIMESTAMP FALSE - EXCLUDE_FROM_ALL - ) - FetchContent_MakeAvailable(abseil-cpp) - if (NOT TARGET absl::flat_hash_map OR NOT TARGET absl::btree) - message(FATAL_ERROR "Failed to make abseil-cpp available") - endif () -endif () - -include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/AuroraSDL3Provider.cmake) - -if (NOT TARGET xxhash) - message(STATUS "aurora: Fetching xxhash") - FetchContent_Declare(xxhash - URL https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.4.tar.gz - URL_HASH SHA256=5738270935e7c3d38a79b3adf7c9692566ce7895a25f67de43ad52ab504acd32 - SOURCE_SUBDIR build/cmake - DOWNLOAD_EXTRACT_TIMESTAMP FALSE - EXCLUDE_FROM_ALL - ) - set(XXHASH_BUILD_XXHSUM OFF CACHE INTERNAL "Build the xxhsum binary") - # xxhash uses CMAKE_DEPENDENT_OPTION(BUILD_SHARED_LIBS ...) which writes - # a sticky CACHE INTERNAL entry on reconfigure. Undo it afterward. - set(_aurora_xxhash_saved_bsl "${BUILD_SHARED_LIBS}") - FetchContent_MakeAvailable(xxhash) - unset(BUILD_SHARED_LIBS CACHE) - set(BUILD_SHARED_LIBS "${_aurora_xxhash_saved_bsl}") - unset(_aurora_xxhash_saved_bsl) - if (NOT TARGET xxhash) - message(FATAL_ERROR "Failed to make xxhash available") - endif () -else () - message(STATUS "aurora: Using existing xxhash") -endif () - -if (NOT TARGET fmt) - message(STATUS "aurora: Fetching fmt") - FetchContent_Declare(fmt - URL https://github.com/fmtlib/fmt/archive/refs/tags/11.1.4.tar.gz - URL_HASH SHA256=ac366b7b4c2e9f0dde63a59b3feb5ee59b67974b14ee5dc9ea8ad78aa2c1ee1e - DOWNLOAD_EXTRACT_TIMESTAMP FALSE - EXCLUDE_FROM_ALL - ) - FetchContent_MakeAvailable(fmt) - if (NOT TARGET fmt) - message(FATAL_ERROR "Failed to make fmt available") - endif () -else () - message(STATUS "aurora: Using existing fmt") -endif () - -# fmt 11.1 drops its libc++ transitive includes but still calls malloc/free without . -# Force the missing header for fmt and its consumers until the pinned release is updated. -if (MINGW AND TARGET fmt) - target_compile_options(fmt PUBLIC - $<$:-include> - $<$:cstdlib>) -endif () - -if (AURORA_ENABLE_GX) - if (NOT TARGET ZLIB::ZLIB) - aurora_find_package_global(ZLIB QUIET) - endif () - if (NOT TARGET ZLIB::ZLIB) - message(STATUS "aurora: Fetching zlib") - set(_AURORA_ZLIB_SHARED ${_USE_SHARED}) - # ClangCL injects Clang's C headers into the MSVC resource compiler path, and zlib's DLL version - # resource then hits syntax rc.exe cannot parse. Use the resource-free static target here. - if (MSVC AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(_AURORA_ZLIB_SHARED OFF) - endif () - set(ZLIB_BUILD_SHARED ${_AURORA_ZLIB_SHARED} CACHE BOOL "Enable building zlib shared library" FORCE) - set(ZLIB_BUILD_TESTING OFF CACHE BOOL "Enable Zlib Examples as tests" FORCE) - set(ZLIB_INSTALL OFF CACHE BOOL "Enable installation of zlib" FORCE) - FetchContent_Declare( - ZLIB - URL https://github.com/madler/zlib/releases/download/v1.3.2/zlib-1.3.2.tar.gz - URL_HASH SHA256=bb329a0a2cd0274d05519d61c667c062e06990d72e125ee2dfa8de64f0119d16 - DOWNLOAD_EXTRACT_TIMESTAMP FALSE - EXCLUDE_FROM_ALL - ) - FetchContent_MakeAvailable(ZLIB) - if (NOT TARGET ZLIB::ZLIB AND TARGET ZLIB::ZLIBSTATIC) - add_library(ZLIB::ZLIB ALIAS zlibstatic) - endif () - if (NOT TARGET ZLIB::ZLIB) - message(FATAL_ERROR "Failed to make zlib available") - endif () - # libpng calls find_package(ZLIB) even when zlib was already provided by FetchContent. - file(WRITE "${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/ZLIBConfig.cmake" - "set(ZLIB_FOUND TRUE)\n" - "set(ZLIB_INCLUDE_DIR \"${zlib_SOURCE_DIR}\")\n" - "set(ZLIB_INCLUDE_DIRS \"${zlib_BINARY_DIR};${zlib_SOURCE_DIR}\")\n" - ) - endif () - - if (NOT TARGET PNG::PNG) - if (TARGET png_shared AND _USE_SHARED) - add_library(PNG::PNG ALIAS png_shared) - elseif (TARGET png_static) - add_library(PNG::PNG ALIAS png_static) - else () - aurora_find_package_global(PNG QUIET) - endif () - endif () - if (NOT TARGET PNG::PNG) - message(STATUS "aurora: Fetching libpng") - set(PNG_SHARED ${_USE_SHARED} CACHE BOOL "Build libpng as a shared library" FORCE) - set(PNG_TESTS OFF CACHE BOOL "Build the libpng tests" FORCE) - set(PNG_TOOLS OFF CACHE BOOL "Build the libpng tools" FORCE) - FetchContent_Declare( - PNG - URL https://github.com/pnggroup/libpng/archive/refs/tags/v1.6.58.tar.gz - URL_HASH SHA256=A9D4DF463D36A6E5F9C29BD6F4967312D17E996C1854F3511F833924EB1993CF - DOWNLOAD_EXTRACT_TIMESTAMP FALSE - EXCLUDE_FROM_ALL - ) - FetchContent_MakeAvailable(PNG) - if (TARGET png_shared AND _USE_SHARED) - add_library(PNG::PNG ALIAS png_shared) - elseif (TARGET png_static) - add_library(PNG::PNG ALIAS png_static) - else () - message(FATAL_ERROR "Failed to make libpng available") - endif () - else () - message(STATUS "aurora: Using existing libpng") - endif () - - aurora_find_package_global(Freetype QUIET) - if (NOT TARGET Freetype::Freetype) - message(STATUS "aurora: Fetching Freetype") - set(FT_DISABLE_BROTLI ON CACHE BOOL "" FORCE) - set(FT_DISABLE_HARFBUZZ ON CACHE BOOL "" FORCE) - set(FT_DISABLE_PNG ON CACHE BOOL "" FORCE) - FetchContent_Declare(Freetype - URL https://files.twilitrealm.dev/freetype-2.14.3.tar.gz - URL_HASH SHA256=e61b31ab26358b946e767ed7eb7f4bb2e507da1cfefeb7a8861ace7fd5c899a1 - DOWNLOAD_EXTRACT_TIMESTAMP FALSE - EXCLUDE_FROM_ALL - ) - FetchContent_MakeAvailable(Freetype) - add_library(Freetype::Freetype ALIAS freetype) - else () - message(STATUS "aurora: Using existing Freetype") - endif () - - if (NOT TARGET imgui) - message(STATUS "aurora: Fetching imgui") - FetchContent_Declare(imgui - URL https://github.com/ocornut/imgui/archive/refs/tags/v1.91.9b-docking.tar.gz - URL_HASH SHA256=466fdef9b18de15f0bb6e288e3d00ffa3d82200ec458ce5e4f724a161d9528a5 - DOWNLOAD_EXTRACT_TIMESTAMP FALSE - EXCLUDE_FROM_ALL - ) - FetchContent_MakeAvailable(imgui) - - add_library(imgui STATIC - ${imgui_SOURCE_DIR}/imgui.cpp - ${imgui_SOURCE_DIR}/imgui_demo.cpp - ${imgui_SOURCE_DIR}/imgui_draw.cpp - ${imgui_SOURCE_DIR}/imgui_tables.cpp - ${imgui_SOURCE_DIR}/imgui_widgets.cpp - ${imgui_SOURCE_DIR}/misc/cpp/imgui_stdlib.cpp - ) - target_include_directories(imgui PUBLIC ${imgui_SOURCE_DIR}) - - add_library(imgui_backends STATIC - ${imgui_SOURCE_DIR}/backends/imgui_impl_sdl3.cpp - ${imgui_SOURCE_DIR}/backends/imgui_impl_sdlrenderer3.cpp - ${imgui_SOURCE_DIR}/backends/imgui_impl_wgpu.cpp - ) - target_compile_definitions(imgui_backends PRIVATE IMGUI_IMPL_WEBGPU_BACKEND_DAWN) - target_link_libraries(imgui_backends PRIVATE imgui ${AURORA_SDL3_TARGET} dawn::webgpu_dawn) - target_link_libraries(imgui PUBLIC imgui_backends) - - if (TARGET Freetype::Freetype) - target_sources(imgui PRIVATE ${imgui_SOURCE_DIR}/misc/freetype/imgui_freetype.cpp) - target_compile_definitions(imgui PUBLIC IMGUI_ENABLE_FREETYPE) - target_link_libraries(imgui PRIVATE Freetype::Freetype) - endif () - else () - message(STATUS "aurora: Using existing imgui") - endif () - - if (TARGET imgui) - target_include_directories(imgui PUBLIC ${PROJECT_SOURCE_DIR}/include) - target_compile_definitions(imgui PUBLIC IMGUI_USER_CONFIG="aurora/imgui_config.h") - target_sources(imgui PRIVATE ${PROJECT_SOURCE_DIR}/lib/imgui_config.cpp) - target_link_libraries(imgui PRIVATE ${AURORA_SDL3_TARGET}) - endif () - - if (NOT TARGET sqlite3) - message(STATUS "aurora: Fetching sqlite3") - FetchContent_Declare(sqlite3 - URL https://sqlite.org/2026/sqlite-amalgamation-3510300.zip - URL_HASH SHA256=acb1e6f5d832484bf6d32b681e858c38add8b2acdfd42ac5df24b8afb46552b4 - DOWNLOAD_EXTRACT_TIMESTAMP FALSE - EXCLUDE_FROM_ALL - ) - FetchContent_MakeAvailable(sqlite3) - - add_library(sqlite3 STATIC ${sqlite3_SOURCE_DIR}/sqlite3.c) - target_include_directories(sqlite3 PUBLIC ${sqlite3_SOURCE_DIR}) - else () - message(STATUS "aurora: Using existing sqlite3") - endif () - - if (AURORA_CACHE_USE_ZSTD) - if (NOT TARGET libzstd_static) - message(STATUS "aurora: Fetching zstd") - set(ZSTD_BUILD_STATIC ON) - set(ZSTD_BUILD_SHARED OFF) - set(ZSTD_BUILD_PROGRAMS OFF CACHE BOOL "BUILD PROGRAMS" FORCE) - set(ZSTD_BUILD_TESTS OFF CACHE BOOL "BUILD TESTS" FORCE) - - if (WIN32 AND CMAKE_C_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(C_FLAG_WALL TRUE CACHE INTERNAL "") - set(CXX_FLAG_WALL TRUE CACHE INTERNAL "") - set(C_FLAG_WEXTRA TRUE CACHE INTERNAL "") - set(CXX_FLAG_WEXTRA TRUE CACHE INTERNAL "") - set(C_FLAG_WUNDEF TRUE CACHE INTERNAL "") - set(CXX_FLAG_WUNDEF TRUE CACHE INTERNAL "") - set(C_FLAG_WSHADOW TRUE CACHE INTERNAL "") - set(CXX_FLAG_WSHADOW TRUE CACHE INTERNAL "") - set(C_FLAG_WCAST_ALIGN TRUE CACHE INTERNAL "") - set(CXX_FLAG_WCAST_ALIGN TRUE CACHE INTERNAL "") - set(C_FLAG_WCAST_QUAL TRUE CACHE INTERNAL "") - set(CXX_FLAG_WCAST_QUAL TRUE CACHE INTERNAL "") - set(C_FLAG_WSTRICT_PROTOTYPES TRUE CACHE INTERNAL "") - set(LD_FLAG_WL_Z_NOEXECSTACK FALSE CACHE INTERNAL "") - set(C_FLAG_QUNUSED_ARGUMENTS TRUE CACHE INTERNAL "") - set(CXX_FLAG_QUNUSED_ARGUMENTS TRUE CACHE INTERNAL "") - set(C_FLAG_WA_NOEXECSTACK TRUE CACHE INTERNAL "") - set(CXX_FLAG_WA_NOEXECSTACK TRUE CACHE INTERNAL "") - endif() - - FetchContent_Declare(zstd - URL https://github.com/facebook/zstd/releases/download/v1.5.7/zstd-1.5.7.tar.gz - URL_HASH SHA256=eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 - DOWNLOAD_EXTRACT_TIMESTAMP FALSE - SOURCE_SUBDIR build/cmake - EXCLUDE_FROM_ALL - ) - FetchContent_MakeAvailable(zstd) - else () - message(STATUS "aurora: Using existing zstd") - endif () - endif () -endif () - -if (NOT TARGET TracyClient) - message(STATUS "aurora: Fetching Tracy") - - # Default to off, users can enable the cache variable if they want to use it. - set(TRACY_ENABLE OFF CACHE BOOL "Enable Tracy profiling") - - FetchContent_Declare( - tracy - URL https://github.com/wolfpld/tracy/archive/a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz - URL_HASH SHA256=24d342b5127d7f659dc3cf94f24347b348cc736f25b17a691fd7f69541937658 - DOWNLOAD_EXTRACT_TIMESTAMP FALSE - EXCLUDE_FROM_ALL - ) - FetchContent_MakeAvailable(tracy) - - if (NOT TARGET TracyClient) - message(FATAL_ERROR "Failed to make TracyClient available") - endif () -endif () diff --git a/aurora-main/include/aurora/aurora.h b/aurora-main/include/aurora/aurora.h deleted file mode 100644 index 00c478d..0000000 --- a/aurora-main/include/aurora/aurora.h +++ /dev/null @@ -1,195 +0,0 @@ -#ifndef AURORA_AURORA_H -#define AURORA_AURORA_H - -#ifdef __cplusplus -#include -#include - -extern "C" { -#else -#include "stdbool.h" -#include "stddef.h" -#include "stdint.h" -#endif - -typedef enum { - BACKEND_AUTO, - BACKEND_D3D11, - BACKEND_D3D12, - BACKEND_METAL, - BACKEND_VULKAN, - BACKEND_OPENGL, - BACKEND_OPENGLES, - BACKEND_WEBGPU, - BACKEND_NULL, -} AuroraBackend; - -typedef enum { - LOG_DEBUG, - LOG_INFO, - LOG_WARNING, - LOG_ERROR, - LOG_FATAL, -} AuroraLogLevel; - -typedef enum { - AURORA_DISPLAY_MODE_WINDOWED, - AURORA_DISPLAY_MODE_BORDERLESS, - AURORA_DISPLAY_MODE_EXCLUSIVE, -} AuroraDisplayMode; - -typedef struct { - int32_t x; - int32_t y; -} AuroraWindowPos; - -typedef struct { - uint32_t width; - uint32_t height; - - /** - * Width of the main GX framebuffer. - */ - uint32_t fb_width; - - /** - * Height of the main GX framebuffer. - */ - uint32_t fb_height; - - /** - * The size of the framebuffer used to present to the operating system. - * May differ from fb_width if Aurora is instructed to force an aspect ratio or resolution configuration. - */ - uint32_t native_fb_width; - - /** - * The size of the framebuffer used to present to the operating system. - * May differ from fb_height if Aurora is instructed to force an aspect ratio or resolution configuration. - */ - uint32_t native_fb_height; - float scale; -} AuroraWindowSize; - -typedef struct SDL_Window SDL_Window; -typedef struct AuroraEvent AuroraEvent; - -typedef void (*AuroraLogCallback)(AuroraLogLevel level, const char* module, const char* message, unsigned int len); -typedef void (*AuroraImGuiInitCallback)(const AuroraWindowSize* size); - -typedef struct { - const char* appName; - const char* userPath; - const char* cachePath; - // Read-only application resources. Defaults to SDL_GetBasePath(), which is - // where release builds place initial_pipeline_cache.db. - const char* resourcesPath; - AuroraBackend desiredBackend; - uint32_t msaa; - uint16_t maxTextureAnisotropy; - // No vsync knob exists: the swapchain is always configured for a - // non-blocking present mode (Immediate, else Mailbox). See best_present_mode. - bool startFullscreen; - bool allowJoystickBackgroundEvents; - bool pauseOnFocusLost; - bool allowTextureReplacements; - bool allowTextureDumps; - bool disableCopyFilter; - // When false, Aurora centers the first window. When true, windowPosX/Y are restored verbatim, - // including negative coordinates on monitors left of or above the primary display. - bool hasWindowPosition; - int32_t windowPosX; - int32_t windowPosY; - uint32_t windowWidth; - uint32_t windowHeight; - void* iconRGBA8; - uint32_t iconWidth; - uint32_t iconHeight; - AuroraLogCallback logCallback; - AuroraLogLevel logLevel; - AuroraImGuiInitCallback imGuiInitCallback; - - /* - * The size of the GameCube's main memory, or MEM1 on the Wii. - * Note that it will not be allocated at the exact 0x80000000 address, as that cannot be guaranteed. - * This can be set to 0 to disable allocating this region. - */ - uint32_t mem1Size; - - /* - * The size of the GameCube's ARAM, or MEM2 on the Wii. - * This can be set to 0 to disable allocating this region. - */ - uint32_t mem2Size; - - // Optional directory for the portable GX pipeline database. When null, the - // database is stored in cachePath with Dawn's machine-specific cache. - const char* pipelineCachePath; -} AuroraConfig; - -typedef enum { - AURORA_INITIALIZATION_SUCCESS = 0, - AURORA_INITIALIZATION_GRAPHICS_UNAVAILABLE = 1, -} AuroraInitializationStatus; - -typedef struct { - AuroraBackend backend; - const char* userPath; - const char* cachePath; - SDL_Window* window; - AuroraWindowSize windowSize; - AuroraInitializationStatus initializationStatus; - // On failure, owned by SDL on the calling thread. Copy before another SDL call. - const char* initializationError; -} AuroraInfo; - -AuroraInfo aurora_initialize(int argc, char* argv[], const AuroraConfig* config); -void aurora_shutdown(); -const AuroraEvent* aurora_update(); -bool aurora_begin_frame(); -void aurora_end_frame(); -typedef void (*AuroraFrameWorkerWaitCallback)(); -// Called from the producer thread at bounded intervals while Aurora waits for -// the asynchronous frame worker. The callback must not enter Aurora. -void aurora_set_frame_worker_wait_callback(AuroraFrameWorkerWaitCallback callback); -void aurora_wait_for_frame_worker(); -bool aurora_wait_for_frame_worker_for(uint32_t timeoutMicros); -// Absolute schedule for the next sealed frame, on steady_clock: baseNanos anchors the group and -// intervalNanos is the period, so slot k of N+1 fires at base + k*interval/(N+1). Zeros clear it. -void aurora_set_present_schedule(uint64_t baseNanos, uint64_t intervalNanos); -// Reports whether the frame about to be sealed met its display boundary. Interpolation sizes its -// slot group from this, backing off after misses. Only paced presents may report. -void aurora_report_producer_paced(bool paced); -void aurora_request_frame_capture(uint32_t frame, const char* outputPath); -bool aurora_flush_efb_copies_to_ram(); -bool aurora_flush_efb_copy_to_ram(void* dest); - -void aurora_set_log_level(AuroraLogLevel level); -void aurora_set_pause_on_focus_lost(bool value); -void aurora_set_background_input(bool value); -void aurora_set_display_mode(AuroraDisplayMode mode); -AuroraDisplayMode aurora_get_display_mode(); - -typedef enum { - AURORA_METALFX_DISABLED, - AURORA_METALFX_UNSUPPORTED, - AURORA_METALFX_NOT_UPSCALING, - AURORA_METALFX_ACTIVE, - AURORA_METALFX_ERROR, -} AuroraMetalFXStatus; - -// Changes are consumed at the next sealed frame boundary. MetalFX only applies -// when both source dimensions are smaller than the aspect-fitted output. -void aurora_set_metalfx_spatial(bool enabled); -bool aurora_get_metalfx_spatial(); -bool aurora_is_metalfx_spatial_supported(); -AuroraMetalFXStatus aurora_get_metalfx_status(); - -AuroraBackend aurora_get_backend(); -const AuroraBackend* aurora_get_available_backends(size_t* count); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/aurora/dvd.h b/aurora-main/include/aurora/dvd.h deleted file mode 100644 index 4a7f53b..0000000 --- a/aurora-main/include/aurora/dvd.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef AURORA_DVD_H -#define AURORA_DVD_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -/** - * Open a GC/Wii disc image for use by the DVD API. - * Must be called before DVDInit(). - * Returns true on success, false on failure. - */ -bool aurora_dvd_open(const char* disc_path); - -/** - * Close the disc image and free all resources. - */ -void aurora_dvd_close(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/aurora/event.h b/aurora-main/include/aurora/event.h deleted file mode 100644 index 46ebf40..0000000 --- a/aurora-main/include/aurora/event.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef AURORA_EVENT_H -#define AURORA_EVENT_H - -#include "aurora.h" - -#include -#include - -#ifdef __cplusplus -#include - -extern "C" { -#else -#include "stdint.h" -#endif - -typedef enum { - AURORA_NONE, - AURORA_EXIT, - AURORA_SDL_EVENT, - AURORA_WINDOW_MOVED, - AURORA_WINDOW_RESIZED, - AURORA_CONTROLLER_ADDED, - AURORA_CONTROLLER_REMOVED, - AURORA_PAUSED, - AURORA_UNPAUSED, - AURORA_DISPLAY_SCALE_CHANGED, -} AuroraEventType; - -struct AuroraEvent { - AuroraEventType type; - union { - SDL_Event sdl; - AuroraWindowPos windowPos; - AuroraWindowSize windowSize; - SDL_JoystickID controller; - }; -}; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/aurora/gfx.h b/aurora-main/include/aurora/gfx.h deleted file mode 100644 index f58252f..0000000 --- a/aurora-main/include/aurora/gfx.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef AURORA_GFX_H -#define AURORA_GFX_H - -#ifdef __cplusplus -#include -#include - -extern "C" { -#else -#include "stddef.h" -#include "stdint.h" -#endif - -#ifndef NDEBUG -#define AURORA_GFX_DEBUG_GROUPS -#endif - -void aurora_push_debug_group(const char* label); -void aurora_pop_debug_group(); - -typedef struct { - uint32_t queuedPipelines; - uint32_t createdPipelines; - uint32_t drawCallCount; - uint32_t mergedDrawCallCount; - uint32_t lastVertSize; - uint32_t lastUniformSize; - uint32_t lastIndexSize; - uint32_t lastStorageSize; - uint32_t lastTextureUploadSize; - uint32_t presentedFrameCount; - uint32_t interpolatedFrameCount; -} AuroraStats; - -typedef struct { - uint64_t totalPresentCount; - uint32_t sampleCount; - double framesPerSecond; - double averageFrameTimeMs; - double p95FrameTimeMs; - double jitterMs; - // framesPerSecond with duplicated presentation slots scaled out, so this is the rate of frames - // that carried new motion. Equal to framesPerSecond when every slot replayed real interpolation. - double effectiveFramesPerSecond; -} AuroraPresentTiming; - -const AuroraStats* aurora_get_stats(); -void aurora_get_present_timing(AuroraPresentTiming* timing); - -// Interpolation health: the per-frame fields describe the last sealed frame, the counters -// accumulate since it was configured. This answers "output FPS dropped but the game held 60". -typedef struct { - uint32_t targetFps; // configured target, 0 when interpolation is off - uint32_t targetSamples; // slots the pacing controller currently aims for - uint32_t activeSamples; // slots latched for the latest sealed frame - uint32_t candidates; // perspective draws in the latest sealed frame - uint32_t matchable; // candidates whose identity also existed last frame - uint32_t matches; // draws matched to the previous frame - uint32_t eligible; // latest frame inserted interpolated slots - uint32_t replaySafe; // latest frame could replay its command stream - uint64_t framesSealed; - uint64_t framesLowMatch; - uint64_t framesReplayUnsafe; - uint64_t slotReductions; - uint64_t lateSealDrops; -} AuroraFrameInterpolationDiagnostics; - -void aurora_get_frame_interpolation_diagnostics(AuroraFrameInterpolationDiagnostics* diagnostics); - -// Generates transform-interpolated perspective frames between consecutive 60 Hz logical frames. -// Supported targets are 0 (off), 120, 180 and 240. Guest simulation and VI timing are unchanged. -void aurora_set_frame_interpolation_fps(uint32_t targetFps); -uint32_t aurora_get_frame_interpolation_fps(); - -// Newly encountered GX pipelines compile on the bounded worker queue. Draws whose pipeline is not -// ready are skipped rather than stalling submission, and pick it up once compilation finishes. -void aurora_set_skip_unready_pipelines(bool enabled); -bool aurora_get_skip_unready_pipelines(); -uint32_t aurora_get_queued_pipeline_count(); - -// Controls whether display copies bypass the Wii's vertical copy filter. -void aurora_set_disable_copy_filter(bool disabled); -bool aurora_get_disable_copy_filter(); - -// Guest-RAM write tracking. `generation` changes whenever guest RAM covering a host range was -// written (or returns AURORA_GUEST_WRITE_UNTRACKED); `notify` reports writes aurora made itself. -#define AURORA_GUEST_WRITE_UNTRACKED UINT64_MAX -typedef uint64_t (*AuroraGuestWriteGenerationCallback)(const void* hostPtr, size_t size); -typedef void (*AuroraGuestWriteNotifyCallback)(const void* hostPtr, size_t size); -void aurora_set_guest_write_hooks(AuroraGuestWriteGenerationCallback generation, - AuroraGuestWriteNotifyCallback notify); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/aurora/imgui.h b/aurora-main/include/aurora/imgui.h deleted file mode 100644 index 77eba9a..0000000 --- a/aurora-main/include/aurora/imgui.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef AURORA_IMGUI_H -#define AURORA_IMGUI_H - -#include - -#ifdef __cplusplus -#include - -extern "C" { -#else -#include "stdint.h" -#endif - -ImTextureID aurora_imgui_add_texture(uint32_t width, uint32_t height, const void* rgba8); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/aurora/imgui_config.h b/aurora-main/include/aurora/imgui_config.h deleted file mode 100644 index 3e62e59..0000000 --- a/aurora-main/include/aurora/imgui_config.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS 1 - -typedef struct SDL_IOStream SDL_IOStream; -typedef SDL_IOStream* ImFileHandle; -typedef unsigned long long ImU64; - -ImFileHandle ImFileOpen(const char* filename, const char* mode); -bool ImFileClose(ImFileHandle file); -ImU64 ImFileGetSize(ImFileHandle file); -ImU64 ImFileRead(void* data, ImU64 size, ImU64 count, ImFileHandle file); -ImU64 ImFileWrite(const void* data, ImU64 size, ImU64 count, ImFileHandle file); diff --git a/aurora-main/include/aurora/main.h b/aurora-main/include/aurora/main.h deleted file mode 100644 index 68ee67c..0000000 --- a/aurora-main/include/aurora/main.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef AURORA_MAIN_H -#define AURORA_MAIN_H - -#ifdef __cplusplus -extern "C" { -#endif - -int aurora_main(int argc, char* argv[]); - -#ifdef __cplusplus -} -#endif - -#define main aurora_main - -#endif diff --git a/aurora-main/include/aurora/math.hpp b/aurora-main/include/aurora/math.hpp deleted file mode 100644 index cb15cf1..0000000 --- a/aurora-main/include/aurora/math.hpp +++ /dev/null @@ -1,254 +0,0 @@ -#pragma once - -#include -#include -#include - -#ifndef AURORA_VEC2_EXTRA -#define AURORA_VEC2_EXTRA -#endif -#ifndef AURORA_VEC3_EXTRA -#define AURORA_VEC3_EXTRA -#endif -#ifndef AURORA_VEC4_EXTRA -#define AURORA_VEC4_EXTRA -#endif -#ifndef AURORA_MAT4X4_EXTRA -#define AURORA_MAT4X4_EXTRA -#endif - -#ifndef __has_attribute -#define __has_attribute(x) 0 -#endif -#ifndef __has_builtin -#define __has_builtin(x) 0 -#endif -#if __has_attribute(vector_size) && !defined(__clang__) -#define USE_GCC_VECTOR_EXTENSIONS -#endif - -namespace aurora { -template -struct Vec2 { - T x{}; - T y{}; - - constexpr Vec2() = default; - constexpr Vec2(T x, T y) : x(x), y(y) {} - AURORA_VEC2_EXTRA - - bool operator==(const Vec2& rhs) const { return x == rhs.x && y == rhs.y; } - bool operator!=(const Vec2& rhs) const { return !(*this == rhs); } -}; -template -struct Vec3 { - T x{}; - T y{}; - T z{}; - - constexpr Vec3() = default; - constexpr Vec3(T x, T y, T z) : x(x), y(y), z(z) {} - AURORA_VEC3_EXTRA - - bool operator==(const Vec3& rhs) const { return x == rhs.x && y == rhs.y && z == rhs.z; } - bool operator!=(const Vec3& rhs) const { return !(*this == rhs); } -}; -template -struct Vec4 { -#ifdef USE_GCC_VECTOR_EXTENSIONS - typedef T Vt __attribute__((vector_size(sizeof(T) * 4))); - Vt m; -#else - using Vt = T[4]; - Vt m; -#endif - - constexpr Vec4() = default; - constexpr Vec4(Vt m) : m(m) {} - constexpr Vec4(T x, T y, T z, T w) : m{x, y, z, w} {} - // For Vec3 with padding - constexpr Vec4(T x, T y, T z) : m{x, y, z, {}} {} - // For Vec3 -> Vec4 - constexpr Vec4(Vec3 v, T w) : m{v.x, v.y, v.z, w} {} - AURORA_VEC4_EXTRA - - inline Vec4& operator=(const Vec4& other) { - memcpy(&m, &other.m, sizeof(Vt)); - return *this; - } - - [[nodiscard]] inline T& x() { return m[0]; } - [[nodiscard]] inline T x() const { return m[0]; } - [[nodiscard]] inline T& y() { return m[1]; } - [[nodiscard]] inline T y() const { return m[1]; } - [[nodiscard]] inline T& z() { return m[2]; } - [[nodiscard]] inline T z() const { return m[2]; } - [[nodiscard]] inline T& w() { return m[3]; } - [[nodiscard]] inline T w() const { return m[3]; } - [[nodiscard]] inline T& operator[](size_t i) { return m[i]; } - [[nodiscard]] inline T operator[](size_t i) const { return m[i]; } - - template - [[nodiscard]] constexpr Vec4 shuffle() const { - static_assert(x < 4 && y < 4 && z < 4 && w < 4); -#if defined(USE_GCC_VECTOR_EXTENSIONS) && __has_builtin(__builtin_shuffle) - typedef int Vi __attribute__((vector_size(16))); - return __builtin_shuffle(m, Vi{x, y, z, w}); -#else - return {m[x], m[y], m[z], m[w]}; -#endif - } - - bool operator==(const Vec4& rhs) const { -#if defined(USE_GCC_VECTOR_EXTENSIONS) && __has_builtin(__builtin_reduce_and) - return __builtin_reduce_and(m == rhs.m) != 0; -#else - return m[0] == rhs.m[0] && m[1] == rhs.m[1] && m[2] == rhs.m[2] && m[3] == rhs.m[3]; -#endif - } - bool operator!=(const Vec4& rhs) const { return !(*this == rhs); } -}; -template -[[nodiscard]] Vec4 operator+(const Vec4& a, const Vec4& b) { -#ifdef USE_GCC_VECTOR_EXTENSIONS - return a.m + b.m; -#else - return {a.m[0] + b.m[0], a.m[1] + b.m[1], a.m[2] + b.m[2], a.m[3] + b.m[3]}; -#endif -} -template -[[nodiscard]] Vec4 operator*(const Vec4& a, const Vec4& b) { -#ifdef USE_GCC_VECTOR_EXTENSIONS - return a.m * b.m; -#else - return {a.m[0] * b.m[0], a.m[1] * b.m[1], a.m[2] * b.m[2], a.m[3] * b.m[3]}; -#endif -} -template -struct Mat3x2 { - Vec2 m0{}; - Vec2 m1{}; - Vec2 m2{}; - - constexpr Mat3x2() = default; - constexpr Mat3x2(const Vec2& m0, const Vec2& m1, const Vec2& m2) : m0(m0), m1(m1), m2(m2) {} - - bool operator==(const Mat3x2& rhs) const { return m0 == rhs.m0 && m1 == rhs.m1 && m2 == rhs.m2; } - bool operator!=(const Mat3x2& rhs) const { return !(*this == rhs); } -}; -template -struct Mat4x2 { - Vec2 m0{}; - Vec2 m1{}; - Vec2 m2{}; - Vec2 m3{}; - - constexpr Mat4x2() = default; - constexpr Mat4x2(const Vec2& m0, const Vec2& m1, const Vec2& m2, const Vec2& m3) - : m0(m0), m1(m1), m2(m2), m3(m3) {} - - inline Mat4x2 transpose() const { - return { - {m0.x, m2.x}, - {m0.y, m2.y}, - {m1.x, m3.x}, - {m1.y, m3.y}, - }; - } - - bool operator==(const Mat4x2& rhs) const { return m0 == rhs.m0 && m1 == rhs.m1 && m2 == rhs.m2 && m3 == rhs.m3; } - bool operator!=(const Mat4x2& rhs) const { return !(*this == rhs); } -}; -template -struct Mat2x4 { - Vec4 m0{}; - Vec4 m1{}; - - constexpr Mat2x4() = default; - constexpr Mat2x4(const Vec4& m0, const Vec4& m1, const Vec4& m2) : m0(m0), m1(m1) {} - - bool operator==(const Mat2x4& rhs) const { return m0 == rhs.m0 && m1 == rhs.m1; } - bool operator!=(const Mat2x4& rhs) const { return !(*this == rhs); } -}; -static_assert(sizeof(Mat2x4) == 32); -template -struct Mat4x4; -template -struct Mat3x4 { - Vec4 m0{}; - Vec4 m1{}; - Vec4 m2{}; - - constexpr Mat3x4() = default; - constexpr Mat3x4(const Vec4& m0, const Vec4& m1, const Vec4& m2) : m0(m0), m1(m1), m2(m2) {} - - [[nodiscard]] Mat4x4 to4x4() const; - [[nodiscard]] Mat4x4 toTransposed4x4() const; - - bool operator==(const Mat3x4& rhs) const { return m0 == rhs.m0 && m1 == rhs.m1 && m2 == rhs.m2; } - bool operator!=(const Mat3x4& rhs) const { return !(*this == rhs); } -}; -static_assert(sizeof(Mat3x4) == 48); -template -struct Mat4x4 { - Vec4 m0{}; - Vec4 m1{}; - Vec4 m2{}; - Vec4 m3{}; - - constexpr Mat4x4() = default; - constexpr Mat4x4(const Vec4& m0, const Vec4& m1, const Vec4& m2, const Vec4& m3) - : m0(m0), m1(m1), m2(m2), m3(m3) {} - AURORA_MAT4X4_EXTRA - - [[nodiscard]] Mat4x4 transpose() const { - return { - {m0[0], m1[0], m2[0], m3[0]}, - {m0[1], m1[1], m2[1], m3[1]}, - {m0[2], m1[2], m2[2], m3[2]}, - {m0[3], m1[3], m2[3], m3[3]}, - }; - } - Mat4x4& operator=(const Mat4x4& other) = default; - - Vec4& operator[](size_t i) { return *(&m0 + i); } - const Vec4& operator[](size_t i) const { return *(&m0 + i); } - - bool operator==(const Mat4x4& rhs) const { return m0 == rhs.m0 && m1 == rhs.m1 && m2 == rhs.m2 && m3 == rhs.m3; } - bool operator!=(const Mat4x4& rhs) const { return !(*this == rhs); } -}; -static_assert(sizeof(Mat4x4) == 64); -template -[[nodiscard]] Mat4x4 operator*(const Mat4x4& a, const Mat4x4& b) { - Mat4x4 out; - for (size_t i = 0; i < 4; ++i) { - *(&out.m0 + i) = a.m0 * b[i].template shuffle<0, 0, 0, 0>() + a.m1 * b[i].template shuffle<1, 1, 1, 1>() + - a.m2 * b[i].template shuffle<2, 2, 2, 2>() + a.m3 * b[i].template shuffle<3, 3, 3, 3>(); - } - return out; -} -template -[[nodiscard]] Mat4x4 Mat3x4::to4x4() const { - return { - {m0[0], m0[1], m0[2], 0.f}, - {m1[0], m1[1], m1[2], 0.f}, - {m2[0], m2[1], m2[2], 0.f}, - {m0[3], m1[3], m2[3], 1.f}, - }; -} -template -[[nodiscard]] Mat4x4 Mat3x4::toTransposed4x4() const { - return Mat4x4{ - {m0[0], m1[0], m2[0], 0.f}, - {m0[1], m1[1], m2[1], 0.f}, - {m0[2], m1[2], m2[2], 0.f}, - {m0[3], m1[3], m2[3], 1.f}, - }; -} -constexpr Mat4x4 Mat4x4_Identity{ - Vec4{1.f, 0.f, 0.f, 0.f}, - Vec4{0.f, 1.f, 0.f, 0.f}, - Vec4{0.f, 0.f, 1.f, 0.f}, - Vec4{0.f, 0.f, 0.f, 1.f}, -}; -} // namespace aurora diff --git a/aurora-main/include/aurora/render_size_limits.hpp b/aurora-main/include/aurora/render_size_limits.hpp deleted file mode 100644 index 20d92f3..0000000 --- a/aurora-main/include/aurora/render_size_limits.hpp +++ /dev/null @@ -1,81 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace aurora::render_size_limits { - -struct Size { - uint32_t width; - uint32_t height; -}; - -// The canvas follows the window aspect however wide it gets, since the presenter stretches it and -// a cap would distort the UI. Only the portrait side clamps, where the guest cannot fill taller. -inline constexpr float kMaxDynamicPortraitExpansion = 6.f; -inline constexpr float kMinDynamicAspect = (16.f / 9.f) / kMaxDynamicPortraitExpansion; - -// The adapter limit is an API ceiling, not an allocation budget: a 16384-wide RGBA attachment is -// near 100 MiB. 8192 plus an 8K-UHD pixel budget keeps 8x 16:9 while avoiding device removal. -inline constexpr uint32_t kMaxFramebufferDimension = 8192; -inline constexpr uint64_t kMaxFramebufferPixels = 7680ull * 4320ull; - -inline float clamp_dynamic_aspect(float aspect) noexcept { - if (!std::isfinite(aspect) || aspect <= 0.f) { - return 1.f; - } - return std::max(aspect, kMinDynamicAspect); -} - -inline Size scale_framebuffer_to_aspect(uint32_t width, uint32_t height, float scale, float requestedAspect) noexcept { - if (width == 0 || height == 0 || !std::isfinite(scale) || scale <= 0.f) { - return {std::max(width, 1u), std::max(height, 1u)}; - } - - const auto scaledWidth = std::max(1u, static_cast(std::lround(static_cast(width) * scale))); - const auto scaledHeight = std::max(1u, static_cast(std::lround(static_cast(height) * scale))); - const float aspect = clamp_dynamic_aspect(requestedAspect); - if (aspect >= static_cast(width) / static_cast(height)) { - return { - std::max(1u, static_cast(std::lround(static_cast(scaledHeight) * aspect))), - scaledHeight, - }; - } - return { - scaledWidth, - std::max(1u, static_cast(std::lround(static_cast(scaledWidth) / aspect))), - }; -} - -inline Size fit_framebuffer_to_budget(uint32_t width, uint32_t height, uint32_t adapterMaxDimension) noexcept { - if (width == 0 || height == 0) { - return {width, height}; - } - - uint32_t dimensionLimit = kMaxFramebufferDimension; - if (adapterMaxDimension != 0 && adapterMaxDimension != std::numeric_limits::max()) { - dimensionLimit = std::min(dimensionLimit, adapterMaxDimension); - } - dimensionLimit = std::max(dimensionLimit, 1u); - - double fitScale = 1.0; - fitScale = std::min(fitScale, static_cast(dimensionLimit) / static_cast(width)); - fitScale = std::min(fitScale, static_cast(dimensionLimit) / static_cast(height)); - - const double requestedPixels = static_cast(width) * static_cast(height); - if (requestedPixels > static_cast(kMaxFramebufferPixels)) { - fitScale = std::min(fitScale, std::sqrt(static_cast(kMaxFramebufferPixels) / requestedPixels)); - } - - if (fitScale >= 1.0) { - return {width, height}; - } - return { - std::max(1u, static_cast(std::floor(static_cast(width) * fitScale))), - std::max(1u, static_cast(std::floor(static_cast(height) * fitScale))), - }; -} - -} // namespace aurora::render_size_limits diff --git a/aurora-main/include/dolphin/ai.h b/aurora-main/include/dolphin/ai.h deleted file mode 100644 index 84db334..0000000 --- a/aurora-main/include/dolphin/ai.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef _DOLPHIN_AI_H_ -#define _DOLPHIN_AI_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*AISCallback)(u32 count); -typedef void (*AIDCallback)(); - -#define AI_STREAM_START 1 -#define AI_STREAM_STOP 0 - -#define AI_SAMPLERATE_32KHZ 0 -#define AI_SAMPLERATE_48KHZ 1 - -AIDCallback AIRegisterDMACallback(AIDCallback callback); -void AIInitDMA(u32 start_addr, u32 length); -BOOL AIGetDMAEnableFlag(void); -void AIStartDMA(void); -void AIStopDMA(void); -u32 AIGetDMABytesLeft(void); -u32 AIGetDMAStartAddr(void); -u32 AIGetDMALength(void); -BOOL AICheckInit(void); -AISCallback AIRegisterStreamCallback(AISCallback callback); -u32 AIGetStreamSampleCount(void); -void AIResetStreamSampleCount(void); -void AISetStreamTrigger(u32 trigger); -u32 AIGetStreamTrigger(void); -void AISetStreamPlayState(u32 state); -u32 AIGetStreamPlayState(void); -void AISetDSPSampleRate(u32 rate); -u32 AIGetDSPSampleRate(void); -void AISetStreamSampleRate(u32 rate); -u32 AIGetStreamSampleRate(void); -void AISetStreamVolLeft(u8 vol); -u8 AIGetStreamVolLeft(void); -void AISetStreamVolRight(u8 vol); -u8 AIGetStreamVolRight(void); -void AIInit(u8* stack); -void AIReset(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/ar.h b/aurora-main/include/dolphin/ar.h deleted file mode 100644 index bf09f24..0000000 --- a/aurora-main/include/dolphin/ar.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef _DOLPHIN_AR_H_ -#define _DOLPHIN_AR_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*ARQCallback)(uintptr_t pointerToARQRequest); - -struct ARQRequest { - /* 0x00 */ struct ARQRequest *next; - /* 0x04 */ u32 owner; - /* 0x08 */ u32 type; - /* 0x0C */ u32 priority; - /* 0x10 */ u32 source; - /* 0x14 */ u32 dest; - /* 0x18 */ u32 length; - /* 0x1C */ ARQCallback callback; -}; - -#define ARQ_DMA_ALIGNMENT 32 - -#define ARAM_DIR_MRAM_TO_ARAM 0x00 -#define ARAM_DIR_ARAM_TO_MRAM 0x01 - -#define ARStartDMARead(mmem, aram, len) \ - ARStartDMA(ARAM_DIR_ARAM_TO_MRAM, mmem, aram, len) -#define ARStartDMAWrite(mmem, aram, len) \ - ARStartDMA(ARAM_DIR_MRAM_TO_ARAM, mmem, aram, len) - -typedef struct ARQRequest ARQRequest; - -#define ARQ_TYPE_MRAM_TO_ARAM ARAM_DIR_MRAM_TO_ARAM -#define ARQ_TYPE_ARAM_TO_MRAM ARAM_DIR_ARAM_TO_MRAM - -#define ARQ_PRIORITY_LOW 0 -#define ARQ_PRIORITY_HIGH 1 - -// AR -ARQCallback ARRegisterDMACallback(ARQCallback callback); -u32 ARGetDMAStatus(void); -void ARStartDMA(u32 type, u32 mainmem_addr, u32 aram_addr, u32 length); -u32 ARAlloc(u32 length); -u32 ARFree(u32* length); -BOOL ARCheckInit(void); -u32 ARInit(u32* stack_index_addr, u32 num_entries); -void ARReset(void); -void ARSetSize(void); -u32 ARGetBaseAddress(void); -u32 ARGetSize(void); -u32 ARGetInternalSize(void); -void ARClear(u32 flag); - -/** - * Aurora extension: gets the memory address where ARAM is stored, for direct access. - */ -void* ARGetStorageAddress(); - -// ARQ -void ARQInit(void); -void ARQReset(void); -void ARQPostRequest(ARQRequest* request, u32 owner, u32 type, u32 priority, uintptr_t source, uintptr_t dest, u32 length, ARQCallback callback); -void ARQRemoveRequest(ARQRequest* request); -void ARQRemoveOwnerRequest(u32 owner); -void ARQFlushQueue(void); -void ARQSetChunkSize(u32 size); -u32 ARQGetChunkSize(void); -BOOL ARQCheckInit(void); - -u16 __ARGetInterruptStatus(void); -void __ARClearInterrupt(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/base/PPCArch.h b/aurora-main/include/dolphin/base/PPCArch.h deleted file mode 100644 index 8bdd0dd..0000000 --- a/aurora-main/include/dolphin/base/PPCArch.h +++ /dev/null @@ -1,542 +0,0 @@ -#ifndef _DOLPHIN_PPCARCH -#define _DOLPHIN_PPCARCH - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define CTR 9 -#define XER 1 -#define LR 8 - -#define UPMC1 937 -#define UPMC2 938 -#define UPMC3 941 -#define UPMC4 942 - -#define USIA 939 - -#define UMMCR0 936 -#define UMMCR1 940 - -#define HID0 1008 -#define HID1 1009 - -#define PVR 287 - -#define IBAT0U 528 -#define IBAT0L 529 -#define IBAT1U 530 -#define IBAT1L 531 -#define IBAT2U 532 -#define IBAT2L 533 -#define IBAT3U 534 -#define IBAT3L 535 - -#define DBAT0U 536 -#define DBAT0L 537 -#define DBAT1U 538 -#define DBAT1L 539 -#define DBAT2U 540 -#define DBAT2L 541 -#define DBAT3U 542 -#define DBAT3L 543 - -#define SDR1 25 - -#define SPRG0 272 -#define SPRG1 273 -#define SPRG2 274 -#define SPRG3 275 - -#define DAR 19 -#define DSISR 18 - -#define SRR0 26 -#define SRR1 27 - -#define EAR 282 - -#define DABR 1013 - -#define TBL 284 -#define TBU 285 - -#define L2CR 1017 - -#define DEC 22 - -#define IABR 1010 - -#define PMC1 953 -#define PMC2 954 -#define PMC3 957 -#define PMC4 958 - -#define SIA 955 - -#define MMCR0 952 -#define MMCR1 956 - -#define THRM1 1020 -#define THRM2 1021 -#define THRM3 1022 - -#define ICTC 1019 - -#define GQR0 912 -#define GQR1 913 -#define GQR2 914 -#define GQR3 915 -#define GQR4 916 -#define GQR5 917 -#define GQR6 918 -#define GQR7 919 - -#define HID2 920 - -#define WPAR 921 - -#define DMA_U 922 -#define DMA_L 923 - -#define MSR_POW 0x00040000 // Power Management -#define MSR_ILE 0x00010000 // Interrupt Little Endian -#define MSR_EE 0x00008000 // external interrupt -#define MSR_PR 0x00004000 // privilege level(should be 0) -#define MSR_FP 0x00002000 // floating point available -#define MSR_ME 0x00001000 // machine check enable -#define MSR_FE0 0x00000800 // floating point exception enable -#define MSR_SE 0x00000400 // single step trace enable -#define MSR_BE 0x00000200 // branch trace enable -#define MSR_FE1 0x00000100 // floating point exception enable -#define MSR_IP 0x00000040 // Exception prefix -#define MSR_IR 0x00000020 // instruction relocate -#define MSR_DR 0x00000010 // data relocate -#define MSR_PM 0x00000004 // Performance monitor marked mode -#define MSR_RI 0x00000002 // Recoverable interrupt -#define MSR_LE 0x00000001 // Little Endian - -#define MSR_POW_BIT 13 // Power Management -#define MSR_ILE_BIT 15 // Interrupt Little Endian -#define MSR_EE_BIT 16 // external interrupt -#define MSR_PR_BIT 17 // privilege level (should be 0) -#define MSR_FP_BIT 18 // floating point available -#define MSR_ME_BIT 19 // machine check enable -#define MSR_FE0_BIT 20 // floating point exception enable -#define MSR_SE_BIT 21 // single step trace enable -#define MSR_BE_BIT 22 // branch trace enable -#define MSR_FE1_BIT 23 // floating point exception enable -#define MSR_IP_BIT 25 // Exception prefix -#define MSR_IR_BIT 26 // instruction relocate -#define MSR_DR_BIT 27 // data relocate -#define MSR_PM_BIT 29 // Performance monitor marked mode -#define MSR_RI_BIT 30 // Recoverable interrupt -#define MSR_LE_BIT 31 // Little Endian - -/*---------------------------------------------------------------------------* - HID0 bits - *---------------------------------------------------------------------------*/ -#define HID0_EMCP 0x80000000u // Enable MCP -#define HID0_DBP 0x40000000u // Enable 60x bus address and data parity chk -#define HID0_EBA 0x20000000u // Enable 60x address parity checking -#define HID0_EBD 0x10000000u // Enable 60x data parity checking -#define HID0_BCLK 0x08000000u // CLK_OUT output enable and clk selection -#define HID0_ECLK 0x02000000u // CLK_OUT output enable and clk selection -#define HID0_PAR 0x01000000u // Disable !ARTRY precharge -#define HID0_DOZE 0x00800000u // Doze mode enable -#define HID0_NAP 0x00400000u // Nap mode enable -#define HID0_SLEEP 0x00200000u // Sleep mode enable -#define HID0_DPM 0x00100000u // Dynamic power management enable -#define HID0_NHR 0x00010000u // Not hard reset (0 hard reset if s/w set it) -#define HID0_ICE 0x00008000u // Instruction cache enable -#define HID0_DCE 0x00004000u // Data cache enable -#define HID0_ILOCK 0x00002000u // ICache lock -#define HID0_DLOCK 0x00001000u // DCache lock -#define HID0_ICFI 0x00000800u // ICache flash invalidate -#define HID0_DCFI 0x00000400u // DCache flash invalidate -#define HID0_SPD 0x00000200u // Speculative cache access enable (0 enable) -#define HID0_IFEM 0x00000100u // Enable M bit on bus for Ifetch -#define HID0_SGE 0x00000080u // Store gathering enable -#define HID0_DCFA 0x00000040u // DCache flush assist - set before a flush -#define HID0_BTIC 0x00000020u // Branch target icache enable -#define HID0_ABE 0x00000008u // Address bcast enable -#define HID0_BHT 0x00000004u // Branch history table enable -#define HID0_NOOPTI 0x00000001u // No-op Dcache touch instructions - -#define HID0_ICE_BIT 16 // Instruction cache enable -#define HID0_DCE_BIT 17 // Data cache enable -#define HID0_ILOCK_BIT 18 // ICache lock -#define HID0_DLOCK_BIT 19 // DCache lock - -#define HID2_LSQE 0x80000000 // L/S quantize enable -#define HID2_WPE 0x40000000 // Write pipe enable -#define HID2_PSE 0x20000000 // Paired single enable -#define HID2_LCE 0x10000000 // Locked cache enable - -#define HID2_DCHERR 0x00800000 // ERROR: dcbz_l cache hit -#define HID2_DNCERR 0x00400000 // ERROR: DMA access to normal cache -#define HID2_DCMERR 0x00200000 // ERROR: DMA cache miss error -#define HID2_DQOERR 0x00100000 // ERROR: DMA queue overflow -#define HID2_DCHEE 0x00080000 // dcbz_l cache hit error enable -#define HID2_DNCEE 0x00040000 // DMA access to normal cache error enable -#define HID2_DCMEE 0x00020000 // DMA cache miss error error enable -#define HID2_DQOEE 0x00010000 // DMA queue overflow error enable - -#define HID2_DMAQL_MASK 0x0F000000 // DMA queue length mask -#define HID2_DMAQL_SHIFT 24 // DMA queue shift - -#define HID2_LSQE_BIT 0 -#define HID2_WPE_BIT 1 -#define HID2_PSE_BIT 2 -#define HID2_LCE_BIT 3 - -#define HID2_DCHERR_BIT 8 -#define HID2_DNCERR_BIT 9 -#define HID2_DCMERR_BIT 10 -#define HID2_DQOERR_BIT 11 -#define HID2_DCHEE_BIT 12 -#define HID2_DNCEE_BIT 13 -#define HID2_DCMEE_BIT 14 -#define HID2_DQOEE_BIT 15 - -#define GQR_LOAD_SCALE_MASK 0x3F000000 // load scale field -#define GQR_LOAD_TYPE_MASK 0x00070000 // load type field -#define GQR_STORE_SCALE_MASK 0x00003F00 // store scale field -#define GQR_STORE_TYPE_MASK 0x00000007 // store type field - -typedef struct -{ - u32 _pad0 :2; - u32 loadScale :6; - u32 _pad1 :5; - u32 loadType :3; - u32 _pad2 :2; - u32 storeScale :6; - u32 _pad3 :5; - u32 storeType :3; -} PPC_GQR_t; - -typedef union -{ - u32 val; - PPC_GQR_t f; -} PPC_GQR_u; - - -#define DMA_U_ADDR_MASK 0xFFFFFFE0 // Start addr in memory -#define DMA_U_LEN_U_MASK 0x0000001F // lines to transfer (U) - -#define DMA_L_LC_ADDR_MASK 0xFFFFFFE0 // Start addr in LC -#define DMA_L_LOAD 0x00000010 // 0 - store, 1 - load -#define DMA_L_STORE 0x00000000 // 0 - store, 1 - load -#define DMA_L_LEN_MASK 0x0000000C // lines to transfer (L) -#define DMA_L_TRIGGER 0x00000002 // 0 - cmd inactive, 1 - cmd rdy -#define DMA_L_FLUSH 0x00000001 // 1 - Flush DMA queue - -typedef struct -{ - u32 memAddr :27; - u32 dmaLenU :5; -} PPC_DMA_U_t; - -typedef union -{ - u32 val; - PPC_DMA_U_t f; -} PPC_DMA_U_u; - - -typedef struct -{ - u32 lcAddr :27; - u32 dmaLd :1; - u32 dmaLenL :2; - u32 dmaTrigger :1; - u32 dmaFlush :1; -} PPC_DMA_L_t; - - -typedef union -{ - u32 val; - PPC_DMA_L_t f; -} PPC_DMA_L_u; - - -#define WPAR_ADDR 0xFFFFFFE0 // 32byte gather address -#define WPAR_BNE 0x00000001 // Buffer not empty (R) - -#define SRR1_DMA_BIT 0x00200000 -#define SRR1_L2DP_BIT 0x00100000 - -#define L2CR_L2E 0x80000000 // L2 Enable -#define L2CR_L2PE 0x40000000 // L2 data parity generation and checking enable - -#define L2CR_L2SIZ_256K 0x10000000 // L2 size 256K -#define L2CR_L2SIZ_512K 0x20000000 // L2 size 512 -#define L2CR_L2SIZ_1M 0x30000000 // L2 size 1M - -#define L2CR_L2CLK_1_0 0x02000000 // L2 clock ratio 1 -#define L2CR_L2CLK_1_5 0x04000000 // L2 clock ratio 1.5 -#define L2CR_L2CLK_2_0 0x08000000 // L2 clock ratio 2 -#define L2CR_L2CLK_2_5 0x0A000000 // L2 clock ratio 2.5 -#define L2CR_L2CLK_3_0 0x0C000000 // L2 clock ratio 3 - -#define L2CR_RAM_FLOW_THRU_BURST 0x00000000 // L2 RAM type flow-through sync. burst SRAM -#define L2CR_RAM_PIPELINE_BURST 0x01000000 // L2 RAM type pipelined sync. burst SRAM -#define L2CR_RAM_PIPELINE_LATE 0x01800000 // L2 RAM type pipelined sync. late-write SRAM - -#define L2CR_L2DO 0x00400000 // Data only -#define L2CR_L2I 0x00200000 // Global invalidate -#define L2CR_L2CTL 0x00100000 // ZZ enable -#define L2CR_L2WT 0x00080000 // L2 write through -#define L2CR_L2TS 0x00040000 // L2 test support - -#define L2CR_L2OH_0_5 0x00000000 // L2 output hold 0.5 ns -#define L2CR_L2OH_1_0 0x00010000 // L2 output hold 1.0 ns - -#define L2CR_L2SL 0x00008000 // L2 DLL slow -#define L2CR_L2DF 0x00004000 // L2 differential clock -#define L2CR_L2BYP 0x00002000 // L2 DLL bypass -#define L2CR_L2CS 0x00000200 // L2 clock stop -#define L2CR_L2DRO 0x00000100 // L2 DLL rollover checkstop enable -#define L2CR_L2CTR_MASK 0x000000FE // L2 counter value mask -#define L2CR_L2IP 0x00000001 // L2 global invalidate in progress - -#define MMCR0_DIS 0x80000000 // Disables counting unconditionally -#define MMCR0_DP 0x40000000 // Disables counting while in supervisor mode -#define MMCR0_DU 0x20000000 // Disables counting while in user mode -#define MMCR0_DMS 0x10000000 // Disables counting while MSR[PM] is set -#define MMCR0_DMR 0x08000000 // Disables counting while MSR[PM] is zero -#define MMCR0_ENINT 0x04000000 // Enables performance monitor interrupt signaling -#define MMCR0_DISCOUNT 0x02000000 // Disables counting of PMCn when a performance monitor interrupt is signaled or... -#define MMCR0_RTCSELECT_MASK 0x01800000 // 64-bit time base, bit selection enable -#define MMCR0_RTCSELECT_63 0x00000000 // Pick bit 63 to count -#define MMCR0_RTCSELECT_55 0x00800000 // Pick bit 55 to count -#define MMCR0_RTCSELECT_51 0x01000000 // Pick bit 51 to count -#define MMCR0_RTCSELECT_47 0x01800000 // Pick bit 47 to count -#define MMCR0_INTONBITTRANS 0x00400000 // Causes interrupt signaling on bit transition from off to on -#define MMCR0_THRESHOLD_MASK 0x003F0000 // Threshold value -#define MMCR0_THRESHOLD(n) ((n) << 16) // Threshold value (0 - 63) -#define MMCR0_PMC1INTCONTROL 0x00008000 // Enables interrupt signaling due to PMC1 counter overflow -#define MMCR0_PMC2INTCONTROL 0x00004000 // Enables interrupt signaling due to PMC2-PMC4 counter overflow -#define MMCR0_PMCTRIGGER 0x00002000 // Can be used to trigger counting of PMC2-PMC4 after PMC1 has overflowed or... -#define MMCR0_PMC1SELECT_MASK 0x00001FC0 // PMC1 input selector -#define MMCR0_PMC2SELECT_MASK 0x0000003F // PMC2 input selector - -#define MMCR1_PMC3SELECT_MASK 0xF8000000 // PMC3 input selector -#define MMCR1_PMC4SELECT_MASK 0x07C00000 // PMC4 input selector - -#define PMC1_OV 0x80000000 // Overflow -#define PMC1_COUNTER 0x7FFFFFFF // Counter value -#define PMC2_OV 0x80000000 // Overflow -#define PMC2_COUNTER 0x7FFFFFFF // Counter value -#define PMC3_OV 0x80000000 // Overflow -#define PMC3_COUNTER 0x7FFFFFFF // Counter value -#define PMC4_OV 0x80000000 // Overflow -#define PMC4_COUNTER 0x7FFFFFFF // Counter value - -/*---------------------------------------------------------------------------* - PMC1 Events - *---------------------------------------------------------------------------*/ -#define MMCR0_PMC1_HOLD 0x00000000 // Register holds current value -#define MMCR0_PMC1_CYCLE 0x00000040 // Processor cycles -#define MMCR0_PMC1_INSTRUCTION 0x00000080 // # of instructions completed. -#define MMCR0_PMC1_TRANSITION 0x000000C0 // # of transitions for 0 to 1 -#define MMCR0_PMC1_DISPATCHED 0x00000100 // # of instructions dispatched -#define MMCR0_PMC1_EIEIO 0x00000140 // # of eieio instructions completed -#define MMCR0_PMC1_ITLB_CYCLE 0x00000180 // # of cycles spent performing table search op. for the ITLB -#define MMCR0_PMC1_L2_HIT 0x000001C0 // # of access that hit the L2. -#define MMCR0_PMC1_EA 0x00000200 // # of valid instruction EAs delivered to the memory subsystem -#define MMCR0_PMC1_IABR 0x00000240 // # of time the address of an instruction matches the IABR -#define MMCR0_PMC1_L1_MISS 0x00000280 // # of loads that miss the L1 -#define MMCR0_PMC1_Bx_UNRESOLVED 0x000002C0 // # of branches that are unresolved when processed -#define MMCR0_PMC1_Bx_STALL_CYCLE 0x00000300 // # of cycles that dispatcher stalls due to a second - // unresolved branch in the instruction stream -#define MMCR0_PMC1_IC_FETCH_MISS 0x00000340 // # of times an instruction fetch missed the L1 Icache -#define MMCR0_PMC2_HOLD 0x00000000 // Register holds current value -#define MMCR0_PMC2_CYCLE 0x00000001 // Processor cycles -#define MMCR0_PMC2_INSTRUCTION 0x00000002 // # of instructions completed -#define MMCR0_PMC2_TRANSITION 0x00000003 // # of time-base (lower) bit transitions -#define MMCR0_PMC2_DISPATCHED 0x00000004 // # of instructions dispatched -#define MMCR0_PMC2_IC_MISS 0x00000005 // # of L1 instruction cache misses -#define MMCR0_PMC2_ITLB_MISS 0x00000006 // # of ITLB misses -#define MMCR0_PMC2_L2_I_MISS 0x00000007 // # of L2 instruction misses -#define MMCR0_PMC2_Bx_FALL_TROUGH 0x00000008 // # of fall-through branches -#define MMCR0_PMC2_PR_SWITCH 0x00000009 // # of MSR[PR] bit toggles -#define MMCR0_PMC2_RESERVED_LOAD 0x0000000A // # of reserved loads completed -#define MMCR0_PMC2_LOAD_STORE 0x0000000B // # of completed loads and stores -#define MMCR0_PMC2_SNOOP 0x0000000C // # of snoops -#define MMCR0_PMC2_L1_CASTOUT 0x0000000D // # of L1 castouts to L2 -#define MMCR0_PMC2_SYSTEM 0x0000000E // # of completed system unit instructions -#define MMCR0_PMC2_IC_FETCH_MISS 0x0000000F // # of instruction fetch misses in the L1 -#define MMCR0_PMC2_Bx_OUT_OF_ORDER 0x00000010 // # of branches allowing out-of-order execution - -/*---------------------------------------------------------------------------* - PMC3 Events - *---------------------------------------------------------------------------*/ -#define MMCR1_PMC3_HOLD 0x00000000 // Register holds current value -#define MMCR1_PMC3_CYCLE 0x08000000 // Processor cycles -#define MMCR1_PMC3_INSTRUCTION 0x10000000 // # of instructions completed -#define MMCR1_PMC3_TRANSITION 0x18000000 // # of time-base (lower) bit transitions -#define MMCR1_PMC3_DISPATCHED 0x20000000 // # of instructions dispatched -#define MMCR1_PMC3_DC_MISS 0x28000000 // # of L1 data cache misses -#define MMCR1_PMC3_DTLB_MISS 0x30000000 // # of DTLB misses -#define MMCR1_PMC3_L2_D_MISS 0x38000000 // # of L2 data misses -#define MMCR1_PMC3_Bx_TAKEN 0x40000000 // # predicted branches that were taken -#define MMCR1_PMC3_PM_SWITCH 0x48000000 // # of transitions between marked and unmarked processes -#define MMCR1_PMC3_COND_STORE 0x50000000 // # of store conditional instructions completed -#define MMCR1_PMC3_FPU 0x58000000 // # of instructions completed from the FPU -#define MMCR1_PMC3_L2_SNOOP_CASTOUT 0x60000000 // # of L2 castout caused by snoops to modified lines -#define MMCR1_PMC3_L2_HIT 0x68000000 // # of cache operations that hit in the L2 cache -#define MMCR1_PMC3_L1_MISS_CYCLE 0x78000000 // # of cycles generated by L1 load misses -#define MMCR1_PMC3_Bx_SECOND 0x80000000 // # of branches in the second speculative branch - // resolved correctly -#define MMCR1_PMC3_BPU_LR_CR 0x88000000 // # of cycles the BPU stalls due to LR or CR unresolved - // dependencies - -#define MMCR1_PMC4_HOLD 0x00000000 // Register holds current value -#define MMCR1_PMC4_CYCLE 0x00400000 // Processor cycles -#define MMCR1_PMC4_INSTRUCTION 0x00800000 // # of instructions completed -#define MMCR1_PMC4_TRANSITION 0x00C00000 // # of time-base (lower) bit transitions -#define MMCR1_PMC4_DISPATCHED 0x01000000 // # of instructions dispatched -#define MMCR1_PMC4_L2_CASTOUT 0x01400000 // # of L2 castouts -#define MMCR1_PMC4_DTLB_CYCLE 0x01800000 // # of cycles spent performing table searches for DTLB accesses -#define MMCR1_PMC4_Bx_MISSED 0x02000000 // # of mispredicted branches -#define MMCR1_PMC4_COND_STORE_INT 0x02800000 // # of store conditional instructions completed - // with reservation intact -#define MMCR1_PMC4_SYNC 0x02C00000 // # of completed sync instructions -#define MMCR1_PMC4_SNOOP_RETRY 0x03000000 // # of snoop request retries -#define MMCR1_PMC4_INTEGER 0x03400000 // # of completed integer operations -#define MMCR1_PMC4_BPU_THIRD 0x03800000 // # of cycles the BPU cannot process new branches - // due to having two unresolved branches -#define MMCR1_PMC4_DC_MISS 0x07C00000 // # of L1 data cache misses - -/*---------------------------------------------------------------------------* - FPSCR bits - *---------------------------------------------------------------------------*/ -#ifndef FPSCR_FX -#define FPSCR_FX 0x80000000 // Exception summary -#define FPSCR_FEX 0x40000000 // Enabled exception summary -#define FPSCR_VX 0x20000000 // Invalid operation -#define FPSCR_OX 0x10000000 // Overflow exception -#define FPSCR_UX 0x08000000 // Underflow exception -#define FPSCR_ZX 0x04000000 // Zero divide exception -#define FPSCR_XX 0x02000000 // Inexact exception -#define FPSCR_VXSNAN 0x01000000 // SNaN -#define FPSCR_VXISI 0x00800000 // Infinity - Infinity -#define FPSCR_VXIDI 0x00400000 // Infinity / Infinity -#define FPSCR_VXZDZ 0x00200000 // 0 / 0 -#define FPSCR_VXIMZ 0x00100000 // Infinity * 0 -#define FPSCR_VXVC 0x00080000 // Invalid compare -#define FPSCR_FR 0x00040000 // Fraction rounded -#define FPSCR_FI 0x00020000 // Fraction inexact -#define FPSCR_VXSOFT 0x00000400 // Software request -#define FPSCR_VXSQRT 0x00000200 // Invalid square root -#define FPSCR_VXCVI 0x00000100 // Invalid integer convert -#define FPSCR_VE 0x00000080 // Invalid operation exception enable -#define FPSCR_OE 0x00000040 // Overflow exception enable -#define FPSCR_UE 0x00000020 // Underflow exception enable -#define FPSCR_ZE 0x00000010 // Zero divide exception enable -#define FPSCR_XE 0x00000008 // Inexact exception enable -#define FPSCR_NI 0x00000004 // Non-IEEE mode -#endif - -#ifndef FPSCR_FX_BIT -#define FPSCR_FX_BIT 0 // Exception summary -#define FPSCR_FEX_BIT 1 // Enabled exception summary -#define FPSCR_VX_BIT 2 // Invalid operation -#define FPSCR_OX_BIT 3 // Overflow exception -#define FPSCR_UX_BIT 4 // Underflow exception -#define FPSCR_ZX_BIT 5 // Zero divide exception -#define FPSCR_XX_BIT 6 // Inexact exception -#define FPSCR_VXSNAN_BIT 7 // SNaN -#define FPSCR_VXISI_BIT 8 // Infinity - Infinity -#define FPSCR_VXIDI_BIT 9 // Infinity / Infinity -#define FPSCR_VXZDZ_BIT 10 // 0 / 0 -#define FPSCR_VXIMZ_BIT 11 // Infinity * 0 -#define FPSCR_VXVC_BIT 12 // Invalid compare -#define FPSCR_FR_BIT 13 // Fraction rounded -#define FPSCR_FI_BIT 14 // Fraction inexact -#define FPSCR_VXSOFT_BIT 21 // Software request -#define FPSCR_VXSQRT_BIT 22 // Invalid square root -#define FPSCR_VXCVI_BIT 23 // Invalid integer convert -#define FPSCR_VE_BIT 24 // Invalid operation exception enable -#define FPSCR_OE_BIT 25 // Overflow exception enable -#define FPSCR_UE_BIT 26 // Underflow exception enable -#define FPSCR_ZE_BIT 27 // Zero divide exception enable -#define FPSCR_XE_BIT 28 // Inexact exception enable -#define FPSCR_NI_BIT 29 // Non-IEEE mode -#endif - -union FpscrUnion { - f64 f; - struct { - u32 fpscr_pad; - u32 fpscr; - } u; -}; - -// PPCArch -u32 PPCMfmsr(); -void PPCMtmsr(u32 newMSR); -u32 PPCOrMsr(u32 value); -u32 PPCMfhid0(); -void PPCMthid0(u32 newHID0); -u32 PPCMfl2cr(); -void PPCMtl2cr(u32 newL2cr); -void PPCMtdec(u32 newDec); -void PPCSync(); -void PPCHalt(); -u32 PPCMffpscr(); -void PPCMtfpscr(u32 newFPSCR); -u32 PPCMfhid2(); -void PPCMthid2(u32 newhid2); -u32 PPCMfwpar(); -void PPCMtwpar(u32 newwpar); -void PPCEnableSpeculation(); -void PPCDisableSpeculation(); -void PPCSetFpIEEEMode(); -void PPCSetFpNonIEEEMode(); -u32 PPCMfpmc4(); -u32 PPCMfpmc3(); -u32 PPCMfpmc1(); -void PPCMtpmc1(u32 newPmc1); -void PPCMtpmc2(u32 newPmc1); -void PPCMtpmc3(u32 newPmc1); -void PPCMtpmc4(u32 newPmc1); -void PPCMtmmcr0(u32 newMmcr0); -void PPCMtmmcr1(u32 newMmcr0); -void PPCMtdmaU(u32 newdmau); -void PPCMtdmaL(u32 newdmal); -u32 PPCMfdec(void); -u32 PPCMfpmc2(void); -u32 PPCAndMsr(u32 value); -u32 PPCAndCMsr(u32 value); -u32 PPCMfhid1(); -void PPCEieio(); -u32 PPCMfmmcr0(); -u32 PPCMfmmcr1(); -u32 PPCMfpmc2(); -u32 PPCMfsia(); -void PPCMtsia(u32 newSia); -u32 PPCMfdmaL(); -u32 PPCMfpvr(); -u32 PPCMfdmaU(); - -// PPCPm -void PMBegin(void); -void PMEnd(void); -void PMCycles(void); -void PML1FetchMisses(void); -void PML1MissCycles(void); -void PMInstructions(void); - -#ifdef __cplusplus -} -#endif - -#endif // _DOLPHIN_PPCARCH diff --git a/aurora-main/include/dolphin/card.h b/aurora-main/include/dolphin/card.h deleted file mode 100644 index 33b9a5d..0000000 --- a/aurora-main/include/dolphin/card.h +++ /dev/null @@ -1,340 +0,0 @@ -#ifndef _DOLPHIN_CARD_H_ -#define _DOLPHIN_CARD_H_ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define CARD_FILENAME_MAX 32 -#define CARD_MAX_FILE 127 -#define CARD_ICON_MAX 8 - -#if TARGET_PC - -typedef enum { - CARD_RAWIMAGE, - CARD_GCIFOLDER, -} CARDFileType; - -#endif - -typedef void (*CARDCallback)(s32 chan, s32 result); - -typedef struct CARDFileInfo { - s32 chan; - s32 fileNo; - s32 offset; - s32 length; - u16 iBlock; -} CARDFileInfo; - -typedef struct CARDDir { - u8 gameName[4]; - u8 company[2]; - u8 _padding0; - u8 bannerFormat; - u8 fileName[CARD_FILENAME_MAX]; - u32 time; // seconds since 01/01/2000 midnight - u32 iconAddr; // 0xffffffff if not used - u16 iconFormat; - u16 iconSpeed; - u8 permission; - u8 copyTimes; - u16 startBlock; - u16 length; - u8 _padding1[2]; - u32 commentAddr; // 0xffffffff if not used -} CARDDir; - -typedef struct CARDControl { - /* 0x000 */ BOOL attached; - /* 0x004 */ s32 result; - /* 0x008 */ u16 size; - /* 0x00A */ u16 pageSize; - /* 0x00C */ s32 sectorSize; - /* 0x010 */ u16 cBlock; - /* 0x012 */ u16 vendorID; - /* 0x014 */ s32 latency; - /* 0x018 */ u8 id[12]; - /* 0x024 */ int mountStep; - /* 0x028 */ int formatStep; - /* 0x028 */ u32 scramble; - /* 0x02C */ DSPTaskInfo task; - /* 0x080 */ void* workArea; - /* 0x084 */ CARDDir *currentDir; - /* 0x088 */ u16* currentFat; - /* 0x08C */ OSThreadQueue threadQueue; - /* 0x094 */ u8 cmd[9]; - /* 0x0A0 */ s32 cmdlen; - /* 0x0A4 */ volatile u32 mode; - /* 0x0A8 */ int retry; - /* 0x0AC */ int repeat; - /* 0x0B0 */ u32 addr; - /* 0x0B4 */ void* buffer; - /* 0x0B8 */ s32 xferred; - /* 0x0BC */ u16 freeNo; - /* 0x0BE */ u16 startBlock; - /* 0x0C0 */ CARDFileInfo* fileInfo; - /* 0x0C4 */ CARDCallback extCallback; - /* 0x0C8 */ CARDCallback txCallback; - /* 0x0CC */ CARDCallback exiCallback; - /* 0x0D0 */ CARDCallback apiCallback; - /* 0x0D4 */ CARDCallback xferCallback; - /* 0x0D8 */ CARDCallback eraseCallback; - /* 0x0DC */ CARDCallback unlockCallback; - /* 0x0E0 */ OSAlarm alarm; - /* 0x108 */ u32 cid; - /* 0x10C */ const DVDDiskID* diskID; -} CARDControl; - -typedef struct CARDDecParam { - /* 0x00 */ u8* inputAddr; - /* 0x04 */ u32 inputLength; - /* 0x08 */ u32 aramAddr; - /* 0x0C */ u8* outputAddr; -} CARDDecParam; - -typedef struct CARDID { - /* 0x000 */ u8 serial[32]; - /* 0x020 */ u16 deviceID; - /* 0x022 */ u16 size; - /* 0x024 */ u16 encode; - /* 0x026 */ u8 padding[470]; - /* 0x1FC */ u16 checkSum; - /* 0x1FE */ u16 checkSumInv; -} CARDID; - -typedef struct CARDDirCheck { - /* 0x00 */ u8 padding0[56]; - /* 0x38 */ u16 padding1; - /* 0x3A */ s16 checkCode; - /* 0x3C */ u16 checkSum; - /* 0x3E */ u16 checkSumInv; -} CARDDirCheck; - -typedef struct CARDStat { - /* 0x00 */ char fileName[CARD_FILENAME_MAX]; - /* 0x20 */ u32 length; - /* 0x24 */ u32 time; - /* 0x28 */ u8 gameName[4]; - /* 0x2C */ u8 company[2]; - /* 0x2E */ u8 bannerFormat; - /* 0x30 */ u32 iconAddr; - /* 0x34 */ u16 iconFormat; - /* 0x36 */ u16 iconSpeed; - /* 0x38 */ u32 commentAddr; - /* 0x3C */ u32 offsetBanner; - /* 0x40 */ u32 offsetBannerTlut; - /* 0x44 */ u32 offsetIcon[CARD_ICON_MAX]; - /* 0x64 */ u32 offsetIconTlut; - /* 0x68 */ u32 offsetData; -} CARDStat; - -#define CARD_ATTR_PUBLIC 0x04u -#define CARD_ATTR_NO_COPY 0x08u -#define CARD_ATTR_NO_MOVE 0x10u -#define CARD_ATTR_GLOBAL 0x20u -#define CARD_ATTR_COMPANY 0x40u - -#define CARD_FAT_AVAIL 0x0000u -#define CARD_FAT_CHECKSUM 0x0000u -#define CARD_FAT_CHECKSUMINV 0x0001u -#define CARD_FAT_CHECKCODE 0x0002u -#define CARD_FAT_FREEBLOCKS 0x0003u -#define CARD_FAT_LASTSLOT 0x0004u - -#define CARD_WORKAREA_SIZE (5 * 8 * 1024) - -#define CARD_SEG_SIZE 0x200u -#define CARD_PAGE_SIZE 0x80u -#define CARD_MAX_SIZE 0x01000000U - -#define CARD_NUM_SYSTEM_BLOCK 5 -#define CARD_SYSTEM_BLOCK_SIZE (8 * 1024u) - -#define CARD_MAX_MOUNT_STEP (CARD_NUM_SYSTEM_BLOCK + 2) - -#define CARD_STAT_SPEED_END 0 -#define CARD_STAT_SPEED_FAST 1 -#define CARD_STAT_SPEED_MIDDLE 2 -#define CARD_STAT_SPEED_SLOW 3 -#define CARD_STAT_SPEED_MASK 3 - -#define CARD_STAT_ANIM_LOOP 0 -#define CARD_STAT_ANIM_BOUNCE 4 -#define CARD_STAT_ANIM_MASK 0x4 - -#define CARD_RESULT_UNLOCKED 1 -#define CARD_RESULT_READY 0 -#define CARD_RESULT_BUSY -1 -#define CARD_RESULT_WRONGDEVICE -2 -#define CARD_RESULT_NOCARD -3 -#define CARD_RESULT_NOFILE -4 -#define CARD_RESULT_IOERROR -5 -#define CARD_RESULT_BROKEN -6 -#define CARD_RESULT_EXIST -7 -#define CARD_RESULT_NOENT -8 -#define CARD_RESULT_INSSPACE -9 -#define CARD_RESULT_NOPERM -10 -#define CARD_RESULT_LIMIT -11 -#define CARD_RESULT_NAMETOOLONG -12 -#define CARD_RESULT_ENCODING -13 -#define CARD_RESULT_CANCELED -14 -#define CARD_RESULT_FATAL_ERROR -128 - -#define CARDIsValidBlockNo(card, blockNo) ((blockNo) >= CARD_NUM_SYSTEM_BLOCK && (blockNo) < (card)->cBlock) - -#define CARD_READ_SIZE 512 - -#define CARD_COMMENT_SIZE 64 - -#define CARD_ICON_WIDTH 32 -#define CARD_ICON_HEIGHT 32 - -#define CARD_BANNER_WIDTH 96 -#define CARD_BANNER_HEIGHT 32 - -#define CARD_STAT_ICON_NONE 0 -#define CARD_STAT_ICON_C8 1 -#define CARD_STAT_ICON_RGB5A3 2 -#define CARD_STAT_ICON_MASK 3 - -#define CARD_STAT_BANNER_NONE 0 -#define CARD_STAT_BANNER_C8 1 -#define CARD_STAT_BANNER_RGB5A3 2 -#define CARD_STAT_BANNER_MASK 3 - -#define CARD_ENCODE_ANSI 0 -#define CARD_ENCODE_SJIS 1 - -#define CARDGetDirCheck(dir) ((CARDDirCheck*)&(dir)[CARD_MAX_FILE]) -#define CARDGetBannerFormat(stat) (((stat)->bannerFormat) & CARD_STAT_BANNER_MASK) -#define CARDGetIconAnim(stat) (((stat)->bannerFormat) & CARD_STAT_ANIM_MASK) -#define CARDGetIconFormat(stat, n) (((stat)->iconFormat >> (2 * (n))) & CARD_STAT_ICON_MASK) -#define CARDGetIconSpeed(stat, n) (((stat)->iconSpeed >> (2 * (n))) & CARD_STAT_SPEED_MASK) -#define CARDSetBannerFormat(stat, f) \ - ((stat)->bannerFormat = (u8)(((stat)->bannerFormat & ~CARD_STAT_BANNER_MASK) | (f))) -#define CARDSetIconAnim(stat, f) \ - ((stat)->bannerFormat = (u8)(((stat)->bannerFormat & ~CARD_STAT_ANIM_MASK) | (f))) -#define CARDSetIconFormat(stat, n, f) \ - ((stat)->iconFormat = \ - (u16)(((stat)->iconFormat & ~(CARD_STAT_ICON_MASK << (2 * (n)))) | ((f) << (2 * (n))))) -#define CARDSetIconSpeed(stat, n, f) \ - ((stat)->iconSpeed = \ - (u16)(((stat)->iconSpeed & ~(CARD_STAT_SPEED_MASK << (2 * (n)))) | ((f) << (2 * (n))))) -#define CARDSetIconAddress(stat, addr) ((stat)->iconAddr = (u32)(addr)) -#define CARDSetCommentAddress(stat, addr) ((stat)->commentAddr = (u32)(addr)) -#define CARDGetFileNo(fileInfo) ((fileInfo)->fileNo) - -extern u32 __CARDFreq; - -#if DEBUG -#define CARDFreq __CARDFreq -#else -#define CARDFreq EXI_FREQ_16M -#endif - -s32 CARDRenameAsync(s32 chan, const char* oldName, const char* newName, CARDCallback callback); - -// CARDBios -#if TARGET_PC -void CARDInit(const char* game, const char* maker); -void CARDSetGameAndMaker(const s32 chan, const char* game, const char* maker); - -// pass -1 to set both -void CARDDetectDolphin(s32 chan); -// pass -1 to set both -void CARDSetBasePath(const char*, s32 chan); -void CARDSetLoadType(CARDFileType type); - -#else -void CARDInit(void); -#endif -s32 CARDGetResultCode(s32 chan); -s32 CARDFreeBlocks(s32 chan, s32* byteNotUsed, s32* filesNotUsed); -s32 CARDGetEncoding(s32 chan, u16* encode); -s32 CARDGetMemSize(s32 chan, u16* size); -s32 CARDGetSectorSize(s32 chan, u32* size); -const DVDDiskID* CARDGetDiskID(s32 chan); -s32 CARDSetDiskID(s32 chan, const DVDDiskID* diskID); -BOOL CARDSetFastMode(BOOL enable); -BOOL CARDGetFastMode(void); -s32 CARDGetCurrentMode(s32 chan, u32* mode); - -// CARDCheck -s32 CARDCheckExAsync(s32 chan, s32* xferBytes, CARDCallback callback); -s32 CARDCheckAsync(s32 chan, CARDCallback callback); -s32 CARDCheckEx(s32 chan, s32* xferBytes); -s32 CARDCheck(s32 chan); - -// CARDCreate -s32 CARDCreateAsync(s32 chan, const char* fileName, u32 size, CARDFileInfo* fileInfo, CARDCallback callback); -s32 CARDCreate(s32 chan, const char* fileName, u32 size, CARDFileInfo* fileInfo); - -// CARDDelete -s32 CARDFastDeleteAsync(s32 chan, s32 fileNo, CARDCallback callback); -s32 CARDFastDelete(s32 chan, s32 fileNo); -s32 CARDDeleteAsync(s32 chan, const char* fileName, CARDCallback callback); -s32 CARDDelete(s32 chan, const char* fileName); - -// CARDErase -s32 CARDEraseAsync(CARDFileInfo* fileInfo, s32 length, s32 offset, CARDCallback callback); -s32 CARDErase(CARDFileInfo* fileInfo, s32 length, s32 offset); - -// CARDFormat -s32 CARDFormat(s32 chan); - -// CARDMount -int CARDProbe(s32 chan); -s32 CARDProbeEx(s32 chan, s32* memSize, s32* sectorSize); -s32 CARDMountAsync(s32 chan, void* workArea, CARDCallback detachCallback, CARDCallback attachCallback); -s32 CARDMount(s32 chan, void* workArea, CARDCallback detachCallback); -s32 CARDUnmount(s32 chan); - -// CARDNet -u16 CARDSetVendorID(u16 vendorID); -u16 CARDGetVendorID(); -s32 CARDGetSerialNo(s32 chan, u64* serialNo); -s32 CARDGetUniqueCode(s32 chan, u64* uniqueCode); -s32 CARDGetAttributes(s32 chan, s32 fileNo, u8* attr); -s32 CARDSetAttributesAsync(s32 chan, s32 fileNo, u8 attr, CARDCallback callback); -s32 CARDSetAttributes(s32 chan, s32 fileNo, u8 attr); - -// CARDOpen -s32 CARDFastOpen(s32 chan, s32 fileNo, CARDFileInfo* fileInfo); -s32 CARDOpen(s32 chan, const char* fileName, CARDFileInfo* fileInfo); -s32 CARDClose(CARDFileInfo* fileInfo); - -// CARDProgram -s32 CARDProgramAsync(CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset, CARDCallback callback); -s32 CARDProgram(CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset); - -// CARDRdwr -s32 CARDGetXferredBytes(s32 chan); - -// CARDRead -s32 CARDReadAsync(const CARDFileInfo* fileInfo, void* addr, s32 length, s32 offset, CARDCallback callback); -s32 CARDRead(const CARDFileInfo* fileInfo, void* addr, s32 length, s32 offset); -s32 CARDCancel(CARDFileInfo* fileInfo); - -// CARDRename -s32 CARDRename(s32 chan, const char* oldName, const char* newName); - -// CARDStat -s32 CARDGetStatus(s32 chan, s32 fileNo, CARDStat* stat); -s32 CARDSetStatusAsync(s32 chan, s32 fileNo, const CARDStat* stat, CARDCallback callback); -s32 CARDSetStatus(s32 chan, s32 fileNo, const CARDStat* stat); - -// CARDWrite -s32 CARDWriteAsync(const CARDFileInfo* fileInfo, const void* addr, s32 length, s32 offset, CARDCallback callback); -s32 CARDWrite(const CARDFileInfo* fileInfo, const void* addr, s32 length, s32 offset); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/db.h b/aurora-main/include/dolphin/db.h deleted file mode 100644 index c62f188..0000000 --- a/aurora-main/include/dolphin/db.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _DOLPHIN_DB_H_ -#define _DOLPHIN_DB_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define OS_DBINTERFACE_ADDR 0x00000040 - -BOOL DBIsDebuggerPresent(void); -void DBPrintf(char* str, ...); -s32 DBQueryData(void); -u32 DBRead(u8*, u32); - -#ifdef __cplusplus -} -#endif - -#endif // _DOLPHIN_DB_H_ diff --git a/aurora-main/include/dolphin/db/DBInterface.h b/aurora-main/include/dolphin/db/DBInterface.h deleted file mode 100644 index 7bfa354..0000000 --- a/aurora-main/include/dolphin/db/DBInterface.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef _DOLPHIN_DBINTERFACE_H_ -#define _DOLPHIN_DBINTERFACE_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct DBInterface { - u32 bPresent; - u32 exceptionMask; - void (*ExceptionDestination)(void); - void* exceptionReturn; -} DBInterface; - -extern DBInterface* __DBInterface; - -void DBInit(void); -void DBInitComm(int* inputFlagPtr, int* mtrCallback); -void __DBExceptionDestination(void); -void __DBExceptionDestinationAux(void); -BOOL __DBIsExceptionMarked(__OSException exception); -void __DBMarkException(u8 exception, int value); -void __DBSetPresent(u32 value); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/dolphin.h b/aurora-main/include/dolphin/dolphin.h deleted file mode 100644 index f0025ed..0000000 --- a/aurora-main/include/dolphin/dolphin.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _DOLPHIN_H_ -#define _DOLPHIN_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -// #include -#include -#include - -#endif diff --git a/aurora-main/include/dolphin/dsp.h b/aurora-main/include/dolphin/dsp.h deleted file mode 100644 index 72ffa82..0000000 --- a/aurora-main/include/dolphin/dsp.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef _DOLPHIN_DSP_H_ -#define _DOLPHIN_DSP_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*DSPCallback)(void* task); -typedef struct STRUCT_DSP_TASK DSPTaskInfo; - -typedef struct STRUCT_DSP_TASK { - /* 0x00 */ volatile u32 state; - /* 0x04 */ volatile u32 priority; - /* 0x08 */ volatile u32 flags; - /* 0x0C */ u16* iram_mmem_addr; - /* 0x10 */ u32 iram_length; - /* 0x14 */ u32 iram_addr; - /* 0x18 */ u16* dram_mmem_addr; - /* 0x1C */ u32 dram_length; - /* 0x20 */ u32 dram_addr; - /* 0x24 */ u16 dsp_init_vector; - /* 0x26 */ u16 dsp_resume_vector; - /* 0x28 */ DSPCallback init_cb; - /* 0x2C */ DSPCallback res_cb; - /* 0x30 */ DSPCallback done_cb; - /* 0x34 */ DSPCallback req_cb; - /* 0x38 */ DSPTaskInfo* next; - /* 0x3C */ DSPTaskInfo* prev; - /* 0x40 */ OSTime t_context; - /* 0x48 */ OSTime t_task; -} DSPTaskInfo; - -u32 DSPCheckMailToDSP(void); -u32 DSPCheckMailFromDSP(void); -u32 DSPReadCPUToDSPMbox(void); -u32 DSPReadMailFromDSP(void); -void DSPSendMailToDSP(u32 mail); -void DSPAssertInt(void); -void DSPInit(void); -BOOL DSPCheckInit(void); -void DSPReset(void); -void DSPHalt(void); -void DSPUnhalt(void); -u32 DSPGetDMAStatus(void); -DECL_WEAK DSPTaskInfo* DSPAddTask(DSPTaskInfo* task); -DSPTaskInfo* DSPCancelTask(DSPTaskInfo* task); -DSPTaskInfo* DSPAssertTask(DSPTaskInfo* task); - -DSPTaskInfo* __DSPGetCurrentTask(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/dtk.h b/aurora-main/include/dolphin/dtk.h deleted file mode 100644 index 3a76a0f..0000000 --- a/aurora-main/include/dolphin/dtk.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef _DOLPHIN_DTK_H_ -#define _DOLPHIN_DTK_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*DTKCallback)(u32 eventMask); -typedef void (*DTKFlushCallback)(void); - -typedef struct DTKTrack { - /* 0x00 */ struct DTKTrack* prev; - /* 0x04 */ struct DTKTrack* next; - /* 0x08 */ char* fileName; - /* 0x0C */ u32 eventMask; - /* 0x10 */ DTKCallback callback; - /* 0x14 */ DVDFileInfo dvdFileInfo; -} DTKTrack; - -#define DTK_STATE_STOP 0 -#define DTK_STATE_RUN 1 -#define DTK_STATE_PAUSE 2 -#define DTK_STATE_BUSY 3 -#define DTK_STATE_PREPARE 4 - -#define DTK_MODE_NOREPEAT 0 -#define DTK_MODE_ALLREPEAT 1 -#define DTK_MODE_REPEAT1 2 - -void DTKInit(void); -void DTKShutdown(void); -u32 DTKQueueTrack(char* fileName, DTKTrack* track, u32 eventMask, DTKCallback callback); -u32 DTKRemoveTrack(DTKTrack* track); -int DTKFlushTracks(DTKFlushCallback callback); -void DTKSetSampleRate(u32 samplerate); -void DTKSetInterruptFrequency(u32 samples); -void DTKSetRepeatMode(u32 repeat); -int DTKSetState(u32 state); -int DTKNextTrack(void); -int DTKPrevTrack(void); -u32 DTKGetSampleRate(void); -u32 DTKGetRepeatMode(void); -u32 DTKGetState(void); -u32 DTKGetPosition(void); -u32 DTKGetInterruptFrequency(void); -DTKTrack* DTKGetCurrentTrack(void); -void DTKSetVolume(u8 left, u8 right); -u16 DTKGetVolume(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/dvd.h b/aurora-main/include/dolphin/dvd.h deleted file mode 100644 index b2e1757..0000000 --- a/aurora-main/include/dolphin/dvd.h +++ /dev/null @@ -1,237 +0,0 @@ -#ifndef _DOLPHIN_DVD_H_ -#define _DOLPHIN_DVD_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define DVD_ASSERTMSGLINE(line, cond, msg) \ - if (!(cond)) \ - OSPanic(__FILE__, line, msg) - -#define DVD_ASSERTMSG1LINE(line, cond, msg, arg1) \ - if (!(cond)) \ - OSPanic(__FILE__, line, msg, arg1) - -#define DVD_ASSERTMSG2LINE(line, cond, msg, arg1, arg2) \ - if (!(cond)) \ - OSPanic(__FILE__, line, msg, arg1, arg2) - -#define DVD_RESULT_GOOD 0 -#define DVD_RESULT_FATAL_ERROR -1 -#define DVD_RESULT_IGNORED -2 -#define DVD_RESULT_CANCELED -6 - -#define DVD_STATE_FATAL_ERROR -1 -#define DVD_STATE_END 0 -#define DVD_STATE_BUSY 1 -#define DVD_STATE_WAITING 2 -#define DVD_STATE_COVER_CLOSED 3 -#define DVD_STATE_NO_DISK 4 -#define DVD_STATE_COVER_OPEN 5 -#define DVD_STATE_WRONG_DISK 6 -#define DVD_STATE_MOTOR_STOPPED 7 -#define DVD_STATE_PAUSING 8 -#define DVD_STATE_IGNORED 9 -#define DVD_STATE_CANCELED 10 -#define DVD_STATE_RETRY 11 - -#define DVD_MIN_TRANSFER_SIZE 32 - -// could be bitfields -#define DVD_INTTYPE_TC 1 -#define DVD_INTTYPE_DE 2 -// unk type 3 -#define DVD_INTTYPE_CVR 4 - -// DVD Commands -#define DVD_COMMAND_NONE 0 -#define DVD_COMMAND_READ 1 -#define DVD_COMMAND_SEEK 2 -#define DVD_COMMAND_CHANGE_DISK 3 -#define DVD_COMMAND_BSREAD 4 -#define DVD_COMMAND_READID 5 -#define DVD_COMMAND_INITSTREAM 6 -#define DVD_COMMAND_CANCELSTREAM 7 -#define DVD_COMMAND_STOP_STREAM_AT_END 8 -#define DVD_COMMAND_REQUEST_AUDIO_ERROR 9 -#define DVD_COMMAND_REQUEST_PLAY_ADDR 10 -#define DVD_COMMAND_REQUEST_START_ADDR 11 -#define DVD_COMMAND_REQUEST_LENGTH 12 -#define DVD_COMMAND_AUDIO_BUFFER_CONFIG 13 -#define DVD_COMMAND_INQUIRY 14 -#define DVD_COMMAND_BS_CHANGE_DISK 15 -#define DVD_COMMAND_UNK_16 16 - -typedef struct DVDDiskID { - char gameName[4]; - char company[2]; - u8 diskNumber; - u8 gameVersion; - u8 streaming; - u8 streamingBufSize; - u8 padding[22]; -} DVDDiskID; - -typedef struct DVDCommandBlock DVDCommandBlock; -typedef void (*DVDCBCallback)(s32 result, DVDCommandBlock* block); -typedef void (*DVDLowCallback)(u32); - -typedef void (*DVDCommandCheckerCallback)(u32); -typedef void (*DVDCommandChecker)(DVDCommandBlock*, DVDCommandCheckerCallback); - -struct DVDCommandBlock { - /* 0x00 */ DVDCommandBlock* next; - /* 0x04 */ DVDCommandBlock* prev; - /* 0x08 */ u32 command; - /* 0x0C */ s32 state; - /* 0x10 */ u32 offset; - /* 0x14 */ u32 length; - /* 0x18 */ void* addr; - /* 0x1C */ u32 currTransferSize; - /* 0x20 */ u32 transferredSize; - /* 0x24 */ DVDDiskID* id; - /* 0x28 */ DVDCBCallback callback; - /* 0x2C */ void* userData; -}; - -typedef struct DVDFileInfo DVDFileInfo; -typedef void (*DVDCallback)(s32 result, DVDFileInfo *fileInfo); -struct DVDFileInfo { - /* 0x00 */ DVDCommandBlock cb; - /* 0x30 */ u32 startAddr; - /* 0x34 */ u32 length; - /* 0x38 */ DVDCallback callback; -}; - -typedef struct { - u32 entryNum; - u32 location; - u32 next; -} DVDDir; - -typedef struct { - u32 entryNum; - BOOL isDir; - char* name; -} DVDDirEntry; - -typedef struct DVDBB2 { - /* 0x00 */ u32 bootFilePosition; - /* 0x04 */ u32 FSTPosition; - /* 0x08 */ u32 FSTLength; - /* 0x0C */ u32 FSTMaxLength; - /* 0x10 */ void* FSTAddress; - /* 0x14 */ u32 userPosition; - /* 0x18 */ u32 userLength; - /* 0x1C */ u32 padding0; -} DVDBB2; - -typedef struct DVDDriveInfo { - /* 0x00 */ u16 revisionLevel; - /* 0x02 */ u16 deviceCode; - /* 0x04 */ u32 releaseDate; - /* 0x08 */ u8 padding[24]; -} DVDDriveInfo; - -// DVD -void DVDInit(void); -int DVDReadAbsAsyncPrio(DVDCommandBlock* block, void* addr, s32 length, s32 offset, DVDCBCallback callback, s32 prio); -int DVDSeekAbsAsyncPrio(DVDCommandBlock* block, s32 offset, DVDCBCallback callback, s32 prio); -int DVDReadAbsAsyncForBS(DVDCommandBlock* block, void* addr, s32 length, s32 offset, DVDCBCallback callback); -int DVDReadDiskID(DVDCommandBlock* block, DVDDiskID* diskID, DVDCBCallback callback); -int DVDPrepareStreamAbsAsync(DVDCommandBlock* block, u32 length, u32 offset, DVDCBCallback callback); -int DVDCancelStreamAsync(DVDCommandBlock* block, DVDCBCallback callback); -s32 DVDCancelStream(DVDCommandBlock* block); -int DVDStopStreamAtEndAsync(DVDCommandBlock* block, DVDCBCallback callback); -s32 DVDStopStreamAtEnd(DVDCommandBlock* block); -int DVDGetStreamErrorStatusAsync(DVDCommandBlock* block, DVDCBCallback callback); -s32 DVDGetStreamErrorStatus(DVDCommandBlock* block); -int DVDGetStreamPlayAddrAsync(DVDCommandBlock* block, DVDCBCallback callback); -s32 DVDGetStreamPlayAddr(DVDCommandBlock* block); -int DVDGetStreamStartAddrAsync(DVDCommandBlock* block, DVDCBCallback callback); -s32 DVDGetStreamStartAddr(DVDCommandBlock* block); -int DVDGetStreamLengthAsync(DVDCommandBlock* block, DVDCBCallback callback); -s32 DVDGetStreamLength(DVDCommandBlock* block); -int DVDChangeDiskAsyncForBS(DVDCommandBlock* block, DVDCBCallback callback); -int DVDChangeDiskAsync(DVDCommandBlock* block, DVDDiskID* id, DVDCBCallback callback); -s32 DVDChangeDisk(DVDCommandBlock* block, DVDDiskID* id); -int DVDStopMotorAsync(DVDCommandBlock* block, DVDCBCallback callback); -s32 DVDStopMotor(DVDCommandBlock* block); -int DVDInquiryAsync(DVDCommandBlock* block, DVDDriveInfo* info, DVDCBCallback callback); -s32 DVDInquiry(DVDCommandBlock* block, DVDDriveInfo* info); -void DVDReset(void); -int DVDResetRequired(void); -s32 DVDGetCommandBlockStatus(const DVDCommandBlock* block); -s32 DVDGetDriveStatus(void); -BOOL DVDSetAutoInvalidation(BOOL autoInval); -void DVDPause(void); -void DVDResume(void); -int DVDCancelAsync(DVDCommandBlock* block, DVDCBCallback callback); -s32 DVDCancel(volatile DVDCommandBlock* block); -int DVDCancelAllAsync(DVDCBCallback callback); -s32 DVDCancelAll(void); -DVDDiskID* DVDGetCurrentDiskID(void); -BOOL DVDCheckDisk(void); - -// DVD FATAL -int DVDSetAutoFatalMessaging(BOOL enable); - -// DVD FS -s32 DVDConvertPathToEntrynum(const char* pathPtr); -BOOL DVDFastOpen(s32 entrynum, DVDFileInfo* fileInfo); -BOOL DVDOpen(const char* fileName, DVDFileInfo* fileInfo); -BOOL DVDClose(DVDFileInfo* fileInfo); -BOOL DVDGetCurrentDir(char* path, u32 maxlen); -BOOL DVDChangeDir(const char* dirName); -BOOL DVDReadAsyncPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset, - DVDCallback callback, s32 prio); -s32 DVDReadPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset, s32 prio); -int DVDSeekAsyncPrio(DVDFileInfo* fileInfo, s32 offset, void (* callback)(s32, DVDFileInfo *), s32 prio); -s32 DVDSeekPrio(DVDFileInfo* fileInfo, s32 offset, s32 prio); -s32 DVDGetFileInfoStatus(const DVDFileInfo* fileInfo); -BOOL DVDFastOpenDir(s32 entrynum, DVDDir* dir); -int DVDOpenDir(const char* dirName, DVDDir* dir); -int DVDReadDir(DVDDir* dir, DVDDirEntry* dirent); -int DVDCloseDir(DVDDir* dir); -void DVDRewindDir(DVDDir* dir); -void* DVDGetFSTLocation(void); -const u8* DVDGetDOLLocation(s32* out_size); -BOOL DVDPrepareStreamAsync(DVDFileInfo* fileInfo, u32 length, u32 offset, DVDCallback callback); -s32 DVDPrepareStream(DVDFileInfo* fileInfo, u32 length, u32 offset); -s32 DVDGetTransferredSize(DVDFileInfo* fileinfo); - -#define DVDReadAsync(fileInfo, addr, length, offset, callback) \ - DVDReadAsyncPrio((fileInfo), (addr), (length), (offset), (callback), 2) - -// DVD ID UTILS -int DVDCompareDiskID(const DVDDiskID* id1, const DVDDiskID* id2); -DVDDiskID* DVDGenerateDiskID(DVDDiskID* id, const char* game, const char* company, u8 diskNum, u8 version); - -// DVD LOW -BOOL DVDLowRead(void* addr, u32 length, u32 offset, DVDLowCallback callback); -BOOL DVDLowSeek(u32 offset, DVDLowCallback callback); -BOOL DVDLowWaitCoverClose(DVDLowCallback callback); -BOOL DVDLowReadDiskID(DVDDiskID* diskID, DVDLowCallback callback); -BOOL DVDLowStopMotor(DVDLowCallback callback); -BOOL DVDLowRequestError(DVDLowCallback callback); -BOOL DVDLowInquiry(DVDDriveInfo* info, DVDLowCallback callback); -BOOL DVDLowAudioStream(u32 subcmd, u32 length, u32 offset, DVDLowCallback callback); -BOOL DVDLowRequestAudioStatus(u32 subcmd, DVDLowCallback callback); -BOOL DVDLowAudioBufferConfig(BOOL enable, u32 size, DVDLowCallback callback); -void DVDLowReset(void); -DVDLowCallback DVDLowSetResetCoverCallback(DVDLowCallback callback); -BOOL DVDLowBreak(void); -DVDLowCallback DVDLowClearCallback(void); -u32 DVDLowGetCoverStatus(void); - -// DVD QUEUE -void DVDDumpWaitingQueue(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/exi.h b/aurora-main/include/dolphin/exi.h deleted file mode 100644 index f094c36..0000000 --- a/aurora-main/include/dolphin/exi.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef _DOLPHIN_EXI_H_ -#define _DOLPHIN_EXI_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define EXI_MEMORY_CARD_59 0x00000004 -#define EXI_MEMORY_CARD_123 0x00000008 -#define EXI_MEMORY_CARD_251 0x00000010 -#define EXI_MEMORY_CARD_507 0x00000020 - -#define EXI_MEMORY_CARD_1019 0x00000040 -#define EXI_MEMORY_CARD_2043 0x00000080 - -#define EXI_MEMORY_CARD_1019A 0x00000140 -#define EXI_MEMORY_CARD_1019B 0x00000240 -#define EXI_MEMORY_CARD_1019C 0x00000340 -#define EXI_MEMORY_CARD_1019D 0x00000440 -#define EXI_MEMORY_CARD_1019E 0x00000540 -#define EXI_MEMORY_CARD_1019F 0x00000640 -#define EXI_MEMORY_CARD_1019G 0x00000740 - -#define EXI_MEMORY_CARD_2043A 0x00000180 -#define EXI_MEMORY_CARD_2043B 0x00000280 -#define EXI_MEMORY_CARD_2043C 0x00000380 -#define EXI_MEMORY_CARD_2043D 0x00000480 -#define EXI_MEMORY_CARD_2043E 0x00000580 -#define EXI_MEMORY_CARD_2043F 0x00000680 -#define EXI_MEMORY_CARD_2043G 0x00000780 - -#define EXI_USB_ADAPTER 0x01010000 -#define EXI_NPDP_GDEV 0x01020000 - -#define EXI_MODEM 0x02020000 -#define EXI_ETHER 0x04020200 -#define EXI_MIC 0x04060000 -#define EXI_AD16 0x04120000 -#define EXI_RS232C 0x04040404 -#define EXI_ETHER_VIEWER 0x04220001 -#define EXI_STREAM_HANGER 0x04130000 - -#define EXI_MARLIN 0x03010000 - -#define EXI_IS_VIEWER 0x05070000 - -#define EXI_READ 0 -#define EXI_WRITE 1 - -#define EXI_FREQ_1M 0 -#define EXI_FREQ_2M 1 -#define EXI_FREQ_4M 2 -#define EXI_FREQ_8M 3 -#define EXI_FREQ_16M 4 -#define EXI_FREQ_32M 5 - -typedef void (*EXICallback)(s32 chan, OSContext* context); -typedef struct EXIControl { - EXICallback exiCallback; - EXICallback tcCallback; - EXICallback extCallback; - volatile u32 state; - int immLen; - u8* immBuf; - u32 dev; - u32 id; - s32 idTime; - int items; - struct { - u32 dev; - EXICallback callback; - } queue[3]; -} EXIControl; - -EXICallback EXISetExiCallback(s32 channel, EXICallback callback); - -void EXIInit(void); -BOOL EXILock(s32 channel, u32 device, EXICallback callback); -BOOL EXIUnlock(s32 channel); -BOOL EXISelect(s32 channel, u32 device, u32 frequency); -BOOL EXIDeselect(s32 channel); -BOOL EXIImm(s32 channel, void* buffer, s32 length, u32 type, EXICallback callback); -BOOL EXIImmEx(s32 channel, void* buffer, s32 length, u32 type); -BOOL EXIDma(s32 channel, void* buffer, s32 length, u32 type, EXICallback callback); -BOOL EXISync(s32 channel); -BOOL EXIProbe(s32 channel); -s32 EXIProbeEx(s32 channel); -BOOL EXIAttach(s32 channel, EXICallback callback); -BOOL EXIDetach(s32 channel); -u32 EXIGetState(s32 channel); -s32 EXIGetID(s32 channel, u32 device, u32* id); -void EXIProbeReset(void); -int EXISelectSD(s32 chan, u32 dev, u32 freq); -s32 EXIGetType(s32 chan, u32 dev, u32* type); -char* EXIGetTypeString(u32 type); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gd.h b/aurora-main/include/dolphin/gd.h deleted file mode 100644 index d4fabfd..0000000 --- a/aurora-main/include/dolphin/gd.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _DOLPHIN_GD_H_ -#define _DOLPHIN_GD_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif diff --git a/aurora-main/include/dolphin/gd/GDAurora.h b/aurora-main/include/dolphin/gd/GDAurora.h deleted file mode 100644 index f898ece..0000000 --- a/aurora-main/include/dolphin/gd/GDAurora.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef DOLPHIN_GDAURORA_H -#define DOLPHIN_GDAURORA_H - -/** - * Pushes a debug group to the backend graphics API. These may show in debugging tools such as RenderDoc. - * - * It is considered an error to have unpopped debug groups at the end of the frame. They will be automatically cleared. - * Debug groups are *not* automatically scoped to a display list. - */ -void GDPushDebugGroup(const char* label); - -/** - * Pop a debug group previously pushed via GXPushDebugGroup(). - */ -void GDPopDebugGroup(); - -/** - * Sends a debug marker to the backend graphics API. These may show in debugging tools such as RenderDoc. - */ -void GDInsertDebugMarker(const char* label); - -#endif // DOLPHIN_GDAURORA_H diff --git a/aurora-main/include/dolphin/gd/GDBase.h b/aurora-main/include/dolphin/gd/GDBase.h deleted file mode 100644 index 1c88333..0000000 --- a/aurora-main/include/dolphin/gd/GDBase.h +++ /dev/null @@ -1,177 +0,0 @@ -#ifndef _DOLPHIN_GD_BASE_H -#define _DOLPHIN_GD_BASE_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*GDOverflowCb)(void); - -typedef struct _GDLObj { - u8* start; - u32 length; - u8* ptr; - u8* top; -} GDLObj; - -extern GDLObj* __GDCurrentDL; - -void GDInitGDLObj(GDLObj* dl, void* start, u32 length); -void GDFlushCurrToMem(void); -void GDPadCurr32(void); -void GDOverflowed(void); -void GDSetOverflowCallback(GDOverflowCb callback); -GDOverflowCb GDGetOverflowCallback(void); - -inline static void GDOverflowCheck(u32 size) { - if (__GDCurrentDL->ptr + size > __GDCurrentDL->top) { - GDOverflowed(); - } -} - -inline static void __GDWrite(u8 data) { - *__GDCurrentDL->ptr++ = data; -} - -inline static void GDWrite_data(const void* data, u32 length) { - GDOverflowCheck(length); - // The compiler realizes this is memcpy, trust. - const u8* dataPtr = static_cast(data); - for (u32 i = 0; i < length; i++) { - __GDWrite(dataPtr[i]); - } -} - -inline static void GDWrite_u8(u8 data) { - GDOverflowCheck(sizeof(u8)); - __GDWrite(data); -} - -inline static void GDWrite_u16(u16 data) { - GDOverflowCheck(sizeof(u16)); - __GDWrite((u8)((data >> 8))); - __GDWrite((u8)((data >> 0) & 0xFF)); -} - -inline static void GDWrite_u24(u32 data) { - GDOverflowCheck(3); - __GDWrite((u8)((data >> 16) & 0xFF)); - __GDWrite((u8)((data >> 8) & 0xFF)); - __GDWrite((u8)((data >> 0) & 0xFF)); -} - -inline static void GDWrite_u32(u32 data) { - GDOverflowCheck(sizeof(u32)); - __GDWrite((u8)((data >> 24) & 0xFF)); - __GDWrite((u8)((data >> 16) & 0xFF)); - __GDWrite((u8)((data >> 8) & 0xFF)); - __GDWrite((u8)((data >> 0) & 0xFF)); -} - -inline static void GDWrite_u64(u64 data) { - GDOverflowCheck(sizeof(u64)); - __GDWrite((u8)((data >> 56) & 0xFF)); - __GDWrite((u8)((data >> 48) & 0xFF)); - __GDWrite((u8)((data >> 40) & 0xFF)); - __GDWrite((u8)((data >> 32) & 0xFF)); - __GDWrite((u8)((data >> 24) & 0xFF)); - __GDWrite((u8)((data >> 16) & 0xFF)); - __GDWrite((u8)((data >> 8) & 0xFF)); - __GDWrite((u8)((data >> 0) & 0xFF)); -} - -inline static void GDWrite_f32(f32 data) { - union { - f32 f; - u32 u; - } fid; - fid.f = data; - GDWrite_u32(fid.u); -} - -inline static void GDWriteXFCmdHdr(u16 addr, u8 len) { - GDWrite_u8(GX_LOAD_XF_REG); - GDWrite_u16(len - 1); - GDWrite_u16(addr); -} - -inline static void GDWriteXFCmd(u16 addr, u32 val) { - GDWrite_u8(GX_LOAD_XF_REG); - GDWrite_u16(0); - GDWrite_u16(addr); - GDWrite_u32(val); -} - -inline static void GDWriteXFIndxDCmd(u16 addr, u8 len, u16 index) { - GDWrite_u8(GX_LOAD_INDX_D); - GDWrite_u16(index); - GDWrite_u16((len - 1) << 12 | addr); -} - -inline static void GDWriteXFIndxACmd(u16 addr, u8 len, u16 index) { - GDWrite_u8(GX_LOAD_INDX_A); - GDWrite_u16(index); - GDWrite_u16(((len - 1) << 12) | addr); -} - -inline static void GDWriteXFIndxBCmd(u16 addr, u8 len, u16 index) { - GDWrite_u8(GX_LOAD_INDX_B); - GDWrite_u16(index); - GDWrite_u16(((len - 1) << 12) | addr); -} - -inline static void GDWriteXFIndxCCmd(u16 addr, u8 len, u16 index) { - GDWrite_u8(GX_LOAD_INDX_C); - GDWrite_u16(index); - GDWrite_u16(((len - 1) << 12) | addr); -} - -inline static void GDWriteCPCmd(u8 addr, u32 val) { - GDWrite_u8(GX_LOAD_CP_REG); - GDWrite_u8(addr); - GDWrite_u32(val); -} - -inline static void GDWriteBPCmd(u32 regval) { - GDWrite_u8(GX_LOAD_BP_REG); - GDWrite_u32(regval); -} - -inline static void GDWriteAuroraCmd(u16 subCommand) { - GDWrite_u8(GX_LOAD_AURORA); - GDWrite_u16(subCommand); -} - -inline static void GDSetCurrent(GDLObj* dl) { - __GDCurrentDL = dl; -} - -static inline u32 GDGetCurrOffset(void) { - return (u32)(__GDCurrentDL->ptr - __GDCurrentDL->start); -} - -static inline void GDSetCurrOffset(u32 offset) { - __GDCurrentDL->ptr = __GDCurrentDL->start + offset; -} - -static inline void* GDGetCurrPointer(void) { - return (void*)__GDCurrentDL->ptr; -} - -static inline u8* GDGetCurrPointer2(void) { - return __GDCurrentDL->ptr; -} - -static inline u32 GDGetGDLObjOffset(const GDLObj* dl) { - return (u32)(dl->ptr - dl->start); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gd/GDFile.h b/aurora-main/include/dolphin/gd/GDFile.h deleted file mode 100644 index 3589fbb..0000000 --- a/aurora-main/include/dolphin/gd/GDFile.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef _DOLPHIN_GD_FILE_H -#define _DOLPHIN_GD_FILE_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define GD_FILE_VERSION_NUMBER 0x11223344 - -typedef struct _GDGList { - void* ptr; - u32 byteLength; -} GDGList; - -typedef struct _GDFileHeader { - u32 versionNumber; - u32 numDLs; - u32 numPLs; - GDGList* DLDescArray; - GDGList* PLDescArray; -} GDFileHeader; - -s32 GDReadDLFile(const char* fName, u32* numDLs, u32* numPLs, GDGList** DLDescArray, GDGList** PLDescArray); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gd/GDGeometry.h b/aurora-main/include/dolphin/gd/GDGeometry.h deleted file mode 100644 index ef80885..0000000 --- a/aurora-main/include/dolphin/gd/GDGeometry.h +++ /dev/null @@ -1,525 +0,0 @@ -#ifndef _DOLPHIN_GD_GEOMETRY_H_ -#define _DOLPHIN_GD_GEOMETRY_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// Command processor register IDs -#define CP_REG_MTXIDXA_ID 0x30 // Matrix index A -#define CP_REG_MTXIDXB_ID 0x40 // Matrix index B -#define CP_REG_VCD_LO_ID 0x50 // Vertex descriptor (lo) -#define CP_REG_VCD_HI_ID 0x60 // Vertex descriptor (hi) -#define CP_REG_VAT_GRP0_ID 0x70 // Vertex attribute table (group 0) -#define CP_REG_VAT_GRP1_ID 0x80 // Vertex attribute table (group 1) -#define CP_REG_VAT_GRP2_ID 0x90 // Vertex attribute table (group 2) -#define CP_REG_ARRAYBASE_ID 0xA0 // Vertex array start/base -#define CP_REG_ARRAYSTRIDE_ID 0xB0 // Vertex array stride - -// XF locators for textures -// Projection type [30-30] -#define GX_XF_TEX_PROJTYPE_ST 30 -#define GX_XF_TEX_PROJTYPE_END 30 - -// Input format [29-29] -#define GX_XF_TEX_INPUTFORM_ST 29 -#define GX_XF_TEX_INPUTFORM_END 29 - -// Texture gen type [25-27] -#define GX_XF_TEX_TEXGENTYPE_ST 25 -#define GX_XF_TEX_TEXGENTYPE_END 27 - -// Source row [20-24] -#define GX_XF_TEX_SRCROW_ST 20 -#define GX_XF_TEX_SRCROW_END 24 - -// Bump source texture [17-19] -#define GX_XF_TEX_BUMPSRCTEX_ST 17 -#define GX_XF_TEX_BUMPSRCTEX_END 19 - -// Bump source light [14-16] -#define GX_XF_TEX_BUMPSRCLIGHT_ST 14 -#define GX_XF_TEX_BUMPSRCLIGHT_END 16 - -// Blitting processor registers. -#define GX_BP_REG_GENMODE 0x0 // gen mode - -// display copy filters -#define GX_BP_REG_DISPCOPYFILTER0 0x1 // display copy filter 0 -#define GX_BP_REG_DISPCOPYFILTER1 0x2 // display copy filter 1 -#define GX_BP_REG_DISPCOPYFILTER2 0x3 // display copy filter 2 -#define GX_BP_REG_DISPCOPYFILTER3 0x4 // display copy filter 3 - -// indirect matrices -#define GX_BP_REG_INDMTX0A 0x6 // indirect matrix 0A -#define GX_BP_REG_INDMTX0B 0x7 // indirect matrix 0B -#define GX_BP_REG_INDMTX0C 0x8 // indirect matrix 0C -#define GX_BP_REG_INDMTX1A 0x9 // indirect matrix 1A -#define GX_BP_REG_INDMTX1B 0xA // indirect matrix 1B -#define GX_BP_REG_INDMTX1C 0xB // indirect matrix 1C -#define GX_BP_REG_INDMTX2A 0xC // indirect matrix 2A -#define GX_BP_REG_INDMTX2B 0xD // indirect matrix 2B -#define GX_BP_REG_INDMTX2C 0xE // indirect matrix 2C -#define GX_BP_REG_INDIMASK 0xF // indirect mask - -// indirect TEV stages -#define GX_BP_REG_INDTEVSTAGE0 0x10 // indirect TEV stage 0 -#define GX_BP_REG_INDTEVSTAGE1 0x11 // indirect TEV stage 1 -#define GX_BP_REG_INDTEVSTAGE2 0x12 // indirect TEV stage 2 -#define GX_BP_REG_INDTEVSTAGE3 0x13 // indirect TEV stage 3 -#define GX_BP_REG_INDTEVSTAGE4 0x14 // indirect TEV stage 4 -#define GX_BP_REG_INDTEVSTAGE5 0x15 // indirect TEV stage 5 -#define GX_BP_REG_INDTEVSTAGE6 0x16 // indirect TEV stage 6 -#define GX_BP_REG_INDTEVSTAGE7 0x17 // indirect TEV stage 7 -#define GX_BP_REG_INDTEVSTAGE8 0x18 // indirect TEV stage 8 -#define GX_BP_REG_INDTEVSTAGE9 0x19 // indirect TEV stage 9 -#define GX_BP_REG_INDTEVSTAGE10 0x1A // indirect TEV stage 10 -#define GX_BP_REG_INDTEVSTAGE11 0x1B // indirect TEV stage 11 -#define GX_BP_REG_INDTEVSTAGE12 0x1C // indirect TEV stage 12 -#define GX_BP_REG_INDTEVSTAGE13 0x1D // indirect TEV stage 13 -#define GX_BP_REG_INDTEVSTAGE14 0x1E // indirect TEV stage 14 -#define GX_BP_REG_INDTEVSTAGE15 0x1F // indirect TEV stage 15 - -// performance manips -#define GX_BP_REG_SCISSORTL 0x20 // scissor top left -#define GX_BP_REG_SCISSORBR 0x21 // scissor bottom right -#define GX_BP_REG_LINEPTWIDTH 0x22 // line point width -#define GX_BP_REG_PERF0TRI 0x23 // performance 0 (triangle) -#define GX_BP_REG_PERF0QUAD 0x24 // performance 0 (quad) - -// rasters -#define GX_BP_REG_RAS1_SS0 0x25 -#define GX_BP_REG_RAS1_SS1 0x26 -#define GX_BP_REG_RAS1_IREF 0x27 -#define GX_BP_REG_RAS1_TREF0 0x28 -#define GX_BP_REG_RAS1_TREF1 0x29 -#define GX_BP_REG_RAS1_TREF2 0x2A -#define GX_BP_REG_RAS1_TREF3 0x2B -#define GX_BP_REG_RAS1_TREF4 0x2C -#define GX_BP_REG_RAS1_TREF5 0x2D -#define GX_BP_REG_RAS1_TREF6 0x2E -#define GX_BP_REG_RAS1_TREF7 0x2F - -// setup sizes -#define GX_BP_REG_SU_SSIZE0 0x30 -#define GX_BP_REG_SU_TSIZE0 0x31 -#define GX_BP_REG_SU_SSIZE1 0x32 -#define GX_BP_REG_SU_TSIZE1 0x33 -#define GX_BP_REG_SU_SSIZE2 0x34 -#define GX_BP_REG_SU_TSIZE2 0x35 -#define GX_BP_REG_SU_SSIZE3 0x36 -#define GX_BP_REG_SU_TSIZE3 0x37 -#define GX_BP_REG_SU_SSIZE4 0x38 -#define GX_BP_REG_SU_TSIZE4 0x39 -#define GX_BP_REG_SU_SSIZE5 0x3A -#define GX_BP_REG_SU_TSIZE5 0x3B -#define GX_BP_REG_SU_SSIZE6 0x3C -#define GX_BP_REG_SU_TSIZE6 0x3D -#define GX_BP_REG_SU_SSIZE7 0x3E -#define GX_BP_REG_SU_TSIZE7 0x3F - -// Z and blend controls -#define GX_BP_REG_ZMODE 0x40 -#define GX_BP_REG_BLENDMODE 0x41 -#define GX_BP_REG_DSTALPHA 0x42 -#define GX_BP_REG_ZCONTROL 0x43 -#define GX_BP_REG_FIELDMASK 0x44 -#define GX_BP_REG_DRAWDONE 0x45 -#define GX_BP_REG_PETOKEN 0x47 -#define GX_BP_REG_PETOKENINT 0x48 - -// copying -#define GX_BP_REG_TEXCOPYSRCXY 0x49 -#define GX_BP_REG_TEXCOPYSRCWH 0x4A -#define GX_BP_REG_TEXCOPYDST 0x4B -#define GX_BP_REG_DISPCOPYSTRIDE 0x4D -#define GX_BP_REG_DISPCOPYSCALEY 0x4E -#define GX_BP_REG_COPYCLEARAR 0x4F -#define GX_BP_REG_COPYCLEARGB 0x50 -#define GX_BP_REG_COPYCLEARZ 0x51 -#define GX_BP_REG_COPYFILTER0 0x53 -#define GX_BP_REG_COPYFILTER1 0x54 - -// -#define GX_BP_REG_BOUNDINGBOX0 0x55 -#define GX_BP_REG_BOUNDINGBOX1 0x56 - -#define GX_BP_REG_SCISSOROFFSET 0x59 - -// texture memory -#define GX_BP_REG_TMEMPRELOADADDR 0x60 -#define GX_BP_REG_TMEMPRELOADEVEN 0x61 -#define GX_BP_REG_TMEMPRELOADODD 0x62 -#define GX_BP_REG_TMEMPRELOADMODE 0x63 -#define GX_BP_REG_TMEMTLUTSRC 0x64 -#define GX_BP_REG_TMEMTLUTDST 0x65 -#define GX_BP_REG_TMEMTEXINVALIDATE 0x66 - -// performance 1 -#define GX_BP_REG_PERF1 0x67 -#define GX_BP_REG_FIELDMODE 0x68 - -// set modes -#define GX_BP_REG_SETMODE0_TEX0 0x80 -#define GX_BP_REG_SETMODE0_TEX1 0x81 -#define GX_BP_REG_SETMODE0_TEX2 0x82 -#define GX_BP_REG_SETMODE0_TEX3 0x83 -#define GX_BP_REG_SETMODE1_TEX0 0x84 -#define GX_BP_REG_SETMODE1_TEX1 0x85 -#define GX_BP_REG_SETMODE1_TEX2 0x86 -#define GX_BP_REG_SETMODE1_TEX3 0x87 - -// set images -#define GX_BP_REG_SETIMAGE0_TEX0 0x88 -#define GX_BP_REG_SETIMAGE0_TEX1 0x89 -#define GX_BP_REG_SETIMAGE0_TEX2 0x8A -#define GX_BP_REG_SETIMAGE0_TEX3 0x8B -#define GX_BP_REG_SETIMAGE1_TEX0 0x8C -#define GX_BP_REG_SETIMAGE1_TEX1 0x8D -#define GX_BP_REG_SETIMAGE1_TEX2 0x8E -#define GX_BP_REG_SETIMAGE1_TEX3 0x8F -#define GX_BP_REG_SETIMAGE2_TEX0 0x90 -#define GX_BP_REG_SETIMAGE2_TEX1 0x91 -#define GX_BP_REG_SETIMAGE2_TEX2 0x92 -#define GX_BP_REG_SETIMAGE2_TEX3 0x93 -#define GX_BP_REG_SETIMAGE3_TEX0 0x94 -#define GX_BP_REG_SETIMAGE3_TEX1 0x95 -#define GX_BP_REG_SETIMAGE3_TEX2 0x96 -#define GX_BP_REG_SETIMAGE3_TEX3 0x97 - -// set texture lookups -#define GX_BP_REG_SETTLUT_TEX0 0x98 -#define GX_BP_REG_SETTLUT_TEX1 0x99 -#define GX_BP_REG_SETTLUT_TEX2 0x9A -#define GX_BP_REG_SETTLUT_TEX3 0x9B - -// set modes continued -#define GX_BP_REG_SETMODE0_TEX4 0xA0 -#define GX_BP_REG_SETMODE0_TEX5 0xA1 -#define GX_BP_REG_SETMODE0_TEX6 0xA2 -#define GX_BP_REG_SETMODE0_TEX7 0xA3 -#define GX_BP_REG_SETMODE1_TEX4 0xA4 -#define GX_BP_REG_SETMODE1_TEX5 0xA5 -#define GX_BP_REG_SETMODE1_TEX6 0xA6 -#define GX_BP_REG_SETMODE1_TEX7 0xA7 - -// set images continued -#define GX_BP_REG_SETIMAGE0_TEX4 0xA8 -#define GX_BP_REG_SETIMAGE0_TEX5 0xA9 -#define GX_BP_REG_SETIMAGE0_TEX6 0xAA -#define GX_BP_REG_SETIMAGE0_TEX7 0xAB -#define GX_BP_REG_SETIMAGE1_TEX4 0xAC -#define GX_BP_REG_SETIMAGE1_TEX5 0xAD -#define GX_BP_REG_SETIMAGE1_TEX6 0xAE -#define GX_BP_REG_SETIMAGE1_TEX7 0xAF -#define GX_BP_REG_SETIMAGE2_TEX4 0xB0 -#define GX_BP_REG_SETIMAGE2_TEX5 0xB1 -#define GX_BP_REG_SETIMAGE2_TEX6 0xB2 -#define GX_BP_REG_SETIMAGE2_TEX7 0xB3 -#define GX_BP_REG_SETIMAGE3_TEX4 0xB4 -#define GX_BP_REG_SETIMAGE3_TEX5 0xB5 -#define GX_BP_REG_SETIMAGE3_TEX6 0xB6 -#define GX_BP_REG_SETIMAGE3_TEX7 0xB7 - -// set texture lookups continued -#define GX_BP_REG_SETTLUT_TEX4 0xB8 -#define GX_BP_REG_SETTLUT_TEX5 0xB9 -#define GX_BP_REG_SETTLUT_TEX6 0xBA -#define GX_BP_REG_SETTLUT_TEX7 0xBB - -// TEV color manips -#define GX_BP_REG_TEVCOLORCOMBINER0 0xC0 -#define GX_BP_REG_TEVALPHACOMBINER0 0xC1 -#define GX_BP_REG_TEVCOLORCOMBINER1 0xC2 -#define GX_BP_REG_TEVALPHACOMBINER1 0xC3 -#define GX_BP_REG_TEVCOLORCOMBINER2 0xC4 -#define GX_BP_REG_TEVALPHACOMBINER2 0xC5 -#define GX_BP_REG_TEVCOLORCOMBINER3 0xC6 -#define GX_BP_REG_TEVALPHACOMBINER3 0xC7 -#define GX_BP_REG_TEVCOLORCOMBINER4 0xC8 -#define GX_BP_REG_TEVALPHACOMBINER4 0xC9 -#define GX_BP_REG_TEVCOLORCOMBINER5 0xCA -#define GX_BP_REG_TEVALPHACOMBINER5 0xCB -#define GX_BP_REG_TEVCOLORCOMBINER6 0xCC -#define GX_BP_REG_TEVALPHACOMBINER6 0xCD -#define GX_BP_REG_TEVCOLORCOMBINER7 0xCE -#define GX_BP_REG_TEVALPHACOMBINER7 0xCF -#define GX_BP_REG_TEVCOLORCOMBINER8 0xD0 -#define GX_BP_REG_TEVALPHACOMBINER8 0xD1 -#define GX_BP_REG_TEVCOLORCOMBINER9 0xD2 -#define GX_BP_REG_TEVALPHACOMBINER9 0xD3 -#define GX_BP_REG_TEVCOLORCOMBINER10 0xD4 -#define GX_BP_REG_TEVALPHACOMBINER10 0xD5 -#define GX_BP_REG_TEVCOLORCOMBINER11 0xD6 -#define GX_BP_REG_TEVALPHACOMBINER11 0xD7 -#define GX_BP_REG_TEVCOLORCOMBINER12 0xD8 -#define GX_BP_REG_TEVALPHACOMBINER12 0xD9 -#define GX_BP_REG_TEVCOLORCOMBINER13 0xDA -#define GX_BP_REG_TEVALPHACOMBINER13 0xDB -#define GX_BP_REG_TEVCOLORCOMBINER14 0xDC -#define GX_BP_REG_TEVALPHACOMBINER14 0xDD -#define GX_BP_REG_TEVCOLORCOMBINER15 0xDE -#define GX_BP_REG_TEVALPHACOMBINER15 0xDF - -// TEV registers -#define GX_BP_REG_TEVREG0LO 0xE0 -#define GX_BP_REG_TEVREG0HI 0xE1 -#define GX_BP_REG_TEVREG1LO 0xE2 -#define GX_BP_REG_TEVREG1HI 0xE3 -#define GX_BP_REG_TEVREG2LO 0xE4 -#define GX_BP_REG_TEVREG2HI 0xE5 -#define GX_BP_REG_TEVREG3LO 0xE6 -#define GX_BP_REG_TEVREG3HI 0xE7 - -// fog registers -#define GX_BP_REG_FOGRANGE 0xE8 -#define GX_BP_REG_FOGRANGEK0 0xE9 -#define GX_BP_REG_FOGRANGEK1 0xEA -#define GX_BP_REG_FOGRANGEK2 0xEB -#define GX_BP_REG_FOGRANGEK3 0xEC -#define GX_BP_REG_FOGRANGEK4 0xED -#define GX_BP_REG_FOGPARAM0 0xEE -#define GX_BP_REG_FOGPARAM1 0xEF -#define GX_BP_REG_FOGPARAM2 0xF0 -#define GX_BP_REG_FOGPARAM3 0xF1 -#define GX_BP_REG_FOGCOLOR 0xF2 - -// performance manip registers -#define GX_BP_REG_ALPHACOMPARE 0xF3 -#define GX_BP_REG_ZTEXTURE0 0xF4 -#define GX_BP_REG_ZTEXTURE1 0xF5 - -// TEV K selectors -#define GX_BP_REG_TEVKSEL0 0xF6 -#define GX_BP_REG_TEVKSEL1 0xF7 -#define GX_BP_REG_TEVKSEL2 0xF8 -#define GX_BP_REG_TEVKSEL3 0xF9 -#define GX_BP_REG_TEVKSEL4 0xFA -#define GX_BP_REG_TEVKSEL5 0xFB -#define GX_BP_REG_TEVKSEL6 0xFC -#define GX_BP_REG_TEVKSEL7 0xFD - -// SS mask -#define GX_BP_REG_SSMASK 0xFE - -// Transform Unit Registers -#define GX_XF_REG_ERROR 0x1000 -#define GX_XF_REG_DIAGNOSTICS 0x1001 -#define GX_XF_REG_STATE0 0x1002 -#define GX_XF_REG_STATE1 0x1003 -#define GX_XF_REG_CLOCK 0x1004 -#define GX_XF_REG_CLIPDISABLE 0x1005 -#define GX_XF_REG_PERF0 0x1006 -#define GX_XF_REG_PERF1 0x1007 -#define GX_XF_REG_INVERTEXSPEC 0x1008 -#define GX_XF_REG_NUMCOLORS 0x1009 -#define GX_XF_REG_AMBIENT0 0x100A -#define GX_XF_REG_AMBIENT1 0x100B -#define GX_XF_REG_MATERIAL0 0x100C -#define GX_XF_REG_MATERIAL1 0x100D -#define GX_XF_REG_COLOR0CNTRL 0x100E -#define GX_XF_REG_COLOR1CNTRL 0x100F -#define GX_XF_REG_ALPHA0CNTRL 0x1010 -#define GX_XF_REG_ALPHA1CNTRL 0x1011 -#define GX_XF_REG_DUALTEXTRAN 0x1012 -#define GX_XF_REG_MATRIXINDEX0 0x1018 -#define GX_XF_REG_MATRIXINDEX1 0x1019 -#define GX_XF_REG_SCALEX 0x101A -#define GX_XF_REG_SCALEY 0x101B -#define GX_XF_REG_SCALEZ 0x101C -#define GX_XF_REG_OFFSETX 0x101D -#define GX_XF_REG_OFFSETY 0x101E -#define GX_XF_REG_OFFSETZ 0x101F -#define GX_XF_REG_PROJECTIONA 0x1020 -#define GX_XF_REG_PROJECTIONB 0x1021 -#define GX_XF_REG_PROJECTIONC 0x1022 -#define GX_XF_REG_PROJECTIOND 0x1023 -#define GX_XF_REG_PROJECTIONE 0x1024 -#define GX_XF_REG_PROJECTIONF 0x1025 -#define GX_XF_REG_PROJECTORTHO 0x1026 -#define GX_XF_REG_NUMTEX 0x103F -#define GX_XF_REG_TEX0 0x1040 -#define GX_XF_REG_TEX1 0x1041 -#define GX_XF_REG_TEX2 0x1042 -#define GX_XF_REG_TEX3 0x1043 -#define GX_XF_REG_TEX4 0x1044 -#define GX_XF_REG_TEX5 0x1045 -#define GX_XF_REG_TEX6 0x1046 -#define GX_XF_REG_TEX7 0x1047 -#define GX_XF_REG_DUALTEX0 0x1050 -#define GX_XF_REG_DUALTEX1 0x1051 -#define GX_XF_REG_DUALTEX2 0x1052 -#define GX_XF_REG_DUALTEX3 0x1053 -#define GX_XF_REG_DUALTEX4 0x1054 -#define GX_XF_REG_DUALTEX5 0x1055 -#define GX_XF_REG_DUALTEX6 0x1056 -#define GX_XF_REG_DUALTEX7 0x1057 - -#define CP_REG_VCD_LO(pnMtxIdx, txMtxIdxMask, posn, norm, col0, col1) \ - ( \ - (pnMtxIdx) << 0 | \ - (txMtxIdxMask) << 1 | \ - (posn) << 9 | \ - (norm) << 11 | \ - (col0) << 13 | \ - (col1) << 15 \ - ) - -#define CP_REG_VCD_HI(tex0, tex1, tex2, tex3, tex4, tex5, tex6, tex7) \ - ( \ - (tex0) << 0 | \ - (tex1) << 2 | \ - (tex2) << 4 | \ - (tex3) << 6 | \ - (tex4) << 8 | \ - (tex5) << 10 | \ - (tex6) << 12 | \ - (tex7) << 14 \ - ) - -#define CP_REG_VAT_GRP0(posCnt, posType, posFrac, nrmCnt, nrmType, c0Cnt, c0Type, c1Cnt, c1Type, tx0Cnt, tx0Type, tx0Frac, p12, nrmIdx3) \ - ( \ - (posCnt) << 0 | \ - (posType) << 1 | \ - (posFrac) << 4 | \ - (nrmCnt) << 9 | \ - (nrmType) << 10 | \ - (c0Cnt) << 13 | \ - (c0Type) << 14 | \ - (c1Cnt) << 17 | \ - (c1Type) << 18 | \ - (tx0Cnt) << 21 | \ - (tx0Type) << 22 | \ - (tx0Frac) << 25 | \ - (p12) << 30 | \ - (nrmIdx3) << 31 \ - ) - -#define CP_REG_VAT_GRP1(tx1Cnt, tx1Type, tx1Frac, tx2Cnt, tx2Type, tx2Frac, tx3Cnt, tx3Type, tx3Frac, tx4Cnt, tx4Type, p11) \ - ( \ - (tx1Cnt) << 0 | \ - (tx1Type) << 1 | \ - (tx1Frac) << 4 | \ - (tx2Cnt) << 9 | \ - (tx2Type) << 10 | \ - (tx2Frac) << 13 | \ - (tx3Cnt) << 18 | \ - (tx3Type) << 19 | \ - (tx3Frac) << 22 | \ - (tx4Cnt) << 27 | \ - (tx4Type) << 28 | \ - p11 << 31 \ - ) - -#define CP_REG_VAT_GRP2(tx4Frac, tx5Cnt, tx5Type, tx5Frac, tx6Cnt, tx6Type, tx6Frac, tx7Cnt, tx7Type, tx7Frac) \ - ( \ - (tx4Frac) << 0 | \ - (tx5Cnt) << 5 | \ - (tx5Type) << 6 | \ - (tx5Frac) << 9 | \ - (tx6Cnt) << 14 | \ - (tx6Type) << 15 | \ - (tx6Frac) << 18 | \ - (tx7Cnt) << 23 | \ - (tx7Type) << 24 | \ - (tx7Frac) << 27 \ - ) - -// Transform unit register IDs -#define XF_REG_ERROR_ID 0x1000 -#define XF_REG_DIAGNOSTICS_ID 0x1001 -#define XF_REG_STATE0_ID 0x1002 -#define XF_REG_STATE1_ID 0x1003 -#define XF_REG_CLOCK_ID 0x1004 -#define XF_REG_CLIPDISABLE_ID 0x1005 -#define XF_REG_PERF0_ID 0x1006 -#define XF_REG_PERF1_ID 0x1007 -#define XF_REG_INVERTEXSPEC_ID 0x1008 -#define XF_REG_NUMCOLORS_ID 0x1009 -#define XF_REG_DUALTEXTRAN_ID 0x1012 -#define XF_REG_SCALEX_ID 0x101A -#define XF_REG_SCALEY_ID 0x101B -#define XF_REG_SCALEZ_ID 0x101C -#define XF_REG_OFFSETX_ID 0x101D -#define XF_REG_OFFSETY_ID 0x101E -#define XF_REG_OFFSETZ_ID 0x101F -#define XF_REG_NUMTEX_ID 0x103F -#define XF_REG_TEX0_ID 0x1040 -#define XF_REG_TEX1_ID 0x1041 -#define XF_REG_TEX2_ID 0x1042 -#define XF_REG_TEX3_ID 0x1043 -#define XF_REG_TEX4_ID 0x1044 -#define XF_REG_TEX5_ID 0x1045 -#define XF_REG_TEX6_ID 0x1046 -#define XF_REG_TEX7_ID 0x1047 -#define XF_REG_DUALTEX0_ID 0x1050 -#define XF_REG_DUALTEX1_ID 0x1051 -#define XF_REG_DUALTEX2_ID 0x1052 -#define XF_REG_DUALTEX3_ID 0x1053 -#define XF_REG_DUALTEX4_ID 0x1054 -#define XF_REG_DUALTEX5_ID 0x1055 -#define XF_REG_DUALTEX6_ID 0x1056 -#define XF_REG_DUALTEX7_ID 0x1057 - -#define XF_REG_INVTXSPEC(ncols, nnorms, ntexs) \ - ( \ - (ncols) << 0 | \ - (nnorms) << 2 | \ - (ntexs) << 4 \ - ) - -#define XF_REG_TEX(proj, form, tgType, row, embossRow, embossLit) \ - ( \ - (proj) << 1 | \ - (form) << 2 | \ - (tgType) << 4 | \ - (row) << 7 | \ - (embossRow) << 12 | \ - (embossLit) << 15 \ - ) - -#define XF_REG_DUALTEX(mtx, normalize) \ - ( \ - (mtx) << 0 | \ - (normalize) << 8 \ - ) - -#define BP_GEN_MODE(nTexGens, nChans, nTevs, p4, nInds) \ - ( \ - (u32)(nTexGens) << 0 | \ - (u32)(nChans) << 4 | \ - (u32)(nTevs) << 10 | \ - (u32)(p4) << 14 | \ - (u32)(nInds) << 16 \ - ) - -#define BP_LP_SIZE(lineWidth, pointSize, lineOffset, pointOffset, lineHalfAspect, p5) \ - ( \ - (u32)(lineWidth) << 0 | \ - (u32)(pointSize) << 8 | \ - (u32)(lineOffset) << 16 | \ - (u32)(pointOffset) << 19 | \ - (u32)(lineHalfAspect) << 22 | \ - (u32)(p5) << 24 \ - ) - -void GDSetVtxDescv(const GXVtxDescList* attrPtr); -void GDSetVtxAttrFmtv(GXVtxFmt vtxfmt, const GXVtxAttrFmtList* list); -void GDSetArraySized(GXAttr attr, void* base_ptr, u32 size, u8 stride, bool le); -void GDSetArray(GXAttr attr, void* base_ptr, u8 stride); -void GDSetArrayRaw(GXAttr attr, u32 base_ptr_raw, u8 stride); -void GDPatchArrayPtr(void* base_ptr); -void GDSetTexCoordGen(GXTexCoordID dst_coord, GXTexGenType func, GXTexGenSrc src_param, u8 normalize, u32 postmtx); -void GDSetCullMode(GXCullMode mode); -void GDSetGenMode(u8 nTexGens, u8 nChans, u8 nTevs); -void GDSetGenMode2(u8 nTexGens, u8 nChans, u8 nTevs, u8 nInds, GXCullMode cm); -void GDSetLPSize(u8 lineWidth, u8 pointSize, GXTexOffset lineOffset, GXTexOffset pointOffset, u8 lineHalfAspect); -void GDSetCoPlanar(u8 enable); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gd/GDIndirect.h b/aurora-main/include/dolphin/gd/GDIndirect.h deleted file mode 100644 index 4ca854c..0000000 --- a/aurora-main/include/dolphin/gd/GDIndirect.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef _DOLPHIN_GD_INDIRECT_H_ -#define _DOLPHIN_GD_INDIRECT_H_ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define BP_TEV_INDIRECT(ind_stage, format, bias_sel, alpha_sel, mtx_sel, wrap_s, wrap_t, utc_lod, add_prev, id) \ - ( \ - (u32)(ind_stage) << 0 | \ - (u32)(format) << 2 | \ - (u32)(bias_sel) << 4 | \ - (u32)(alpha_sel) << 7 | \ - (u32)(mtx_sel) << 9 | \ - (u32)(wrap_s) << 13 | \ - (u32)(wrap_t) << 16 | \ - (u32)(utc_lod) << 19 | \ - (u32)(add_prev) << 20 | \ - (u32)(id) << 24 \ - ) - -#define BP_IND_MTX(m0, m1, scale_exp, id) \ - ( \ - (u32)(m0) << 0 | \ - (u32)(m1) << 11 | \ - (u32)(scale_exp) << 22 | \ - (u32)(id) << 24 \ - ) - -#define BP_IND_TEXCOORD_SCALE(scaleS0, scaleT0, scaleS1, scaleT1, id) \ - ( \ - (u32)(scaleS0) << 0 | \ - (u32)(scaleT0) << 4 | \ - (u32)(scaleS1) << 8 | \ - (u32)(scaleT1) << 12 | \ - (u32)(id) << 24 \ - ) - -#define BP_IND_TEX_ORDER(map0, coord0, map1, coord1, map2, coord2, map3, coord3, id) \ - ( \ - (u32)(map0) << 0 | \ - (u32)(coord0) << 3 | \ - (u32)(map1) << 6 | \ - (u32)(coord1) << 9 | \ - (u32)(map2) << 12 | \ - (u32)(coord2) << 15 | \ - (u32)(map3) << 18 | \ - (u32)(coord3) << 21 | \ - (u32)(id) << 24 \ - ) - -#define BP_IND_MASK(mask, id) \ - ( \ - (u32)(mask) << 0 | \ - (u32)(id) << 24 \ - ) - -void GDSetTevIndirect(GXTevStageID tev_stage, GXIndTexStageID ind_stage, - GXIndTexFormat format, GXIndTexBiasSel bias_sel, - GXIndTexMtxID matrix_sel, GXIndTexWrap wrap_s, - GXIndTexWrap wrap_t, u8 add_prev, u8 utc_lod, - GXIndTexAlphaSel alpha_sel); -void GDSetIndTexMtx(GXIndTexMtxID mtx_id, const f32 offset[2][3], s8 scale_exp); -void GDSetIndTexCoordScale(GXIndTexStageID indStageEven, GXIndTexScale scaleS0, - GXIndTexScale scaleT0, GXIndTexScale scaleS1, - GXIndTexScale scaleT1); -void GDSetIndTexOrder(GXTexCoordID texCoord0, GXTexMapID texMap0, - GXTexCoordID texCoord1, GXTexMapID texMap1, - GXTexCoordID texCoord2, GXTexMapID texMap2, - GXTexCoordID texCoord3, GXTexMapID texMap3); -void GDSetTevDirect(GXTevStageID tev_stage); -void GDSetTevIndWarp(GXTevStageID tev_stage, GXIndTexStageID ind_stage, u8 signed_offset, u8 replace_mode, GXIndTexMtxID matrix_sel); -void GDSetTevIndTile(GXTevStageID tev_stage, GXIndTexStageID ind_stage, - u16 tilesize_s, u16 tilesize_t, u16 tilespacing_s, - u16 tilespacing_t, GXIndTexFormat format, - GXIndTexMtxID matrix_sel, GXIndTexBiasSel bias_sel, - GXIndTexAlphaSel alpha_sel); -void GDSetTevIndBumpST(GXTevStageID tev_stage, GXIndTexStageID ind_stage, GXIndTexMtxID matrix_sel); -void GDSetTevIndBumpXYZ(GXTevStageID tev_stage, GXIndTexStageID ind_stage, GXIndTexMtxID matrix_sel); -void GDSetTevIndRepeat(GXTevStageID tev_stage); -void __GDSetIndTexMask(u32 mask); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gd/GDLight.h b/aurora-main/include/dolphin/gd/GDLight.h deleted file mode 100644 index 512a9d7..0000000 --- a/aurora-main/include/dolphin/gd/GDLight.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef _DOLPHIN_GD_LIGHT_H_ -#define _DOLPHIN_GD_LIGHT_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define XF_LIGHT_ID 0x0600 -#define XF_LIGHT_COLOR_ID 0x0603 -#define XF_LIGHT_ATTN_ID 0x0604 -#define XF_LIGHT_DISTATTN_ID 0x0607 -#define XF_LIGHT_POS_ID 0x060A -#define XF_LIGHT_SPEC_DIR_ID 0x060A -#define XF_LIGHT_DIR_ID 0x060D - -#define XF_REG_AMBIENT0_ID 0x100A -#define XF_REG_AMBIENT1_ID 0x100B -#define XF_REG_MATERIAL0_ID 0x100C -#define XF_REG_MATERIAL1_ID 0x100D -#define XF_REG_COLOR0CNTRL_ID 0x100E -#define XF_REG_COLOR1CNTRL_ID 0x100F -#define XF_REG_ALPHA0CNTRL_ID 0x1010 -#define XF_REG_ALPHA1CNTRL_ID 0x1011 - -#define XF_REG_CHAN_CTRL(matsrc, enable, lightmask0, ambsrc, diff_fn, p5, p6, lightmask4) \ - ( \ - (u32)(matsrc) << 0 | \ - (u32)(enable) << 1 | \ - (u32)(lightmask0) << 2 | \ - (u32)(ambsrc) << 6 | \ - (u32)(diff_fn) << 7 | \ - (u32)(p5) << 9 | \ - (u32)(p6) << 10 | \ - (u32)(lightmask4) << 11 \ - ) - -void GDSetLightAttn(GXLightID light, f32 a0, f32 a1, f32 a2, f32 k0, f32 k1, f32 k2); -void GDSetLightSpot(GXLightID light, f32 cutoff, GXSpotFn spot_func); -void GDSetLightDistAttn(GXLightID light, f32 ref_dist, f32 ref_br, GXDistAttnFn dist_func); -void GDSetLightColor(GXLightID light, GXColor color); -void GDSetLightPos(GXLightID light, f32 x, f32 y, f32 z); -void GDSetLightDir(GXLightID light, f32 nx, f32 ny, f32 nz); -void GDSetSpecularDirHA(GXLightID light, f32 nx, f32 ny, f32 nz, f32 hx, f32 hy, f32 hz); -void GDSetSpecularDir(GXLightID light, f32 nx, f32 ny, f32 nz); -void GDLoadLightObjIndx(u32 lt_obj_indx, GXLightID light); -void GDSetChanAmbColor(GXChannelID chan, GXColor color); -void GDSetChanMatColor(GXChannelID chan, GXColor color); -void GDSetChanCtrl(GXChannelID chan, u8 enable, GXColorSrc amb_src, - GXColorSrc mat_src, u32 light_mask, GXDiffuseFn diff_fn, - GXAttnFn attn_fn); - -u16 __GDLightID2Index(GXLightID id); - -inline static u16 __GDLightID2Offset(GXLightID id) { - return __GDLightID2Index(id) * 16; -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gd/GDPixel.h b/aurora-main/include/dolphin/gd/GDPixel.h deleted file mode 100644 index 158b04e..0000000 --- a/aurora-main/include/dolphin/gd/GDPixel.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef _DOLPHIN_GD_PIXEL_H -#define _DOLPHIN_GD_PIXEL_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define BP_FOG_UNK0(a, id) \ - ( \ - (u32)(a) << 0 | \ - (u32)(id) << 24 \ - ) - -#define BP_FOG_UNK1(b_m, id) \ - ( \ - (u32)(b_m) << 0 | \ - (u32)(id) << 24 \ - ) - -#define BP_FOG_UNK2(b_expn, id) \ - ( \ - (u32)(b_expn) << 0 | \ - (u32)(id) << 24 \ - ) - -#define BP_FOG_UNK3(c, proj, fsel, id) \ - ( \ - (u32)(c) << 0 | \ - (u32)(proj) << 20 | \ - (u32)(fsel) << 21 | \ - (u32)(id) << 24 \ - ) - -#define BP_FOG_COLOR(r, g, b, id) \ - ( \ - (u32)(b) << 0 | \ - (u32)(g) << 8 | \ - (u32)(r) << 16 | \ - (u32)(id) << 24 \ - ) - -#define BP_BLEND_MODE(enable, enable_logic, enable_dither, enable_color_update, enable_alpha_update, dst_factor, src_factor, blend_sub, logic_op, id) \ - ( \ - (u32)(enable) << 0 | \ - (u32)(enable_logic) << 1 | \ - (u32)(enable_dither) << 2 | \ - (u32)(enable_color_update) << 3 | \ - (u32)(enable_alpha_update) << 4 | \ - (u32)(dst_factor) << 5 | \ - (u32)(src_factor) << 8 | \ - (u32)(blend_sub) << 11 | \ - (u32)(logic_op) << 12 | \ - (u32)(id) << 24 \ - ) - -#define BP_Z_MODE(enable_compare, compare_fn, enable_update, id) \ - ( \ - (u32)(enable_compare) << 0 | \ - (u32)(compare_fn) << 1 | \ - (u32)(enable_update) << 4 | \ - (u32)(id) << 24 \ - ) - -#define BP_DST_ALPHA(alpha, enable, id) \ - ( \ - (u32)(alpha) << 0 | \ - (u32)(enable) << 8 | \ - (u32)(id) << 24 \ - ) - -#define BP_TOKEN(token, id) \ - ( \ - (u32)(token) << 0 | \ - (u32)(id) << 24 \ - ) - -void GDSetFog(GXFogType type, f32 startz, f32 endz, f32 nearz, f32 farz, GXColor color); -void GDSetBlendMode(GXBlendMode type, GXBlendFactor src_factor, GXBlendFactor dst_factor, GXLogicOp logic_op); -void GDSetBlendModeEtc(GXBlendMode type, GXBlendFactor src_factor, - GXBlendFactor dst_factor, GXLogicOp logic_op, - u8 color_update_enable, - u8 alpha_update_enable, - u8 dither_enable); -void GDSetZMode(u8 compare_enable, GXCompare func, u8 update_enable); -void GDSetDstAlpha(u8 enable, u8 alpha); -void GDSetDrawSync(u16 token); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gd/GDTev.h b/aurora-main/include/dolphin/gd/GDTev.h deleted file mode 100644 index baec8b5..0000000 --- a/aurora-main/include/dolphin/gd/GDTev.h +++ /dev/null @@ -1,133 +0,0 @@ -#ifndef _DOLPHIN_GD_TEV_H -#define _DOLPHIN_GD_TEV_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define BP_TEV_COLOR(d, c, b, a, bias, op, clamp, scale, out, id) \ - ( \ - (u32)(d) << 0 | \ - (u32)(c) << 4 | \ - (u32)(b) << 8 | \ - (u32)(a) << 12 | \ - (u32)(bias) << 16 | \ - (u32)(op) << 18 | \ - (u32)(clamp) << 19 | \ - (u32)(scale) << 20 | \ - (u32)(out) << 22 | \ - (u32)(id) << 24 \ - ) - -#define BP_TEV_ALPHA(ras_sel, tex_sel, d, c, b, a, bias, op, clamp, scale, out, id) \ - ( \ - (u32)(ras_sel) << 0 | \ - (u32)(tex_sel) << 2 | \ - (u32)(d) << 4 | \ - (u32)(c) << 7 | \ - (u32)(b) << 10 | \ - (u32)(a) << 13 | \ - (u32)(bias) << 16 | \ - (u32)(op) << 18 | \ - (u32)(clamp) << 19 | \ - (u32)(scale) << 20 | \ - (u32)(out) << 22 | \ - (u32)(id) << 24 \ - ) - -#define BP_TEV_COLOR_REG_RA(r, a, reg, id) \ - ( \ - (u32)(r) << 0 | \ - (u32)(a) << 12 | \ - (u32)(reg) << 23 | \ - (u32)(id) << 24 \ - ) - -#define BP_TEV_COLOR_REG_BG(b, g, reg, id) \ - ( \ - (u32)(b) << 0 | \ - (u32)(g) << 12 | \ - (u32)(reg) << 23 | \ - (u32)(id) << 24 \ - ) - -#define BP_TEV_KSEL(rb, ga, kcsel0, kasel0, kcsel1, kasel1, id) \ - ( \ - (u32)(rb) << 0 | \ - (u32)(ga) << 2 | \ - (u32)(kcsel0) << 4 | \ - (u32)(kasel0) << 9 | \ - (u32)(kcsel1) << 14 | \ - (u32)(kasel1) << 19 | \ - (u32)(id) << 24 \ - ) - -#define BP_ALPHA_COMPARE(ref0, ref1, comp0, comp1, op, id) \ - ( \ - (u32)(ref0) << 0 | \ - (u32)(ref1) << 8 | \ - (u32)(comp0) << 16 | \ - (u32)(comp1) << 19 | \ - (u32)(op) << 22 | \ - (u32)(id) << 24 \ - ) - -#define BP_ZTEX_PARAMS_0(bias, id) \ - ( \ - (u32)(bias) << 0 | \ - (u32)(id) << 24 \ - ) - -#define BP_ZTEX_PARAMS_1(zfmt, op, id) \ - ( \ - (u32)(zfmt) << 0 | \ - (u32)(op) << 2 | \ - (u32)(id) << 24 \ - ) - -#define BP_TEV_ORDER(map0, coord0, enable0, color0, map1, coord1, enable1, color1, id) \ - ( \ - (u32)(map0) << 0 | \ - (u32)(coord0) << 3 | \ - (u32)(enable0) << 6 | \ - (u32)(color0) << 7 | \ - (u32)(map1) << 12 | \ - (u32)(coord1) << 15 | \ - (u32)(enable1) << 18 | \ - (u32)(color1) << 19 | \ - (u32)(id) << 24 \ - ) - -void GDSetTevOp(GXTevStageID stage, GXTevMode mode); -void GDSetTevColorCalc(GXTevStageID stage, GXTevColorArg a, GXTevColorArg b, - GXTevColorArg c, GXTevColorArg d, GXTevOp op, - GXTevBias bias, GXTevScale scale, u8 clamp, - GXTevRegID out_reg); -void GDSetTevAlphaCalcAndSwap(GXTevStageID stage, GXTevAlphaArg a, - GXTevAlphaArg b, GXTevAlphaArg c, GXTevAlphaArg d, - GXTevOp op, GXTevBias bias, GXTevScale scale, - u8 clamp, GXTevRegID out_reg, - GXTevSwapSel ras_sel, GXTevSwapSel tex_sel); -void GDSetTevColor(GXTevRegID reg, GXColor color); -void GDSetTevColorS10(GXTevRegID reg, GXColorS10 color); -void GDSetTevKColor(GXTevKColorID reg, GXColor color); -void GDSetTevKonstantSel(GXTevStageID evenStage, GXTevKColorSel kcsel0, - GXTevKAlphaSel kasel0, GXTevKColorSel kcsel1, - GXTevKAlphaSel kasel1); -void GDSetTevSwapModeTable(GXTevSwapSel table, GXTevColorChan red, - GXTevColorChan green, GXTevColorChan blue, - GXTevColorChan alpha); -void GDSetAlphaCompare(GXCompare comp0, u8 ref0, GXAlphaOp op, GXCompare comp1, u8 ref1); -void GDSetZTexture(GXZTexOp op, GXTexFmt fmt, u32 bias); -void GDSetTevOrder(GXTevStageID evenStage, GXTexCoordID coord0, GXTexMapID map0, - GXChannelID color0, GXTexCoordID coord1, GXTexMapID map1, - GXChannelID color1); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gd/GDTexture.h b/aurora-main/include/dolphin/gd/GDTexture.h deleted file mode 100644 index 2370cbb..0000000 --- a/aurora-main/include/dolphin/gd/GDTexture.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef _DOLPHIN_GD_TEXTURE_H -#define _DOLPHIN_GD_TEXTURE_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define BP_TEX_MODE0(wrap_s, wrap_t, mag_filt, min_filt, edge_lod, lod_bias, max_aniso, bias_clamp, id) \ - ( \ - (u32)(wrap_s) << 0 | \ - (u32)(wrap_t) << 2 | \ - (u32)(mag_filt) << 4 | \ - (u32)(min_filt) << 5 | \ - (u32)(edge_lod) << 8 | \ - (u32)(lod_bias) << 9 | \ - (u32)(max_aniso) << 19 | \ - (u32)(bias_clamp) << 21 | \ - (u32)(id) << 24 \ - ) - -#define BP_TEX_MODE1(min_lod, max_lod, id) \ - ( \ - (u32)(min_lod) << 0 | \ - (u32)(max_lod) << 8 | \ - (u32)(id) << 24 \ - ) - -#define BP_IMAGE_ATTR(width, height, format, id) \ - ( \ - (u32)(width) << 0 | \ - (u32)(height) << 10 | \ - (u32)(format) << 20 | \ - (u32)(id) << 24 \ - ) - -#define BP_IMAGE_PTR(ptr, id) \ - ( \ - (u32)(ptr) << 0 | \ - (u32)(id) << 24 \ - ) - -#define BP_TEX_CACHE_EVEN(tmem, size0, size1, type, id) \ - ( \ - (u32)(tmem) << 0 | \ - (u32)(size0) << 15 | \ - (u32)(size1) << 18 | \ - (u32)(type) << 21 | \ - (u32)(id) << 24 \ - ) - -#define BP_TEX_CACHE_ODD(tmem, size0, size1, id) \ - ( \ - (u32)(tmem) << 0 | \ - (u32)(size0) << 15 | \ - (u32)(size1) << 18 | \ - (u32)(id) << 24 \ - ) - -#define BP_TEX_TLUT(tmem, format, id) \ - ( \ - (u32)(tmem) << 0 | \ - (u32)(format) << 10 | \ - (u32)(id) << 24 \ - ) - -#define BP_TEXCOORD_S_SCALE(s_scale, s_bias, s_wrap, line_offset, point_offset, id) \ - ( \ - (u32)(s_scale) << 0 | \ - (u32)(s_bias) << 16 | \ - (u32)(s_wrap) << 17 | \ - (u32)(line_offset) << 18 | \ - (u32)(point_offset) << 19 | \ - (u32)(id) << 24 \ - ) - -#define BP_TEXCOORD_T_SCALE(t_scale, t_bias, t_wrap, id) \ - ( \ - (u32)(t_scale) << 0 | \ - (u32)(t_bias) << 16 | \ - (u32)(t_wrap) << 17 | \ - (u32)(id) << 24 \ - ) - -#define BP_LOAD_TLUT0(ptr, id) \ - ( \ - (u32)(ptr) << 0 | \ - (u32)(id) << 24 \ - ) - -#define BP_LOAD_TLUT1(ptr, size, id) \ - ( \ - (u32)(ptr) << 0 | \ - (u32)(size) << 10 | \ - (u32)(id) << 24 \ - ) - -void GDSetTexLookupMode(GXTexMapID id, GXTexWrapMode wrap_s, - GXTexWrapMode wrap_t, GXTexFilter min_filt, - GXTexFilter mag_filt, f32 min_lod, f32 max_lod, - f32 lod_bias, u8 bias_clamp, u8 do_edge_lod, - GXAnisotropy max_aniso); - -void GDSetTexImgAttr(GXTexMapID id, u16 width, u16 height, GXTexFmt format); -void GDSetTexImgPtr(GXTexMapID id, void* image_ptr); -void GDSetTexImgPtrRaw(GXTexMapID id, u32 image_ptr_raw); -void GDPatchTexImgPtr(void* image_ptr); -void GDSetTexCached(GXTexMapID id, u32 tmem_even, GXTexCacheSize size_even, - u32 tmem_odd, GXTexCacheSize size_odd); -void GDSetTexPreLoaded(GXTexMapID id, u32 tmem_even, u32 tmem_odd); -void GDSetTexTlut(GXTexMapID id, u32 tmem_addr, GXTlutFmt format); -void GDSetTexCoordScale(GXTexCoordID coord, u16 s_scale, u16 t_scale); -void GDSetTexCoordScale2(GXTexCoordID coord, u16 s_scale, u8 s_bias, - u8 s_wrap, u16 t_scale, u8 t_bias, u8 t_wrap); -void GDSetTexCoordScaleAndTOEs(GXTexCoordID coord, u16 s_scale, u8 s_bias, - u8 s_wrap, u16 t_scale, u8 t_bias, u8 t_wrap, - u8 line_offset, u8 point_offset); -void GDLoadTlut(void* tlut_ptr, u32 tmem_addr, GXTlutSize size); -void GDLoadTlutRaw(u32 tlut_ptr_raw, u32 tmem_addr, GXTlutSize size); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gd/GDTransform.h b/aurora-main/include/dolphin/gd/GDTransform.h deleted file mode 100644 index 8d0159f..0000000 --- a/aurora-main/include/dolphin/gd/GDTransform.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef _DOLPHIN_GD_TRANSFORM_H_ -#define _DOLPHIN_GD_TRANSFORM_H_ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define CP_MTX_REG_A_ID 0x30 -#define CP_MTX_REG_B_ID 0x40 - -#define XF_REG_MATRIXINDEX0_ID 0x1018 -#define XF_REG_MATRIXINDEX1_ID 0x1019 -#define XF_REG_PROJECTIONA_ID 0x1020 -#define XF_REG_PROJECTIONB_ID 0x1021 -#define XF_REG_PROJECTIONC_ID 0x1022 -#define XF_REG_PROJECTIOND_ID 0x1023 -#define XF_REG_PROJECTIONE_ID 0x1024 -#define XF_REG_PROJECTIONF_ID 0x1025 -#define XF_REG_PROJECTORTHO_ID 0x1026 - -#define CP_MTX_REG_A(pn, t0, t1, t2, t3) \ - ( \ - (u32)(pn) << 0 | \ - (u32)(t0) << 6 | \ - (u32)(t1) << 12 | \ - (u32)(t2) << 18 | \ - (u32)(t3) << 24 \ - ) - -#define CP_MTX_REG_B(t4, t5, t6, t7) \ - ( \ - (u32)(t4) << 0 | \ - (u32)(t5) << 6 | \ - (u32)(t6) << 12 | \ - (u32)(t7) << 18 \ - ) - -void GDLoadPosMtxImm(const Mtx mtx, u32 id); -void GDLoadPosMtxIndx(u16 mtx_indx, u32 id); -void GDLoadNrmMtxImm(const Mtx mtx, u32 id); -void GDLoadNrmMtxImm3x3(const f32 mtx[3][3], u32 id); -void GDLoadNrmMtxIndx3x3(u16 mtx_indx, u32 id); -void GDLoadTexMtxImm(const Mtx mtx, u32 id, GXTexMtxType type); -void GDLoadTexMtxIndx(u16 mtx_indx, u32 id, GXTexMtxType type); -void GDSetCurrentMtx(u32 pn, u32 t0, u32 t1, u32 t2, u32 t3, u32 t4, u32 t5, u32 t6, u32 t7); -void GDSetProjection(const Mtx44 mtx, GXProjectionType type); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gf.h b/aurora-main/include/dolphin/gf.h deleted file mode 100644 index 50676ae..0000000 --- a/aurora-main/include/dolphin/gf.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _DOLPHIN_GF_H_ -#define _DOLPHIN_GF_H_ - -#include -#include -#include -#include - -#endif diff --git a/aurora-main/include/dolphin/gf/GFGeometry.h b/aurora-main/include/dolphin/gf/GFGeometry.h deleted file mode 100644 index c0866a5..0000000 --- a/aurora-main/include/dolphin/gf/GFGeometry.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _DOLPHIN_GF_GFGEOMETRY_H_ -#define _DOLPHIN_GF_GFGEOMETRY_H_ - -#include - -#define GF_GEN_MODE(nTexGens, nChans, nTevs, cm, nInds) \ - ( \ - (u32)(nTexGens) << 0 | \ - (u32)(nChans) << 4 | \ - (u32)(nTevs) << 10 | \ - (u32)(cm) << 14 | \ - (u32)(nInds) << 16 \ - ) - -static inline void GFWrite_u8(u8 data) { - GXCmd1u8(data); -} - -static inline void GFWrite_u32(u32 data) { - GXCmd1u32(data); -} - -static inline void GFWrite_u16(u16 data) { - GXCmd1u16(data); -} - -static inline void GFWriteBPCmd(u32 regval) { - GFWrite_u8(GX_LOAD_BP_REG); - GFWrite_u32(regval); -} - -static inline void GFWriteXFCmd(u16 addr, u32 val) { - GFWrite_u8(GX_LOAD_XF_REG); - GFWrite_u16(0); - GFWrite_u16(addr); - GFWrite_u32(val); -} - -void GFSetGenMode2(u8 nTexGens, u8 nChans, u8 nTevs, u8 nInds, GXCullMode cm); - -#endif /* _DOLPHIN_GF_GFGEOMETRY_H_ */ diff --git a/aurora-main/include/dolphin/gf/GFLight.h b/aurora-main/include/dolphin/gf/GFLight.h deleted file mode 100644 index 3c4e222..0000000 --- a/aurora-main/include/dolphin/gf/GFLight.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _DOLPHIN_GF_GFLIGHT_H -#define _DOLPHIN_GF_GFLIGHT_H - -#include - -void GFSetChanAmbColor(GXChannelID chan, GXColor color); - -#endif /* _DOLPHIN_GF_GFLIGHT_H */ diff --git a/aurora-main/include/dolphin/gf/GFPixel.h b/aurora-main/include/dolphin/gf/GFPixel.h deleted file mode 100644 index 93b7ff9..0000000 --- a/aurora-main/include/dolphin/gf/GFPixel.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _DOLPHIN_GF_GFPIXEL_H -#define _DOLPHIN_GF_GFPIXEL_H - -#include - -void GFSetFog(GXFogType type, f32 startz, f32 endz, f32 nearz, f32 farz, GXColor color); -void GFSetBlendModeEtc(GXBlendMode type, GXBlendFactor src_factor, - GXBlendFactor dst_factor, GXLogicOp logic_op, - u8 color_update_enable, u8 alpha_update_enable, - u8 dither_enable); -void GFSetZMode(u8 compare_enable, GXCompare func, u8 update_enable); - -#endif /* _DOLPHIN_GF_GFPIXEL_H */ diff --git a/aurora-main/include/dolphin/gf/GFTev.h b/aurora-main/include/dolphin/gf/GFTev.h deleted file mode 100644 index ade4c41..0000000 --- a/aurora-main/include/dolphin/gf/GFTev.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _DOLPHIN_GF_GFTEV_H -#define _DOLPHIN_GF_GFTEV_H - -#include - -void GFSetTevColorS10(GXTevRegID reg, GXColorS10 color); - -#endif /* _DOLPHIN_GF_GFTEV_H */ diff --git a/aurora-main/include/dolphin/gx.h b/aurora-main/include/dolphin/gx.h deleted file mode 100644 index b4cf7ef..0000000 --- a/aurora-main/include/dolphin/gx.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef DOLPHIN_GX_H -#define DOLPHIN_GX_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXAurora.h b/aurora-main/include/dolphin/gx/GXAurora.h deleted file mode 100644 index b227945..0000000 --- a/aurora-main/include/dolphin/gx/GXAurora.h +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef DOLPHIN_GXAURORA_H -#define DOLPHIN_GXAURORA_H - -#include - -#if __cplusplus -extern "C" { -#endif - -// -// Subcommands for GX_LOAD_AURORA. -// - -/** - * Sets the actual render viewport in native framebuffer coordinates. - * Must be followed by six f32 values: left, top, width, height, nearz, farz. - */ -#define GX_LOAD_AURORA_VIEWPORT_RENDER 0x0001 - -/** - * Sets the actual render scissor in native framebuffer coordinates. - * Must be followed by four u32 values: left, top, width, height. - */ -#define GX_LOAD_AURORA_SCISSOR_RENDER 0x0002 - -/** - * Aurora equivalent of CP_REG_ARRAYBASE_ID: sets the base address and size of a vertex array. - * This command must be followed by a 64-bit memory address, 32-bit size, and 1-byte little-endian flag. - * The index of the vertex array is given by the lowest 4 bits of the command ID, - * e.g. writing GX_LOAD_AURORA_ARRAYBASE + 5 will set the vertex array for the sixth vertex attribute. - * To set strides, use the normal CP_REG_ARRAYSTRIDE_ID register. - */ -#define GX_LOAD_AURORA_ARRAYBASE 0x0010 - -/** - * Pushes a debug group to the backend graphics API. These may show in debugging tools such as RenderDoc. - * Must be followed by a u16 string length and that many UTF-8 characters (no null terminator required). - * It is considered an error to have unpopped debug groups at the end of the frame. They will be automatically cleared. - */ -#define GX_LOAD_AURORA_DEBUG_GROUP_PUSH 0x0020 - -/** - * Pops a previously pushed debug group. - * Followed by nothing. - */ -#define GX_LOAD_AURORA_DEBUG_GROUP_POP 0x0021 - -/** - * Sends a debug marker to the backend graphics API. - * Must be followed by a u16 string length and that many UTF-8 characters (no null terminator required). - */ -#define GX_LOAD_AURORA_DEBUG_MARKER_INSERT 0x0022 - -#define GX_LOAD_AURORA_TEXOBJ 0x0030 - -#define GX_LOAD_AURORA_TLUT 0x0031 - -#define GX_LOAD_AURORA_DESTROY_TEXOBJ 0x0032 - -#define GX_LOAD_AURORA_DESTROY_TLUT 0x0033 - -#define GX_LOAD_AURORA_DESTROY_COPY_TEX 0x0034 - -#define GX_LOAD_AURORA_INVALIDATE_TEX_ALL 0x0035 - - -/* - * Debug marker stuff - */ - -/** - * Pushes a debug group to the backend graphics API. These may show in debugging tools such as RenderDoc. - * It is considered an error to have unpopped debug groups at the end of the frame. They will be automatically cleared. - */ -void GXPushDebugGroup(const char* label); - -/** - * Pop a debug group previously pushed via GXPushDebugGroup(). - */ -void GXPopDebugGroup(); - -/** - * Sends a debug marker to the backend graphics API. These may show in debugging tools such as RenderDoc. - */ -void GXInsertDebugMarker(const char* label); - -typedef enum _AuroraViewportPolicy { - AURORA_VIEWPORT_FIT = 0, // Preserve logical aspect in the content framebuffer - AURORA_VIEWPORT_STRETCH = 1, // Match content framebuffer aspect to the native surface - AURORA_VIEWPORT_NATIVE = 2, // Use active framebuffer pixels directly - AURORA_VIEWPORT_16_9 = 3, // Fixed 16:9 content with bars on other surfaces -} AuroraViewportPolicy; - -/** - * Configures content framebuffer sizing and how GXSetViewport/GXSetScissor parameters are applied to rendering. - * When AURORA_VIEWPORT_NATIVE is used, GXSetTexCopySrc/GXSetTexCopyDst will use native framebuffer resolution. - */ -void AuroraSetViewportPolicy(AuroraViewportPolicy policy); - -/** - * Retrieves the current content framebuffer size. - */ -void AuroraGetRenderSize(u32* width, u32* height); - -/** Retrieves the current native presentation-surface size, ignoring the GX sizing policy. */ -void AuroraGetSurfaceSize(u32* width, u32* height); - -/** - * Sets the actual render viewport in native framebuffer coordinates. - * Overrides the automatically scaled values set by the logical GXSetViewport. - */ -void GXSetViewportRender(f32 left, f32 top, f32 wd, f32 ht, f32 nearz, f32 farz); - -/** - * Sets the actual render scissor in native framebuffer coordinates. - * Overrides the automatically scaled values set by the logical GXSetScissor. - */ -void GXSetScissorRender(u32 left, u32 top, u32 wd, u32 ht); - -/** Maps the logical GX viewport and scissor into a centered safe area, for fixed-aspect UI bridges. */ -void GXSetViewportScissorRenderSafeArea(f32 aspect); - -/** Restores the viewport and scissor from logical GX state after GXSetViewportScissorRenderSafeArea. */ -void GXRestoreViewportScissorRender(void); - -/** Sets the texture-copy source in active render-target coordinates, for bridges that already - * resolved VI/window scaling. */ -void GXSetTexCopySrcRender(u16 left, u16 top, u16 wd, u16 ht); - -/** - * Create an offscreen framebuffer and switch rendering to it. - * All subsequent GX rendering will target this framebuffer until GXRestoreFrameBuffer() is called. - * Use GXCopyTex to resolve the offscreen content into a texture. - */ -void GXCreateFrameBuffer(u32 width, u32 height); - -/** - * Restore rendering to the main EFB framebuffer. - * Must be called after GXCreateFrameBuffer() to resume normal rendering. - */ -void GXRestoreFrameBuffer(void); - -void GXApplyBPReg(u8 reg, u32 value); - -#if __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXBump.h b/aurora-main/include/dolphin/gx/GXBump.h deleted file mode 100644 index aa99477..0000000 --- a/aurora-main/include/dolphin/gx/GXBump.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef DOLPHIN_GXBUMP_H -#define DOLPHIN_GXBUMP_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void GXSetTevDirect(GXTevStageID tev_stage); -void GXSetTevIndTile(GXTevStageID tevStage, GXIndTexStageID indStage, u16 tileSizeS, u16 tileSizeT, u16 tileSizeS_exp, - u16 tileSizeT_exp, GXIndTexFormat fmt, GXIndTexMtxID matrixSel, GXIndTexBiasSel biasSel, - GXIndTexAlphaSel alphaSel); -void GXSetNumIndStages(u8 nIndStages); -#ifdef TARGET_PC -void GXSetIndTexMtx(GXIndTexMtxID mtx_sel, const void* offset, s8 scale_exp); -#else -void GXSetIndTexMtx(GXIndTexMtxID mtx_sel, f32 offset[2][3], s8 scale_exp); -#endif -void GXSetIndTexOrder(GXIndTexStageID ind_stage, GXTexCoordID tex_coord, GXTexMapID tex_map); -void GXSetIndTexCoordScale(GXIndTexStageID indStage, GXIndTexScale scaleS, GXIndTexScale scaleT); -void GXSetTevIndirect(GXTevStageID tev_stage, GXIndTexStageID ind_stage, GXIndTexFormat format, - GXIndTexBiasSel bias_sel, GXIndTexMtxID matrix_sel, GXIndTexWrap wrap_s, GXIndTexWrap wrap_t, - GXBool add_prev, GXBool ind_lod, GXIndTexAlphaSel alpha_sel); -void GXSetTevIndWarp(GXTevStageID tev_stage, GXIndTexStageID ind_stage, GXBool signed_offsets, GXBool replace_mode, - GXIndTexMtxID matrix_sel); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXCommandList.h b/aurora-main/include/dolphin/gx/GXCommandList.h deleted file mode 100644 index 069a086..0000000 --- a/aurora-main/include/dolphin/gx/GXCommandList.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef DOLPHIN_GXCOMMANDLIST_H -#define DOLPHIN_GXCOMMANDLIST_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define GX_NOP 0x00 -#define GX_DRAW_QUADS 0x80 -#define GX_DRAW_TRIANGLES 0x90 -#define GX_DRAW_TRIANGLE_STRIP 0x98 -#define GX_DRAW_TRIANGLE_FAN 0xA0 -#define GX_DRAW_LINES 0xA8 -#define GX_DRAW_LINE_STRIP 0xB0 -#define GX_DRAW_POINTS 0xB8 - -#define GX_LOAD_BP_REG 0x61 -#define GX_LOAD_CP_REG 0x08 -#define GX_LOAD_XF_REG 0x10 -#define GX_LOAD_INDX_A 0x20 -#define GX_LOAD_INDX_B 0x28 -#define GX_LOAD_INDX_C 0x30 -#define GX_LOAD_INDX_D 0x38 - -#define GX_CMD_CALL_DL 0x40 -#define GX_CMD_INVL_VC 0x48 - -/** - * Custom Aurora commands that are followed by another 2-byte identifier. - * See GXAurora.h for further documentation on these. - */ -#define GX_LOAD_AURORA 0x50 - -#define GX_OPCODE_MASK 0xF8 -#define GX_VAT_MASK 0x07 - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXCpu2Efb.h b/aurora-main/include/dolphin/gx/GXCpu2Efb.h deleted file mode 100644 index eefbcd8..0000000 --- a/aurora-main/include/dolphin/gx/GXCpu2Efb.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _DOLPHIN_GX_GXCPU2EFB_H_ -#define _DOLPHIN_GX_GXCPU2EFB_H_ - -#include "GXEnum.h" - -void GXPokeAlphaMode(GXCompare func, u8 threshold); -void GXPokeAlphaRead(GXAlphaReadMode mode); -void GXPokeAlphaUpdate(GXBool update_enable); -void GXPokeBlendMode(GXBlendMode type, GXBlendFactor src_factor, GXBlendFactor dst_factor, GXLogicOp op); -void GXPokeColorUpdate(GXBool update_enable); -void GXPokeDstAlpha(GXBool enable, u8 alpha); -void GXPokeDither(GXBool dither); -void GXPokeZMode(GXBool compare_enable, GXCompare func, GXBool update_enable); -void GXPeekARGB(u16 x, u16 y, u32* color); -void GXPokeARGB(u16 x, u16 y, u32 color); -void GXPeekZ(u16 x, u16 y, u32* z); -void GXPokeZ(u16 x, u16 y, u32 z); -u32 GXCompressZ16(u32 z24, GXZFmt16 zfmt); -u32 GXDecompressZ16(u32 z16, GXZFmt16 zfmt); - - -#endif // _DOLPHIN_GX_GXCPU2EFB_H_ diff --git a/aurora-main/include/dolphin/gx/GXCull.h b/aurora-main/include/dolphin/gx/GXCull.h deleted file mode 100644 index bf2d922..0000000 --- a/aurora-main/include/dolphin/gx/GXCull.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef DOLPHIN_GXCULL_H -#define DOLPHIN_GXCULL_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void GXSetScissor(u32 left, u32 top, u32 wd, u32 ht); -void GXSetCullMode(GXCullMode mode); -void GXSetCoPlanar(GXBool enable); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXDispList.h b/aurora-main/include/dolphin/gx/GXDispList.h deleted file mode 100644 index 41597c1..0000000 --- a/aurora-main/include/dolphin/gx/GXDispList.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef DOLPHIN_GXDISPLIST_H -#define DOLPHIN_GXDISPLIST_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef AURORA -#define GXCallDisplayListNative GXCallDisplayListLE -#else -#define GXCallDisplayListNative GXCallDisplayList -#endif - -void GXBeginDisplayList(void* list, u32 size); -u32 GXEndDisplayList(void); -void GXCallDisplayListLE(const void* list, u32 nbytes); -void GXCallDisplayList(const void* list, u32 nbytes); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXDraw.h b/aurora-main/include/dolphin/gx/GXDraw.h deleted file mode 100644 index 3c02a08..0000000 --- a/aurora-main/include/dolphin/gx/GXDraw.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef DOLPHIN_GXDRAW_H -#define DOLPHIN_GXDRAW_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void GXDrawCylinder(u8 numEdges); -void GXDrawTorus(f32 rc, u8 numc, u8 numt); -void GXDrawSphere(u8 numMajor, u8 numMinor); -void GXDrawCube(void); -void GXDrawDodeca(void); -void GXDrawOctahedron(void); -void GXDrawIcosahedron(void); -void GXDrawSphere1(u8 depth); -u32 GXGenNormalTable(u8 depth, f32* table); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXEnum.h b/aurora-main/include/dolphin/gx/GXEnum.h deleted file mode 100644 index d081f45..0000000 --- a/aurora-main/include/dolphin/gx/GXEnum.h +++ /dev/null @@ -1,915 +0,0 @@ -#ifndef DOLPHIN_GXENUM_H -#define DOLPHIN_GXENUM_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef TARGET_PC -#include - -typedef bool GXBool; -#else -typedef u8 GXBool; -#endif - -#define GX_FALSE ((GXBool)0) -#define GX_TRUE ((GXBool)1) - -#define GX_ENABLE ((GXBool)1) -#define GX_DISABLE ((GXBool)0) - -typedef enum { - GX_PERSPECTIVE, - GX_ORTHOGRAPHIC, -} GXProjectionType; - -typedef enum { - GX_NEVER, - GX_LESS, - GX_EQUAL, - GX_LEQUAL, - GX_GREATER, - GX_NEQUAL, - GX_GEQUAL, - GX_ALWAYS, -} GXCompare; - -typedef enum { - GX_AOP_AND, - GX_AOP_OR, - GX_AOP_XOR, - GX_AOP_XNOR, - GX_MAX_ALPHAOP, -} GXAlphaOp; - -typedef enum { - GX_ZC_LINEAR, - GX_ZC_NEAR, - GX_ZC_MID, - GX_ZC_FAR, -} GXZFmt16; - -typedef enum { - GX_GM_1_0, - GX_GM_1_7, - GX_GM_2_2, -} GXGamma; - -typedef enum { - GX_PF_RGB8_Z24, - GX_PF_RGBA6_Z24, - GX_PF_RGB565_Z16, - GX_PF_Z24, - GX_PF_Y8, - GX_PF_U8, - GX_PF_V8, - GX_PF_YUV420, -} GXPixelFmt; - -typedef enum { - GX_QUADS = 0x80, - GX_TRIANGLES = 0x90, - GX_TRIANGLESTRIP = 0x98, - GX_TRIANGLEFAN = 0xA0, - GX_LINES = 0xA8, - GX_LINESTRIP = 0xB0, - GX_POINTS = 0xB8, -} GXPrimitive; - -typedef enum { - GX_VTXFMT0, - GX_VTXFMT1, - GX_VTXFMT2, - GX_VTXFMT3, - GX_VTXFMT4, - GX_VTXFMT5, - GX_VTXFMT6, - GX_VTXFMT7, - GX_MAX_VTXFMT, -} GXVtxFmt; - -typedef enum { - GX_VA_PNMTXIDX, - GX_VA_TEX0MTXIDX, - GX_VA_TEX1MTXIDX, - GX_VA_TEX2MTXIDX, - GX_VA_TEX3MTXIDX, - GX_VA_TEX4MTXIDX, - GX_VA_TEX5MTXIDX, - GX_VA_TEX6MTXIDX, - GX_VA_TEX7MTXIDX, - GX_VA_POS, - GX_VA_NRM, - GX_VA_CLR0, - GX_VA_CLR1, - GX_VA_TEX0, - GX_VA_TEX1, - GX_VA_TEX2, - GX_VA_TEX3, - GX_VA_TEX4, - GX_VA_TEX5, - GX_VA_TEX6, - GX_VA_TEX7, - GX_POS_MTX_ARRAY, - GX_NRM_MTX_ARRAY, - GX_TEX_MTX_ARRAY, - GX_LIGHT_ARRAY, - GX_VA_NBT, - GX_VA_MAX_ATTR, - GX_VA_NULL = 0xFF, -} GXAttr; - -typedef enum { - GX_NONE, - GX_DIRECT, - GX_INDEX8, - GX_INDEX16, -} GXAttrType; - -#define _GX_TF_CTF 0x20 -#define _GX_TF_ZTF 0x10 - -// Aurora-specific linear texture types -#define _GX_TF_PC 0x40 - -typedef enum { - GX_TF_I4 = 0x0, - GX_TF_I8 = 0x1, - GX_TF_IA4 = 0x2, - GX_TF_IA8 = 0x3, - GX_TF_RGB565 = 0x4, - GX_TF_RGB5A3 = 0x5, - GX_TF_RGBA8 = 0x6, - GX_TF_CMPR = 0xE, - - GX_CTF_R4 = 0x0 | _GX_TF_CTF, - GX_CTF_RA4 = 0x2 | _GX_TF_CTF, - GX_CTF_RA8 = 0x3 | _GX_TF_CTF, - GX_CTF_YUVA8 = 0x6 | _GX_TF_CTF, - GX_CTF_A8 = 0x7 | _GX_TF_CTF, - GX_CTF_R8 = 0x8 | _GX_TF_CTF, - GX_CTF_G8 = 0x9 | _GX_TF_CTF, - GX_CTF_B8 = 0xA | _GX_TF_CTF, - GX_CTF_RG8 = 0xB | _GX_TF_CTF, - GX_CTF_GB8 = 0xC | _GX_TF_CTF, - - GX_TF_Z8 = 0x1 | _GX_TF_ZTF, - GX_TF_Z16 = 0x3 | _GX_TF_ZTF, - GX_TF_Z24X8 = 0x6 | _GX_TF_ZTF, - - GX_CTF_Z4 = 0x0 | _GX_TF_ZTF | _GX_TF_CTF, - GX_CTF_Z8M = 0x9 | _GX_TF_ZTF | _GX_TF_CTF, - GX_CTF_Z8L = 0xA | _GX_TF_ZTF | _GX_TF_CTF, - GX_CTF_Z16L = 0xC | _GX_TF_ZTF | _GX_TF_CTF, - - GX_TF_A8 = GX_CTF_A8, - -#ifdef TARGET_PC - GX_TF_R8_PC = 0x1 | _GX_TF_PC, - GX_TF_RGBA8_PC = 0x6 | _GX_TF_PC, -#endif -} GXTexFmt; - -typedef enum { - GX_TF_C4 = 0x8, - GX_TF_C8 = 0x9, - GX_TF_C14X2 = 0xa, -} GXCITexFmt; - -typedef enum { - GX_CLAMP, - GX_REPEAT, - GX_MIRROR, - GX_MAX_TEXWRAPMODE, -} GXTexWrapMode; - -typedef enum { - GX_NEAR, - GX_LINEAR, - GX_NEAR_MIP_NEAR, - GX_LIN_MIP_NEAR, - GX_NEAR_MIP_LIN, - GX_LIN_MIP_LIN, -} GXTexFilter; - -typedef enum { - GX_ANISO_1, - GX_ANISO_2, - GX_ANISO_4, - GX_MAX_ANISOTROPY, -} GXAnisotropy; - -typedef enum { - GX_TEXMAP0, - GX_TEXMAP1, - GX_TEXMAP2, - GX_TEXMAP3, - GX_TEXMAP4, - GX_TEXMAP5, - GX_TEXMAP6, - GX_TEXMAP7, - GX_MAX_TEXMAP, - GX_TEXMAP_NULL = 0xFF, - GX_TEX_DISABLE = 0x100, -} GXTexMapID; - -typedef enum { - GX_TEXCOORD0, - GX_TEXCOORD1, - GX_TEXCOORD2, - GX_TEXCOORD3, - GX_TEXCOORD4, - GX_TEXCOORD5, - GX_TEXCOORD6, - GX_TEXCOORD7, - GX_MAX_TEXCOORD, - GX_TEXCOORD_NULL = 0xFF, -} GXTexCoordID; - -typedef enum { - GX_TEVSTAGE0, - GX_TEVSTAGE1, - GX_TEVSTAGE2, - GX_TEVSTAGE3, - GX_TEVSTAGE4, - GX_TEVSTAGE5, - GX_TEVSTAGE6, - GX_TEVSTAGE7, - GX_TEVSTAGE8, - GX_TEVSTAGE9, - GX_TEVSTAGE10, - GX_TEVSTAGE11, - GX_TEVSTAGE12, - GX_TEVSTAGE13, - GX_TEVSTAGE14, - GX_TEVSTAGE15, - GX_MAX_TEVSTAGE, -} GXTevStageID; - -typedef enum { - GX_MODULATE, - GX_DECAL, - GX_BLEND, - GX_REPLACE, - GX_PASSCLR, -} GXTevMode; - -typedef enum { - GX_MTX3x4, - GX_MTX2x4, -} GXTexMtxType; - -typedef enum { - GX_TG_MTX3x4, - GX_TG_MTX2x4, - GX_TG_BUMP0, - GX_TG_BUMP1, - GX_TG_BUMP2, - GX_TG_BUMP3, - GX_TG_BUMP4, - GX_TG_BUMP5, - GX_TG_BUMP6, - GX_TG_BUMP7, - GX_TG_SRTG, -} GXTexGenType; - -typedef enum { - GX_PNMTX0 = 0, - GX_PNMTX1 = 3, - GX_PNMTX2 = 6, - GX_PNMTX3 = 9, - GX_PNMTX4 = 12, - GX_PNMTX5 = 15, - GX_PNMTX6 = 18, - GX_PNMTX7 = 21, - GX_PNMTX8 = 24, - GX_PNMTX9 = 27, -} GXPosNrmMtx; - -typedef enum { - GX_TEXMTX0 = 30, - GX_TEXMTX1 = 33, - GX_TEXMTX2 = 36, - GX_TEXMTX3 = 39, - GX_TEXMTX4 = 42, - GX_TEXMTX5 = 45, - GX_TEXMTX6 = 48, - GX_TEXMTX7 = 51, - GX_TEXMTX8 = 54, - GX_TEXMTX9 = 57, - GX_IDENTITY = 60, -} GXTexMtx; - -typedef enum { - GX_COLOR0, - GX_COLOR1, - GX_ALPHA0, - GX_ALPHA1, - GX_COLOR0A0, - GX_COLOR1A1, - GX_COLOR_ZERO, - GX_ALPHA_BUMP, - GX_ALPHA_BUMPN, - GX_COLOR_NULL = 0xFF, -} GXChannelID; - -typedef enum { - GX_TG_POS, - GX_TG_NRM, - GX_TG_BINRM, - GX_TG_TANGENT, - GX_TG_TEX0, - GX_TG_TEX1, - GX_TG_TEX2, - GX_TG_TEX3, - GX_TG_TEX4, - GX_TG_TEX5, - GX_TG_TEX6, - GX_TG_TEX7, - GX_TG_TEXCOORD0, - GX_TG_TEXCOORD1, - GX_TG_TEXCOORD2, - GX_TG_TEXCOORD3, - GX_TG_TEXCOORD4, - GX_TG_TEXCOORD5, - GX_TG_TEXCOORD6, - GX_TG_COLOR0, - GX_TG_COLOR1, - GX_MAX_TEXGENSRC, -} GXTexGenSrc; - -typedef enum { - GX_BM_NONE, - GX_BM_BLEND, - GX_BM_LOGIC, - GX_BM_SUBTRACT, - GX_MAX_BLENDMODE, -} GXBlendMode; - -typedef enum { - GX_BL_ZERO, - GX_BL_ONE, - GX_BL_SRCCLR, - GX_BL_INVSRCCLR, - GX_BL_SRCALPHA, - GX_BL_INVSRCALPHA, - GX_BL_DSTALPHA, - GX_BL_INVDSTALPHA, - GX_BL_DSTCLR = GX_BL_SRCCLR, - GX_BL_INVDSTCLR = GX_BL_INVSRCCLR, -} GXBlendFactor; - -typedef enum { - GX_LO_CLEAR, - GX_LO_AND, - GX_LO_REVAND, - GX_LO_COPY, - GX_LO_INVAND, - GX_LO_NOOP, - GX_LO_XOR, - GX_LO_OR, - GX_LO_NOR, - GX_LO_EQUIV, - GX_LO_INV, - GX_LO_REVOR, - GX_LO_INVCOPY, - GX_LO_INVOR, - GX_LO_NAND, - GX_LO_SET, -} GXLogicOp; - -typedef enum { - GX_POS_XY = 0, - GX_POS_XYZ = 1, - GX_NRM_XYZ = 0, - GX_NRM_NBT = 1, - GX_NRM_NBT3 = 2, - GX_CLR_RGB = 0, - GX_CLR_RGBA = 1, - GX_TEX_S = 0, - GX_TEX_ST = 1, -} GXCompCnt; - -typedef enum { - GX_U8 = 0, - GX_S8 = 1, - GX_U16 = 2, - GX_S16 = 3, - GX_F32 = 4, - GX_RGB565 = 0, - GX_RGB8 = 1, - GX_RGBX8 = 2, - GX_RGBA4 = 3, - GX_RGBA6 = 4, - GX_RGBA8 = 5, -} GXCompType; - -typedef enum { - GX_PTTEXMTX0 = 64, - GX_PTTEXMTX1 = 67, - GX_PTTEXMTX2 = 70, - GX_PTTEXMTX3 = 73, - GX_PTTEXMTX4 = 76, - GX_PTTEXMTX5 = 79, - GX_PTTEXMTX6 = 82, - GX_PTTEXMTX7 = 85, - GX_PTTEXMTX8 = 88, - GX_PTTEXMTX9 = 91, - GX_PTTEXMTX10 = 94, - GX_PTTEXMTX11 = 97, - GX_PTTEXMTX12 = 100, - GX_PTTEXMTX13 = 103, - GX_PTTEXMTX14 = 106, - GX_PTTEXMTX15 = 109, - GX_PTTEXMTX16 = 112, - GX_PTTEXMTX17 = 115, - GX_PTTEXMTX18 = 118, - GX_PTTEXMTX19 = 121, - GX_PTIDENTITY = 125, -} GXPTTexMtx; - -typedef enum { - GX_TEVPREV, - GX_TEVREG0, - GX_TEVREG1, - GX_TEVREG2, - GX_MAX_TEVREG, -} GXTevRegID; - -typedef enum { - GX_DF_NONE, - GX_DF_SIGN, - GX_DF_CLAMP, -} GXDiffuseFn; - -typedef enum { - GX_SRC_REG, - GX_SRC_VTX, -} GXColorSrc; - -typedef enum { - GX_AF_SPEC, - GX_AF_SPOT, - GX_AF_NONE, -} GXAttnFn; - -typedef enum { - GX_LIGHT0 = 0x001, - GX_LIGHT1 = 0x002, - GX_LIGHT2 = 0x004, - GX_LIGHT3 = 0x008, - GX_LIGHT4 = 0x010, - GX_LIGHT5 = 0x020, - GX_LIGHT6 = 0x040, - GX_LIGHT7 = 0x080, - GX_MAX_LIGHT = 0x100, - GX_LIGHT_NULL = 0, -} GXLightID; - -typedef enum { - GX_TO_ZERO, - GX_TO_SIXTEENTH, - GX_TO_EIGHTH, - GX_TO_FOURTH, - GX_TO_HALF, - GX_TO_ONE, - GX_MAX_TEXOFFSET, -} GXTexOffset; - -typedef enum { - GX_SP_OFF, - GX_SP_FLAT, - GX_SP_COS, - GX_SP_COS2, - GX_SP_SHARP, - GX_SP_RING1, - GX_SP_RING2, -} GXSpotFn; - -typedef enum { - GX_DA_OFF, - GX_DA_GENTLE, - GX_DA_MEDIUM, - GX_DA_STEEP, -} GXDistAttnFn; - -typedef enum { - GX_CULL_NONE, - GX_CULL_FRONT, - GX_CULL_BACK, - GX_CULL_ALL - -} GXCullMode; - -typedef enum { GX_TEV_SWAP0 = 0, GX_TEV_SWAP1, GX_TEV_SWAP2, GX_TEV_SWAP3, GX_MAX_TEVSWAP } GXTevSwapSel; - -typedef enum { GX_CH_RED = 0, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA } GXTevColorChan; - -typedef enum _GXFogType { - GX_FOG_NONE = 0, - GX_FOG_PERSP_LIN = 2, - GX_FOG_PERSP_EXP = 4, - GX_FOG_PERSP_EXP2 = 5, - GX_FOG_PERSP_REVEXP = 6, - GX_FOG_PERSP_REVEXP2 = 7, - GX_FOG_ORTHO_LIN = 10, - GX_FOG_ORTHO_EXP = 12, - GX_FOG_ORTHO_EXP2 = 13, - GX_FOG_ORTHO_REVEXP = 14, - GX_FOG_ORTHO_REVEXP2 = 15, - GX_FOG_LIN = GX_FOG_PERSP_LIN, - GX_FOG_EXP = GX_FOG_PERSP_EXP, - GX_FOG_EXP2 = GX_FOG_PERSP_EXP2, - GX_FOG_REVEXP = GX_FOG_PERSP_REVEXP, - GX_FOG_REVEXP2 = GX_FOG_PERSP_REVEXP2, -} GXFogType; - -typedef enum { - GX_CC_CPREV, - GX_CC_APREV, - GX_CC_C0, - GX_CC_A0, - GX_CC_C1, - GX_CC_A1, - GX_CC_C2, - GX_CC_A2, - GX_CC_TEXC, - GX_CC_TEXA, - GX_CC_RASC, - GX_CC_RASA, - GX_CC_ONE, - GX_CC_HALF, - GX_CC_KONST, - GX_CC_ZERO -} GXTevColorArg; - -typedef enum { - GX_CA_APREV, - GX_CA_A0, - GX_CA_A1, - GX_CA_A2, - GX_CA_TEXA, - GX_CA_RASA, - GX_CA_KONST, - GX_CA_ZERO -} GXTevAlphaArg; - -typedef enum { - GX_TEV_ADD = 0, - GX_TEV_SUB = 1, - GX_TEV_COMP_R8_GT = 8, - GX_TEV_COMP_R8_EQ = 9, - GX_TEV_COMP_GR16_GT = 10, - GX_TEV_COMP_GR16_EQ = 11, - GX_TEV_COMP_BGR24_GT = 12, - GX_TEV_COMP_BGR24_EQ = 13, - GX_TEV_COMP_RGB8_GT = 14, - GX_TEV_COMP_RGB8_EQ = 15, - GX_TEV_COMP_A8_GT = GX_TEV_COMP_RGB8_GT, - GX_TEV_COMP_A8_EQ = GX_TEV_COMP_RGB8_EQ -} GXTevOp; - -typedef enum { GX_TB_ZERO, GX_TB_ADDHALF, GX_TB_SUBHALF, GX_MAX_TEVBIAS } GXTevBias; - -typedef enum { GX_CS_SCALE_1, GX_CS_SCALE_2, GX_CS_SCALE_4, GX_CS_DIVIDE_2, GX_MAX_TEVSCALE } GXTevScale; - -typedef enum { - GX_TEV_KCSEL_8_8 = 0x00, - GX_TEV_KCSEL_7_8 = 0x01, - GX_TEV_KCSEL_6_8 = 0x02, - GX_TEV_KCSEL_5_8 = 0x03, - GX_TEV_KCSEL_4_8 = 0x04, - GX_TEV_KCSEL_3_8 = 0x05, - GX_TEV_KCSEL_2_8 = 0x06, - GX_TEV_KCSEL_1_8 = 0x07, - GX_TEV_KCSEL_1 = GX_TEV_KCSEL_8_8, - GX_TEV_KCSEL_3_4 = GX_TEV_KCSEL_6_8, - GX_TEV_KCSEL_1_2 = GX_TEV_KCSEL_4_8, - GX_TEV_KCSEL_1_4 = GX_TEV_KCSEL_2_8, - GX_TEV_KCSEL_K0 = 0x0C, - GX_TEV_KCSEL_K1 = 0x0D, - GX_TEV_KCSEL_K2 = 0x0E, - GX_TEV_KCSEL_K3 = 0x0F, - GX_TEV_KCSEL_K0_R = 0x10, - GX_TEV_KCSEL_K1_R = 0x11, - GX_TEV_KCSEL_K2_R = 0x12, - GX_TEV_KCSEL_K3_R = 0x13, - GX_TEV_KCSEL_K0_G = 0x14, - GX_TEV_KCSEL_K1_G = 0x15, - GX_TEV_KCSEL_K2_G = 0x16, - GX_TEV_KCSEL_K3_G = 0x17, - GX_TEV_KCSEL_K0_B = 0x18, - GX_TEV_KCSEL_K1_B = 0x19, - GX_TEV_KCSEL_K2_B = 0x1A, - GX_TEV_KCSEL_K3_B = 0x1B, - GX_TEV_KCSEL_K0_A = 0x1C, - GX_TEV_KCSEL_K1_A = 0x1D, - GX_TEV_KCSEL_K2_A = 0x1E, - GX_TEV_KCSEL_K3_A = 0x1F -} GXTevKColorSel; - -typedef enum { - GX_TEV_KASEL_8_8 = 0x00, - GX_TEV_KASEL_7_8 = 0x01, - GX_TEV_KASEL_6_8 = 0x02, - GX_TEV_KASEL_5_8 = 0x03, - GX_TEV_KASEL_4_8 = 0x04, - GX_TEV_KASEL_3_8 = 0x05, - GX_TEV_KASEL_2_8 = 0x06, - GX_TEV_KASEL_1_8 = 0x07, - GX_TEV_KASEL_1 = GX_TEV_KASEL_8_8, - GX_TEV_KASEL_3_4 = GX_TEV_KASEL_6_8, - GX_TEV_KASEL_1_2 = GX_TEV_KASEL_4_8, - GX_TEV_KASEL_1_4 = GX_TEV_KASEL_2_8, - GX_TEV_KASEL_K0_R = 0x10, - GX_TEV_KASEL_K1_R = 0x11, - GX_TEV_KASEL_K2_R = 0x12, - GX_TEV_KASEL_K3_R = 0x13, - GX_TEV_KASEL_K0_G = 0x14, - GX_TEV_KASEL_K1_G = 0x15, - GX_TEV_KASEL_K2_G = 0x16, - GX_TEV_KASEL_K3_G = 0x17, - GX_TEV_KASEL_K0_B = 0x18, - GX_TEV_KASEL_K1_B = 0x19, - GX_TEV_KASEL_K2_B = 0x1A, - GX_TEV_KASEL_K3_B = 0x1B, - GX_TEV_KASEL_K0_A = 0x1C, - GX_TEV_KASEL_K1_A = 0x1D, - GX_TEV_KASEL_K2_A = 0x1E, - GX_TEV_KASEL_K3_A = 0x1F -} GXTevKAlphaSel; - -typedef enum { GX_KCOLOR0 = 0, GX_KCOLOR1, GX_KCOLOR2, GX_KCOLOR3, GX_MAX_KCOLOR } GXTevKColorID; - -typedef enum { - GX_ZT_DISABLE, - GX_ZT_ADD, - GX_ZT_REPLACE, - GX_MAX_ZTEXOP, -} GXZTexOp; - -typedef enum { - GX_ITF_8, - GX_ITF_5, - GX_ITF_4, - GX_ITF_3, - GX_MAX_ITFORMAT, -} GXIndTexFormat; - -typedef enum { - GX_ITB_NONE, - GX_ITB_S, - GX_ITB_T, - GX_ITB_ST, - GX_ITB_U, - GX_ITB_SU, - GX_ITB_TU, - GX_ITB_STU, - GX_MAX_ITBIAS, -} GXIndTexBiasSel; - -typedef enum { - GX_ITBA_OFF, - GX_ITBA_S, - GX_ITBA_T, - GX_ITBA_U, - GX_MAX_ITBALPHA, -} GXIndTexAlphaSel; - -typedef enum { - GX_ITM_OFF, - GX_ITM_0, - GX_ITM_1, - GX_ITM_2, - GX_ITM_S0 = 5, - GX_ITM_S1, - GX_ITM_S2, - GX_ITM_T0 = 9, - GX_ITM_T1, - GX_ITM_T2, -} GXIndTexMtxID; - -typedef enum { - GX_ITW_OFF, - GX_ITW_256, - GX_ITW_128, - GX_ITW_64, - GX_ITW_32, - GX_ITW_16, - GX_ITW_0, - GX_MAX_ITWRAP, -} GXIndTexWrap; - -typedef enum { - GX_INDTEXSTAGE0, - GX_INDTEXSTAGE1, - GX_INDTEXSTAGE2, - GX_INDTEXSTAGE3, - GX_MAX_INDTEXSTAGE, -} GXIndTexStageID; - -typedef enum { - GX_ITS_1, - GX_ITS_2, - GX_ITS_4, - GX_ITS_8, - GX_ITS_16, - GX_ITS_32, - GX_ITS_64, - GX_ITS_128, - GX_ITS_256, - GX_MAX_ITSCALE, -} GXIndTexScale; - -typedef enum { - GX_PERF0_VERTICES, - GX_PERF0_CLIP_VTX, - GX_PERF0_CLIP_CLKS, - GX_PERF0_XF_WAIT_IN, - GX_PERF0_XF_WAIT_OUT, - GX_PERF0_XF_XFRM_CLKS, - GX_PERF0_XF_LIT_CLKS, - GX_PERF0_XF_BOT_CLKS, - GX_PERF0_XF_REGLD_CLKS, - GX_PERF0_XF_REGRD_CLKS, - GX_PERF0_CLIP_RATIO, - - GX_PERF0_TRIANGLES, - GX_PERF0_TRIANGLES_CULLED, - GX_PERF0_TRIANGLES_PASSED, - GX_PERF0_TRIANGLES_SCISSORED, - GX_PERF0_TRIANGLES_0TEX, - GX_PERF0_TRIANGLES_1TEX, - GX_PERF0_TRIANGLES_2TEX, - GX_PERF0_TRIANGLES_3TEX, - GX_PERF0_TRIANGLES_4TEX, - GX_PERF0_TRIANGLES_5TEX, - GX_PERF0_TRIANGLES_6TEX, - GX_PERF0_TRIANGLES_7TEX, - GX_PERF0_TRIANGLES_8TEX, - GX_PERF0_TRIANGLES_0CLR, - GX_PERF0_TRIANGLES_1CLR, - GX_PERF0_TRIANGLES_2CLR, - - GX_PERF0_QUAD_0CVG, - GX_PERF0_QUAD_NON0CVG, - GX_PERF0_QUAD_1CVG, - GX_PERF0_QUAD_2CVG, - GX_PERF0_QUAD_3CVG, - GX_PERF0_QUAD_4CVG, - GX_PERF0_AVG_QUAD_CNT, - - GX_PERF0_CLOCKS, - GX_PERF0_NONE, -} GXPerf0; - -typedef enum { - GX_PERF1_TEXELS, - GX_PERF1_TX_IDLE, - GX_PERF1_TX_REGS, - GX_PERF1_TX_MEMSTALL, - GX_PERF1_TC_CHECK1_2, - GX_PERF1_TC_CHECK3_4, - GX_PERF1_TC_CHECK5_6, - GX_PERF1_TC_CHECK7_8, - GX_PERF1_TC_MISS, - - GX_PERF1_VC_ELEMQ_FULL, - GX_PERF1_VC_MISSQ_FULL, - GX_PERF1_VC_MEMREQ_FULL, - GX_PERF1_VC_STATUS7, - GX_PERF1_VC_MISSREP_FULL, - GX_PERF1_VC_STREAMBUF_LOW, - GX_PERF1_VC_ALL_STALLS, - GX_PERF1_VERTICES, - - GX_PERF1_FIFO_REQ, - GX_PERF1_CALL_REQ, - GX_PERF1_VC_MISS_REQ, - GX_PERF1_CP_ALL_REQ, - - GX_PERF1_CLOCKS, - GX_PERF1_NONE, -} GXPerf1; - -typedef enum { - GX_VC_POS = 0, - GX_VC_NRM = 1, - GX_VC_CLR0 = 2, - GX_VC_CLR1 = 3, - GX_VC_TEX0 = 4, - GX_VC_TEX1 = 5, - GX_VC_TEX2 = 6, - GX_VC_TEX3 = 7, - GX_VC_TEX4 = 8, - GX_VC_TEX5 = 9, - GX_VC_TEX6 = 10, - GX_VC_TEX7 = 11, - GX_VC_ALL = 15, -} GXVCachePerf; - -typedef enum { - GX_CLIP_ENABLE = 0, - GX_CLIP_DISABLE = 1, -} GXClipMode; - -typedef enum { - GX_CLAMP_NONE = 0, - GX_CLAMP_TOP = 1, - GX_CLAMP_BOTTOM = 2, -} GXFBClamp; - -typedef enum { - GX_TLUT0 = 0, - GX_TLUT1 = 1, - GX_TLUT2 = 2, - GX_TLUT3 = 3, - GX_TLUT4 = 4, - GX_TLUT5 = 5, - GX_TLUT6 = 6, - GX_TLUT7 = 7, - GX_TLUT8 = 8, - GX_TLUT9 = 9, - GX_TLUT10 = 10, - GX_TLUT11 = 11, - GX_TLUT12 = 12, - GX_TLUT13 = 13, - GX_TLUT14 = 14, - GX_TLUT15 = 15, - GX_BIGTLUT0 = 16, - GX_BIGTLUT1 = 17, - GX_BIGTLUT2 = 18, - GX_BIGTLUT3 = 19, -} GXTlut; - -typedef enum { - GX_TL_IA8, - GX_TL_RGB565, - GX_TL_RGB5A3, - GX_MAX_TLUTFMT, -} GXTlutFmt; - -typedef enum { - GX_TLUT_16 = 1, - GX_TLUT_32 = 2, - GX_TLUT_64 = 4, - GX_TLUT_128 = 8, - GX_TLUT_256 = 16, - GX_TLUT_512 = 32, - GX_TLUT_1K = 64, - GX_TLUT_2K = 128, - GX_TLUT_4K = 256, - GX_TLUT_8K = 512, - GX_TLUT_16K = 1024, -} GXTlutSize; - -typedef enum { - GX_READ_00, - GX_READ_FF, - GX_READ_NONE, -} GXAlphaReadMode; - -typedef enum { - GX_TEXCACHE_32K, - GX_TEXCACHE_128K, - GX_TEXCACHE_512K, - GX_TEXCACHE_NONE, -} GXTexCacheSize; - -typedef enum { - GX_MT_XF_FLUSH = 1, - GX_MT_DL_SAVE_CONTEXT = 2, - GX_MT_NULL = 0, -} GXMiscToken; - -typedef enum { - GX_CMD_LOAD_INDX_A = 0x20, - GX_CMD_LOAD_INDX_B = 0x28, - GX_CMD_LOAD_INDX_C = 0x30, - GX_CMD_LOAD_INDX_D = 0x38, - - GX_CMD_LOAD_CP_REG = 0x08, - GX_CMD_LOAD_XF_REG = 0x10, - GX_CMD_LOAD_BP_REG = 0x61, -} GXCommand; - -typedef enum { - GX_CP_REG_MTXIDXA = 0x30, // Matrix index A - GX_CP_REG_MTXIDXB = 0x40, // Matrix index B - GX_CP_REG_VCD_LO = 0x50, // Vertex descriptor (lo) - GX_CP_REG_VCD_HI = 0x60, // Vertex descriptor (hi) - GX_CP_REG_VAT_GRP0 = 0x70, // Vertex attribute table (group 0) - GX_CP_REG_VAT_GRP1 = 0x80, // Vertex attribute table (group 1) - GX_CP_REG_VAT_GRP2 = 0x90, // Vertex attribute table (group 2) - GX_CP_REG_ARRAYBASE = 0xA0, // Vertex array start/base - GX_CP_REG_ARRAYSTRIDE = 0xB0, // Vertex array stride -} GXCPRegs; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXExtra.h b/aurora-main/include/dolphin/gx/GXExtra.h deleted file mode 100644 index 27713aa..0000000 --- a/aurora-main/include/dolphin/gx/GXExtra.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef DOLPHIN_GXEXTRA_H -#define DOLPHIN_GXEXTRA_H -// Extra types for PC -#ifdef TARGET_PC -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - float r; - float g; - float b; - float a; -} GXColorF32; - -void GXDestroyTexObj(GXTexObj* obj); -void GXDestroyTlutObj(GXTlutObj* obj); -void GXDestroyCopyTex(void* dest); - -void GXColor4f32(float r, float g, float b, float a); - -#ifdef __cplusplus -} -#endif -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXFifo.h b/aurora-main/include/dolphin/gx/GXFifo.h deleted file mode 100644 index 8edbf04..0000000 --- a/aurora-main/include/dolphin/gx/GXFifo.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef DOLPHIN_GXFIFO_H -#define DOLPHIN_GXFIFO_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - u8 pad[128]; -} GXFifoObj; - -typedef struct OSThread OSThread; - -void GXInitFifoBase(GXFifoObj* fifo, void* base, u32 size); -void GXInitFifoPtrs(GXFifoObj* fifo, void* readPtr, void* writePtr); -void GXGetFifoPtrs(GXFifoObj* fifo, void** readPtr, void** writePtr); -OSThread *GXSetCurrentGXThread(void); -OSThread *GXGetCurrentGXThread(void); -GXFifoObj* GXGetCPUFifo(void); -GXFifoObj* GXGetGPFifo(void); -void GXSetCPUFifo(GXFifoObj* fifo); -void GXSetGPFifo(GXFifoObj* fifo); -void GXSaveCPUFifo(GXFifoObj* fifo); -void GXGetFifoStatus(GXFifoObj* fifo, GXBool* overhi, GXBool* underlow, u32* fifoCount, GXBool* cpu_write, - GXBool* gp_read, GXBool* fifowrap); -void GXGetGPStatus(GXBool* overhi, GXBool* underlow, GXBool* readIdle, GXBool* cmdIdle, GXBool* brkpt); -void GXInitFifoLimits(GXFifoObj* fifo, u32 hiWaterMark, u32 loWaterMark); -void* GXGetFifoBase(const GXFifoObj* fifo); -u32 GXGetFifoSize(const GXFifoObj* fifo); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXFrameBuffer.h b/aurora-main/include/dolphin/gx/GXFrameBuffer.h deleted file mode 100644 index c289cd3..0000000 --- a/aurora-main/include/dolphin/gx/GXFrameBuffer.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef DOLPHIN_GXFRAMEBUFFER_H -#define DOLPHIN_GXFRAMEBUFFER_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define GX_MAX_Z24 0x00FFFFFF - -extern GXRenderModeObj GXNtsc240Ds; -extern GXRenderModeObj GXNtsc240DsAa; -extern GXRenderModeObj GXNtsc240Int; -extern GXRenderModeObj GXNtsc240IntAa; -extern GXRenderModeObj GXNtsc480IntDf; -extern GXRenderModeObj GXNtsc480Int; -extern GXRenderModeObj GXNtsc480IntAa; -extern GXRenderModeObj GXNtsc480Prog; -extern GXRenderModeObj GXNtsc480ProgAa; -extern GXRenderModeObj GXMpal240Ds; -extern GXRenderModeObj GXMpal240DsAa; -extern GXRenderModeObj GXMpal240Int; -extern GXRenderModeObj GXMpal240IntAa; -extern GXRenderModeObj GXMpal480IntDf; -extern GXRenderModeObj GXMpal480Int; -extern GXRenderModeObj GXMpal480IntAa; -extern GXRenderModeObj GXPal264Ds; -extern GXRenderModeObj GXPal264DsAa; -extern GXRenderModeObj GXPal264Int; -extern GXRenderModeObj GXPal264IntAa; -extern GXRenderModeObj GXPal528IntDf; -extern GXRenderModeObj GXPal528Int; -extern GXRenderModeObj GXPal528IntAa; - -void GXSetCopyClear(GXColor clear_clr, u32 clear_z); -void GXAdjustForOverscan(GXRenderModeObj* rmin, GXRenderModeObj* rmout, u16 hor, u16 ver); -void GXCopyDisp(void* dest, GXBool clear); -void GXSetDispCopyGamma(GXGamma gamma); -void GXSetDispCopySrc(u16 left, u16 top, u16 wd, u16 ht); -void GXSetDispCopyDst(u16 wd, u16 ht); -void GXSetCopyClamp(GXFBClamp clamp); -void GXSetDispCopyFrame2Field(u32 mode); -u32 GXSetDispCopyYScale(f32 vscale); -void GXSetCopyFilter(GXBool aa, u8 sample_pattern[12][2], GXBool vf, u8 vfilter[7]); -void GXSetPixelFmt(GXPixelFmt pix_fmt, GXZFmt16 z_fmt); -void GXSetTexCopySrc(u16 left, u16 top, u16 wd, u16 ht); -void GXSetTexCopyDst(u16 wd, u16 ht, GXTexFmt fmt, GXBool mipmap); -void GXCopyTex(void* dest, GXBool clear); -void GXClearBoundingBox(void); -void GXReadBoundingBox(u16* left, u16* right, u16* top, u16* bottom); -u16 GXGetNumXfbLines(u16 efbHeight, f32 yScale); -f32 GXGetYScaleFactor(u16 efbHeight, u16 xfbHeight); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXGeometry.h b/aurora-main/include/dolphin/gx/GXGeometry.h deleted file mode 100644 index a71eb74..0000000 --- a/aurora-main/include/dolphin/gx/GXGeometry.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef DOLPHIN_GXGEOMETRY_H -#define DOLPHIN_GXGEOMETRY_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void GXSetVtxDesc(GXAttr attr, GXAttrType type); -void GXSetSourceVtxDesc(GXAttr attr, GXAttrType type); -void GXSetVtxDescv(GXVtxDescList* list); -void GXClearVtxDesc(void); -void GXSetVtxAttrFmtv(GXVtxFmt vtxfmt, const GXVtxAttrFmtList* list); -void GXSetVtxAttrFmt(GXVtxFmt vtxfmt, GXAttr attr, GXCompCnt cnt, GXCompType type, u8 frac); -void GXSetNumTexGens(u8 nTexGens); -void GXBegin(GXPrimitive type, GXVtxFmt vtxfmt, u16 nverts); -void GXSetTexCoordGen2(GXTexCoordID dst_coord, GXTexGenType func, GXTexGenSrc src_param, u32 mtx, GXBool normalize, - u32 postmtx); -void GXSetLineWidth(u8 width, GXTexOffset texOffsets); -void GXSetPointSize(u8 pointSize, GXTexOffset texOffsets); -void GXEnableTexOffsets(GXTexCoordID coord, GXBool line_enable, GXBool point_enable); -#ifdef TARGET_PC -void GXSetArray(GXAttr attr, const void* data, u32 size, u8 stride, bool le); -static inline void GXSetArray(GXAttr attr, const void* data, u32 size, u8 stride) { - GXSetArray(attr, data, size, stride, false); -} -#define GXSETARRAY(attr, data, size, stride, le) GXSetArray((attr), (data), (size), (stride), (le)) -#else -void GXSetArray(GXAttr attr, const void* data, u8 stride); -#define GXSETARRAY(attr, data, size, stride, le) GXSetArray((attr), (data), (stride)) -#endif -void GXInvalidateVtxCache(void); - -static inline void GXSetTexCoordGen(GXTexCoordID dst_coord, GXTexGenType func, GXTexGenSrc src_param, u32 mtx) { - GXSetTexCoordGen2(dst_coord, func, src_param, mtx, GX_FALSE, GX_PTIDENTITY); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXGet.h b/aurora-main/include/dolphin/gx/GXGet.h deleted file mode 100644 index a1b7e1c..0000000 --- a/aurora-main/include/dolphin/gx/GXGet.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef DOLPHIN_GXGET_H -#define DOLPHIN_GXGET_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void GXGetVtxDesc(GXAttr attr, GXAttrType* type); -void GXGetVtxDescv(GXVtxDescList* vcd); -void GXGetVtxAttrFmtv(GXVtxFmt fmt, GXVtxAttrFmtList* vat); -void GXGetLineWidth(u8* width, GXTexOffset* texOffsets); -void GXGetPointSize(u8* pointSize, GXTexOffset* texOffsets); -void GXGetCullMode(GXCullMode* mode); -GXBool GXGetTexObjMipMap(GXTexObj* tex_obj); -GXTexFmt GXGetTexObjFmt(GXTexObj* tex_obj); -u16 GXGetTexObjHeight(GXTexObj* tex_obj); -u16 GXGetTexObjWidth(GXTexObj* tex_obj); -GXTexWrapMode GXGetTexObjWrapS(GXTexObj* tex_obj); -GXTexWrapMode GXGetTexObjWrapT(GXTexObj* tex_obj); -void* GXGetTexObjData(GXTexObj* tex_obj); -void GXGetProjectionv(f32* p); -void GXGetLightAttnA(GXLightObj* lt_obj, f32* a0, f32* a1, f32* a2); -void GXGetLightAttnK(GXLightObj* lt_obj, f32* k0, f32* k1, f32* k2); -void GXGetLightPos(GXLightObj* lt_obj, f32* x, f32* y, f32* z); -void GXGetLightDir(GXLightObj* lt_obj, f32* nx, f32* ny, f32* nz); -void GXGetLightColor(GXLightObj* lt_obj, GXColor* color); -void GXGetVtxAttrFmt(GXVtxFmt idx, GXAttr attr, GXCompCnt* compCnt, GXCompType* compType, u8* shift); -u32 GXGetTexObjTlut(const GXTexObj* tex_obj); - -void GXGetViewportv(f32* vp); -void GXGetScissor(u32* left, u32* top, u32* wd, u32* ht); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXLighting.h b/aurora-main/include/dolphin/gx/GXLighting.h deleted file mode 100644 index 2e7ff19..0000000 --- a/aurora-main/include/dolphin/gx/GXLighting.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef DOLPHIN_GXLIGHTING_H -#define DOLPHIN_GXLIGHTING_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void GXSetNumChans(u8 nChans); -void GXSetChanCtrl(GXChannelID chan, GXBool enable, GXColorSrc amb_src, GXColorSrc mat_src, u32 light_mask, - GXDiffuseFn diff_fn, GXAttnFn attn_fn); -void GXSetChanAmbColor(GXChannelID chan, GXColor amb_color); -void GXSetChanMatColor(GXChannelID chan, GXColor mat_color); - -void GXInitLightSpot(GXLightObj* lt_obj, f32 cutoff, GXSpotFn spot_func); -void GXInitLightDistAttn(GXLightObj* lt_obj, f32 ref_distance, f32 ref_brightness, GXDistAttnFn dist_func); -void GXInitLightPos(GXLightObj* lt_obj, f32 x, f32 y, f32 z); -void GXInitLightDir(GXLightObj* lt_obj, f32 nx, f32 ny, f32 nz); -void GXInitSpecularDir(GXLightObj* lt_obj, f32 nx, f32 ny, f32 nz); -void GXInitLightColor(GXLightObj* lt_obj, GXColor color); -void GXInitLightAttn(GXLightObj* lt_obj, f32 a0, f32 a1, f32 a2, f32 k0, f32 k1, f32 k2); -void GXInitLightAttnA(GXLightObj* lt_obj, f32 a0, f32 a1, f32 a2); -void GXInitLightAttnK(GXLightObj* lt_obj, f32 k0, f32 k1, f32 k2); -void GXLoadLightObjImm(GXLightObj* lt_obj, GXLightID light); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXManage.h b/aurora-main/include/dolphin/gx/GXManage.h deleted file mode 100644 index a4d7d72..0000000 --- a/aurora-main/include/dolphin/gx/GXManage.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef DOLPHIN_GXMANAGE_H -#define DOLPHIN_GXMANAGE_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*GXDrawSyncCallback)(u16 token); -typedef void (*GXDrawDoneCallback)(void); - -GXFifoObj* GXInit(void* base, u32 size); -GXDrawSyncCallback GXSetDrawSyncCallback(GXDrawSyncCallback cb); -GXDrawDoneCallback GXSetDrawDoneCallback(GXDrawDoneCallback cb); -void GXDrawDone(void); -void GXSetDrawDone(void); -void GXFlush(void); -void GXPixModeSync(void); -void GXTexModeSync(void); -void GXSetMisc(GXMiscToken token, u32 val); -void GXAbortFrame(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXPerf.h b/aurora-main/include/dolphin/gx/GXPerf.h deleted file mode 100644 index 7859e18..0000000 --- a/aurora-main/include/dolphin/gx/GXPerf.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef DOLPHIN_GXPERF_H -#define DOLPHIN_GXPERF_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void GXReadXfRasMetric(u32* xf_wait_in, u32* xf_wait_out, u32* ras_busy, u32* clocks); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXPixel.h b/aurora-main/include/dolphin/gx/GXPixel.h deleted file mode 100644 index db6d9d0..0000000 --- a/aurora-main/include/dolphin/gx/GXPixel.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef DOLPHIN_GXPIXEL_H -#define DOLPHIN_GXPIXEL_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void GXSetFog(GXFogType type, f32 startz, f32 endz, f32 nearz, f32 farz, GXColor color); -void GXSetFogColor(GXColor color); -void GXSetFogRangeAdj(GXBool enable, u16 center, GXFogAdjTable *table); -void GXSetBlendMode(GXBlendMode type, GXBlendFactor src_factor, GXBlendFactor dst_factor, GXLogicOp op); -void GXSetColorUpdate(GXBool update_enable); -void GXSetAlphaUpdate(GXBool update_enable); -void GXSetZMode(GXBool compare_enable, GXCompare func, GXBool update_enable); -void GXSetZCompLoc(GXBool before_tex); -void GXSetPixelFmt(GXPixelFmt pix_fmt, GXZFmt16 z_fmt); -void GXSetDither(GXBool dither); -void GXSetDstAlpha(GXBool enable, u8 alpha); -void GXSetFieldMask(GXBool odd_mask, GXBool even_mask); -void GXSetFieldMode(GXBool field_mode, GXBool half_aspect_ratio); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXStruct.h b/aurora-main/include/dolphin/gx/GXStruct.h deleted file mode 100644 index fc7b16a..0000000 --- a/aurora-main/include/dolphin/gx/GXStruct.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef DOLPHIN_GXSTRUCT_H -#define DOLPHIN_GXSTRUCT_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define VI_TVMODE(format, interlace) (((format) << 2) + (interlace)) - -#define VI_INTERLACE 0 -#define VI_NON_INTERLACE 1 -#define VI_PROGRESSIVE 2 - -#define VI_NTSC 0 -#define VI_PAL 1 -#define VI_MPAL 2 -#define VI_DEBUG 3 -#define VI_DEBUG_PAL 4 -#define VI_EURGB60 5 - -typedef enum { - VI_TVMODE_NTSC_INT = VI_TVMODE(VI_NTSC, VI_INTERLACE), - VI_TVMODE_NTSC_DS = VI_TVMODE(VI_NTSC, VI_NON_INTERLACE), - VI_TVMODE_NTSC_PROG = VI_TVMODE(VI_NTSC, VI_PROGRESSIVE), - VI_TVMODE_PAL_INT = VI_TVMODE(VI_PAL, VI_INTERLACE), - VI_TVMODE_PAL_DS = VI_TVMODE(VI_PAL, VI_NON_INTERLACE), - VI_TVMODE_EURGB60_INT = VI_TVMODE(VI_EURGB60, VI_INTERLACE), - VI_TVMODE_EURGB60_DS = VI_TVMODE(VI_EURGB60, VI_NON_INTERLACE), - VI_TVMODE_MPAL_INT = VI_TVMODE(VI_MPAL, VI_INTERLACE), - VI_TVMODE_MPAL_DS = VI_TVMODE(VI_MPAL, VI_NON_INTERLACE), - VI_TVMODE_DEBUG_INT = VI_TVMODE(VI_DEBUG, VI_INTERLACE), - VI_TVMODE_DEBUG_PAL_INT = VI_TVMODE(VI_DEBUG_PAL, VI_INTERLACE), - VI_TVMODE_DEBUG_PAL_DS = VI_TVMODE(VI_DEBUG_PAL, VI_NON_INTERLACE) -} VITVMode; - -typedef enum { VI_XFBMODE_SF = 0, VI_XFBMODE_DF } VIXFBMode; - -typedef struct { - /*0x00*/ VITVMode viTVmode; - /*0x04*/ u16 fbWidth; - /*0x06*/ u16 efbHeight; - /*0x08*/ u16 xfbHeight; - /*0x0A*/ u16 viXOrigin; - /*0x0C*/ u16 viYOrigin; - /*0x0E*/ u16 viWidth; - /*0x10*/ u16 viHeight; - /*0x14*/ VIXFBMode xFBmode; - /*0x18*/ u8 field_rendering; - u8 aa; - u8 sample_pattern[12][2]; - u8 vfilter[7]; -} GXRenderModeObj; - -typedef struct { - u8 r; - u8 g; - u8 b; - u8 a; -} GXColor; - -typedef struct { -#ifdef TARGET_PC - u32 dummy[24]; -#else - u32 dummy[8]; -#endif -} GXTexObj; - -typedef struct { -#ifdef TARGET_PC - u32 dummy[12]; -#else - u32 dummy[3]; -#endif -} GXTlutObj; - -typedef struct { - u32 dummy[16]; -} GXLightObj; - -typedef struct { - GXAttr attr; - GXAttrType type; -} GXVtxDescList; - -typedef struct { - GXAttr attr; - GXCompCnt cnt; - GXCompType type; - u8 frac; -} GXVtxAttrFmtList; - -typedef struct { - s16 r; - s16 g; - s16 b; - s16 a; -} GXColorS10; - -typedef struct _GXTexRegion { - u32 dummy[4]; -} GXTexRegion; - -typedef struct _GXTlutRegion { - u32 dummy[4]; -} GXTlutRegion; - -typedef struct _GXFogAdjTable -{ - u16 r[10]; -} GXFogAdjTable; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXTev.h b/aurora-main/include/dolphin/gx/GXTev.h deleted file mode 100644 index dccd4d5..0000000 --- a/aurora-main/include/dolphin/gx/GXTev.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef DOLPHIN_GXTEV_H -#define DOLPHIN_GXTEV_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void GXSetTevOp(GXTevStageID id, GXTevMode mode); -void GXSetTevColorIn(GXTevStageID stage, GXTevColorArg a, GXTevColorArg b, GXTevColorArg c, GXTevColorArg d); -void GXSetTevAlphaIn(GXTevStageID stage, GXTevAlphaArg a, GXTevAlphaArg b, GXTevAlphaArg c, GXTevAlphaArg d); -void GXSetTevColorOp(GXTevStageID stage, GXTevOp op, GXTevBias bias, GXTevScale scale, GXBool clamp, - GXTevRegID out_reg); -void GXSetTevAlphaOp(GXTevStageID stage, GXTevOp op, GXTevBias bias, GXTevScale scale, GXBool clamp, - GXTevRegID out_reg); -void GXSetTevColor(GXTevRegID id, GXColor color); -void GXSetTevColorS10(GXTevRegID id, GXColorS10 color); -void GXSetTevKColor(GXTevKColorID id, GXColor color); -void GXSetTevKColorSel(GXTevStageID stage, GXTevKColorSel sel); -void GXSetTevKAlphaSel(GXTevStageID stage, GXTevKAlphaSel sel); -void GXSetTevSwapMode(GXTevStageID stage, GXTevSwapSel ras_sel, GXTevSwapSel tex_sel); -void GXSetTevSwapModeTable(GXTevSwapSel table, GXTevColorChan red, GXTevColorChan green, GXTevColorChan blue, - GXTevColorChan alpha); -void GXSetAlphaCompare(GXCompare comp0, u8 ref0, GXAlphaOp op, GXCompare comp1, u8 ref1); -void GXSetZTexture(GXZTexOp op, GXTexFmt fmt, u32 bias); -void GXSetTevOrder(GXTevStageID stage, GXTexCoordID coord, GXTexMapID map, GXChannelID color); -void GXSetNumTevStages(u8 nStages); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXTexture.h b/aurora-main/include/dolphin/gx/GXTexture.h deleted file mode 100644 index 5e7afc8..0000000 --- a/aurora-main/include/dolphin/gx/GXTexture.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef DOLPHIN_GXTEXTURE_H -#define DOLPHIN_GXTEXTURE_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef GXTexRegion* (*GXTexRegionCallback)(const GXTexObj* obj, GXTexMapID id); - -void GXInitTexObj(GXTexObj* obj, const void* data, u16 width, u16 height, GXTexFmt format, GXTexWrapMode wrapS, - GXTexWrapMode wrapT, GXBool mipmap); -void GXInitTexObjCI(GXTexObj* obj, const void* data, u16 width, u16 height, GXCITexFmt format, GXTexWrapMode wrapS, - GXTexWrapMode wrapT, GXBool mipmap, u32 tlut); -void GXInitTexObjData(GXTexObj* obj, const void* data); -void GXInitTexObjLOD(GXTexObj* obj, GXTexFilter min_filt, GXTexFilter mag_filt, f32 min_lod, f32 max_lod, f32 lod_bias, - GXBool bias_clamp, GXBool do_edge_lod, GXAnisotropy max_aniso); -void GXInitTexObjFilter(GXTexObj* obj, GXTexFilter min_filt, GXTexFilter mag_filt); -void GXInitTexObjMaxLOD(GXTexObj* obj, f32 max_lod); -void GXInitTexObjMinLOD(GXTexObj* obj, f32 min_lod); -void GXInitTexObjLODBias(GXTexObj* obj, f32 lod_bias); -void GXInitTexObjBiasClamp(GXTexObj* obj, GXBool bias_clamp); -void GXInitTexObjEdgeLOD(GXTexObj* obj, GXBool do_edge_lod); -void GXInitTexObjMaxAniso(GXTexObj* obj, GXAnisotropy max_aniso); -void GXInitTexObjUserData(GXTexObj* obj, void* user_data); -void* GXGetTexObjUserData(const GXTexObj* obj); -void GXInitTexObjTlut(GXTexObj* obj_, u32 tlut); -void GXLoadTexObj(GXTexObj* obj, GXTexMapID id); -u32 GXGetTexBufferSize(u16 width, u16 height, u32 format, GXBool mipmap, u8 max_lod); -void GXInvalidateTexAll(); -void GXInitTexObjWrapMode(GXTexObj* obj, GXTexWrapMode s, GXTexWrapMode t); -void GXInitTlutObj(GXTlutObj* obj, const void* data, GXTlutFmt format, u16 entries); -void GXInitTlutObjData(GXTlutObj* obj, const void* data); -void GXLoadTlut(const GXTlutObj* obj, u32 idx); -void GXSetTexCoordScaleManually(GXTexCoordID coord, GXBool enable, u16 ss, u16 ts); -void GXSetTexCoordCylWrap(GXTexCoordID coord, GXBool s_enable, GXBool t_enable); -void GXSetTexCoordBias(GXTexCoordID coord, GXBool s_enable, GXBool t_enable); -void GXInitTexCacheRegion(GXTexRegion* region, GXBool is_32b_mipmap, u32 tmem_even, GXTexCacheSize size_even, - u32 tmem_odd, GXTexCacheSize size_odd); -GXTexRegionCallback GXSetTexRegionCallback(GXTexRegionCallback callback); -void GXInvalidateTexRegion(const GXTexRegion* region); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXTransform.h b/aurora-main/include/dolphin/gx/GXTransform.h deleted file mode 100644 index d961e5a..0000000 --- a/aurora-main/include/dolphin/gx/GXTransform.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef DOLPHIN_GXTRANSFORM_H -#define DOLPHIN_GXTRANSFORM_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define GX_PROJECTION_SZ 7 - -void GXProject(f32 x, f32 y, f32 z, const f32 mtx[3][4], const f32* pm, const f32* vp, f32* sx, f32* sy, f32* sz); -void GXSetProjectionv(const f32* ptr); - -#ifdef TARGET_PC -void GXSetProjection(const void* mtx, GXProjectionType type); -void GXLoadPosMtxImm(const void* mtx, u32 id); -void GXLoadNrmMtxImm(const void* mtx, u32 id); -void GXLoadTexMtxImm(const void* mtx, u32 id, GXTexMtxType type); -#else -void GXSetProjection(f32 mtx[4][4], GXProjectionType type); -void GXLoadPosMtxImm(f32 mtx[3][4], u32 id); -void GXLoadNrmMtxImm(f32 mtx[3][4], u32 id); -void GXLoadTexMtxImm(f32 mtx[][4], u32 id, GXTexMtxType type); -#endif -void GXSetViewport(f32 left, f32 top, f32 wd, f32 ht, f32 nearz, f32 farz); -void GXSetCurrentMtx(u32 id); -void GXSetViewportJitter(f32 left, f32 top, f32 wd, f32 ht, f32 nearz, f32 farz, u32 field); -void GXSetZScaleOffset(f32 scale, f32 offset); -void GXSetScissorBoxOffset(s32 x_off, s32 y_off); -void GXSetClipMode(GXClipMode mode); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/gx/GXVert.h b/aurora-main/include/dolphin/gx/GXVert.h deleted file mode 100644 index 355231c..0000000 --- a/aurora-main/include/dolphin/gx/GXVert.h +++ /dev/null @@ -1,150 +0,0 @@ -#ifndef DOLPHIN_GXVERT_H -#define DOLPHIN_GXVERT_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define GXFIFO_ADDR 0xCC008000 - -typedef union { - u8 u8; - u16 u16; - u32 u32; - u64 u64; - s8 s8; - s16 s16; - s32 s32; - s64 s64; - f32 f32; - f64 f64; -} PPCWGPipe; - -#ifdef __MWERKS__ -volatile PPCWGPipe GXWGFifo : GXFIFO_ADDR; -#else -#define GXWGFifo (*(volatile PPCWGPipe*)GXFIFO_ADDR) -#endif - -#ifdef TARGET_PC - -void GXPosition3f32(f32 x, f32 y, f32 z); -void GXPosition3u16(u16 x, u16 y, u16 z); -void GXPosition3s16(s16 x, s16 y, s16 z); -void GXPosition3u8(u8 x, u8 y, u8 z); -void GXPosition3s8(s8 x, s8 y, s8 z); - -void GXPosition2f32(f32 x, f32 y); -void GXPosition2u16(u16 x, u16 y); -void GXPosition2s16(s16 x, s16 y); -void GXPosition2u8(u8 x, u8 y); -void GXPosition2s8(s8 x, s8 y); - -void GXPosition1x16(u16 index); -void GXPosition1x8(u8 index); - -void GXNormal3f32(f32 x, f32 y, f32 z); -void GXNormal3u16(u16 x, u16 y, u16 z); -void GXNormal3s16(s16 x, s16 y, s16 z); -void GXNormal3u8(u8 x, u8 y, u8 z); -void GXNormal3s8(s8 x, s8 y, s8 z); - -void GXNormal1x16(u16 index); -void GXNormal1x8(u8 index); - -void GXColor4u8(u8 r, u8 g, u8 b, u8 a); - -void GXColor3u8(u8 r, u8 g, u8 b); - -void GXColor1u32(u32 clr); -void GXColor1u16(u16 clr); - -void GXColor1x16(u16 index); -void GXColor1x8(u8 index); - -void GXTexCoord2f32(f32 s, f32 t); -void GXTexCoord2u16(u16 s, u16 t); -void GXTexCoord2s16(s16 s, s16 t); -void GXTexCoord2u8(u8 s, u8 t); -void GXTexCoord2s8(s8 s, s8 t); - -void GXTexCoord1f32(f32 s); -void GXTexCoord1u16(u16 s); -void GXTexCoord1s16(s16 s); -void GXTexCoord1u8(u8 s); -void GXTexCoord1s8(s8 s); - -void GXTexCoord1x16(u16 index); -void GXTexCoord1x8(u8 index); - -extern void GXEnd(void); - -#else - -static inline void GXPosition2f32(const f32 x, const f32 y) { - GXWGFifo.f32 = x; - GXWGFifo.f32 = y; -} - -static inline void GXPosition3s16(const s16 x, const s16 y, const s16 z) { - GXWGFifo.s16 = x; - GXWGFifo.s16 = y; - GXWGFifo.s16 = z; -} - -static inline void GXPosition3f32(const f32 x, const f32 y, const f32 z) { - GXWGFifo.f32 = x; - GXWGFifo.f32 = y; - GXWGFifo.f32 = z; -} - -static inline void GXNormal3f32(const f32 x, const f32 y, const f32 z) { - GXWGFifo.f32 = x; - GXWGFifo.f32 = y; - GXWGFifo.f32 = z; -} - -static inline void GXColor4u8(const u8 r, const u8 g, const u8 b, const u8 a) { - GXWGFifo.u8 = r; - GXWGFifo.u8 = g; - GXWGFifo.u8 = b; - GXWGFifo.u8 = a; -} - -static inline void GXTexCoord2s16(const s16 u, const s16 v) { - GXWGFifo.s16 = u; - GXWGFifo.s16 = v; -} - -static inline void GXTexCoord2f32(const f32 u, const f32 v) { - GXWGFifo.f32 = u; - GXWGFifo.f32 = v; -} - -static inline void GXEnd(void) {} - -#endif - -void GXCmd1u8(const u8 x); -void GXCmd1u16(const u16 x); -void GXCmd1u32(const u32 x); -void GXCmd1u64(const u64 x); - -void GXParam1u8(const u8 x); -void GXParam1u16(const u16 x); -void GXParam1u32(const u32 x); -void GXParam1s8(const s8 x); -void GXParam1s16(const s16 x); -void GXParam1s32(const s32 x); -void GXParam1f32(const f32 x); -void GXParam3f32(const f32 x, const f32 y, const f32 z); -void GXParam4f32(const f32 x, const f32 y, const f32 z, const f32 w); -void GXMatrixIndex1u8(GXAttr attr, u8 index); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/hio.h b/aurora-main/include/dolphin/hio.h deleted file mode 100644 index dc83ee1..0000000 --- a/aurora-main/include/dolphin/hio.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _DOLPHIN_HIO_H_ -#define _DOLPHIN_HIO_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*HIOCallback)(void); -typedef BOOL (*HIOEnumCallback)(s32 chan); - -BOOL HIOEnumDevices(HIOEnumCallback callback); -BOOL HIOInit(s32 chan, HIOCallback callback); -BOOL HIOInitEx(s32 chan, u32 dev, HIOCallback callback); -BOOL HIOReadMailbox(u32* word); -BOOL HIOWriteMailbox(u32 word); -BOOL HIORead(u32 addr, void* buffer, s32 size); -BOOL HIOWrite(u32 addr, void* buffer, s32 size); -BOOL HIOReadAsync(u32 addr, void* buffer, s32 size, HIOCallback callback); -BOOL HIOWriteAsync(u32 addr, void* buffer, s32 size, HIOCallback callback); -BOOL HIOReadStatus(u32* status); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/hio2.h b/aurora-main/include/dolphin/hio2.h deleted file mode 100644 index 46b873c..0000000 --- a/aurora-main/include/dolphin/hio2.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _REVOLUTION_HIO2_H_ -#define _REVOLUTION_HIO2_H_ - -// Actually from revolution but who cares? -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - HIO2_DEVICE_INVALID = -1, - HIO2_DEVICE_UNK_0 = 0, - HIO2_DEVICE_UNK_1 = 1, - HIO2_DEVICE_UNK_2 = 2, -} HIO2DeviceType; - -typedef BOOL (*HIO2EnumCallback)(HIO2DeviceType); -typedef void (*HIO2UnkCallback)(s32); -typedef void (*HIO2DisconnectCallback)(s32); - -typedef struct HIO2Control { - /* 0x00 */ HIO2DeviceType type; - /* 0x04 */ s32 chan; - /* 0x08 */ u32 _0x8; - /* 0x0C */ HIO2UnkCallback exiCallback; - /* 0x10 */ HIO2UnkCallback _0x10; - /* 0x14 */ HIO2UnkCallback _0x14; - /* 0x18 */ HIO2DisconnectCallback disconnectCb; -} HIO2Control; // size 0x1C - - -BOOL HIO2Init(void); -BOOL HIO2EnumDevices(HIO2EnumCallback callback); -s32 HIO2Open(HIO2DeviceType type, HIO2UnkCallback exiCb, HIO2DisconnectCallback disconnectCb); -BOOL HIO2Close(s32 handle); -BOOL HIO2Read(s32 handle, u32 addr, void* buffer, s32 size); -BOOL HIO2Write(s32 handle, u32 addr, void* buffer, s32 size); -void HIO2Exit(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/hw_regs.h b/aurora-main/include/dolphin/hw_regs.h deleted file mode 100644 index 1f5700a..0000000 --- a/aurora-main/include/dolphin/hw_regs.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef _DOLPHIN_HW_REGS_H_ -#define _DOLPHIN_HW_REGS_H_ - -#include - -#ifdef __MWERKS__ -volatile u16 __VIRegs[59] AT_ADDRESS(0xCC002000); -volatile u32 __PIRegs[12] AT_ADDRESS(0xCC003000); -volatile u16 __MEMRegs[64] AT_ADDRESS(0xCC004000); -volatile u16 __DSPRegs[] AT_ADDRESS(0xCC005000); -volatile u32 __DIRegs[] AT_ADDRESS(0xCC006000); -volatile u32 __SIRegs[0x100] AT_ADDRESS(0xCC006400); -volatile u32 __EXIRegs[0x40] AT_ADDRESS(0xCC006800); -volatile u32 __AIRegs[8] AT_ADDRESS(0xCC006C00); -#else -#define __VIRegs ((volatile u16 *)0xCC002000) -#define __PIRegs ((volatile u32 *)0xCC003000) -#define __MEMRegs ((volatile u16 *)0xCC004000) -#define __DSPRegs ((volatile u16 *)0xCC005000) -#define __DIRegs ((volatile u32 *)0xCC006000) -#define __SIRegs ((volatile u32 *)0xCC006400) -#define __EXIRegs ((volatile u32 *)0xCC006800) -#define __AIRegs ((volatile u32 *)0xCC006C00) -#endif - -// Offsets for __VIRegs - -// offsets for __VIRegs[i] -#define VI_VERT_TIMING (0) -#define VI_DISP_CONFIG (1) -#define VI_HORIZ_TIMING_0L (2) -#define VI_HORIZ_TIMING_0U (3) -#define VI_HORIZ_TIMING_1L (4) -#define VI_HORIZ_TIMING_1U (5) -#define VI_VERT_TIMING_ODD (6) -#define VI_VERT_TIMING_ODD_U (7) -#define VI_VERT_TIMING_EVEN (8) -#define VI_VERT_TIMING_EVEN_U (9) - -#define VI_BBI_ODD (10) // burst blanking interval -#define VI_BBI_ODD_U (11) // burst blanking interval -#define VI_BBI_EVEN (12) // burst blanking interval -#define VI_BBI_EVEN_U (13) // burst blanking interval - -#define VI_TOP_FIELD_BASE_LEFT (14) // top in 2d, top of left pic in 3d -#define VI_TOP_FIELD_BASE_LEFT_U (15) // top in 2d, top of left pic in 3d - -#define VI_TOP_FIELD_BASE_RIGHT (16) // top of right pic in 3d -#define VI_TOP_FIELD_BASE_RIGHT_U (17) // top of right pic in 3d - -#define VI_BTTM_FIELD_BASE_LEFT (18) // bottom in 2d, bottom of left pic in 3d -#define VI_BTTM_FIELD_BASE_LEFT_U (19) // bottom in 2d, bottom of left pic in 3d - -#define VI_BTTM_FIELD_BASE_RIGHT (20) // bottom of right pic in 3d -#define VI_BTTM_FIELD_BASE_RIGHT_U (21) // bottom of right pic in 3d - -#define VI_VERT_COUNT (22) // vertical display position -#define VI_HORIZ_COUNT (23) // horizontal display position - -#define VI_DISP_INT_0 (24) // display interrupt 0L -#define VI_DISP_INT_0U (25) // display interrupt 0U -#define VI_DISP_INT_1 (26) // display interrupt 1L -#define VI_DISP_INT_1U (27) // display interrupt 1U -#define VI_DISP_INT_2 (28) // display interrupt 2L -#define VI_DISP_INT_2U (29) // display interrupt 2U -#define VI_DISP_INT_3 (30) // display interrupt 3L -#define VI_DISP_INT_3U (31) // display interrupt 3U - -#define VI_HSW (36) // horizontal scaling width -#define VI_HSR (37) // horizontal scaling register - -#define VI_FCT_0 (38) // filter coefficient table 0L -#define VI_FCT_0U (39) // filter coefficient table 0U -#define VI_FCT_1 (40) // filter coefficient table 1L -#define VI_FCT_1U (41) // filter coefficient table 1U -#define VI_FCT_2 (42) // filter coefficient table 2L -#define VI_FCT_2U (43) // filter coefficient table 2U -#define VI_FCT_3 (44) // filter coefficient table 3L -#define VI_FCT_3U (45) // filter coefficient table 3U -#define VI_FCT_4 (46) // filter coefficient table 4L -#define VI_FCT_4U (47) // filter coefficient table 4U -#define VI_FCT_5 (48) // filter coefficient table 5L -#define VI_FCT_5U (49) // filter coefficient table 5U -#define VI_FCT_6 (50) // filter coefficient table 6L -#define VI_FCT_6U (51) // filter coefficient table 6U - -#define VI_CLOCK_SEL (54) // clock select -#define VI_DTV_STAT (55) // DTV status - -#define VI_WIDTH (56) - -// offsets for __DSPRegs[i] -#define DSP_MAILBOX_IN_HI (0) -#define DSP_MAILBOX_IN_LO (1) -#define DSP_MAILBOX_OUT_HI (2) -#define DSP_MAILBOX_OUT_LO (3) -#define DSP_CONTROL_STATUS (5) - -#define DSP_ARAM_SIZE (9) -#define DSP_ARAM_MODE (11) -#define DSP_ARAM_REFRESH (13) -#define DSP_ARAM_DMA_MM_HI (16) // Main mem address -#define DSP_ARAM_DMA_MM_LO (17) -#define DSP_ARAM_DMA_ARAM_HI (18) // ARAM address -#define DSP_ARAM_DMA_ARAM_LO (19) -#define DSP_ARAM_DMA_SIZE_HI (20) // DMA buffer size -#define DSP_ARAM_DMA_SIZE_LO (21) - -#define DSP_DMA_START_HI (24) // DMA start address -#define DSP_DMA_START_LO (25) -#define DSP_DMA_CONTROL_LEN (27) -#define DSP_DMA_BYTES_LEFT (29) - -#define DSP_DMA_START_FLAG (0x8000) // set to start DSP - -#endif diff --git a/aurora-main/include/dolphin/ms.h b/aurora-main/include/dolphin/ms.h deleted file mode 100644 index 0cd4c55..0000000 --- a/aurora-main/include/dolphin/ms.h +++ /dev/null @@ -1,35 +0,0 @@ -// Aurora exclusive API extension -// While the GC and Wii could both technically support mice, they never received official libraries -// This library is a theoretical implementation based loosely on PAD -#ifndef DOLPHIN_MS_H -#define DOLPHIN_MS_H -#include "types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct MSStatus { - f32 x; - f32 y; - f32 xrel; - f32 yrel; - u32 buttons; - f32 scrollX; - f32 scrollY; -} MSStatus; - -#define MS_BUTTON_LEFT (1 << 0) -#define MS_BUTTON_MIDDLE (1 << 1) -#define MS_BUTTON_RIGHT (1 << 2) -#define MS_BUTTON_X1 (1 << 3) -#define MS_BUTTON_X2 (1 << 4) - -void MSPoll(); -void MSRead(MSStatus* status); - -#ifdef __cplusplus -} -#endif - -#endif // DUSK_MS_H diff --git a/aurora-main/include/dolphin/mtx.h b/aurora-main/include/dolphin/mtx.h deleted file mode 100644 index 7172615..0000000 --- a/aurora-main/include/dolphin/mtx.h +++ /dev/null @@ -1,385 +0,0 @@ -#ifndef _DOLPHIN_MTX -#define _DOLPHIN_MTX - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if !defined(MTX_USE_PS) && !defined(MTX_USE_C) && !defined(GEKKO) -#define MTX_USE_C -#endif - -#if !defined(MTX_USE_PS) && !defined(MTX_USE_C) && defined(GEKKO) -#ifndef _DEBUG -#define MTX_USE_PS -#endif -#endif - -#define MTX_PTR_OFFSET 3 - -#define MTX44_PTR_OFFSET 4 - -typedef struct { - u32 numMtx; - MtxPtr stackBase; - MtxPtr stackPtr; -} MTXStack, MtxStack, *MtxStackPtr; - -#define MTXDegToRad(a) ((a)*0.01745329252f) -#define MTXRadToDeg(a) ((a)*57.29577951f) -#define MTXRowCol(m, r, c) ((m)[(r)][(c)]) - -void C_MTXIdentity(Mtx m); -void C_MTXCopy(const Mtx src, Mtx dst); -void C_MTXConcat(const Mtx a, const Mtx b, Mtx ab); -void C_MTXConcatArray(const Mtx a, const Mtx* srcBase, Mtx* dstBase, u32 count); -void C_MTXTranspose(const Mtx src, Mtx xPose); -u32 C_MTXInverse(const Mtx src, Mtx inv); -u32 C_MTXInvXpose(const Mtx src, Mtx invX); - -#ifdef GEKKO -void PSMTXIdentity(Mtx m); -void PSMTXCopy(const Mtx src, Mtx dst); -void PSMTXConcat(const Mtx a, const Mtx b, Mtx ab); -void PSMTXConcatArray(const Mtx a, const Mtx* srcBase, Mtx* dstBase, u32 count); -void PSMTXTranspose(const Mtx src, Mtx xPose); -u32 PSMTXInverse(const Mtx src, Mtx inv); -u32 PSMTXInvXpose(const Mtx src, Mtx invX); -#else -#define PSMTXIdentity MTXIdentity -#define PSMTXCopy MTXCopy -#define PSMTXConcat MTXConcat -#define PSMTXConcatArray MTXConcatArray -#define PSMTXTranspose MTXTranspose -#define PSMTXInverse MTXInverse -#define PSMTXInvXpose MTXInvXpose -#endif - -#ifdef MTX_USE_PS -#define MTXIdentity C_MTXIdentity -#define MTXCopy C_MTXCopy -#define MTXConcat C_MTXConcat -#define MTXConcatArray C_MTXConcatArray -#define MTXTranspose C_MTXTranspose -#define MTXInverse C_MTXInverse -#define MTXInvXpose C_MTXInvXpose -#else -#define MTXIdentity C_MTXIdentity -#define MTXCopy C_MTXCopy -#define MTXConcat C_MTXConcat -#define MTXConcatArray C_MTXConcatArray -#define MTXTranspose C_MTXTranspose -#define MTXInverse C_MTXInverse -#define MTXInvXpose C_MTXInvXpose -#endif - -void C_MTXMultVec(const Mtx m, const Vec* src, Vec* dst); -void C_MTXMultVecArray(const Mtx m, const Vec* srcBase, Vec* dstBase, u32 count); -void C_MTXMultVecSR(const Mtx m, const Vec* src, Vec* dst); -void C_MTXMultVecArraySR(const Mtx m, const Vec* srcBase, Vec* dstBase, u32 count); -void C_MTXROMultVecArray(const ROMtx m, const Vec *srcBase, Vec *dstBase, u32 count); - -#ifdef GEKKO -void PSMTXMultVec(const Mtx m, const Vec* src, Vec* dst); -void PSMTXMultVecArray(const Mtx m, const Vec* srcBase, Vec* dstBase, u32 count); -void PSMTXMultVecSR(const Mtx m, const Vec* src, Vec* dst); -void PSMTXMultVecArraySR(const Mtx m, const Vec* srcBase, Vec* dstBase, u32 count); -void PSMTXMultS16VecArray(const Mtx m, const S16Vec* srcBase, Vec* dstBase, u32 count); - -void PSMTXROMultVecArray(const ROMtx m, const Vec *srcBase, Vec *dstBase, u32 count); -void PSMTXROSkin2VecArray(const ROMtx m0, const ROMtx m1, const f32* wtBase, const Vec* srcBase, - Vec* dstBase, u32 count); -void PSMTXROMultS16VecArray(const ROMtx m, const S16Vec* srcBase, Vec* dstBase, u32 count); -#else -#define PSMTXMultVec MTXMultVec -#define PSMTXMultVecArray MTXMultVecArray -#define PSMTXMultVecSR MTXMultVecSR -#define PSMTXMultVecArraySR MTXMultVecArraySR -#define PSMTXMultS16VecArray MTXMultS16VecArray - -#define PSMTXROMultVecArray MTXROMultVecArray -#define PSMTXROSkin2VecArray MTXROSkin2VecArray -#define PSMTXROMultS16VecArray MTXROMultS16VecArray -#endif - -#ifdef MTX_USE_PS -#define MTXMultVec C_MTXMultVec -#define MTXMultVecArray C_MTXMultVecArray -#define MTXMultVecSR C_MTXMultVecSR -#define MTXMultVecArraySR C_MTXMultVecArraySR -#define MTXMultS16VecArray PSMTXMultS16VecArray - -#define MTXROMultVecArray C_MTXROMultVecArray -#define MTXROSkin2VecArray PSMTXROSkin2VecArray -#define MTXROMultS16VecArray PSMTXROMultS16VecArray -#else // MTX_USE_C -#define MTXMultVec C_MTXMultVec -#define MTXMultVecArray C_MTXMultVecArray -#define MTXMultVecSR C_MTXMultVecSR -#define MTXMultVecArraySR C_MTXMultVecArraySR - -#define MTXROMultVecArray C_MTXROMultVecArray -#endif - -void C_MTXQuat(Mtx m, const Quaternion* q); -void C_MTXReflect(Mtx m, const Vec* p, const Vec* n); - -void C_MTXTrans(Mtx m, f32 xT, f32 yT, f32 zT); -void C_MTXTransApply(const Mtx src, Mtx dst, f32 xT, f32 yT, f32 zT); -void C_MTXScale(Mtx m, f32 xS, f32 yS, f32 zS); -void C_MTXScaleApply(const Mtx src, Mtx dst, f32 xS, f32 yS, f32 zS); - -void C_MTXRotRad(Mtx m, char axis, f32 rad); -void C_MTXRotTrig(Mtx m, char axis, f32 sinA, f32 cosA); -void C_MTXRotAxisRad(Mtx m, const Vec* axis, f32 rad); - -void C_MTXReorder(const Mtx src, ROMtx dst); - -#ifdef GEKKO -void PSMTXQuat(Mtx m, const Quaternion* q); -void PSMTXReflect(Mtx m, const Vec* p, const Vec* n); - -void PSMTXTrans(Mtx m, f32 xT, f32 yT, f32 zT); -void PSMTXTransApply(const Mtx src, Mtx dst, f32 xT, f32 yT, f32 zT); -void PSMTXScale(Mtx m, f32 xS, f32 yS, f32 zS); -void PSMTXScaleApply(const Mtx src, Mtx dst, f32 xS, f32 yS, f32 zS); - -void PSMTXRotRad(Mtx m, char axis, f32 rad); -void PSMTXRotTrig(Mtx m, char axis, f32 sinA, f32 cosA); -void PSMTXRotAxisRad(Mtx m, const Vec* axis, f32 rad); - -void PSMTXReorder(const Mtx src, ROMtx dest); -#else -#define PSMTXQuat MTXQuat -#define PSMTXReflect MTXReflect -#define PSMTXTrans MTXTrans -#define PSMTXTransApply MTXTransApply -#define PSMTXScale MTXScale -#define PSMTXScaleApply MTXScaleApply -#define PSMTXRotRad MTXRotRad -#define PSMTXRotTrig MTXRotTrig -#define PSMTXRotAxisRad MTXRotAxisRad - -#define PSMTXRotRad MTXRotRad -#define PSMTXRotAxisRad MTXRotAxisRad - -#define PSMTXReorder MTXReorder -#endif - -#ifdef MTX_USE_PS -#define MTXQuat C_MTXQuat -#define MTXReflect C_MTXReflect -#define MTXTrans C_MTXTrans -#define MTXTransApply C_MTXTransApply -#define MTXScale C_MTXScale -#define MTXScaleApply C_MTXScaleApply -#define MTXRotRad C_MTXRotRad -#define MTXRotTrig C_MTXRotTrig -#define MTXRotAxisRad C_MTXRotAxisRad - -#define MTXRotDeg(m, axis, deg) C_MTXRotRad(m, axis, MTXDegToRad(deg)) -#define MTXRotAxisDeg(m, axis, deg) C_MTXRotAxisRad(m, axis, MTXDegToRad(deg)) - -#define MTXReorder C_MTXReorder - -#else // MTX_USE_C -#define MTXQuat C_MTXQuat -#define MTXReflect C_MTXReflect -#define MTXTrans C_MTXTrans -#define MTXTransApply C_MTXTransApply -#define MTXScale C_MTXScale -#define MTXScaleApply C_MTXScaleApply -#define MTXRotRad C_MTXRotRad -#define MTXRotTrig C_MTXRotTrig -#define MTXRotAxisRad C_MTXRotAxisRad - -#define MTXRotDeg(m, axis, deg) C_MTXRotRad(m, axis, MTXDegToRad(deg)) -#define MTXRotAxisDeg(m, axis, deg) C_MTXRotAxisRad(m, axis, MTXDegToRad(deg)) - -#define MTXReorder C_MTXReorder - -#endif - -void C_MTXLookAt(Mtx m, const Point3d* camPos, const Vec* camUp, const Point3d* target); - -#define MTXLookAt C_MTXLookAt - -void C_MTXFrustum(Mtx44 m, f32 t, f32 b, f32 l, f32 r, f32 n, f32 f); -void C_MTXPerspective(Mtx44 m, f32 fovY, f32 aspect, f32 n, f32 f); -void C_MTXOrtho(Mtx44 m, f32 t, f32 b, f32 l, f32 r, f32 n, f32 f); - -#define MTXFrustum C_MTXFrustum -#define MTXPerspective C_MTXPerspective -#define MTXOrtho C_MTXOrtho - -void C_MTXLightFrustum(Mtx m, f32 t, f32 b, f32 l, f32 r, f32 n, f32 scaleS, f32 scaleT, f32 transS, - f32 transT); - -void C_MTXLightPerspective(Mtx m, f32 fovY, f32 aspect, f32 scaleS, f32 scaleT, f32 transS, - f32 transT); - -void C_MTXLightOrtho(Mtx m, f32 t, f32 b, f32 l, f32 r, f32 scaleS, f32 scaleT, f32 transS, - f32 transT); - -#define MTXLightFrustum C_MTXLightFrustum -#define MTXLightPerspective C_MTXLightPerspective -#define MTXLightOrtho C_MTXLightOrtho - -void C_VECAdd(const Vec* a, const Vec* b, Vec* ab); -void C_VECSubtract(const Vec* a, const Vec* b, Vec* a_b); -void C_VECScale(const Vec* src, Vec* dst, f32 scale); -void C_VECNormalize(const Vec* src, Vec* unit); -f32 C_VECSquareMag(const Vec* v); -f32 C_VECMag(const Vec* v); -f32 C_VECDotProduct(const Vec* a, const Vec* b); -void C_VECCrossProduct(const Vec* a, const Vec* b, Vec* axb); -f32 C_VECSquareDistance(const Vec* a, const Vec* b); -f32 C_VECDistance(const Vec* a, const Vec* b); -void C_VECReflect(const Vec* src, const Vec* normal, Vec* dst); -void C_VECHalfAngle(const Vec* a, const Vec* b, Vec* half); - -void PSVECNormalize(const Vec* src, Vec* unit); -f32 PSVECSquareMag(const Vec* v); -f32 PSVECMag(const Vec* v); -f32 PSVECSquareDistance(const Vec* a, const Vec* b); -f32 PSVECDistance(const Vec* a, const Vec* b); - -#ifdef GEKKO -void PSVECAdd(const Vec* a, const Vec* b, Vec* ab); -void PSVECSubtract(const Vec* a, const Vec* b, Vec* a_b); -void PSVECScale(const Vec* src, Vec* dst, f32 scale); -void PSVECNormalize(const Vec* src, Vec* unit); -f32 PSVECSquareMag(const Vec* v); -f32 PSVECMag(const Vec* v); -f32 PSVECDotProduct(const Vec* a, const Vec* b); -void PSVECCrossProduct(const Vec* a, const Vec* b, Vec* axb); -f32 PSVECSquareDistance(const Vec* a, const Vec* b); -f32 PSVECDistance(const Vec* a, const Vec* b); -#else -#define PSVECAdd VECAdd -#define PSVECSubtract VECSubtract -#define PSVECScale VECScale -#define PSVECDotProduct VECDotProduct -#define PSVECCrossProduct VECCrossProduct -#endif - -#if defined(MTX_USE_PS) -#define VECAdd C_VECAdd -#define VECSubtract C_VECSubtract -#define VECScale C_VECScale -#define VECNormalize PSVECNormalize -#define VECSquareMag PSVECSquareMag -#define VECMag PSVECMag -#define VECDotProduct C_VECDotProduct -#define VECCrossProduct C_VECCrossProduct -#define VECSquareDistance PSVECSquareDistance -#define VECDistance PSVECDistance -#else // MTX_USE_C -#define VECAdd C_VECAdd -#define VECSubtract C_VECSubtract -#define VECScale C_VECScale -#define VECNormalize C_VECNormalize -#define VECSquareMag C_VECSquareMag -#define VECMag C_VECMag -#define VECDotProduct C_VECDotProduct -#define VECCrossProduct C_VECCrossProduct -#define VECSquareDistance C_VECSquareDistance -#define VECDistance C_VECDistance -#endif - -#define VECReflect C_VECReflect -#define VECHalfAngle C_VECHalfAngle - -void C_QUATAdd(const Quaternion* p, const Quaternion* q, Quaternion* r); -void C_QUATSubtract(const Quaternion* p, const Quaternion* q, Quaternion* r); -void C_QUATMultiply(const Quaternion* p, const Quaternion* q, Quaternion* pq); -void C_QUATDivide(const Quaternion* p, const Quaternion* q, Quaternion* r); -void C_QUATScale(const Quaternion* q, Quaternion* r, f32 scale); -f32 C_QUATDotProduct(const Quaternion* p, const Quaternion* q); -void C_QUATNormalize(const Quaternion* src, Quaternion* unit); -void C_QUATInverse(const Quaternion* src, Quaternion* inv); -void C_QUATExp(const Quaternion* q, Quaternion* r); -void C_QUATLogN(const Quaternion* q, Quaternion* r); - -void C_QUATMakeClosest(const Quaternion* q, const Quaternion* qto, Quaternion* r); -void C_QUATRotAxisRad(Quaternion* r, const Vec* axis, f32 rad); -void C_QUATMtx(Quaternion* r, const Mtx m); - -void C_QUATLerp(const Quaternion* p, const Quaternion* q, Quaternion* r, f32 t); -void C_QUATSlerp(const Quaternion* p, const Quaternion* q, Quaternion* r, f32 t); -void C_QUATSquad(const Quaternion* p, const Quaternion* a, const Quaternion* b, const Quaternion* q, - Quaternion* r, f32 t); -void C_QUATCompA(const Quaternion* qprev, const Quaternion* q, const Quaternion* qnext, - Quaternion* a); - -#ifdef GEKKO -void PSQUATAdd(const Quaternion* p, const Quaternion* q, Quaternion* r); -void PSQUATSubtract(const Quaternion* p, const Quaternion* q, Quaternion* r); -void PSQUATMultiply(const Quaternion* p, const Quaternion* q, Quaternion* pq); -void PSQUATDivide(const Quaternion* p, const Quaternion* q, Quaternion* r); -void PSQUATScale(const Quaternion* q, Quaternion* r, f32 scale); -f32 PSQUATDotProduct(const Quaternion* p, const Quaternion* q); -void PSQUATNormalize(const Quaternion* src, Quaternion* unit); -void PSQUATInverse(const Quaternion* src, Quaternion* inv); -#else -#define PSQUATAdd QUATAdd -#define PSQUATSubtract QUATSubtract -#define PSQUATMultiply QUATMultiply -#define PSQUATDivide QUATDivide -#define PSQUATScale QUATScale -#define PSQUATDotProduct QUATDotProduct -#define PSQUATNormalize QUATNormalize -#define PSQUATInverse QUATInverse -#endif - -#ifdef MTX_USE_PS -#define QUATAdd C_QUATAdd -#define QUATSubtract C_QUATSubtract -#define QUATMultiply C_QUATMultiply -#define QUATDivide C_QUATDivide -#define QUATScale C_QUATScale -#define QUATDotProduct C_QUATDotProduct -#define QUATNormalize C_QUATNormalize -#define QUATInverse C_QUATInverse -#else // MTX_USE_C -#define QUATAdd C_QUATAdd -#define QUATSubtract C_QUATSubtract -#define QUATMultiply C_QUATMultiply -#define QUATDivide C_QUATDivide -#define QUATScale C_QUATScale -#define QUATDotProduct C_QUATDotProduct -#define QUATNormalize C_QUATNormalize -#define QUATInverse C_QUATInverse -#endif - -#define QUATExp C_QUATExp -#define QUATLogN C_QUATLogN -#define QUATMakeClosest C_QUATMakeClosest -#define QUATRotAxisRad C_QUATRotAxisRad -#define QUATMtx C_QUATMtx -#define QUATLerp C_QUATLerp -#define QUATSlerp C_QUATSlerp -#define QUATSquad C_QUATSquad -#define QUATCompA C_QUATCompA - -void MTXInitStack(MtxStack* sPtr, u32 numMtx); -MtxPtr MTXPush(MtxStack* sPtr, const Mtx m); -MtxPtr MTXPushFwd(MtxStack* sPtr, const Mtx m); -MtxPtr MTXPushInv(MtxStack* sPtr, const Mtx m); -MtxPtr MTXPushInvXpose(MtxStack* sPtr, const Mtx m); -MtxPtr MTXPop(MtxStack* sPtr); -MtxPtr MTXGetStackPtr(const MtxStack* sPtr); - -#define MTXAllocStack(sPtr, numMtx) \ - (((MtxStackPtr)(sPtr))->stackBase = (MtxPtr)OSAlloc(((numMtx) * sizeof(Mtx)))) - -#define MTXFreeStack(sPtr) (OSFree((void*)(((MtxStackPtr)(sPtr))->stackBase))) - -#ifdef __cplusplus -} -#endif - -#endif // _DOLPHIN_MTX diff --git a/aurora-main/include/dolphin/mtx/GeoTypes.h b/aurora-main/include/dolphin/mtx/GeoTypes.h deleted file mode 100644 index 985c2d3..0000000 --- a/aurora-main/include/dolphin/mtx/GeoTypes.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef _DOLPHIN_GEOTYPES -#define _DOLPHIN_GEOTYPES - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - typedef struct Vec { - f32 x, y, z; - } Vec, *VecPtr, Point3d, *Point3dPtr; - - typedef struct { - s16 x; - s16 y; - s16 z; - } S16Vec, *S16VecPtr; - - typedef struct { - f32 x, y, z, w; - } Quaternion, *QuaternionPtr, Qtrn, *QtrnPtr; - - typedef f32 Mtx[3][4]; - - typedef f32 (*MtxPtr)[4]; - - typedef f32 ROMtx[4][3]; - - typedef f32 (*ROMtxPtr)[3]; - - typedef f32 Mtx44[4][4]; - - typedef f32 (*Mtx44Ptr)[4]; - -#ifdef __cplusplus -} -#endif - -#endif // _DOLPHIN_GEOTYPES diff --git a/aurora-main/include/dolphin/mtx/mtx44ext.h b/aurora-main/include/dolphin/mtx/mtx44ext.h deleted file mode 100644 index 391ea57..0000000 --- a/aurora-main/include/dolphin/mtx/mtx44ext.h +++ /dev/null @@ -1,106 +0,0 @@ -#include - -#ifndef _DOLPHIN_MTX44EXT -#define _DOLPHIN_MTX44EXT - -#ifdef __cplusplus -extern "C" { -#endif - -void C_MTX44Identity(Mtx44 m); -void C_MTX44Copy(const Mtx44 src, Mtx44 dst); -void C_MTX44Concat(const Mtx44 a, const Mtx44 b, Mtx44 ab); -void C_MTX44Transpose(const Mtx44 src, Mtx44 xPose); -u32 C_MTX44Inverse(const Mtx44 src, Mtx44 inv); - -#ifdef GEKKO -void PSMTX44Identity(Mtx44 m); -void PSMTX44Copy(const Mtx44 src, Mtx44 dst); -void PSMTX44Concat(const Mtx44 a, const Mtx44 b, Mtx44 ab); -void PSMTX44Transpose(const Mtx44 src, Mtx44 xPose); -#endif - -#ifdef MTX_USE_PS -#define MTX44Identity PSMTX44Identity -#define MTX44Copy PSMTX44Copy -#define MTX44Concat PSMTX44Concat -#define MTX44Transpose PSMTX44Transpose -#else -#define MTX44Identity C_MTX44Identity -#define MTX44Copy C_MTX44Copy -#define MTX44Concat C_MTX44Concat -#define MTX44Transpose C_MTX44Transpose -#endif - -#define MTX44Inverse C_MTX44Inverse - -void C_MTX44Trans(Mtx44 m, f32 xT, f32 yT, f32 zT); -void C_MTX44TransApply(const Mtx44 src, Mtx44 dst, f32 xT, f32 yT, f32 zT); -void C_MTX44Scale(Mtx44 m, f32 xS, f32 yS, f32 zS); -void C_MTX44ScaleApply(const Mtx44 src, Mtx44 dst, f32 xS, f32 yS, f32 zS); - -void C_MTX44RotRad(Mtx44 m, char axis, f32 rad); -void C_MTX44RotTrig(Mtx44 m, char axis, f32 sinA, f32 cosA); -void C_MTX44RotAxisRad(Mtx44 m, const Vec* axis, f32 rad); - -#ifdef GEKKO -void PSMTX44Trans(Mtx44 m, f32 xT, f32 yT, f32 zT); -void PSMTX44TransApply(const Mtx44 src, Mtx44 dst, f32 xT, f32 yT, f32 zT); -void PSMTX44Scale(Mtx44 m, f32 xS, f32 yS, f32 zS); -void PSMTX44ScaleApply(const Mtx44 src, Mtx44 dst, f32 xS, f32 yS, f32 zS); - -void PSMTX44RotRad(Mtx44 m, char axis, f32 rad); -void PSMTX44RotTrig(Mtx44 m, char axis, f32 sinA, f32 cosA); -void PSMTX44RotAxisRad(Mtx44 m, const Vec* axis, f32 rad); -#endif - -#ifdef MTX_USE_PS -#define MTX44Trans PSMTX44Trans -#define MTX44TransApply PSMTX44TransApply -#define MTX44Scale PSMTX44Scale -#define MTX44ScaleApply PSMTX44ScaleApply - -#define MTX44RotRad PSMTX44RotRad -#define MTX44RotTrig PSMTX44RotTrig -#define MTX44RotAxisRad PSMTX44RotAxisRad - -#else -#define MTX44Trans C_MTX44Trans -#define MTX44TransApply C_MTX44TransApply -#define MTX44Scale C_MTX44Scale -#define MTX44ScaleApply C_MTX44ScaleApply - -#define MTX44RotRad C_MTX44RotRad -#define MTX44RotTrig C_MTX44RotTrig -#define MTX44RotAxisRad C_MTX44RotAxisRad -#endif - -void C_MTX44MultVec(const Mtx44 m, const Vec* src, Vec* dst); -void C_MTX44MultVecArray(const Mtx44 m, const Vec* srcBase, Vec* dstBase, u32 count); -void C_MTX44MultVecSR(const Mtx44 m, const Vec* src, Vec* dst); -void C_MTX44MultVecArraySR(const Mtx44 m, const Vec* srcBase, Vec* dstBase, u32 count); - -#ifdef GEKKO -void PSMTX44MultVec(const Mtx44 m, const Vec* src, Vec* dst); -void PSMTX44MultVecArray(const Mtx44 m, const Vec* srcBase, Vec* dstBase, u32 count); -void PSMTX44MultVecSR(const Mtx44 m, const Vec* src, Vec* dst); -void PSMTX44MultVecArraySR(const Mtx44 m, const Vec* srcBase, Vec* dstBase, u32 count); -#endif - -#ifdef MTX_USE_PS -#define MTX44MultVec PSMTX44MultVec -#define MTX44MultVecArray PSMTX44MultVecArray -#define MTX44MultVecSR PSMTX44MultVecSR -#define MTX44MultVecArraySR PSMTX44MultVecArraySR -#else -#define MTX44MultVec C_MTX44MultVec -#define MTX44MultVecArray C_MTX44MultVecArray -#define MTX44MultVecSR C_MTX44MultVecSR -#define MTX44MultVecArraySR C_MTX44MultVecArraySR -#endif - -#ifdef __cplusplus -} -#endif - -#endif // _DOLPHIN_MTX44EXT diff --git a/aurora-main/include/dolphin/os.h b/aurora-main/include/dolphin/os.h deleted file mode 100644 index 18f3637..0000000 --- a/aurora-main/include/dolphin/os.h +++ /dev/null @@ -1,311 +0,0 @@ -#ifndef _DOLPHIN_OS_H_ -#define _DOLPHIN_OS_H_ - -#ifdef __cplusplus -#include -#else -#include -#endif - -#include -#include - -void OSReportInit(void); -void OSSwitchFiberEx(u32, u32, u32, u32, u32, u32); -void OSVAttention(const char* fmt, va_list args); - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef __MWERKS__ -#include -#endif -#include -#include -#include -#include - -// private macro, maybe shouldn't be defined here? -#define OFFSET(addr, align) (((u32)(addr) & ((align)-1))) - -#ifndef __MWERKS__ -typedef struct { - BOOL valid; - u32 restartCode; - u32 bootDol; - void* regionStart; - void* regionEnd; - int argsUseDefault; - void* argsAddr; -} OSExecParams; -#endif - -#define DOLPHIN_ALIGNMENT 32 - -// Upper words of the masks, since UIMM is only 16 bits -#define OS_CACHED_REGION_PREFIX 0x8000 -#define OS_UNCACHED_REGION_PREFIX 0xC000 -#define OS_PHYSICAL_MASK 0x3FFF - -extern uintptr_t OSBaseAddress; - -#define OS_BASE_CACHED (OSBaseAddress) -#define OS_BASE_UNCACHED (OSBaseAddress) - -#ifdef __MWERKS__ -u32 __OSPhysicalMemSize AT_ADDRESS(OS_BASE_CACHED | 0x0028); -volatile int __OSTVMode AT_ADDRESS(OS_BASE_CACHED | 0x00CC); -OSThreadQueue __OSActiveThreadQueue AT_ADDRESS(OS_BASE_CACHED | 0x00DC); -OSThread* __OSCurrentThread AT_ADDRESS(OS_BASE_CACHED | 0x00E4); -u32 __OSSimulatedMemSize AT_ADDRESS(OS_BASE_CACHED | 0x00F0); -u32 __OSBusClock AT_ADDRESS(OS_BASE_CACHED | 0x00F8); -u32 __OSCoreClock AT_ADDRESS(OS_BASE_CACHED | 0x00FC); -volatile u16 __OSDeviceCode AT_ADDRESS(OS_BASE_CACHED | 0x30E6); -u16 __OSWirelessPadFixMode AT_ADDRESS(OS_BASE_CACHED | 0x30E0); - -// unknowns -OSThread* __gUnkThread1 AT_ADDRESS(OS_BASE_CACHED | 0x00D8); -int __gUnknown800030C0[2] AT_ADDRESS(OS_BASE_CACHED | 0x30C0); -u8 __gUnknown800030E3 AT_ADDRESS(OS_BASE_CACHED | 0x30E3); -#else -#define __OSBusClock (*(u32 *)(OS_BASE_CACHED + 0x00F8)) -#define __OSCoreClock (*(u32 *)(OS_BASE_CACHED + 0x00FC)) -#endif - -#define OS_TIMER_CLOCK_DIVIDER 4 -#define OS_BUS_CLOCK 162000000 -#define OS_CORE_CLOCK 162000000 -#define OS_TIMER_CLOCK (OS_BUS_CLOCK/OS_TIMER_CLOCK_DIVIDER) - -#define OSTicksToSeconds(ticks) ((ticks) / (OS_TIMER_CLOCK)) -#define OSTicksToMilliseconds(ticks) ((ticks) / (OS_TIMER_CLOCK/1000)) -#define OSTicksToMicroseconds(ticks) ((ticks) * 8 / (OS_TIMER_CLOCK/125000)) -#define OSSecondsToTicks(sec) ((sec) * (OS_TIMER_CLOCK)) -#define OSMillisecondsToTicks(msec) ((msec) * (OS_TIMER_CLOCK / 1000)) -#define OSNanosecondsToTicks(nsec) (((nsec) * (OS_TIMER_CLOCK / 125000)) / 8000) -#define OSMicrosecondsToTicks(usec) (((usec) * (OS_TIMER_CLOCK / 125000)) / 8) - -u32 OSGetConsoleType(void); -void OSInit(void); -void OSRegisterVersion(const char* id); - -void* OSGetArenaHi(void); -void* OSGetArenaLo(void); -void OSSetArenaHi(void* newHi); -void OSSetArenaLo(void* newLo); -void* OSAllocFromArenaLo(u32 size, u32 align); -void* OSAllocFromArenaHi(u32 size, u32 align); - -u32 OSGetPhysicalMemSize(void); - -void __OSPSInit(void); -void __OSFPRInit(void); -u32 __OSGetDIConfig(void); - -#if 0 -void OSDefaultExceptionHandler(__OSException exception, OSContext* context); -#endif - -typedef struct OSCalendarTime { - /* 0x00 */ int sec; - /* 0x04 */ int min; - /* 0x08 */ int hour; - /* 0x0C */ int mday; - /* 0x10 */ int mon; - /* 0x14 */ int year; - /* 0x18 */ int wday; - /* 0x1C */ int yday; - /* 0x20 */ int msec; - /* 0x24 */ int usec; -} OSCalendarTime; - -#include -typedef struct OSBootInfo_s { - DVDDiskID DVDDiskID; - u32 magic; - u32 version; - u32 memorySize; - u32 consoleType; - void* arenaLo; - void* arenaHi; - void* FSTLocation; - u32 FSTMaxLength; -} OSBootInfo; - -typedef struct OSStopwatch { - char* name; - u32 hits; - OSTime total; - OSTime min; - OSTime max; - OSTime last; - BOOL running; - u32 _padding; -} OSStopwatch; - -void OSInitStopwatch(OSStopwatch* sw, char* name); -void OSStartStopwatch(OSStopwatch* sw); -void OSStopStopwatch(OSStopwatch* sw); -OSTime OSCheckStopwatch(OSStopwatch* sw); -void OSResetStopwatch(OSStopwatch* sw); -void OSDumpStopwatch(OSStopwatch* sw); - -OSTick OSGetTick(void); -OSTime OSGetTime(void); -void OSTicksToCalendarTime(OSTime ticks, OSCalendarTime* td); -OSTime OSCalendarTimeToTicks(OSCalendarTime* td); -BOOL OSEnableInterrupts(void); -BOOL OSDisableInterrupts(void); -BOOL OSRestoreInterrupts(BOOL level); - -#define OS_CONSOLE_MASK 0xF0000000 -#define OS_CONSOLE_RETAIL 0x00000000 -#define OS_CONSOLE_DEVELOPMENT 0x10000000 -#define OS_CONSOLE_TDEV 0x20000000 - -#define OS_CONSOLE_RETAIL4 0x00000004 -#define OS_CONSOLE_RETAIL3 0x00000003 -#define OS_CONSOLE_RETAIL2 0x00000002 -#define OS_CONSOLE_RETAIL1 0x00000001 -#define OS_CONSOLE_TDEVHW4 0x20000007 -#define OS_CONSOLE_TDEVHW3 0x20000006 -#define OS_CONSOLE_TDEVHW2 0x20000005 -#define OS_CONSOLE_TDEVHW1 0x20000004 -#define OS_CONSOLE_DEVHW4 0x10000007 -#define OS_CONSOLE_DEVHW3 0x10000006 -#define OS_CONSOLE_DEVHW2 0x10000005 -#define OS_CONSOLE_DEVHW1 0x10000004 -#define OS_CONSOLE_MINNOW 0x10000003 -#define OS_CONSOLE_ARTHUR 0x10000002 -#define OS_CONSOLE_PC_EMULATOR 0x10000001 -#define OS_CONSOLE_EMULATOR 0x10000000 - -#define OS_SOUND_MODE_MONO 0 -#define OS_SOUND_MODE_STEREO 1 - -u32 OSGetSoundMode(void); -void OSSetSoundMode(u32 mode); - -DECL_WEAK void OSReport(const char* msg, ...); -DECL_WEAK void OSVReport(const char* msg, va_list list); -DECL_WEAK void OSPanic NORETURN(const char* file, int line, const char* msg, ...); -void OSFatal NORETURN(GXColor fg, GXColor bg, const char* msg); - -#define OSRoundUp32B(x) (((uintptr_t)(x) + 32 - 1) & ~(32 - 1)) -#define OSRoundDown32B(x) (((uintptr_t)(x)) & ~(32 - 1)) - -void* OSPhysicalToCached(u32 paddr); -void* OSPhysicalToUncached(u32 paddr); -u32 OSCachedToPhysical(void* caddr); -u32 OSUncachedToPhysical(void* ucaddr); -void* OSCachedToUncached(void* caddr); -void* OSUncachedToCached(void* ucaddr); - -#if !DEBUG && !defined(TARGET_PC) -#define OSPhysicalToCached(paddr) ((void*) ((u32)(OS_BASE_CACHED + (u32)(paddr)))) -#define OSPhysicalToUncached(paddr) ((void*) ((u32)(OS_BASE_UNCACHED + (u32)(paddr)))) -#define OSCachedToPhysical(caddr) ((u32) ((u32)(caddr) - OS_BASE_CACHED)) -#define OSUncachedToPhysical(ucaddr) ((u32) ((u32)(ucaddr) - OS_BASE_UNCACHED)) -#define OSCachedToUncached(caddr) ((void*) ((u8*)(caddr) + (OS_BASE_UNCACHED - OS_BASE_CACHED))) -#define OSUncachedToCached(ucaddr) ((void*) ((u8*)(ucaddr) - (OS_BASE_UNCACHED - OS_BASE_CACHED))) -#endif - -// unsorted externs -extern OSTime __OSGetSystemTime(void); -DECL_WEAK extern int __OSIsGcam; -extern OSExecParams __OSRebootParams; -extern OSTime __OSStartTime; -extern int __OSInIPL; - -// helper for assert line numbers in different revisions -#ifndef SDK_REVISION -#define SDK_REVISION 0 -#endif - -#if SDK_REVISION < 1 - #define LINE(l0, l1, l2) (l0) -#elif SDK_REVISION < 2 - #define LINE(l0, l1, l2) (l1) -#else - #define LINE(l0, l1, l2) (l2) -#endif - -#if DEBUG -#if __MWERKS__ - -#define ASSERTLINE(line, cond) \ - ((cond) || (OSPanic(__FILE__, line, "Failed assertion " #cond), 0)) - -#define ASSERTMSGLINE(line, cond, msg) \ - ((cond) || (OSPanic(__FILE__, line, msg), 0)) - -// This is dumb but we dont have a Metrowerks way to do variadic macros in the macro to make this done in a not scrubby way. -#define ASSERTMSG1LINE(line, cond, msg, arg1) \ - ((cond) || (OSPanic(__FILE__, line, msg, arg1), 0)) - -#define ASSERTMSG2LINE(line, cond, msg, arg1, arg2) \ - ((cond) || (OSPanic(__FILE__, line, msg, arg1, arg2), 0)) - -#define ASSERTMSGLINEV(line, cond, ...) \ - ((cond) || (OSPanic(__FILE__, line, __VA_ARGS__), 0)) - -#else - -#define ASSERTLINE(line, cond) \ - ((cond) || (OSPanic(__FILE__, __LINE__, "Failed assertion " #cond), 0)) - -#define ASSERTMSGLINE(line, cond, msg) \ - ((cond) || (OSPanic(__FILE__, __LINE__, msg), 0)) - - // This is dumb but we dont have a Metrowerks way to do variadic macros in the macro to make this done in a not scrubby way. -#define ASSERTMSG1LINE(line, cond, msg, arg1) \ - ((cond) || (OSPanic(__FILE__, __LINE__, msg, arg1), 0)) -#define ASSERTMSG2LINE(line, cond, msg, arg1, arg2) \ - ((cond) || (OSPanic(__FILE__, __LINE__, msg, arg1, arg2), 0)) - -#define ASSERTMSGLINEV(line, cond, ...) \ - ((cond) || (OSPanic(__FILE__, __LINE__, __VA_ARGS__), 0)) - -#endif - -#else -#define ASSERTLINE(line, cond) (void)0 -#define ASSERTMSGLINE(line, cond, msg) (void)0 -#define ASSERTMSG1LINE(line, cond, msg, arg1) (void)0 -#define ASSERTMSG2LINE(line, cond, msg, arg1, arg2) (void)0 -#define ASSERTMSGLINEV(line, cond, ...) (void)0 -#endif - -#ifdef ASSERT -#undef ASSERT -#endif -#define ASSERT(cond) ASSERTLINE(__LINE__, cond) - -#ifdef __cplusplus -} -#endif -#endif diff --git a/aurora-main/include/dolphin/os/OSAlarm.h b/aurora-main/include/dolphin/os/OSAlarm.h deleted file mode 100644 index 3105039..0000000 --- a/aurora-main/include/dolphin/os/OSAlarm.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef _DOLPHIN_OSALARM_H_ -#define _DOLPHIN_OSALARM_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct OSAlarm OSAlarm; -typedef void (*OSAlarmHandler)(OSAlarm* alarm, OSContext* context); -struct OSAlarm { - OSAlarmHandler handler; - u32 tag; - OSTime fire; - OSAlarm* prev; - OSAlarm* next; - OSTime period; - OSTime start; -}; - -BOOL OSCheckAlarmQueue(void); -void OSInitAlarm(void); -void OSCreateAlarm(OSAlarm* alarm); -void OSSetAlarm(OSAlarm* alarm, OSTime tick, OSAlarmHandler handler); -void OSSetAbsAlarm(OSAlarm* alarm, OSTime time, OSAlarmHandler handler); -void OSSetPeriodicAlarm(OSAlarm* alarm, OSTime start, OSTime period, OSAlarmHandler handler); -void OSCancelAlarm(OSAlarm *alarm); -void OSSetAlarmTag(OSAlarm* alarm, u32 tag); -void OSCancelAlarms(u32 tag); - -#ifdef __cplusplus -} -#endif - -#endif // _DOLPHIN_OSALARM_H_ diff --git a/aurora-main/include/dolphin/os/OSAlloc.h b/aurora-main/include/dolphin/os/OSAlloc.h deleted file mode 100644 index e2cecd9..0000000 --- a/aurora-main/include/dolphin/os/OSAlloc.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef _DOLPHIN_OSALLOC_H_ -#define _DOLPHIN_OSALLOC_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef int OSHeapHandle; - -extern volatile OSHeapHandle __OSCurrHeap; - -void* OSAllocFromHeap(OSHeapHandle heap, u32 size); -void* OSAllocFixed(void* rstart, void* rend); -void OSFreeToHeap(OSHeapHandle heap, void* ptr); -OSHeapHandle OSSetCurrentHeap(OSHeapHandle heap); -void* OSInitAlloc(void* arenaStart, void* arenaEnd, int maxHeaps); -OSHeapHandle OSCreateHeap(void* start, void* end); -void OSDestroyHeap(OSHeapHandle heap); -void OSAddToHeap(OSHeapHandle heap, void* start, void* end); -s32 OSCheckHeap(OSHeapHandle heap); -u32 OSReferentSize(void* ptr); -void OSDumpHeap(OSHeapHandle heap); -void OSVisitAllocated(void (*visitor)(void*, u32)); - -#define OSAlloc(size) OSAllocFromHeap(__OSCurrHeap, (size)) -#define OSFree(ptr) OSFreeToHeap(__OSCurrHeap, (ptr)) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/os/OSCache.h b/aurora-main/include/dolphin/os/OSCache.h deleted file mode 100644 index 89e7ce9..0000000 --- a/aurora-main/include/dolphin/os/OSCache.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef _DOLPHIN_OSCACHE_H_ -#define _DOLPHIN_OSCACHE_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void DCInvalidateRange(void* addr, u32 nBytes); -void DCFlushRange(void* addr, u32 nBytes); -void DCStoreRange(void* addr, u32 nBytes); -void DCFlushRangeNoSync(void* addr, u32 nBytes); -void DCStoreRangeNoSync(void* addr, u32 nBytes); -void DCZeroRange(void* addr, u32 nBytes); -void DCTouchRange(void* addr, u32 nBytes); -void ICInvalidateRange(void* addr, u32 nBytes); - -#define LC_BASE_PREFIX 0xE000 -#define LC_BASE (LC_BASE_PREFIX << 16) -#define LCGetBase() ((void*)LC_BASE) - -void LCEnable(void); -void LCDisable(void); -void LCLoadBlocks(void* destTag, void* srcAddr, u32 numBlocks); -void LCStoreBlocks(void* destAddr, void* srcTag, u32 numBlocks); -u32 LCLoadData(void* destAddr, void* srcAddr, u32 nBytes); -u32 LCStoreData(void* destAddr, void* srcAddr, u32 nBytes); -u32 LCQueueLength(void); -void LCQueueWait(u32 len); -void LCFlushQueue(void); -void __OSCacheInit(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/os/OSContext.h b/aurora-main/include/dolphin/os/OSContext.h deleted file mode 100644 index bf06efc..0000000 --- a/aurora-main/include/dolphin/os/OSContext.h +++ /dev/null @@ -1,177 +0,0 @@ -#ifndef _DOLPHIN_OSCONTEXT_H_ -#define _DOLPHIN_OSCONTEXT_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define __OS_CONTEXT_FRAME 768 - -#define OS_CONTEXT_R0 0 -#define OS_CONTEXT_R1 4 -#define OS_CONTEXT_R2 8 -#define OS_CONTEXT_R3 12 -#define OS_CONTEXT_R4 16 -#define OS_CONTEXT_R5 20 -#define OS_CONTEXT_R6 24 -#define OS_CONTEXT_R7 28 -#define OS_CONTEXT_R8 32 -#define OS_CONTEXT_R9 36 -#define OS_CONTEXT_R10 40 -#define OS_CONTEXT_R11 44 -#define OS_CONTEXT_R12 48 -#define OS_CONTEXT_R13 52 -#define OS_CONTEXT_R14 56 -#define OS_CONTEXT_R15 60 -#define OS_CONTEXT_R16 64 -#define OS_CONTEXT_R17 68 -#define OS_CONTEXT_R18 72 -#define OS_CONTEXT_R19 76 -#define OS_CONTEXT_R20 80 -#define OS_CONTEXT_R21 84 -#define OS_CONTEXT_R22 88 -#define OS_CONTEXT_R23 92 -#define OS_CONTEXT_R24 96 -#define OS_CONTEXT_R25 100 -#define OS_CONTEXT_R26 104 -#define OS_CONTEXT_R27 108 -#define OS_CONTEXT_R28 112 -#define OS_CONTEXT_R29 116 -#define OS_CONTEXT_R30 120 -#define OS_CONTEXT_R31 124 - -#define OS_CONTEXT_CR 128 -#define OS_CONTEXT_LR 132 -#define OS_CONTEXT_CTR 136 -#define OS_CONTEXT_XER 140 - -#define OS_CONTEXT_FPR0 144 -#define OS_CONTEXT_FPR1 152 -#define OS_CONTEXT_FPR2 160 -#define OS_CONTEXT_FPR3 168 -#define OS_CONTEXT_FPR4 176 -#define OS_CONTEXT_FPR5 184 -#define OS_CONTEXT_FPR6 192 -#define OS_CONTEXT_FPR7 200 -#define OS_CONTEXT_FPR8 208 -#define OS_CONTEXT_FPR9 216 -#define OS_CONTEXT_FPR10 224 -#define OS_CONTEXT_FPR11 232 -#define OS_CONTEXT_FPR12 240 -#define OS_CONTEXT_FPR13 248 -#define OS_CONTEXT_FPR14 256 -#define OS_CONTEXT_FPR15 264 -#define OS_CONTEXT_FPR16 272 -#define OS_CONTEXT_FPR17 280 -#define OS_CONTEXT_FPR18 288 -#define OS_CONTEXT_FPR19 296 -#define OS_CONTEXT_FPR20 304 -#define OS_CONTEXT_FPR21 312 -#define OS_CONTEXT_FPR22 320 -#define OS_CONTEXT_FPR23 328 -#define OS_CONTEXT_FPR24 336 -#define OS_CONTEXT_FPR25 344 -#define OS_CONTEXT_FPR26 352 -#define OS_CONTEXT_FPR27 360 -#define OS_CONTEXT_FPR28 368 -#define OS_CONTEXT_FPR29 376 -#define OS_CONTEXT_FPR30 384 -#define OS_CONTEXT_FPR31 392 - -#define OS_CONTEXT_FPSCR 400 - -#define OS_CONTEXT_SRR0 408 -#define OS_CONTEXT_SRR1 412 - -#define OS_CONTEXT_MODE 416 -#define OS_CONTEXT_STATE 418 - -#define OS_CONTEXT_GQR0 420 -#define OS_CONTEXT_GQR1 424 -#define OS_CONTEXT_GQR2 428 -#define OS_CONTEXT_GQR3 432 -#define OS_CONTEXT_GQR4 436 -#define OS_CONTEXT_GQR5 440 -#define OS_CONTEXT_GQR6 444 -#define OS_CONTEXT_GQR7 448 -#define __OSCONTEXT_PADDING 452 - -#define OS_CONTEXT_PSF0 456 -#define OS_CONTEXT_PSF1 464 -#define OS_CONTEXT_PSF2 472 -#define OS_CONTEXT_PSF3 480 -#define OS_CONTEXT_PSF4 488 -#define OS_CONTEXT_PSF5 496 -#define OS_CONTEXT_PSF6 504 -#define OS_CONTEXT_PSF7 512 -#define OS_CONTEXT_PSF8 520 -#define OS_CONTEXT_PSF9 528 -#define OS_CONTEXT_PSF10 536 -#define OS_CONTEXT_PSF11 544 -#define OS_CONTEXT_PSF12 552 -#define OS_CONTEXT_PSF13 560 -#define OS_CONTEXT_PSF14 568 -#define OS_CONTEXT_PSF15 576 -#define OS_CONTEXT_PSF16 584 -#define OS_CONTEXT_PSF17 592 -#define OS_CONTEXT_PSF18 600 -#define OS_CONTEXT_PSF19 608 -#define OS_CONTEXT_PSF20 616 -#define OS_CONTEXT_PSF21 624 -#define OS_CONTEXT_PSF22 632 -#define OS_CONTEXT_PSF23 640 -#define OS_CONTEXT_PSF24 648 -#define OS_CONTEXT_PSF25 656 -#define OS_CONTEXT_PSF26 664 -#define OS_CONTEXT_PSF27 672 -#define OS_CONTEXT_PSF28 680 -#define OS_CONTEXT_PSF29 688 -#define OS_CONTEXT_PSF30 696 -#define OS_CONTEXT_PSF31 704 -#define OS_CONTEXT_STATE_EXC 0x02u - -#define OS_CONTEXT_STATE_FPSAVED 0x01u - -typedef struct OSContext { -#ifndef TARGET_PC - /* 0x000 */ u32 gpr[32]; - /* 0x080 */ u32 cr; - /* 0x084 */ u32 lr; - /* 0x088 */ u32 ctr; - /* 0x08C */ u32 xer; - /* 0x090 */ f64 fpr[32]; - /* 0x190 */ u32 fpscr_pad; - /* 0x194 */ u32 fpscr; - /* 0x198 */ u32 srr0; - /* 0x19C */ u32 srr1; - /* 0x1A0 */ u16 mode; - /* 0x1A2 */ u16 state; - /* 0x1A4 */ u32 gqr[8]; - /* 0x1C4 */ u32 psf_pad; - /* 0x1C8 */ f64 psf[32]; -#else - char storage[0x2C8]; -#endif -} OSContext; - -u32 OSGetStackPointer(void); -void OSDumpContext(OSContext* context); -void OSLoadContext(OSContext* context); -u32 OSSaveContext(OSContext* context); -void OSClearContext(OSContext* context); -OSContext* OSGetCurrentContext(void); -void OSSetCurrentContext(OSContext* context); -void OSLoadFPUContext(OSContext* fpucontext); -void OSSaveFPUContext(OSContext* fpucontext); -u32 OSSwitchStack(u32 newsp); -int OSSwitchFiber(u32 pc, u32 newsp); -void OSInitContext(OSContext* context, u32 pc, u32 newsp); -void OSFillFPUContext(OSContext* context); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/os/OSDC.h b/aurora-main/include/dolphin/os/OSDC.h deleted file mode 100644 index bab2d68..0000000 --- a/aurora-main/include/dolphin/os/OSDC.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _DOLPHIN_OSDC_H_ -#define _DOLPHIN_OSDC_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -void DCFlashInvalidate(void); -void DCEnable(void); -void DCDisable(void); -void DCFreeze(void); -void DCUnfreeze(void); -void DCTouchLoad(void* addr); -void DCBlockZero(void* addr); -void DCBlockStore(void* addr); -void DCBlockFlush(void* addr); -void DCBlockInvalidate(void* addr); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/os/OSError.h b/aurora-main/include/dolphin/os/OSError.h deleted file mode 100644 index 32278eb..0000000 --- a/aurora-main/include/dolphin/os/OSError.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _DOLPHIN_OSERROR_H_ -#define _DOLPHIN_OSERROR_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef u16 OSError; -typedef void (*OSErrorHandler)(OSError error, OSContext* context, ...); - -#define OS_ERROR_SYSTEM_RESET 0 -#define OS_ERROR_MACHINE_CHECK 1 -#define OS_ERROR_DSI 2 -#define OS_ERROR_ISI 3 -#define OS_ERROR_EXTERNAL_INTERRUPT 4 -#define OS_ERROR_ALIGNMENT 5 -#define OS_ERROR_PROGRAM 6 -#define OS_ERROR_FLOATING_POINT 7 -#define OS_ERROR_DECREMENTER 8 -#define OS_ERROR_SYSTEM_CALL 9 -#define OS_ERROR_TRACE 10 -#define OS_ERROR_PERFORMACE_MONITOR 11 -#define OS_ERROR_BREAKPOINT 12 -#define OS_ERROR_SYSTEM_INTERRUPT 13 -#define OS_ERROR_THERMAL_INTERRUPT 14 -#define OS_ERROR_PROTECTION 15 -#define OS_ERROR_MAX (OS_ERROR_PROTECTION + 1) - -OSErrorHandler OSSetErrorHandler(OSError error, OSErrorHandler handler); -extern u32 __OSFpscrEnableBits; -extern OSErrorHandler __OSErrorTable[17]; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/os/OSException.h b/aurora-main/include/dolphin/os/OSException.h deleted file mode 100644 index e9a2f22..0000000 --- a/aurora-main/include/dolphin/os/OSException.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef _DOLPHIN_OSEXCEPTION_H_ -#define _DOLPHIN_OSEXCEPTION_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define __OS_EXCEPTION_SYSTEM_RESET 0 -#define __OS_EXCEPTION_MACHINE_CHECK 1 -#define __OS_EXCEPTION_DSI 2 -#define __OS_EXCEPTION_ISI 3 -#define __OS_EXCEPTION_EXTERNAL_INTERRUPT 4 -#define __OS_EXCEPTION_ALIGNMENT 5 -#define __OS_EXCEPTION_PROGRAM 6 -#define __OS_EXCEPTION_FLOATING_POINT 7 -#define __OS_EXCEPTION_DECREMENTER 8 -#define __OS_EXCEPTION_SYSTEM_CALL 9 -#define __OS_EXCEPTION_TRACE 10 -#define __OS_EXCEPTION_PERFORMACE_MONITOR 11 -#define __OS_EXCEPTION_BREAKPOINT 12 -#define __OS_EXCEPTION_SYSTEM_INTERRUPT 13 -#define __OS_EXCEPTION_THERMAL_INTERRUPT 14 -#define __OS_EXCEPTION_MEMORY_PROTECTION 15 -#define __OS_EXCEPTION_FLOATING_POINT_EXCEPTION 16 -#define __OS_EXCEPTION_MAX \ - (__OS_EXCEPTION_THERMAL_INTERRUPT+1) - -typedef u8 __OSException; -typedef void (*__OSExceptionHandler)(__OSException exception, OSContext* context); - -__OSExceptionHandler __OSSetExceptionHandler(__OSException exception, __OSExceptionHandler handler); -__OSExceptionHandler __OSGetExceptionHandler(__OSException exception); - -#define OS_EXCEPTION_SAVE_GPRS(context) \ - stw r0, OS_CONTEXT_R0(context); \ - stw r1, OS_CONTEXT_R1(context); \ - stw r2, OS_CONTEXT_R2(context); \ - stmw r6, OS_CONTEXT_R6(context); \ - mfspr r0, GQR1; \ - stw r0, OS_CONTEXT_GQR1(context); \ - mfspr r0, GQR2; \ - stw r0, OS_CONTEXT_GQR2(context); \ - mfspr r0, GQR3; \ - stw r0, OS_CONTEXT_GQR3(context); \ - mfspr r0, GQR4; \ - stw r0, OS_CONTEXT_GQR4(context); \ - mfspr r0, GQR5; \ - stw r0, OS_CONTEXT_GQR5(context); \ - mfspr r0, GQR6; \ - stw r0, OS_CONTEXT_GQR6(context); \ - mfspr r0, GQR7; \ - stw r0, OS_CONTEXT_GQR7(context); - -#ifdef __cplusplus -} -#endif - -#endif // _DOLPHIN_OSEXCEPTION_H_ diff --git a/aurora-main/include/dolphin/os/OSExec.h b/aurora-main/include/dolphin/os/OSExec.h deleted file mode 100644 index af0dc4d..0000000 --- a/aurora-main/include/dolphin/os/OSExec.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _DOLPHIN_OSEXEC_H_ -#define _DOLPHIN_OSEXEC_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - BOOL valid; - u32 restartCode; - u32 bootDol; - void* regionStart; - void* regionEnd; - int argsUseDefault; - void* argsAddr; -} OSExecParams; - -typedef int (*appGetNextCallback)(void*, u32*, u32*); -typedef void (*appInitCallback)(void (*)(char*)); -typedef void* (*appGetEntryCallback)(); -typedef void (*AppLoaderCallback)(appInitCallback*, appGetNextCallback*, appGetEntryCallback*); - -OSExecParams* __OSExecParams AT_ADDRESS(0x800030F0); -s32 __OSAppLoaderOffset AT_ADDRESS(0x800030F4); - -void OSExecv(const char* dolfile, const char** argv); -void OSExecl(const char* dolfile, const char* arg0, ...); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/os/OSFastCast.h b/aurora-main/include/dolphin/os/OSFastCast.h deleted file mode 100644 index 6c57394..0000000 --- a/aurora-main/include/dolphin/os/OSFastCast.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef _DOLPHIN_OSFASTCAST_H_ -#define _DOLPHIN_OSFASTCAST_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -static inline void OSInitFastCast(void) {} - -static inline s16 __OSf32tos16(f32 inF) { return (s16) inF; } -static inline void OSf32tos16(f32 *f, s16 *out) { *out = __OSf32tos16(*f); } - -static inline u8 __OSf32tou8(f32 inF) { return (u8)inF; } -static inline void OSf32tou8(f32 *f, u8 *out) { *out = __OSf32tou8(*f); } - -static inline s8 __OSf32tos8(f32 inF) { return (s8) inF; } -static inline void OSf32tos8(f32 *f, s8 *out) { *out = __OSf32tos8(*f); } - -static inline u16 __OSf32tou16(f32 inF) { return (u16) inF; } -static inline void OSf32tou16(f32 *f, u16 *out) { *out = __OSf32tou16(*f); } - -static inline f32 __OSs8tof32(const s8* arg) { return (f32)*arg; } -static inline void OSs8tof32(const s8* in, f32* out) { *out = __OSs8tof32(in); } - -static inline f32 __OSs16tof32(const s16* arg) { return (f32)*arg; } -static inline void OSs16tof32(const s16* in, f32* out) { *out = __OSs16tof32(in); } - -static inline f32 __OSu8tof32(const u8* arg) { return (f32)*arg; } -static inline void OSu8tof32(const u8* in, f32* out) { *out = __OSu8tof32(in); } - -static inline f32 __OSu16tof32(const u16* arg) { return (f32)*arg; } -static inline void OSu16tof32(const u16* in, f32* out) { *out = __OSu16tof32(in); } - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/os/OSFont.h b/aurora-main/include/dolphin/os/OSFont.h deleted file mode 100644 index 1fff41a..0000000 --- a/aurora-main/include/dolphin/os/OSFont.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _DOLPHIN_OSFONT_H_ -#define _DOLPHIN_OSFONT_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define OS_FONT_ENCODE_ANSI 0u -#define OS_FONT_ENCODE_SJIS 1u -#define OS_FONT_ENCODE_MAX 5u -#define OS_FONT_SIZE_ANSI (288 + 131072) // 9 sheets -#define OS_FONT_SIZE_SJIS (3840 + 1179648) // 1 sheet -#define OS_FONT_ROM_SIZE_ANSI 0x03000 -#define OS_FONT_ROM_SIZE_SJIS 0x4D000 - -typedef struct OSFontHeader { - u16 fontType; - u16 firstChar; - u16 lastChar; - u16 invalChar; - u16 ascent; - u16 descent; - u16 width; - u16 leading; - u16 cellWidth; - u16 cellHeight; - u32 sheetSize; - u16 sheetFormat; - u16 sheetColumn; - u16 sheetRow; - u16 sheetWidth; - u16 sheetHeight; - u16 widthTable; - u32 sheetImage; - u32 sheetFullSize; - u8 c0; - u8 c1; - u8 c2; - u8 c3; -} OSFontHeader; - -u16 OSGetFontEncode(void); -u16 OSSetFontEncode(u16 encode); -BOOL OSInitFont(OSFontHeader* fontData); -u32 OSLoadFont(OSFontHeader* fontData, void* tmp); -char* OSGetFontTexture(const char* string, void** image, s32* x, s32* y, s32* width); -char* OSGetFontWidth(const char* string, s32* width); -char* OSGetFontTexel(const char* string, void* image, s32 pos, s32 stride, s32* width); -int OSSetFontWidth(int fixed); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/os/OSIC.h b/aurora-main/include/dolphin/os/OSIC.h deleted file mode 100644 index 3309d3a..0000000 --- a/aurora-main/include/dolphin/os/OSIC.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _DOLPHIN_OSIC_H_ -#define _DOLPHIN_OSIC_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -void ICFlashInvalidate(void); -void ICEnable(void); -void ICDisable(void); -void ICFreeze(void); -void ICUnfreeze(void); -void ICBlockInvalidate(void *addr); -void ICSync(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/os/OSInterrupt.h b/aurora-main/include/dolphin/os/OSInterrupt.h deleted file mode 100644 index 8fa27d2..0000000 --- a/aurora-main/include/dolphin/os/OSInterrupt.h +++ /dev/null @@ -1,119 +0,0 @@ -#ifndef _DOLPHIN_OSINTERRUPT_H_ -#define _DOLPHIN_OSINTERRUPT_H_ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef s16 __OSInterrupt; -typedef u32 OSInterruptMask; - -#define __OS_INTERRUPT_MEM_0 0 -#define __OS_INTERRUPT_MEM_1 1 -#define __OS_INTERRUPT_MEM_2 2 -#define __OS_INTERRUPT_MEM_3 3 -#define __OS_INTERRUPT_MEM_ADDRESS 4 -#define __OS_INTERRUPT_DSP_AI 5 -#define __OS_INTERRUPT_DSP_ARAM 6 -#define __OS_INTERRUPT_DSP_DSP 7 -#define __OS_INTERRUPT_AI_AI 8 -#define __OS_INTERRUPT_EXI_0_EXI 9 -#define __OS_INTERRUPT_EXI_0_TC 10 -#define __OS_INTERRUPT_EXI_0_EXT 11 -#define __OS_INTERRUPT_EXI_1_EXI 12 -#define __OS_INTERRUPT_EXI_1_TC 13 -#define __OS_INTERRUPT_EXI_1_EXT 14 -#define __OS_INTERRUPT_EXI_2_EXI 15 -#define __OS_INTERRUPT_EXI_2_TC 16 -#define __OS_INTERRUPT_PI_CP 17 -#define __OS_INTERRUPT_PI_PE_TOKEN 18 -#define __OS_INTERRUPT_PI_PE_FINISH 19 -#define __OS_INTERRUPT_PI_SI 20 -#define __OS_INTERRUPT_PI_DI 21 -#define __OS_INTERRUPT_PI_RSW 22 -#define __OS_INTERRUPT_PI_ERROR 23 -#define __OS_INTERRUPT_PI_VI 24 -#define __OS_INTERRUPT_PI_DEBUG 25 -#define __OS_INTERRUPT_PI_HSP 26 -#define __OS_INTERRUPT_MAX 32 - -#define OS_INTERRUPTMASK(interrupt) (0x80000000u >> (interrupt)) - -#define OS_INTERRUPTMASK_MEM_0 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_0) -#define OS_INTERRUPTMASK_MEM_1 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_1) -#define OS_INTERRUPTMASK_MEM_2 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_2) -#define OS_INTERRUPTMASK_MEM_3 OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_3) -#define OS_INTERRUPTMASK_MEM_ADDRESS OS_INTERRUPTMASK(__OS_INTERRUPT_MEM_ADDRESS) -#define OS_INTERRUPTMASK_MEM_RESET \ - (OS_INTERRUPTMASK_MEM_0 | OS_INTERRUPTMASK_MEM_1 | OS_INTERRUPTMASK_MEM_2 | \ - OS_INTERRUPTMASK_MEM_3) -#define OS_INTERRUPTMASK_MEM \ - (OS_INTERRUPTMASK_MEM_0 | OS_INTERRUPTMASK_MEM_1 | OS_INTERRUPTMASK_MEM_2 | \ - OS_INTERRUPTMASK_MEM_3 | OS_INTERRUPTMASK_MEM_ADDRESS) -#define OS_INTERRUPTMASK_DSP_AI OS_INTERRUPTMASK(__OS_INTERRUPT_DSP_AI) -#define OS_INTERRUPTMASK_DSP_ARAM OS_INTERRUPTMASK(__OS_INTERRUPT_DSP_ARAM) -#define OS_INTERRUPTMASK_DSP_DSP OS_INTERRUPTMASK(__OS_INTERRUPT_DSP_DSP) -#define OS_INTERRUPTMASK_DSP \ - (OS_INTERRUPTMASK_DSP_AI | OS_INTERRUPTMASK_DSP_ARAM | OS_INTERRUPTMASK_DSP_DSP) -#define OS_INTERRUPTMASK_AI_AI OS_INTERRUPTMASK(__OS_INTERRUPT_AI_AI) -#define OS_INTERRUPTMASK_AI (OS_INTERRUPTMASK_AI_AI) -#define OS_INTERRUPTMASK_EXI_0_EXI OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_0_EXI) -#define OS_INTERRUPTMASK_EXI_0_TC OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_0_TC) -#define OS_INTERRUPTMASK_EXI_0_EXT OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_0_EXT) -#define OS_INTERRUPTMASK_EXI_0 \ - (OS_INTERRUPTMASK_EXI_0_EXI | OS_INTERRUPTMASK_EXI_0_TC | OS_INTERRUPTMASK_EXI_0_EXT) -#define OS_INTERRUPTMASK_EXI_1_EXI OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_1_EXI) -#define OS_INTERRUPTMASK_EXI_1_TC OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_1_TC) -#define OS_INTERRUPTMASK_EXI_1_EXT OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_1_EXT) -#define OS_INTERRUPTMASK_EXI_1 \ - (OS_INTERRUPTMASK_EXI_1_EXI | OS_INTERRUPTMASK_EXI_1_TC | OS_INTERRUPTMASK_EXI_1_EXT) -#define OS_INTERRUPTMASK_EXI_2_EXI OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_2_EXI) -#define OS_INTERRUPTMASK_EXI_2_TC OS_INTERRUPTMASK(__OS_INTERRUPT_EXI_2_TC) -#define OS_INTERRUPTMASK_EXI_2 (OS_INTERRUPTMASK_EXI_2_EXI | OS_INTERRUPTMASK_EXI_2_TC) -#define OS_INTERRUPTMASK_EXI \ - (OS_INTERRUPTMASK_EXI_0_EXI | OS_INTERRUPTMASK_EXI_0_TC | OS_INTERRUPTMASK_EXI_0_EXT | \ - OS_INTERRUPTMASK_EXI_1_EXI | OS_INTERRUPTMASK_EXI_1_TC | OS_INTERRUPTMASK_EXI_1_EXT | \ - OS_INTERRUPTMASK_EXI_2_EXI | OS_INTERRUPTMASK_EXI_2_TC) -#define OS_INTERRUPTMASK_PI_PE_TOKEN OS_INTERRUPTMASK(__OS_INTERRUPT_PI_PE_TOKEN) -#define OS_INTERRUPTMASK_PI_PE_FINISH OS_INTERRUPTMASK(__OS_INTERRUPT_PI_PE_FINISH) -#define OS_INTERRUPTMASK_PI_PE (OS_INTERRUPTMASK_PI_PE_TOKEN | OS_INTERRUPTMASK_PI_PE_FINISH) -#define OS_INTERRUPTMASK_PI_CP OS_INTERRUPTMASK(__OS_INTERRUPT_PI_CP) -#define OS_INTERRUPTMASK_PI_SI OS_INTERRUPTMASK(__OS_INTERRUPT_PI_SI) -#define OS_INTERRUPTMASK_PI_DI OS_INTERRUPTMASK(__OS_INTERRUPT_PI_DI) -#define OS_INTERRUPTMASK_PI_RSW OS_INTERRUPTMASK(__OS_INTERRUPT_PI_RSW) -#define OS_INTERRUPTMASK_PI_ERROR OS_INTERRUPTMASK(__OS_INTERRUPT_PI_ERROR) -#define OS_INTERRUPTMASK_PI_VI OS_INTERRUPTMASK(__OS_INTERRUPT_PI_VI) -#define OS_INTERRUPTMASK_PI_DEBUG OS_INTERRUPTMASK(__OS_INTERRUPT_PI_DEBUG) -#define OS_INTERRUPTMASK_PI_HSP OS_INTERRUPTMASK(__OS_INTERRUPT_PI_HSP) -#define OS_INTERRUPTMASK_PI \ - (OS_INTERRUPTMASK_PI_CP | OS_INTERRUPTMASK_PI_SI | OS_INTERRUPTMASK_PI_DI | \ - OS_INTERRUPTMASK_PI_RSW | OS_INTERRUPTMASK_PI_ERROR | OS_INTERRUPTMASK_PI_VI | \ - OS_INTERRUPTMASK_PI_PE_TOKEN | OS_INTERRUPTMASK_PI_PE_FINISH | OS_INTERRUPTMASK_PI_DEBUG | \ - OS_INTERRUPTMASK_PI_HSP) - -typedef void (*__OSInterruptHandler)(__OSInterrupt interrupt, OSContext* context); - -extern volatile __OSInterrupt __OSLastInterrupt; -extern volatile u32 __OSLastInterruptSrr0; -extern volatile OSTime __OSLastInterruptTime; - -__OSInterruptHandler __OSSetInterruptHandler(__OSInterrupt interrupt, __OSInterruptHandler handler); - -__OSInterruptHandler __OSGetInterruptHandler(__OSInterrupt interrupt); - -void __OSDispatchInterrupt(__OSException exception, OSContext* context); - -OSInterruptMask OSGetInterruptMask(void); -OSInterruptMask OSSetInterruptMask(OSInterruptMask mask); -OSInterruptMask __OSMaskInterrupts(OSInterruptMask mask); -OSInterruptMask __OSUnmaskInterrupts(OSInterruptMask mask); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/os/OSL2.h b/aurora-main/include/dolphin/os/OSL2.h deleted file mode 100644 index 01b4a62..0000000 --- a/aurora-main/include/dolphin/os/OSL2.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _DOLPHIN_OSL2_H_ -#define _DOLPHIN_OSL2_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void L2Enable(void); -void L2Disable(void); -void L2GlobalInvalidate(void); -void L2SetDataOnly(BOOL dataOnly); -void L2SetWriteThrough(BOOL writeThrough); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/os/OSLC.h b/aurora-main/include/dolphin/os/OSLC.h deleted file mode 100644 index af49708..0000000 --- a/aurora-main/include/dolphin/os/OSLC.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _DOLPHIN_OSLC_H_ -#define _DOLPHIN_OSLC_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void LCAllocOneTag(BOOL invalidate, void *tag); -void LCAllocTags(BOOL invalidate, void *startTag, u32 numBlocks); -void LCAlloc(void *addr, u32 nBytes); -void LCAllocNoInvalidate(void *addr, u32 nBytes); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/os/OSMemory.h b/aurora-main/include/dolphin/os/OSMemory.h deleted file mode 100644 index a5debeb..0000000 --- a/aurora-main/include/dolphin/os/OSMemory.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _DOLPHIN_OSMEMORY_H_ -#define _DOLPHIN_OSMEMORY_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define OS_PROTECT_CHAN0 0 -#define OS_PROTECT_CHAN1 1 -#define OS_PROTECT_CHAN2 2 -#define OS_PROTECT_CHAN3 3 - -#define OS_PROTECT_CONTROL_NONE 0x00 -#define OS_PROTECT_CONTROL_READ 0x01 -#define OS_PROTECT_CONTROL_WRITE 0x02 -#define OS_PROTECT_CONTROL_RDWR (OS_PROTECT_CONTROL_READ | OS_PROTECT_CONTROL_WRITE) - -void OSProtectRange(u32 chan, void* addr, u32 nBytes, u32 control); -u32 OSGetPhysicalMemSize(void); -u32 OSGetConsoleSimulatedMemSize(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/os/OSMessage.h b/aurora-main/include/dolphin/os/OSMessage.h deleted file mode 100644 index 19743b8..0000000 --- a/aurora-main/include/dolphin/os/OSMessage.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef _DOLPHIN_OSMESSAGE_H_ -#define _DOLPHIN_OSMESSAGE_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void* OSMessage; - -#define OS_MESSAGE_NOBLOCK 0 -#define OS_MESSAGE_BLOCK 1 - -typedef struct { - OSThreadQueue queueSend; - OSThreadQueue queueReceive; - OSMessage* msgArray; - s32 msgCount; - s32 firstIndex; - s32 usedCount; -} OSMessageQueue; - -void OSInitMessageQueue(OSMessageQueue* mq, OSMessage* msgArray, s32 msgCount); -BOOL OSSendMessage(OSMessageQueue* mq, OSMessage msg, s32 flags); -BOOL OSReceiveMessage(OSMessageQueue* mq, OSMessage* msg, s32 flags); -BOOL OSJamMessage(OSMessageQueue* mq, OSMessage msg, s32 flags); - -#ifdef __cplusplus -} -#endif - -#endif // _DOLPHIN_OSMESSAGE_H_ diff --git a/aurora-main/include/dolphin/os/OSModule.h b/aurora-main/include/dolphin/os/OSModule.h deleted file mode 100644 index 6e66e9b..0000000 --- a/aurora-main/include/dolphin/os/OSModule.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef _DOLPHIN_OSMODULE_H_ -#define _DOLPHIN_OSMODULE_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define OS_MODULE_VERSION 3 -typedef struct OSModuleHeader OSModuleHeader; - -typedef u32 OSModuleID; -typedef struct OSModuleQueue OSModuleQueue; -typedef struct OSModuleLink OSModuleLink; -typedef struct OSModuleInfo OSModuleInfo; -typedef struct OSSectionInfo OSSectionInfo; -typedef struct OSImportInfo OSImportInfo; -typedef struct OSRel OSRel; - -struct OSModuleQueue { - OSModuleInfo* head; - OSModuleInfo* tail; -}; - -struct OSModuleLink { - OSModuleInfo* next; - OSModuleInfo* prev; -}; - -struct OSModuleInfo { - OSModuleID id; // unique identifier for the module - OSModuleLink link; // doubly linked list of modules - u32 numSections; // # of sections - u32 sectionInfoOffset; // offset to section info table - u32 nameOffset; // offset to module name - u32 nameSize; // size of module name - u32 version; // version number -}; - -struct OSModuleHeader { - // CAUTION: info must be the 1st member - OSModuleInfo info; - - // OS_MODULE_VERSION == 1 - u32 bssSize; // total size of bss sections in bytes - u32 relOffset; - u32 impOffset; - u32 impSize; // size in bytes - u8 prologSection; // section # for prolog function - u8 epilogSection; // section # for epilog function - u8 unresolvedSection; // section # for unresolved function - u8 bssSection; // section # for bss section (set at run-time) - u32 prolog; // prolog function offset - u32 epilog; // epilog function offset - u32 unresolved; // unresolved function offset - - // OS_MODULE_VERSION == 2 -#if (2 <= OS_MODULE_VERSION) - u32 align; // module alignment constraint - u32 bssAlign; // bss alignment constraint -#endif - - // OS_MODULE_VERSION == 3 -#if (3 <= OS_MODULE_VERSION) - u32 fixSize; -#endif -}; - -#define OSGetSectionInfo(module) ((OSSectionInfo*)(((OSModuleInfo*)(module))->sectionInfoOffset)) - -struct OSSectionInfo { - u32 offset; - u32 size; -}; - -// OSSectionInfo.offset bit -#define OS_SECTIONINFO_EXEC 0x1 -#define OS_SECTIONINFO_OFFSET(offset) ((offset) & ~0x1) - -struct OSImportInfo { - OSModuleID id; // external module id - u32 offset; // offset to OSRel instructions -}; - -struct OSRel { - u16 offset; // byte offset from the previous entry - u8 type; - u8 section; - u32 addend; -}; - -#define R_DOLPHIN_NOP 201 // C9h current offset += OSRel.offset -#define R_DOLPHIN_SECTION 202 // CAh current section = OSRel.section -#define R_DOLPHIN_END 203 // CBh -#define R_DOLPHIN_MRKREF 204 // CCh - -void OSSetStringTable(void* stringTable); -BOOL OSLink(OSModuleInfo* newModule, void* bss); - -#if (3 <= OS_MODULE_VERSION) -BOOL OSLinkFixed(OSModuleInfo* newModule, void* bss); -#endif - -BOOL OSUnlink(OSModuleInfo* oldModule); - -OSModuleInfo* OSSearchModule(void* ptr, u32* section, u32* offset); - -// debugger notification -void OSNotifyLink(OSModuleInfo* module); -void OSNotifyUnlink(OSModuleInfo* module); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/os/OSMutex.h b/aurora-main/include/dolphin/os/OSMutex.h deleted file mode 100644 index ef5565e..0000000 --- a/aurora-main/include/dolphin/os/OSMutex.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef _DOLPHIN_OSMUTEX_H_ -#define _DOLPHIN_OSMUTEX_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct OSMutex { - /* 0x00 */ OSThreadQueue queue; - /* 0x08 */ OSThread* thread; - /* 0x0C */ s32 count; - /* 0x10 */ OSMutexLink link; -}; - -typedef struct OSCond { - OSThreadQueue queue; -} OSCond; - -void OSInitMutex(OSMutex* mutex); -void OSLockMutex(OSMutex* mutex); -void OSUnlockMutex(OSMutex* mutex); -BOOL OSTryLockMutex(OSMutex* mutex); -void OSInitCond(OSCond* cond); -void OSWaitCond(OSCond* cond, OSMutex* mutex); -void OSSignalCond(OSCond* cond); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/os/OSReboot.h b/aurora-main/include/dolphin/os/OSReboot.h deleted file mode 100644 index 6509534..0000000 --- a/aurora-main/include/dolphin/os/OSReboot.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _DOLPHIN_OSREBOOT_H_ -#define _DOLPHIN_OSREBOOT_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void OSSetSaveRegion(void* start, void* end); -void OSGetSaveRegion(void** start, void** end); -void OSGetSavedRegion(void** start, void** end); -void __OSReboot(u32 resetCode, u32 bootDol); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/os/OSReset.h b/aurora-main/include/dolphin/os/OSReset.h deleted file mode 100644 index 8c6b27d..0000000 --- a/aurora-main/include/dolphin/os/OSReset.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef _DOLPHIN_OSRESET_H_ -#define _DOLPHIN_OSRESET_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define OS_RESET_RESTART 0 -#define OS_RESET_HOTRESET 1 -#define OS_RESET_SHUTDOWN 2 - -typedef struct OSResetFunctionInfo OSResetFunctionInfo; -typedef struct OSResetFunctionQueue { - OSResetFunctionInfo* head; - OSResetFunctionInfo* tail; -} OSResetFunctionQueue; - -typedef BOOL (*OSResetFunction)(BOOL); - -struct OSResetFunctionInfo { - OSResetFunction func; - u32 priority; - OSResetFunctionInfo* next; - OSResetFunctionInfo* prev; -}; - -#define OS_RESET_RESTART 0 -#define OS_RESET_HOTRESET 1 -#define OS_RESET_SHUTDOWN 2 -#define OS_RESETCODE_RESTART 0x80000000 - -void OSRegisterResetFunction(OSResetFunctionInfo* info); -void OSUnregisterResetFunction(OSResetFunctionInfo* info); -void OSResetSystem(int reset, u32 resetCode, BOOL forceMenu); -u32 OSGetResetCode(); -u32 OSSetBootDol(u32 dolOffset); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/os/OSResetSW.h b/aurora-main/include/dolphin/os/OSResetSW.h deleted file mode 100644 index 3c630b8..0000000 --- a/aurora-main/include/dolphin/os/OSResetSW.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _DOLPHIN_OSRESETSW_H_ -#define _DOLPHIN_OSRESETSW_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*OSResetCallback)(void); - -OSResetCallback OSSetResetCallback(OSResetCallback callback); -BOOL OSGetResetSwitchState(void); -BOOL OSGetResetButtonState(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/os/OSRtc.h b/aurora-main/include/dolphin/os/OSRtc.h deleted file mode 100644 index 583043f..0000000 --- a/aurora-main/include/dolphin/os/OSRtc.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef _DOLPHIN_OSRTC_H_ -#define _DOLPHIN_OSRTC_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// make the assert happy -#define OS_SOUND_MODE_MONO 0 -#define OS_SOUND_MODE_STEREO 1 - -// make the asserts happy -#define OS_VIDEO_MODE_NTSC 0 -#define OS_VIDEO_MODE_MPAL 2 - -#define OS_PROGRESSIVE_MODE_OFF 0 -#define OS_PROGRESSIVE_MODE_ON 1 - -#define OS_EURGB60_OFF 0 -#define OS_EURGB60_ON 1 - -#define OS_LANGUAGE_ENGLISH 0 -#define OS_LANGUAGE_GERMAN 1 -#define OS_LANGUAGE_FRENCH 2 -#define OS_LANGUAGE_SPANISH 3 -#define OS_LANGUAGE_ITALIAN 4 -#define OS_LANGUAGE_DUTCH 5 - -typedef struct OSSram { - u16 checkSum; - u16 checkSumInv; - u32 ead0; - u32 ead1; - u32 counterBias; - s8 displayOffsetH; - u8 ntd; - u8 language; - u8 flags; -} OSSram; - -typedef struct OSSramEx { - u8 flashID[2][12]; - u32 wirelessKeyboardID; - u16 wirelessPadID[4]; - u8 dvdErrorCode; - u8 _padding0; - u8 flashIDCheckSum[2]; - u16 gbs; - u8 _padding1[2]; -} OSSramEx; - -#define SRAM_SIZE (sizeof(OSSram) + sizeof(OSSramEx)) - -typedef struct SramControl { - u8 sram[SRAM_SIZE]; // dummy for OSSram + OSSramEx - u32 offset; - BOOL enabled; - BOOL locked; - int sync; - void (*callback)(); -} SramControl; - -u32 OSGetSoundMode(void); -void OSSetSoundMode(u32 mode); -u32 OSGetVideoMode(void); -void OSSetVideoMode(u32 mode); -u8 OSGetLanguage(void); -void OSSetLanguage(u8 language); -u16 OSGetGbsMode(void); -void OSSetGbsMode(u16 mode); -u32 OSGetProgressiveMode(void); -void OSSetProgressiveMode(u32 on); -u32 OSGetEuRgb60Mode(void); -void OSSetEuRgb60Mode(u32 on); -u16 OSGetWirelessID(s32 chan); -void OSSetWirelessID(s32 chan, u16 id); - -#ifdef __cplusplus -} -#endif - -#endif // _DOLPHIN_OSRTC_H_ diff --git a/aurora-main/include/dolphin/os/OSSemaphore.h b/aurora-main/include/dolphin/os/OSSemaphore.h deleted file mode 100644 index aac2381..0000000 --- a/aurora-main/include/dolphin/os/OSSemaphore.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _DOLPHIN_OSSEMAPHORE_H_ -#define _DOLPHIN_OSSEMAPHORE_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct OSSemaphore { - s32 count; - OSThreadQueue queue; -} OSSemaphore; - -void OSInitSemaphore(OSSemaphore* sem, s32 count); -s32 OSWaitSemaphore(OSSemaphore* sem); -s32 OSTryWaitSemaphore(OSSemaphore* sem); -s32 OSSignalSemaphore(OSSemaphore* sem); -s32 OSGetSemaphoreCount(OSSemaphore* sem); - -#ifdef __cplusplus -} -#endif - -#endif // _DOLPHIN_OSSEMAPHORE_H_ diff --git a/aurora-main/include/dolphin/os/OSSerial.h b/aurora-main/include/dolphin/os/OSSerial.h deleted file mode 100644 index 7c38395..0000000 --- a/aurora-main/include/dolphin/os/OSSerial.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _DOLPHIN_OSSERIAL_H -#define _DOLPHIN_OSSERIAL_H - -#include - -#endif // _DOLPHIN_OSSERIAL_H diff --git a/aurora-main/include/dolphin/os/OSThread.h b/aurora-main/include/dolphin/os/OSThread.h deleted file mode 100644 index 2053ff5..0000000 --- a/aurora-main/include/dolphin/os/OSThread.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef _DOLPHIN_OSTHREAD_H_ -#define _DOLPHIN_OSTHREAD_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef s32 OSPriority; - -typedef struct OSThread OSThread; -typedef struct OSMutex OSMutex; -typedef struct OSThreadQueue OSThreadQueue; -typedef struct OSMutexQueue OSMutexQueue; -typedef struct OSThreadLink OSThreadLink; -typedef struct OSMutexLink OSMutexLink; - -struct OSThreadQueue { - OSThread* head; - OSThread* tail; -}; - -struct OSThreadLink { - OSThread* next; - OSThread* prev; -}; - -struct OSMutexQueue { - OSMutex* head; - OSMutex* tail; -}; - -struct OSMutexLink { - OSMutex* next; - OSMutex* prev; -}; - -struct OSThread { - /* 0x000 */ OSContext context; - /* 0x2C8 */ u16 state; - /* 0x2CA */ u16 attr; - /* 0x2CC */ s32 suspend; - /* 0x2D0 */ OSPriority priority; - /* 0x2D4 */ OSPriority base; - /* 0x2D8 */ void* val; - /* 0x2DC */ OSThreadQueue* queue; - /* 0x2E0 */ OSThreadLink link; - /* 0x2E8 */ OSThreadQueue queueJoin; - /* 0x2F0 */ OSMutex* mutex; - /* 0x2F4 */ OSMutexQueue queueMutex; - /* 0x2FC */ OSThreadLink linkActive; - /* 0x304 */ u8* stackBase; - /* 0x308 */ u8* stackEnd; - /* 0x30C */ s32 error; - /* 0x310 */ void* specific[2]; -}; - -enum OS_THREAD_STATE { - OS_THREAD_STATE_READY = 1, - OS_THREAD_STATE_RUNNING = 2, - OS_THREAD_STATE_WAITING = 4, - OS_THREAD_STATE_MORIBUND = 8, -}; - -#define OS_PRIORITY_MIN 0 // highest -#define OS_PRIORITY_MAX 31 // lowest -#define OS_PRIORITY_IDLE OS_PRIORITY_MAX - -#define OS_THREAD_SPECIFIC_MAX 2 - -#define OS_THREAD_ATTR_DETACH 0x0001u - -#define OS_THREAD_STACK_MAGIC 0xDEADBABE - -typedef void (*OSSwitchThreadCallback)(OSThread*, OSThread*); -typedef void (*OSIdleFunction)(void*); - -void OSInitThreadQueue(OSThreadQueue* queue); -void OSSleepThread(OSThreadQueue* queue); -void OSWakeupThread(OSThreadQueue* queue); -s32 OSSuspendThread(OSThread* thread); -s32 OSResumeThread(OSThread* thread); -OSThread* OSGetCurrentThread(void); -s32 OSEnableScheduler(void); -s32 OSDisableScheduler(void); -void OSCancelThread(OSThread* thread); -void OSClearStack(u8 val); -BOOL OSIsThreadSuspended(OSThread* thread); -BOOL OSIsThreadTerminated(OSThread* thread); -void OSYieldThread(void); -BOOL OSCreateThread(OSThread* thread, void* (*func)(void*), void* param, void* stack, u32 stackSize, - OSPriority priority, u16 attr); -void OSExitThread(void* val); -BOOL OSJoinThread(OSThread* thread, void** val); -void OSDetachThread(OSThread* thread); -BOOL OSSetThreadPriority(OSThread* thread, OSPriority priority); -s32 OSGetThreadPriority(OSThread* thread); -OSThread* OSSetIdleFunction(OSIdleFunction idleFunction, void* param, void* stack, u32 stackSize); -OSThread* OSGetIdleFunction(void); -s32 OSCheckActiveThreads(void); -void OSSetThreadSpecific(s32 index, void* ptr); -void* OSGetThreadSpecific(s32 index); - -OSSwitchThreadCallback OSSetSwitchThreadCallback(OSSwitchThreadCallback callback); - -#define IsSuspended(suspend) (suspend > 0) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/os/OSTime.h b/aurora-main/include/dolphin/os/OSTime.h deleted file mode 100644 index 2dc1cf2..0000000 --- a/aurora-main/include/dolphin/os/OSTime.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef _DOLPHIN_OSTIME_H_ -#define _DOLPHIN_OSTIME_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef s64 OSTime; -typedef u32 OSTick; - -#define OSDiffTick(tick1, tick0) ((s32)(tick1) - (s32)(tick0)) - -// Time base frequency = 1/4 bus clock -#define OS_TIME_SPEED (OS_BUS_CLOCK / 4) - -// OS time -> Real time -#define OS_TICKS_TO_SEC(x) ((x) / (OS_TIME_SPEED)) -#define OS_TICKS_TO_MSEC(x) ((x) / (OS_TIME_SPEED / 1000)) -#define OS_TICKS_TO_USEC(x) (((x) * 8) / (OS_TIME_SPEED / 125000)) -#define OS_TICKS_TO_NSEC(x) (((x) * 8000) / (OS_TIME_SPEED / 125000)) - -// Real time -> OS time -#define OS_SEC_TO_TICKS(x) ((x) * (OS_TIME_SPEED)) -#define OS_MSEC_TO_TICKS(x) ((x) * (OS_TIME_SPEED / 1000)) -#define OS_USEC_TO_TICKS(x) ((x) * (OS_TIME_SPEED / 125000) / 8) -#define OS_NSEC_TO_TICKS(x) ((x) * (OS_TIME_SPEED / 125000) / 8000) - -#define USEC_MAX 1000 -#define MSEC_MAX 1000 -#define MONTH_MAX 12 -#define WEEK_DAY_MAX 7 -#define YEAR_DAY_MAX 365 - -#define SECS_IN_MIN 60 -#define SECS_IN_HOUR (SECS_IN_MIN * 60) -#define SECS_IN_DAY (SECS_IN_HOUR * 24) -#define SECS_IN_YEAR (SECS_IN_DAY * 365) - -#define BIAS 0xB2575 - -#define __OSSystemTime (OSTime*)0x800030D8 - -#ifdef __cplusplus -} -#endif - -#endif // _DOLPHIN_OSTIME_H_ diff --git a/aurora-main/include/dolphin/os/OSTimer.h b/aurora-main/include/dolphin/os/OSTimer.h deleted file mode 100644 index 490cccb..0000000 --- a/aurora-main/include/dolphin/os/OSTimer.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _DOLPHIN_OSTIMER_H_ -#define _DOLPHIN_OSTIMER_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*OSTimerCallback)(void); - -OSTimerCallback OSSetTimerCallback(OSTimerCallback callback); -void OSInitTimer(u32 time, u32 mode); -void OSStartTimer(void); -void OSStopTimer(void); - -#ifdef __cplusplus -} -#endif - -#endif // _DOLPHIN_OSTIMER_H_ diff --git a/aurora-main/include/dolphin/os/OSUtf.h b/aurora-main/include/dolphin/os/OSUtf.h deleted file mode 100644 index 2f721d5..0000000 --- a/aurora-main/include/dolphin/os/OSUtf.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _DOLPHIN_OSUTF_H_ -#define _DOLPHIN_OSUTF_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -char* OSUTF8to32(const char* utf8, u32* utf32); -char* OSUTF32to8(u32 utf32, char* utf8); -u16* OSUTF16to32(const u16* utf16, u32* utf32); -u16* OSUTF32to16(u32 utf32, u16* utf16); -u8 OSUTF32toANSI(u32 utf32); -u32 OSANSItoUTF32(u8 ansi); -u16 OSUTF32toSJIS(u32 utf32); -u32 OSSJIStoUTF32(u16 sjis); - -#ifdef __cplusplus -} -#endif - -#endif // _DOLPHIN_OSUTF_H_ diff --git a/aurora-main/include/dolphin/pad.h b/aurora-main/include/dolphin/pad.h deleted file mode 100644 index 69dfcd3..0000000 --- a/aurora-main/include/dolphin/pad.h +++ /dev/null @@ -1,316 +0,0 @@ -#ifndef DOLPHIN_PAD_H -#define DOLPHIN_PAD_H - -#include - -#define PAD_SPEC_0 0 -#define PAD_SPEC_1 1 -#define PAD_SPEC_2 2 -#define PAD_SPEC_3 3 -#define PAD_SPEC_4 4 -#define PAD_SPEC_5 5 - -#define PAD_CHAN0 0 -#define PAD_CHAN1 1 -#define PAD_CHAN2 2 -#define PAD_CHAN3 3 -#define PAD_CHANMAX 4 - -#define PAD_MOTOR_STOP 0 -#define PAD_MOTOR_RUMBLE 1 -#define PAD_MOTOR_STOP_HARD 2 - -#define PAD_ERR_NONE 0 -#define PAD_ERR_NO_CONTROLLER -1 -#define PAD_ERR_NOT_READY -2 -#define PAD_ERR_TRANSFER -3 - -#define PAD_MAX_CONTROLLERS 4 - -#define PAD_BUTTON_LEFT 0x0001 -#define PAD_BUTTON_RIGHT 0x0002 -#define PAD_BUTTON_DOWN 0x0004 -#define PAD_BUTTON_UP 0x0008 -#define PAD_TRIGGER_Z 0x0010 -#define PAD_TRIGGER_R 0x0020 -#define PAD_TRIGGER_L 0x0040 -#define PAD_BUTTON_A 0x0100 -#define PAD_BUTTON_B 0x0200 -#define PAD_BUTTON_X 0x0400 -#define PAD_BUTTON_Y 0x0800 -#define PAD_BUTTON_MENU 0x1000 -#define PAD_BUTTON_START 0x1000 -#ifdef TARGET_PC -#define PAD_BUTTON_BACK 0x0002000 -#define PAD_BUTTON_GUIDE 0x0004000 -#define PAD_BUTTON_MISC1 0x0008000 -#define PAD_BUTTON_MISC2 0x0010000 -#define PAD_BUTTON_MISC3 0x0020000 -#define PAD_BUTTON_MISC4 0x0040000 -#define PAD_BUTTON_MISC5 0x0080000 -#define PAD_BUTTON_MISC6 0x0100000 -#define PAD_BUTTON_RIGHT_PADDLE1 0x0200000 -#define PAD_BUTTON_LEFT_PADDLE1 0x0400000 -#define PAD_BUTTON_RIGHT_PADDLE2 0x0800000 -#define PAD_BUTTON_LEFT_PADDLE2 0x1000000 -#define PAD_BUTTON_RIGHT_STICK 0x2000000 -#define PAD_BUTTON_LEFT_STICK 0x4000000 -#define PAD_BUTTON_TOUCHPAD 0x8000000 -#define PAD_EXT_BUTTON_COUNT 15 -#endif - -#define PAD_BUTTON_COUNT 12 - -// added by Aurora, not present in original SDK -#define PAD_AXIS_LEFT_X_POS 0 -#define PAD_AXIS_LEFT_X_NEG 1 -#define PAD_AXIS_LEFT_Y_POS 2 -#define PAD_AXIS_LEFT_Y_NEG 3 -#define PAD_AXIS_RIGHT_X_POS 4 -#define PAD_AXIS_RIGHT_X_NEG 5 -#define PAD_AXIS_RIGHT_Y_POS 6 -#define PAD_AXIS_RIGHT_Y_NEG 7 -#define PAD_AXIS_TRIGGER_L 8 -#define PAD_AXIS_TRIGGER_R 9 - -#define PAD_AXIS_COUNT 10 - -#define PAD_CHAN0_BIT 0x80000000 -#define PAD_CHAN1_BIT 0x40000000 -#define PAD_CHAN2_BIT 0x20000000 -#define PAD_CHAN3_BIT 0x10000000 - -#define PADButtonDown(buttonLast, button) (((buttonLast) ^ (button)) & (button)) -#define PADButtonUp(buttonLast, button) (((buttonLast) ^ (button)) & (buttonLast)) - -#ifdef __cplusplus -extern "C" { -#endif - -#define PAD_NATIVE_BUTTON_INVALID 0xFFFFFFFF - -typedef struct PADStatus { - u16 button; - s8 stickX; - s8 stickY; - s8 substickX; - s8 substickY; - union { - u8 triggerLeft; - u8 triggerL; - }; - union { - u8 triggerRight; - u8 triggerR; - }; - u8 analogA; - u8 analogB; - s8 err; -#ifdef TARGET_PC - u32 extButton; -#endif -} PADStatus; - -typedef enum PADAxisSign { - AXIS_SIGN_NEGATIVE = -1, - AXIS_SIGN_POSITIVE = 1, -} PADAxisSign; - -typedef struct PADSignedNativeAxis { - int32_t nativeAxis; - PADAxisSign sign; -} PADSignedNativeAxis; - -struct SDL_Gamepad; - -BOOL PADInit(); -u32 PADRead(PADStatus* status); -BOOL PADReset(u32 mask); -BOOL PADRecalibrate(u32 mask); -void PADClamp(PADStatus* status); -void PADClampCircle(PADStatus* status); -void PADControlMotor(u32 chan, u32 cmd); -void PADSetSpec(u32 spec); -void PADControlAllMotors(const u32* cmdArr); -void PADSetAnalogMode(u32 mode); - -#ifdef TARGET_PC -#define PAD_KEY_INVALID (-1) -#define PAD_KEY_MOUSE_LEFT (-2) -#define PAD_KEY_MOUSE_MIDDLE (-3) -#define PAD_KEY_MOUSE_RIGHT (-4) -#define PAD_KEY_MOUSE_X1 (-5) -#define PAD_KEY_MOUSE_X2 (-6) -typedef u16 PADButton; -typedef u32 PADExtButton; -typedef u16 PADAxis; - -typedef struct PADKeyButtonBinding { - s32 scancode; - PADButton padButton; -} PADKeyButtonBinding; - -typedef struct PADKeyAxisBinding { - s32 scancode; - PADAxis padAxis; - s16 influence; // normalized percentage between 0 and 1 -} PADKeyAxisBinding; - -/* New API to facilitate controller interactions */ -typedef struct PADDeadZones { - bool emulateTriggers; - bool useDeadzones; - u16 stickDeadZone; - u16 substickDeadZone; - u16 leftTriggerActivationZone; - u16 rightTriggerActivationZone; -} PADDeadZones; - -typedef struct PADButtonMapping { - u32 nativeButton; - PADButton padButton; -} PADButtonMapping; - -// Explicitly disabled, unlike INVALID which permits default L/R trigger input. -#define PAD_NATIVE_BUTTON_DISABLED 0xfffffffeu - -// Axis-to-button bindings share the persisted nativeButton field without -// changing the binary layout of existing controller mapping files. -constexpr u32 PADEncodeAxisButton(u32 axis, bool negative, u32 threshold = 50) { - return 0x10000u | axis | (negative ? 0x80u : 0u) | (threshold << 8); -} -constexpr bool PADIsAxisButton(u32 binding) { return (binding & 0xffff0000u) == 0x10000u; } -constexpr u32 PADAxisButtonThreshold(u32 binding) { return (binding >> 8) & 0xffu; } -constexpr u32 PADAxisButtonAxis(u32 binding) { return binding & 0x7fu; } -constexpr bool PADAxisButtonNegative(u32 binding) { return (binding & 0x80u) != 0; } -constexpr u32 PADAxisButtonIdentity(u32 binding) { - return PADIsAxisButton(binding) ? (binding & ~0xff00u) : binding; -} - -typedef struct PADAxisMapping { - PADSignedNativeAxis nativeAxis; - s32 nativeButton; - PADAxis padAxis; -} PADAxisMapping; - -typedef struct PADDefaultMapping { - PADButtonMapping buttons[PAD_BUTTON_COUNT]; - PADAxisMapping axes[PAD_AXIS_COUNT]; -} PADDefaultMapping; - -/* Returns the total number of controllers */ -u32 PADCount(); -/* Returns the controller name for the given index into the controller map */ -const char* PADGetNameForControllerIndex(u32 idx); -void PADSetPortForIndex(u32 index, u32 port); -s32 PADGetIndexForPort(u32 port); -void PADGetVidPid(u32 port, u32* vid, u32* pid); -void PADClearPort(u32 port); -const char* PADGetName(u32 port); -void PADSetButtonMapping(u32 port, PADButtonMapping mapping); -void PADSetAllButtonMappings(u32 port, PADButtonMapping buttons[PAD_BUTTON_COUNT]); -PADButtonMapping* PADGetButtonMappings(u32 port, u32* buttonCount); -void PADSetAltButtonMapping(u32 port, PADButtonMapping mapping); -PADButtonMapping* PADGetAltButtonMappings(u32 port, u32* buttonCount); -void PADSetAxisMapping(u32 port, PADAxisMapping mapping); -void PADSetAllAxisMappings(u32 port, PADAxisMapping axes[PAD_AXIS_COUNT]); -PADAxisMapping* PADGetAxisMappings(u32 port, u32* axisCount); -void PADSerializeMappings(); - -BOOL PADSetKeyButtonBinding(u32 port, PADKeyButtonBinding binding); -BOOL PADSetKeyButtonBindings(u32 port, PADKeyButtonBinding bindings[PAD_BUTTON_COUNT]); -PADKeyButtonBinding* PADGetKeyButtonBindings(u32 port, u32* buttonCount); -BOOL PADSetKeyAxisBinding(u32 port, PADKeyAxisBinding binding); -BOOL PADSetKeyAxisBindings(u32 port, PADKeyAxisBinding bindings[PAD_BUTTON_COUNT]); -PADKeyAxisBinding* PADGetKeyAxisBindings(u32 port, u32* axisCount); -void PADClearKeyBindings(u32 port); -void PADSetKeyboardActive(u32 port, BOOL active); - -PADDeadZones* PADGetDeadZones(u32 port); -const char* PADGetButtonName(PADButton); -const char* PADGetNativeButtonName(u32 button); -const char* PADGetAxisName(PADAxis); -const char* PADGetAxisDirectionLabel(PADAxis); -const char* PADGetNativeAxisName(PADSignedNativeAxis axis); - -BOOL PADIsGCAdapter(u32 port); - -/** - * Returns the SDL gamepad for the index into the controller map. - */ -struct SDL_Gamepad* PADGetSDLGamepadForIndex(u32 index); -/* Returns the first native button which is currently pressed */ -s32 PADGetNativeButtonPressed(u32 port); -/* Returns the first native axis which is currently pulled halfway or more */ -PADSignedNativeAxis PADGetNativeAxisPulled(u32 port); -void PADRestoreDefaultMapping(u32 port); -void PADBlockInput(bool block); - -/** - * Set the default controller mapping used. - * - * Must be called before PADInit. - */ - -typedef enum { - PAD_TYPE_UNKNOWN = 0, - PAD_TYPE_STANDARD, - PAD_TYPE_XBOX360, - PAD_TYPE_XBOXONE, - PAD_TYPE_PS3, - PAD_TYPE_PS4, - PAD_TYPE_PS5, - PAD_TYPE_SWITCH_PROCON, - PAD_TYPE_JOYCON_LEFT, - PAD_TYPE_JOYCON_RIGHT, - PAD_TYPE_JOYCON_PAIR, - PAD_TYPE_GAMECUBE, - PAD_TYPE_NSO_GAMECUBE, -} PADControllerType; - -void PADSetDefaultMapping(const PADDefaultMapping* mapping, PADControllerType type); - -BOOL PADSetColor(u32 port, u8 red, u8 green, u8 blue); -BOOL PADGetColor(u32 port, u8* red, u8* green, u8* blue); - -typedef enum { - PAD_SENSOR_INVALID = -1, - PAD_SENSOR_UNKNOWN, - PAD_SENSOR_ACCEL, - PAD_SENSOR_GYRO, - PAD_SENSOR_ACCEL_LEFT, - PAD_SENSOR_GYRO_LEFT, - PAD_SENSOR_ACCEL_RIGHT, - PAD_SENSOR_GYRO_RIGHT, -} PADSensorType; -BOOL PADSetSensorEnabled(u32 port, PADSensorType sensor, BOOL enabled); - -BOOL PADHasSensor(u32 port, PADSensorType sensor); - -BOOL PADGetSensorData(u32 port, PADSensorType sensor, f32* data, int nValues); - -BOOL PADSetRumbleIntensity(u32 port, u16 low, u16 high); -BOOL PADGetRumbleIntensity(u32 port, u16* low, u16* high); -BOOL PADSupportsRumbleIntensity(u32 port); - -typedef enum PADBatteryState { - PAD_BATTERYSTATE_ERROR = -1, - PAD_BATTERYSTATE_UNKNOWN, - PAD_BATTERYSTATE_ON_BATTERY, - PAD_BATTERYSTATE_NO_BATTERY, - PAD_BATTERYSTATE_CHARGING, - PAD_BATTERYSTATE_CHARGED, -} PADBatteryState; - -PADBatteryState PADGetBatteryState(u32 port, f32* perc); - -PADControllerType PADGetControllerType(u32 port); -PADControllerType PADGetControllerTypeForIndex(u32 index); - -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/perf.h b/aurora-main/include/dolphin/perf.h deleted file mode 100644 index 71471a5..0000000 --- a/aurora-main/include/dolphin/perf.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef _DOLPHIN_PERF_H_ -#define _DOLPHIN_PERF_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef u8 PERFId; - -typedef enum { - PERF_CPU_EVENT, - PERF_CPU_GP_EVENT, - PERF_GP_EVENT, -} PerfType; - -typedef struct PerfSample { - /* 0x00 */ u8 id; - /* 0x04 */ u32 cpuTimeStampStart; - /* 0x08 */ u32 cpuTimeStampEnd; - /* 0x0C */ u32 gpTimeStampStart; - /* 0x10 */ u32 gpTimeStampEnd; - /* 0x14 */ int interrupted; - /* 0x18 */ u32 origcpuStart; - /* 0x1C */ u32 origgpStart; - /* 0x20 */ u32 cacheMisses[4]; - /* 0x30 */ u32 instructions[4]; - /* 0x40 */ u32 cpReq[2]; - /* 0x48 */ u32 tcReq[2]; - /* 0x50 */ u32 cpuRdReq[2]; - /* 0x58 */ u32 cpuWrReq[2]; - /* 0x60 */ u32 dspReq[2]; - /* 0x68 */ u32 ioReq[2]; - /* 0x70 */ u32 viReq[2]; - /* 0x78 */ u32 peReq[2]; - /* 0x80 */ u32 rfReq[2]; - /* 0x88 */ u32 fiReq[2]; - /* 0x90 */ u32 xfWaitIn[2]; - /* 0x98 */ u32 xfWaitOut[2]; - /* 0xA0 */ u32 rasBusy[2]; - /* 0xA8 */ u32 rasClocks[2]; -} PerfSample; - -typedef struct { - PerfSample* samples; - s32 lastSample; - u32 end; - u32 cachemisscycles; -} Frame; - -typedef struct { - char* name; - PerfType type; - s32 currSample; - GXColor color; -} PerfEvent; - -typedef void* (*PERFAllocator)(u32 size); -typedef void (*PERFDeallocator)(void* block); -typedef void (*PERFDrawCallback)(void); - -extern void (*GameDrawInit)(); - -u32 PERFInit(u32 numSamples, u32 numFramesHistory, u32 numTypes, PERFAllocator allocator, PERFDeallocator deallocator, PERFDrawCallback initDraw); -void PERFEventStart(PERFId id); -void PERFEventEnd(PERFId id); -void PERFSetEvent(PERFId id, char* name, PerfType type); -void PERFStartFrame(void); -void PERFEndFrame(void); -void PERFStartAutoSampling(f32 msInterval); -void PERFStopAutoSampling(void); - -void PERFPreDraw(void); -void PERFDumpScreen(void); -void PERFPostDraw(void); -void PERFSetDrawBWBarKey(BOOL tf); -void PERFSetDrawBWBar(BOOL tf); -void PERFSetDrawCPUBar(BOOL tf); -void PERFSetDrawXFBars(BOOL tf); -void PERFSetDrawRASBar(BOOL tf); -void PERFToggleDrawBWBarKey(void); -void PERFToggleDrawBWBar(void); -void PERFToggleDrawCPUBar(void); -void PERFToggleDrawXFBars(void); -void PERFToggleDrawRASBar(void); -void PERFShutDown(void); -void PERFSetDrawFrames(u32 frames); - -extern Frame* PERFFrames; -extern u32 PERFCurrFrame; -extern PerfEvent* PERFEvents; -extern u32 PERFNumEvents; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/ppc_math.h b/aurora-main/include/dolphin/ppc_math.h deleted file mode 100644 index c8f4cb5..0000000 --- a/aurora-main/include/dolphin/ppc_math.h +++ /dev/null @@ -1,136 +0,0 @@ -#ifndef DOLPHIN_PPC_MATH_H -#define DOLPHIN_PPC_MATH_H - -#include -#include - -// frsqrte matching courtesy of Geotale, with reference to https://achurch.org/cpu-tests/ppc750cl.s - -struct BaseAndDec32 { - uint32_t base; - int32_t dec; -}; - -struct BaseAndDec64 { - uint64_t base; - int64_t dec; -}; - -union c32 { - uint32_t u; - float f; -}; - -union c64 { - uint64_t u; - double f; -}; - -#define EXPONENT_SHIFT_F64 ((uint64_t)52) -#define MANTISSA_MASK_F64 ((uint64_t)0x000fffffffffffffULL) -#define EXPONENT_MASK_F64 ((uint64_t)0x7ff0000000000000ULL) -#define SIGN_MASK_F64 ((uint64_t)0x8000000000000000ULL) - -static const struct BaseAndDec64 RSQRTE_TABLE[32] = { - {0x69fa000000000ULL, -0x15a0000000LL}, - {0x5f2e000000000ULL, -0x13cc000000LL}, - {0x554a000000000ULL, -0x1234000000LL}, - {0x4c30000000000ULL, -0x10d4000000LL}, - {0x43c8000000000ULL, -0x0f9c000000LL}, - {0x3bfc000000000ULL, -0x0e88000000LL}, - {0x34b8000000000ULL, -0x0d94000000LL}, - {0x2df0000000000ULL, -0x0cb8000000LL}, - {0x2794000000000ULL, -0x0bf0000000LL}, - {0x219c000000000ULL, -0x0b40000000LL}, - {0x1bfc000000000ULL, -0x0aa0000000LL}, - {0x16ae000000000ULL, -0x0a0c000000LL}, - {0x11a8000000000ULL, -0x0984000000LL}, - {0x0ce6000000000ULL, -0x090c000000LL}, - {0x0862000000000ULL, -0x0898000000LL}, - {0x0416000000000ULL, -0x082c000000LL}, - {0xffe8000000000ULL, -0x1e90000000LL}, - {0xf0a4000000000ULL, -0x1c00000000LL}, - {0xe2a8000000000ULL, -0x19c0000000LL}, - {0xd5c8000000000ULL, -0x17c8000000LL}, - {0xc9e4000000000ULL, -0x1610000000LL}, - {0xbedc000000000ULL, -0x1490000000LL}, - {0xb498000000000ULL, -0x1330000000LL}, - {0xab00000000000ULL, -0x11f8000000LL}, - {0xa204000000000ULL, -0x10e8000000LL}, - {0x9994000000000ULL, -0x0fe8000000LL}, - {0x91a0000000000ULL, -0x0f08000000LL}, - {0x8a1c000000000ULL, -0x0e38000000LL}, - {0x8304000000000ULL, -0x0d78000000LL}, - {0x7c48000000000ULL, -0x0cc8000000LL}, - {0x75e4000000000ULL, -0x0c28000000LL}, - {0x6fd0000000000ULL, -0x0b98000000LL}, -}; - -#ifdef _MSC_VER -#include -static inline uint32_t ppc_clz64(uint64_t x) { - unsigned long idx; - _BitScanReverse64(&idx, x); - return 63u - (uint32_t)idx; -} -#else -static inline uint32_t ppc_clz64(uint64_t x) { - return (uint32_t)__builtin_clzll(x); -} -#endif - -static inline double frsqrte(double val) { - union c64 bits; - uint64_t mantissa; - int64_t exponent; - int sign; - uint32_t key; - uint64_t new_exp; - const struct BaseAndDec64 *entry; - union c64 result; - - bits.f = val; - mantissa = bits.u & MANTISSA_MASK_F64; - exponent = (int64_t)(bits.u & EXPONENT_MASK_F64); - sign = (bits.u & SIGN_MASK_F64) != 0; - - if (mantissa == 0 && exponent == 0) { - return copysign(INFINITY, bits.f); - } - - if ((uint64_t)exponent == EXPONENT_MASK_F64) { - if (mantissa == 0) { - return sign ? NAN : 0.0; - } - return val; - } - - if (sign) { - return NAN; - } - - if (exponent == 0) { - uint32_t shift = ppc_clz64(mantissa) - (uint32_t)(63 - EXPONENT_SHIFT_F64); - mantissa <<= shift; - mantissa &= MANTISSA_MASK_F64; - exponent -= (int64_t)(shift - 1) << EXPONENT_SHIFT_F64; - } - - key = (uint32_t)(((uint64_t)exponent | mantissa) >> 37); - new_exp = (((0xbfcULL << EXPONENT_SHIFT_F64) - (uint64_t)exponent) >> 1) & EXPONENT_MASK_F64; - - entry = &RSQRTE_TABLE[0x1fu & (key >> 11)]; - result.u = new_exp | (uint64_t)(entry->base + entry->dec * (int64_t)(key & 0x7ffu)); - return result.f; -} - -// One Newton-Raphson step -static inline float ppc_rsqrte(float x) { - double rsqrt_d = frsqrte((double)x); - float nwork0 = (float)(rsqrt_d * rsqrt_d); - float nwork1 = (float)(rsqrt_d * 0.5); - nwork0 = fmaf(-nwork0, x, 3.0f); - return nwork0 * nwork1; -} - -#endif // DOLPHIN_PPC_MATH_H diff --git a/aurora-main/include/dolphin/si.h b/aurora-main/include/dolphin/si.h deleted file mode 100644 index 02eb65a..0000000 --- a/aurora-main/include/dolphin/si.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef DOLPHIN_SI_H -#define DOLPHIN_SI_H - -#include - -#define SI_CHAN0 0 -#define SI_CHAN1 1 -#define SI_CHAN2 2 -#define SI_CHAN3 3 -#define SI_MAX_CHAN 4 - -#define SI_CHAN0_BIT 0x80000000 -#define SI_CHAN1_BIT 0x40000000 -#define SI_CHAN2_BIT 0x20000000 -#define SI_CHAN3_BIT 0x10000000 -#define SI_CHAN_BIT(chn) (SI_CHAN0_BIT >> (chn)) - -#define SI_ERROR_UNDER_RUN 0x0001 -#define SI_ERROR_OVER_RUN 0x0002 -#define SI_ERROR_COLLISION 0x0004 -#define SI_ERROR_NO_RESPONSE 0x0008 -#define SI_ERROR_WRST 0x0010 -#define SI_ERROR_RDST 0x0020 -#define SI_ERROR_UNKNOWN 0x0040 -#define SI_ERROR_BUSY 0x0080 - -#define SI_TYPE_MASK 0x18000000u -#define SI_TYPE_N64 0x00000000u -#define SI_TYPE_DOLPHIN 0x08000000u -#define SI_TYPE_GC SI_TYPE_DOLPHIN - -// GameCube specific -#define SI_GC_WIRELESS 0x80000000u -#define SI_GC_NOMOTOR 0x20000000u // no rumble motor -#define SI_GC_STANDARD 0x01000000u // dolphin standard controller - -// WaveBird specific -#define SI_WIRELESS_RECEIVED 0x40000000u // 0: no wireless unit -#define SI_WIRELESS_IR 0x04000000u // 0: IR 1: RF -#define SI_WIRELESS_STATE 0x02000000u // 0: variable 1: fixed -#define SI_WIRELESS_ORIGIN 0x00200000u // 0: invalid 1: valid -#define SI_WIRELESS_FIX_ID 0x00100000u // 0: not fixed 1: fixed -#define SI_WIRELESS_TYPE 0x000f0000u -#define SI_WIRELESS_LITE_MASK 0x000c0000u // 0: normal 1: lite controller -#define SI_WIRELESS_LITE 0x00040000u // 0: normal 1: lite controller -#define SI_WIRELESS_CONT_MASK 0x00080000u // 0: non-controller 1: non-controller -#define SI_WIRELESS_CONT 0x00000000u -#define SI_WIRELESS_ID 0x00c0ff00u -#define SI_WIRELESS_TYPE_ID (SI_WIRELESS_TYPE | SI_WIRELESS_ID) - -#define SI_N64_CONTROLLER (SI_TYPE_N64 | 0x05000000) -#define SI_N64_MIC (SI_TYPE_N64 | 0x00010000) -#define SI_N64_KEYBOARD (SI_TYPE_N64 | 0x00020000) -#define SI_N64_MOUSE (SI_TYPE_N64 | 0x02000000) -#define SI_GBA (SI_TYPE_N64 | 0x00040000) -#define SI_GC_CONTROLLER (SI_TYPE_GC | SI_GC_STANDARD) -#define SI_GC_RECEIVER (SI_TYPE_GC | SI_GC_WIRELESS) -#define SI_GC_WAVEBIRD (SI_TYPE_GC | SI_GC_WIRELESS | SI_GC_STANDARD | SI_WIRELESS_STATE | SI_WIRELESS_FIX_ID) -#define SI_GC_KEYBOARD (SI_TYPE_GC | 0x00200000) -#define SI_GC_STEERING (SI_TYPE_GC | 0x00000000) - -#ifdef __cplusplus -extern "C" { -#endif - -u32 SIProbe(s32 chan); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/dolphin/thp.h b/aurora-main/include/dolphin/thp.h deleted file mode 100644 index 455afe6..0000000 --- a/aurora-main/include/dolphin/thp.h +++ /dev/null @@ -1,154 +0,0 @@ -#ifndef _DOLPHIN_THP_H_ -#define _DOLPHIN_THP_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef u8 THPSample; -typedef s16 THPCoeff; -typedef f32 THPQuantTab[64]; - -typedef struct _THPHuffmanTab { - u8 quick[32]; - u8 increment[32]; - u8* Vij; - s32 maxCode[18]; - s32 valPtr[18]; - u8 Vij1; - u8 pad[11]; -} THPHuffmanTab; - -typedef struct _THPComponent { - u8 quantizationTableSelector; - u8 DCTableSelector; - u8 ACTableSelector; - THPCoeff predDC; -} THPComponent; - -typedef struct _THPFileInfo { - THPQuantTab quantTabs[3]; - THPHuffmanTab huffmanTabs[4]; - THPComponent components[3]; - u16 xPixelSize; - u16 yPixelSize; - u16 MCUsPerRow; - u16 decompressedY; - u8* c; - u32 currByte; - u32 cnt; - u8 validHuffmanTabs; - u8 RST; - u16 nMCU; - u16 currMCU; - u8* dLC[3]; -} THPFileInfo; - -typedef struct THPAudioRecordHeader { - u32 offsetNextChannel; - u32 sampleSize; - s16 lCoef[8][2]; - s16 rCoef[8][2]; - s16 lYn1; - s16 lYn2; - s16 rYn1; - s16 rYn2; -} THPAudioRecordHeader; - -typedef struct THPAudioDecodeInfo { - u8* encodeData; - u32 offsetNibbles; - u8 predictor; - u8 scale; - s16 yn1; - s16 yn2; -} THPAudioDecodeInfo; - -typedef struct THPTextureSet { - u8* ytexture; - u8* utexture; - u8* vtexture; - s32 frameNumber; -} THPTextureSet; - -typedef struct THPAudioBuffer { - s16* buffer; - s16* curPtr; - u32 validSample; -} THPAudioBuffer; - -typedef struct THPVideoInfo { - u32 xSize; - u32 ySize; - u32 videoType; -} THPVideoInfo; - -typedef struct THPAudioInfo { - u32 sndChannels; - u32 sndFrequency; - u32 sndNumSamples; - u32 sndNumTracks; -} THPAudioInfo; - -typedef struct THPFrameCompInfo { - u32 numComponents; - u8 frameComp[16]; -} THPFrameCompInfo; - -typedef struct THPHeader { - /* 0x00 */ char magic[4]; - /* 0x04 */ u32 version; - /* 0x08 */ u32 bufsize; - /* 0x0C */ u32 audioMaxSamples; - /* 0x10 */ f32 frameRate; - /* 0x14 */ u32 numFrames; - /* 0x18 */ u32 firstFrameSize; - /* 0x1C */ u32 movieDataSize; - /* 0x20 */ u32 compInfoDataOffsets; - /* 0x24 */ u32 offsetDataOffsets; - /* 0x28 */ u32 movieDataOffsets; - /* 0x2C */ u32 finalFrameDataOffsets; -} THPHeader; - -#define THP_AUDIO_BUFFER_COUNT 3 -#define THP_READ_BUFFER_COUNT 10 -#define THP_TEXTURE_SET_COUNT 3 - -static u32 THPAudioDecode(s16* audioBuffer, u8* audioFrame, s32 flag); -static s32 __THPAudioGetNewSample(THPAudioDecodeInfo* info); -static void __THPAudioInitialize(THPAudioDecodeInfo* info, u8* ptr); - -s32 __THPAudioGetNewSample(THPAudioDecodeInfo*); -void __THPAudioInitialize(THPAudioDecodeInfo*, u8*); - -static void __THPSetupBuffers(void); -static u8 __THPReadFrameHeader(void); -static u8 __THPReadScaneHeader(void); -static u8 __THPReadQuantizationTable(void); -static u8 __THPReadHuffmanTableSpecification(void); -static void __THPHuffGenerateSizeTable(void); -static void __THPHuffGenerateCodeTable(void); -static void __THPHuffGenerateDecoderTables(u8 tabIndex); -static void __THPRestartDefinition(void); -static void __THPPrepBitStream(void); -static void __THPDecompressYUV(void* tileY, void* tileU, void* tileV); -static void __THPGQRRestore(void); -static void __THPDecompressiMCURow512x448(void); -static void __THPDecompressiMCURow640x480(void); -static void __THPDecompressiMCURowNxN(void); -static void __THPInverseDCTNoYPos(THPCoeff* in, u32 xPos); -static void __THPHuffDecodeDCTCompY(THPFileInfo* info, THPCoeff* block); -static void __THPHuffDecodeDCTCompU(THPFileInfo* info, THPCoeff* block); -static void __THPHuffDecodeDCTCompV(THPFileInfo* info, THPCoeff* block); - -static void __THPInverseDCTY8(THPCoeff* in, u32 xPos); -static void __THPGQRSetup(); -static s32 __THPHuffDecodeTab(THPFileInfo* info, THPHuffmanTab* h); - -#ifdef __cplusplus -} -#endif - -#endif // _DOLPHIN_THP_H_ diff --git a/aurora-main/include/dolphin/types.h b/aurora-main/include/dolphin/types.h deleted file mode 100644 index 48c51bf..0000000 --- a/aurora-main/include/dolphin/types.h +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef DOLPHIN_TYPES_H -#define DOLPHIN_TYPES_H - -#if _WIN64 || __LP64__ -#define BIT_64 1 -#else -#define BIT_64 0 -#endif - -#ifdef TARGET_PC -#include -typedef int8_t s8; -typedef int16_t s16; -typedef int32_t s32; -typedef int64_t s64; -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; -#else -typedef signed char s8; -typedef signed short int s16; -typedef signed long s32; -typedef signed long long int s64; -typedef unsigned char u8; -typedef unsigned short int u16; -typedef unsigned long u32; -typedef unsigned long long int u64; -#endif - -typedef volatile u8 vu8; -typedef volatile u16 vu16; -typedef volatile u32 vu32; -typedef volatile u64 vu64; - -typedef volatile s8 vs8; -typedef volatile s16 vs16; -typedef volatile s32 vs32; -typedef volatile s64 vs64; - -typedef float f32; -typedef double f64; - -typedef volatile f32 vf32; -typedef volatile f64 vf64; - -typedef char *Ptr; - -#if defined(TARGET_PC) -#include -typedef int BOOL; -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef TRUE -#define TRUE 1 -#endif -#endif - -#ifdef TARGET_PC -#include -#else -#ifndef NULL -#define NULL 0 -#endif -#endif -#ifndef __cplusplus -#ifndef nullptr -#define nullptr NULL -#endif -#endif - -#if defined(__MWERKS__) -#define AT_ADDRESS(addr) : (addr) -#define ATTRIBUTE_ALIGN(num) __attribute__((aligned(num))) -#elif defined(__GNUC__) -#define AT_ADDRESS(addr) -#define ATTRIBUTE_ALIGN(num) __attribute__((aligned(num))) -#elif defined(_MSC_VER) -#define AT_ADDRESS(addr) -#define ATTRIBUTE_ALIGN(num) -#else -#error unknown compiler -#endif - -#ifndef DECL_WEAK -#if defined(__MWERKS__) -#define DECL_WEAK __declspec(weak) -#elif defined(__GNUC__) -#define DECL_WEAK __attribute__((weak)) -#elif defined(_MSC_VER) -#define DECL_WEAK -#else -#error unknown compiler -#endif -#endif - -#if TARGET_PC && __cplusplus -#define NORETURN [[noreturn]] -#else -#define NORETURN -#endif - -#ifdef __MWERKS__ -#define __REGISTER register -#else -#define __REGISTER -#endif - -#endif diff --git a/aurora-main/include/dolphin/vi.h b/aurora-main/include/dolphin/vi.h deleted file mode 100644 index 377d952..0000000 --- a/aurora-main/include/dolphin/vi.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef DOLPHIN_VI_H -#define DOLPHIN_VI_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*VIRetraceCallback)(u32 retraceCount); - -void VIInit(void); -void VIConfigure(const GXRenderModeObj *rm); -void VIConfigurePan(u16 xOrg, u16 yOrg, u16 width, u16 height); -void VIFlush(void); - -void VIWaitForRetrace(void); - -u32 VIGetTvFormat(void); -u32 VIGetRetraceCount(void); -u32 VIGetNextField(void); -u32 VIGetDTVStatus(void); - -void* VIGetCurrentFrameBuffer(void); -void* VIGetNextFrameBuffer(void); -void VISetNextFrameBuffer(void *fb); -void VISetBlack(BOOL black); - -typedef void (*VIRetraceCallback)(u32 retraceCount); - -VIRetraceCallback VISetPreRetraceCallback(VIRetraceCallback cb); -VIRetraceCallback VISetPostRetraceCallback(VIRetraceCallback cb); - -#ifdef TARGET_PC -void VISetWindowTitle(const char* title); -void VISetWindowFullscreen(bool fullscreen); -bool VIGetWindowFullscreen(); -void VISetWindowSize(uint32_t width, uint32_t height); -void VISetWindowPosition(uint32_t x, uint32_t y); -void VICenterWindow(); - -/** - * Sets the internal framebuffer resolution to a specific scale factor of the configured EFB size. - * A value of 0.0f means "Auto", which will use the underlying swapchain size (usually the window size). - */ -void VISetFrameBufferScale(float scale); - -/** - * \brief Lock the GX framebuffer to a specific aspect ratio, without changing the native framebuffer. - * - * @param width Width part of the aspect ratio fraction. - * @param height Height part of the aspect ratio fraction. - */ -void VILockAspectRatio(int width, int height); - -/** - * \brief Undoes a previous call to VILockAspectRatio. - */ -void VIUnlockAspectRatio(); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/aurora-main/include/magic_enum.hpp b/aurora-main/include/magic_enum.hpp deleted file mode 100644 index 18c2804..0000000 --- a/aurora-main/include/magic_enum.hpp +++ /dev/null @@ -1,1135 +0,0 @@ -// __ __ _ ______ _____ -// | \/ | (_) | ____| / ____|_ _ -// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ -// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| -// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| -// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| -// __/ | https://github.com/Neargye/magic_enum -// |___/ version 0.7.2 -// -// Licensed under the MIT License . -// SPDX-License-Identifier: MIT -// Copyright (c) 2019 - 2021 Daniil Goncharov . -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#ifndef NEARGYE_MAGIC_ENUM_HPP -#define NEARGYE_MAGIC_ENUM_HPP - -#define MAGIC_ENUM_VERSION_MAJOR 0 -#define MAGIC_ENUM_VERSION_MINOR 7 -#define MAGIC_ENUM_VERSION_PATCH 2 - -#include -#include -#include -#include -#include -#include -#include -#include - -#if !defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL) -#include -#endif -#if !defined(MAGIC_ENUM_USING_ALIAS_STRING) -#include -#endif -#if !defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW) -#include -#endif - -#if defined(__clang__) -# pragma clang diagnostic push -#elif defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'. -#elif defined(_MSC_VER) -# pragma warning(push) -# pragma warning(disable : 26495) // Variable 'static_string::chars_' is uninitialized. -# pragma warning(disable : 28020) // Arithmetic overflow: Using operator '-' on a 4 byte value and then casting the result to a 8 byte value. -# pragma warning(disable : 26451) // The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call. -#endif - -// Checks magic_enum compiler compatibility. -#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1910 -# undef MAGIC_ENUM_SUPPORTED -# define MAGIC_ENUM_SUPPORTED 1 -#endif - -// Checks magic_enum compiler aliases compatibility. -#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1920 -# undef MAGIC_ENUM_SUPPORTED_ALIASES -# define MAGIC_ENUM_SUPPORTED_ALIASES 1 -#endif - -// Enum value must be greater or equals than MAGIC_ENUM_RANGE_MIN. By default MAGIC_ENUM_RANGE_MIN = -128. -// If need another min range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN. -#if !defined(MAGIC_ENUM_RANGE_MIN) -# define MAGIC_ENUM_RANGE_MIN -128 -#endif - -// Enum value must be less or equals than MAGIC_ENUM_RANGE_MAX. By default MAGIC_ENUM_RANGE_MAX = 128. -// If need another max range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MAX. -#if !defined(MAGIC_ENUM_RANGE_MAX) -# define MAGIC_ENUM_RANGE_MAX 128 -#endif - -namespace magic_enum { - -// If need another optional type, define the macro MAGIC_ENUM_USING_ALIAS_OPTIONAL. -#if defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL) -MAGIC_ENUM_USING_ALIAS_OPTIONAL -#else -using std::optional; -#endif - -// If need another string_view type, define the macro MAGIC_ENUM_USING_ALIAS_STRING_VIEW. -#if defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW) -MAGIC_ENUM_USING_ALIAS_STRING_VIEW -#else -using std::string_view; -#endif - -// If need another string type, define the macro MAGIC_ENUM_USING_ALIAS_STRING. -#if defined(MAGIC_ENUM_USING_ALIAS_STRING) -MAGIC_ENUM_USING_ALIAS_STRING -#else -using std::string; -#endif - -namespace customize { - -// Enum value must be in range [MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]. By default MAGIC_ENUM_RANGE_MIN = -128, MAGIC_ENUM_RANGE_MAX = 128. -// If need another range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN and MAGIC_ENUM_RANGE_MAX. -// If need another range for specific enum type, add specialization enum_range for necessary enum type. -template -struct enum_range { - static_assert(std::is_enum_v, "magic_enum::customize::enum_range requires enum type."); - inline static constexpr int min = MAGIC_ENUM_RANGE_MIN; - inline static constexpr int max = MAGIC_ENUM_RANGE_MAX; - static_assert(max > min, "magic_enum::customize::enum_range requires max > min."); -}; - -static_assert(MAGIC_ENUM_RANGE_MIN <= 0, "MAGIC_ENUM_RANGE_MIN must be less or equals than 0."); -static_assert(MAGIC_ENUM_RANGE_MIN > (std::numeric_limits::min)(), "MAGIC_ENUM_RANGE_MIN must be greater than INT16_MIN."); - -static_assert(MAGIC_ENUM_RANGE_MAX > 0, "MAGIC_ENUM_RANGE_MAX must be greater than 0."); -static_assert(MAGIC_ENUM_RANGE_MAX < (std::numeric_limits::max)(), "MAGIC_ENUM_RANGE_MAX must be less than INT16_MAX."); - -static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN."); - -// If need custom names for enum, add specialization enum_name for necessary enum type. -template -constexpr string_view enum_name(E) noexcept { - static_assert(std::is_enum_v, "magic_enum::customize::enum_name requires enum type."); - - return {}; -} - -} // namespace magic_enum::customize - -namespace detail { - -template -struct supported -#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT) - : std::true_type {}; -#else - : std::false_type {}; -#endif - -struct char_equal_to { - constexpr bool operator()(char lhs, char rhs) const noexcept { - return lhs == rhs; - } -}; - -template -class static_string { - public: - constexpr explicit static_string(string_view str) noexcept : static_string{str, std::make_index_sequence{}} { - assert(str.size() == N); - } - - constexpr const char* data() const noexcept { return chars_; } - - constexpr std::size_t size() const noexcept { return N; } - - constexpr operator string_view() const noexcept { return {data(), size()}; } - - private: - template - constexpr static_string(string_view str, std::index_sequence) noexcept : chars_{str[I]..., '\0'} {} - - char chars_[N + 1]; -}; - -template <> -class static_string<0> { - public: - constexpr explicit static_string(string_view) noexcept {} - - constexpr const char* data() const noexcept { return nullptr; } - - constexpr std::size_t size() const noexcept { return 0; } - - constexpr operator string_view() const noexcept { return {}; } -}; - -constexpr string_view pretty_name(string_view name) noexcept { - for (std::size_t i = name.size(); i > 0; --i) { - if (!((name[i - 1] >= '0' && name[i - 1] <= '9') || - (name[i - 1] >= 'a' && name[i - 1] <= 'z') || - (name[i - 1] >= 'A' && name[i - 1] <= 'Z') || - (name[i - 1] == '_'))) { - name.remove_prefix(i); - break; - } - } - - if (name.size() > 0 && ((name.front() >= 'a' && name.front() <= 'z') || - (name.front() >= 'A' && name.front() <= 'Z') || - (name.front() == '_'))) { - return name; - } - - return {}; // Invalid name. -} - -constexpr std::size_t find(string_view str, char c) noexcept { -#if defined(__clang__) && __clang_major__ < 9 && defined(__GLIBCXX__) || defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) -// https://stackoverflow.com/questions/56484834/constexpr-stdstring-viewfind-last-of-doesnt-work-on-clang-8-with-libstdc -// https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html - constexpr bool workaround = true; -#else - constexpr bool workaround = false; -#endif - if constexpr (workaround) { - for (std::size_t i = 0; i < str.size(); ++i) { - if (str[i] == c) { - return i; - } - } - - return string_view::npos; - } else { - return str.find_first_of(c); - } -} - -template -constexpr std::array, N> to_array(T (&a)[N], std::index_sequence) { - return {{a[I]...}}; -} - -template -constexpr bool cmp_equal(string_view lhs, string_view rhs, BinaryPredicate&& p) noexcept(std::is_nothrow_invocable_r_v) { -#if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) - // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html - // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html - constexpr bool workaround = true; -#else - constexpr bool workaround = false; -#endif - constexpr bool default_predicate = std::is_same_v, char_equal_to>; - - if constexpr (default_predicate && !workaround) { - static_cast(p); - return lhs == rhs; - } else { - if (lhs.size() != rhs.size()) { - return false; - } - - const auto size = lhs.size(); - for (std::size_t i = 0; i < size; ++i) { - if (!p(lhs[i], rhs[i])) { - return false; - } - } - - return true; - } -} - -template -constexpr bool cmp_less(L lhs, R rhs) noexcept { - static_assert(std::is_integral_v && std::is_integral_v, "magic_enum::detail::cmp_less requires integral type."); - - if constexpr (std::is_signed_v == std::is_signed_v) { - // If same signedness (both signed or both unsigned). - return lhs < rhs; - } else if constexpr (std::is_signed_v) { - // If 'right' is negative, then result is 'false', otherwise cast & compare. - return rhs > 0 && lhs < static_cast>(rhs); - } else { - // If 'left' is negative, then result is 'true', otherwise cast & compare. - return lhs < 0 || static_cast>(lhs) < rhs; - } -} - -template -constexpr I log2(I value) noexcept { - static_assert(std::is_integral_v, "magic_enum::detail::log2 requires integral type."); - - auto ret = I{0}; - for (; value > I{1}; value >>= I{1}, ++ret) {} - - return ret; -} - -template -constexpr bool is_pow2(I x) noexcept { - static_assert(std::is_integral_v, "magic_enum::detail::is_pow2 requires integral type."); - - return x != 0 && (x & (x - 1)) == 0; -} - -template -inline constexpr bool is_enum_v = std::is_enum_v && std::is_same_v>; - -template -constexpr auto n() noexcept { - static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); -#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED -# if defined(__clang__) - constexpr string_view name{__PRETTY_FUNCTION__ + 34, sizeof(__PRETTY_FUNCTION__) - 36}; -# elif defined(__GNUC__) - constexpr string_view name{__PRETTY_FUNCTION__ + 49, sizeof(__PRETTY_FUNCTION__) - 51}; -# elif defined(_MSC_VER) - constexpr string_view name{__FUNCSIG__ + 40, sizeof(__FUNCSIG__) - 57}; -# endif - return static_string{name}; -#else - return string_view{}; // Unsupported compiler. -#endif -} - -template -inline constexpr auto type_name_v = n(); - -template -constexpr auto n() noexcept { - static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); - constexpr auto custom_name = customize::enum_name(V); - - if constexpr (custom_name.empty()) { - static_cast(custom_name); -#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED -# if defined(__clang__) || defined(__GNUC__) - constexpr auto name = pretty_name({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2}); -# elif defined(_MSC_VER) - constexpr auto name = pretty_name({__FUNCSIG__, sizeof(__FUNCSIG__) - 17}); -# endif - return static_string{name}; -#else - return string_view{}; // Unsupported compiler. -#endif - } else { - return static_string{custom_name}; - } -} - -template -inline constexpr auto enum_name_v = n(); - -template -constexpr bool is_valid() noexcept { - static_assert(is_enum_v, "magic_enum::detail::is_valid requires enum type."); - - return n(V)>().size() != 0; -} - -template > -constexpr E value(std::size_t i) noexcept { - static_assert(is_enum_v, "magic_enum::detail::value requires enum type."); - - if constexpr (IsFlags) { - return static_cast(U{1} << static_cast(static_cast(i) + O)); - } else { - return static_cast(static_cast(i) + O); - } -} - -template > -constexpr int reflected_min() noexcept { - static_assert(is_enum_v, "magic_enum::detail::reflected_min requires enum type."); - - if constexpr (IsFlags) { - return 0; - } else { - constexpr auto lhs = customize::enum_range::min; - static_assert(lhs > (std::numeric_limits::min)(), "magic_enum::enum_range requires min must be greater than INT16_MIN."); - constexpr auto rhs = (std::numeric_limits::min)(); - - if constexpr (cmp_less(lhs, rhs)) { - return rhs; - } else { - static_assert(!is_valid(0)>(), "magic_enum::enum_range detects enum value smaller than min range size."); - return lhs; - } - } -} - -template > -constexpr int reflected_max() noexcept { - static_assert(is_enum_v, "magic_enum::detail::reflected_max requires enum type."); - - if constexpr (IsFlags) { - return std::numeric_limits::digits - 1; - } else { - constexpr auto lhs = customize::enum_range::max; - static_assert(lhs < (std::numeric_limits::max)(), "magic_enum::enum_range requires max must be less than INT16_MAX."); - constexpr auto rhs = (std::numeric_limits::max)(); - - if constexpr (cmp_less(lhs, rhs)) { - static_assert(!is_valid(0)>(), "magic_enum::enum_range detects enum value larger than max range size."); - return lhs; - } else { - return rhs; - } - } -} - -template -inline constexpr auto reflected_min_v = reflected_min(); - -template -inline constexpr auto reflected_max_v = reflected_max(); - -template -constexpr std::size_t values_count(const bool (&valid)[N]) noexcept { - auto count = std::size_t{0}; - for (std::size_t i = 0; i < N; ++i) { - if (valid[i]) { - ++count; - } - } - - return count; -} - -template -constexpr auto values(std::index_sequence) noexcept { - static_assert(is_enum_v, "magic_enum::detail::values requires enum type."); - constexpr bool valid[sizeof...(I)] = {is_valid(I)>()...}; - constexpr std::size_t count = values_count(valid); - - if constexpr (count > 0) { - E values[count] = {}; - for (std::size_t i = 0, v = 0; v < count; ++i) { - if (valid[i]) { - values[v++] = value(i); - } - } - - return to_array(values, std::make_index_sequence{}); - } else { - return std::array{}; - } -} - -template > -constexpr auto values() noexcept { - static_assert(is_enum_v, "magic_enum::detail::values requires enum type."); - constexpr auto min = reflected_min_v; - constexpr auto max = reflected_max_v; - constexpr auto range_size = max - min + 1; - static_assert(range_size > 0, "magic_enum::enum_range requires valid size."); - static_assert(range_size < (std::numeric_limits::max)(), "magic_enum::enum_range requires valid size."); - - return values>(std::make_index_sequence{}); -} - -template -inline constexpr auto values_v = values(); - -template > -using values_t = decltype((values_v)); - -template -inline constexpr auto count_v = values_v.size(); - -template > -inline constexpr auto min_v = (count_v > 0) ? static_cast(values_v.front()) : U{0}; - -template > -inline constexpr auto max_v = (count_v > 0) ? static_cast(values_v.back()) : U{0}; - -template > -constexpr std::size_t range_size() noexcept { - static_assert(is_enum_v, "magic_enum::detail::range_size requires enum type."); - constexpr auto max = IsFlags ? log2(max_v) : max_v; - constexpr auto min = IsFlags ? log2(min_v) : min_v; - constexpr auto range_size = max - min + U{1}; - static_assert(range_size > 0, "magic_enum::enum_range requires valid size."); - static_assert(range_size < (std::numeric_limits::max)(), "magic_enum::enum_range requires valid size."); - - return static_cast(range_size); -} - -template -inline constexpr auto range_size_v = range_size(); - -template -using index_t = std::conditional_t < (std::numeric_limits::max)(), std::uint8_t, std::uint16_t>; - -template -inline constexpr auto invalid_index_v = (std::numeric_limits>::max)(); - -template -constexpr auto indexes(std::index_sequence) noexcept { - static_assert(is_enum_v, "magic_enum::detail::indexes requires enum type."); - constexpr auto min = IsFlags ? log2(min_v) : min_v; - [[maybe_unused]] auto i = index_t{0}; - - return std::array{{(is_valid(I)>() ? i++ : invalid_index_v)...}}; -} - -template -inline constexpr auto indexes_v = indexes(std::make_index_sequence>{}); - -template -constexpr auto names(std::index_sequence) noexcept { - static_assert(is_enum_v, "magic_enum::detail::names requires enum type."); - - return std::array{{enum_name_v[I]>...}}; -} - -template -inline constexpr auto names_v = names(std::make_index_sequence>{}); - -template > -using names_t = decltype((names_v)); - -template -constexpr auto entries(std::index_sequence) noexcept { - static_assert(is_enum_v, "magic_enum::detail::entries requires enum type."); - - return std::array, sizeof...(I)>{{{values_v[I], enum_name_v[I]>}...}}; -} - -template -inline constexpr auto entries_v = entries(std::make_index_sequence>{}); - -template > -using entries_t = decltype((entries_v)); - -template > -constexpr bool is_sparse() noexcept { - static_assert(is_enum_v, "magic_enum::detail::is_sparse requires enum type."); - - return range_size_v != count_v; -} - -template -inline constexpr bool is_sparse_v = is_sparse(); - -template > -constexpr std::size_t undex(U value) noexcept { - static_assert(is_enum_v, "magic_enum::detail::undex requires enum type."); - - if (const auto i = static_cast(value - min_v); value >= min_v && value <= max_v) { - if constexpr (is_sparse_v) { - if (const auto idx = indexes_v[i]; idx != invalid_index_v) { - return idx; - } - } else { - return i; - } - } - - return invalid_index_v; // Value out of range. -} - -template > -constexpr std::size_t endex(E value) noexcept { - static_assert(is_enum_v, "magic_enum::detail::endex requires enum type."); - - return undex(static_cast(value)); -} - -template > -constexpr U value_ors() noexcept { - static_assert(is_enum_v, "magic_enum::detail::endex requires enum type."); - - auto value = U{0}; - for (std::size_t i = 0; i < count_v; ++i) { - value |= static_cast(values_v[i]); - } - - return value; -} - -template -struct enable_if_enum {}; - -template -struct enable_if_enum { - using type = R; - using D = std::decay_t; - static_assert(supported::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility)."); -}; - -template -using enable_if_enum_t = std::enable_if_t>, R>; - -template >>> -using enum_concept = T; - -template > -struct is_scoped_enum : std::false_type {}; - -template -struct is_scoped_enum : std::bool_constant>> {}; - -template > -struct is_unscoped_enum : std::false_type {}; - -template -struct is_unscoped_enum : std::bool_constant>> {}; - -template >> -struct underlying_type {}; - -template -struct underlying_type : std::underlying_type> {}; - -} // namespace magic_enum::detail - -// Checks is magic_enum supported compiler. -inline constexpr bool is_magic_enum_supported = detail::supported::value; - -template -using Enum = detail::enum_concept; - -// Checks whether T is an Unscoped enumeration type. -// Provides the member constant value which is equal to true, if T is an [Unscoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Unscoped_enumeration) type. Otherwise, value is equal to false. -template -struct is_unscoped_enum : detail::is_unscoped_enum {}; - -template -inline constexpr bool is_unscoped_enum_v = is_unscoped_enum::value; - -// Checks whether T is an Scoped enumeration type. -// Provides the member constant value which is equal to true, if T is an [Scoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Scoped_enumerations) type. Otherwise, value is equal to false. -template -struct is_scoped_enum : detail::is_scoped_enum {}; - -template -inline constexpr bool is_scoped_enum_v = is_scoped_enum::value; - -// If T is a complete enumeration type, provides a member typedef type that names the underlying type of T. -// Otherwise, if T is not an enumeration type, there is no member type. Otherwise (T is an incomplete enumeration type), the program is ill-formed. -template -struct underlying_type : detail::underlying_type {}; - -template -using underlying_type_t = typename underlying_type::type; - -// Returns type name of enum. -template -[[nodiscard]] constexpr auto enum_type_name() noexcept -> detail::enable_if_enum_t { - using D = std::decay_t; - constexpr string_view name = detail::type_name_v; - static_assert(name.size() > 0, "Enum type does not have a name."); - - return name; -} - -// Returns number of enum values. -template -[[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_enum_t { - using D = std::decay_t; - - return detail::count_v; -} - -// Returns enum value at specified index. -// No bounds checking is performed: the behavior is undefined if index >= number of enum values. -template -[[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_enum_t> { - using D = std::decay_t; - static_assert(detail::count_v > 0, "magic_enum requires enum implementation and valid max and min."); - - if constexpr (detail::is_sparse_v) { - return assert((index < detail::count_v)), detail::values_v[index]; - } else { - return assert((index < detail::count_v)), detail::value>(index); - } -} - -// Returns std::array with enum values, sorted by enum value. -template -[[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_enum_t> { - using D = std::decay_t; - static_assert(detail::count_v > 0, "magic_enum requires enum implementation and valid max and min."); - - return detail::values_v; -} - -// Returns name from static storage enum variable. -// This version is much lighter on the compile times and is not restricted to the enum_range limitation. -template -[[nodiscard]] constexpr auto enum_name() noexcept -> detail::enable_if_enum_t { - using D = std::decay_t; - constexpr string_view name = detail::enum_name_v; - static_assert(name.size() > 0, "Enum value does not have a name."); - - return name; -} - -// Returns name from enum value. -// If enum value does not have name or value out of range, returns empty string. -template -[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_enum_t { - using D = std::decay_t; - - if (const auto i = detail::endex(value); i != detail::invalid_index_v) { - return detail::names_v[i]; - } - - return {}; // Invalid value or out of range. -} - -// Returns std::array with names, sorted by enum value. -template -[[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_enum_t> { - using D = std::decay_t; - static_assert(detail::count_v > 0, "magic_enum requires enum implementation and valid max and min."); - - return detail::names_v; -} - -// Returns std::array with pairs (value, name), sorted by enum value. -template -[[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_enum_t> { - using D = std::decay_t; - static_assert(detail::count_v > 0, "magic_enum requires enum implementation and valid max and min."); - - return detail::entries_v; -} - -// Obtains enum value from integer value. -// Returns optional with enum value. -template -[[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_enum_t>> { - using D = std::decay_t; - - if (detail::undex(value) != detail::invalid_index_v) { - return static_cast(value); - } - - return {}; // Invalid value or out of range. -} - -// Obtains enum value from name. -// Returns optional with enum value. -template -[[nodiscard]] constexpr auto enum_cast(string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v) -> detail::enable_if_enum_t>> { - static_assert(std::is_invocable_r_v, "magic_enum::enum_cast requires bool(char, char) invocable predicate."); - using D = std::decay_t; - - for (std::size_t i = 0; i < detail::count_v; ++i) { - if (detail::cmp_equal(value, detail::names_v[i], p)) { - return enum_value(i); - } - } - - return {}; // Invalid value or out of range. -} - -// Obtains enum value from name. -// Returns optional with enum value. -template -[[nodiscard]] constexpr auto enum_cast(string_view value) noexcept -> detail::enable_if_enum_t>> { - using D = std::decay_t; - - return enum_cast(value, detail::char_equal_to{}); -} - -// Returns integer value from enum value. -template -[[nodiscard]] constexpr auto enum_integer(E value) noexcept -> detail::enable_if_enum_t> { - return static_cast>(value); -} - -// Obtains index in enum values from enum value. -// Returns optional with index. -template -[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_enum_t> { - using D = std::decay_t; - - if (const auto i = detail::endex(value); i != detail::invalid_index_v) { - return i; - } - - return {}; // Invalid value or out of range. -} - -// Checks whether enum contains enumerator with such enum value. -template -[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_enum_t { - using D = std::decay_t; - - return detail::endex(value) != detail::invalid_index_v; -} - -// Checks whether enum contains enumerator with such integer value. -template -[[nodiscard]] constexpr auto enum_contains(underlying_type_t value) noexcept -> detail::enable_if_enum_t { - using D = std::decay_t; - - return detail::undex(value) != detail::invalid_index_v; -} - -// Checks whether enum contains enumerator with such name. -template -[[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v) -> detail::enable_if_enum_t { - static_assert(std::is_invocable_r_v, "magic_enum::enum_contains requires bool(char, char) invocable predicate."); - using D = std::decay_t; - - return enum_cast(value, std::move_if_noexcept(p)).has_value(); -} - -// Checks whether enum contains enumerator with such name. -template -[[nodiscard]] constexpr auto enum_contains(string_view value) noexcept -> detail::enable_if_enum_t { - using D = std::decay_t; - - return enum_cast(value).has_value(); -} - -namespace ostream_operators { - -template , int> = 0> -std::basic_ostream& operator<<(std::basic_ostream& os, E value) { - using D = std::decay_t; - using U = underlying_type_t; -#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED - if (const auto name = magic_enum::enum_name(value); !name.empty()) { - for (const auto c : name) { - os.put(c); - } - return os; - } -#endif - return (os << static_cast(value)); -} - -template , int> = 0> -std::basic_ostream& operator<<(std::basic_ostream& os, optional value) { - return value.has_value() ? (os << value.value()) : os; -} - -} // namespace magic_enum::ostream_operators - -namespace bitwise_operators { - -template , int> = 0> -constexpr E operator~(E rhs) noexcept { - return static_cast(~static_cast>(rhs)); -} - -template , int> = 0> -constexpr E operator|(E lhs, E rhs) noexcept { - return static_cast(static_cast>(lhs) | static_cast>(rhs)); -} - -template , int> = 0> -constexpr E operator&(E lhs, E rhs) noexcept { - return static_cast(static_cast>(lhs) & static_cast>(rhs)); -} - -template , int> = 0> -constexpr E operator^(E lhs, E rhs) noexcept { - return static_cast(static_cast>(lhs) ^ static_cast>(rhs)); -} - -template , int> = 0> -constexpr E& operator|=(E& lhs, E rhs) noexcept { - return lhs = (lhs | rhs); -} - -template , int> = 0> -constexpr E& operator&=(E& lhs, E rhs) noexcept { - return lhs = (lhs & rhs); -} - -template , int> = 0> -constexpr E& operator^=(E& lhs, E rhs) noexcept { - return lhs = (lhs ^ rhs); -} - -} // namespace magic_enum::bitwise_operators - -namespace flags { - -// Returns type name of enum. -using magic_enum::enum_type_name; - -// Returns number of enum-flags values. -template -[[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_enum_t { - using D = std::decay_t; - - return detail::count_v; -} - -// Returns enum-flags value at specified index. -// No bounds checking is performed: the behavior is undefined if index >= number of enum-flags values. -template -[[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_enum_t> { - using D = std::decay_t; - static_assert(detail::count_v > 0, "magic_enum::flags requires enum-flags implementation."); - - if constexpr (detail::is_sparse_v) { - return assert((index < detail::count_v)), detail::values_v[index]; - } else { - constexpr auto min = detail::log2(detail::min_v); - - return assert((index < detail::count_v)), detail::value(index); - } -} - -// Returns std::array with enum-flags values, sorted by enum-flags value. -template -[[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_enum_t> { - using D = std::decay_t; - static_assert(detail::count_v > 0, "magic_enum::flags requires enum-flags implementation."); - - return detail::values_v; -} - -// Returns name from enum-flags value. -// If enum-flags value does not have name or value out of range, returns empty string. -template -[[nodiscard]] auto enum_name(E value) -> detail::enable_if_enum_t { - using D = std::decay_t; - using U = underlying_type_t; - - string name; - auto check_value = U{0}; - for (std::size_t i = 0; i < detail::count_v; ++i) { - if (const auto v = static_cast(enum_value(i)); (static_cast(value) & v) != 0) { - check_value |= v; - const auto n = detail::names_v[i]; - if (!name.empty()) { - name.append(1, '|'); - } - name.append(n.data(), n.size()); - } - } - - if (check_value != 0 && check_value == static_cast(value)) { - return name; - } - - return {}; // Invalid value or out of range. -} - -// Returns std::array with string names, sorted by enum-flags value. -template -[[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_enum_t> { - using D = std::decay_t; - static_assert(detail::count_v > 0, "magic_enum::flags requires enum-flags implementation."); - - return detail::names_v; -} - -// Returns std::array with pairs (value, name), sorted by enum-flags value. -template -[[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_enum_t> { - using D = std::decay_t; - static_assert(detail::count_v > 0, "magic_enum::flags requires enum-flags implementation."); - - return detail::entries_v; -} - -// Obtains enum-flags value from integer value. -// Returns optional with enum-flags value. -template -[[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_enum_t>> { - using D = std::decay_t; - using U = underlying_type_t; - - if constexpr (detail::is_sparse_v) { - auto check_value = U{0}; - for (std::size_t i = 0; i < detail::count_v; ++i) { - if (const auto v = static_cast(enum_value(i)); (value & v) != 0) { - check_value |= v; - } - } - - if (check_value != 0 && check_value == value) { - return static_cast(value); - } - } else { - constexpr auto min = detail::min_v; - constexpr auto max = detail::value_ors(); - - if (value >= min && value <= max) { - return static_cast(value); - } - } - - return {}; // Invalid value or out of range. -} - -// Obtains enum-flags value from name. -// Returns optional with enum-flags value. -template -[[nodiscard]] constexpr auto enum_cast(string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v) -> detail::enable_if_enum_t>> { - static_assert(std::is_invocable_r_v, "magic_enum::flags::enum_cast requires bool(char, char) invocable predicate."); - using D = std::decay_t; - using U = underlying_type_t; - - auto result = U{0}; - while (!value.empty()) { - const auto d = detail::find(value, '|'); - const auto s = (d == string_view::npos) ? value : value.substr(0, d); - auto f = U{0}; - for (std::size_t i = 0; i < detail::count_v; ++i) { - if (detail::cmp_equal(s, detail::names_v[i], p)) { - f = static_cast(enum_value(i)); - result |= f; - break; - } - } - if (f == U{0}) { - return {}; // Invalid value or out of range. - } - value.remove_prefix((d == string_view::npos) ? value.size() : d + 1); - } - - if (result == U{0}) { - return {}; // Invalid value or out of range. - } else { - return static_cast(result); - } -} - -// Obtains enum-flags value from name. -// Returns optional with enum-flags value. -template -[[nodiscard]] constexpr auto enum_cast(string_view value) noexcept -> detail::enable_if_enum_t>> { - using D = std::decay_t; - - return enum_cast(value, detail::char_equal_to{}); -} - -// Returns integer value from enum value. -using magic_enum::enum_integer; - -// Obtains index in enum-flags values from enum-flags value. -// Returns optional with index. -template -[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_enum_t> { - using D = std::decay_t; - using U = underlying_type_t; - - if (detail::is_pow2(static_cast(value))) { - for (std::size_t i = 0; i < detail::count_v; ++i) { - if (enum_value(i) == value) { - return i; - } - } - } - - return {}; // Invalid value or out of range. -} - -// Checks whether enum-flags contains enumerator with such enum-flags value. -template -[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_enum_t { - using D = std::decay_t; - using U = underlying_type_t; - - return enum_cast(static_cast(value)).has_value(); -} - -// Checks whether enum-flags contains enumerator with such integer value. -template -[[nodiscard]] constexpr auto enum_contains(underlying_type_t value) noexcept -> detail::enable_if_enum_t { - using D = std::decay_t; - - return enum_cast(value).has_value(); -} - -// Checks whether enum-flags contains enumerator with such name. -template -[[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p) noexcept(std::is_nothrow_invocable_r_v) -> detail::enable_if_enum_t { - static_assert(std::is_invocable_r_v, "magic_enum::flags::enum_contains requires bool(char, char) invocable predicate."); - using D = std::decay_t; - - return enum_cast(value, std::move_if_noexcept(p)).has_value(); -} - -// Checks whether enum-flags contains enumerator with such name. -template -[[nodiscard]] constexpr auto enum_contains(string_view value) noexcept -> detail::enable_if_enum_t { - using D = std::decay_t; - - return enum_cast(value).has_value(); -} - -} // namespace magic_enum::flags - -namespace flags::ostream_operators { - -template , int> = 0> -std::basic_ostream& operator<<(std::basic_ostream& os, E value) { - using D = std::decay_t; - using U = underlying_type_t; -#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED - if (const auto name = magic_enum::flags::enum_name(value); !name.empty()) { - for (const auto c : name) { - os.put(c); - } - return os; - } -#endif - return (os << static_cast(value)); -} - -template , int> = 0> -std::basic_ostream& operator<<(std::basic_ostream& os, optional value) { - return value.has_value() ? (os << value.value()) : os; -} - -} // namespace magic_enum::flags::ostream_operators - -namespace flags::bitwise_operators { - -using namespace magic_enum::bitwise_operators; - -} // namespace magic_enum::flags::bitwise_operators - -} // namespace magic_enum - -#if defined(__clang__) -# pragma clang diagnostic pop -#elif defined(__GNUC__) -# pragma GCC diagnostic pop -#elif defined(_MSC_VER) -# pragma warning(pop) -#endif - -#endif // NEARGYE_MAGIC_ENUM_HPP diff --git a/aurora-main/lib/aurora.cpp b/aurora-main/lib/aurora.cpp deleted file mode 100644 index aede66a..0000000 --- a/aurora-main/lib/aurora.cpp +++ /dev/null @@ -1,2105 +0,0 @@ -#include - -#ifdef AURORA_ENABLE_GX -#include "gfx/common.hpp" -#include "gfx/efb_ram_copy.hpp" -#include "gx/fifo.hpp" -#include "gx/shader_info.hpp" -#include "imgui.hpp" -#include "webgpu/gpu.hpp" -#include "webgpu/metalfx.hpp" -#include -#endif - -#include "input.hpp" -#include "internal.hpp" -#include "window.hpp" - -#include -#include -#include - -#include "system_info.hpp" -#include "tracy/Tracy.hpp" - -#if defined(_WIN32) -#define WIN32_LEAN_AND_MEAN -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef AURORA_ENABLE_GX -namespace aurora::gx { -// Producer pacing feedback for the adaptive slot count, defined in lib/gx/shader_info.cpp; -// declared here so the C entry point at the bottom of this file can forward to it. -void report_producer_paced(bool paced) noexcept; -} // namespace aurora::gx -#endif - -namespace aurora { -AuroraConfig g_config; -uint32_t g_sdlCustomEventsStart; -char g_gameName[4]; -std::atomic g_frameWorkerWaitCallback{nullptr}; -// Presentation schedule for the frame being sealed, set by the producer. Jobs carry absolute -// deadlines derived from it, so the presenter cannot drift. Zero means present when ready. -std::atomic g_presentScheduleBaseNanos{0}; -std::atomic g_presentScheduleIntervalNanos{0}; -std::atomic g_metalfxRequested{false}; -std::atomic g_metalfxSupported{false}; -std::atomic g_metalfxStatus{AURORA_METALFX_DISABLED}; - -namespace { -Module Log("aurora"); - -std::atomic g_captureFrame{UINT32_MAX}; -std::string g_captureOutputPath; - -using PresentClock = std::chrono::steady_clock; - -struct PresentTimingSample { - PresentClock::time_point presentedAt{}; - std::chrono::nanoseconds interval{}; - // Slot carried a copy of the native image instead of replayed interpolation, so the present - // counts toward the rate but shows no new motion. - bool duplicated = false; -}; - -std::mutex g_presentTimingMutex; -std::array g_presentTimingSamples{}; -size_t g_presentTimingWriteIndex = 0; -size_t g_presentTimingSampleCount = 0; -std::optional g_lastSuccessfulPresent; -uint64_t g_totalPresentCount = 0; - -void wait_until_precise(PresentClock::time_point deadline) noexcept { - // Busy-spin tail covering the waitable timer's wakeup jitter. 150 us was not enough in - // practice; 400 us absorbs the observed overshoot, about 1.6 ms of one core at 240 Hz. - constexpr auto kSpinWindow = std::chrono::microseconds(400); - auto now = PresentClock::now(); - if (now >= deadline) { - return; - } - - const auto timerDeadline = deadline - now > kSpinWindow ? deadline - kSpinWindow : deadline; -#if defined(_WIN32) -#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION -#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002 -#endif - struct HighResolutionTimer { - HANDLE handle = ::CreateWaitableTimerExW(nullptr, nullptr, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, - TIMER_MODIFY_STATE | SYNCHRONIZE); - ~HighResolutionTimer() { - if (handle != nullptr) { - ::CloseHandle(handle); - } - } - }; - static thread_local HighResolutionTimer timer; - if (timer.handle != nullptr && timerDeadline > now) { - const auto remaining100ns = - std::chrono::duration_cast>>( - timerDeadline - now); - LARGE_INTEGER due{}; - due.QuadPart = -std::max(remaining100ns.count(), 1); - if (::SetWaitableTimerEx(timer.handle, &due, 0, nullptr, nullptr, nullptr, 0) != FALSE) { - ::WaitForSingleObject(timer.handle, INFINITE); - } - } else -#endif - { - std::this_thread::sleep_until(timerDeadline); - } - - while (PresentClock::now() < deadline) { -#if defined(_WIN32) - YieldProcessor(); -#else - std::this_thread::yield(); -#endif - } -} - -void record_successful_present(bool, uint32_t, - std::chrono::nanoseconds, - std::chrono::nanoseconds, - std::chrono::nanoseconds, - std::chrono::nanoseconds, - std::chrono::nanoseconds, - std::chrono::nanoseconds, bool duplicated, - uint32_t, std::chrono::nanoseconds) noexcept { - const auto now = PresentClock::now(); - std::chrono::nanoseconds interval{}; - { - std::lock_guard lock(g_presentTimingMutex); - if (g_lastSuccessfulPresent) { - interval = std::chrono::duration_cast(now - *g_lastSuccessfulPresent); - } - g_lastSuccessfulPresent = now; - g_presentTimingSamples[g_presentTimingWriteIndex] = { - .presentedAt = now, - .interval = interval, - .duplicated = duplicated, - }; - g_presentTimingWriteIndex = (g_presentTimingWriteIndex + 1) % g_presentTimingSamples.size(); - g_presentTimingSampleCount = std::min(g_presentTimingSampleCount + 1, g_presentTimingSamples.size()); - ++g_totalPresentCount; - } -} - -AuroraPresentTiming snapshot_present_timing() noexcept { - constexpr auto kWindow = std::chrono::seconds(1); - const auto cutoff = PresentClock::now() - kWindow; - std::vector milliseconds; - uint64_t totalPresentCount = 0; - size_t newMotionSamples = 0; - { - std::lock_guard lock(g_presentTimingMutex); - totalPresentCount = g_totalPresentCount; - milliseconds.reserve(g_presentTimingSampleCount); - for (size_t i = 0; i < g_presentTimingSampleCount; ++i) { - const auto& sample = g_presentTimingSamples[i]; - if (sample.presentedAt >= cutoff && sample.interval.count() > 0) { - milliseconds.push_back( - std::chrono::duration(sample.interval).count()); - if (!sample.duplicated) { - ++newMotionSamples; - } - } - } - } - - AuroraPresentTiming result{ - .totalPresentCount = totalPresentCount, - .sampleCount = static_cast(milliseconds.size()), - }; - if (milliseconds.empty()) { - return result; - } - - double totalMilliseconds = 0.0; - for (const double value : milliseconds) { - totalMilliseconds += value; - } - result.averageFrameTimeMs = totalMilliseconds / static_cast(milliseconds.size()); - result.framesPerSecond = result.averageFrameTimeMs > 0.0 ? 1000.0 / result.averageFrameTimeMs : 0.0; - // Duplicated presentation slots keep the presented cadence but carry no new - // motion; scale them out so this reads as the rate the eye actually sees. - result.effectiveFramesPerSecond = - result.framesPerSecond * - (static_cast(newMotionSamples) / static_cast(milliseconds.size())); - for (const double value : milliseconds) { - const double difference = value - result.averageFrameTimeMs; - result.jitterMs += difference * difference; - } - result.jitterMs = std::sqrt(result.jitterMs / static_cast(milliseconds.size())); - std::sort(milliseconds.begin(), milliseconds.end()); - result.p95FrameTimeMs = - milliseconds[static_cast(std::floor(static_cast(milliseconds.size() - 1) * 0.95))]; - return result; -} - -// ImGui draw data lives in the shared context, so starting the next ImGui frame destroys draw -// lists the sealed slots still replay. That is why ImGui callers wait for DONE, not SEALED. -enum class ImGuiFramePolicy { - // Start ImGui's next frame as part of renderer preparation, as the - // synchronous path always has. - Immediate, - // Leave it unstarted; the caller owes an imgui::new_frame() once it has - // finished replaying this frame's draw data. - Deferred, -}; - -bool begin_frame_impl(bool pumpEvents, ImGuiFramePolicy imguiPolicy = ImGuiFramePolicy::Immediate, - bool* imguiNewFrameOwed = nullptr) noexcept; -bool begin_frame_render_state_impl(ImGuiFramePolicy imguiPolicy, bool* imguiNewFrameOwed) noexcept; -void end_frame_impl(bool pumpEvents, bool drainFifo); - -// The two publication points of a frame-worker cycle, cleared together under `mutex`. Sealed: -// producer-shared renderer state is free again. Done: slots encoded, presented, ImGui restarted. -enum class FrameWorkerPhase { - Sealed, - Done, -}; - -struct FrameWorkerState { - std::mutex mutex; - std::condition_variable cv; - std::thread thread; - std::thread::id threadId{}; - bool started = false; - bool stop = false; - bool jobPending = false; - // Readiness is polled thousands of times per frame, so these flags double as a publication - // barrier. `sealed` is released before `ready`, and both are cleared under `mutex`. - std::atomic_bool sealed{true}; - std::atomic_bool ready{true}; - bool framePrepared = false; - bool prepareAllowed = false; -}; - -FrameWorkerState g_frameWorker; - -bool frame_worker_requested() noexcept { -#ifdef AURORA_ENABLE_GX - static const bool enabled = [] { -#if defined(__APPLE__) - // ImGui's SDL backend may raise an SDL window from ImGui::NewFrame(). On - // macOS that reaches AppKit, whose window operations are main-thread-only; - // doing it on the frame worker terminates the process with EXC_BREAKPOINT. - // Keep all SDL/ImGui work on the calling thread until the worker no longer - // owns frame preparation on Apple platforms. - return false; -#endif -#if defined(_WIN32) - // RenderDoc's D3D12 layer is injected before Aurora starts and needs device and command - // ownership on one thread, so keep frame submission synchronous there. - if (::GetModuleHandleW(L"renderdoc.dll") != nullptr) { - return false; - } -#endif - return true; - }(); -#if defined(_WIN32) - static const bool renderDocLoaded = ::GetModuleHandleW(L"renderdoc.dll") != nullptr; - if (renderDocLoaded) { - static const bool logged = [] { - Log.info("Disabled asynchronous frame submission worker for RenderDoc capture"); - return true; - }(); - (void)logged; - } -#endif - return enabled; -#else - return false; -#endif -} - -#ifdef AURORA_ENABLE_GX -// Returns false when a stop request was observed mid-cycle. -bool run_frame_worker_cycle(gfx::SealedFrame& sealedFrame) noexcept; -#endif - -void frame_worker_main() noexcept { - { - std::lock_guard lock(g_frameWorker.mutex); - g_frameWorker.threadId = std::this_thread::get_id(); - } - -#ifdef AURORA_ENABLE_GX - // Owned by the worker for its whole lifetime so the sealed pass vector and - // its pooled command lists keep their capacity across frames. - gfx::SealedFrame sealedFrame; -#endif - - for (;;) { - { - std::unique_lock lock(g_frameWorker.mutex); - g_frameWorker.cv.wait(lock, [] { return g_frameWorker.stop || g_frameWorker.jobPending; }); - if (g_frameWorker.stop) { - break; - } - g_frameWorker.jobPending = false; - } - - // The CPU already decoded the sealed frame at its GX boundary; the worker only owns - // encode/submit/present, so it never touches the producer's next FIFO buffer. -#ifdef AURORA_ENABLE_GX - if (!run_frame_worker_cycle(sealedFrame)) { - break; - } -#endif - } - - // A stop request can unblock either wait above mid-cycle, so release both phases before - // stop_frame_worker() joins. - { - std::lock_guard lock(g_frameWorker.mutex); - g_frameWorker.sealed.store(true, std::memory_order_release); - g_frameWorker.ready.store(true, std::memory_order_release); - } - g_frameWorker.cv.notify_all(); -} - -void ensure_frame_worker_started() noexcept { - if (!frame_worker_requested()) { - return; - } - std::lock_guard lock(g_frameWorker.mutex); - if (g_frameWorker.started) { - return; - } - g_frameWorker.stop = false; - g_frameWorker.jobPending = false; - g_frameWorker.sealed.store(true, std::memory_order_release); - g_frameWorker.ready.store(true, std::memory_order_release); - g_frameWorker.prepareAllowed = false; - g_frameWorker.started = true; - g_frameWorker.thread = std::thread(frame_worker_main); - Log.info("Enabled bounded asynchronous frame submission worker"); -} - -bool frame_worker_phase_reached(FrameWorkerPhase phase) noexcept { - return phase == FrameWorkerPhase::Sealed ? g_frameWorker.sealed.load(std::memory_order_acquire) - : g_frameWorker.ready.load(std::memory_order_acquire); -} - -bool wait_for_frame_worker_private_for(FrameWorkerPhase phase, std::chrono::microseconds timeout) noexcept; - -void wait_for_frame_worker_private(FrameWorkerPhase phase) noexcept { - constexpr auto kWaitServiceInterval = std::chrono::milliseconds(1); - while (!wait_for_frame_worker_private_for(phase, kWaitServiceInterval)) { - } -} - -bool wait_for_frame_worker_private_for(FrameWorkerPhase phase, std::chrono::microseconds timeout) noexcept { - // Each phase's state is published before its flag is set, which keeps the common - // display-list path out of the worker control mutex. - if (frame_worker_phase_reached(phase)) { - return true; - } - - std::unique_lock lock(g_frameWorker.mutex); - if (!g_frameWorker.started || g_frameWorker.threadId == std::this_thread::get_id()) { - return true; - } - if (timeout <= std::chrono::microseconds::zero()) { - return frame_worker_phase_reached(phase); - } - - const bool reached = - g_frameWorker.cv.wait_for(lock, timeout, [phase] { return frame_worker_phase_reached(phase); }); - if (reached) { - return true; - } - - lock.unlock(); - // Both phases service the guest's alarm/retrace pump identically; the - // producer must keep its own timing alive however long it waits. - if (const auto callback = g_frameWorkerWaitCallback.load(std::memory_order_acquire)) { - callback(); - } - return false; -} - -void stop_frame_worker() noexcept { - { - std::lock_guard lock(g_frameWorker.mutex); - if (!g_frameWorker.started) { - return; - } - g_frameWorker.stop = true; - g_frameWorker.prepareAllowed = true; - } - g_frameWorker.cv.notify_all(); - if (g_frameWorker.thread.joinable()) { - g_frameWorker.thread.join(); - } - std::lock_guard lock(g_frameWorker.mutex); - g_frameWorker.started = false; - g_frameWorker.threadId = {}; - g_frameWorker.framePrepared = false; -} - -uint32_t align_to(uint32_t value, uint32_t alignment) noexcept { - return (value + alignment - 1) & ~(alignment - 1); -} - -void append_u16(std::ofstream& out, uint16_t value) { - const char bytes[] = {static_cast(value), static_cast(value >> 8)}; - out.write(bytes, sizeof(bytes)); -} - -void append_u32(std::ofstream& out, uint32_t value) { - const char bytes[] = {static_cast(value), static_cast(value >> 8), - static_cast(value >> 16), static_cast(value >> 24)}; - out.write(bytes, sizeof(bytes)); -} - -bool write_bmp(const char* path, const uint8_t* pixels, uint32_t width, uint32_t height, - uint32_t bytesPerRow, bool bgra) { - std::ofstream out(path, std::ios::binary | std::ios::trunc); - if (!out) return false; - constexpr uint32_t pixelOffset = 14 + 40; - const uint32_t imageSize = width * height * 4; - out.write("BM", 2); - append_u32(out, pixelOffset + imageSize); - append_u16(out, 0); - append_u16(out, 0); - append_u32(out, pixelOffset); - append_u32(out, 40); - append_u32(out, width); - append_u32(out, height); - append_u16(out, 1); - append_u16(out, 32); - append_u32(out, 0); - append_u32(out, imageSize); - append_u32(out, 2835); - append_u32(out, 2835); - append_u32(out, 0); - append_u32(out, 0); - std::vector row(width * 4); - for (uint32_t y = height; y-- > 0;) { - const auto* source = pixels + static_cast(y) * bytesPerRow; - if (bgra) { - out.write(reinterpret_cast(source), row.size()); - } else { - for (uint32_t x = 0; x < width; ++x) { - row[x * 4 + 0] = source[x * 4 + 2]; - row[x * 4 + 1] = source[x * 4 + 1]; - row[x * 4 + 2] = source[x * 4 + 0]; - row[x * 4 + 3] = source[x * 4 + 3]; - } - out.write(reinterpret_cast(row.data()), row.size()); - } - } - return out.good(); -} - -#ifdef AURORA_ENABLE_GX -// GPU -using webgpu::g_device; -using webgpu::g_instance; -using webgpu::g_queue; -using webgpu::g_surface; -std::recursive_mutex g_rendererGpuMutex; -std::mutex g_queueSubmitMutex; -// Surface ownership, held apart from the renderer mutex: a presentation slot touches the surface, -// its image and the queue, nothing recorded. Lock order is surface then renderer. -std::mutex g_surfaceMutex; -std::atomic g_surfaceReconfigurePending{false}; -std::atomic g_surfaceRecreatePending{false}; - -void request_surface_reconfigure() noexcept { - g_surfaceReconfigurePending.store(true, std::memory_order_release); -} - -void request_surface_recreate() noexcept { - g_surfaceRecreatePending.store(true, std::memory_order_release); - g_surfaceReconfigurePending.store(true, std::memory_order_release); -} - -struct PendingFrameCapture { - wgpu::Buffer buffer; - uint32_t width = 0; - uint32_t height = 0; - uint32_t bytesPerRow = 0; - uint64_t bufferSize = 0; - bool bgra = false; - std::string path; -}; - -std::optional encode_frame_capture(const wgpu::CommandEncoder& encoder, - const webgpu::PresentSource& source) { - const uint32_t requestedFrame = g_captureFrame.load(std::memory_order_acquire); - const uint32_t currentFrame = gfx::current_frame(); - if (requestedFrame == UINT32_MAX || currentFrame < requestedFrame) return std::nullopt; - g_captureFrame.store(UINT32_MAX, std::memory_order_release); - if (currentFrame != requestedFrame) { - Log.error("Missed requested frame capture {} (current frame {})", requestedFrame, currentFrame); - return std::nullopt; - } - if (!source.texture || source.size.width == 0 || source.size.height == 0) { - Log.error("Frame {} capture has no present-source texture", currentFrame); - return std::nullopt; - } - const bool bgra = source.format == wgpu::TextureFormat::BGRA8Unorm || - source.format == wgpu::TextureFormat::BGRA8UnormSrgb; - const bool rgba = source.format == wgpu::TextureFormat::RGBA8Unorm || - source.format == wgpu::TextureFormat::RGBA8UnormSrgb; - if (!bgra && !rgba) { - Log.error("Frame {} capture does not support texture format {}", currentFrame, - magic_enum::enum_name(source.format)); - return std::nullopt; - } - const uint32_t bytesPerRow = align_to(source.size.width * 4, 256); - const uint64_t bufferSize = static_cast(bytesPerRow) * source.size.height; - const wgpu::BufferDescriptor descriptor{ - .label = "Visual validation frame capture", - .usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::MapRead, - .size = bufferSize, - }; - auto buffer = g_device.CreateBuffer(&descriptor); - const wgpu::TexelCopyTextureInfo sourceInfo{ - .texture = source.texture, - .mipLevel = 0, - .origin = {0, 0, 0}, - .aspect = wgpu::TextureAspect::All, - }; - const wgpu::TexelCopyBufferInfo destinationInfo{ - .layout = {.offset = 0, .bytesPerRow = bytesPerRow, .rowsPerImage = source.size.height}, - .buffer = buffer, - }; - encoder.CopyTextureToBuffer(&sourceInfo, &destinationInfo, &source.size); - return PendingFrameCapture{ - .buffer = std::move(buffer), - .width = source.size.width, - .height = source.size.height, - .bytesPerRow = bytesPerRow, - .bufferSize = bufferSize, - .bgra = bgra, - .path = g_captureOutputPath, - }; -} - -void complete_frame_capture(PendingFrameCapture& capture) { - wgpu::MapAsyncStatus mapStatus = wgpu::MapAsyncStatus::CallbackCancelled; - wgpu::StringView mapMessage{}; - const auto future = capture.buffer.MapAsync( - wgpu::MapMode::Read, 0, capture.bufferSize, wgpu::CallbackMode::WaitAnyOnly, - [&mapStatus, &mapMessage](wgpu::MapAsyncStatus status, wgpu::StringView message) { - mapStatus = status; - mapMessage = message; - }); - const auto waitStatus = g_instance.WaitAny(future, 5000000000); - if (waitStatus != wgpu::WaitStatus::Success || mapStatus != wgpu::MapAsyncStatus::Success) { - Log.error("Frame capture readback failed wait={} map={} message={}", magic_enum::enum_name(waitStatus), - magic_enum::enum_name(mapStatus), mapMessage); - return; - } - const auto* pixels = static_cast(capture.buffer.GetConstMappedRange(0, capture.bufferSize)); - if (write_bmp(capture.path.c_str(), pixels, capture.width, capture.height, capture.bytesPerRow, capture.bgra)) { - Log.info("Captured rendered frame to '{}' ({}x{})", capture.path, capture.width, capture.height); - } else { - Log.error("Failed to write rendered frame capture to '{}'", capture.path); - } - capture.buffer.Unmap(); -} -#endif - -// AuroraBackend is an anonymous C typedef enum, which magic_enum cannot -// reflect under this toolchain -- name it by hand for diagnostics. -constexpr const char* backend_name(AuroraBackend backend) noexcept { - switch (backend) { - case BACKEND_AUTO: - return "Auto"; - case BACKEND_D3D11: - return "D3D11"; - case BACKEND_D3D12: - return "D3D12"; - case BACKEND_METAL: - return "Metal"; - case BACKEND_VULKAN: - return "Vulkan"; - case BACKEND_OPENGL: - return "OpenGL"; - case BACKEND_OPENGLES: - return "OpenGLES"; - case BACKEND_WEBGPU: - return "WebGPU"; - case BACKEND_NULL: - return "Null"; - } - return "Unknown"; -} - -#ifdef AURORA_ENABLE_GX -constexpr std::array PreferredBackendOrder{ -#ifdef ENABLE_BACKEND_WEBGPU - BACKEND_WEBGPU, -#endif -#ifdef DAWN_ENABLE_BACKEND_D3D12 - BACKEND_D3D12, -#endif -#if defined(_WIN32) && defined(DAWN_ENABLE_BACKEND_D3D11) - BACKEND_D3D11, -#endif -#ifdef DAWN_ENABLE_BACKEND_METAL - BACKEND_METAL, -#endif -#ifdef DAWN_ENABLE_BACKEND_VULKAN - BACKEND_VULKAN, -#endif -#if !defined(_WIN32) && defined(DAWN_ENABLE_BACKEND_D3D11) - BACKEND_D3D11, -#endif -// #ifdef DAWN_ENABLE_BACKEND_DESKTOP_GL -// BACKEND_OPENGL, -// #endif -// #ifdef DAWN_ENABLE_BACKEND_OPENGLES -// BACKEND_OPENGLES, -// #endif -#ifdef DAWN_ENABLE_BACKEND_NULL - BACKEND_NULL, -#endif -}; -#else -constexpr std::array PreferredBackendOrder{}; -#endif - -bool g_initialFrame = false; - - -AuroraInfo initialize(int argc, char* argv[], const AuroraConfig& config) noexcept { - g_config = config; - Log.info("Aurora initializing"); - log_system_information(); - if (g_config.appName == nullptr) { - g_config.appName = "Aurora"; - } else { - g_config.appName = strdup(g_config.appName); - } - if (g_config.userPath == nullptr) { - g_config.userPath = SDL_GetPrefPath(nullptr, g_config.appName); - } else { - g_config.userPath = strdup(g_config.userPath); - } - if (g_config.cachePath == nullptr) { - g_config.cachePath = SDL_GetPrefPath(nullptr, g_config.appName); - } else { - g_config.cachePath = strdup(g_config.cachePath); - } - if (g_config.resourcesPath == nullptr) { - g_config.resourcesPath = SDL_GetBasePath(); - } else { - g_config.resourcesPath = strdup(g_config.resourcesPath); - } - if (g_config.pipelineCachePath == nullptr) { - g_config.pipelineCachePath = g_config.cachePath; - } else { - g_config.pipelineCachePath = strdup(g_config.pipelineCachePath); - } - if (g_config.msaa == 0) { - g_config.msaa = 1; - } - if (g_config.maxTextureAnisotropy == 0) { - g_config.maxTextureAnisotropy = 16; - } - ASSERT(window::initialize(), "Error initializing window"); - - g_sdlCustomEventsStart = SDL_RegisterEvents(2); - ASSERT(g_sdlCustomEventsStart, "Failed to allocate user events: {}", SDL_GetError()); - ASSERT(window::initialize_event_watch(), "Error initializing SDL event watch"); - -#ifdef AURORA_ENABLE_GX - /* Attempt to create a window using the calling application's desired backend */ - const AuroraBackend requestedBackend = config.desiredBackend; - AuroraBackend selectedBackend = requestedBackend; - bool windowCreated = false; - std::string firstGraphicsError; - const auto rememberGraphicsError = [&] { - if (firstGraphicsError.empty() && SDL_GetError()[0] != '\0') { - firstGraphicsError = SDL_GetError(); - } - }; - if (selectedBackend != BACKEND_AUTO) { - Log.info("Requested graphics backend: {}", backend_name(selectedBackend)); - if (window::create_window(selectedBackend)) { - if (webgpu::initialize(selectedBackend)) { - windowCreated = true; - } else { - rememberGraphicsError(); - window::destroy_window(); - } - } else { - rememberGraphicsError(); - Log.error("Failed to create a window for backend {}: {}", backend_name(selectedBackend), - SDL_GetError()); - } - if (!windowCreated) { - /* An explicitly requested backend that cannot be brought up falls back to the BACKEND_AUTO - * search instead of aborting, and the substitution is always reported. */ - Log.error("Requested graphics backend {} is unavailable on this system; " - "falling back to automatic selection", - backend_name(requestedBackend)); - } - } - - if (!windowCreated) { - for (const auto backendType : PreferredBackendOrder) { - selectedBackend = backendType; - if (!window::create_window(selectedBackend)) { - rememberGraphicsError(); - continue; - } - if (webgpu::initialize(selectedBackend)) { - windowCreated = true; - break; - } else { - rememberGraphicsError(); - window::destroy_window(); - } - } - } - - if (!windowCreated) { - if (firstGraphicsError.empty()) firstGraphicsError = "No supported graphics backend is available"; - SDL_SetError("%s", firstGraphicsError.c_str()); - Log.error("Graphics initialization failed: {}", firstGraphicsError); - return { - .initializationStatus = AURORA_INITIALIZATION_GRAPHICS_UNAVAILABLE, - .initializationError = SDL_GetError(), - }; - } - if (requestedBackend != BACKEND_AUTO && selectedBackend != requestedBackend) { - Log.error("Graphics backend fallback in effect: video.graphics_api requested {}, " - "running on {}", - backend_name(requestedBackend), backend_name(selectedBackend)); - } - - // Initialize SDL_Renderer for ImGui when we can't use a Dawn backend - if (webgpu::g_backendType == wgpu::BackendType::Null) { - ASSERT(window::create_renderer(), "Failed to initialize SDL renderer: {}", SDL_GetError()); - } -#else - AuroraBackend selectedBackend = BACKEND_NULL; - ASSERT(window::create_window(BACKEND_NULL), "Error creating window: {}", SDL_GetError()); - ASSERT(window::create_renderer(), "Failed to initialize SDL renderer: {}", SDL_GetError()); -#endif - - window::show_window(); - -#ifdef AURORA_ENABLE_GX - gfx::initialize(); - - g_metalfxSupported.store(webgpu::metalfx::supported(g_device, webgpu::g_backendType)); - g_metalfxStatus.store(AURORA_METALFX_DISABLED); - - imgui::create_context(); -#endif - const auto size = window::get_window_size(); - Log.info("Using framebuffer size {}x{} scale {}", size.fb_width, size.fb_height, size.scale); -#ifdef AURORA_ENABLE_GX - if (g_config.imGuiInitCallback != nullptr) { - g_config.imGuiInitCallback(&size); - } - imgui::initialize(); -#endif - - g_initialFrame = true; - g_config.desiredBackend = selectedBackend; - return { - .backend = selectedBackend, - .userPath = g_config.userPath, - .cachePath = g_config.cachePath, - .window = window::get_sdl_window(), - .windowSize = size, - }; -} - -#ifdef AURORA_ENABLE_GX -struct AcquiredSurfaceTexture { - wgpu::Texture texture; - wgpu::TextureView view; -}; - -std::optional acquire_surface_texture() noexcept { - if (!window::is_presentable()) { - request_surface_reconfigure(); - return std::nullopt; - } - if (!g_surface) { - request_surface_reconfigure(); - return std::nullopt; - } - - wgpu::SurfaceTexture surfaceTexture; - g_surface.GetCurrentTexture(&surfaceTexture); - switch (surfaceTexture.status) { - case wgpu::SurfaceGetCurrentTextureStatus::SuccessOptimal: - return AcquiredSurfaceTexture{ - .texture = surfaceTexture.texture, - .view = surfaceTexture.texture.CreateView(), - }; - case wgpu::SurfaceGetCurrentTextureStatus::SuccessSuboptimal: - Log.info("Surface texture is suboptimal, deferring swapchain reconfiguration"); - request_surface_reconfigure(); - return AcquiredSurfaceTexture{ - .texture = surfaceTexture.texture, - .view = surfaceTexture.texture.CreateView(), - }; - case wgpu::SurfaceGetCurrentTextureStatus::Timeout: - Log.warn("Surface texture acquisition timed out"); - return std::nullopt; - case wgpu::SurfaceGetCurrentTextureStatus::Outdated: - Log.info("Surface texture is {}, reconfiguring swapchain", magic_enum::enum_name(surfaceTexture.status)); - request_surface_reconfigure(); - return std::nullopt; - case wgpu::SurfaceGetCurrentTextureStatus::Lost: - Log.warn("Surface texture is {}, requesting surface recreation", magic_enum::enum_name(surfaceTexture.status)); - request_surface_recreate(); - return std::nullopt; - case wgpu::SurfaceGetCurrentTextureStatus::Error: - Log.warn("Surface texture is {}, deferring surface recovery", magic_enum::enum_name(surfaceTexture.status)); - request_surface_reconfigure(); - return std::nullopt; - default: - Log.error("Failed to get surface texture: {}", magic_enum::enum_name(surfaceTexture.status)); - return std::nullopt; - } -} - -struct PresentationImage { - webgpu::TextureWithSampler texture; - wgpu::BindGroup bindGroup; -}; - -struct PresentationJob { - std::shared_ptr image; - uint32_t logicalFrame = 0; - // Absolute deadline on PresentClock stamped by the producer's schedule. - // Default (epoch) means "present as soon as ready" (no software pacing). - PresentClock::time_point presentAt{}; - bool interpolated = false; - // Slot carries a copy of the native image rather than a replayed interpolation. It counts as a - // present but not toward effectiveFramesPerSecond. - bool duplicated = false; - // Whole display periods the group slid forward at encode time (late group). - uint32_t slidPeriods = 0; -}; - -std::array>, gx::MaxInterpolatedFrames + 1> - g_presentationImagePools; - -std::shared_ptr acquire_presentation_image(size_t slot, uint32_t width, - uint32_t height) { - auto& pool = g_presentationImagePools.at(slot); - // A use count of one means only the pool holds the image, so no job can be reading it. Idle - // images from an older surface size are dropped here instead of leaking for the run. - for (auto it = pool.begin(); it != pool.end();) { - const auto& image = *it; - if (image->texture.size.width == width && image->texture.size.height == height) { - if (image.use_count() == 1) { - return image; - } - ++it; - continue; - } - if (image.use_count() == 1) { - it = pool.erase(it); - } else { - ++it; - } - } - - auto image = std::make_shared(); - image->texture = webgpu::create_render_texture(width, height, false); - image->bindGroup = webgpu::create_copy_bind_group(image->texture); - pool.emplace_back(image); - return image; -} - -bool present_presentation_job(const PresentationJob& job) { - ZoneScoped; - const auto submissionStarted = PresentClock::now(); - // Keep the threshold far above compositor and scheduling jitter. The timings below separate a - // real surface stall from a bad deadline, and only the former needs a rebuild. - constexpr auto kSurfaceStallThreshold = std::chrono::milliseconds(250); - std::chrono::nanoseconds surfaceLockDuration{}; - std::chrono::nanoseconds acquireDuration{}; - std::chrono::nanoseconds encodeDuration{}; - std::chrono::nanoseconds finishDuration{}; - std::chrono::nanoseconds submitDuration{}; - std::chrono::nanoseconds scheduleWaitDuration{}; - std::chrono::nanoseconds presentDuration{}; - bool presented = false; - if (g_surfaceReconfigurePending.load(std::memory_order_acquire) || - window::native_resize_pending() || !window::is_presentable()) { - return false; - } - std::chrono::nanoseconds lateBy{}; - if (job.presentAt != PresentClock::time_point{}) { - // How expired the deadline already is at dequeue. Positive values mean the - // slot cannot be paced and fires immediately, which is a burst symptom. - lateBy = std::chrono::duration_cast(PresentClock::now() - - job.presentAt); - } - { - window::SurfaceLock surfaceLock; - // Acquire, encode, submit and present are one unit against a configured swapchain, so the - // surface lock covers all of them. The renderer mutex is deliberately not taken. - const auto surfaceLockStarted = PresentClock::now(); - std::unique_lock surfaceOwnership(g_surfaceMutex); - surfaceLockDuration = std::chrono::duration_cast( - PresentClock::now() - surfaceLockStarted); - // Surface contention is waiting, not encoding, so keep it out of the encode timing where a - // reconfigure would look like GPU command recording. - const auto workStarted = PresentClock::now(); - bool surfaceSizeChanged = window::native_resize_pending(); - if (!surfaceSizeChanged && - !g_surfaceReconfigurePending.load(std::memory_order_acquire) && - window::is_presentable() && g_surface) { - // native_window_size_matches compares the OS client size with the configured swapchain, which is - // what native_fb_* reports. One window query instead of SDL's per-call ones. - surfaceSizeChanged = !window::native_window_size_matches( - webgpu::g_graphicsConfig.surfaceConfiguration.width, - webgpu::g_graphicsConfig.surfaceConfiguration.height); - } - if (!surfaceSizeChanged && window::is_presentable()) { - const auto acquireStarted = PresentClock::now(); - auto acquired = acquire_surface_texture(); - acquireDuration = - std::chrono::duration_cast(PresentClock::now() - acquireStarted); - if (acquired) { - const wgpu::CommandEncoderDescriptor encoderDescriptor{ - .label = "Presentation encoder", - }; - const auto encoder = g_device.CreateCommandEncoder(&encoderDescriptor); - const std::array attachments{ - wgpu::RenderPassColorAttachment{ - .view = acquired->view, - .loadOp = wgpu::LoadOp::Clear, - .storeOp = wgpu::StoreOp::Store, - }, - }; - const wgpu::RenderPassDescriptor renderPassDescriptor{ - .label = "Presentation copy pass", - .colorAttachmentCount = attachments.size(), - .colorAttachments = attachments.data(), - }; - const auto pass = encoder.BeginRenderPass(&renderPassDescriptor); - pass.SetPipeline(webgpu::g_CopyPipeline); - pass.SetBindGroup(0, job.image->bindGroup, 0, nullptr); - pass.SetViewport(0.f, 0.f, - static_cast(webgpu::g_graphicsConfig.surfaceConfiguration.width), - static_cast(webgpu::g_graphicsConfig.surfaceConfiguration.height), - 0.f, 1.f); - pass.Draw(3); - pass.End(); - const auto encodeFinished = PresentClock::now(); - encodeDuration = std::chrono::duration_cast( - encodeFinished - workStarted - acquireDuration); - const wgpu::CommandBufferDescriptor cmdBufDescriptor{ - .label = "Presentation command buffer", - }; - const auto finishStarted = PresentClock::now(); - const auto buffer = encoder.Finish(&cmdBufDescriptor); - finishDuration = std::chrono::duration_cast( - PresentClock::now() - finishStarted); - const auto submitStarted = PresentClock::now(); - { - std::lock_guard submitLock(g_queueSubmitMutex); - g_queue.Submit(1, &buffer); - } - submitDuration = std::chrono::duration_cast( - PresentClock::now() - submitStarted); - // Pace the Present() call itself, not the whole unit, so acquire/encode/submit variance stays out - // of the cadence. Holding the image across the wait is safe while the surface lock is held. - if (job.presentAt != PresentClock::time_point{}) { - const auto scheduleWaitStarted = PresentClock::now(); - wait_until_precise(job.presentAt); - scheduleWaitDuration = std::chrono::duration_cast( - PresentClock::now() - scheduleWaitStarted); - } - // A native resize can arrive after acquisition, so drop the obsolete image and let the render - // worker reconfigure at its ordered frame boundary. - if (!g_surfaceReconfigurePending.load(std::memory_order_acquire) && - !window::native_resize_pending() && window::is_presentable() && - window::native_window_size_matches( - webgpu::g_graphicsConfig.surfaceConfiguration.width, - webgpu::g_graphicsConfig.surfaceConfiguration.height)) { - const auto presentStarted = PresentClock::now(); - wgpu::Status presentStatus; - { - std::lock_guard submitLock(g_queueSubmitMutex); - presentStatus = g_surface.Present(); - } - presentDuration = std::chrono::duration_cast( - PresentClock::now() - presentStarted); - if (presentStatus == wgpu::Status::Success) { - presented = true; - record_successful_present( - job.interpolated, job.logicalFrame, acquireDuration, encodeDuration, - finishDuration, submitDuration, presentDuration, - std::chrono::duration_cast(PresentClock::now() - - submissionStarted), - job.duplicated, job.slidPeriods, lateBy); - } else { - Log.warn("Surface present failed: {}", static_cast(presentStatus)); - request_surface_reconfigure(); - } - } - acquired.reset(); - } - } - } - const auto totalDuration = - std::chrono::duration_cast(PresentClock::now() - submissionStarted); - constexpr int kStallRebuildThreshold = 3; - constexpr auto kStallRebuildCooldown = std::chrono::seconds(5); - static int s_consecutiveStalledPresents = 0; - static PresentClock::time_point s_lastStallRebuild{}; - if (totalDuration >= kSurfaceStallThreshold) { - const auto surfaceWorkDuration = - acquireDuration + encodeDuration + finishDuration + submitDuration + presentDuration; - const bool surfaceStalled = surfaceWorkDuration >= kSurfaceStallThreshold; - bool rebuildRequested = false; - if (surfaceStalled) { - ++s_consecutiveStalledPresents; - const auto now = PresentClock::now(); - if (s_consecutiveStalledPresents >= kStallRebuildThreshold && - (s_lastStallRebuild == PresentClock::time_point{} || - now - s_lastStallRebuild >= kStallRebuildCooldown)) { - s_lastStallRebuild = now; - s_consecutiveStalledPresents = 0; - rebuildRequested = true; - } - } else { - s_consecutiveStalledPresents = 0; - } - Log.warn("Presentation job took {:.1f} ms (surface lock {:.1f}, acquire {:.1f}, encode {:.1f}, " - "finish {:.1f}, submit {:.1f}, schedule wait {:.1f}, present {:.1f}){}", - std::chrono::duration(totalDuration).count(), - std::chrono::duration(surfaceLockDuration).count(), - std::chrono::duration(acquireDuration).count(), - std::chrono::duration(encodeDuration).count(), - std::chrono::duration(finishDuration).count(), - std::chrono::duration(submitDuration).count(), - std::chrono::duration(scheduleWaitDuration).count(), - std::chrono::duration(presentDuration).count(), - rebuildRequested ? "; rebuilding the surface" : ""); - if (rebuildRequested) { - request_surface_reconfigure(); - } - } else { - s_consecutiveStalledPresents = 0; - } - return presented; -} - -struct PresenterState { - std::mutex mutex; - std::condition_variable cv; - std::thread thread; - std::deque jobs; - bool started = false; - bool stop = false; - bool presenting = false; -}; - -PresenterState g_presenter; -std::atomic g_presenterStarted{false}; - -void presenter_main() noexcept { - if (!SDL_SetCurrentThreadPriority(SDL_THREAD_PRIORITY_HIGH)) { - Log.warn("Could not raise the asynchronous presenter thread priority: {}", SDL_GetError()); - } - for (;;) { - PresentationJob job; - { - std::unique_lock lock(g_presenter.mutex); - g_presenter.cv.wait(lock, [] { return g_presenter.stop || !g_presenter.jobs.empty(); }); - if (g_presenter.stop && g_presenter.jobs.empty()) { - break; - } - job = std::move(g_presenter.jobs.front()); - g_presenter.jobs.pop_front(); - g_presenter.presenting = true; - } - g_presenter.cv.notify_all(); - - present_presentation_job(job); - - { - std::lock_guard lock(g_presenter.mutex); - g_presenter.presenting = false; - } - g_presenter.cv.notify_all(); - } -} - -void ensure_presenter_started() { - std::lock_guard lock(g_presenter.mutex); - if (g_presenter.started) { - return; - } - g_presenter.stop = false; - g_presenter.presenting = false; - g_presenter.thread = std::thread(presenter_main); - g_presenter.started = true; - g_presenterStarted.store(true, std::memory_order_release); - Log.info("Enabled bounded asynchronous presentation worker"); -} - -void wait_for_presenter_idle() noexcept { - if (!g_presenterStarted.load(std::memory_order_acquire)) { - return; - } - std::unique_lock lock(g_presenter.mutex); - g_presenter.cv.wait( - lock, [] { return g_presenter.jobs.empty() && !g_presenter.presenting; }); -} - -void enqueue_presentations(std::vector&& jobs) { - ensure_presenter_started(); - // Scale the bound with the group being handed over: a 240 Hz frame enqueues four jobs at once, - // and a bound sized for two groups blocked the frame worker on a draining one. - const size_t maximumQueuedJobs = - (std::max)(static_cast(2 * (gx::MaxInterpolatedFrames + 1)), 3 * jobs.size()); - std::unique_lock lock(g_presenter.mutex); - if (g_presenter.stop) { - return; - } - if (g_presenter.jobs.size() + jobs.size() > maximumQueuedJobs) { - // Presentation is a real-time stream, not a lossless queue: waiting for room couples the guest - // and audio clocks to a blocked Present(). Keep the newest group and drop obsolete images. - const size_t dropped = g_presenter.jobs.size(); - g_presenter.jobs.clear(); - if (dropped != 0) { - // A stuck Present can keep replacement mode active for a while. Aggregate - // the warning instead of turning a driver stall into a log flood. - static size_t droppedSinceWarning = 0; - static PresentClock::time_point lastWarning{}; - droppedSinceWarning += dropped; - const auto now = PresentClock::now(); - if (lastWarning == PresentClock::time_point{} || now - lastWarning >= std::chrono::seconds(1)) { - Log.warn("Presenter fell behind; dropped {} stale presentation jobs", droppedSinceWarning); - droppedSinceWarning = 0; - lastWarning = now; - } - } - } - for (auto& job : jobs) { - g_presenter.jobs.emplace_back(std::move(job)); - } - lock.unlock(); - g_presenter.cv.notify_all(); -} - -void stop_presenter() noexcept { - if (!g_presenterStarted.load(std::memory_order_acquire)) { - return; - } - { - std::lock_guard lock(g_presenter.mutex); - g_presenter.stop = true; - } - g_presenter.cv.notify_all(); - if (g_presenter.thread.joinable()) { - g_presenter.thread.join(); - } - { - std::lock_guard lock(g_presenter.mutex); - g_presenter.jobs.clear(); - g_presenter.started = false; - g_presenter.presenting = false; - } - g_presenterStarted.store(false, std::memory_order_release); -} - -struct MetalFXSlot { - webgpu::metalfx::Size size{}; - std::unique_ptr scaler; - wgpu::BindGroup bindGroup; -}; -std::array g_metalfxSlots; -size_t g_metalfxNextSlot = 0; -webgpu::metalfx::SpatialScaler* g_metalfxPendingOutput = nullptr; -bool g_metalfxFailed = false; - -void metalfx_failed(const std::string& reason) { - Log.warn("MetalFX spatial upscaling disabled: {}; using normal presentation", reason); - g_metalfxFailed = true; - g_metalfxStatus.store(AURORA_METALFX_ERROR); - g_metalfxPendingOutput = nullptr; - g_metalfxSlots = {}; -} - -wgpu::BindGroup upscale_presentation(wgpu::CommandEncoder& encoder, - const webgpu::PresentSource& source, - const webgpu::Viewport& viewport, bool enabled) { - if (!enabled) { - g_metalfxSlots = {}; - g_metalfxFailed = false; - g_metalfxStatus.store(AURORA_METALFX_DISABLED); - return {}; - } - if (!g_metalfxSupported.load()) { - g_metalfxStatus.store(AURORA_METALFX_UNSUPPORTED); - return {}; - } - if (g_metalfxFailed) return {}; - const webgpu::metalfx::Size size{ - source.size.width, source.size.height, - static_cast(viewport.width), static_cast(viewport.height), - webgpu::g_graphicsConfig.surfaceConfiguration.format, - }; - // The existing copy path samples perceptual values from unorm game images. - // Do not introduce implicit sRGB decoding or downscaling into MetalFX. - if (!size.inputWidth || !size.inputHeight || size.inputWidth >= size.outputWidth || - size.inputHeight >= size.outputHeight || - (source.format != wgpu::TextureFormat::RGBA8Unorm && source.format != wgpu::TextureFormat::BGRA8Unorm)) { - g_metalfxStatus.store(AURORA_METALFX_NOT_UPSCALING); - return {}; - } - auto& slot = g_metalfxSlots[g_metalfxNextSlot++ % g_metalfxSlots.size()]; - if (!slot.scaler || !(slot.size == size)) { - slot = {}; - std::string error; - slot.scaler = webgpu::metalfx::create(g_instance, g_device, size, error); - if (!slot.scaler) { - if (error.empty()) g_metalfxStatus.store(AURORA_METALFX_NOT_UPSCALING); - else metalfx_failed(error); - return {}; - } - slot.size = size; - wgpu::SamplerDescriptor samplerDescriptor{}; - samplerDescriptor.magFilter = wgpu::FilterMode::Linear; - samplerDescriptor.minFilter = wgpu::FilterMode::Linear; - slot.bindGroup = webgpu::create_copy_bind_group(slot.scaler->output_view(), - g_device.CreateSampler(&samplerDescriptor)); - Log.info("MetalFX spatial slot: {}x{} -> {}x{}", size.inputWidth, size.inputHeight, - size.outputWidth, size.outputHeight); - } - if (!slot.scaler->begin_input()) { - metalfx_failed(slot.scaler->error()); - return {}; - } - const wgpu::RenderPassColorAttachment attachment{ - .view = slot.scaler->input_view(), - .loadOp = wgpu::LoadOp::Clear, - .storeOp = wgpu::StoreOp::Store, - }; - const wgpu::RenderPassDescriptor descriptor{ - .label = "MetalFX input copy", - .colorAttachmentCount = 1, - .colorAttachments = &attachment, - }; - auto pass = encoder.BeginRenderPass(&descriptor); - pass.SetPipeline(webgpu::g_CopyPipeline); - pass.SetBindGroup(0, source.bindGroup); - pass.SetViewport(0, 0, static_cast(size.inputWidth), static_cast(size.inputHeight), 0, 1); - pass.Draw(3); - pass.End(); - // Submit the sealed scene and input copy before crossing to the native queue. - // The replacement encoder composites the upscaled image and ImGui normally. - auto buffer = encoder.Finish(); - { - std::lock_guard submitLock(g_queueSubmitMutex); - g_queue.Submit(1, &buffer); - } - encoder = g_device.CreateCommandEncoder(); - if (!slot.scaler->upscale()) { - metalfx_failed(slot.scaler->error()); - return {}; - } - g_metalfxPendingOutput = slot.scaler.get(); - g_metalfxStatus.store(AURORA_METALFX_ACTIVE); - return slot.bindGroup; -} - -// `presentSource` is latched in the seal prologue: by the time this encodes, the producer's next -// gfx::begin_frame() may already have cleared the display-copy override. -wgpu::BindGroup encode_presentation_snapshot(wgpu::CommandEncoder& encoder, - const webgpu::PresentSource& presentSource, - const PresentationImage& image, - bool includeImGui, bool metalfxEnabled, - const wgpu::BindGroup* cachedMetalFXOutput = nullptr) { - ZoneScoped; - auto viewport = webgpu::calculate_present_viewport( - image.texture.size.width, image.texture.size.height, presentSource.size.width, - presentSource.size.height); - float presentAspect = 0.f; - if (window::get_present_aspect_ratio(presentAspect)) { - viewport = webgpu::calculate_present_viewport_for_aspect( - image.texture.size.width, image.texture.size.height, presentAspect); - } - wgpu::BindGroup presentBindGroup = presentSource.bindGroup; - wgpu::BindGroup newMetalFXOutput; - if (cachedMetalFXOutput && *cachedMetalFXOutput) { - presentBindGroup = *cachedMetalFXOutput; - } else if (auto upscaled = upscale_presentation(encoder, presentSource, viewport, metalfxEnabled)) { - presentBindGroup = std::move(upscaled); - newMetalFXOutput = presentBindGroup; - } - { - const std::array attachments{ - wgpu::RenderPassColorAttachment{ - .view = image.texture.view, - .loadOp = wgpu::LoadOp::Clear, - .storeOp = wgpu::StoreOp::Store, - }, - }; - const wgpu::RenderPassDescriptor renderPassDescriptor{ - .label = "Interpolation snapshot pass", - .colorAttachmentCount = attachments.size(), - .colorAttachments = attachments.data(), - }; - const auto pass = encoder.BeginRenderPass(&renderPassDescriptor); - pass.SetPipeline(webgpu::g_CopyPipeline); - pass.SetBindGroup(0, presentBindGroup, 0, nullptr); - pass.SetViewport(viewport.left, viewport.top, viewport.width, viewport.height, - viewport.znear, viewport.zfar); - pass.Draw(3); - pass.End(); - } - if (includeImGui) { - const std::array attachments{ - wgpu::RenderPassColorAttachment{ - .view = image.texture.view, - .loadOp = wgpu::LoadOp::Load, - .storeOp = wgpu::StoreOp::Store, - }, - }; - const wgpu::RenderPassDescriptor renderPassDescriptor{ - .label = "Snapshot ImGui pass", - .colorAttachmentCount = attachments.size(), - .colorAttachments = attachments.data(), - }; - const auto pass = encoder.BeginRenderPass(&renderPassDescriptor); - pass.SetViewport(0.f, 0.f, static_cast(image.texture.size.width), - static_cast(image.texture.size.height), 0.f, 1.f); - imgui::render(pass); - pass.End(); - } - return newMetalFXOutput; -} -#endif - -void shutdown() noexcept { - stop_frame_worker(); -#ifdef AURORA_ENABLE_GX - stop_presenter(); - g_presentationImagePools = {}; - g_metalfxSlots = {}; - g_metalfxPendingOutput = nullptr; - g_metalfxNextSlot = 0; - g_metalfxFailed = false; - g_metalfxRequested.store(false); - g_metalfxSupported.store(false); - g_metalfxStatus.store(AURORA_METALFX_DISABLED); - imgui::shutdown(); - gfx::shutdown(); - webgpu::shutdown(); -#endif - input::shutdown(); - window::shutdown(); -} - -const AuroraEvent* update() noexcept { - ZoneScoped; - if (g_initialFrame) { - g_initialFrame = false; - input::initialize(); - } - return window::poll_events(); -} - -bool begin_frame_impl(bool pumpEvents, ImGuiFramePolicy imguiPolicy, bool* imguiNewFrameOwed) noexcept { - ZoneScoped; -#ifdef AURORA_ENABLE_GX - webgpu::fail_if_device_lost(); - if (pumpEvents) { - window::pump_events(); - } - const bool surfaceReconfigurePending = - g_surfaceReconfigurePending.load(std::memory_order_acquire); - const bool surfaceMutationRequired = - surfaceReconfigurePending || !window::is_presentable() || !g_surface || - window::native_resize_pending() || - !window::native_window_size_matches( - webgpu::g_graphicsConfig.surfaceConfiguration.width, - webgpu::g_graphicsConfig.surfaceConfiguration.height); - if (surfaceMutationRequired) { - wait_for_presenter_idle(); - window::SurfaceLock surfaceLock; - // Reconfiguring invalidates any image the presenter holds, so take the surface exclusively; a - // drained queue does not stop a later job. Order is surface before renderer everywhere. - std::lock_guard surfaceOwnership(g_surfaceMutex); - std::lock_guard gpuLock(g_rendererGpuMutex); - // Surface configuration belongs to the render thread; the SDL thread must not reconfigure Dawn - // while this worker is acquiring or presenting. - if (!window::is_presentable()) { - webgpu::release_surface(); - return false; - } - if (window::is_paused()) { - return false; - } - const bool consumeSurfaceReconfigure = - g_surfaceReconfigurePending.exchange(false, std::memory_order_acq_rel); - const bool consumeSurfaceRecreate = - g_surfaceRecreatePending.exchange(false, std::memory_order_acq_rel); - if (!g_surface || consumeSurfaceReconfigure) { - // Reconfigure in place unless the surface was actually lost. See - // g_surfaceRecreatePending for why destroying a live surface here is fatal - // while a capture overlay is attached. - webgpu::refresh_surface(consumeSurfaceRecreate); - if (!g_surface) { - return false; - } - } - if (window::native_resize_pending() || - !window::native_window_size_matches(webgpu::g_graphicsConfig.surfaceConfiguration.width, - webgpu::g_graphicsConfig.surfaceConfiguration.height)) { - window::sync_frame_buffer_size(); - } - } else if (window::is_paused()) { - return false; - } - - return begin_frame_render_state_impl(imguiPolicy, imguiNewFrameOwed); -#else - (void)imguiPolicy; - (void)imguiNewFrameOwed; - return true; -#endif -} - -bool begin_frame_render_state_impl(ImGuiFramePolicy imguiPolicy, bool* imguiNewFrameOwed) noexcept { -#ifdef AURORA_ENABLE_GX - std::lock_guard gpuLock(g_rendererGpuMutex); - // Note the debt before gfx::begin_frame() can fail: the synchronous path always started the - // ImGui frame here, and the runtime's retry loop depends on that pairing. - if (imguiPolicy == ImGuiFramePolicy::Immediate) { - imgui::new_frame(window::get_window_size()); - } else if (imguiNewFrameOwed != nullptr) { - *imguiNewFrameOwed = true; - } - if (!gfx::begin_frame()) { - return false; - } -#else - (void)imguiPolicy; - (void)imguiNewFrameOwed; -#endif - return true; -} - -#ifdef AURORA_ENABLE_GX -// Everything the mutex-free encode phase needs, latched while the renderer GPU mutex is held. -// None of it may be re-read from a global later; the producer has already begun the next frame. -struct SealedFrameContext { - wgpu::CommandEncoder encoder; // slot 0's encoder; already holds the staging copies - webgpu::PresentSource presentSource{}; - uint64_t scheduleBaseNanos = 0; - uint64_t scheduleIntervalNanos = 0; - uint32_t interpolatedFrameCount = 0; - uint32_t snapshotWidth = 1; - uint32_t snapshotHeight = 1; - uint32_t logicalFrame = 0; - bool interpolationActive = false; - bool replayInterpolatedFrames = false; - bool metalfxEnabled = false; -}; - -// Phase 1: everything that touches producer-shared renderer state. Needs g_rendererGpuMutex and -// a FIFO already drained into the recorded pass list. -void seal_frame_locked(gfx::SealedFrame& sealedFrame, SealedFrameContext& ctx) { - ZoneScopedN("Seal frame"); - const auto encoderDescriptor = wgpu::CommandEncoderDescriptor{ - .label = "Redraw encoder", - }; - ctx.encoder = g_device.CreateCommandEncoder(&encoderDescriptor); - // Probe-sized CPU-consumed copies read back asynchronously. Their downscale blits push uniforms, - // so prepare them while the producer's staging buffers are still mapped. - gfx::efb_ram::seal_async_downloads(); - gfx::end_frame(ctx.encoder); - gfx::g_stats.presentedFrameCount = 0; - gfx::g_stats.interpolatedFrameCount = 0; - // Latched before the producer's next gfx::begin_frame() calls - // gx::begin_frame_interpolation(), which resets both of these. - ctx.interpolatedFrameCount = gx::interpolated_frame_count(); - ctx.interpolationActive = ctx.interpolatedFrameCount != 0; - ctx.replayInterpolatedFrames = ctx.interpolationActive && gx::frame_interpolation_replay_safe(); - ctx.scheduleBaseNanos = g_presentScheduleBaseNanos.load(std::memory_order_acquire); - ctx.scheduleIntervalNanos = g_presentScheduleIntervalNanos.load(std::memory_order_acquire); - const auto windowSize = window::get_window_size(); - ctx.snapshotWidth = (std::max)(windowSize.native_fb_width, 1u); - ctx.snapshotHeight = (std::max)(windowSize.native_fb_height, 1u); - ctx.logicalFrame = gfx::current_frame(); - ctx.metalfxEnabled = g_metalfxRequested.load(); - // Latched before webgpu::clear_present_source_override() in the producer's - // next gfx::begin_frame(). - ctx.presentSource = webgpu::current_present_source(); - // ImGui draw lists are built once per frame and replayed by each slot's ImGui pass, which is why - // the next ImGui frame cannot start until the encode phase is done. - imgui::render_frame_data(); - // Drop the sealed frame's lazy RAM-readback requests while the producer is still excluded; it - // starts registering the next frame's as soon as SEALED is published. - gfx::efb_ram::cancel(); - // Detach the recorded passes. From here the producer's list is empty and the - // encode phase reads only worker-private state. - gfx::seal_frame(sealedFrame); - gfx::expire_bind_group_cache(); -} - -// Phase 2: encode every presentation slot. Reads only `ctx` and the sealed passes, so it runs -// without the renderer GPU mutex while the producer records the next frame. -std::vector encode_sealed_frame(gfx::SealedFrame& sealedFrame, SealedFrameContext& ctx) { - ZoneScopedN("Encode sealed frame"); - auto encoder = std::move(ctx.encoder); - const auto encoderDescriptor = wgpu::CommandEncoderDescriptor{ - .label = "Redraw encoder", - }; - // Absolute slot deadlines: slot k of jobCount presents at base + k * interval / jobCount. With - // interpolation off, pace to the boundary that just passed plus 6.5 ms; late frames free-run. - constexpr uint64_t kNativePresentOffsetNanos = 6'500'000; - const uint32_t presentationJobCount = ctx.interpolatedFrameCount + 1; - const auto slotPresentDeadline = [&](uint32_t slot) -> PresentClock::time_point { - if (ctx.scheduleBaseNanos == 0 || ctx.scheduleIntervalNanos == 0) { - return {}; - } - if (!ctx.interpolationActive) { - return PresentClock::time_point{std::chrono::nanoseconds{ - ctx.scheduleBaseNanos - ctx.scheduleIntervalNanos + kNativePresentOffsetNanos}}; - } - const uint64_t offsetNanos = - (ctx.scheduleIntervalNanos * static_cast(slot)) / presentationJobCount; - return PresentClock::time_point{std::chrono::nanoseconds{ctx.scheduleBaseNanos + offsetNanos}}; - }; - std::vector presentationJobs; - presentationJobs.reserve(presentationJobCount); - - // Each slot is submitted as soon as it is encoded, so the GPU starts slot 0 while slot 1 is still - // recording. Queue order preserves the ordering the single batched buffer gave. - const wgpu::CommandBufferDescriptor cmdBufDescriptor{ - .label = "Presentation slot command buffer", - }; - const auto submitEncodedSlot = [&](wgpu::CommandEncoder& target, bool releaseMetalFXOutput = true) { - const auto buffer = target.Finish(&cmdBufDescriptor); - std::lock_guard submitLock(g_queueSubmitMutex); - g_queue.Submit(1, &buffer); - if (releaseMetalFXOutput && g_metalfxPendingOutput) { - if (!g_metalfxPendingOutput->end_output()) metalfx_failed(g_metalfxPendingOutput->error()); - g_metalfxPendingOutput = nullptr; - } - }; - - if (ctx.replayInterpolatedFrames) { - for (uint32_t interpolatedFrame = 0; interpolatedFrame < ctx.interpolatedFrameCount; - ++interpolatedFrame) { - gfx::render(sealedFrame, encoder, static_cast(interpolatedFrame), false); - auto image = - acquire_presentation_image(interpolatedFrame, ctx.snapshotWidth, ctx.snapshotHeight); - encode_presentation_snapshot(encoder, ctx.presentSource, *image, true, ctx.metalfxEnabled); - presentationJobs.push_back({ - .image = std::move(image), - .logicalFrame = ctx.logicalFrame, - .presentAt = slotPresentDeadline(interpolatedFrame), - .interpolated = true, - }); - submitEncodedSlot(encoder); - encoder = g_device.CreateCommandEncoder(&encoderDescriptor); - } - } - - // A demanded CPU-visible EFB readback submits a prefix of the frame, so replaying the resumed - // stream would mutate an already-rendered EFB. Render once, then duplicate into the slots. - gfx::render(sealedFrame, encoder, -1, true); - // The copy targets now hold this frame's resolves, so queue their readbacks on the same encoder; - // completion is harvested in gfx::after_submit, never waited on here. - gfx::efb_ram::encode_async_downloads(encoder); - wgpu::BindGroup duplicatedMetalFXOutput; - if (!ctx.replayInterpolatedFrames) { - for (uint32_t interpolatedFrame = 0; interpolatedFrame < ctx.interpolatedFrameCount; - ++interpolatedFrame) { - auto image = - acquire_presentation_image(interpolatedFrame, ctx.snapshotWidth, ctx.snapshotHeight); - const auto newMetalFXOutput = encode_presentation_snapshot( - encoder, ctx.presentSource, *image, true, ctx.metalfxEnabled, - duplicatedMetalFXOutput ? &duplicatedMetalFXOutput : nullptr); - if (!duplicatedMetalFXOutput && newMetalFXOutput) { - duplicatedMetalFXOutput = newMetalFXOutput; - } - presentationJobs.push_back({ - .image = std::move(image), - .logicalFrame = ctx.logicalFrame, - .presentAt = slotPresentDeadline(interpolatedFrame), - .interpolated = true, - .duplicated = true, - }); - submitEncodedSlot(encoder, false); - encoder = g_device.CreateCommandEncoder(&encoderDescriptor); - } - } - auto finalImage = - acquire_presentation_image(ctx.interpolatedFrameCount, ctx.snapshotWidth, ctx.snapshotHeight); - encode_presentation_snapshot(encoder, ctx.presentSource, *finalImage, true, ctx.metalfxEnabled, - duplicatedMetalFXOutput ? &duplicatedMetalFXOutput : nullptr); - auto pendingFrameCapture = encode_frame_capture(encoder, ctx.presentSource); - presentationJobs.push_back({ - .image = std::move(finalImage), - .logicalFrame = ctx.logicalFrame, - .presentAt = slotPresentDeadline(ctx.interpolatedFrameCount), - .interpolated = false, - }); - submitEncodedSlot(encoder); - - // A group that finished encoding past its anchor slides forward by whole display periods, never - // per slot. The cursor keeps two groups off one anchor, which bursts then holds for a period. - static PresentClock::time_point s_lastGroupAnchor{}; - if (ctx.interpolationActive && ctx.scheduleIntervalNanos != 0 && !presentationJobs.empty() && - presentationJobs.front().presentAt != PresentClock::time_point{}) { - const std::chrono::nanoseconds interval{static_cast(ctx.scheduleIntervalNanos)}; - auto anchor = presentationJobs.front().presentAt; - const auto now = PresentClock::now(); - if (now > anchor) { - const auto behind = std::chrono::duration_cast(now - anchor); - const uint64_t periods = - static_cast(behind.count()) / ctx.scheduleIntervalNanos + 1u; - anchor += std::chrono::nanoseconds{static_cast(periods * ctx.scheduleIntervalNanos)}; - } - if (s_lastGroupAnchor != PresentClock::time_point{} && anchor <= s_lastGroupAnchor) { - anchor = s_lastGroupAnchor + interval; - } - const auto shift = - std::chrono::duration_cast(anchor - presentationJobs.front().presentAt); - if (shift.count() > 0) { - const uint32_t slidPeriods = static_cast( - (static_cast(shift.count()) + ctx.scheduleIntervalNanos - 1u) / - ctx.scheduleIntervalNanos); - for (auto& job : presentationJobs) { - job.presentAt += shift; - job.slidPeriods = slidPeriods; - } - } - s_lastGroupAnchor = anchor; - } else { - // No schedule (interpolation off, boot/black presents): the grid is gone, - // so the cursor must not constrain the next scheduled group. - s_lastGroupAnchor = {}; - } - - if (pendingFrameCapture.has_value()) { - complete_frame_capture(*pendingFrameCapture); - } - gfx::after_submit(); - gfx::g_stats.presentedFrameCount = static_cast(presentationJobs.size()); - gfx::g_stats.interpolatedFrameCount = ctx.interpolatedFrameCount; - return presentationJobs; -} - -// Phase 3: hand the encoded group to whoever owns presentation. -void publish_presentations(std::vector&& presentationJobs, bool interpolationActive) { -#if defined(__APPLE__) - (void)interpolationActive; - // Presenting reaches SDL/AppKit, whose window operations must stay on the - // main thread. Interpolation normally starts the presenter worker, so keep - // its jobs synchronous on Apple platforms. - for (const auto& job : presentationJobs) { - present_presentation_job(job); - } -#else - // Keep presentation on the presenter whenever the async frame worker runs, even with - // interpolation off, so every mode shares one surface/resize path. RenderDoc keeps the sync path. - if (frame_worker_requested() || interpolationActive || - g_presenterStarted.load(std::memory_order_acquire)) { - enqueue_presentations(std::move(presentationJobs)); - } else { - for (const auto& job : presentationJobs) { - present_presentation_job(job); - } - } -#endif -} - -void record_frame_telemetry() { - TracyPlotConfig("aurora: lastVertSize", tracy::PlotFormatType::Memory, false, true, 0); - TracyPlotConfig("aurora: lastUniformSize", tracy::PlotFormatType::Memory, false, true, 0); - TracyPlotConfig("aurora: lastIndexSize", tracy::PlotFormatType::Memory, false, true, 0); - TracyPlotConfig("aurora: lastStorageSize", tracy::PlotFormatType::Memory, false, true, 0); - TracyPlotConfig("aurora: lastTextureUploadSize", tracy::PlotFormatType::Memory, false, true, 0); - - TracyPlot("aurora: queuedPipelines", static_cast(gfx::g_stats.queuedPipelines)); - TracyPlot("aurora: createdPipelines", static_cast(gfx::g_stats.createdPipelines)); - TracyPlot("aurora: drawCallCount", static_cast(gfx::g_stats.drawCallCount)); - TracyPlot("aurora: mergedDrawCallCount", static_cast(gfx::g_stats.mergedDrawCallCount)); - TracyPlot("aurora: lastVertSize", static_cast(gfx::g_stats.lastVertSize)); - TracyPlot("aurora: lastUniformSize", static_cast(gfx::g_stats.lastUniformSize)); - TracyPlot("aurora: lastIndexSize", static_cast(gfx::g_stats.lastIndexSize)); - TracyPlot("aurora: lastStorageSize", static_cast(gfx::g_stats.lastStorageSize)); - TracyPlot("aurora: lastTextureUploadSize", static_cast(gfx::g_stats.lastTextureUploadSize)); - TracyPlot("aurora: frameIndex", static_cast(gfx::current_frame())); -#if defined(TRACY_ENABLE) && defined(_WIN32) - const auto fileTimeValue = [](const FILETIME& value) noexcept { - ULARGE_INTEGER result{}; - result.LowPart = value.dwLowDateTime; - result.HighPart = value.dwHighDateTime; - return result.QuadPart; - }; - FILETIME creation{}, exit{}, processKernel{}, processUser{}, threadKernel{}, threadUser{}; - const bool processTimesAvailable = - GetProcessTimes(GetCurrentProcess(), &creation, &exit, &processKernel, &processUser) != FALSE; - const bool threadTimesAvailable = - GetThreadTimes(GetCurrentThread(), &creation, &exit, &threadKernel, &threadUser) != FALSE; - const uint64_t processCpu100ns = - processTimesAvailable ? fileTimeValue(processKernel) + fileTimeValue(processUser) : 0; - const uint64_t threadCpu100ns = - threadTimesAvailable ? fileTimeValue(threadKernel) + fileTimeValue(threadUser) : 0; - static uint64_t previousProcessCpu100ns = processCpu100ns; - static uint64_t previousThreadCpu100ns = threadCpu100ns; - TracyPlot("aurora: processCpuUsPerFrame", - static_cast((processCpu100ns - previousProcessCpu100ns) / 10)); - TracyPlot("aurora: mainThreadCpuUsPerFrame", - static_cast((threadCpu100ns - previousThreadCpu100ns) / 10)); - previousProcessCpu100ns = processCpu100ns; - previousThreadCpu100ns = threadCpu100ns; -#endif - FrameMarkNamed("Aurora frame"); -} - -// One complete frame-worker cycle. The scene encode only leaves the renderer mutex when -// interpolation actually inserts slots; otherwise both phases publish together. -bool run_frame_worker_cycle(gfx::SealedFrame& sealedFrame) noexcept { - ZoneScopedN("Frame worker cycle"); - webgpu::fail_if_device_lost(); - SealedFrameContext ctx; - std::vector presentationJobs; - bool overlapEncode = false; - { - std::lock_guard gpuLock(g_rendererGpuMutex); - seal_frame_locked(sealedFrame, ctx); - overlapEncode = ctx.interpolationActive; - if (!overlapEncode) { - presentationJobs = encode_sealed_frame(sealedFrame, ctx); - } - } - if (!overlapEncode) { - publish_presentations(std::move(presentationJobs), ctx.interpolationActive); - } - - { - std::unique_lock lock(g_frameWorker.mutex); - g_frameWorker.cv.wait(lock, [] { return g_frameWorker.stop || g_frameWorker.prepareAllowed; }); - if (g_frameWorker.stop) { - return false; - } - g_frameWorker.prepareAllowed = false; - } - - // Preparing the next frame belongs to the SEALED phase: without a fresh pass 0 and mapped - // staging buffers the producer's drain has nowhere to put its commands. - bool imguiNewFrameOwed = false; - const bool prepared = begin_frame_impl( - false, overlapEncode ? ImGuiFramePolicy::Deferred : ImGuiFramePolicy::Immediate, - &imguiNewFrameOwed); - - { - std::lock_guard lock(g_frameWorker.mutex); - g_frameWorker.framePrepared = prepared; - g_frameWorker.sealed.store(true, std::memory_order_release); - if (!overlapEncode) { - g_frameWorker.ready.store(true, std::memory_order_release); - } - } - g_frameWorker.cv.notify_all(); - - if (overlapEncode) { - // Mutex-free: the producer drains and records the next frame in parallel, taking the renderer - // mutex per drain, and this phase never takes it. - presentationJobs = encode_sealed_frame(sealedFrame, ctx); - publish_presentations(std::move(presentationJobs), ctx.interpolationActive); - if (imguiNewFrameOwed) { - // Safe only now: every slot has replayed this frame's ImGui draw lists. - std::lock_guard gpuLock(g_rendererGpuMutex); - imgui::new_frame(window::get_window_size()); - } - { - std::lock_guard lock(g_frameWorker.mutex); - g_frameWorker.ready.store(true, std::memory_order_release); - } - g_frameWorker.cv.notify_all(); - } - - record_frame_telemetry(); - return true; -} -#endif - -// Synchronous frame submission: seal, encode and present inline on the calling thread. Used when -// the frame worker is disabled (RenderDoc captures) and on the boot path. -void end_frame_impl(bool pumpEvents, bool drainFifo) { - ZoneScoped; -#ifdef AURORA_ENABLE_GX - webgpu::fail_if_device_lost(); - if (pumpEvents) { - window::pump_events(); - } - gfx::SealedFrame sealedFrame; - SealedFrameContext ctx; - std::vector presentationJobs; - if (drainFifo) gx::fifo::drain(); - { - std::lock_guard gpuLock(g_rendererGpuMutex); - seal_frame_locked(sealedFrame, ctx); - presentationJobs = encode_sealed_frame(sealedFrame, ctx); - } - publish_presentations(std::move(presentationJobs), ctx.interpolationActive); - record_frame_telemetry(); -#else - (void)pumpEvents; - (void)drainFifo; -#endif -} - -bool begin_frame() noexcept { -#ifdef AURORA_ENABLE_GX - // The asynchronous fast path below can return a logically prepared frame - // without entering begin_frame_impl(), so loss must be checked before it. - webgpu::fail_if_device_lost(); -#endif - if (!frame_worker_requested()) { - return begin_frame_impl(true); - } - - ensure_frame_worker_started(); - // SDL needs event pumping on the window-owning producer thread, and the worker passes - // pumpEvents=false, so keep it here even when the fast path returns early. - window::pump_events(); - bool waitForSurfacePreparation = false; -#ifdef AURORA_ENABLE_GX - // A surface mutation can legitimately fail preparation, and optimistic success would let GX/ImGui - // record into a frame that was never begun, so join this path and return its real result. - waitForSurfacePreparation = - !window::is_presentable() || !g_surface || - window::native_resize_pending() || window::is_paused() || - !window::native_window_size_matches( - webgpu::g_graphicsConfig.surfaceConfiguration.width, - webgpu::g_graphicsConfig.surfaceConfiguration.height); -#endif - bool workerPreparationPending = false; - { - std::lock_guard lock(g_frameWorker.mutex); - // The runtime begins right after an asynchronous end, so treat the worker's pending begin as an - // active frame unless a resize needs the real preparation result. - if (!g_frameWorker.ready.load(std::memory_order_acquire)) { - g_frameWorker.prepareAllowed = true; - g_frameWorker.cv.notify_one(); - if (!waitForSurfacePreparation) { - return true; - } - workerPreparationPending = true; - } else if (g_frameWorker.framePrepared) { - return true; - } - } - - if (workerPreparationPending) { - // DONE, not SEALED: this only runs while the window is changing and the caller is about to act on - // the surface, so keep the resize path fully serialized. - wait_for_frame_worker_private(FrameWorkerPhase::Done); - std::lock_guard lock(g_frameWorker.mutex); - return g_frameWorker.framePrepared; - } - - { - std::lock_guard lock(g_frameWorker.mutex); - if (g_frameWorker.framePrepared) { - return true; - } - } - - const bool prepared = begin_frame_impl(false); - { - std::lock_guard lock(g_frameWorker.mutex); - g_frameWorker.framePrepared = prepared; - } - return prepared; -} - -void end_frame() { -#ifdef AURORA_ENABLE_GX - webgpu::fail_if_device_lost(); -#endif - if (!frame_worker_requested()) { - end_frame_impl(true, true); - return; - } - - ensure_frame_worker_started(); - // DONE: this seals another frame, which means reusing the worker's encoder - // state and its SealedFrame. The previous cycle must be completely finished. - wait_for_frame_worker_private(FrameWorkerPhase::Done); - - // Seal all current GX work on the CPU while the renderer is known ready. - // Later FIFO writes belong exclusively to the next frame. - gx::fifo::drain(); - { - std::lock_guard lock(g_frameWorker.mutex); - g_frameWorker.framePrepared = false; - g_frameWorker.sealed.store(false, std::memory_order_release); - g_frameWorker.ready.store(false, std::memory_order_release); - g_frameWorker.jobPending = true; - g_frameWorker.prepareAllowed = false; - } - g_frameWorker.cv.notify_one(); -} -} // namespace - -void wait_for_frame_worker() noexcept { wait_for_frame_worker_private(FrameWorkerPhase::Done); } -std::chrono::nanoseconds wait_for_frame_worker_sealed() noexcept { - if (g_frameWorker.sealed.load(std::memory_order_acquire)) { - return std::chrono::nanoseconds::zero(); - } - const auto started = std::chrono::steady_clock::now(); - wait_for_frame_worker_private(FrameWorkerPhase::Sealed); - return std::chrono::duration_cast(std::chrono::steady_clock::now() - started); -} -bool wait_for_frame_worker_for(std::chrono::microseconds timeout) noexcept { - return wait_for_frame_worker_private_for(FrameWorkerPhase::Done, timeout); -} -std::recursive_mutex& renderer_gpu_mutex() noexcept { return g_rendererGpuMutex; } -void submit_staging_commands(const wgpu::CommandBuffer& commands) { - std::lock_guard submitLock(g_queueSubmitMutex); - webgpu::g_queue.Submit(1, &commands); -} -} // namespace aurora - -// C API bindings -AuroraInfo aurora_initialize(int argc, char* argv[], const AuroraConfig* config) { - return aurora::initialize(argc, argv, *config); -} -void aurora_shutdown() { aurora::shutdown(); } -const AuroraEvent* aurora_update() { return aurora::update(); } -bool aurora_begin_frame() { return aurora::begin_frame(); } -void aurora_end_frame() { aurora::end_frame(); } -void aurora_set_frame_worker_wait_callback(AuroraFrameWorkerWaitCallback callback) { - aurora::g_frameWorkerWaitCallback.store(callback, std::memory_order_release); -} -void aurora_wait_for_frame_worker() { aurora::wait_for_frame_worker(); } -bool aurora_wait_for_frame_worker_for(uint32_t timeoutMicros) { - return aurora::wait_for_frame_worker_for(std::chrono::microseconds(timeoutMicros)); -} -void aurora_set_present_schedule(uint64_t baseNanos, uint64_t intervalNanos) { - aurora::g_presentScheduleBaseNanos.store(baseNanos, std::memory_order_release); - aurora::g_presentScheduleIntervalNanos.store(intervalNanos, std::memory_order_release); -} -void aurora_report_producer_paced(bool paced) { -#ifdef AURORA_ENABLE_GX - aurora::gx::report_producer_paced(paced); -#else - (void)paced; -#endif -} -void aurora_get_frame_interpolation_diagnostics(AuroraFrameInterpolationDiagnostics* diagnostics) { - if (diagnostics != nullptr) { - aurora::gx::get_frame_interpolation_diagnostics(*diagnostics); - } -} - -void aurora_get_present_timing(AuroraPresentTiming* timing) { - if (timing != nullptr) { - *timing = aurora::snapshot_present_timing(); - } -} -void aurora_set_frame_interpolation_fps(uint32_t targetFps) { -#ifdef AURORA_ENABLE_GX - aurora::gx::set_frame_interpolation_fps(targetFps); -#else - (void)targetFps; -#endif -} -uint32_t aurora_get_frame_interpolation_fps() { -#ifdef AURORA_ENABLE_GX - return aurora::gx::frame_interpolation_fps(); -#else - return 0; -#endif -} -void aurora_request_frame_capture(uint32_t frame, const char* outputPath) { - aurora::g_captureOutputPath = outputPath != nullptr ? outputPath : "frame_capture.bmp"; - aurora::g_captureFrame.store(frame, std::memory_order_release); -} -bool aurora_flush_efb_copies_to_ram() { -#ifdef AURORA_ENABLE_GX - if (!aurora::gfx::efb_ram::has_pending()) { - return true; - } - // This finalizes the frame still being recorded, on the producer thread, so join the whole cycle - // first: the encode phase owns the previous passes, EFB targets and image pool. - aurora::wait_for_frame_worker(); - // The renderer is about to submit a prefix of the active frame. Its resumed - // suffix cannot safely be replayed against the same mutable EFB resources. - aurora::gx::mark_frame_interpolation_replay_unsafe(); - aurora::gx::fifo::drain(); - if (!aurora::gfx::efb_ram::prepare_downloads()) return false; - const wgpu::CommandEncoderDescriptor encoderDescriptor{ - .label = "GX CPU-visible EFB copy encoder", - }; - auto encoder = aurora::webgpu::g_device.CreateCommandEncoder(&encoderDescriptor); - aurora::gfx::end_batch(encoder); - aurora::gfx::render(encoder); - aurora::gfx::efb_ram::encode_downloads(encoder); - const wgpu::CommandBufferDescriptor commandDescriptor{ - .label = "GX CPU-visible EFB copy command buffer", - }; - const auto commandBuffer = encoder.Finish(&commandDescriptor); - { - std::lock_guard submitLock(aurora::g_queueSubmitMutex); - aurora::webgpu::g_queue.Submit(1, &commandBuffer); - } - const bool copied = aurora::gfx::efb_ram::complete_downloads(); - aurora::gfx::after_submit(); - const bool resumed = aurora::gfx::resume_frame(); - return copied && resumed; -#else - return true; -#endif -} -bool aurora_flush_efb_copy_to_ram(void* dest) { -#ifdef AURORA_ENABLE_GX - if (dest == nullptr || !aurora::gfx::efb_ram::has_pending(dest)) { - return false; - } - - // See aurora_flush_efb_copies_to_ram: this encodes the in-progress frame on - // the producer thread, so the worker's overlapped encode has to be finished. - aurora::wait_for_frame_worker(); - // Preserve the requested output cadence by duplicating the completed native - // image instead of replaying this split frame. - aurora::gx::mark_frame_interpolation_replay_unsafe(); - aurora::gx::fifo::drain(); - if (!aurora::gfx::efb_ram::prepare_downloads(dest)) return false; - const wgpu::CommandEncoderDescriptor encoderDescriptor{ - .label = "GX demanded EFB copy encoder", - }; - auto encoder = aurora::webgpu::g_device.CreateCommandEncoder(&encoderDescriptor); - aurora::gfx::end_batch(encoder); - aurora::gfx::render(encoder); - aurora::gfx::efb_ram::encode_downloads(encoder, dest); - const wgpu::CommandBufferDescriptor commandDescriptor{ - .label = "GX demanded EFB copy command buffer", - }; - const auto commandBuffer = encoder.Finish(&commandDescriptor); - { - std::lock_guard submitLock(aurora::g_queueSubmitMutex); - aurora::webgpu::g_queue.Submit(1, &commandBuffer); - } - const bool copied = aurora::gfx::efb_ram::complete_downloads(); - aurora::gfx::after_submit(); - const bool resumed = aurora::gfx::resume_frame(); - return copied && resumed; -#else - (void)dest; - return true; -#endif -} -AuroraBackend aurora_get_backend() { return aurora::g_config.desiredBackend; } -const AuroraBackend* aurora_get_available_backends(size_t* count) { - if (count != nullptr) { - *count = aurora::PreferredBackendOrder.size(); - } - return aurora::PreferredBackendOrder.data(); -} -void aurora_set_log_level(AuroraLogLevel level) { aurora::g_config.logLevel = level; } -void aurora_set_pause_on_focus_lost(bool value) { aurora::g_config.pauseOnFocusLost = value; } -void aurora_set_disable_copy_filter(bool disabled) { aurora::g_config.disableCopyFilter = disabled; } -bool aurora_get_disable_copy_filter() { return aurora::g_config.disableCopyFilter; } -void aurora_set_background_input(bool value) { - aurora::g_config.allowJoystickBackgroundEvents = value; - aurora::window::set_background_input(value); -} -void aurora_set_display_mode(AuroraDisplayMode mode) { aurora::window::set_display_mode(mode); } -AuroraDisplayMode aurora_get_display_mode() { return aurora::window::get_display_mode(); } -void aurora_set_metalfx_spatial(bool enabled) { aurora::g_metalfxRequested.store(enabled); } -bool aurora_get_metalfx_spatial() { return aurora::g_metalfxRequested.load(); } -bool aurora_is_metalfx_spatial_supported() { return aurora::g_metalfxSupported.load(); } -AuroraMetalFXStatus aurora_get_metalfx_status() { return aurora::g_metalfxStatus.load(); } diff --git a/aurora-main/lib/card/BlockAllocationTable.cpp b/aurora-main/lib/card/BlockAllocationTable.cpp deleted file mode 100644 index 95739bb..0000000 --- a/aurora-main/lib/card/BlockAllocationTable.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "BlockAllocationTable.hpp" - -#include -#include - -#include "../internal.hpp" -#include "Util.hpp" - -namespace aurora::card { -void BlockAllocationTable::swapEndian() { - m_checksum = bswap(m_checksum); - m_checksumInv = bswap(m_checksumInv); - m_updateCounter = bswap(m_updateCounter); - m_freeBlocks = bswap(m_freeBlocks); - m_lastAllocated = bswap(m_lastAllocated); - std::for_each(std::begin(m_map), std::end(m_map), [](uint16_t& val) { val = bswap(val); }); -} - -void BlockAllocationTable::updateChecksum() { - swapEndian(); - calculateChecksumBE(reinterpret_cast(raw.data() + 4), 0xFFE, &m_checksum, &m_checksumInv); - swapEndian(); -} - -bool BlockAllocationTable::valid() const { - uint16_t ckSum = 0; - uint16_t ckSumInv = 0; - const_cast(*this).swapEndian(); - calculateChecksumBE(reinterpret_cast(raw.data() + 4), 0xFFE, &ckSum, &ckSumInv); - bool res = ckSum == m_checksum && ckSumInv == m_checksumInv; - const_cast(*this).swapEndian(); - return res; -} - -BlockAllocationTable::BlockAllocationTable(uint32_t blockCount) -: m_checksum{0} -, m_checksumInv{0} -, m_updateCounter{0} -, m_freeBlocks{static_cast(blockCount - FSTBlocks)} -, m_lastAllocated{4} -, m_map{{}} { - updateChecksum(); -} - -uint16_t BlockAllocationTable::getNextBlock(uint16_t block) const { - if ((block < FSTBlocks) || (block > (BATSize - FSTBlocks))) - return 0xFFFF; - - return m_map[block - FSTBlocks]; -} - -uint16_t BlockAllocationTable::nextFreeBlock(uint16_t maxBlock, uint16_t startingBlock) const { - if (m_freeBlocks > 0) { - maxBlock = std::min(maxBlock, static_cast(BATSize)); - for (uint16_t i = startingBlock; i < maxBlock; ++i) - if (m_map[i - FSTBlocks] == 0) - return i; - - for (uint16_t i = FSTBlocks; i < startingBlock; ++i) - if (m_map[i - FSTBlocks] == 0) - return i; - } - - return 0xFFFF; -} - -bool BlockAllocationTable::clear(uint16_t first, uint16_t count) { - std::vector blocks; - while (first != 0xFFFF && first != 0) { - blocks.push_back(first); - first = getNextBlock(first); - } - if (first > 0) { - size_t length = blocks.size(); - if (length != count) - return false; - - for (size_t i = 0; i < length; ++i) - m_map[blocks.at(i) - FSTBlocks] = 0; - m_freeBlocks += count; - return true; - } - return false; -} - -uint16_t BlockAllocationTable::allocateBlocks(uint16_t count, uint16_t maxBlocks) { - uint16_t firstBlock = nextFreeBlock(maxBlocks - FSTBlocks, m_lastAllocated + 1); - uint16_t freeBlock = firstBlock; - if (freeBlock != 0xFFFF) { - uint16_t tmpCount = count; - while ((count--) > 0 && freeBlock != 0xFFFF) { - m_map[(freeBlock - FSTBlocks)] = 0xFFFF; - if (count != 0) { - m_map[(freeBlock - FSTBlocks)] = nextFreeBlock(maxBlocks - FSTBlocks, freeBlock + 1); - freeBlock = m_map[(freeBlock - FSTBlocks)]; - } - } - if (freeBlock == 0xFFFF) - return 0xFFFF; - - m_lastAllocated = freeBlock; - m_freeBlocks -= tmpCount; - } - return firstBlock; -} -} // namespace aurora::card diff --git a/aurora-main/lib/card/BlockAllocationTable.hpp b/aurora-main/lib/card/BlockAllocationTable.hpp deleted file mode 100644 index 56f7a40..0000000 --- a/aurora-main/lib/card/BlockAllocationTable.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include -#include - -#include "Constants.hpp" - -namespace aurora::card { -class BlockAllocationTable { - friend class CardRawFile; -#pragma pack(push, 4) - union { - struct { - uint16_t m_checksum; - uint16_t m_checksumInv; - uint16_t m_updateCounter; - uint16_t m_freeBlocks; - uint16_t m_lastAllocated; - std::array m_map; - }; - std::array raw{}; - }; -#pragma pack(pop) - - void swapEndian(); - void updateChecksum(); - bool valid() const; - -public: - explicit BlockAllocationTable(uint32_t blockCount = (static_cast(ECardSize::Card2043Mb) * MbitToBlocks)); - ~BlockAllocationTable() = default; - - uint16_t getNextBlock(uint16_t block) const; - uint16_t nextFreeBlock(uint16_t maxBlock, uint16_t startingBlock) const; - bool clear(uint16_t first, uint16_t count); - uint16_t allocateBlocks(uint16_t count, uint16_t maxBlocks); - uint16_t numFreeBlocks() const { return m_freeBlocks; } -}; -} // namespace aurora::card diff --git a/aurora-main/lib/card/CardGciFolder.cpp b/aurora-main/lib/card/CardGciFolder.cpp deleted file mode 100644 index 57bd6a6..0000000 --- a/aurora-main/lib/card/CardGciFolder.cpp +++ /dev/null @@ -1,431 +0,0 @@ -#include "CardGciFolder.hpp" - -#include -#include "../fs_helper.hpp" - -#include "Directory.hpp" -#include "FileIO.hpp" -#include "../internal.hpp" - -namespace { -aurora::Module Log("aurora::card"); -} - -namespace aurora::card { - -CardGciFolder::GciFile* CardGciFolder::getFile(uint32_t idx) { - if (m_files.size() > idx) { - auto file = &m_files[idx]; - if (file->opened) - return file; - } - return nullptr; -} - -CardGciFolder::GciFile* CardGciFolder::getFile(FileHandle& fh) { return getFile(fh.getFileNo()); } - -const CardGciFolder::GciFile* CardGciFolder::getFile(uint32_t idx) const { - if (m_files.size() > idx) { - auto file = &m_files[idx]; - if (file->opened) - return file; - } - return nullptr; -} - -const CardGciFolder::GciFile* CardGciFolder::getFile(FileHandle& fh) const { return getFile(fh.getFileNo()); } - -CardGciFolder::CardGciFolder() {} - -CardGciFolder::CardGciFolder(CardGciFolder&& other) { - m_files = std::move(other.m_files); - m_bat = std::move(other.m_bat); - m_folderPath = other.m_folderPath; - m_encoding = other.m_encoding; - - CardGciFolder::setCurrentGame(other.m_game); - CardGciFolder::setCurrentMaker(other.m_maker); -} - -CardGciFolder& CardGciFolder::operator=(CardGciFolder&& other) { return *this; } - -void CardGciFolder::InitCard(const char* game, const char* maker) { - setCurrentGame(game); - setCurrentMaker(maker); -} - -ECardResult CardGciFolder::openFile(const char* filename, FileHandle& handleOut) { - int idx = 0; - for (auto& gciFile : m_files) { - if (strcmp(filename, gciFile.file.m_filename) == 0) { - gciFile.opened = true; - if (gciFile.fileSize == 0) - gciFile.fileSize = std::filesystem::file_size(m_folderPath / gciFile.filename); - - handleOut = FileHandle(idx, 0); - return ECardResult::READY; - } - idx++; - } - - return ECardResult::NOCARD; -} - -ECardResult CardGciFolder::openFile(uint32_t fileno, FileHandle& handleOut) { - if (m_files.size() > fileno) { - auto& gciFile = m_files[fileno]; - handleOut = FileHandle(fileno, 0); - gciFile.opened = true; - if (gciFile.fileSize == 0) - gciFile.fileSize = std::filesystem::file_size(m_folderPath / gciFile.filename); - - return ECardResult::READY; - } - - return ECardResult::NOCARD; -} - -ECardResult CardGciFolder::createFile(const char* filename, size_t size, FileHandle& handleOut) { - std::string gciFilename = fmt::format("{}-{}-{}.gci", m_maker, m_game, filename); - uint16_t neededBlocks = ROUND_UP_8192(size) / BlockSize; - size_t fileSize = sizeof(File) + size; - constexpr uint16_t maxBlocks = ((uint16_t)ECardSize::Card2043Mb * MbitToBlocks) - FSTBlocks; - - std::vector fileBuf(fileSize); - - File* gciFileHeader = (File*)fileBuf.data(); - - std::memcpy(gciFileHeader->m_game, m_game, 4); - std::memcpy(gciFileHeader->m_maker, m_maker, 2); - strncpy(gciFileHeader->m_filename, filename, std::size(gciFileHeader->m_filename)); - - gciFileHeader->m_modifiedTime = static_cast(getGCTime()); - gciFileHeader->m_blockCount = neededBlocks; - gciFileHeader->m_firstBlock = m_bat.allocateBlocks(neededBlocks, maxBlocks); - - // write big endian header for dolphin compat - gciFileHeader->swapEndian(); - FileIO file(m_folderPath / gciFilename, true); - if (!file || !file.fileWrite(fileBuf.data(), fileBuf.size(), 0)) { - return ECardResult::IOERROR; - } - - gciFileHeader->swapEndian(); - // push non-endian swapped header first - m_files.push_back({*gciFileHeader, fileSize, - std::u8string(gciFilename.begin(), gciFilename.end()), false}); - handleOut = FileHandle(m_files.size() - 1, 0); - - return ECardResult::READY; -} - -ECardResult CardGciFolder::closeFile(FileHandle& fh) { - auto file = getFile(fh); - if (file) { - file->opened = false; - return ECardResult::READY; - } - - return ECardResult::NOFILE; -} - -void CardGciFolder::deleteFile(const FileHandle& fh) { - auto file = getFile(fh.getFileNo()); - if (!file) - return; - - FileIO fileIO(m_folderPath / file->filename, true); - if (fileIO) - fileIO.deleteFile(); -} - -ECardResult CardGciFolder::deleteFile(const char* filename) { return ECardResult::NOCARD; } - -ECardResult CardGciFolder::deleteFile(uint32_t fileno) { return ECardResult::NOCARD; } - -ECardResult CardGciFolder::renameFile(const char* oldName, const char* newName) { - for (auto& gciFile : m_files) { - if (strcmp(oldName, gciFile.file.m_filename) == 0) { - strncpy(gciFile.file.m_filename, newName, std::size(gciFile.file.m_filename)); - return ECardResult::READY; - } - } - - return ECardResult::NOCARD; -} - -ECardResult CardGciFolder::fileWrite(FileHandle& fh, const void* buf, size_t size) { - auto file = getFile(fh); - if (file) { - FileIO fileIO(m_folderPath / file->filename); - if (fileIO) { - if (fileIO.fileWrite(buf, size, sizeof(File) + fh.offset)) - return ECardResult::READY; - return ECardResult::IOERROR; - } - return ECardResult::NOFILE; - } - - return ECardResult::NOCARD; -} - -ECardResult CardGciFolder::fileRead(FileHandle& fh, void* dst, size_t size) { - auto file = getFile(fh); - if (file) { - FileIO fileIO(m_folderPath / file->filename); - if (fileIO) { - if (fileIO.fileRead(dst, size, sizeof(File) + fh.offset)) - return ECardResult::READY; - return ECardResult::IOERROR; - } - return ECardResult::NOFILE; - } - - return ECardResult::NOCARD; -} - -void CardGciFolder::seek(FileHandle& fh, int32_t pos, SeekOrigin whence) { - auto file = getFile(fh); - if (file) { - switch (whence) { - case SeekOrigin::Begin: - fh.offset = pos; - break; - case SeekOrigin::Current: - fh.offset += pos; - break; - case SeekOrigin::End: - fh.offset = file->fileSize - pos; - break; - } - } -} - -ECardResult CardGciFolder::getStatus(const FileHandle& fh, CardStat& statOut) const { - return getStatus(fh.getFileNo(), statOut); -} - -ECardResult CardGciFolder::getStatus(uint32_t fileNo, CardStat& statOut) const { - auto gciFile = getFile(fileNo); - - if (!gciFile) - return ECardResult::NOFILE; - const auto file = &gciFile->file; - - std::strncpy(statOut.x0_fileName, file->m_filename, 32); - statOut.x20_length = file->m_blockCount * BlockSize; - statOut.x24_time = file->m_modifiedTime; - memmove(statOut.x28_gameName.data(), file->m_game, 4); - memmove(statOut.x2c_company.data(), file->m_maker, 4); - - statOut.x2e_bannerFormat = file->m_bannerFlags; - statOut.x30_iconAddr = file->m_iconAddress; - statOut.x34_iconFormat = file->m_iconFmt; - statOut.x36_iconSpeed = file->m_animSpeed; - statOut.x38_commentAddr = file->m_commentAddr; - - if (file->m_iconAddress == UINT32_MAX) { - statOut.x3c_offsetBanner = UINT32_MAX; - statOut.x40_offsetBannerTlut = UINT32_MAX; - statOut.x44_offsetIcon.fill(UINT32_MAX); - statOut.x64_offsetIconTlut = UINT32_MAX; - statOut.x68_offsetData = file->m_commentAddr + 64; - } else { - uint32_t cur = file->m_iconAddress; - statOut.x3c_offsetBanner = cur; - cur += BannerSize(statOut.GetBannerFormat()); - statOut.x40_offsetBannerTlut = cur; - cur += TlutSize(statOut.GetBannerFormat()); - bool palette = false; - for (size_t i = 0; i < statOut.x44_offsetIcon.size(); ++i) { - statOut.x44_offsetIcon[i] = cur; - const EImageFormat fmt = statOut.GetIconFormat(static_cast(i)); - if (fmt == EImageFormat::C8) { - palette = true; - } - cur += IconSize(fmt); - } - if (palette) { - statOut.x64_offsetIconTlut = cur; - cur += TlutSize(EImageFormat::C8); - } else - statOut.x64_offsetIconTlut = UINT32_MAX; - statOut.x68_offsetData = cur; - } - - return ECardResult::READY; -} - -ECardResult CardGciFolder::setStatus(const FileHandle& fh, const CardStat& stat) { - return setStatus(fh.getFileNo(), stat); -} - -ECardResult CardGciFolder::setStatus(uint32_t fileNo, const CardStat& stat) { - auto gciFile = getFile(fileNo); - - if (!gciFile) - return ECardResult::NOFILE; - const auto file = &gciFile->file; - - file->m_bannerFlags = stat.x2e_bannerFormat; - file->m_iconAddress = stat.x30_iconAddr; - file->m_iconFmt = stat.x34_iconFormat; - file->m_animSpeed = stat.x36_iconSpeed; - file->m_commentAddr = stat.x38_commentAddr; - - return ECardResult::READY; -} - -void CardGciFolder::setCurrentGame(const char* game) { - if (game != nullptr && std::strlen(game) == 4) { - std::memcpy(m_game, game, 4); - } -} - -const uint8_t* CardGciFolder::getCurrentGame() const { - if (std::strlen(m_game) == sizeof(m_game) - 1) { - return reinterpret_cast(m_game); - } - - return nullptr; -} - -void CardGciFolder::setCurrentMaker(const char* maker) { - if (maker != nullptr && std::strlen(maker) == 2) { - std::memcpy(m_maker, maker, 2); - } -} - -const uint8_t* CardGciFolder::getCurrentMaker() const { - if (std::strlen(m_maker) == sizeof(m_maker) - 1) { - return reinterpret_cast(m_maker); - } - - return nullptr; -} - -void CardGciFolder::getSerial(uint64_t& serial) { - serial = 0; // TODO -} - -void CardGciFolder::getChecksum(uint16_t& checksum, uint16_t& inverse) const { - // TODO - checksum = 0; - inverse = 0; -} - -void CardGciFolder::getFreeBlocks(int32_t& bytesNotUsed, int32_t& filesNotUsed) const { - bytesNotUsed = m_bat.numFreeBlocks() * BlockSize; - filesNotUsed = MaxFiles; -} - -void CardGciFolder::getEncoding(uint16_t& encoding) const { encoding = (uint16_t)m_encoding; } - -void CardGciFolder::format(ECardSlot deviceId, ECardSize size, EEncoding encoding) { - m_encoding = encoding; - - if (!std::filesystem::create_directories(m_folderPath)) { - Log.error("Failed to create directory: {}", fs_path_to_string(m_folderPath)); - } -} - -void CardGciFolder::commit() { - for (auto& gciFile : m_files) { - if (gciFile.opened) { - FileIO file(m_folderPath / gciFile.filename); - - File tempFile = gciFile.file; - tempFile.swapEndian(); - file.fileWrite(&tempFile, sizeof(File), 0); // update header - } - } -} - -bool CardGciFolder::open(const std::filesystem::path& filepath) { - m_folderPath = filepath; - - std::error_code ec; - if (!std::filesystem::exists(filepath, ec) || !std::filesystem::is_directory(filepath, ec)) { - if (ec) { - Log.warn("Failed to inspect GCI folder '{}': {}", fs_path_to_string(filepath), ec.message()); - } - return false; - } - - std::filesystem::directory_iterator it( - filepath, std::filesystem::directory_options::skip_permission_denied, ec); - if (ec) { - Log.warn("Failed to enumerate GCI folder '{}': {}", fs_path_to_string(filepath), ec.message()); - return false; - } - - const std::filesystem::directory_iterator end; - while (it != end) { - const auto path = it->path(); - const auto status = it->status(ec); - if (ec) { - Log.warn("Failed to inspect GCI folder entry '{}': {}", fs_path_to_string(path), ec.message()); - return false; - } - if (!std::filesystem::is_regular_file(status)) { - it.increment(ec); - if (ec) { - Log.warn("Failed to continue enumerating GCI folder '{}': {}", fs_path_to_string(filepath), ec.message()); - return false; - } - continue; - } - - if (path.extension() != ".gci") { - it.increment(ec); - if (ec) { - Log.warn("Failed to continue enumerating GCI folder '{}': {}", fs_path_to_string(filepath), ec.message()); - return false; - } - continue; - } - - FileIO file(path); - if (!file) { - Log.warn("Failed to open GCI file '{}'", fs_path_to_string(path)); - return false; - } - - File fileData; - if (!file.fileRead(&fileData, sizeof(File), 0)) { - Log.warn("Failed to read GCI file '{}'", fs_path_to_string(path)); - return false; - } - fileData.swapEndian(); - - m_files.push_back({fileData, file.fileSize(), path.filename().u8string(), false}); - - it.increment(ec); - if (ec) { - Log.warn("Failed to continue enumerating GCI folder '{}': {}", fs_path_to_string(filepath), ec.message()); - return false; - } - } - - return true; -} - -void CardGciFolder::close() { - m_files.clear(); - m_folderPath = ""; - m_bat = BlockAllocationTable(); -} - -static std::filesystem::path g_cardFileNameEmpty = ""; - -const std::filesystem::path& CardGciFolder::cardFilename() const { return g_cardFileNameEmpty; } - -ECardResult CardGciFolder::getError() const { return ECardResult::READY; } - -ProbeResults CardGciFolder::probeCardFile(const std::filesystem::path& filename) { - if (!std::filesystem::exists(filename) || !std::filesystem::is_directory(filename)) - return {ECardResult::NOCARD, 0, 0}; - return {ECardResult::READY, static_cast(ECardSize::Card2043Mb), BlockSize}; -} - -} // namespace aurora::card diff --git a/aurora-main/lib/card/CardGciFolder.hpp b/aurora-main/lib/card/CardGciFolder.hpp deleted file mode 100644 index b74c689..0000000 --- a/aurora-main/lib/card/CardGciFolder.hpp +++ /dev/null @@ -1,77 +0,0 @@ -#pragma once -#include -#include - -#include "BlockAllocationTable.hpp" -#include "CommonData.h" -#include "File.hpp" -#include "ICard.hpp" - -namespace aurora::card { - -class CardGciFolder : public ICard { -private: - struct GciFile { - File file; - size_t fileSize; - std::u8string filename; - bool opened = false; - }; - - std::vector m_files; - std::filesystem::path m_folderPath; - BlockAllocationTable m_bat; - - EEncoding m_encoding = EEncoding::ASCII; - - char m_game[5] = {'\0'}; - char m_maker[3] = {'\0'}; - - GciFile* getFile(FileHandle& fh); - const GciFile* getFile(FileHandle& fh) const; - GciFile* getFile(uint32_t idx); - const GciFile* getFile(uint32_t idx) const; -public: - CardGciFolder(); - ~CardGciFolder() override = default; - - CardGciFolder(const CardGciFolder& other) = delete; - CardGciFolder& operator=(const CardGciFolder& other) = delete; - CardGciFolder(CardGciFolder&& other); - CardGciFolder& operator=(CardGciFolder&& other); - - void InitCard(const char* game, const char* maker) override; - - ECardResult openFile(const char* filename, FileHandle& handleOut) override; - ECardResult openFile(uint32_t fileno, FileHandle& handleOut) override; - ECardResult createFile(const char* filename, size_t size, FileHandle& handleOut) override; - ECardResult closeFile(FileHandle& fh) override; - void deleteFile(const FileHandle& fh) override; - ECardResult deleteFile(const char* filename) override; - ECardResult deleteFile(uint32_t fileno) override; - ECardResult renameFile(const char* oldName, const char* newName) override; - ECardResult fileWrite(FileHandle& fh, const void* buf, size_t size) override; - ECardResult fileRead(FileHandle& fh, void* dst, size_t size) override; - void seek(FileHandle& fh, int32_t pos, SeekOrigin whence) override; - ECardResult getStatus(const FileHandle& fh, CardStat& statOut) const override; - ECardResult getStatus(uint32_t fileNo, CardStat& statOut) const override; - ECardResult setStatus(const FileHandle& fh, const CardStat& stat) override; - ECardResult setStatus(uint32_t fileNo, const CardStat& stat) override; - void setCurrentGame(const char* game) override; - const uint8_t* getCurrentGame() const override; - void setCurrentMaker(const char* maker) override; - const uint8_t* getCurrentMaker() const override; - void getSerial(uint64_t& serial) override; - void getChecksum(uint16_t& checksum, uint16_t& inverse) const override; - void getFreeBlocks(int32_t& bytesNotUsed, int32_t& filesNotUsed) const override; - void getEncoding(uint16_t& encoding) const override; - void format(ECardSlot deviceId, ECardSize size = ECardSize::Card2043Mb, EEncoding encoding = EEncoding::ASCII) override; - void commit() override; - bool open(const std::filesystem::path& filepath) override; - void close() override; - const std::filesystem::path& cardFilename() const override; - ECardResult getError() const override; - ProbeResults probeCardFile(const std::filesystem::path& filename) override; -}; - -} diff --git a/aurora-main/lib/card/CardRawFile.cpp b/aurora-main/lib/card/CardRawFile.cpp deleted file mode 100644 index f897327..0000000 --- a/aurora-main/lib/card/CardRawFile.cpp +++ /dev/null @@ -1,817 +0,0 @@ -#include "CardRawFile.hpp" - -#include -#include -#include -#include -#include - -#include "../internal.hpp" -#include "SRAM.hpp" - -namespace aurora::card { - -static void NullFileAccess() { fprintf(stderr, "Attempted to access null file\n"); } - -void CardRawFile::CardHeader::_swapEndian() { - m_formatTime = bswap(m_formatTime); - m_sramBias = bswap(m_sramBias); - m_sramLanguage = bswap(m_sramLanguage); - m_unknown = bswap(m_unknown); - m_deviceId = bswap(m_deviceId); - m_sizeMb = bswap(m_sizeMb); - m_encoding = bswap(m_encoding); - m_updateCounter = bswap(m_updateCounter); - m_checksum = bswap(m_checksum); - m_checksumInv = bswap(m_checksumInv); -} - -CardRawFile::CardRawFile() { m_ch.raw.fill(0xFF); } - -CardRawFile::CardRawFile(CardRawFile&& other) { - m_ch.raw = other.m_ch.raw; - m_filename = std::move(other.m_filename); - m_fileHandle = std::move(other.m_fileHandle); - m_dirs = std::move(other.m_dirs); - m_bats = std::move(other.m_bats); - m_currentDir = other.m_currentDir; - m_currentBat = other.m_currentBat; - - m_maxBlock = other.m_maxBlock; - std::copy(std::cbegin(other.m_game), std::cend(other.m_game), std::begin(m_game)); - std::copy(std::cbegin(other.m_maker), std::cend(other.m_maker), std::begin(m_maker)); -} - -CardRawFile& CardRawFile::operator=(CardRawFile&& other) { - close(); - - m_ch.raw = other.m_ch.raw; - m_filename = std::move(other.m_filename); - m_fileHandle = std::move(other.m_fileHandle); - m_dirs = std::move(other.m_dirs); - m_bats = std::move(other.m_bats); - m_currentDir = other.m_currentDir; - m_currentBat = other.m_currentBat; - - m_maxBlock = other.m_maxBlock; - std::copy(std::cbegin(other.m_game), std::cend(other.m_game), std::begin(m_game)); - std::copy(std::cbegin(other.m_maker), std::cend(other.m_maker), std::begin(m_maker)); - - return *this; -} - -ECardResult CardRawFile::_pumpOpen() { - if (m_opened) - return ECardResult::READY; - - if (!m_fileHandle) - return ECardResult::NOCARD; - - m_ch._swapEndian(); - m_maxBlock = m_ch.m_sizeMb * MbitToBlocks; - - m_dirs[0].swapEndian(); - m_dirs[1].swapEndian(); - m_bats[0].swapEndian(); - m_bats[1].swapEndian(); - - /* Check for data integrity, restoring valid data in case of corruption if possible */ - if (!m_dirs[0].valid() && m_dirs[1].valid()) - m_dirs[0] = m_dirs[1]; - else if (!m_dirs[1].valid() && m_dirs[0].valid()) - m_dirs[1] = m_dirs[0]; - if (!m_bats[0].valid() && m_bats[1].valid()) - m_bats[0] = m_bats[1]; - else if (!m_bats[1].valid() && m_bats[0].valid()) - m_bats[1] = m_bats[0]; - - if (m_dirs[0].data.m_updateCounter > m_dirs[1].data.m_updateCounter) - m_currentDir = 0; - else - m_currentDir = 1; - - if (m_bats[0].m_updateCounter > m_bats[1].m_updateCounter) - m_currentBat = 0; - else - m_currentBat = 1; - - m_opened = true; - - return ECardResult::READY; -} - -void CardRawFile::InitCard(const char* game, const char* maker) { - m_ch.raw.fill(0xFF); - - if (game != nullptr && std::strlen(game) == 4) { - std::memcpy(m_game, game, 4); - } - if (maker != nullptr && std::strlen(maker) == 2) { - std::memcpy(m_maker, maker, 2); - } -} - -CardRawFile::~CardRawFile() { CardRawFile::close(); } - -ECardResult CardRawFile::openFile(const char* filename, FileHandle& handleOut) { - const ECardResult openRes = _pumpOpen(); - if (openRes != ECardResult::READY) { - return openRes; - } - - handleOut = {}; - const File* const f = m_dirs[m_currentDir].getFile(m_game, m_maker, filename); - if (!f || f->m_game[0] == 0xFF) { - return ECardResult::NOFILE; - } - - const int32_t idx = m_dirs[m_currentDir].indexForFile(f); - if (idx != -1) { - handleOut = FileHandle(idx); - return ECardResult::READY; - } - - return ECardResult::FATAL_ERROR; -} - -ECardResult CardRawFile::openFile(uint32_t fileno, FileHandle& handleOut) { - ECardResult openRes = _pumpOpen(); - if (openRes != ECardResult::READY) - return openRes; - - handleOut = {}; - File* f = m_dirs[m_currentDir].getFile(fileno); - if (!f || f->m_game[0] == 0xFF) - return ECardResult::NOFILE; - handleOut = FileHandle(fileno); - return ECardResult::READY; -} - -void CardRawFile::_updateDirAndBat(const Directory& dir, const BlockAllocationTable& bat) { - m_currentDir = !m_currentDir; - Directory& updateDir = m_dirs[m_currentDir]; - updateDir = dir; - updateDir.data.m_updateCounter++; - updateDir.updateChecksum(); - - m_currentBat = !m_currentBat; - BlockAllocationTable& updateBat = m_bats[m_currentBat]; - updateBat = bat; - updateBat.m_updateCounter++; - updateBat.updateChecksum(); - - m_dirty = true; -} - -void CardRawFile::_updateChecksum() { - m_ch._swapEndian(); - calculateChecksumBE(reinterpret_cast(m_ch.raw.data()), 0xFE, &m_ch.m_checksum, &m_ch.m_checksumInv); - m_ch._swapEndian(); -} - -File* CardRawFile::_fileFromHandle(const FileHandle& fh) const { - if (!fh) { - NullFileAccess(); - return nullptr; - } - return const_cast(m_dirs[m_currentDir]).getFile(fh.idx); -} - -ECardResult CardRawFile::createFile(const char* filename, size_t size, FileHandle& handleOut) { - ECardResult openRes = _pumpOpen(); - if (openRes != ECardResult::READY) - return openRes; - - handleOut = {}; - - if (size <= 0) - return ECardResult::FATAL_ERROR; - if (strlen(filename) > 32) - return ECardResult::NAMETOOLONG; - if (m_dirs[m_currentDir].getFile(m_game, m_maker, filename)) - return ECardResult::EXIST; - uint16_t neededBlocks = ROUND_UP_8192(size) / BlockSize; - if (neededBlocks > m_bats[m_currentBat].numFreeBlocks()) - return ECardResult::INSSPACE; - if (!m_dirs[m_currentDir].hasFreeFile()) - return ECardResult::NOENT; - - Directory dir = m_dirs[m_currentDir]; - BlockAllocationTable bat = m_bats[m_currentBat]; - File* f = dir.getFirstFreeFile(m_game, m_maker, filename); - uint16_t block = bat.allocateBlocks(neededBlocks, m_maxBlock - FSTBlocks); - if (f && block != 0xFFFF) { - f->m_modifiedTime = static_cast(getGCTime()); - f->m_firstBlock = block; - f->m_blockCount = neededBlocks; - - handleOut = FileHandle(dir.indexForFile(f)); - _updateDirAndBat(dir, bat); - return ECardResult::READY; - } - - return ECardResult::FATAL_ERROR; -} - -ECardResult CardRawFile::closeFile(FileHandle& fh) { - fh.offset = 0; - return ECardResult::READY; -} - -FileHandle CardRawFile::firstFile() { - const File* const f = m_dirs[m_currentDir].getFirstNonFreeFile(0, m_game, m_maker); - - if (f == nullptr) { - return {}; - } - - return FileHandle(m_dirs[m_currentDir].indexForFile(f)); -} - -FileHandle CardRawFile::nextFile(const FileHandle& cur) { - if (!cur) { - NullFileAccess(); - return {}; - } - - const File* const next = m_dirs[m_currentDir].getFirstNonFreeFile(cur.idx + 1, m_game, m_maker); - if (next == nullptr) { - return {}; - } - - return FileHandle(m_dirs[m_currentDir].indexForFile(next)); -} - -const char* CardRawFile::getFilename(const FileHandle& fh) const { - const File* const f = _fileFromHandle(fh); - - if (f == nullptr) { - return nullptr; - } - - return f->m_filename; -} - -void CardRawFile::_deleteFile(File& f, BlockAllocationTable& bat) { - uint16_t block = f.m_firstBlock; - while (block != 0xFFFF) { - /* TODO: add a fragmentation check */ - uint16_t nextBlock = bat.getNextBlock(block); - bat.clear(block, 1); - block = nextBlock; - } - f = File(); -} - -void CardRawFile::deleteFile(const FileHandle& fh) { - if (!fh) { - NullFileAccess(); - return; - } - Directory dir = m_dirs[m_currentDir]; - BlockAllocationTable bat = m_bats[m_currentBat]; - _deleteFile(*dir.getFile(fh.idx), bat); - _updateDirAndBat(dir, bat); -} - -ECardResult CardRawFile::deleteFile(const char* filename) { - ECardResult openRes = _pumpOpen(); - if (openRes != ECardResult::READY) - return openRes; - - Directory dir = m_dirs[m_currentDir]; - File* f = dir.getFile(m_game, m_maker, filename); - if (!f) - return ECardResult::NOFILE; - - BlockAllocationTable bat = m_bats[m_currentBat]; - _deleteFile(*f, bat); - _updateDirAndBat(dir, bat); - return ECardResult::READY; -} - -ECardResult CardRawFile::deleteFile(uint32_t fileno) { - ECardResult openRes = _pumpOpen(); - if (openRes != ECardResult::READY) - return openRes; - - Directory dir = m_dirs[m_currentDir]; - File* f = dir.getFile(fileno); - if (!f) - return ECardResult::NOFILE; - - BlockAllocationTable bat = m_bats[m_currentBat]; - _deleteFile(*f, bat); - _updateDirAndBat(dir, bat); - return ECardResult::READY; -} - -ECardResult CardRawFile::renameFile(const char* oldName, const char* newName) { - const ECardResult openRes = _pumpOpen(); - if (openRes != ECardResult::READY) { - return openRes; - } - - if (std::strlen(newName) > 32) { - return ECardResult::NAMETOOLONG; - } - - Directory dir = m_dirs[m_currentDir]; - File* f = dir.getFile(m_game, m_maker, oldName); - if (f == nullptr) { - return ECardResult::NOFILE; - } - - if (File* replF = dir.getFile(m_game, m_maker, newName)) { - BlockAllocationTable bat = m_bats[m_currentBat]; - _deleteFile(*replF, bat); - std::memset(f->m_filename, 0, 32); - std::strncpy(f->m_filename, newName, 32); - _updateDirAndBat(dir, bat); - } else { - std::memset(f->m_filename, 0, 32); - std::strncpy(f->m_filename, newName, 32); - _updateDirAndBat(dir, m_bats[m_currentBat]); - } - return ECardResult::READY; -} - -ECardResult CardRawFile::fileWrite(FileHandle& fh, const void* buf, size_t size) { - ECardResult openRes = _pumpOpen(); - if (openRes != ECardResult::READY) - return openRes; - - if (!fh) { - NullFileAccess(); - return ECardResult::NOFILE; - } - File* file = m_dirs[m_currentDir].getFile(fh.idx); - if (!file) - return ECardResult::NOFILE; - - /* Block handling is a little different from cache handling, - * since each block can be in an arbitrary location we must - * first find our starting block. - */ - const uint16_t blockId = static_cast(fh.offset / BlockSize); - uint16_t block = file->m_firstBlock; - for (uint16_t i = 0; i < blockId; i++) - block = m_bats[m_currentBat].getNextBlock(block); - - const uint8_t* tmpBuf = static_cast(buf); - uint16_t curBlock = block; - uint32_t blockOffset = fh.offset % BlockSize; - size_t rem = size; - while (rem) { - if (curBlock == 0xFFFF) - return ECardResult::NOFILE; - - size_t cacheSize = rem; - if (cacheSize + blockOffset > BlockSize) - cacheSize = BlockSize - blockOffset; - uint32_t offset = (curBlock * BlockSize) + blockOffset; - if (!m_fileHandle.fileWrite(tmpBuf, cacheSize, offset)) - return ECardResult::FATAL_ERROR; - tmpBuf += cacheSize; - rem -= cacheSize; - blockOffset += cacheSize; - if (blockOffset >= BlockSize) { - curBlock = m_bats[m_currentBat].getNextBlock(curBlock); - blockOffset = 0; - } - } - fh.offset += size; - - return ECardResult::READY; -} - -ECardResult CardRawFile::fileRead(FileHandle& fh, void* dst, size_t size) { - ECardResult openRes = _pumpOpen(); - if (openRes != ECardResult::READY) - return openRes; - - if (!fh) { - NullFileAccess(); - return ECardResult::NOFILE; - } - File* file = m_dirs[m_currentDir].getFile(fh.idx); - if (!file) - return ECardResult::NOFILE; - /* Block handling is a little different from cache handling, - * since each block can be in an arbitrary location we must - * first find our starting block. - */ - const uint16_t blockId = static_cast(fh.offset / BlockSize); - uint16_t block = file->m_firstBlock; - for (uint16_t i = 0; i < blockId; i++) - block = m_bats[m_currentBat].getNextBlock(block); - - uint8_t* tmpBuf = static_cast(dst); - uint16_t curBlock = block; - uint32_t blockOffset = fh.offset % BlockSize; - size_t rem = size; - while (rem) { - if (curBlock == 0xFFFF) - return ECardResult::NOFILE; - - size_t cacheSize = rem; - if (cacheSize + blockOffset > BlockSize) - cacheSize = BlockSize - blockOffset; - uint32_t offset = (curBlock * BlockSize) + blockOffset; - if (!m_fileHandle.fileRead(tmpBuf, cacheSize, offset)) - return ECardResult::FATAL_ERROR; - tmpBuf += cacheSize; - rem -= cacheSize; - blockOffset += cacheSize; - if (blockOffset >= BlockSize) { - curBlock = m_bats[m_currentBat].getNextBlock(curBlock); - blockOffset = 0; - } - } - fh.offset += size; - - return ECardResult::READY; -} - -void CardRawFile::seek(FileHandle& fh, int32_t pos, SeekOrigin whence) { - if (!fh) { - NullFileAccess(); - return; - } - File* file = m_dirs[m_currentDir].getFile(fh.idx); - if (!file) - return; - - switch (whence) { - case SeekOrigin::Begin: - fh.offset = pos; - break; - case SeekOrigin::Current: - fh.offset += pos; - break; - case SeekOrigin::End: - fh.offset = static_cast(file->m_blockCount * BlockSize) - pos; - break; - } -} - -int32_t CardRawFile::tell(const FileHandle& fh) const { return fh.offset; } - -void CardRawFile::setPublic(const FileHandle& fh, bool pub) { - File* file = _fileFromHandle(fh); - if (!file) - return; - - if (pub) - file->m_permissions |= EPermissions::Public; - else - file->m_permissions &= ~EPermissions::Public; -} - -bool CardRawFile::isPublic(const FileHandle& fh) const { - File* file = _fileFromHandle(fh); - if (!file) - return false; - - return static_cast(file->m_permissions & EPermissions::Public); -} - -void CardRawFile::setCanCopy(const FileHandle& fh, bool copy) const { - File* file = _fileFromHandle(fh); - if (!file) - return; - - if (copy) - file->m_permissions &= ~EPermissions::NoCopy; - else - file->m_permissions |= EPermissions::NoCopy; -} - -bool CardRawFile::canCopy(const FileHandle& fh) const { - File* file = _fileFromHandle(fh); - if (!file) - return false; - - return !static_cast(file->m_permissions & EPermissions::NoCopy); -} - -void CardRawFile::setCanMove(const FileHandle& fh, bool move) { - File* file = _fileFromHandle(fh); - if (!file) - return; - - if (move) - file->m_permissions &= ~EPermissions::NoMove; - else - file->m_permissions |= EPermissions::NoMove; -} - -bool CardRawFile::canMove(const FileHandle& fh) const { - File* file = _fileFromHandle(fh); - if (!file) - return false; - - return !static_cast(file->m_permissions & EPermissions::NoMove); -} - -ECardResult CardRawFile::getStatus(const FileHandle& fh, CardStat& statOut) const { - if (!fh) { - NullFileAccess(); - return ECardResult::NOFILE; - } - return getStatus(fh.idx, statOut); -} - -ECardResult CardRawFile::getStatus(uint32_t fileNo, CardStat& statOut) const { - ECardResult openRes = const_cast(this)->_pumpOpen(); - if (openRes != ECardResult::READY) - return openRes; - - const File* file = const_cast(m_dirs[m_currentDir]).getFile(fileNo); - if (!file || file->m_game[0] == 0xFF) - return ECardResult::NOFILE; - - std::strncpy(statOut.x0_fileName, file->m_filename, 32); - statOut.x20_length = file->m_blockCount * BlockSize; - statOut.x24_time = file->m_modifiedTime; - memmove(statOut.x28_gameName.data(), file->m_game, 4); - memmove(statOut.x2c_company.data(), file->m_maker, 4); - - statOut.x2e_bannerFormat = file->m_bannerFlags; - statOut.x30_iconAddr = file->m_iconAddress; - statOut.x34_iconFormat = file->m_iconFmt; - statOut.x36_iconSpeed = file->m_animSpeed; - statOut.x38_commentAddr = file->m_commentAddr; - - if (file->m_iconAddress == UINT32_MAX) { - statOut.x3c_offsetBanner = UINT32_MAX; - statOut.x40_offsetBannerTlut = UINT32_MAX; - statOut.x44_offsetIcon.fill(UINT32_MAX); - statOut.x64_offsetIconTlut = UINT32_MAX; - statOut.x68_offsetData = file->m_commentAddr + 64; - } else { - uint32_t cur = file->m_iconAddress; - statOut.x3c_offsetBanner = cur; - cur += BannerSize(statOut.GetBannerFormat()); - statOut.x40_offsetBannerTlut = cur; - cur += TlutSize(statOut.GetBannerFormat()); - bool palette = false; - for (size_t i = 0; i < statOut.x44_offsetIcon.size(); ++i) { - statOut.x44_offsetIcon[i] = cur; - const EImageFormat fmt = statOut.GetIconFormat(static_cast(i)); - if (fmt == EImageFormat::C8) { - palette = true; - } - cur += IconSize(fmt); - } - if (palette) { - statOut.x64_offsetIconTlut = cur; - cur += TlutSize(EImageFormat::C8); - } else - statOut.x64_offsetIconTlut = UINT32_MAX; - statOut.x68_offsetData = cur; - } - - return ECardResult::READY; -} - -ECardResult CardRawFile::setStatus(const FileHandle& fh, const CardStat& stat) { - if (!fh) { - NullFileAccess(); - return ECardResult::NOFILE; - } - return setStatus(fh.idx, stat); -} - -ECardResult CardRawFile::setStatus(uint32_t fileNo, const CardStat& stat) { - ECardResult openRes = _pumpOpen(); - if (openRes != ECardResult::READY) - return openRes; - - Directory dir = m_dirs[m_currentDir]; - File* file = dir.getFile(fileNo); - if (!file || file->m_game[0] == 0xFF) - return ECardResult::NOFILE; - - file->m_bannerFlags = stat.x2e_bannerFormat; - file->m_iconAddress = stat.x30_iconAddr; - file->m_iconFmt = stat.x34_iconFormat; - file->m_animSpeed = stat.x36_iconSpeed; - file->m_commentAddr = stat.x38_commentAddr; - - _updateDirAndBat(dir, m_bats[m_currentBat]); - return ECardResult::READY; -} - -void CardRawFile::setCurrentGame(const char* game) { - if (game == nullptr) { - std::memset(m_game, 0, sizeof(m_game)); - return; - } - - constexpr size_t copy_amount = sizeof(m_game) - 1; - if (std::strlen(game) != copy_amount) { - return; - } - - std::memcpy(m_game, game, copy_amount); -} - -const uint8_t* CardRawFile::getCurrentGame() const { - if (std::strlen(m_game) == sizeof(m_game) - 1) { - return reinterpret_cast(m_game); - } - - return nullptr; -} - -void CardRawFile::setCurrentMaker(const char* maker) { - if (maker == nullptr) { - std::memset(m_maker, 0, sizeof(m_maker)); - return; - } - - constexpr size_t copy_amount = sizeof(m_maker) - 1; - if (std::strlen(maker) != copy_amount) { - return; - } - - std::memcpy(m_maker, maker, copy_amount); -} - -const uint8_t* CardRawFile::getCurrentMaker() const { - if (std::strlen(m_maker) == sizeof(m_maker) - 1) { - return reinterpret_cast(m_maker); - } - - return nullptr; -} - -void CardRawFile::getSerial(uint64_t& serial) { - m_ch._swapEndian(); - - std::array serialBuf{}; - for (size_t i = 0; i < serialBuf.size(); i++) { - serialBuf[i] = bswap(*reinterpret_cast(m_ch.raw.data() + (i * 4))); - } - serial = static_cast(serialBuf[0] ^ serialBuf[2] ^ serialBuf[4] ^ serialBuf[6]) << 32 | - (serialBuf[1] ^ serialBuf[3] ^ serialBuf[5] ^ serialBuf[7]); - - m_ch._swapEndian(); -} - -void CardRawFile::getChecksum(uint16_t& checksum, uint16_t& inverse) const { - checksum = m_ch.m_checksum; - inverse = m_ch.m_checksumInv; -} - -void CardRawFile::getFreeBlocks(int32_t& bytesNotUsed, int32_t& filesNotUsed) const { - bytesNotUsed = m_bats[m_currentBat].numFreeBlocks() * 0x2000; - filesNotUsed = m_dirs[m_currentDir].numFreeFiles(); -} - -void CardRawFile::getEncoding(uint16_t& encoding) const { encoding = m_ch.m_encoding; } - -void CardRawFile::format(ECardSlot id, ECardSize size, EEncoding encoding) { - m_ch.raw.fill(0xFF); - - uint64_t rand = static_cast(getGCTime()); - m_ch.m_formatTime = rand; - for (size_t i = 0; i < m_ch.m_serial.size(); i++) { - rand = (((rand * static_cast(0x41c64e6d)) + static_cast(0x3039)) >> 16); - m_ch.m_serial[i] = static_cast(g_SRAM.flash_id[uint32_t(id)][i] + uint32_t(rand)); - rand = (((rand * static_cast(0x41c64e6d)) + static_cast(0x3039)) >> 16); - rand &= static_cast(0x7fffULL); - } - - m_ch.m_sramBias = static_cast(bswap(g_SRAM.counter_bias)); - m_ch.m_sramLanguage = static_cast(g_SRAM.lang); - m_ch.m_unknown = 0; /* 1 works for slot A, 0 both */ - m_ch.m_deviceId = 0; - m_ch.m_sizeMb = static_cast(size); - m_maxBlock = m_ch.m_sizeMb * MbitToBlocks; - m_ch.m_encoding = static_cast(encoding); - _updateChecksum(); - m_dirs[0] = Directory(); - m_dirs[1] = m_dirs[0]; - m_bats[0] = BlockAllocationTable(static_cast(size) * MbitToBlocks); - m_bats[1] = m_bats[0]; - m_currentDir = 1; - m_currentBat = 1; - - m_fileHandle = {}; - m_fileHandle = FileIO(m_filename, true); - - if (m_fileHandle) { - const uint32_t blockCount = (static_cast(size) * MbitToBlocks) - 5; - - m_tmpCh = m_ch; - m_tmpCh._swapEndian(); - m_fileHandle.fileWrite(m_tmpCh.raw.data(), BlockSize, 0); - m_tmpDirs[0] = m_dirs[0]; - m_tmpDirs[0].swapEndian(); - m_fileHandle.fileWrite(m_tmpDirs[0].raw.data(), BlockSize, BlockSize * 1); - m_tmpDirs[1] = m_dirs[1]; - m_tmpDirs[1].swapEndian(); - m_fileHandle.fileWrite(m_tmpDirs[1].raw.data(), BlockSize, BlockSize * 2); - m_tmpBats[0] = m_bats[0]; - m_tmpBats[0].swapEndian(); - m_fileHandle.fileWrite(m_tmpBats[0].raw.data(), BlockSize, BlockSize * 3); - m_tmpBats[1] = m_bats[1]; - m_tmpBats[1].swapEndian(); - m_fileHandle.fileWrite(m_tmpBats[1].raw.data(), BlockSize, BlockSize * 4); - - std::unique_ptr dummyBlock; - dummyBlock.reset(new uint8_t[BlockSize * blockCount]); - memset(dummyBlock.get(), 0xFF, BlockSize * blockCount); - m_fileHandle.fileWrite(dummyBlock.get(), BlockSize, BlockSize * blockCount); - m_dirty = false; - } -} - -ProbeResults CardRawFile::probeCardFile(const std::filesystem::path& filename) { - if (!std::filesystem::exists(filename)) - return {ECardResult::NOCARD, 0, 0}; - return {ECardResult::READY, static_cast(std::filesystem::file_size(filename) / BlockSize) / MbitToBlocks, - BlockSize}; -} - -void CardRawFile::commit() { - if (!m_dirty) - return; - if (m_fileHandle) { - m_tmpCh = m_ch; - m_tmpCh._swapEndian(); - m_fileHandle.fileWrite(&m_tmpCh, BlockSize, 0); - m_tmpDirs[0] = m_dirs[0]; - m_tmpDirs[0].updateChecksum(); - m_tmpDirs[0].swapEndian(); - m_fileHandle.fileWrite(m_tmpDirs[0].raw.data(), BlockSize, BlockSize * 1); - m_tmpDirs[1] = m_dirs[1]; - m_tmpDirs[1].updateChecksum(); - m_tmpDirs[1].swapEndian(); - m_fileHandle.fileWrite(m_tmpDirs[1].raw.data(), BlockSize, BlockSize * 2); - m_tmpBats[0] = m_bats[0]; - m_tmpBats[0].updateChecksum(); - m_tmpBats[0].swapEndian(); - m_fileHandle.fileWrite(m_tmpBats[0].raw.data(), BlockSize, BlockSize * 3); - m_tmpBats[1] = m_bats[1]; - m_tmpBats[1].updateChecksum(); - m_tmpBats[1].swapEndian(); - m_fileHandle.fileWrite(m_tmpBats[1].raw.data(), BlockSize, BlockSize * 4); - m_dirty = false; - } -} - -bool CardRawFile::open(const std::filesystem::path& filepath) { - m_opened = false; - m_filename = filepath; - m_fileHandle = FileIO(m_filename); - if (m_fileHandle) { - if (!m_fileHandle.fileRead(m_ch.raw.data(), BlockSize, 0)) - return false; - if (!m_fileHandle.fileRead(m_dirs[0].raw.data(), BlockSize, BlockSize * 1)) - return false; - if (!m_fileHandle.fileRead(m_dirs[1].raw.data(), BlockSize, BlockSize * 2)) - return false; - if (!m_fileHandle.fileRead(m_bats[0].raw.data(), BlockSize, BlockSize * 3)) - return false; - if (!m_fileHandle.fileRead(m_bats[1].raw.data(), BlockSize, BlockSize * 4)) - return false; - return true; - } - return false; -} - -void CardRawFile::close() { - m_opened = false; - if (m_fileHandle) { - commit(); - m_fileHandle = {}; - } -} - -ECardResult CardRawFile::getError() const { - if (!m_fileHandle) - return ECardResult::NOCARD; - - ECardResult openRes = const_cast(this)->_pumpOpen(); - if (openRes != ECardResult::READY) - return openRes; - - uint16_t ckSum, ckSumInv; - const_cast(*this).m_ch._swapEndian(); - calculateChecksumBE(reinterpret_cast(m_ch.raw.data()), 0xFE, &ckSum, &ckSumInv); - bool res = ckSum == m_ch.m_checksum && ckSumInv == m_ch.m_checksumInv; - const_cast(*this).m_ch._swapEndian(); - - if (!res) - return ECardResult::BROKEN; - if (!m_dirs[0].valid() && !m_dirs[1].valid()) - return ECardResult::BROKEN; - if (!m_bats[0].valid() && !m_bats[1].valid()) - return ECardResult::BROKEN; - - return ECardResult::READY; -} -} // namespace aurora::card diff --git a/aurora-main/lib/card/CardRawFile.hpp b/aurora-main/lib/card/CardRawFile.hpp deleted file mode 100644 index c13ab2c..0000000 --- a/aurora-main/lib/card/CardRawFile.hpp +++ /dev/null @@ -1,438 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "FileIO.hpp" -#include "BlockAllocationTable.hpp" -#include "Directory.hpp" -#include "File.hpp" -#include "Util.hpp" - -#include "CommonData.h" -#include "ICard.hpp" - -namespace aurora::card { - -class CardRawFile : public ICard { -#pragma pack(push, 4) - struct CardHeader { - union { - struct { - std::array m_serial; - uint64_t m_formatTime; - int32_t m_sramBias; - uint32_t m_sramLanguage; - uint32_t m_unknown; - uint16_t m_deviceId; /* 0 for Slot A, 1 for Slot B */ - uint16_t m_sizeMb; - uint16_t m_encoding; - std::array padding; - uint16_t m_updateCounter; - uint16_t m_checksum; - uint16_t m_checksumInv; - }; - std::array raw; - }; - void _swapEndian(); - }; -#pragma pack(pop) - - CardHeader m_ch; - CardHeader m_tmpCh; - - std::filesystem::path m_filename; - FileIO m_fileHandle; - std::array m_dirs; - std::array m_bats; - std::array m_tmpDirs; - std::array m_tmpBats; - uint8_t m_currentDir; - uint8_t m_currentBat; - - uint16_t m_maxBlock; - char m_game[5] = {'\0'}; - char m_maker[3] = {'\0'}; - - void _updateDirAndBat(const Directory& dir, const BlockAllocationTable& bat); - void _updateChecksum(); - File* _fileFromHandle(const FileHandle& fh) const; - void _deleteFile(File& f, BlockAllocationTable& bat); - - bool m_dirty = false; - bool m_opened = false; - ECardResult _pumpOpen(); - -public: - CardRawFile(); - CardRawFile(const CardRawFile& other) = delete; - CardRawFile& operator=(const CardRawFile& other) = delete; - CardRawFile(CardRawFile&& other); - CardRawFile& operator=(CardRawFile&& other); - - /** - * @brief Card - * - * @param game The game code. - * @param maker The maker code. - */ - void InitCard(const char* game = nullptr, const char* maker = nullptr) override; - - ~CardRawFile() override; - - /** - * @brief openFile - * - * @param[in] filename The name of the file to open. - * @param[out] handleOut Out reference that will contain the opened file handle. - * - * @return A result indicating the error status of the operation. - */ - ECardResult openFile(const char* filename, FileHandle& handleOut) override; - - /** - * @brief openFile - * - * @param[in] fileno The file index. - * @param[out] handleOut Out reference that will contain the opened file handle. - * - * @return A result indicating the error status of the operation. - */ - ECardResult openFile(uint32_t fileno, FileHandle& handleOut) override; - - /** - * @brief createFile - * - * @param[in] filename The name of the file to create. - * @param[out] handleOut Out reference that will contain the handle of the created file. - * - * @return A result indicating the error status of the operation. - */ - ECardResult createFile(const char* filename, size_t size, FileHandle& handleOut) override; - - /** - * @brief closeFile - * - * @param fh FileHandle to close - * - * @return READY - */ - ECardResult closeFile(FileHandle& fh) override; - - /** - * @brief firstFile - * - * @return The first file within this card instance. If - * no file is able to be found, then an invalid - * handle will be returned. - */ - FileHandle firstFile(); - - /** - * @brief nextFile - * - * @param cur The file handle indicating the current file handle. - * - * @return The next file within this card. If no file can be found, - * an invalid handle will be returned. - */ - FileHandle nextFile(const FileHandle& cur); - - /** - * @brief getFilename - * - * @param fh A valid file handle to retrieve the name of. - * - * @return Gets the name of the given file. - */ - const char* getFilename(const FileHandle& fh) const; - - /** - * @brief deleteFile - * - * @param fh File handle to delete. - */ - void deleteFile(const FileHandle& fh) override; - - /** - * @brief deleteFile - * - * @param filename The name of the file to delete. - */ - ECardResult deleteFile(const char* filename) override; - - /** - * @brief deleteFile - * - * @param fileno The file number indicating the file to delete. - */ - ECardResult deleteFile(uint32_t fileno) override; - - /** - * @brief renameFile - * - * @param oldName The old name of the file. - * @param newName The new name to assign to the file. - */ - ECardResult renameFile(const char* oldName, const char* newName) override; - - /** - * @brief write - * - * @param fh A valid file handle to write to. - * @param buf The buffer to write to the file. - * @param size The size of the given buffer. - */ - ECardResult fileWrite(FileHandle& fh, const void* buf, size_t size) override; - - /** - * @brief read - * - * @param fh A valid file handle to read from. - * @param dst A buffer to read data into. - * @param size The size of the buffer to read into. - */ - ECardResult fileRead(FileHandle& fh, void* dst, size_t size) override; - - /** - * @brief seek - * - * @param fh A valid file handle. - * @param pos The position to seek to. - * @param whence The origin to seek relative to. - */ - void seek(FileHandle& fh, int32_t pos, SeekOrigin whence) override; - - /** - * @brief Returns the current offset of the specified file. - * - * @param fh The file to retrieve the offset from. - * - * @return The offset or -1 if an invalid handle is passed. - */ - int32_t tell(const FileHandle& fh) const; - - /** - * @brief setPublic - * - * @param fh The file handle to make public. - * @param pub Whether or not this file is public (i.e. readable by any game). - */ - void setPublic(const FileHandle& fh, bool pub); - - /** - * @brief isPublic - * - * @param fh The file handle to query. - * - * @return Whether or not this file is public (i.e. readable by any game). - */ - bool isPublic(const FileHandle& fh) const; - - /** - * @brief setCanCopy - * - * @param fh The file handle to set as copyable. - * @param copy Whether or not to set the file handle as copyable. - */ - void setCanCopy(const FileHandle& fh, bool copy) const; - - /** - * @brief canCopy - * - * @param fh The file handle to query. - * - * @return Whether or not this file handle is copyable by the IPL. - */ - bool canCopy(const FileHandle& fh) const; - - /** - * @brief setCanMove - * - * @param fh The file handle to set as moveable. - * @param move Whether or not to set the file handle as movable. - */ - void setCanMove(const FileHandle& fh, bool move); - - /** - * @brief canMove - * - * @param fh The file handle to query. - * - * @return whether or not the file can be moved by the IPL. - */ - bool canMove(const FileHandle& fh) const; - - /** - * @brief getStatus - * - * @param fh Handle of requested file - * @param statOut Structure to fill with file stat - * - * @return NOFILE or READY - */ - ECardResult getStatus(const FileHandle& fh, CardStat& statOut) const override; - - /** - * @brief getStatus - * - * @param fileNo Number of requested file - * @param statOut Structure to fill with file stat - * - * @return NOFILE or READY - */ - ECardResult getStatus(uint32_t fileNo, CardStat& statOut) const override; - - /** - * @brief setStatus - * - * @param fh Handle of requested file - * @param stat Structure to access for file stat - * - * @return NOFILE or READY - */ - ECardResult setStatus(const FileHandle& fh, const CardStat& stat) override; - - /** - * @brief setStatus - * - * @param fileNo Number of requested file - * @param stat Structure to access for file stat - * - * @return NOFILE or READY - */ - ECardResult setStatus(uint32_t fileNo, const CardStat& stat) override; - -#if 0 // TODO: Async-friendly implementations - /** - * @brief Copies a file from the current Card instance to a specified Card instance - * @param fh The file to copy - * @param dest The destination Card instance - * @return True if successful, false otherwise - */ - bool copyFileTo(FileHandle& fh, CardRawFile& dest); - - /** - * @brief moveFileTo - * @param fh - * @param dest - * @return - */ - bool moveFileTo(FileHandle& fh, CardRawFile& dest); -#endif - - /** - * @brief Sets the current game, if not null any openFile requests will only return files that match this game - * - * @param game The target game id, e.g "GM8E" - * - * @sa openFile - */ - void setCurrentGame(const char* game) override; - - /** - * @brief Returns the currently selected game. - * - * @return The selected game, or nullptr - */ - const uint8_t* getCurrentGame() const override; - - /** - * @brief Sets the current maker, if not null any openFile requests will only return files that match this maker. - * - * @param maker The target maker id, e.g "01". - * - * @sa openFile - */ - void setCurrentMaker(const char* maker) override; - - /** - * @brief Returns the currently selected maker. - * - * @return The selected maker, or nullptr. - */ - const uint8_t* getCurrentMaker() const override; - - /** - * @brief Retrieves the format assigned serial. - * - * @param[out] serial Out reference that will contain the serial number. - */ - void getSerial(uint64_t& serial) override; - - /** - * @brief Retrieves the checksum values of the Card system header. - * - * @param checksum The checksum of the system header. - * @param inverse The inverse checksum of the system header. - */ - void getChecksum(uint16_t& checksum, uint16_t& inverse) const override; - - /** - * @brief Retrieves the available storage and directory space. - * - * @param bytesNotUsed Number of free bytes out. - * @param filesNotUsed Number of free files out. - */ - void getFreeBlocks(int32_t& bytesNotUsed, int32_t& filesNotUsed) const override; - - /** - * @brief Retrieves the current file's encoding. - * - * @param encoding File encoding out. - */ - void getEncoding(uint16_t& encoding) const override; - - /** - * @brief Formats the memory card and assigns a new serial. - * - * @param deviceId The slot to format. - * @param size The desired size of the file @sa ECardSize. - * @param encoding The desired encoding @sa EEncoding. - */ - void format(ECardSlot deviceId, ECardSize size = ECardSize::Card2043Mb, EEncoding encoding = EEncoding::ASCII) override; - - /** - * @brief Returns basic stats about a card image without opening a handle. - * - * @return ProbeResults structure. - */ - ProbeResults probeCardFile(const std::filesystem::path& filename) override; - - /** - * @brief Writes any changes to the Card instance immediately to disk.
- * Note: Under normal circumstances there is no need to call this function. - */ - void commit() override; - - /** - * @brief Opens card image (does nothing if currently open path matches). - */ - bool open(const std::filesystem::path& filepath) override; - - /** - * @brief Commits changes to disk and closes host file. - */ - void close() override; - - /** - * @brief Access host filename of card. - * - * @return A view to the card's filename. - */ - const std::filesystem::path& cardFilename() const override { return m_filename; } - - /** - * @brief Gets card-scope error state. - * - * @return READY, BROKEN, or NOCARD - */ - ECardResult getError() const override; - - /** - * @return Whether or not the card is within a ready state. - */ - explicit operator bool() const { return getError() == ECardResult::READY; } -}; -} // namespace aurora::card diff --git a/aurora-main/lib/card/CommonData.h b/aurora-main/lib/card/CommonData.h deleted file mode 100644 index 14caa06..0000000 --- a/aurora-main/lib/card/CommonData.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include - -#include "Util.hpp" -#include "Constants.hpp" - -namespace aurora::card { - -class FileHandle { - friend class CardRawFile; - friend class CardGciFolder; - uint32_t idx = UINT32_MAX; - int32_t offset = 0; - explicit FileHandle(uint32_t idx) : idx(idx) {} - -public: - FileHandle() = default; - explicit FileHandle(uint32_t idx, int32_t offset) : idx(idx), offset(offset) {} - - [[nodiscard]] uint32_t getFileNo() const { return idx; } - [[nodiscard]] uint32_t getOffset() const { return offset; } - explicit operator bool() const { return getFileNo() != UINT32_MAX; } -}; - -struct ProbeResults { - ECardResult x0_error; - uint32_t x4_cardSize; /* in megabits */ - uint32_t x8_sectorSize; /* in bytes */ -}; - -struct CardStat { - /* read-only (Set by Card::getStatus) */ - char x0_fileName[CARD_FILENAME_MAX]; - uint32_t x20_length; - uint32_t x24_time; /* seconds since 01/01/2000 midnight */ - std::array x28_gameName; - std::array x2c_company; - - /* read/write (Set by Card::getStatus/Card::setStatus) */ - uint8_t x2e_bannerFormat; - uint8_t x2f___padding; - uint32_t x30_iconAddr; /* offset to the banner, bannerTlut, icon, iconTlut data set. */ - uint16_t x34_iconFormat; - uint16_t x36_iconSpeed; - uint32_t x38_commentAddr; /* offset to the pair of 32 byte character strings. */ - - /* read-only (Set by Card::getStatus) */ - uint32_t x3c_offsetBanner; - uint32_t x40_offsetBannerTlut; - std::array x44_offsetIcon; - uint32_t x64_offsetIconTlut; - uint32_t x68_offsetData; - - EImageFormat GetBannerFormat() const { return EImageFormat(x2e_bannerFormat & 0x3); } - EImageFormat GetIconFormat(int idx) const { return EImageFormat((x34_iconFormat >> (idx * 2)) & 0x3); } -}; - -} diff --git a/aurora-main/lib/card/Constants.hpp b/aurora-main/lib/card/Constants.hpp deleted file mode 100644 index 1367e91..0000000 --- a/aurora-main/lib/card/Constants.hpp +++ /dev/null @@ -1,109 +0,0 @@ -#pragma once - -#include - -#include "Util.hpp" - -#define CARD_FILENAME_MAX 32 -#define CARD_ICON_MAX 8 - -namespace aurora::card { -constexpr uint32_t BlockSize = 0x2000; -constexpr uint32_t MaxFiles = 127; -constexpr uint32_t FSTBlocks = 5; -constexpr uint32_t MbitToBlocks = 0x10; -constexpr uint32_t BATSize = 0xFFB; - -/** - * @brief The EPermissions enum - */ -enum class EPermissions : uint8_t { - Public = (1 << 2), - NoCopy = (1 << 3), - NoMove = (1 << 4), - Global = (1 << 5), - Company = (1 << 6) -}; -ENABLE_BITWISE_ENUM(EPermissions) - -enum class EImageFormat : uint8_t { - None, - C8, - RGB5A3, -}; - -enum class EAnimationType { - Loop = 0, - Bounce = 2, -}; - -enum class EAnimationSpeed { - End, - Fast, - Middle, - Slow, -}; - -enum class SeekOrigin { Begin, Current, End }; - -/** - * @brief The ECardSlot enum - */ -enum class ECardSlot : uint16_t { SlotA, SlotB }; - -/** - * @brief The ECardSize enum - */ -enum class ECardSize : uint16_t { - Card59Mb = 0x04, - Card123Mb = 0x08, - Card251Mb = 0x10, - Card507Mb = 0x20, - Card1019Mb = 0x40, - Card2043Mb = 0x80 -}; - -/** - * @brief The EEncoding enum - */ -enum class EEncoding : uint16_t { - ASCII, /**< Standard ASCII Encoding */ - SJIS /**< SJIS Encoding for japanese */ -}; - -constexpr uint32_t BannerSize(EImageFormat fmt) { - switch (fmt) { - default: - case EImageFormat::None: - return 0; - case EImageFormat::C8: - return 3584; - case EImageFormat::RGB5A3: - return 6144; - } -} - -constexpr uint32_t IconSize(EImageFormat fmt) { - switch (fmt) { - default: - case EImageFormat::None: - return 0; - case EImageFormat::C8: - return 1024; - case EImageFormat::RGB5A3: - return 2048; - } -} - -constexpr uint32_t TlutSize(EImageFormat fmt) { - switch (fmt) { - default: - case EImageFormat::None: - case EImageFormat::RGB5A3: - return 0; - case EImageFormat::C8: - return 512; - } -} - -} // namespace aurora::card diff --git a/aurora-main/lib/card/Directory.cpp b/aurora-main/lib/card/Directory.cpp deleted file mode 100644 index b2a9bcb..0000000 --- a/aurora-main/lib/card/Directory.cpp +++ /dev/null @@ -1,142 +0,0 @@ -#include "Directory.hpp" - -#include -#include - -#include "../internal.hpp" -#include "Util.hpp" - -namespace aurora::card { -void Directory::swapEndian() { - std::for_each(std::begin(data.m_files), std::end(data.m_files), [](File& f) { f.swapEndian(); }); - - data.m_updateCounter = bswap(data.m_updateCounter); - data.m_checksum = bswap(data.m_checksum); - data.m_checksumInv = bswap(data.m_checksumInv); -} - -void Directory::updateChecksum() { - swapEndian(); - calculateChecksumBE(reinterpret_cast(raw.data()), 0xFFE, &data.m_checksum, &data.m_checksumInv); - swapEndian(); -} - -bool Directory::valid() const { - uint16_t ckSum, ckSumInv; - const_cast(*this).swapEndian(); - calculateChecksumBE(reinterpret_cast(raw.data()), 0xFFE, &ckSum, &ckSumInv); - const bool res = (ckSum == data.m_checksum && ckSumInv == data.m_checksumInv); - const_cast(*this).swapEndian(); - return res; -} - -Directory::Directory() { - raw.fill(0xFF); - data.m_updateCounter = 0; - updateChecksum(); -} - -Directory::Directory(const RawData& rawData) : raw{rawData} {} - -bool Directory::hasFreeFile() const { - return std::any_of(std::cbegin(data.m_files), std::cend(data.m_files), - [](const auto& file) { return file.m_game[0] == 0xFF; }); -} - -int32_t Directory::numFreeFiles() const { - return int32_t(std::count_if(std::cbegin(data.m_files), std::cend(data.m_files), - [](const auto& file) { return file.m_game[0] == 0xFF; })); -} - -File* Directory::getFirstFreeFile(const char* game, const char* maker, const char* filename) { - const auto iter = std::find_if(std::begin(data.m_files), std::end(data.m_files), - [](const auto& file) { return file.m_game[0] == 0xFF; }); - - if (iter == std::end(data.m_files)) { - return nullptr; - } - - *iter = File(filename); - if (game != nullptr && std::strlen(game) == 4) { - std::memcpy(iter->m_game, game, 4); - } - if (maker != nullptr && std::strlen(maker) == 2) { - std::memcpy(iter->m_maker, maker, 2); - } - - return &*iter; -} - -File* Directory::getFirstNonFreeFile(uint32_t start, const char* game, const char* maker) { - const auto iter = - std::find_if(std::begin(data.m_files) + start, std::end(data.m_files), [game, maker](const auto& file) { - if (file.m_game[0] == 0xFF) { - return false; - } - - const auto* const game_ptr = reinterpret_cast(file.m_game); - const auto game_size = 4; - if (game != nullptr && std::strlen(game) == game_size && std::strncmp(game_ptr, game, game_size) != 0) { - return false; - } - - const auto* const maker_ptr = reinterpret_cast(file.m_maker); - const auto maker_size = 2; - if (maker != nullptr && std::strlen(maker) == maker_size && std::strncmp(maker_ptr, maker, maker_size) != 0) { - return false; - } - - return true; - }); - - if (iter == std::end(data.m_files)) { - return nullptr; - } - - return &*iter; -} - -File* Directory::getFile(const char* game, const char* maker, const char* filename) { - const auto iter = std::find_if(std::begin(data.m_files), std::end(data.m_files), [=](const auto& file) { - const auto game_size = 4; - if (game != nullptr && std::strlen(game) == game_size && std::memcmp(file.m_game, game, game_size) != 0) { - return false; - } - - const auto maker_size = 2; - if (maker != nullptr && std::strlen(maker) == maker_size && std::memcmp(file.m_maker, maker, maker_size) != 0) { - return false; - } - - return std::strncmp(file.m_filename, filename, 32) == 0; - }); - - if (iter == std::cend(data.m_files)) { - return nullptr; - } - - return &*iter; -} - -File* Directory::getFile(uint32_t idx) { - if (idx >= MaxFiles) { - return nullptr; - } - - return &data.m_files[idx]; -} - -int32_t Directory::indexForFile(const File* f) const { - if (f == nullptr) { - return -1; - } - - const auto it = - std::find_if(std::cbegin(data.m_files), std::cend(data.m_files), [&f](const File& file) { return f == &file; }); - if (it == std::cend(data.m_files)) { - return -1; - } - - return it - std::cbegin(data.m_files); -} -} // namespace aurora::card diff --git a/aurora-main/lib/card/Directory.hpp b/aurora-main/lib/card/Directory.hpp deleted file mode 100644 index bee9027..0000000 --- a/aurora-main/lib/card/Directory.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include -#include - -#include "File.hpp" - -namespace aurora::card { -class Directory { - friend class CardRawFile; - -#pragma pack(push, 4) - using RawData = std::array; - struct Data { - File m_files[MaxFiles]; - uint8_t padding[0x3a]; - uint16_t m_updateCounter; - uint16_t m_checksum; - uint16_t m_checksumInv; - }; -#pragma pack(pop) - - union { - Data data; - RawData raw; - }; - - void swapEndian(); - void updateChecksum(); - bool valid() const; - -public: - Directory(); - explicit Directory(const RawData& rawData); - ~Directory() = default; - - bool hasFreeFile() const; - int32_t numFreeFiles() const; - File* getFirstFreeFile(const char* game, const char* maker, const char* filename); - File* getFirstNonFreeFile(uint32_t start, const char* game, const char* maker); - File* getFile(const char* game, const char* maker, const char* filename); - File* getFile(uint32_t idx); - int32_t indexForFile(const File* f) const; -}; -} // namespace aurora::card diff --git a/aurora-main/lib/card/DolphinCardPath.cpp b/aurora-main/lib/card/DolphinCardPath.cpp deleted file mode 100644 index 0d0adf0..0000000 --- a/aurora-main/lib/card/DolphinCardPath.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include - -#include "DolphinCardPath.hpp" - -#if WIN32 -#include "windows.h" -#include "winreg.h" -#include "shlobj_core.h" -#endif - -#include - -#include "../internal.hpp" - -#if WIN32 -namespace { - std::string ConvertWideToANSI(const std::wstring& wstr) { - int count = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.length(), NULL, 0, NULL, NULL); - std::string str(count, 0); - WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, &str[0], count, NULL, NULL); - return str; - } -} -#endif - -namespace aurora::card { -aurora::Module Log("aurora::card"); - -#if WIN32 - -#if WINDOWS_STORE -using namespace Windows::Storage; -#endif - -std::string ResolveDolphinCardPath(ECardSlot slot, const char* regionCode, bool isGciFolder) { -#if !WINDOWS_STORE - /* Detect where the User directory is. There are two different cases - * 1. HKCU\Software\Dolphin Emulator\UserConfigPath exists - * -> Use this as the user directory path - * 2. My Documents exists - * -> Use My Documents\Dolphin Emulator as the User directory path - */ - - /* Check our registry keys */ - HKEY hkey; - wchar_t configPath[MAX_PATH] = {0}; - if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\Dolphin Emulator"), 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS) { - DWORD size = MAX_PATH; - if (RegQueryValueEx(hkey, TEXT("UserConfigPath"), nullptr, nullptr, (LPBYTE)configPath, &size) != ERROR_SUCCESS) - configPath[0] = 0; - RegCloseKey(hkey); - } - - /* Get My Documents path in case we need it. */ - PWSTR my_documents; - bool my_documents_found = - SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &my_documents)); - - std::wstring w_path; - if (configPath[0]) /* Case 1 */ - w_path = configPath; - else if (my_documents_found) /* Case 2 */ { - w_path = my_documents; - w_path += L"\\Dolphin Emulator"; - } - else /* Unable to find */ { - Log.error("Unable to find Dolphin Emulator user directory!"); - return {}; - } -#else - StorageFolder ^ localFolder = ApplicationData::Current->LocalFolder; - std::string path(localFolder->Path->Data()); -#endif - - std::string path; - if (isGciFolder) { - path = fmt::format("{}/GC/{}/Card {}", ConvertWideToANSI(w_path), regionCode, slot == ECardSlot::SlotA ? 'A' : 'B'); - }else { - path = fmt::format("{}/GC/MemoryCard{}.{}.raw", ConvertWideToANSI(w_path), slot == ECardSlot::SlotA ? 'A' : 'B', regionCode); - } - - if (!std::filesystem::exists(path)) { - Log.error("Unable to find Dolphin Card file! Search Path: {}", path); - return {}; - } - - return path; -} -#else -static std::optional GetPrefPath(const char* app) { - char* path = SDL_GetPrefPath(nullptr, app); - if (path == nullptr) { - return {}; - } - std::string str{path}; - SDL_free(path); - return str; -} - -std::string ResolveDolphinCardPath(ECardSlot slot, const char* regionCode, bool isGciFolder) { - const auto dolphinPath = GetPrefPath("dolphin-emu"); - if (!dolphinPath) { - return {}; - } - auto path = *dolphinPath; - if (isGciFolder) { - path += fmt::format("GC/{}/Card {}", regionCode, slot == ECardSlot::SlotA ? 'A' : 'B'); - }else { - path += fmt::format("GC/MemoryCard{}.{}.raw", slot == ECardSlot::SlotA ? 'A' : 'B', regionCode); - } - - if (!std::filesystem::exists(path)) return {}; - - return path; -} -#endif - -} diff --git a/aurora-main/lib/card/DolphinCardPath.hpp b/aurora-main/lib/card/DolphinCardPath.hpp deleted file mode 100644 index 2a45182..0000000 --- a/aurora-main/lib/card/DolphinCardPath.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include -#include - -#include "Constants.hpp" - -namespace aurora::card { -std::string ResolveDolphinCardPath(ECardSlot slot, const char* regionCode, bool isGciFolder); -} \ No newline at end of file diff --git a/aurora-main/lib/card/File.cpp b/aurora-main/lib/card/File.cpp deleted file mode 100644 index 8be888c..0000000 --- a/aurora-main/lib/card/File.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "File.hpp" - -#include -#include - -#include "../internal.hpp" - -namespace aurora::card { -File::File() { raw.fill(0xFF); } - -File::File(const RawData& rawData) : raw{rawData} {} - -File::File(const char* filename) { - raw.fill(0); - std::memset(m_filename, 0, std::size(m_filename)); - std::strncpy(m_filename, filename, std::size(m_filename) - 1); -} -void File::swapEndian() { - m_modifiedTime = bswap(m_modifiedTime); - m_iconAddress = bswap(m_iconAddress); - m_iconFmt = bswap(m_iconFmt); - m_animSpeed = bswap(m_animSpeed); - m_firstBlock = bswap(m_firstBlock); - m_blockCount = bswap(m_blockCount); - m_reserved2 = bswap(m_reserved2); - m_commentAddr = bswap(m_commentAddr); -} -} // namespace aurora::card diff --git a/aurora-main/lib/card/File.hpp b/aurora-main/lib/card/File.hpp deleted file mode 100644 index 7bb9b5d..0000000 --- a/aurora-main/lib/card/File.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include -#include - -#include "Constants.hpp" - -namespace aurora::card { -class File { - friend class IFileHandle; - friend class Directory; - friend class CardRawFile; - friend class CardGciFolder; -#pragma pack(push, 4) - using RawData = std::array; - union { - struct { - uint8_t m_game[4]; - uint8_t m_maker[2]; - uint8_t m_reserved; - uint8_t m_bannerFlags; -#if __GNUC__ && !__clang__ - __attribute__((nonstring)) -#endif - char m_filename[0x20]; - uint32_t m_modifiedTime; - uint32_t m_iconAddress; - uint16_t m_iconFmt; - uint16_t m_animSpeed; - EPermissions m_permissions; - int8_t m_copyCounter; - uint16_t m_firstBlock; - uint16_t m_blockCount; - uint16_t m_reserved2; - uint32_t m_commentAddr; - }; - RawData raw; - }; -#pragma pack(pop) - void swapEndian(); - -public: - File(); - explicit File(const RawData& rawData); - explicit File(const char* filename); - ~File() = default; -}; -} // namespace aurora::card diff --git a/aurora-main/lib/card/FileIO.cpp b/aurora-main/lib/card/FileIO.cpp deleted file mode 100644 index c19185f..0000000 --- a/aurora-main/lib/card/FileIO.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include "FileIO.hpp" - -#include -#include - -#include -#include - -#include "../fs_helper.hpp" - -namespace aurora::card { - -FileIO::FileIO(const std::filesystem::path& filename, bool truncate) { - m_path = fs_path_to_string(filename);; - SDL_IOStream* stream = nullptr; - - stream = fileOpen(m_path, truncate ? "w+b" : "r+b"); - - if (stream != nullptr) { - SDL_FlushIO(stream); - SDL_CloseIO(stream); - m_ready = true; - } -} - -FileIO::FileIO(FileIO&& other) noexcept { - m_path = std::move(other.m_path); - m_ready = std::exchange(other.m_ready, false); -} - -FileIO& FileIO::operator=(FileIO&& other) noexcept { - if (this != &other) { - m_path = std::move(other.m_path); - m_ready = std::exchange(other.m_ready, false); - } - return *this; -} - -bool FileIO::fileRead(void* buf, size_t length, off_t offset) { - if (!isReady()) { - return false; - } - - SDL_IOStream* stream = fileOpen(m_path, "rb"); - if (stream == nullptr) { - return false; - } - - if (SDL_SeekIO(stream, offset, SDL_IO_SEEK_SET) < 0) { - SDL_CloseIO(stream); - return false; - } - - size_t total = 0; - auto* dst = static_cast(buf); - while (total < length) { - const size_t read = SDL_ReadIO(stream, dst + total, length - total); - if (read == 0) { - SDL_CloseIO(stream); - return false; - } - total += read; - } - - SDL_CloseIO(stream); - return true; -} - -bool FileIO::fileWrite(const void* buf, size_t length, off_t offset) { - if (!isReady()) { - return false; - } - - SDL_IOStream* stream = fileOpen(m_path, "r+b"); - if (stream == nullptr) { - stream = fileOpen(m_path, "w+b"); - } - if (stream == nullptr) { - return false; - } - - if (SDL_SeekIO(stream, offset, SDL_IO_SEEK_SET) < 0) { - SDL_FlushIO(stream); - SDL_CloseIO(stream); - return false; - } - - size_t total = 0; - auto* src = static_cast(buf); - while (total < length) { - const size_t written = SDL_WriteIO(stream, src + total, length - total); - if (written == 0) { - SDL_CloseIO(stream); - return false; - } - total += written; - } - - SDL_FlushIO(stream); - SDL_CloseIO(stream); - return true; -} - -size_t FileIO::fileSize() const { - SDL_PathInfo info; - const auto tr = fs_path_to_string(m_path); - if (SDL_GetPathInfo(m_path.c_str(), &info)) { - return info.size; - } - return 0; -} - -bool FileIO::deleteFile() { - if (SDL_RemovePath(m_path.c_str())) { - m_ready = false; - m_path.clear(); - return true; - } - return false; -} - -FileIO::operator bool() const { return isReady(); } - -} // namespace aurora::card diff --git a/aurora-main/lib/card/FileIO.hpp b/aurora-main/lib/card/FileIO.hpp deleted file mode 100644 index 98fa929..0000000 --- a/aurora-main/lib/card/FileIO.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include -#include - -#include - -namespace aurora::card { - -class FileIO { - std::string m_path; - bool m_ready = false; - - bool isReady() const { return m_ready && !m_path.empty(); }; - -public: - FileIO() = default; - explicit FileIO(const std::filesystem::path& filename, bool truncate = false); - ~FileIO() = default; - - FileIO(FileIO&& other) noexcept; - FileIO& operator=(FileIO&& other) noexcept; - FileIO(const FileIO& other) = delete; - FileIO& operator=(const FileIO& other) = delete; - - static SDL_IOStream* fileOpen(const std::string& path, const char* mode) {return path.empty() ? nullptr : SDL_IOFromFile(path.c_str(), mode);} - bool fileRead(void* buf, size_t length, off_t offset); - bool fileWrite(const void* buf, size_t length, off_t offset); - size_t fileSize() const; - bool deleteFile(); - explicit operator bool() const; -}; - -} // namespace aurora::card diff --git a/aurora-main/lib/card/ICard.hpp b/aurora-main/lib/card/ICard.hpp deleted file mode 100644 index a169d4d..0000000 --- a/aurora-main/lib/card/ICard.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include "Constants.hpp" -#include "Util.hpp" -#include - -namespace aurora::card { -class ICard { -public: - virtual ~ICard() = default; - - virtual void InitCard(const char* game = nullptr, const char* maker = nullptr) = 0; - - virtual ECardResult openFile(const char* filename, FileHandle& handleOut) = 0; - virtual ECardResult openFile(uint32_t fileno, FileHandle& handleOut) = 0; - virtual ECardResult createFile(const char* filename, size_t size, FileHandle& handleOut) = 0; - virtual ECardResult closeFile(FileHandle& fh) = 0; - virtual void deleteFile(const FileHandle& fh) = 0; - virtual ECardResult deleteFile(const char* filename) = 0; - virtual ECardResult deleteFile(uint32_t fileno) = 0; - virtual ECardResult renameFile(const char* oldName, const char* newName) = 0; - virtual ECardResult fileWrite(FileHandle& fh, const void* buf, size_t size) = 0; - virtual ECardResult fileRead(FileHandle& fh, void* dst, size_t size) = 0; - virtual void seek(FileHandle& fh, int32_t pos, SeekOrigin whence) = 0; - virtual ECardResult getStatus(const FileHandle& fh, CardStat& statOut) const = 0; - virtual ECardResult getStatus(uint32_t fileNo, CardStat& statOut) const = 0; - virtual ECardResult setStatus(const FileHandle& fh, const CardStat& stat) = 0; - virtual ECardResult setStatus(uint32_t fileNo, const CardStat& stat) = 0; - virtual void setCurrentGame(const char* game) = 0; - virtual const uint8_t* getCurrentGame() const = 0; - virtual void setCurrentMaker(const char* maker) = 0; - virtual const uint8_t* getCurrentMaker() const = 0; - virtual void getSerial(uint64_t& serial) = 0; - virtual void getChecksum(uint16_t& checksum, uint16_t& inverse) const = 0; - virtual void getFreeBlocks(int32_t& bytesNotUsed, int32_t& filesNotUsed) const = 0; - virtual void getEncoding(uint16_t& encoding) const = 0; - virtual void format(ECardSlot deviceId, ECardSize size = ECardSize::Card2043Mb, EEncoding encoding = EEncoding::ASCII) = 0; - virtual void commit() = 0; - virtual bool open(const std::filesystem::path& filepath) = 0; - virtual void close() = 0; - virtual const std::filesystem::path& cardFilename() const = 0; - virtual ECardResult getError() const = 0; - virtual ProbeResults probeCardFile(const std::filesystem::path& filename) = 0; -}; -} \ No newline at end of file diff --git a/aurora-main/lib/card/SRAM.cpp b/aurora-main/lib/card/SRAM.cpp deleted file mode 100644 index a39448f..0000000 --- a/aurora-main/lib/card/SRAM.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "SRAM.hpp" -namespace aurora::card { -// clang-format off -const SRAM g_SRAM = -{{ - 0xFF, 0x6B, - 0x00, 0x91, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0x40, - 0x00, - 0x00, - 0x00, - 0x2C, - 0x41, 0x58, 0x49, 0x4F, 0x44, 0x4C, 0x5F, 0x53, 0x4C, 0x4F, 0x54, 0x41, - 0x41, 0x58, 0x49, 0x4F, 0x44, 0x4C, 0x5F, 0x53, 0x4C, 0x4F, 0x54, 0x42, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, 0x00, - 0x00, - 0x00, - 0x6E, 0x6D, - 0x00, 0x00, - 0x00, 0x00 -}}; -// clang-format on -} // namespace aurora::card diff --git a/aurora-main/lib/card/SRAM.hpp b/aurora-main/lib/card/SRAM.hpp deleted file mode 100644 index b035dd6..0000000 --- a/aurora-main/lib/card/SRAM.hpp +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once - -#include -#include - -// Modified code taken from libogc - -/*------------------------------------------------------------- -system.h -- OS functions and initialization -Copyright (C) 2004 -Michael Wiedenbauer (shagkur) -Dave Murphy (WinterMute) -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: -1. The origin of this software must not be misrepresented; you -must not claim that you wrote the original software. If you use -this software in a product, an acknowledgment in the product -documentation would be appreciated but is not required. -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. -3. This notice may not be removed or altered from any source -distribution. --------------------------------------------------------------*/ - -namespace aurora::card { -#pragma pack(push, 1) -union SRAMFlags { - uint8_t Hex; - struct { - uint8_t : 2; - uint8_t sound : 1; // Audio settings; 0 = Mono, 1 = Stereo - uint8_t initialized : 1; // if 0, displays prompt to set language on boot and asks user to set options and time/date - uint8_t : 2; - uint8_t boot_menu : 1; // if 1, skips logo animation and boots into the system menu regardless of if there is a - // disc inserted - uint8_t progressive : 1; // if 1, automatically displays Progressive Scan prompt in games that support it - }; -}; - -union SRAM { - using FlashID = std::array, 2>; - - std::array p_SRAM; - struct // Stored configuration value from the system SRAM area - { - uint16_t checksum; // Holds the block checksum. - uint16_t checksum_inv; // Holds the inverse block checksum - uint32_t ead0; // Unknown attribute - uint32_t ead1; // Unknown attribute - uint32_t counter_bias; // Bias value for the realtime clock - int8_t display_offsetH; // Pixel offset for the VI - uint8_t ntd; // Unknown attribute - uint8_t lang; // Language of system - SRAMFlags flags; // Device and operations flag - - // Stored configuration value from the extended SRAM area - FlashID flash_id; // flash_id[2][12] 96bit memorycard unlock flash ID - uint32_t wirelessKbd_id; // Device ID of last connected wireless keyboard - std::array wirelessPad_id; // 16-bit device ID of last connected pad. - uint8_t dvderr_code; // last non-recoverable error from DVD interface - uint8_t __padding0; // reserved - std::array flashID_chksum; // 8-bit checksum of unlock flash ID - uint32_t __padding1; // padding - }; -}; -#pragma pack(pop) - -extern const SRAM g_SRAM; -} // namespace aurora::card diff --git a/aurora-main/lib/card/Util.cpp b/aurora-main/lib/card/Util.cpp deleted file mode 100644 index 0447183..0000000 --- a/aurora-main/lib/card/Util.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include - -#include "../internal.hpp" - -namespace aurora::card { -uint64_t getGCTime() { - time_t sysTime, tzDST; - - time(&sysTime); - - // Account for DST where needed - tm* gmTime = localtime(&sysTime); - if (gmTime->tm_isdst == 1) - tzDST = 3600; - else - tzDST = 0; - - // Lazy way to get local time in sec - gmTime = gmtime(&sysTime); - time_t tzDiff = sysTime - mktime(gmTime); - - return static_cast(sysTime + tzDiff + tzDST) - 0x386D4380; -} - -void calculateChecksumBE(const uint16_t* data, size_t len, uint16_t* checksum, uint16_t* checksumInv) { - *checksum = 0; - *checksumInv = 0; - for (size_t i = 0; i < len; ++i) { - *checksum += bswap(data[i]); - *checksumInv += bswap(static_cast(data[i] ^ 0xFFFF)); - } - - *checksum = bswap(*checksum); - *checksumInv = bswap(*checksumInv); - if (*checksum == 0xFFFF) - *checksum = 0; - if (*checksumInv == 0xFFFF) - *checksumInv = 0; -} - -} // namespace aurora::card diff --git a/aurora-main/lib/card/Util.hpp b/aurora-main/lib/card/Util.hpp deleted file mode 100644 index 0875d7e..0000000 --- a/aurora-main/lib/card/Util.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include -#include -#include - -#ifndef ENABLE_BITWISE_ENUM -#define ENABLE_BITWISE_ENUM(type) \ - constexpr type operator|(type a, type b) { \ - using T = std::underlying_type_t; \ - return type(static_cast(a) | static_cast(b)); \ - } \ - constexpr type operator&(type a, type b) { \ - using T = std::underlying_type_t; \ - return type(static_cast(a) & static_cast(b)); \ - } \ - constexpr type& operator|=(type& a, type b) { \ - using T = std::underlying_type_t; \ - a = type(static_cast(a) | static_cast(b)); \ - return a; \ - } \ - constexpr type& operator&=(type& a, type b) { \ - using T = std::underlying_type_t; \ - a = type(static_cast(a) & static_cast(b)); \ - return a; \ - } \ - constexpr type operator~(type key) { \ - using T = std::underlying_type_t; \ - return type(~static_cast(key)); \ - } \ - constexpr bool True(type key) { \ - using T = std::underlying_type_t; \ - return static_cast(key) != 0; \ - } \ - constexpr bool False(type key) { \ - using T = std::underlying_type_t; \ - return static_cast(key) == 0; \ - } -#endif - -#define ROUND_UP_8192(val) (((val) + 8191) & ~8191) - -namespace aurora::card { - -uint64_t getGCTime(); - -/** - * @brief calculateChecksum - * @param data - * @param len - * @param checksum - * @param checksumInv - */ -void calculateChecksumBE(const uint16_t* data, size_t len, uint16_t* checksum, uint16_t* checksumInv); - -#undef NOFILE - -enum class ECardResult { - CRC_MISMATCH = -1003, /* Extension enum for Retro's CRC check */ - FATAL_ERROR = -128, - ENCODING = -13, - NAMETOOLONG = -12, - INSSPACE = -9, - NOENT = -8, - EXIST = -7, - BROKEN = -6, - IOERROR = -5, - NOFILE = -4, - NOCARD = -3, - WRONGDEVICE = -2, - BUSY = -1, - READY = 0 -}; -} // namespace aurora::card diff --git a/aurora-main/lib/dawn/BackendBinding.cpp b/aurora-main/lib/dawn/BackendBinding.cpp deleted file mode 100644 index bb8fba4..0000000 --- a/aurora-main/lib/dawn/BackendBinding.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "BackendBinding.hpp" - -#include - -#if !defined(SDL_PLATFORM_MACOS) && !defined(SDL_PLATFORM_IOS) && !defined(SDL_PLATFORM_TVOS) -#include -#endif - -namespace aurora::webgpu::utils { -std::shared_ptr SetupWindowAndGetSurfaceDescriptorCocoa(SDL_Window* window); - -std::shared_ptr SetupWindowAndGetSurfaceDescriptor(SDL_Window* window) { -#if defined(SDL_PLATFORM_MACOS) || defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS) - return SetupWindowAndGetSurfaceDescriptorCocoa(window); -#else - const auto props = SDL_GetWindowProperties(window); -#if defined(SDL_PLATFORM_ANDROID) - std::shared_ptr desc = - std::make_shared(); - desc->window = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_ANDROID_WINDOW_POINTER, nullptr); - return std::move(desc); -#elif defined(SDL_PLATFORM_WIN32) - std::shared_ptr desc = std::make_shared(); - desc->hwnd = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr); - desc->hinstance = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WIN32_INSTANCE_POINTER, nullptr); - return std::move(desc); -#elif defined(SDL_PLATFORM_LINUX) - const char* driver = SDL_GetCurrentVideoDriver(); - if (SDL_strcmp(driver, "wayland") == 0) { - std::shared_ptr desc = std::make_shared(); - desc->display = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, nullptr); - desc->surface = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr); - return std::move(desc); - } - if (SDL_strcmp(driver, "x11") == 0) { - std::shared_ptr desc = std::make_shared(); - desc->display = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_X11_DISPLAY_POINTER, nullptr); - desc->window = SDL_GetNumberProperty(props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0); - return std::move(desc); - } -#endif - return nullptr; -#endif -} - -} // namespace aurora::webgpu::utils diff --git a/aurora-main/lib/dawn/BackendBinding.hpp b/aurora-main/lib/dawn/BackendBinding.hpp deleted file mode 100644 index ac49d5c..0000000 --- a/aurora-main/lib/dawn/BackendBinding.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include -#include - -struct SDL_Window; - -namespace aurora::webgpu::utils { - -std::shared_ptr SetupWindowAndGetSurfaceDescriptor(SDL_Window* window); - -} // namespace aurora::webgpu::utils diff --git a/aurora-main/lib/dawn/MetalBinding.mm b/aurora-main/lib/dawn/MetalBinding.mm deleted file mode 100644 index 33b3f65..0000000 --- a/aurora-main/lib/dawn/MetalBinding.mm +++ /dev/null @@ -1,44 +0,0 @@ -#include "BackendBinding.hpp" - -#import -#include -#include -#include - -namespace aurora::webgpu::utils { -namespace { -constexpr const char* MetalViewProperty = "aurora.window.metal_view"; - -void SDLCALL DestroyMetalView(void*, void* value) { - SDL_Metal_DestroyView(value); -} -} // namespace - -std::shared_ptr SetupWindowAndGetSurfaceDescriptorCocoa(SDL_Window* window) { - const auto properties = SDL_GetWindowProperties(window); - if (!properties) { - return nullptr; - } - auto view = SDL_GetPointerProperty(properties, MetalViewProperty, nullptr); - if (!view) { - view = SDL_Metal_CreateView(window); - if (!view) { - return nullptr; - } - // Own one view per window, not per WebGPU surface. Surface recovery must - // preserve the UIKit root and its controls (and the Cocoa Metal subview). - // SDL cleans window properties before destroying its native window. - // The cleanup callback also runs if setting the property fails. - if (!SDL_SetPointerPropertyWithCleanup(properties, MetalViewProperty, view, DestroyMetalView, nullptr)) { - return nullptr; - } - } - auto desc = std::make_shared(); - desc->layer = SDL_Metal_GetLayer(view); - if (!desc->layer) { - SDL_ClearProperty(properties, MetalViewProperty); - return nullptr; - } - return desc; -} -} // namespace aurora::webgpu::utils diff --git a/aurora-main/lib/dolphin/AR.cpp b/aurora-main/lib/dolphin/AR.cpp deleted file mode 100644 index c2cb3bc..0000000 --- a/aurora-main/lib/dolphin/AR.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include -#include "../internal.hpp" -#include "dolphin/os.h" - -static aurora::Module Log("aurora::ar"); - -static u32 AR_StackPointer; -static u32* AR_BlockLength; -static u32 AR_FreeBlocks; -static BOOL AR_init_flag; - -#define ARAM_STACK_START 0x4000; - -// ARAM emulation: allocate a large buffer to simulate the GameCube's Auxiliary RAM. -// ARAM "addresses" are offsets into this buffer. On GameCube, ARAM is 16 MB starting -// at a base address returned by ARInit. We emulate this by malloc'ing a buffer -// and using a simple bump allocator (matching ARAlloc behavior on real hardware). -static u8* sAramBuffer = nullptr; - -// Convert an ARAM "address" (offset) to a real host pointer -static u8* aramToHost(u32 aramAddr) { - if (!sAramBuffer || aramAddr >= aurora::g_config.mem2Size) { - return nullptr; - } - return sAramBuffer + aramAddr; -} - -u32 ARAlloc(u32 length) { - u32 tmp; - - ASSERTMSGLINE(430, !(length & 0x1F), "ARAlloc(): length is not multiple of 32bytes!"); - ASSERTMSGLINE(434, length <= (__AR_Size - __AR_StackPointer), "ARAlloc(): Out of ARAM!"); - ASSERTMSGLINE(435, __AR_FreeBlocks, "ARAlloc(): No more free blocks!"); - - tmp = AR_StackPointer; - AR_StackPointer += length; - *AR_BlockLength = length; - AR_BlockLength += 1; - AR_FreeBlocks -= 1; - return tmp; -} - -u32 ARFree(u32* length) { - AR_BlockLength -= 1; - if (length) { - *length = *AR_BlockLength; - } - AR_StackPointer -= *AR_BlockLength; - AR_FreeBlocks += 1; - return AR_StackPointer; -} - -BOOL ARCheckInit(void) { return AR_init_flag; } - -u32 ARInit(u32* stack_index_addr, u32 num_entries) { - if (aurora::g_config.mem2Size == 0) { - Log.warn("ARInit called but no mem2Size specified in AuroraConfig. ARAM will not be available!"); - return 0; - } - - if (AR_init_flag == TRUE) { - return ARAM_STACK_START; - } - - sAramBuffer = (u8*)calloc(1, aurora::g_config.mem2Size); - if (sAramBuffer) { - Log.debug("Initialized 0x{:X} bytes of ARAM!", aurora::g_config.mem2Size); - } else { - Log.fatal("Failed to allocate ARAM!"); - } - - AR_StackPointer = ARAM_STACK_START; - AR_FreeBlocks = num_entries; - AR_BlockLength = stack_index_addr; - - AR_init_flag = TRUE; - return AR_StackPointer; -} - -u32 ARGetSize(void) { return aurora::g_config.mem2Size; } - -#pragma mark ARQ -void ARQPostRequest(ARQRequest* request, u32 owner, u32 type, u32 priority, uintptr_t source, uintptr_t dest, - u32 length, ARQCallback callback) { - // Emulate ARAM DMA transfers using memcpy. - // type 0 = MRAM -> ARAM, type 1 = ARAM -> MRAM - if (type == ARAM_DIR_MRAM_TO_ARAM) { - // Main RAM -> ARAM: source is a host pointer (cast to u32), dest is an ARAM offset - u8* hostSrc = (u8*)(uintptr_t)source; - u8* aramDst = aramToHost(dest); - if (aramDst && hostSrc) { - memcpy(aramDst, hostSrc, length); - } - } else { - // ARAM -> Main RAM: source is an ARAM offset, dest is a host pointer (cast to u32) - u8* aramSrc = aramToHost(source); - u8* hostDst = (u8*)(uintptr_t)dest; - if (aramSrc && hostDst) { - memcpy(hostDst, aramSrc, length); - } - } - - // Immediately invoke the callback (synchronous on PC, no DMA latency) - if (callback) { - callback((uintptr_t)request); - } -} - -void ARQInit() { - // Nothing to do on PC - ARAM is initialized in ARInit -} - -void* ARGetStorageAddress() { - return sAramBuffer; -} diff --git a/aurora-main/lib/dolphin/card.cpp b/aurora-main/lib/dolphin/card.cpp deleted file mode 100644 index 81c450b..0000000 --- a/aurora-main/lib/dolphin/card.cpp +++ /dev/null @@ -1,742 +0,0 @@ -#include "dolphin/card.h" - -#include - -#include "../internal.hpp" -#include "dolphin/types.h" - -#include "../card/CardRawFile.hpp" -#include "../card/DolphinCardPath.hpp" -#include "../logging.hpp" -#include "../card/CardGciFolder.hpp" -#include "../fs_helper.hpp" - -namespace { -aurora::Module Log("aurora::card"); -std::array, 2> CardChannels = {{}}; -std::array cardPaths; - -constexpr uint16_t CARD_SECTOR_SIZE = 8192; - -const char* GetCardRegion() { - switch (aurora::g_gameName[3]) { - case 'E': - default: - return "USA"; - case 'P': - return "EUR"; - case 'J': - return "JAP"; - } -} - -#define GET_CARD(slot) CardChannels[slot] -#define CARD_USE_GCI_FOLDER SelectedFileType == CARD_GCIFOLDER -#define CARD_READY(slot) (CARD_USE_GCI_FOLDER ? true : std::filesystem::exists(CardChannels[slot]->cardFilename())) -#define CARD_STUB Log.debug("{} is stubbed.", __FUNCTION__); - -bool Initialized = false; -CARDFileType SelectedFileType = CARD_GCIFOLDER; -bool UseFastMode = false; - -void CopyKabuFileHandleToDolphin(const s32 chan, const aurora::card::FileHandle& handle, CARDFileInfo* fileInfo) { - fileInfo->chan = chan; - fileInfo->fileNo = handle.getFileNo(); - fileInfo->offset = handle.getOffset(); -} - -aurora::card::FileHandle CreateKabuFileHandleFromDolphin(const CARDFileInfo* fileInfo) { - return aurora::card::FileHandle{static_cast(fileInfo->fileNo), fileInfo->offset}; -} - -std::filesystem::path GetCardFullPath(const std::filesystem::path& path, const aurora::card::ECardSlot slot) { - if (path.empty()) - return ""; - - if (CARD_USE_GCI_FOLDER) { - return path / GetCardRegion() / (slot == aurora::card::ECardSlot::SlotA ? "Card A" : "Card B"); - } else { - return path / fmt::format("MemoryCard{}.{}.raw", slot == aurora::card::ECardSlot::SlotA ? "A" : "B", GetCardRegion()); - } -} -} // namespace - -extern "C" { - -void CopyKabuStatsToDolphin(const aurora::card::CardStat& kabuStats, CARDStat* stats) { - memcpy(stats->fileName, kabuStats.x0_fileName, std::size(kabuStats.x0_fileName)); - memcpy(stats->gameName, kabuStats.x28_gameName.data(), kabuStats.x28_gameName.size()); - memcpy(stats->company, kabuStats.x2c_company.data(), kabuStats.x2c_company.size()); - memcpy(stats->offsetIcon, kabuStats.x44_offsetIcon.data(), kabuStats.x44_offsetIcon.size()); - - stats->length = kabuStats.x20_length; - stats->time = kabuStats.x24_time; - stats->bannerFormat = kabuStats.x2e_bannerFormat; - stats->iconAddr = kabuStats.x30_iconAddr; - stats->iconFormat = kabuStats.x34_iconFormat; - stats->iconSpeed = kabuStats.x36_iconSpeed; - stats->commentAddr = kabuStats.x38_commentAddr; - stats->offsetBanner = kabuStats.x3c_offsetBanner; - stats->offsetBannerTlut = kabuStats.x40_offsetBannerTlut; - stats->offsetIconTlut = kabuStats.x64_offsetIconTlut; - stats->offsetData = kabuStats.x68_offsetData; -} - -void CopyDolphinStatsToKabu(aurora::card::CardStat& kabuStats, const CARDStat* stats) { - memcpy(kabuStats.x0_fileName, stats->fileName, std::size(kabuStats.x0_fileName)); - memcpy(kabuStats.x28_gameName.data(), stats->gameName, kabuStats.x28_gameName.size()); - memcpy(kabuStats.x2c_company.data(), stats->company, kabuStats.x2c_company.size()); - memcpy(kabuStats.x44_offsetIcon.data(), stats->offsetIcon, kabuStats.x44_offsetIcon.size()); - - kabuStats.x20_length = stats->length; - kabuStats.x24_time = stats->time; - kabuStats.x2e_bannerFormat = stats->bannerFormat; - kabuStats.x30_iconAddr = stats->iconAddr; - kabuStats.x34_iconFormat = stats->iconFormat; - kabuStats.x36_iconSpeed = stats->iconSpeed; - kabuStats.x38_commentAddr = stats->commentAddr; - kabuStats.x3c_offsetBanner = stats->offsetBanner; - kabuStats.x40_offsetBannerTlut = stats->offsetBannerTlut; - kabuStats.x64_offsetIconTlut = stats->offsetIconTlut; - kabuStats.x68_offsetData = stats->offsetData; -} - -void CARDDetectDolphin(const s32 chan) { - if (Initialized) { - Log.fatal("CARDDetectDolphin() called after CARDInit()!"); - } - - if (chan == 0 || chan == 1) { - cardPaths[chan] = - aurora::card::ResolveDolphinCardPath(static_cast(chan), GetCardRegion(), CARD_USE_GCI_FOLDER); - if (cardPaths[chan].empty()) { - Log.error("Failed to detect Dolphin Card!"); - return; - } - Log.info("Detected Dolphin Card at: {}", fs_path_to_string(cardPaths[chan])); - } else { - cardPaths[0] = aurora::card::ResolveDolphinCardPath(aurora::card::ECardSlot::SlotA, GetCardRegion(), CARD_USE_GCI_FOLDER); - cardPaths[1] = aurora::card::ResolveDolphinCardPath(aurora::card::ECardSlot::SlotB, GetCardRegion(), CARD_USE_GCI_FOLDER); - - if (cardPaths[0].empty() && cardPaths[1].empty()) { - Log.error("Failed to detect Dolphin Card!"); - return; - } - - Log.info( - "Detected Dolphin Card at: {} and {}", - fs_path_to_string(cardPaths[0]), - fs_path_to_string(cardPaths[1])); - } -} - -void CARDSetBasePath(const char* path, const s32 chan) { - if (Initialized) { - Log.fatal("CARDSetBasePath() called after CARDInit()!"); - } - - std::filesystem::path filePath(path); - - if (filePath.has_filename() && !std::filesystem::is_directory(filePath)) { - filePath = filePath.remove_filename(); - Log.warn("Path supplied a filename, discarding. New Path: {}", fs_path_to_string(filePath)); - } - - if (chan == 0 || chan == 1) { - cardPaths[chan] = GetCardFullPath(filePath, static_cast(chan)); - } else { - cardPaths[0] = GetCardFullPath(filePath, aurora::card::ECardSlot::SlotA); - cardPaths[1] = GetCardFullPath(filePath, aurora::card::ECardSlot::SlotB); - } -} - -void CARDSetLoadType(CARDFileType type) { - SelectedFileType = type; -} - -void CARDInit(const char* game, const char* maker) { - if (Initialized) { - return; - } - Initialized = true; - Log.info("CARD API Initialized BUILT <{} {}>", __DATE__, __TIME__); - - for (int i = 0; i < CardChannels.size(); ++i) { - switch (SelectedFileType) { - case CARD_RAWIMAGE: - CardChannels[i] = std::make_unique(); - break; - case CARD_GCIFOLDER: - CardChannels[i] = std::make_unique(); - break; - } - CardChannels[i]->InitCard(game, maker); - } - - std::filesystem::path cardWorkingDir; - if (aurora::g_config.userPath != nullptr) - cardWorkingDir = fs_path_from_string(aurora::g_config.userPath); - else - cardWorkingDir = std::filesystem::current_path(); - - bool loadedCard = false; - - for (int i = 0; i < 2; ++i) { - // use default working directory if no path was supplied for card - if (cardPaths[i].empty()) { - cardPaths[i] = GetCardFullPath(cardWorkingDir, static_cast(i)); - } - - const auto& curPath = cardPaths[i]; - - std::error_code ec; - if (std::filesystem::exists(curPath, ec) && CardChannels[i]->open(curPath)) { - loadedCard = true; - Log.info("Loaded GC Card Image: {}", fs_path_to_string(curPath)); - } else if (ec) { - Log.warn("Failed to inspect GC Card path '{}': {}", fs_path_to_string(curPath), ec.message()); - } else if (std::filesystem::exists(curPath, ec)) { - Log.warn("Failed to load GC Card Image: {}", fs_path_to_string(curPath)); - } - } - - // create a SlotA card if no cards were loaded - if (!loadedCard) { - CardChannels[0]->open(cardPaths[0]); - CardChannels[0]->format(aurora::card::ECardSlot::SlotA); - CardChannels[0]->close(); - CardChannels[0]->open(cardPaths[0]); - } -} - -void CARDSetGameAndMaker(const s32 chan, const char* game, const char* maker) { - if (chan < 0 || chan >= 2) { - return; - } - - CardChannels[chan]->setCurrentGame(game); - CardChannels[chan]->setCurrentMaker(maker); -} - -// TODO: Investigate if this is necessary. Do some games throw an error if CARD's fast mode can't be use? -BOOL CARDGetFastMode() { return UseFastMode; } - -BOOL CARDSetFastMode(const BOOL enable) { - const bool oldFast = UseFastMode; - UseFastMode = enable; - return oldFast; -} - -s32 CARDCheck(const s32 chan) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(chan)) - return CARD_RESULT_NOCARD; - - const auto& card = GET_CARD(chan); - - return static_cast(card->getError()); -} - -s32 CARDCheckAsync(const s32 chan, const CARDCallback callback) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(chan)) - return CARD_RESULT_NOCARD; - - const auto& card = GET_CARD(chan); - const auto res = static_cast(card->getError()); - callback(chan, res); - return static_cast(card->getError()); -} - -s32 CARDCheckEx(const s32 chan, s32* xferBytes [[maybe_unused]]) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(chan)) - return CARD_RESULT_NOCARD; - - const auto& card = GET_CARD(chan); - - return static_cast(card->getError()); -} - -s32 CARDCheckExAsync(const s32 chan, s32* xferBytes [[maybe_unused]], const CARDCallback callback) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - const auto& card = GET_CARD(chan); - const auto res = static_cast(card->getError()); - callback(chan, res); - return static_cast(card->getError()); -} - -s32 CARDCreate(const s32 chan, const char* fileName, const u32 size, CARDFileInfo* fileInfo) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(chan)) - return CARD_RESULT_NOCARD; - const auto& card = GET_CARD(chan); - - aurora::card::FileHandle handle; - auto res = card->createFile(fileName, size, handle); - if (res == aurora::card::ECardResult::READY) { - CopyKabuFileHandleToDolphin(chan, handle, fileInfo); - card->commit(); - } else - Log.error("Failed to create file: {}", fileName); - - return static_cast(res); -} - -s32 CARDCreateAsync(const s32 chan, const char* fileName, const u32 size, CARDFileInfo* fileInfo, - const CARDCallback callback) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - const auto res = CARDCreate(chan, fileName, size, fileInfo); - callback(chan, res); - return res; -} - -s32 CARDDelete(const s32 chan, const char* fileName) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(chan)) - return CARD_RESULT_NOCARD; - - const auto& card = GET_CARD(chan); - const auto res = card->deleteFile(fileName); - - if (res != aurora::card::ECardResult::READY) { - Log.error("Failed to delete file: {}", fileName); - } else { - card->commit(); - } - - return static_cast(res); -} - -s32 CARDDeleteAsync(const s32 chan, const char* fileName, const CARDCallback callback) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - const auto res = CARDDelete(chan, fileName); - callback(chan, res); - return res; -} - -s32 CARDFastDelete(const s32 chan, const s32 fileNo) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(chan)) - return CARD_RESULT_NOCARD; - - const auto& card = GET_CARD(chan); - const auto res = card->deleteFile(fileNo); - if (res != aurora::card::ECardResult::READY) { - Log.error("Failed to delete file at idx: {}", fileNo); - } else { - card->commit(); - } - - return static_cast(res); -} - -s32 CARDFastDeleteAsync(const s32 chan, const s32 fileNo, const CARDCallback callback) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - const auto res = CARDFastDelete(chan, fileNo); - callback(chan, res); - return res; -} - -s32 CARDFastOpen(const s32 chan, const s32 fileNo, CARDFileInfo* fileInfo) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(chan)) - return CARD_RESULT_NOCARD; - - const auto& card = GET_CARD(chan); - - aurora::card::FileHandle handle; - const auto res = card->openFile(fileNo, handle); - if (res == aurora::card::ECardResult::READY) - CopyKabuFileHandleToDolphin(chan, handle, fileInfo); - else - Log.error("Failed to open file at idx: {}", fileNo); - - return static_cast(res); -} - -s32 CARDFormat(s32 chan) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(chan)) - return CARD_RESULT_NOCARD; - - const auto& card = GET_CARD(chan); - card->format(static_cast(chan)); - card->commit(); - return CARD_RESULT_READY; -} - -s32 CARDFormatAsync(const s32 chan, const CARDCallback callback) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - const auto res = CARDFormat(chan); - callback(chan, res); - return res; -} - -s32 CARDFreeBlocks(const s32 chan, s32* byteNotUsed, s32* filesNotUsed) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(chan)) - return CARD_RESULT_NOCARD; - - const auto& card = GET_CARD(chan); - card->getFreeBlocks(*byteNotUsed, *filesNotUsed); - return CARD_RESULT_READY; -} - -s32 CARDGetAttributes(const s32 chan, const s32 fileNo [[maybe_unused]], u8* attr [[maybe_unused]]) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - // TODO: - CARD_STUB - return CARD_RESULT_READY; -} - -s32 CARDGetEncoding(const s32 chan, u16* encode) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(chan)) - return CARD_RESULT_NOCARD; - - const auto& card = GET_CARD(chan); - card->getEncoding(*encode); - return CARD_RESULT_READY; -} - -s32 CARDGetMemSize(const s32 chan, u16* size [[maybe_unused]]) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - // TODO: - CARD_STUB - return CARD_RESULT_READY; -} - -s32 CARDGetResultCode(const s32 chan) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(chan)) - return CARD_RESULT_NOCARD; - - const auto& card = GET_CARD(chan); - return static_cast(card->getError()); -} - -s32 CARDGetSectorSize(const s32 chan, u32* size) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(chan)) - return CARD_RESULT_NOCARD; - - *size = CARD_SECTOR_SIZE; - return CARD_RESULT_READY; -} - -s32 CARDGetSerialNo(const s32 chan, u64* serialNo) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(chan)) - return CARD_RESULT_NOCARD; - - const auto& card = GET_CARD(chan); - card->getSerial(*serialNo); - return CARD_RESULT_READY; -} - -s32 __CARDGetStatusEx(const s32 chan, const s32 fileNo [[maybe_unused]], CARDDir* dirent [[maybe_unused]]) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - // TODO: - CARD_STUB - return CARD_RESULT_READY; -} - -s32 CARDGetStatus(const s32 chan, s32 fileNo, CARDStat* stat) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(chan)) - return CARD_RESULT_NOCARD; - const auto& card = GET_CARD(chan); - - aurora::card::CardStat kabuStat; - const auto res = card->getStatus(fileNo, kabuStat); - if (res == aurora::card::ECardResult::READY) - CopyKabuStatsToDolphin(kabuStat, stat); - else - Log.error("Failed to get status of file at idx: {}", fileNo); - - return static_cast(res); -} - -s32 CARDGetXferredBytes(const s32 chan) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(chan)) - return CARD_RESULT_NOCARD; - // TODO: - CARD_STUB - return CARD_RESULT_READY; -} -// these two funcs are out of scope for aurora::card. stubbed for now -s32 CARDMount(const s32 chan, void* workArea [[maybe_unused]], CARDCallback detachCallback [[maybe_unused]]) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - - return CARD_RESULT_READY; -} -s32 CARDMountAsync(const s32 chan, void* workArea [[maybe_unused]], const CARDCallback detachCallback [[maybe_unused]], - const CARDCallback attachCallback [[maybe_unused]]) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - return CARD_RESULT_READY; -} - -s32 CARDOpen(const s32 chan, const char* fileName, CARDFileInfo* fileInfo) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(chan)) - return CARD_RESULT_NOCARD; - const auto& card = GET_CARD(chan); - - aurora::card::FileHandle handle; - const auto res = card->openFile(fileName, handle); - if (res == aurora::card::ECardResult::READY) - CopyKabuFileHandleToDolphin(chan, handle, fileInfo); - else - Log.error("Failed to open file: {}", fileName); - - return static_cast(res); -} - -BOOL CARDProbe(const s32 chan) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - const auto& card = GET_CARD(chan); - - aurora::card::ProbeResults probeData = card->probeCardFile(cardPaths[chan]); - return probeData.x0_error != aurora::card::ECardResult::NOCARD ? TRUE : FALSE; -} - -s32 CARDProbeEx(const s32 chan, s32* memSize, s32* sectorSize) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - const auto& card = GET_CARD(chan); - - // ReSharper disable once CppUseStructuredBinding - const aurora::card::ProbeResults probeData = card->probeCardFile(cardPaths[chan]); - *memSize = probeData.x4_cardSize; - *sectorSize = probeData.x8_sectorSize; - - return static_cast(probeData.x0_error); -} - -s32 CARDRename(const s32 chan, const char* oldName, const char* newName) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(chan)) - return CARD_RESULT_NOCARD; - const auto& card = GET_CARD(chan); - - return static_cast(card->renameFile(oldName, newName)); -} - -s32 CARDRenameAsync(const s32 chan, const char* oldName, const char* newName, const CARDCallback callback) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - const auto res = CARDRename(chan, oldName, newName); - callback(chan, res); - return res; -} - -s32 CARDSetAttributesAsync(const s32 chan, s32 fileNo [[maybe_unused]], u8 attr [[maybe_unused]], - CARDCallback callback [[maybe_unused]]) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - // TODO: - CARD_STUB - return CARD_RESULT_READY; -} - -s32 CARDSetAttributes(const s32 chan, s32 fileNo [[maybe_unused]], u8 attr [[maybe_unused]]) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - // TODO: - CARD_STUB - return CARD_RESULT_READY; -} - -s32 CARDSetStatus(const s32 chan, s32 fileNo, const CARDStat* stat) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(chan)) - return CARD_RESULT_NOCARD; - const auto& card = GET_CARD(chan); - - aurora::card::CardStat kabuStat; - CopyDolphinStatsToKabu(kabuStat, stat); - auto res = card->setStatus(fileNo, kabuStat); - if (res != aurora::card::ECardResult::READY) { - Log.error("Failed to set status of file at idx: {}", fileNo); - } else { - card->commit(); - } - - return static_cast(res); -} - -s32 __CARDSetStatusEx(const s32 chan, s32 fileNo [[maybe_unused]], CARDDir* dirent [[maybe_unused]]) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - // TODO: - CARD_STUB - return CARD_RESULT_READY; -} - -s32 CARDSetStatusAsync(const s32 chan, const s32 fileNo, const CARDStat* stat, const CARDCallback callback) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - const auto res = CARDSetStatus(chan, fileNo, stat); - callback(chan, res); - return res; -} - -s32 CARDUnmount(const s32 chan) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - // TODO: - return CARD_RESULT_NOCARD; -} - -s32 CARDGetCurrentMode(const s32 chan, u32* mode [[maybe_unused]]) { - if (chan < 0 || chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - // TODO: - return CARD_RESULT_NOCARD; -} - -s32 CARDCancel(CARDFileInfo* fileInfo [[maybe_unused]]) { - // TODO:ge - return CARD_RESULT_NOCARD; -} - -s32 CARDClose(CARDFileInfo* fileInfo) { - if (fileInfo->chan < 0 || fileInfo->chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(fileInfo->chan)) - return CARD_RESULT_NOCARD; - const auto& card = GET_CARD(fileInfo->chan); - - auto handle = CreateKabuFileHandleFromDolphin(fileInfo); - const auto res = card->closeFile(handle); - - if (res != aurora::card::ECardResult::READY) - Log.error("Failed to close file at idx: {}", fileInfo->fileNo); - - return static_cast(res); -} - -s32 CARDRead(const CARDFileInfo* fileInfo, void* addr, s32 length, const s32 offset) { - if (fileInfo->chan < 0 || fileInfo->chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(fileInfo->chan)) - return CARD_RESULT_NOCARD; - const auto& card = GET_CARD(fileInfo->chan); - - aurora::card::FileHandle handle = CreateKabuFileHandleFromDolphin(fileInfo); - - card->seek(handle, offset, aurora::card::SeekOrigin::Begin); - auto res = card->fileRead(handle, addr, length); - - if (res != aurora::card::ECardResult::READY) - Log.error("Failed to read {} bytes from card", length); - - return static_cast(res); -} - -s32 CARDReadAsync(const CARDFileInfo* fileInfo, void* addr, const s32 length, const s32 offset, - const CARDCallback callback) { - const auto res = CARDRead(fileInfo, addr, length, offset); - callback(fileInfo->chan, res); - return res; -} - -s32 CARDWrite(const CARDFileInfo* fileInfo, const void* addr, const s32 length, const s32 offset) { - if (fileInfo->chan < 0 || fileInfo->chan >= 2) { - return CARD_RESULT_FATAL_ERROR; - } - if (!CARD_READY(fileInfo->chan)) - return CARD_RESULT_NOCARD; - const auto& card = GET_CARD(fileInfo->chan); - - aurora::card::FileHandle handle = CreateKabuFileHandleFromDolphin(fileInfo); - - card->seek(handle, offset, aurora::card::SeekOrigin::Begin); - auto res = card->fileWrite(handle, addr, length); - - if (res != aurora::card::ECardResult::READY) { - Log.error("Failed to write {} bytes to card", length); - } else { - card->commit(); - } - - return static_cast(res); -} - -s32 CARDWriteAsync(const CARDFileInfo* fileInfo, const void* addr, const s32 length, const s32 offset, - const CARDCallback callback) { - const auto res = CARDWrite(fileInfo, addr, length, offset); - callback(fileInfo->chan, res); - return res; -} -} diff --git a/aurora-main/lib/dolphin/dvd/dvd.cpp b/aurora-main/lib/dolphin/dvd/dvd.cpp deleted file mode 100644 index 9a054b5..0000000 --- a/aurora-main/lib/dolphin/dvd/dvd.cpp +++ /dev/null @@ -1,1100 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "../../internal.hpp" - -namespace { - -struct FSTEntry { - std::string name; - bool isDir = false; - u32 parent = 0; - u32 nextOrLength = 0; -}; - -struct IterateContext { - std::vector* entries = nullptr; - std::vector> dirStack; -}; - -NodHandle* s_disc = nullptr; -NodHandle* s_partition = nullptr; -std::vector s_fstEntries; -s32 s_currentDir = 0; -std::string s_currentPath = "/"; -BOOL s_autoInvalidation = FALSE; -BOOL s_autoFatalMessaging = FALSE; -DVDDiskID s_diskID = {}; -DVDLowCallback s_resetCoverCallback = nullptr; -bool s_initialized = false; - -void clearState() { - if (s_partition != nullptr) { - nod_free(s_partition); - s_partition = nullptr; - } - if (s_disc != nullptr) { - nod_free(s_disc); - s_disc = nullptr; - } - s_fstEntries.clear(); - s_currentDir = 0; - s_currentPath = "/"; - s_diskID = {}; - s_initialized = false; -} - -bool isValidEntryIndex(s32 entry) { return entry >= 0 && static_cast(entry) < s_fstEntries.size(); } - -bool isAligned(const void* addr, uintptr_t align) { - return (reinterpret_cast(addr) & (align - 1)) == 0; -} - -int64_t sdlStreamReadAt(void* userData, uint64_t offset, void* out, size_t len) { - auto* io = static_cast(userData); - if (io == nullptr || out == nullptr || - offset > static_cast(std::numeric_limits::max())) { - return -1; - } - - if (SDL_SeekIO(io, static_cast(offset), SDL_IO_SEEK_SET) < 0) { - return -1; - } - - size_t total = 0; - auto* dst = static_cast(out); - while (total < len) { - const size_t read = SDL_ReadIO(io, dst + total, len - total); - if (read == 0) { - break; - } - total += read; - } - return static_cast(total); -} - -int64_t sdlStreamLen(void* userData) { - auto* io = static_cast(userData); - if (io == nullptr) { - return -1; - } - - const Sint64 size = SDL_GetIOSize(io); - return size < 0 ? -1 : static_cast(size); -} - -void sdlStreamClose(void* userData) { - auto* io = static_cast(userData); - if (io == nullptr) { - return; - } - SDL_CloseIO(io); -} - -u32 fstCallback(u32 index, NodNodeKind kind, const char* name, u32 size, void* userData) { - auto* ctx = static_cast(userData); - - while (!ctx->dirStack.empty() && index >= ctx->dirStack.back().second) { - ctx->dirStack.pop_back(); - } - - if (ctx->entries->size() <= index) { - ctx->entries->resize(index + 1); - } - - FSTEntry& entry = (*ctx->entries)[index]; - entry.name = (name != nullptr) ? name : ""; - entry.isDir = (kind == NOD_NODE_KIND_DIRECTORY); - entry.parent = ctx->dirStack.empty() ? 0 : ctx->dirStack.back().first; - entry.nextOrLength = size; - - if (entry.isDir) { - ctx->dirStack.emplace_back(index, size); - } - - return index + 1; -} - -bool rebuildFST() { - if (s_partition == nullptr) { - return false; - } - - s_fstEntries.clear(); - IterateContext ctx{}; - ctx.entries = &s_fstEntries; - nod_partition_iterate_fst(s_partition, fstCallback, &ctx); - - if (s_fstEntries.empty()) { - FSTEntry root; - root.name = ""; - root.isDir = true; - root.parent = 0; - root.nextOrLength = 1; - s_fstEntries.push_back(std::move(root)); - } - - s_fstEntries[0].name.clear(); - s_fstEntries[0].isDir = true; - s_fstEntries[0].parent = 0; - if (s_fstEntries[0].nextOrLength < 1 || s_fstEntries[0].nextOrLength > s_fstEntries.size()) { - s_fstEntries[0].nextOrLength = static_cast(s_fstEntries.size()); - } - return true; -} - -bool nameEqualsIgnoreCase(const std::string& lhs, const char* rhs, size_t rhsLen) { - if (lhs.size() != rhsLen) { - return false; - } - for (size_t i = 0; i < rhsLen; ++i) { - char lc = lhs[i]; - char rc = rhs[i]; - if (lc >= 'a' && lc <= 'z') { - lc = static_cast(lc - 'a' + 'A'); - } - if (rc >= 'a' && rc <= 'z') { - rc = static_cast(rc - 'a' + 'A'); - } - if (lc != rc) { - return false; - } - } - return true; -} - -s32 findInDir(s32 dirEntry, const char* name, size_t nameLen) { - if (!isValidEntryIndex(dirEntry) || !s_fstEntries[dirEntry].isDir) { - return -1; - } - - u32 childEnd = s_fstEntries[dirEntry].nextOrLength; - u32 i = static_cast(dirEntry) + 1; - while (i < childEnd && i < s_fstEntries.size()) { - if (nameEqualsIgnoreCase(s_fstEntries[i].name, name, nameLen)) { - return static_cast(i); - } - - if (s_fstEntries[i].isDir) { - u32 next = s_fstEntries[i].nextOrLength; - i = (next > i) ? next : i + 1; - } else { - ++i; - } - } - return -1; -} - -std::string buildDirPath(s32 entryNum) { - if (entryNum <= 0 || !isValidEntryIndex(entryNum)) { - return "/"; - } - - std::vector parts; - s32 cur = entryNum; - while (cur > 0 && isValidEntryIndex(cur)) { - parts.push_back(s_fstEntries[cur].name); - s32 parent = static_cast(s_fstEntries[cur].parent); - if (parent == cur) { - break; - } - cur = parent; - } - - std::string out = "/"; - for (auto it = parts.rbegin(); it != parts.rend(); ++it) { - out += *it; - out += '/'; - } - return out; -} - -s32 readFromHandle(NodHandle* handle, void* out, s32 length, s32 offset, u32* transferredOut) { - if (transferredOut != nullptr) { - *transferredOut = 0; - } - if (handle == nullptr || out == nullptr || length < 0 || offset < 0) { - return DVD_RESULT_FATAL_ERROR; - } - if (length == 0) { - return 0; - } - if (nod_seek(handle, offset, 0) < 0) { - return DVD_RESULT_FATAL_ERROR; - } - - u8* writePtr = static_cast(out); - s32 totalRead = 0; - s32 remaining = length; - while (remaining > 0) { - const int64_t read = nod_read(handle, writePtr + totalRead, static_cast(remaining)); - if (read < 0) { - return DVD_RESULT_FATAL_ERROR; - } - if (read == 0) { - break; - } - totalRead += static_cast(read); - remaining -= static_cast(read); - } - - if (transferredOut != nullptr) { - *transferredOut = static_cast(totalRead); - } - return totalRead; -} - -void setCommandResult(DVDCommandBlock* block, s32 state, u32 transferred) { - if (block == nullptr) { - return; - } - block->state = state; - block->transferredSize = transferred; -} - -s32 stateForResult(s32 result) { - if (result == DVD_RESULT_CANCELED) { - return DVD_STATE_CANCELED; - } - if (result == DVD_RESULT_IGNORED) { - return DVD_STATE_IGNORED; - } - return result >= 0 ? DVD_STATE_END : DVD_STATE_FATAL_ERROR; -} - -bool isCommandBlockIdle(const DVDCommandBlock* block) { - return block != nullptr && block->state != DVD_STATE_BUSY && block->state != DVD_STATE_WAITING; -} - -NodHandle* getCommandHandle(DVDCommandBlock* block) { - if (block != nullptr && block->userData != nullptr) { - return static_cast(block->userData); - } - return s_disc; -} - -void beginCommand(DVDCommandBlock* block, u32 command, void* addr, u32 length, u32 offset, DVDCBCallback callback) { - if (block == nullptr) { - return; - } - block->command = command; - block->addr = addr; - block->length = length; - block->offset = offset; - block->transferredSize = 0; - block->callback = callback; - block->state = DVD_STATE_BUSY; -} - -void finishCommand(DVDCommandBlock* block, s32 result, u32 transferred) { - setCommandResult(block, stateForResult(result), transferred); -} - -int completeImmediateCommand(DVDCommandBlock* block, u32 command, s32 result, u32 transferred, DVDCBCallback callback) { - beginCommand(block, command, nullptr, 0, 0, callback); - finishCommand(block, result, transferred); - if (callback != nullptr) { - callback(result, block); - } - return TRUE; -} - -void cbForReadAsync(s32 result, DVDCommandBlock* block) { - auto* fileInfo = reinterpret_cast(reinterpret_cast(block) - offsetof(DVDFileInfo, cb)); - ASSERTLINE(0x2ED, &fileInfo->cb == block); - if (fileInfo->callback != nullptr) { - fileInfo->callback(result, fileInfo); - } -} - -void cbForSeekAsync(s32 result, DVDCommandBlock* block) { - auto* fileInfo = reinterpret_cast(reinterpret_cast(block) - offsetof(DVDFileInfo, cb)); - ASSERTLINE(0x383, &fileInfo->cb == block); - if (fileInfo->callback != nullptr) { - fileInfo->callback(result, fileInfo); - } -} - -void cbForPrepareStreamAsync(s32 result, DVDCommandBlock* block) { - auto* fileInfo = reinterpret_cast(reinterpret_cast(block) - offsetof(DVDFileInfo, cb)); - ASSERTLINE(0x497, &fileInfo->cb == block); - if (fileInfo->callback != nullptr) { - fileInfo->callback(result, fileInfo); - } -} - -} // namespace - -extern "C" { - -bool aurora_dvd_open(const char* disc_path) { - if (disc_path == nullptr) { - return false; - } - - clearState(); - - SDL_IOStream* io = SDL_IOFromFile(disc_path, "rb"); - if (io == nullptr) { - return false; - } - - const NodDiscStream stream{ - .user_data = io, - .read_at = sdlStreamReadAt, - .stream_len = sdlStreamLen, - .close = sdlStreamClose, - }; - const NodDiscOptions options{ - .preloader_threads = 1, - }; - - NodResult result = nod_disc_open_stream(&stream, &options, &s_disc); - if (result != NOD_RESULT_OK || s_disc == nullptr) { - clearState(); - return false; - } - - result = nod_disc_open_partition_kind(s_disc, NOD_PARTITION_KIND_DATA, nullptr, &s_partition); - if (result != NOD_RESULT_OK || s_partition == nullptr) { - clearState(); - return false; - } - - NodDiscHeader header{}; - if (nod_disc_header(s_disc, &header) == NOD_RESULT_OK) { - std::memcpy(s_diskID.gameName, header.game_id, sizeof(s_diskID.gameName)); - std::memcpy(s_diskID.company, header.game_id + sizeof(s_diskID.gameName), sizeof(s_diskID.company)); - s_diskID.diskNumber = header.disc_num; - s_diskID.gameVersion = header.disc_version; - s_diskID.streaming = header.audio_streaming; - s_diskID.streamingBufSize = header.audio_stream_buf_size; - - std::memcpy(aurora::g_gameName, s_diskID.gameName, sizeof(s_diskID.gameName)); - } - - if (!rebuildFST()) { - clearState(); - return false; - } - - s_currentDir = 0; - s_currentPath = "/"; - s_initialized = true; - return true; -} - -void aurora_dvd_close(void) { clearState(); } - -void DVDInit(void) {} - -const u8* DVDGetDOLLocation(s32* out_size) { - if (s_partition == nullptr) { - *out_size = 0; - return nullptr; - } - - NodPartitionMeta meta{}; - - if (nod_partition_meta(s_partition, &meta) != NOD_RESULT_OK) { - *out_size = 0; - return nullptr; - } - - *out_size = meta.raw_dol.size; - return meta.raw_dol.data; -} - -int DVDReadAbsAsyncPrio(DVDCommandBlock* block, void* addr, s32 length, s32 offset, DVDCBCallback callback, s32 prio) { - (void)prio; - ASSERTMSGLINE(0x780, block, "DVDReadAbsAsync(): null pointer is specified to command block address."); - ASSERTMSGLINE(0x781, addr, "DVDReadAbsAsync(): null pointer is specified to addr."); - ASSERTMSGLINE(0x783, isAligned(addr, 32), "DVDReadAbsAsync(): address must be aligned with 32 byte boundary."); - ASSERTMSGLINE(0x785, !(length & (32 - 1)), "DVDReadAbsAsync(): length must be a multiple of 32."); - ASSERTMSGLINE(0x787, !(offset & (4 - 1)), "DVDReadAbsAsync(): offset must be a multiple of 4."); - ASSERTMSGLINE(0x789, length >= 0, "DVD read: negative value was specified to length of the read\n"); - - beginCommand(block, DVD_COMMAND_READ, addr, static_cast(length), static_cast(offset), callback); - u32 transferred = 0; - s32 result = readFromHandle(getCommandHandle(block), addr, length, offset, &transferred); - finishCommand(block, result, transferred); - if (callback != nullptr) { - callback(result, block); - } - const bool idle = isCommandBlockIdle(block); - ASSERTMSGLINE(0x793, idle, "DVDReadAbsAsync(): command block is used for processing previous request."); - return TRUE; -} - -int DVDSeekAbsAsyncPrio(DVDCommandBlock* block, s32 offset, DVDCBCallback callback, s32 prio) { - (void)prio; - ASSERTMSGLINE(0x7AA, block, "DVDSeekAbs(): null pointer is specified to command block address."); - ASSERTMSGLINE(0x7AC, !(offset & (4 - 1)), "DVDSeekAbs(): offset must be a multiple of 4."); - - beginCommand(block, DVD_COMMAND_SEEK, nullptr, 0, static_cast(offset), callback); - NodHandle* handle = getCommandHandle(block); - const int64_t seek = handle != nullptr ? nod_seek(handle, static_cast(offset), 0) : -1; - const s32 result = (seek < 0) ? DVD_RESULT_FATAL_ERROR : DVD_RESULT_GOOD; - finishCommand(block, result, 0); - if (callback != nullptr) { - callback(result, block); - } - const bool idle = isCommandBlockIdle(block); - ASSERTMSGLINE(0x7B3, idle, "DVDSeekAbs(): command block is used for processing previous request."); - return TRUE; -} - -int DVDReadAbsAsyncForBS(DVDCommandBlock* block, void* addr, s32 length, s32 offset, DVDCBCallback callback) { - const int result = DVDReadAbsAsyncPrio(block, addr, length, offset, callback, 2); - if (result != FALSE && block != nullptr) { - block->command = DVD_COMMAND_BSREAD; - } - return result; -} - -int DVDReadDiskID(DVDCommandBlock* block, DVDDiskID* diskID, DVDCBCallback callback) { - if (diskID != nullptr) { - *diskID = s_diskID; - } - if (block != nullptr) { - setCommandResult(block, DVD_STATE_END, 0); - } - if (callback != nullptr) { - callback(DVD_RESULT_GOOD, block); - } - return TRUE; -} - -int DVDPrepareStreamAbsAsync(DVDCommandBlock* block, u32 length, u32 offset, DVDCBCallback callback) { - const bool idle = isCommandBlockIdle(block); - if (block == nullptr || !idle) { - return FALSE; - } - beginCommand(block, DVD_COMMAND_INITSTREAM, nullptr, length, offset, callback); - finishCommand(block, DVD_RESULT_IGNORED, 0); - if (callback != nullptr) { - callback(DVD_RESULT_IGNORED, block); - } - return TRUE; -} - -int DVDCancelStreamAsync(DVDCommandBlock* block, DVDCBCallback callback) { - if (block != nullptr) { - block->state = DVD_STATE_CANCELED; - } - if (callback != nullptr) { - callback(DVD_RESULT_CANCELED, block); - } - return TRUE; -} - -s32 DVDCancelStream(DVDCommandBlock* block) { - if (block != nullptr) { - block->state = DVD_STATE_CANCELED; - } - return DVD_RESULT_GOOD; -} - -int DVDStopStreamAtEndAsync(DVDCommandBlock* block, DVDCBCallback callback) { - if (block != nullptr) { - setCommandResult(block, DVD_STATE_END, 0); - } - if (callback != nullptr) { - callback(DVD_RESULT_GOOD, block); - } - return TRUE; -} - -s32 DVDStopStreamAtEnd(DVDCommandBlock* block) { - if (block != nullptr) { - setCommandResult(block, DVD_STATE_END, 0); - } - return DVD_RESULT_GOOD; -} - -int DVDGetStreamErrorStatusAsync(DVDCommandBlock* block, DVDCBCallback callback) { - if (block == nullptr || !isCommandBlockIdle(block)) { - return FALSE; - } - return completeImmediateCommand(block, DVD_COMMAND_REQUEST_AUDIO_ERROR, DVD_RESULT_IGNORED, 0, callback); -} - -s32 DVDGetStreamErrorStatus(DVDCommandBlock* block) { - (void)block; - return DVD_RESULT_IGNORED; -} - -int DVDGetStreamPlayAddrAsync(DVDCommandBlock* block, DVDCBCallback callback) { - if (block == nullptr || !isCommandBlockIdle(block)) { - return FALSE; - } - return completeImmediateCommand(block, DVD_COMMAND_REQUEST_PLAY_ADDR, DVD_RESULT_IGNORED, 0, callback); -} - -s32 DVDGetStreamPlayAddr(DVDCommandBlock* block) { - (void)block; - return 0; -} - -int DVDGetStreamStartAddrAsync(DVDCommandBlock* block, DVDCBCallback callback) { - if (block == nullptr || !isCommandBlockIdle(block)) { - return FALSE; - } - return completeImmediateCommand(block, DVD_COMMAND_REQUEST_START_ADDR, DVD_RESULT_IGNORED, 0, callback); -} - -s32 DVDGetStreamStartAddr(DVDCommandBlock* block) { - (void)block; - return 0; -} - -int DVDGetStreamLengthAsync(DVDCommandBlock* block, DVDCBCallback callback) { - if (block == nullptr || !isCommandBlockIdle(block)) { - return FALSE; - } - return completeImmediateCommand(block, DVD_COMMAND_REQUEST_LENGTH, DVD_RESULT_IGNORED, 0, callback); -} - -s32 DVDGetStreamLength(DVDCommandBlock* block) { - (void)block; - return 0; -} - -int DVDChangeDiskAsyncForBS(DVDCommandBlock* block, DVDCBCallback callback) { - ASSERTMSGLINE(0xA1F, block, "DVDChangeDiskAsyncForBS(): null pointer is specified to command block address."); - const bool idle = isCommandBlockIdle(block); - ASSERTMSGLINE(0xA25, idle, "DVDChangeDiskAsyncForBS(): command block is used for processing previous request."); - if (block == nullptr || !idle) { - return FALSE; - } - return completeImmediateCommand(block, DVD_COMMAND_BS_CHANGE_DISK, DVD_RESULT_IGNORED, 0, callback); -} - -int DVDChangeDiskAsync(DVDCommandBlock* block, DVDDiskID* id, DVDCBCallback callback) { - (void)id; - return DVDChangeDiskAsyncForBS(block, callback); -} - -s32 DVDChangeDisk(DVDCommandBlock* block, DVDDiskID* id) { - (void)block; - (void)id; - return DVD_RESULT_IGNORED; -} - -int DVDStopMotorAsync(DVDCommandBlock* block, DVDCBCallback callback) { - if (block != nullptr) { - setCommandResult(block, DVD_STATE_END, 0); - } - if (callback != nullptr) { - callback(DVD_RESULT_GOOD, block); - } - return TRUE; -} - -s32 DVDStopMotor(DVDCommandBlock* block) { - (void)block; - return DVD_RESULT_GOOD; -} - -int DVDInquiryAsync(DVDCommandBlock* block, DVDDriveInfo* info, DVDCBCallback callback) { - if (info != nullptr) { - std::memset(info, 0, sizeof(*info)); - } - if (block != nullptr) { - setCommandResult(block, DVD_STATE_END, 0); - } - if (callback != nullptr) { - callback(DVD_RESULT_GOOD, block); - } - return TRUE; -} - -s32 DVDInquiry(DVDCommandBlock* block, DVDDriveInfo* info) { - DVDInquiryAsync(block, info, nullptr); - return DVD_RESULT_GOOD; -} - -void DVDReset(void) {} - -int DVDResetRequired(void) { return FALSE; } - -s32 DVDGetCommandBlockStatus(const DVDCommandBlock* block) { - if (block == nullptr) { - return DVD_STATE_END; - } - return block->state; -} - -s32 DVDGetDriveStatus(void) { return s_initialized ? DVD_STATE_END : DVD_STATE_NO_DISK; } - -BOOL DVDSetAutoInvalidation(BOOL autoInval) { - BOOL prev = s_autoInvalidation; - s_autoInvalidation = autoInval; - return prev; -} - -void DVDPause(void) {} - -void DVDResume(void) {} - -int DVDCancelAsync(DVDCommandBlock* block, DVDCBCallback callback) { - if (block != nullptr) { - block->state = DVD_STATE_CANCELED; - } - if (callback != nullptr) { - callback(DVD_RESULT_GOOD, block); - } - return TRUE; -} - -s32 DVDCancel(volatile DVDCommandBlock* block) { - if (block != nullptr) { - block->state = DVD_STATE_CANCELED; - } - return DVD_RESULT_GOOD; -} - -int DVDCancelAllAsync(DVDCBCallback callback) { - if (callback != nullptr) { - callback(DVD_RESULT_CANCELED, nullptr); - } - return TRUE; -} - -s32 DVDCancelAll(void) { return DVD_RESULT_GOOD; } - -DVDDiskID* DVDGetCurrentDiskID(void) { return &s_diskID; } - -BOOL DVDCheckDisk(void) { return s_initialized ? TRUE : FALSE; } - -int DVDSetAutoFatalMessaging(BOOL enable) { - const BOOL prev = s_autoFatalMessaging; - s_autoFatalMessaging = enable; - return prev; -} - -s32 DVDConvertPathToEntrynum(const char* pathPtr) { - if (!s_initialized || pathPtr == nullptr || s_fstEntries.empty()) { - return -1; - } - - s32 current = 0; - const char* p = pathPtr; - if (*p == '/') { - ++p; - } else { - current = s_currentDir; - } - - while (*p != '\0') { - while (*p == '/') { - ++p; - } - if (*p == '\0') { - break; - } - - if (!isValidEntryIndex(current) || !s_fstEntries[current].isDir) { - return -1; - } - - const char* compEnd = p; - while (*compEnd != '\0' && *compEnd != '/') { - ++compEnd; - } - size_t compLen = static_cast(compEnd - p); - - if (compLen == 1 && p[0] == '.') { - // no-op - } else if (compLen == 2 && p[0] == '.' && p[1] == '.') { - current = static_cast(s_fstEntries[current].parent); - } else { - const s32 found = findInDir(current, p, compLen); - if (found < 0) { - return -1; - } - current = found; - } - p = compEnd; - } - - return current; -} - -BOOL DVDFastOpen(s32 entrynum, DVDFileInfo* fileInfo) { - if (!s_initialized || fileInfo == nullptr || !isValidEntryIndex(entrynum) || s_partition == nullptr) { - return FALSE; - } - if (s_fstEntries[entrynum].isDir) { - return FALSE; - } - - std::memset(fileInfo, 0, sizeof(*fileInfo)); - fileInfo->startAddr = 0; - fileInfo->length = s_fstEntries[entrynum].nextOrLength; - - NodHandle* handle = nullptr; - NodResult result = nod_partition_open_file(s_partition, static_cast(entrynum), &handle); - if (result != NOD_RESULT_OK || handle == nullptr) { - return FALSE; - } - - fileInfo->cb.userData = handle; - fileInfo->cb.state = DVD_STATE_END; - return TRUE; -} - -BOOL DVDOpen(const char* fileName, DVDFileInfo* fileInfo) { - s32 entrynum = DVDConvertPathToEntrynum(fileName); - if (entrynum < 0) { - return FALSE; - } - return DVDFastOpen(entrynum, fileInfo); -} - -BOOL DVDClose(DVDFileInfo* fileInfo) { - if (fileInfo == nullptr) { - return FALSE; - } - if (fileInfo->cb.userData != nullptr) { - nod_free(static_cast(fileInfo->cb.userData)); - fileInfo->cb.userData = nullptr; - } - fileInfo->cb.state = DVD_STATE_END; - return TRUE; -} - -BOOL DVDGetCurrentDir(char* path, u32 maxlen) { - if (path == nullptr || maxlen == 0) { - return FALSE; - } - const size_t len = s_currentPath.size(); - const size_t copyLen = (len >= maxlen) ? (maxlen - 1) : len; - std::memcpy(path, s_currentPath.c_str(), copyLen); - path[copyLen] = '\0'; - return TRUE; -} - -BOOL DVDChangeDir(const char* dirName) { - s32 entry = DVDConvertPathToEntrynum(dirName); - if (!isValidEntryIndex(entry) || !s_fstEntries[entry].isDir) { - return FALSE; - } - s_currentDir = entry; - s_currentPath = buildDirPath(entry); - return TRUE; -} - -BOOL DVDReadAsyncPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset, DVDCallback callback, s32 prio) { - ASSERTMSGLINE(0x2C7, fileInfo, "DVDReadAsync(): null pointer is specified to file info address "); - ASSERTMSGLINE(0x2C8, addr, "DVDReadAsync(): null pointer is specified to addr "); - - ASSERTMSGLINE(0x2D5, (0 <= offset) && (offset <= static_cast(fileInfo->length)), - "DVDReadAsync(): specified area is out of the file "); - ASSERTMSGLINE(0x2DB, (0 <= offset + length) && (offset + length < static_cast(fileInfo->length) + DVD_MIN_TRANSFER_SIZE), - "DVDReadAsync(): specified area is out of the file "); - - fileInfo->callback = callback; - DVDReadAbsAsyncPrio(&fileInfo->cb, addr, length, offset, cbForReadAsync, prio); - return TRUE; -} - -s32 DVDReadPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset, s32 prio) { - if (!DVDReadAsyncPrio(fileInfo, addr, length, offset, nullptr, prio)) { - return DVD_RESULT_FATAL_ERROR; - } - if (fileInfo->cb.state == DVD_STATE_END) { - return static_cast(fileInfo->cb.transferredSize); - } - if (fileInfo->cb.state == DVD_STATE_CANCELED) { - return DVD_RESULT_CANCELED; - } - return DVD_RESULT_FATAL_ERROR; -} - -int DVDSeekAsyncPrio(DVDFileInfo* fileInfo, s32 offset, void (*callback)(s32, DVDFileInfo*), s32 prio) { - ASSERTMSGLINE(0x368, fileInfo, "DVDSeek(): null pointer is specified to file info address "); - ASSERTMSGLINE(0x36C, !(offset & 3), "DVDSeek(): offset must be multiple of 4 byte "); - - ASSERTMSGLINE(0x371, (0 <= offset) && (offset <= static_cast(fileInfo->length)), - "DVDSeek(): offset is out of the file "); - - fileInfo->callback = callback; - DVDSeekAbsAsyncPrio(&fileInfo->cb, offset, cbForSeekAsync, prio); - return 1; -} - -s32 DVDSeekPrio(DVDFileInfo* fileInfo, s32 offset, s32 prio) { - if (!DVDSeekAsyncPrio(fileInfo, offset, nullptr, prio)) { - return DVD_RESULT_FATAL_ERROR; - } - if (fileInfo->cb.state == DVD_STATE_END) { - return DVD_RESULT_GOOD; - } - if (fileInfo->cb.state == DVD_STATE_CANCELED) { - return DVD_RESULT_CANCELED; - } - return DVD_RESULT_FATAL_ERROR; -} - -s32 DVDGetFileInfoStatus(const DVDFileInfo* fileInfo) { - if (fileInfo == nullptr) { - return DVD_STATE_END; - } - return fileInfo->cb.state; -} - -BOOL DVDFastOpenDir(s32 entrynum, DVDDir* dir) { - if (!isValidEntryIndex(entrynum) || dir == nullptr || !s_fstEntries[entrynum].isDir) { - return FALSE; - } - dir->entryNum = static_cast(entrynum); - dir->location = static_cast(entrynum) + 1; - dir->next = s_fstEntries[entrynum].nextOrLength; - return TRUE; -} - -int DVDOpenDir(const char* dirName, DVDDir* dir) { - s32 entrynum = DVDConvertPathToEntrynum(dirName); - if (entrynum < 0) { - return FALSE; - } - return DVDFastOpenDir(entrynum, dir); -} - -int DVDReadDir(DVDDir* dir, DVDDirEntry* dirent) { - if (dir == nullptr || dirent == nullptr) { - return FALSE; - } - if (dir->location >= dir->next || dir->location >= s_fstEntries.size()) { - return FALSE; - } - - const u32 index = dir->location; - FSTEntry& entry = s_fstEntries[index]; - dirent->entryNum = index; - dirent->isDir = entry.isDir ? TRUE : FALSE; - dirent->name = entry.name.empty() ? nullptr : entry.name.data(); - - if (entry.isDir) { - const u32 next = entry.nextOrLength; - dir->location = (next > index) ? next : index + 1; - } else { - dir->location = index + 1; - } - return TRUE; -} - -int DVDCloseDir(DVDDir* dir) { - (void)dir; - return TRUE; -} - -void DVDRewindDir(DVDDir* dir) { - if (dir == nullptr) { - return; - } - dir->location = dir->entryNum + 1; -} - -void* DVDGetFSTLocation(void) { - if (s_fstEntries.empty()) { - return nullptr; - } - return s_fstEntries.data(); -} - -BOOL DVDPrepareStreamAsync(DVDFileInfo* fileInfo, u32 length, u32 offset, DVDCallback callback) { - ASSERTMSGLINE(0x46C, fileInfo, "DVDPrepareStreamAsync(): NULL file info was specified"); - if (fileInfo == nullptr || fileInfo->cb.userData == nullptr) { - return FALSE; - } - if (length == 0) { - length = fileInfo->length - offset; - } - const uint64_t end = static_cast(offset) + static_cast(length); - if (!(offset < fileInfo->length && end <= fileInfo->length)) { - OSPanic(__FILE__, 0x484, - "DVDPrepareStreamAsync(): The area specified (offset(0x%x), length(0x%x)) is out of the file", offset, - length); - return FALSE; - } - fileInfo->callback = callback; - return DVDPrepareStreamAbsAsync(&fileInfo->cb, length, offset, cbForPrepareStreamAsync); -} - -s32 DVDPrepareStream(DVDFileInfo* fileInfo, u32 length, u32 offset) { - (void)fileInfo; - (void)length; - (void)offset; - return DVD_RESULT_IGNORED; -} - -s32 DVDGetTransferredSize(DVDFileInfo* fileinfo) { - if (fileinfo == nullptr) { - return 0; - } - return static_cast(fileinfo->cb.transferredSize); -} - -int DVDCompareDiskID(const DVDDiskID* id1, const DVDDiskID* id2) { - if (id1 == nullptr || id2 == nullptr) { - return FALSE; - } - - if (id1->gameName[0] != 0 && id2->gameName[0] != 0 && std::memcmp(id1->gameName, id2->gameName, 4) != 0) { - return 0; - } - - if (id1->company[0] == 0 || id2->company[0] == 0 || std::memcmp(id1->company, id2->company, 2) != 0) { - return 0; - } - - if (id1->diskNumber != 0xFF && id2->diskNumber != 0xFF && id1->diskNumber != id2->diskNumber) { - return 0; - } - - if (id1->gameVersion != 0xFF && id2->gameVersion != 0xFF && id1->gameVersion != id2->gameVersion) { - return 0; - } - - return 1; -} - -DVDDiskID* DVDGenerateDiskID(DVDDiskID* id, const char* game, const char* company, u8 diskNum, u8 version) { - if (id == nullptr) { - return nullptr; - } - std::memset(id, 0, sizeof(*id)); - if (game != nullptr) { - std::memcpy(id->gameName, game, 4); - } - if (company != nullptr) { - std::memcpy(id->company, company, 2); - } - id->diskNumber = diskNum; - id->gameVersion = version; - return id; -} - -BOOL DVDLowRead(void* addr, u32 length, u32 offset, DVDLowCallback callback) { - u32 transferred = 0; - s32 result = readFromHandle(s_disc, addr, static_cast(length), static_cast(offset), &transferred); - if (callback != nullptr) { - callback(static_cast((result >= 0) ? DVD_RESULT_GOOD : DVD_RESULT_FATAL_ERROR)); - } - return TRUE; -} - -BOOL DVDLowSeek(u32 offset, DVDLowCallback callback) { - const int64_t seek = s_disc != nullptr ? nod_seek(s_disc, static_cast(offset), 0) : -1; - if (callback != nullptr) { - callback(static_cast((seek >= 0) ? DVD_RESULT_GOOD : DVD_RESULT_FATAL_ERROR)); - } - return TRUE; -} - -BOOL DVDLowWaitCoverClose(DVDLowCallback callback) { - if (callback != nullptr) { - callback(0); - } - return TRUE; -} - -BOOL DVDLowReadDiskID(DVDDiskID* diskID, DVDLowCallback callback) { - if (diskID != nullptr) { - *diskID = s_diskID; - } - if (callback != nullptr) { - callback(0); - } - return TRUE; -} - -BOOL DVDLowStopMotor(DVDLowCallback callback) { - if (callback != nullptr) { - callback(0); - } - return TRUE; -} - -BOOL DVDLowRequestError(DVDLowCallback callback) { - if (callback != nullptr) { - callback(0); - } - return TRUE; -} - -BOOL DVDLowInquiry(DVDDriveInfo* info, DVDLowCallback callback) { - if (info != nullptr) { - std::memset(info, 0, sizeof(*info)); - } - if (callback != nullptr) { - callback(0); - } - return TRUE; -} - -BOOL DVDLowAudioStream(u32 subcmd, u32 length, u32 offset, DVDLowCallback callback) { - (void)subcmd; - (void)length; - (void)offset; - if (callback != nullptr) { - callback(0); - } - return TRUE; -} - -BOOL DVDLowRequestAudioStatus(u32 subcmd, DVDLowCallback callback) { - (void)subcmd; - if (callback != nullptr) { - callback(0); - } - return TRUE; -} - -BOOL DVDLowAudioBufferConfig(BOOL enable, u32 size, DVDLowCallback callback) { - (void)enable; - (void)size; - if (callback != nullptr) { - callback(0); - } - return TRUE; -} - -void DVDLowReset(void) { - if (s_resetCoverCallback != nullptr) { - s_resetCoverCallback(0); - } -} - -DVDLowCallback DVDLowSetResetCoverCallback(DVDLowCallback callback) { - DVDLowCallback previous = s_resetCoverCallback; - s_resetCoverCallback = callback; - return previous; -} - -BOOL DVDLowBreak(void) { return TRUE; } - -DVDLowCallback DVDLowClearCallback(void) { - DVDLowCallback previous = s_resetCoverCallback; - s_resetCoverCallback = nullptr; - return previous; -} - -u32 DVDLowGetCoverStatus(void) { return s_initialized ? 0 : 1; } - -void DVDDumpWaitingQueue(void) {} - -} // extern "C" diff --git a/aurora-main/lib/dolphin/gd/GDAurora.cpp b/aurora-main/lib/dolphin/gd/GDAurora.cpp deleted file mode 100644 index 14bbbee..0000000 --- a/aurora-main/lib/dolphin/gd/GDAurora.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include - -#include "gd.hpp" -#include "dolphin/gd/GDAurora.h" -#include "dolphin/gd/GDBase.h" -#include "dolphin/gx/GXAurora.h" - -static void GDWriteString(const char* label) { - auto length = strlen(label); - - if (length > std::numeric_limits::max()) { - Log.warn("Debug marker size over u16 max, truncating"); - length = std::numeric_limits::max(); - } - - GDWrite_u16(length); - GDWrite_data(label, length); -} - -void GDPushDebugGroup(const char* label) { - GDWriteAuroraCmd(GX_LOAD_AURORA_DEBUG_GROUP_PUSH); - GDWriteString(label); -} - -void GDPopDebugGroup() { - GDWriteAuroraCmd(GX_LOAD_AURORA_DEBUG_GROUP_POP); -} - -void GDInsertDebugMarker(const char* label) { - GDWriteAuroraCmd(GX_LOAD_AURORA_DEBUG_MARKER_INSERT); - GDWriteString(label); -} diff --git a/aurora-main/lib/dolphin/gd/GDBase.cpp b/aurora-main/lib/dolphin/gd/GDBase.cpp deleted file mode 100644 index da0bdb5..0000000 --- a/aurora-main/lib/dolphin/gd/GDBase.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include -#include "gd.hpp" - -GDLObj* __GDCurrentDL = NULL; -static GDOverflowCb overflowcb = NULL; - -void GDInitGDLObj(GDLObj* dl, void* start, u32 length) { - ASSERTMSGLINE(40, !((u32)start & 0x1F), "start must be aligned to 32 bytes"); - ASSERTMSGLINE(41, !((u32)length & 0x1F), "length must be aligned to 32 bytes"); - dl->start = (u8*)start; - dl->ptr = (u8*)start; - dl->top = (u8*)start + length; - dl->length = length; -} - -void GDFlushCurrToMem(void) { - DCFlushRange(__GDCurrentDL->start, __GDCurrentDL->length); -} - -void GDPadCurr32(void) { - uintptr_t n; - - n = (uintptr_t)__GDCurrentDL->ptr & 0x1F; - if (n != 0) { - for (; n < 32; n = n + 1) { - __GDWrite(0); - } - } -} - -void GDOverflowed(void) { - if (overflowcb) { - (*overflowcb)(); - } else { - Log.fatal("GDWrite: display list overflowed"); - } -} - -void GDSetOverflowCallback(GDOverflowCb callback) { - overflowcb = callback; -} - -GDOverflowCb GDGetOverflowCallback(void) { - return overflowcb; -} diff --git a/aurora-main/lib/dolphin/gd/GDGeometry.cpp b/aurora-main/lib/dolphin/gd/GDGeometry.cpp deleted file mode 100644 index 194a1b5..0000000 --- a/aurora-main/lib/dolphin/gd/GDGeometry.cpp +++ /dev/null @@ -1,435 +0,0 @@ -#include -#include -#include - -#include "dolphin/gx/GXAurora.h" - -void GDSetVtxDescv(const GXVtxDescList* attrPtr) { - u32 nnorms = 0; - u32 ncols = 0; - u32 ntexs = 0; - u32 pnMtxIdx = GX_NONE; - u32 txMtxIdxMask = 0; - u32 posn = GX_DIRECT; - u32 norm = GX_NONE; - u32 col0 = GX_NONE; - u32 col1 = GX_NONE; - u32 tex0 = GX_NONE; - u32 tex1 = GX_NONE; - u32 tex2 = GX_NONE; - u32 tex3 = GX_NONE; - u32 tex4 = GX_NONE; - u32 tex5 = GX_NONE; - u32 tex6 = GX_NONE; - u32 tex7 = GX_NONE; - - for (; attrPtr->attr != GX_VA_NULL; ++attrPtr) { - ASSERTMSGLINE(91, attrPtr->attr >= GX_VA_PNMTXIDX && attrPtr->attr <= GX_VA_MAX_ATTR, "GDSetVtxDescv: invalid attribute"); - ASSERTMSGLINE(95, attrPtr->type >= GX_NONE && attrPtr->type <= GX_INDEX16, "GDSetVtxDescv: invalid type"); - - ASSERTMSGLINE(101, attrPtr->attr >= GX_VA_PNMTXIDX && attrPtr->attr <= GX_VA_TEX7MTXIDX ? (attrPtr->type == 0 || attrPtr->type == 1) : TRUE, "GDSetVtxDescv: invalid type for given attribute"); - - switch (attrPtr->attr) { - case GX_VA_PNMTXIDX: - pnMtxIdx = attrPtr->type; - break; - case GX_VA_TEX0MTXIDX: - txMtxIdxMask = (txMtxIdxMask & ~0x1) | (attrPtr->type << 0); - break; - case GX_VA_TEX1MTXIDX: - txMtxIdxMask = (txMtxIdxMask & ~0x2) | (attrPtr->type << 1); - break; - case GX_VA_TEX2MTXIDX: - txMtxIdxMask = (txMtxIdxMask & ~0x4) | (attrPtr->type << 2); - break; - case GX_VA_TEX3MTXIDX: - txMtxIdxMask = (txMtxIdxMask & ~0x8) | (attrPtr->type << 3); - break; - case GX_VA_TEX4MTXIDX: - txMtxIdxMask = (txMtxIdxMask & ~0x10) | (attrPtr->type << 4); - break; - case GX_VA_TEX5MTXIDX: - txMtxIdxMask = (txMtxIdxMask & ~0x20) | (attrPtr->type << 5); - break; - case GX_VA_TEX6MTXIDX: - txMtxIdxMask = (txMtxIdxMask & ~0x40) | (attrPtr->type << 6); - break; - case GX_VA_TEX7MTXIDX: - txMtxIdxMask = (txMtxIdxMask & ~0x80) | (attrPtr->type << 7); - break; - case GX_VA_POS: - posn = attrPtr->type; - break; - case GX_VA_NRM: - if (attrPtr->type != GX_NONE) { - norm = attrPtr->type; - nnorms = 1; - } - break; - case GX_VA_NBT: - if (attrPtr->type != GX_NONE) { - norm = attrPtr->type; - nnorms = 2; - } - break; - case GX_VA_CLR0: - col0 = attrPtr->type; - ncols += (col0 != GX_NONE); - break; - case GX_VA_CLR1: - col1 = attrPtr->type; - ncols += (col1 != GX_NONE); - break; - case GX_VA_TEX0: - tex0 = attrPtr->type; - ntexs += (tex0 != GX_NONE); - break; - case GX_VA_TEX1: - tex1 = attrPtr->type; - ntexs += (tex1 != GX_NONE); - break; - case GX_VA_TEX2: - tex2 = attrPtr->type; - ntexs += (tex2 != GX_NONE); - break; - case GX_VA_TEX3: - tex3 = attrPtr->type; - ntexs += (tex3 != GX_NONE); - break; - case GX_VA_TEX4: - tex4 = attrPtr->type; - ntexs += (tex4 != GX_NONE); - break; - case GX_VA_TEX5: - tex5 = attrPtr->type; - ntexs += (tex5 != GX_NONE); - break; - case GX_VA_TEX6: - tex6 = attrPtr->type; - ntexs += (tex6 != GX_NONE); - break; - case GX_VA_TEX7: - tex7 = attrPtr->type; - ntexs += (tex7 != GX_NONE); - break; - } - } - - GDWriteCPCmd(CP_REG_VCD_LO_ID, CP_REG_VCD_LO(pnMtxIdx, txMtxIdxMask, posn, norm, col0, col1)); - GDWriteCPCmd(CP_REG_VCD_HI_ID, CP_REG_VCD_HI(tex0, tex1, tex2, tex3, tex4, tex5, tex6, tex7)); - GDWriteXFCmd(XF_REG_INVERTEXSPEC_ID, XF_REG_INVTXSPEC(ncols, nnorms, ntexs)); -} - -void GDSetVtxAttrFmtv(GXVtxFmt vtxfmt, const GXVtxAttrFmtList* list) { - u32 posCnt = GX_POS_XYZ; - u32 posType = GX_F32; - u32 posFrac = 0; - - u32 nrmCnt = GX_NRM_XYZ; - u32 nrmType = GX_F32; - u32 nrmIdx3 = 0; - - u32 c0Cnt = GX_CLR_RGBA; - u32 c0Type = GX_RGBA8; - - u32 c1Cnt = GX_CLR_RGBA; - u32 c1Type = GX_RGBA8; - - u32 tx0Cnt = GX_TEX_ST; - u32 tx0Type = GX_F32; - u32 tx0Frac = 0; - - u32 tx1Cnt = GX_TEX_ST; - u32 tx1Type = GX_F32; - u32 tx1Frac = 0; - - u32 tx2Cnt = GX_TEX_ST; - u32 tx2Type = GX_F32; - u32 tx2Frac = 0; - - u32 tx3Cnt = GX_TEX_ST; - u32 tx3Type = GX_F32; - u32 tx3Frac = 0; - - u32 tx4Cnt = GX_TEX_ST; - u32 tx4Type = GX_F32; - u32 tx4Frac = 0; - - u32 tx5Cnt = GX_TEX_ST; - u32 tx5Type = GX_F32; - u32 tx5Frac = 0; - - u32 tx6Cnt = GX_TEX_ST; - u32 tx6Type = GX_F32; - u32 tx6Frac = 0; - - u32 tx7Cnt = GX_TEX_ST; - u32 tx7Type = GX_F32; - u32 tx7Frac = 0; - - ASSERTMSGLINE(221, vtxfmt < GX_MAX_VTXFMT, "GDSetVtxAttrFmtv: invalid vtx fmt"); - - for (; list->attr != GX_VA_NULL; ++list) { - ASSERTMSGLINE(226, list->attr >= GX_VA_POS && list->attr <= GX_VA_TEX7, "GDSetVtxAttrFmtv: invalid attribute"); - ASSERTMSGLINE(227, list->frac < 32, "GDSetVtxAttrFmtv: invalid frac value"); - - switch (list->attr) { - case GX_VA_POS: - posCnt = list->cnt; - posType = list->type; - posFrac = list->frac; - break; - case GX_VA_NRM: - case GX_VA_NBT: - nrmType = list->type; - if (list->cnt == GX_NRM_NBT3) { - nrmCnt = GX_NRM_NBT; - nrmIdx3 = 1; - } else { - nrmCnt = list->cnt; - nrmIdx3 = 0; - } - break; - case GX_VA_CLR0: - c0Cnt = list->cnt; - c0Type = list->type; - break; - case GX_VA_CLR1: - c1Cnt = list->cnt; - c1Type = list->type; - break; - case GX_VA_TEX0: - tx0Cnt = list->cnt; - tx0Type = list->type; - tx0Frac = list->frac; - break; - case GX_VA_TEX1: - tx1Cnt = list->cnt; - tx1Type = list->type; - tx1Frac = list->frac; - break; - case GX_VA_TEX2: - tx2Cnt = list->cnt; - tx2Type = list->type; - tx2Frac = list->frac; - break; - case GX_VA_TEX3: - tx3Cnt = list->cnt; - tx3Type = list->type; - tx3Frac = list->frac; - break; - case GX_VA_TEX4: - tx4Cnt = list->cnt; - tx4Type = list->type; - tx4Frac = list->frac; - break; - case GX_VA_TEX5: - tx5Cnt = list->cnt; - tx5Type = list->type; - tx5Frac = list->frac; - break; - case GX_VA_TEX6: - tx6Cnt = list->cnt; - tx6Type = list->type; - tx6Frac = list->frac; - break; - case GX_VA_TEX7: - tx7Cnt = list->cnt; - tx7Type = list->type; - tx7Frac = list->frac; - } - } - - GDWriteCPCmd(vtxfmt + CP_REG_VAT_GRP0_ID, CP_REG_VAT_GRP0(posCnt, posType, posFrac, nrmCnt, nrmType, c0Cnt, c0Type, c1Cnt, c1Type, tx0Cnt, tx0Type, tx0Frac, 1, nrmIdx3)); - GDWriteCPCmd(vtxfmt + CP_REG_VAT_GRP1_ID, CP_REG_VAT_GRP1(tx1Cnt, tx1Type, tx1Frac, tx2Cnt, tx2Type, tx2Frac, tx3Cnt, tx3Type, tx3Frac, tx4Cnt, tx4Type, 1)); - GDWriteCPCmd(vtxfmt + CP_REG_VAT_GRP2_ID, CP_REG_VAT_GRP2(tx4Frac, tx5Cnt, tx5Type, tx5Frac, tx6Cnt, tx6Type, tx6Frac, tx7Cnt, tx7Type, tx7Frac)); -} - -void GDSetArraySized(GXAttr attr, void* base_ptr, u32 size, u8 stride, bool le) { - s32 cpAttr; - if (attr == GX_VA_NBT) { - cpAttr = 1; - } else { - cpAttr = attr - GX_VA_POS; - } - - assert((cpAttr & ~0xF) == 0); - - GDWriteAuroraCmd(cpAttr + GX_LOAD_AURORA_ARRAYBASE); - GDWrite_u64((u64)base_ptr); - GDWrite_u32(size); - GDWrite_u8(le ? 1 : 0); - - GDWriteCPCmd(cpAttr + CP_REG_ARRAYSTRIDE_ID, stride); -} - -void GDSetArray(GXAttr, void*, u8) { - OSPanic(__FILE__, __LINE__, "GDSetArray is not supported on Aurora"); -} - -void GDSetArrayRaw(GXAttr, u32, u8) { - OSPanic(__FILE__, __LINE__, "GDSetArrayRaw is not supported on Aurora"); -} - -void GDPatchArrayPtr(void* base_ptr) { - GDWrite_u32(OSCachedToPhysical(base_ptr)); -} - -void GDSetTexCoordGen(GXTexCoordID dst_coord, GXTexGenType func, GXTexGenSrc src_param, u8 normalize, u32 postmtx) { - u32 form; - u32 tgType; - u32 proj; - u32 row; - u32 embossRow; - u32 embossLit; - - form = 0; - proj = 0; - row = 5; - embossRow = 5; - embossLit = 0; - - ASSERTMSGLINE(432, dst_coord < GX_MAX_TEXCOORD, "GDSetTexCoordGen: invalid texcoord ID"); - - switch(src_param) { - case GX_TG_POS: - row = 0; - form = 1; - break; - case GX_TG_NRM: - row = 1; - form = 1; - break; - case GX_TG_BINRM: - row = 3; - form = 1; - break; - case GX_TG_TANGENT: - row = 4; - form = 1; - break; - case GX_TG_COLOR0: - row = 2; - break; - case GX_TG_COLOR1: - row = 2; - break; - case GX_TG_TEX0: - row = 5; - break; - case GX_TG_TEX1: - row = 6; - break; - case GX_TG_TEX2: - row = 7; - break; - case GX_TG_TEX3: - row = 8; - break; - case GX_TG_TEX4: - row = 9; - break; - case GX_TG_TEX5: - row = 10; - break; - case GX_TG_TEX6: - row = 11; - break; - case GX_TG_TEX7: - row = 12; - break; - case GX_TG_TEXCOORD0: - embossRow = 0; - break; - case GX_TG_TEXCOORD1: - embossRow = 1; - break; - case GX_TG_TEXCOORD2: - embossRow = 2; - break; - case GX_TG_TEXCOORD3: - embossRow = 3; - break; - case GX_TG_TEXCOORD4: - embossRow = 4; - break; - case GX_TG_TEXCOORD5: - embossRow = 5; - break; - case GX_TG_TEXCOORD6: - embossRow = 6; - break; - default: - ASSERTMSGLINE(457, 0, "GDSetTexCoordGen: invalid texgen source"); - break; - } - - switch (func) { - case GX_TG_MTX2x4: - tgType = 0; - break; - case GX_TG_MTX3x4: - tgType = 0; - proj = 1; - break; - case GX_TG_BUMP0: - case GX_TG_BUMP1: - case GX_TG_BUMP2: - case GX_TG_BUMP3: - case GX_TG_BUMP4: - case GX_TG_BUMP5: - case GX_TG_BUMP6: - case GX_TG_BUMP7: - ASSERTMSGLINE(481, src_param >= GX_TG_TEXCOORD0 && src_param <= GX_TG_TEXCOORD6, "GDSetTexCoordGen: invalid emboss source"); - tgType = 1; - embossLit = func - GX_TG_BUMP0; - break; - case GX_TG_SRTG: - if (src_param == GX_TG_COLOR0) { - tgType = 2; - } else { - tgType = 3; - } - break; - default: - ASSERTMSGLINE(495, 0, "GDSetTexCoordGen: invalid texgen function"); - break; - } - - GDWriteXFCmd(dst_coord + XF_REG_TEX0_ID, XF_REG_TEX(proj, form, tgType, row, embossRow, embossLit)); - GDWriteXFCmd(dst_coord + XF_REG_DUALTEX0_ID, XF_REG_DUALTEX(postmtx - 0x40, normalize)); -} - -void GDSetCullMode(GXCullMode mode) { - static u8 cm2hw[4] = { 0, 2, 1, 3 }; - - GDWriteBPCmd(0xFE00C000); - GDWriteBPCmd(cm2hw[mode] << 14); -} - -void GDSetGenMode(u8 nTexGens, u8 nChans, u8 nTevs) { - GDWriteBPCmd(0xFE003C3F); - GDWriteBPCmd(BP_GEN_MODE(nTexGens, nChans, nTevs - 1, 0, 0)); - - GDWriteXFCmd(XF_REG_NUMCOLORS_ID, nChans); - GDWriteXFCmd(XF_REG_NUMTEX_ID, nTexGens); -} - -void GDSetGenMode2(u8 nTexGens, u8 nChans, u8 nTevs, u8 nInds, GXCullMode cm) { - static u8 cm2hw[4] = { 0, 2, 1, 3 }; - - GDWriteBPCmd(0xFE07FC3F); - GDWriteBPCmd(BP_GEN_MODE(nTexGens, nChans, nTevs - 1, cm2hw[cm], nInds)); - - GDWriteXFCmd(XF_REG_NUMCOLORS_ID, nChans); - GDWriteXFCmd(XF_REG_NUMTEX_ID, nTexGens); -} - -void GDSetLPSize(u8 lineWidth, u8 pointSize, GXTexOffset lineOffset, GXTexOffset pointOffset, u8 lineHalfAspect) { - GDWriteBPCmd(BP_LP_SIZE(lineWidth, pointSize, lineOffset, pointOffset, lineHalfAspect, 0x22)); -} - -void GDSetCoPlanar(u8 enable) { - GDWriteBPCmd(0xFE080000); - GDWriteBPCmd(enable << 19); -} diff --git a/aurora-main/lib/dolphin/gd/GDIndirect.cpp b/aurora-main/lib/dolphin/gd/GDIndirect.cpp deleted file mode 100644 index 50add72..0000000 --- a/aurora-main/lib/dolphin/gd/GDIndirect.cpp +++ /dev/null @@ -1,270 +0,0 @@ -#include -#include - -void GDSetTevIndirect(GXTevStageID tev_stage, GXIndTexStageID ind_stage, - GXIndTexFormat format, GXIndTexBiasSel bias_sel, - GXIndTexMtxID matrix_sel, GXIndTexWrap wrap_s, - GXIndTexWrap wrap_t, u8 add_prev, u8 utc_lod, - GXIndTexAlphaSel alpha_sel) { - GDWriteBPCmd(BP_TEV_INDIRECT( - ind_stage & 3, - format & 3, - bias_sel & 7, - alpha_sel & 3, - matrix_sel & 0xF, - wrap_s & 7, - wrap_t & 7, - utc_lod & 1, - add_prev & 1, - 0x10 + (tev_stage & 0xF) - )); -} - -void GDSetIndTexMtx(GXIndTexMtxID mtx_id, const f32 offset[2][3], s8 scale_exp) { - u32 id_offset; - - switch (mtx_id) { - case GX_ITM_0: - id_offset = 0; - break; - case GX_ITM_1: - id_offset = 3; - break; - case GX_ITM_2: - id_offset = 6; - break; - default: - ASSERTMSGLINE(111, 0, "GDSetIndTexMtx: Invalid matrix id"); - break; - } - - scale_exp += 17; - - GDWriteBPCmd(BP_IND_MTX( - (s32)(offset[0][0] * 0x400) & 0x7FF, - (s32)(offset[1][0] * 0x400) & 0x7FF, - scale_exp & 3, - 6 + id_offset - )); - - GDWriteBPCmd(BP_IND_MTX( - (s32)(offset[0][1] * 0x400) & 0x7FF, - (s32)(offset[1][1] * 0x400) & 0x7FF, - (scale_exp >> 2) & 3, - 7 + id_offset - )); - - GDWriteBPCmd(BP_IND_MTX( - (s32)(offset[0][2] * 0x400) & 0x7FF, - (s32)(offset[1][2] * 0x400) & 0x7FF, - (scale_exp >> 4) & 3, - 8 + id_offset - )); -} - -void GDSetIndTexCoordScale(GXIndTexStageID indStageEven, GXIndTexScale scaleS0, - GXIndTexScale scaleT0, GXIndTexScale scaleS1, - GXIndTexScale scaleT1) { - GDWriteBPCmd(BP_IND_TEXCOORD_SCALE( - scaleS0 & 0xF, - scaleT0 & 0xF, - scaleS1 & 0xF, - scaleT1 & 0xF, - 0x25 + ((indStageEven >> 1) & 1) - )); -} - -void GDSetIndTexOrder(GXTexCoordID texCoord0, GXTexMapID texMap0, - GXTexCoordID texCoord1, GXTexMapID texMap1, - GXTexCoordID texCoord2, GXTexMapID texMap2, - GXTexCoordID texCoord3, GXTexMapID texMap3) { - GDWriteBPCmd(BP_IND_TEX_ORDER( - texMap0 & 7, - texCoord0 & 7, - texMap1 & 7, - texCoord1 & 7, - texMap2 & 7, - texCoord2 & 7, - texMap3 & 7, - texCoord3 & 7, - 0x27 - )); -} - -void GDSetTevDirect(GXTevStageID tev_stage) { - GDSetTevIndirect(tev_stage, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_NONE, GX_ITM_OFF, GX_ITW_OFF, GX_ITW_OFF, 0, 0, GX_ITBA_OFF); -} - -void GDSetTevIndWarp(GXTevStageID tev_stage, GXIndTexStageID ind_stage, u8 signed_offset, u8 replace_mode, GXIndTexMtxID matrix_sel) { - GXIndTexWrap wrap; - wrap = replace_mode ? GX_ITW_0 : GX_ITW_OFF; - - GDSetTevIndirect(tev_stage, - ind_stage, - GX_ITF_8, - signed_offset ? GX_ITB_STU : GX_ITB_NONE, - matrix_sel, - wrap, - wrap, - 0, - 0, - GX_ITBA_OFF); -} - -void GDSetTevIndTile(GXTevStageID tev_stage, GXIndTexStageID ind_stage, - u16 tilesize_s, u16 tilesize_t, u16 tilespacing_s, - u16 tilespacing_t, GXIndTexFormat format, - GXIndTexMtxID matrix_sel, GXIndTexBiasSel bias_sel, - GXIndTexAlphaSel alpha_sel) { - GXIndTexWrap wrap_s; - GXIndTexWrap wrap_t; - f32 mtx[2][3]; - - switch (tilesize_s) { - case 256: - wrap_s = GX_ITW_256; - break; - case 128: - wrap_s = GX_ITW_128; - break; - case 64: - wrap_s = GX_ITW_64; - break; - case 32: - wrap_s = GX_ITW_32; - break; - case 16: - wrap_s = GX_ITW_16; - break; - default: - ASSERTMSGLINE(268, 0, "GDSetTevIndTile: Invalid tilesize for S coordinate"); - wrap_s = GX_ITW_OFF; - break; - } - - switch (tilesize_t) { - case 256: - wrap_t = GX_ITW_256; - break; - case 128: - wrap_t = GX_ITW_128; - break; - case 64: - wrap_t = GX_ITW_64; - break; - case 32: - wrap_t = GX_ITW_32; - break; - case 16: - wrap_t = GX_ITW_16; - break; - default: - ASSERTMSGLINE(280, 0, "GDSetTevIndTile: Invalid tilesize for T coordinate"); - wrap_t = GX_ITW_OFF; - break; - } - - mtx[0][0] = (f32)tilespacing_s / 0x400; - mtx[0][1] = mtx[0][2] = 0.0f; - - mtx[1][1] = (f32)tilespacing_t / 0x400; - mtx[1][0] = mtx[1][2] = 0.0f; - GDSetIndTexMtx(matrix_sel, mtx, 10); - - GDSetTevIndirect(tev_stage, - ind_stage, - format, - bias_sel, - matrix_sel, - wrap_s, - wrap_t, - 0, - 1, - alpha_sel); -} - -void GDSetTevIndBumpST(GXTevStageID tev_stage, GXIndTexStageID ind_stage, GXIndTexMtxID matrix_sel) { - GXIndTexMtxID sm; - GXIndTexMtxID tm; - - switch(matrix_sel) { - case GX_ITM_0: - sm = GX_ITM_S0; - tm = GX_ITM_T0; - break; - case GX_ITM_1: - sm = GX_ITM_S1; - tm = GX_ITM_T1; - break; - case GX_ITM_2: - sm = GX_ITM_S2; - tm = GX_ITM_T2; - break; - default: - ASSERTMSGLINE(332, 0, "GDSetTevIndBumpST: Invalid matrix selection"); - break; - } - - GDSetTevIndirect(tev_stage, - ind_stage, - GX_ITF_8, - GX_ITB_ST, - sm, - GX_ITW_0, - GX_ITW_0, - 0, - 0, - GX_ITBA_OFF); - - GDSetTevIndirect((GXTevStageID)(tev_stage + 1), - ind_stage, - GX_ITF_8, - GX_ITB_ST, - tm, - GX_ITW_0, - GX_ITW_0, - 1, - 0, - GX_ITBA_OFF); - - GDSetTevIndirect((GXTevStageID)(tev_stage + 2), - ind_stage, - GX_ITF_8, - GX_ITB_NONE, - GX_ITM_OFF, - GX_ITW_OFF, - GX_ITW_OFF, - 1, - 0, - GX_ITBA_OFF); -} - -void GDSetTevIndBumpXYZ(GXTevStageID tev_stage, GXIndTexStageID ind_stage, GXIndTexMtxID matrix_sel) { - GDSetTevIndirect(tev_stage, - ind_stage, - GX_ITF_8, - GX_ITB_STU, - matrix_sel, - GX_ITW_OFF, - GX_ITW_OFF, - 0, - 0, - GX_ITBA_OFF); -} - -void GDSetTevIndRepeat(GXTevStageID tev_stage) { - GDSetTevIndirect(tev_stage, - GX_INDTEXSTAGE0, - GX_ITF_8, - GX_ITB_NONE, - GX_ITM_OFF, - GX_ITW_0, - GX_ITW_0, - 1, - 0, - GX_ITBA_OFF); -} - -void __GDSetIndTexMask(u32 mask) { - GDWriteBPCmd(BP_IND_MASK(mask & 0xFF, 0xF)); -} diff --git a/aurora-main/lib/dolphin/gd/GDLight.cpp b/aurora-main/lib/dolphin/gd/GDLight.cpp deleted file mode 100644 index c036032..0000000 --- a/aurora-main/lib/dolphin/gd/GDLight.cpp +++ /dev/null @@ -1,216 +0,0 @@ -#include -#include -#include -#include - -void GDSetLightAttn(GXLightID light, f32 a0, f32 a1, f32 a2, f32 k0, f32 k1, f32 k2) { - GDWriteXFCmdHdr(__GDLightID2Offset(light) + XF_LIGHT_ATTN_ID, 6); - GDWrite_f32(a0); - GDWrite_f32(a1); - GDWrite_f32(a2); - GDWrite_f32(k0); - GDWrite_f32(k1); - GDWrite_f32(k2); -} - -void GDSetLightSpot(GXLightID light, f32 cutoff, GXSpotFn spot_func) { - f32 a0; - f32 a1; - f32 a2; - f32 r; - f32 d; - f32 cr; - - if (cutoff <= 0.0f || cutoff > 90.0f) { - spot_func = GX_SP_OFF; - } - - r = std::numbers::pi_v * cutoff / 180.0f; - cr = cosf(r); - - switch(spot_func) { - case GX_SP_FLAT: - a0 = -1000.0f * cr; - a1 = 1000.0f; - a2 = 0.0f; - break; - case GX_SP_COS: - a0 = -cr / (1.0f - cr); - a1 = 1.0f / (1.0f - cr); - a2 = 0.0f; - break; - case GX_SP_COS2: - a0 = 0.0f; - a1 = -cr / (1.0f - cr); - a2 = 1.0f / (1.0f - cr); - break; - case GX_SP_SHARP: - d = (1.0f - cr) * (1.0f - cr); - a0 = (cr * (cr - 2.0f)) / d; - a1 = 2.0f / d; - a2 = -1.0f / d; - break; - case GX_SP_RING1: - d = (1.0f - cr) * (1.0f - cr); - a0 = (-4.0f * cr) / d; - a1 = (4.0f * (1.0f + cr)) / d; - a2 = -4.0f / d; - break; - case GX_SP_RING2: - d = (1.0f - cr) * (1.0f - cr); - a0 = 1.0f - (2.0f * cr * cr) / d; - a1 = (4.0f * cr) / d; - a2 = -2.0f / d; - break; - case GX_SP_OFF: - default: - a0 = 1.0f; - a1 = 0.0f; - a2 = 0.0f; - break; - } - - GDWriteXFCmdHdr(__GDLightID2Offset(light) + XF_LIGHT_ATTN_ID, 3); - GDWrite_f32(a0); - GDWrite_f32(a1); - GDWrite_f32(a2); -} - -void GDSetLightDistAttn(GXLightID light, f32 ref_dist, f32 ref_br, GXDistAttnFn dist_func) { - f32 k0; - f32 k1; - f32 k2; - - if (ref_dist < 0.0f || ref_br <= 0.0f || ref_br >= 1.0f) { - dist_func = GX_DA_OFF; - } - - switch (dist_func) { - case GX_DA_GENTLE: - k0 = 1.0f; - k1 = (1.0f - ref_br) / (ref_br * ref_dist); - k2 = 0.0f; - break; - case GX_DA_MEDIUM: - k0 = 1.0f; - k1 = (0.5f * (1.0f - ref_br)) / (ref_br * ref_dist); - k2 = (0.5f * (1.0f - ref_br)) / (ref_dist * (ref_br * ref_dist)); - break; - case GX_DA_STEEP: - k0 = 1.0f; - k1 = 0.0f; - k2 = (1.0f - ref_br) / (ref_dist * (ref_br * ref_dist)); - break; - case GX_DA_OFF: - default: - k0 = 1.0f; - k1 = 0.0f; - k2 = 0.0f; - break; - } - - GDWriteXFCmdHdr(__GDLightID2Offset(light) + XF_LIGHT_DISTATTN_ID, 3); - GDWrite_f32(k0); - GDWrite_f32(k1); - GDWrite_f32(k2); -} - -void GDSetLightColor(GXLightID light, GXColor color) { - GDWriteXFCmd(__GDLightID2Offset(light) + XF_LIGHT_COLOR_ID, color.r << 24 | color.g << 16 | color.b << 8 | color.a); -} - -void GDSetLightPos(GXLightID light, f32 x, f32 y, f32 z) { - GDWriteXFCmdHdr(__GDLightID2Offset(light) + XF_LIGHT_POS_ID, 3); - GDWrite_f32(x); - GDWrite_f32(y); - GDWrite_f32(z); -} - -void GDSetLightDir(GXLightID light, f32 nx, f32 ny, f32 nz) { - GDWriteXFCmdHdr(__GDLightID2Offset(light) + XF_LIGHT_DIR_ID, 3); - GDWrite_f32(nx); - GDWrite_f32(ny); - GDWrite_f32(nz); -} - -void GDSetSpecularDirHA(GXLightID light, f32 nx, f32 ny, f32 nz, f32 hx, f32 hy, f32 hz) { - f32 px; - f32 py; - f32 pz; - px = 1000000000000000000.0f * -nx; - py = 1000000000000000000.0f * -ny; - pz = 1000000000000000000.0f * -nz; - - GDWriteXFCmdHdr(__GDLightID2Offset(light) + XF_LIGHT_SPEC_DIR_ID, 6); - GDWrite_f32(px); - GDWrite_f32(py); - GDWrite_f32(pz); - GDWrite_f32(hx); - GDWrite_f32(hy); - GDWrite_f32(hz); -} - -void GDSetSpecularDir(GXLightID light, f32 nx, f32 ny, f32 nz) { - f32 px; - f32 py; - f32 pz; - f32 hx; - f32 hy; - f32 hz; - f32 mag; - - hx = -nx; - hy = -ny; - hz = 1.0f + -nz; - - mag = hx * hx + hy * hy + hz * hz; - if (mag != 0.0f) { - mag = 1.0f / sqrtf(mag); - } - - hx = hx * mag; - hy = hy * mag; - hz = hz * mag; - px = 1000000000000000000.0f * -nx; - py = 1000000000000000000.0f * -ny; - pz = 1000000000000000000.0f * -nz; - - GDWriteXFCmdHdr(__GDLightID2Offset(light) + XF_LIGHT_SPEC_DIR_ID, 6); - GDWrite_f32(px); - GDWrite_f32(py); - GDWrite_f32(pz); - GDWrite_f32(hx); - GDWrite_f32(hy); - GDWrite_f32(hz); -} - -void GDLoadLightObjIndx(u32 lt_obj_indx, GXLightID light) { - GDWriteXFIndxDCmd(__GDLightID2Offset(light) + XF_LIGHT_ID, 0x10, lt_obj_indx); -} - -void GDSetChanAmbColor(GXChannelID chan, GXColor color) { - GDWriteXFCmd((chan & 1) + XF_REG_AMBIENT0_ID, color.r << 24 | color.g << 16 | color.b << 8 | color.a); -} - -void GDSetChanMatColor(GXChannelID chan, GXColor color) { - GDWriteXFCmd((chan & 1) + XF_REG_MATERIAL0_ID, color.r << 24 | color.g << 16 | color.b << 8 | color.a); -} - -void GDSetChanCtrl(GXChannelID chan, u8 enable, GXColorSrc amb_src, GXColorSrc mat_src, u32 light_mask, GXDiffuseFn diff_fn, GXAttnFn attn_fn) { - u32 reg; - - reg = XF_REG_CHAN_CTRL(mat_src, enable, light_mask & 0xF, amb_src, attn_fn == GX_AF_SPEC ? GX_DF_NONE : diff_fn, attn_fn != GX_AF_NONE, attn_fn != GX_AF_SPEC, (light_mask >> 4) & 0xF); - GDWriteXFCmd((chan & 3) + XF_REG_COLOR0CNTRL_ID, reg); - - if (chan == 4 || chan == 5) { - GDWriteXFCmd(chan + XF_REG_MATERIAL0_ID, reg); - } -} - -u16 __GDLightID2Index(GXLightID id) { - u16 idx = 0x1F - std::countl_zero((u32) id); - if (idx > 7) { - idx = 0; - } - return idx; -} diff --git a/aurora-main/lib/dolphin/gd/GDPixel.cpp b/aurora-main/lib/dolphin/gd/GDPixel.cpp deleted file mode 100644 index c18cf77..0000000 --- a/aurora-main/lib/dolphin/gd/GDPixel.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include -#include - -void GDSetFog(GXFogType type, f32 startz, f32 endz, f32 nearz, f32 farz, GXColor color) { - f32 A; - f32 B; - f32 B_mant; - f32 C; - f32 A_f; - u32 b_expn; - u32 b_m; - u32 a_hex; - u32 c_hex; - u32 fsel; - u32 proj; - - ASSERTMSGLINE(62, farz >= 0.0f, "GDSetFog: The farz should be positive value"); - ASSERTMSGLINE(63, farz >= nearz, "GDSetFog: The farz should be larger than nearz"); - - fsel = type & 7; - proj = (type >> 3) & 1; - - if (proj != 0) { - if (farz == nearz || endz == startz) { - A_f = 0.0f; - C = 0.0f; - } else { - A = 1.0f / (endz - startz); - A_f = (farz - nearz) * A; - C = (startz - nearz) * A; - } - - b_expn = 0; - b_m = 0; - } else { - if (farz == nearz || endz == startz) { - A = 0.0f; - B = 0.5f; - C = 0.0f; - } else { - A = (farz * nearz) / ((farz - nearz) * (endz - startz)); - B = farz / (farz - nearz); - C = startz / (endz - startz); - } - - B_mant = B; - b_expn = 1; - - while (B_mant > 1.0) { - B_mant *= 0.5f; - b_expn++; - } - - while (B_mant > 0.0f && B_mant < 0.5) { - B_mant *= 2.0f; - b_expn--; - } - - A_f = A / (1 << b_expn); - b_m = (u32) (8388638.0f * B_mant); - } - - a_hex = *(u32*)&A_f; - c_hex = *(u32*)&C; - - GDWriteBPCmd(BP_FOG_UNK0(a_hex >> 12, 0xEE)); - GDWriteBPCmd(BP_FOG_UNK1(b_m, 0xEF)); - GDWriteBPCmd(BP_FOG_UNK2(b_expn, 0xF0)); - GDWriteBPCmd(BP_FOG_UNK3(c_hex >> 12, proj, fsel, 0xF1)); - GDWriteBPCmd(BP_FOG_COLOR(color.r, color.g, color.b, 0xF2)); -} - -void GDSetBlendMode(GXBlendMode type, GXBlendFactor src_factor, GXBlendFactor dst_factor, GXLogicOp logic_op) { - GDWriteBPCmd(0xFE00FFE3); - GDWriteBPCmd(BP_BLEND_MODE( - type == GX_BM_BLEND || type == GX_BM_SUBTRACT, - type == GX_BM_LOGIC, - 0, - 0, - 0, - dst_factor, - src_factor, - type == GX_BM_SUBTRACT, - logic_op, - 0x41 - )); -} - -void GDSetBlendModeEtc(GXBlendMode type, GXBlendFactor src_factor, - GXBlendFactor dst_factor, GXLogicOp logic_op, - u8 color_update_enable, u8 alpha_update_enable, - u8 dither_enable) { - GDWriteBPCmd(BP_BLEND_MODE( - type == GX_BM_BLEND || type == GX_BM_SUBTRACT, - type == GX_BM_LOGIC, - dither_enable, - color_update_enable, - alpha_update_enable, - dst_factor, - src_factor, - type == GX_BM_SUBTRACT, - logic_op, - 0x41 - )); -} - -void GDSetZMode(u8 compare_enable, GXCompare func, u8 update_enable) { - GDWriteBPCmd(BP_Z_MODE(compare_enable, func, update_enable, 0x40)); -} - -void GDSetDstAlpha(u8 enable, u8 alpha) { - GDWriteBPCmd(BP_DST_ALPHA(alpha, enable, 0x42)); -} - -void GDSetDrawSync(u16 token) { - GDWriteBPCmd(BP_TOKEN(token, 0x48)); - GDWriteBPCmd(BP_TOKEN(token, 0x47)); -} diff --git a/aurora-main/lib/dolphin/gd/GDTev.cpp b/aurora-main/lib/dolphin/gd/GDTev.cpp deleted file mode 100644 index 69803e8..0000000 --- a/aurora-main/lib/dolphin/gd/GDTev.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include -#include - -void GDSetTevOp(GXTevStageID stage, GXTevMode mode) { - GXTevColorArg carg = GX_CC_RASC; - GXTevAlphaArg aarg = GX_CA_RASA; - - if (stage != GX_TEVSTAGE0) { - carg = GX_CC_CPREV; - aarg = GX_CA_APREV; - } - - switch (mode) { - case GX_MODULATE: - GDSetTevColorCalc(stage, GX_CC_ZERO, GX_CC_TEXC, carg, GX_CC_ZERO, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV); - GDSetTevAlphaCalcAndSwap(stage, GX_CA_ZERO, GX_CA_TEXA, aarg, GX_CA_ZERO, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV, GX_TEV_SWAP0, GX_TEV_SWAP0); - break; - case GX_DECAL: - GDSetTevColorCalc(stage, carg, GX_CC_TEXC, GX_CC_TEXA, GX_CC_ZERO, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV); - GDSetTevAlphaCalcAndSwap(stage, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, aarg, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV, GX_TEV_SWAP0, GX_TEV_SWAP0); - break; - case GX_BLEND: - GDSetTevColorCalc(stage, carg, GX_CC_ONE, GX_CC_TEXC, GX_CC_ZERO, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV); - GDSetTevAlphaCalcAndSwap(stage, GX_CA_ZERO, GX_CA_TEXA, aarg, GX_CA_ZERO, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV, GX_TEV_SWAP0, GX_TEV_SWAP0); - break; - case GX_REPLACE: - GDSetTevColorCalc(stage, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_TEXC, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV); - GDSetTevAlphaCalcAndSwap(stage, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV, GX_TEV_SWAP0, GX_TEV_SWAP0); - break; - case GX_PASSCLR: - GDSetTevColorCalc(stage, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, carg, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV); - GDSetTevAlphaCalcAndSwap(stage, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, aarg, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV, GX_TEV_SWAP0, GX_TEV_SWAP0); - break; - default: - ASSERTMSGLINE(110, 0, "GDSetTevOp: Invalid Tev Mode"); - break; - } -} - -void GDSetTevColorCalc(GXTevStageID stage, GXTevColorArg a, GXTevColorArg b, - GXTevColorArg c, GXTevColorArg d, GXTevOp op, - GXTevBias bias, GXTevScale scale, u8 clamp, - GXTevRegID out_reg) { - if (op <= GX_TEV_SUB) { - GDWriteBPCmd(BP_TEV_COLOR(d, c, b, a, bias, op & 1, clamp, scale, out_reg, stage * 2 + 0xC0)); - } else { - GDWriteBPCmd(BP_TEV_COLOR(d, c, b, a, 3, op & 1, clamp, (op >> 1) & 3, out_reg, stage * 2 + 0xC0)); - } -} - -void GDSetTevAlphaCalcAndSwap(GXTevStageID stage, GXTevAlphaArg a, - GXTevAlphaArg b, GXTevAlphaArg c, GXTevAlphaArg d, - GXTevOp op, GXTevBias bias, GXTevScale scale, - u8 clamp, GXTevRegID out_reg, - GXTevSwapSel ras_sel, GXTevSwapSel tex_sel) { - if (op <= GX_TEV_SUB) { - GDWriteBPCmd(BP_TEV_ALPHA(ras_sel, tex_sel, d, c, b, a, bias, op & 1, clamp, scale, out_reg, stage * 2 + 0xC1)); - } else { - GDWriteBPCmd(BP_TEV_ALPHA(ras_sel, tex_sel, d, c, b, a, 3, op & 1, clamp, (op >> 1) & 3, out_reg, stage * 2 + 0xC1)); - } -} - -void GDSetTevColor(GXTevRegID reg, GXColor color) { - u32 regRA; - u32 regBG; - - regRA = BP_TEV_COLOR_REG_RA(color.r, color.a, 0, 0xE0 + reg * 2); - regBG = BP_TEV_COLOR_REG_BG(color.b, color.g, 0, 0xE1 + reg * 2); - - GDWriteBPCmd(regRA); - GDWriteBPCmd(regBG); - GDWriteBPCmd(regBG); - GDWriteBPCmd(regBG); -} - -void GDSetTevColorS10(GXTevRegID reg, GXColorS10 color) { - u32 regRA; - u32 regBG; - - regRA = BP_TEV_COLOR_REG_RA(color.r & 0x7FF, color.a & 0x7FF, 0, 0xE0 + reg * 2); - regBG = BP_TEV_COLOR_REG_BG(color.b & 0x7FF, color.g & 0x7FF, 0, 0xE1 + reg * 2); - - GDWriteBPCmd(regRA); - GDWriteBPCmd(regBG); - GDWriteBPCmd(regBG); - GDWriteBPCmd(regBG); -} - -void GDSetTevKColor(GXTevKColorID reg, GXColor color) { - u32 regRA; - u32 regBG; - - regRA = BP_TEV_COLOR_REG_RA(color.r, color.a, 1, 0xE0 + reg * 2); - regBG = BP_TEV_COLOR_REG_BG(color.b, color.g, 1, 0xE1 + reg * 2); - - GDWriteBPCmd(regRA); - GDWriteBPCmd(regBG); -} - -void GDSetTevKonstantSel(GXTevStageID evenStage, GXTevKColorSel kcsel0, - GXTevKAlphaSel kasel0, GXTevKColorSel kcsel1, - GXTevKAlphaSel kasel1) { - GDWriteBPCmd(0xFEFFFFF0); - GDWriteBPCmd(BP_TEV_KSEL(0, 0, kcsel0, kasel0, kcsel1, kasel1, evenStage / 2 + 0xF6)); -} - -void GDSetTevSwapModeTable(GXTevSwapSel table, GXTevColorChan red, - GXTevColorChan green, GXTevColorChan blue, - GXTevColorChan alpha) { - GDWriteBPCmd(0xFE00000F); - GDWriteBPCmd(BP_TEV_KSEL(red, green, 0, 0, 0, 0, table * 2 + 0xF6)); - - GDWriteBPCmd(0xFE00000F); - GDWriteBPCmd(BP_TEV_KSEL(blue, alpha, 0, 0, 0, 0, table * 2 + 0xF7)); -} - -void GDSetAlphaCompare(GXCompare comp0, u8 ref0, GXAlphaOp op, GXCompare comp1, u8 ref1) { - GDWriteBPCmd(BP_ALPHA_COMPARE(ref0, ref1, comp0, comp1, op, 0xF3)); -} - -void GDSetZTexture(GXZTexOp op, GXTexFmt fmt, u32 bias) { - u32 zfmt; - - switch (fmt) { - case GX_TF_Z8: - zfmt = 0; - break; - case GX_TF_Z16: - zfmt = 1; - break; - case GX_TF_Z24X8: - zfmt = 2; - break; - default: - ASSERTMSGLINE(399, 0, "GDSetZTexture: Invalid format"); - zfmt = 2; - break; - } - - GDWriteBPCmd(BP_ZTEX_PARAMS_0(bias, 0xF4)); - GDWriteBPCmd(BP_ZTEX_PARAMS_1(zfmt, op, 0xF5)); -} - -void GDSetTevOrder(GXTevStageID evenStage, GXTexCoordID coord0, GXTexMapID map0, - GXChannelID color0, GXTexCoordID coord1, GXTexMapID map1, - GXChannelID color1) { - static u8 c2r[] = { 0, 1, 0, 1, 0, 1, 7, 5, 6, 0, 0, 0, 0, 0, 0, 7 }; - GDWriteBPCmd(BP_TEV_ORDER( - map0 & 7, - coord0 & 7, - map0 != GX_TEXMAP_NULL && !(map0 & GX_TEX_DISABLE), - c2r[color0 & 0xF], - map1 & 7, - coord1 & 7, - map1 != GX_TEXMAP_NULL && !(map1 & GX_TEX_DISABLE), - c2r[color1 & 0xF], - evenStage / 2 + 0x28 - )); -} diff --git a/aurora-main/lib/dolphin/gd/GDTexture.cpp b/aurora-main/lib/dolphin/gd/GDTexture.cpp deleted file mode 100644 index c3c1a6c..0000000 --- a/aurora-main/lib/dolphin/gd/GDTexture.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include -#include - -u8 GD2HWFiltConv[] = {0, 4, 1, 5, 2, 6}; - -u8 GDTexMode0Ids[8] = {128, 129, 130, 131, 160, 161, 162, 163}; -u8 GDTexMode1Ids[8] = {132, 133, 134, 135, 164, 165, 166, 167}; -u8 GDTexImage0Ids[8] = {136, 137, 138, 139, 168, 169, 170, 171}; -u8 GDTexImage1Ids[8] = {140, 141, 142, 143, 172, 173, 174, 175}; -u8 GDTexImage2Ids[8] = {144, 145, 146, 147, 176, 177, 178, 179}; -u8 GDTexImage3Ids[8] = {148, 149, 150, 151, 180, 181, 182, 183}; -u8 GDTexTlutIds[8] = {152, 153, 154, 155, 184, 185, 186, 187}; - -void GDSetTexLookupMode(GXTexMapID id, GXTexWrapMode wrap_s, - GXTexWrapMode wrap_t, GXTexFilter min_filt, - GXTexFilter mag_filt, f32 min_lod, f32 max_lod, - f32 lod_bias, u8 bias_clamp, u8 do_edge_lod, - GXAnisotropy max_aniso) { - GDWriteBPCmd(BP_TEX_MODE0(wrap_s, wrap_t, mag_filt == TRUE, GD2HWFiltConv[min_filt], !do_edge_lod, (u8)(32.0f * lod_bias), max_aniso, bias_clamp, GDTexMode0Ids[id])); - GDWriteBPCmd(BP_TEX_MODE1((u8)(16.0f * min_lod), (u8)(16.0f * max_lod), GDTexMode1Ids[id])); -} - -void GDSetTexImgAttr(GXTexMapID id, u16 width, u16 height, GXTexFmt format) { - GDWriteBPCmd(BP_IMAGE_ATTR(width - 1, height - 1, format, GDTexImage0Ids[id])); -} - -void GDSetTexImgPtr(GXTexMapID id, void* image_ptr) { - GDWriteBPCmd(BP_IMAGE_PTR(OSCachedToPhysical(image_ptr) >> 5, GDTexImage3Ids[id])); -} - -void GDSetTexImgPtrRaw(GXTexMapID id, u32 image_ptr_raw) { - GDWriteBPCmd(BP_IMAGE_PTR(image_ptr_raw, GDTexImage3Ids[id])); -} - -void GDPatchTexImgPtr(void* image_ptr) { - GDWrite_u24(OSCachedToPhysical(image_ptr) >> 5); -} - -void GDSetTexCached(GXTexMapID id, u32 tmem_even, GXTexCacheSize size_even, - u32 tmem_odd, GXTexCacheSize size_odd) { - GDWriteBPCmd(BP_TEX_CACHE_EVEN(tmem_even >> 5, size_even + 3, size_even + 3, 0, GDTexImage1Ids[id])); - - if (size_odd != 3 && tmem_odd < 0x100000) { - GDWriteBPCmd(BP_TEX_CACHE_ODD(tmem_odd >> 5, size_odd + 3, size_odd + 3, GDTexImage2Ids[id])); - } -} - - -void GDSetTexPreLoaded(GXTexMapID id, u32 tmem_even, u32 tmem_odd) { - GDWriteBPCmd(BP_TEX_CACHE_EVEN(tmem_even >> 5, 0, 0, 1, GDTexImage1Ids[id])); - - if (tmem_odd < 0x100000) { - GDWriteBPCmd(BP_TEX_CACHE_ODD(tmem_odd >> 5, 0, 0, GDTexImage2Ids[id])); - } -} - -void GDSetTexTlut(GXTexMapID id, u32 tmem_addr, GXTlutFmt format) { - GDWriteBPCmd(BP_TEX_TLUT((tmem_addr - 0x80000) >> 9, format, GDTexTlutIds[id])); -} - -void GDSetTexCoordScale(GXTexCoordID coord, u16 s_scale, u16 t_scale) { - GDWriteBPCmd(0xFE00FFFF); - GDWriteBPCmd(BP_TEXCOORD_S_SCALE(s_scale - 1, 0, 0, 0, 0, coord * 2 + 0x30)); - - GDWriteBPCmd(0xFE00FFFF); - GDWriteBPCmd(BP_TEXCOORD_T_SCALE(t_scale - 1, 0, 0, coord * 2 + 0x31)); -} - -void GDSetTexCoordScale2(GXTexCoordID coord, u16 s_scale, u8 s_bias, - u8 s_wrap, u16 t_scale, u8 t_bias, u8 t_wrap) { - GDWriteBPCmd(0xFE03FFFF); - GDWriteBPCmd(BP_TEXCOORD_S_SCALE(s_scale - 1, s_bias, s_wrap, 0, 0, coord * 2 + 0x30)); - GDWriteBPCmd(BP_TEXCOORD_T_SCALE(t_scale - 1, t_bias, t_wrap, coord * 2 + 0x31)); -} - -void GDSetTexCoordScaleAndTOEs(GXTexCoordID coord, u16 s_scale, u8 s_bias, - u8 s_wrap, u16 t_scale, u8 t_bias, u8 t_wrap, - u8 line_offset, u8 point_offset) { - GDWriteBPCmd(BP_TEXCOORD_S_SCALE(s_scale - 1, s_bias, s_wrap, line_offset, point_offset, coord * 2 + 0x30)); - GDWriteBPCmd(BP_TEXCOORD_T_SCALE(t_scale - 1, t_bias, t_wrap, coord * 2 + 0x31)); -} - -void GDLoadTlut(void* tlut_ptr, u32 tmem_addr, GXTlutSize size) { - ASSERTMSGLINE(488, !(tmem_addr & 0x1ff), "GDLoadTlut: invalid TMEM pointer"); - ASSERTMSGLINE(489, size <= 0x400, "GDLoadTlut: invalid TLUT size"); - - GDWriteBPCmd(0xFEFFFF00); - GDWriteBPCmd(0xF000000); - GDWriteBPCmd(BP_LOAD_TLUT0(OSCachedToPhysical(tlut_ptr) >> 5, 0x64)); - GDWriteBPCmd(BP_LOAD_TLUT1((tmem_addr - 0x80000) >> 9, size, 0x65)); - GDWriteBPCmd(0xFEFFFF00); - GDWriteBPCmd(0xF000000); -} - -void GDLoadTlutRaw(u32 tlut_ptr_raw, u32 tmem_addr, GXTlutSize size) { - ASSERTMSGLINE(527, size <= 0x400, "GDLoadTlut: invalid TLUT size"); - - GDWriteBPCmd(0xFEFFFF00); - GDWriteBPCmd(0xF000000); - GDWriteBPCmd(BP_LOAD_TLUT0(tlut_ptr_raw, 0x64)); - GDWriteBPCmd(BP_LOAD_TLUT1((tmem_addr - 0x80000) >> 9, size, 0x65)); - GDWriteBPCmd(0xFEFFFF00); - GDWriteBPCmd(0xF000000); -} diff --git a/aurora-main/lib/dolphin/gd/GDTransform.cpp b/aurora-main/lib/dolphin/gd/GDTransform.cpp deleted file mode 100644 index 9ac9c66..0000000 --- a/aurora-main/lib/dolphin/gd/GDTransform.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include -#include - -void GDLoadPosMtxImm(const Mtx mtx, u32 id) { - GDWriteXFCmdHdr(4 * id, 12); - GDWrite_f32(mtx[0][0]); - GDWrite_f32(mtx[0][1]); - GDWrite_f32(mtx[0][2]); - GDWrite_f32(mtx[0][3]); - GDWrite_f32(mtx[1][0]); - GDWrite_f32(mtx[1][1]); - GDWrite_f32(mtx[1][2]); - GDWrite_f32(mtx[1][3]); - GDWrite_f32(mtx[2][0]); - GDWrite_f32(mtx[2][1]); - GDWrite_f32(mtx[2][2]); - GDWrite_f32(mtx[2][3]); -} - -void GDLoadPosMtxIndx(u16 mtx_indx, u32 id) { - GDWriteXFIndxACmd(4 * id, 12, mtx_indx); -} - -void GDLoadNrmMtxImm(const Mtx mtx, u32 id) { - GDWriteXFCmdHdr(id * 3 + 0x400, 9); - GDWrite_f32(mtx[0][0]); - GDWrite_f32(mtx[0][1]); - GDWrite_f32(mtx[0][2]); - GDWrite_f32(mtx[1][0]); - GDWrite_f32(mtx[1][1]); - GDWrite_f32(mtx[1][2]); - GDWrite_f32(mtx[2][0]); - GDWrite_f32(mtx[2][1]); - GDWrite_f32(mtx[2][2]); -} - -void GDLoadNrmMtxImm3x3(const f32 mtx[3][3], u32 id) { - GDWriteXFCmdHdr(id * 3 + 0x400, 9); - GDWrite_f32(mtx[0][0]); - GDWrite_f32(mtx[0][1]); - GDWrite_f32(mtx[0][2]); - GDWrite_f32(mtx[1][0]); - GDWrite_f32(mtx[1][1]); - GDWrite_f32(mtx[1][2]); - GDWrite_f32(mtx[2][0]); - GDWrite_f32(mtx[2][1]); - GDWrite_f32(mtx[2][2]); -} - -void GDLoadNrmMtxIndx3x3(u16 mtx_indx, u32 id) { - GDWriteXFIndxBCmd(id * 3 + 0x400, 9, mtx_indx); -} - -void GDLoadTexMtxImm(const Mtx mtx, u32 id, GXTexMtxType type) { - u16 addr; - u8 count; - - if (id >= 0x40) { - ASSERTMSGLINE(178, type == GX_MTX3x4, "GDLoadTexMtxImm: invalid matrix type"); - addr = ((id - 0x40) << 2) + 0x500; - count = 12; - } else { - addr = 4 * id; - count = type == GX_MTX2x4 ? 8 : 12; - } - - GDWriteXFCmdHdr(addr,count); - GDWrite_f32(mtx[0][0]); - GDWrite_f32(mtx[0][1]); - GDWrite_f32(mtx[0][2]); - GDWrite_f32(mtx[0][3]); - GDWrite_f32(mtx[1][0]); - GDWrite_f32(mtx[1][1]); - GDWrite_f32(mtx[1][2]); - GDWrite_f32(mtx[1][3]); - - if (type == GX_MTX3x4) { - GDWrite_f32(mtx[2][0]); - GDWrite_f32(mtx[2][1]); - GDWrite_f32(mtx[2][2]); - GDWrite_f32(mtx[2][3]); - } -} - -void GDLoadTexMtxIndx(u16 mtx_indx, u32 id, GXTexMtxType type) { - u16 addr; - u8 count; - - if (id >= 0x40) { - ASSERTMSGLINE(227, type == GX_MTX3x4, "GDLoadTexMtxIndx: invalid matrix type"); - addr = ((id - 0x40) << 2) + 0x500; - count = 12; - } else { - addr = 4 * id; - count = type == GX_MTX2x4 ? 8 : 12; - } - - GDWriteXFIndxCCmd(addr, count, mtx_indx); -} - -void GDSetCurrentMtx(u32 pn, u32 t0, u32 t1, u32 t2, u32 t3, u32 t4, u32 t5, u32 t6, u32 t7) { - u32 regA; - u32 regB; - - regA = CP_MTX_REG_A(pn, t0, t1, t2, t3); - regB = CP_MTX_REG_B(t4, t5, t6, t7); - - GDWriteCPCmd(CP_MTX_REG_A_ID, regA); - GDWriteCPCmd(CP_MTX_REG_B_ID, regB); - GDWriteXFCmdHdr(XF_REG_MATRIXINDEX0_ID, 2); - GDWrite_u32(regA); - GDWrite_u32(regB); -} - -void GDSetProjection(const Mtx44 mtx, GXProjectionType type) { - u32 c; - c = type == GX_ORTHOGRAPHIC ? 3 : 2; - - GDWriteXFCmdHdr(XF_REG_PROJECTIONA_ID, 7); - GDWrite_f32(mtx[0][0]); - GDWrite_f32(mtx[0][c]); - GDWrite_f32(mtx[1][1]); - GDWrite_f32(mtx[1][c]); - GDWrite_f32(mtx[2][2]); - GDWrite_f32(mtx[2][3]); - GDWrite_u32(type); -} diff --git a/aurora-main/lib/dolphin/gd/gd.hpp b/aurora-main/lib/dolphin/gd/gd.hpp deleted file mode 100644 index 0f69c24..0000000 --- a/aurora-main/lib/dolphin/gd/gd.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include "../../internal.hpp" - -static aurora::Module Log("aurora::gd"); diff --git a/aurora-main/lib/dolphin/gx/GXAurora.cpp b/aurora-main/lib/dolphin/gx/GXAurora.cpp deleted file mode 100644 index eacc674..0000000 --- a/aurora-main/lib/dolphin/gx/GXAurora.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#include "dolphin/gx/GXAurora.h" - -#include -#include -#include - -#include "__gx.h" -#include "gx.hpp" -#include "../../window.hpp" - -#include "../../gfx/common.hpp" -#include "../../gx/fifo.hpp" - -// Single definition for the `Log` that gx.hpp declares for this directory. -aurora::Module Log("aurora::gx"); - -static void GXWriteString(const char* label) { - auto length = strlen(label); - - if (length > std::numeric_limits::max()) { - Log.warn("Debug marker size over u16 max, truncating"); - length = std::numeric_limits::max(); - } - - GX_WRITE_U16(length); - GX_WRITE_DATA(label, length); -} - -void GXPushDebugGroup(const char* label) { - GX_WRITE_AURORA(GX_LOAD_AURORA_DEBUG_GROUP_PUSH); - GXWriteString(label); -} - -void GXPopDebugGroup() { GX_WRITE_AURORA(GX_LOAD_AURORA_DEBUG_GROUP_POP); } - -void GXInsertDebugMarker(const char* label) { - GX_WRITE_AURORA(GX_LOAD_AURORA_DEBUG_MARKER_INSERT); - GXWriteString(label); -} - -void AuroraSetViewportPolicy(AuroraViewportPolicy policy) { - const bool changed = g_gxState.viewportPolicy != policy; - if (changed) { - // Finish commands using the old framebuffer mapping before changing it. - aurora::gx::fifo::drain(); - } - g_gxState.viewportPolicy = policy; - aurora::window::set_frame_buffer_aspect_fit(policy == AURORA_VIEWPORT_FIT); - aurora::window::set_force_aspect_16_9(policy == AURORA_VIEWPORT_16_9); - aurora::window::set_present_surface_fill(policy == AURORA_VIEWPORT_STRETCH); - if (changed) { - // Reapply the guest viewport and scissor after a resize. - aurora::gx::set_logical_viewport(g_gxState.logicalViewport); - aurora::gx::set_logical_scissor(g_gxState.logicalScissor); - } -} - -void AuroraGetRenderSize(u32* width, u32* height) { - // The guest CPU thread uses this safe render-size value outside render passes. - const auto renderSize = aurora::gfx::get_frame_buffer_size(); - if (width != nullptr) { - *width = renderSize.x; - } - if (height != nullptr) { - *height = renderSize.y; - } -} - -void AuroraGetSurfaceSize(u32* width, u32* height) { - const auto windowSize = aurora::window::get_window_size(); - if (width != nullptr) { - *width = windowSize.native_fb_width; - } - if (height != nullptr) { - *height = windowSize.native_fb_height; - } -} - -void GXSetViewportRender(f32 left, f32 top, f32 wd, f32 ht, f32 nearz, f32 farz) { - GX_WRITE_AURORA(GX_LOAD_AURORA_VIEWPORT_RENDER); - GX_WRITE_F32(left); - GX_WRITE_F32(top); - GX_WRITE_F32(wd); - GX_WRITE_F32(ht); - GX_WRITE_F32(nearz); - GX_WRITE_F32(farz); -} - -void GXSetScissorRender(u32 left, u32 top, u32 wd, u32 ht) { - GX_WRITE_AURORA(GX_LOAD_AURORA_SCISSOR_RENDER); - GX_WRITE_U32(left); - GX_WRITE_U32(top); - GX_WRITE_U32(wd); - GX_WRITE_U32(ht); -} - -namespace { -void WriteMappedRenderState(const aurora::gx::MappedRenderState& mapped) { - GXSetViewportRender(mapped.viewport.left, mapped.viewport.top, mapped.viewport.width, mapped.viewport.height, - mapped.viewport.znear, mapped.viewport.zfar); - GXSetScissorRender(static_cast(std::max(mapped.scissor.x, 0)), - static_cast(std::max(mapped.scissor.y, 0)), - static_cast(std::max(mapped.scissor.width, 0)), - static_cast(std::max(mapped.scissor.height, 0))); -} -} // namespace - -void GXSetViewportScissorRenderSafeArea(f32 aspect) { - const auto [targetWidth, targetHeight] = aurora::gfx::get_render_target_size(); - if (targetWidth == 0 || targetHeight == 0 || !std::isfinite(aspect) || aspect <= 0.0f) { - return; - } - - // Apply queued viewport changes before direct layout draws use the safe area. - aurora::gx::fifo::drain(); - auto mapped = aurora::gx::map_logical_render_state(); - const float targetAspect = static_cast(targetWidth) / static_cast(targetHeight); - - float safeLeft = 0.0f; - float safeTop = 0.0f; - float safeWidth = static_cast(targetWidth); - float safeHeight = static_cast(targetHeight); - if (targetAspect > aspect) { - safeWidth = safeHeight * aspect; - safeLeft = (static_cast(targetWidth) - safeWidth) * 0.5f; - } else if (targetAspect < aspect) { - safeHeight = safeWidth / aspect; - safeTop = (static_cast(targetHeight) - safeHeight) * 0.5f; - } - - const float scaleX = safeWidth / static_cast(targetWidth); - const float scaleY = safeHeight / static_cast(targetHeight); - mapped.viewport.left = safeLeft + mapped.viewport.left * scaleX; - mapped.viewport.top = safeTop + mapped.viewport.top * scaleY; - mapped.viewport.width *= scaleX; - mapped.viewport.height *= scaleY; - - const float scissorLeft = safeLeft + static_cast(mapped.scissor.x) * scaleX; - const float scissorTop = safeTop + static_cast(mapped.scissor.y) * scaleY; - const float scissorRight = - safeLeft + static_cast(mapped.scissor.x + mapped.scissor.width) * scaleX; - const float scissorBottom = - safeTop + static_cast(mapped.scissor.y + mapped.scissor.height) * scaleY; - const int32_t left = std::clamp(static_cast(std::floor(scissorLeft)), 0, - static_cast(targetWidth)); - const int32_t top = std::clamp(static_cast(std::floor(scissorTop)), 0, - static_cast(targetHeight)); - const int32_t right = std::clamp(static_cast(std::ceil(scissorRight)), left, - static_cast(targetWidth)); - const int32_t bottom = std::clamp(static_cast(std::ceil(scissorBottom)), top, - static_cast(targetHeight)); - mapped.scissor = {left, top, right - left, bottom - top}; - - WriteMappedRenderState(mapped); -} - -void GXRestoreViewportScissorRender() { - // Run queued GX draws before leaving the direct layout safe area. - aurora::gx::fifo::drain(); - WriteMappedRenderState(aurora::gx::map_logical_render_state()); -} - -void GXSetTexCopySrcRender(u16 left, u16 top, u16 wd, u16 ht) { - aurora::gx::g_gxState.texCopySrc = {left, top, wd, ht}; - aurora::gx::g_gxState.texCopySrcRenderSpace = true; -} - -void GXCreateFrameBuffer(u32 width, u32 height) { - aurora::gx::fifo::drain(); - aurora::gfx::begin_offscreen(width, height); -} - -void GXRestoreFrameBuffer() { - aurora::gx::fifo::drain(); - aurora::gfx::end_offscreen(); -} diff --git a/aurora-main/lib/dolphin/gx/GXBump.cpp b/aurora-main/lib/dolphin/gx/GXBump.cpp deleted file mode 100644 index 511bcfe..0000000 --- a/aurora-main/lib/dolphin/gx/GXBump.cpp +++ /dev/null @@ -1,213 +0,0 @@ -#include "gx.hpp" -#include "__gx.h" - -extern "C" { -void GXSetNumIndStages(u8 num) { - SET_REG_FIELD(0, __gx->genMode, 3, 16, num); - __gx->dirtyState |= 6; // gen mode dirty + BP mask dirty -} - -void GXSetIndTexOrder(GXIndTexStageID indStage, GXTexCoordID texCoord, GXTexMapID texMap) { - switch (indStage) { - case GX_INDTEXSTAGE0: - SET_REG_FIELD(0, __gx->iref, 3, 0, texMap); - SET_REG_FIELD(0, __gx->iref, 3, 3, texCoord); - break; - case GX_INDTEXSTAGE1: - SET_REG_FIELD(0, __gx->iref, 3, 6, texMap); - SET_REG_FIELD(0, __gx->iref, 3, 9, texCoord); - break; - case GX_INDTEXSTAGE2: - SET_REG_FIELD(0, __gx->iref, 3, 12, texMap); - SET_REG_FIELD(0, __gx->iref, 3, 15, texCoord); - break; - case GX_INDTEXSTAGE3: - SET_REG_FIELD(0, __gx->iref, 3, 18, texMap); - SET_REG_FIELD(0, __gx->iref, 3, 21, texCoord); - break; - } - GX_WRITE_RAS_REG(__gx->iref); - __gx->bpSent = 1; - __gx->dirtyState |= 3; // SU tex regs + BP mask dirty -} - -void GXSetIndTexCoordScale(GXIndTexStageID indStage, GXIndTexScale scaleS, GXIndTexScale scaleT) { - if (indStage < GX_INDTEXSTAGE2) { - switch (indStage) { - case GX_INDTEXSTAGE0: - SET_REG_FIELD(0, __gx->IndTexScale0, 4, 0, scaleS); - SET_REG_FIELD(0, __gx->IndTexScale0, 4, 4, scaleT); - break; - case GX_INDTEXSTAGE1: - SET_REG_FIELD(0, __gx->IndTexScale0, 4, 8, scaleS); - SET_REG_FIELD(0, __gx->IndTexScale0, 4, 12, scaleT); - break; - } - GX_WRITE_RAS_REG(__gx->IndTexScale0); - } else { - switch (indStage) { - case GX_INDTEXSTAGE2: - SET_REG_FIELD(0, __gx->IndTexScale1, 4, 0, scaleS); - SET_REG_FIELD(0, __gx->IndTexScale1, 4, 4, scaleT); - break; - case GX_INDTEXSTAGE3: - SET_REG_FIELD(0, __gx->IndTexScale1, 4, 8, scaleS); - SET_REG_FIELD(0, __gx->IndTexScale1, 4, 12, scaleT); - break; - } - GX_WRITE_RAS_REG(__gx->IndTexScale1); - } - __gx->bpSent = 1; -} - -void GXSetIndTexMtx(GXIndTexMtxID id, const void* offset, s8 scaleExp) { - u32 idx = 0; - if (id >= GX_ITM_0 && id <= GX_ITM_2) { - idx = id - GX_ITM_0; - } else if (id >= GX_ITM_S0 && id <= GX_ITM_S2) { - idx = id - GX_ITM_S0; - } else if (id >= GX_ITM_T0 && id <= GX_ITM_T2) { - idx = id - GX_ITM_T0; - } - - const auto* mtx = reinterpret_cast(offset); - s32 adjScale = scaleExp + 17; - - // Write 3 BP registers for the 2x3 matrix - - // Column 0: m[0][0] and m[1][0] - u32 reg0 = 0; - s32 m00 = static_cast(1024.0f * mtx[0]) & 0x7FF; - s32 m10 = static_cast(1024.0f * mtx[3]) & 0x7FF; - SET_REG_FIELD(0, reg0, 11, 0, m00); - SET_REG_FIELD(0, reg0, 11, 11, m10); - SET_REG_FIELD(0, reg0, 2, 22, adjScale & 3); - SET_REG_FIELD(0, reg0, 8, 24, idx * 3 + 6); - GX_WRITE_RAS_REG(reg0); - - // Column 1: m[0][1] and m[1][1] - u32 reg1 = 0; - s32 m01 = static_cast(1024.0f * mtx[1]) & 0x7FF; - s32 m11 = static_cast(1024.0f * mtx[4]) & 0x7FF; - SET_REG_FIELD(0, reg1, 11, 0, m01); - SET_REG_FIELD(0, reg1, 11, 11, m11); - SET_REG_FIELD(0, reg1, 2, 22, (adjScale >> 2) & 3); - SET_REG_FIELD(0, reg1, 8, 24, idx * 3 + 7); - GX_WRITE_RAS_REG(reg1); - - // Column 2: m[0][2] and m[1][2] - u32 reg2 = 0; - s32 m02 = static_cast(1024.0f * mtx[2]) & 0x7FF; - s32 m12 = static_cast(1024.0f * mtx[5]) & 0x7FF; - SET_REG_FIELD(0, reg2, 11, 0, m02); - SET_REG_FIELD(0, reg2, 11, 11, m12); - SET_REG_FIELD(0, reg2, 2, 22, (adjScale >> 4) & 3); - SET_REG_FIELD(0, reg2, 8, 24, idx * 3 + 8); - GX_WRITE_RAS_REG(reg2); - __gx->bpSent = 1; -} - -void GXSetTevIndirect(GXTevStageID tevStage, GXIndTexStageID indStage, GXIndTexFormat fmt, GXIndTexBiasSel biasSel, - GXIndTexMtxID matrixSel, GXIndTexWrap wrapS, GXIndTexWrap wrapT, GXBool addPrev, GXBool indLod, - GXIndTexAlphaSel alphaSel) { - // BP register: tev_stage + 0x10 - u32 reg = 0; - SET_REG_FIELD(0, reg, 2, 0, indStage); - SET_REG_FIELD(0, reg, 2, 2, fmt); - SET_REG_FIELD(0, reg, 3, 4, biasSel); - SET_REG_FIELD(0, reg, 2, 7, alphaSel); - SET_REG_FIELD(0, reg, 4, 9, matrixSel); - SET_REG_FIELD(0, reg, 3, 13, wrapS); - SET_REG_FIELD(0, reg, 3, 16, wrapT); - SET_REG_FIELD(0, reg, 1, 19, indLod); - SET_REG_FIELD(0, reg, 1, 20, addPrev); - SET_REG_FIELD(0, reg, 8, 24, tevStage + 16); - GX_WRITE_RAS_REG(reg); - __gx->bpSent = 1; -} - -void GXSetTevDirect(GXTevStageID stageId) { - GXSetTevIndirect(stageId, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_NONE, GX_ITM_OFF, GX_ITW_OFF, GX_ITW_OFF, GX_FALSE, - GX_FALSE, GX_ITBA_OFF); -} - -void GXSetTevIndWarp(GXTevStageID tevStage, GXIndTexStageID indStage, GXBool signedOffsets, GXBool replaceMode, - GXIndTexMtxID matrixSel) { - const auto wrap = replaceMode ? GX_ITW_0 : GX_ITW_OFF; - const auto biasSel = signedOffsets ? GX_ITB_STU : GX_ITB_NONE; - GXSetTevIndirect(tevStage, indStage, GX_ITF_8, biasSel, matrixSel, wrap, wrap, false, false, GX_ITBA_OFF); -} - -void GXSetTevIndRepeat(GXTevStageID tevStage) { - GXSetTevIndirect(tevStage, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_NONE, GX_ITM_OFF, GX_ITW_0, GX_ITW_0, GX_TRUE, - GX_FALSE, GX_ITBA_OFF); -} - -void GXSetTevIndBumpXYZ(GXTevStageID tevStage, GXIndTexStageID indStage, GXIndTexMtxID matrixSel) { - GXSetTevIndirect(tevStage, indStage, GX_ITF_8, GX_ITB_STU, matrixSel, GX_ITW_OFF, GX_ITW_OFF, GX_FALSE, GX_FALSE, - GX_ITBA_OFF); -} - -void GXSetTevIndBumpST(GXTevStageID tevStage, GXIndTexStageID indStage, GXIndTexMtxID matrixSel) { - GXIndTexMtxID sMtx, tMtx; - switch (matrixSel) { - case GX_ITM_0: - sMtx = GX_ITM_S0; - tMtx = GX_ITM_T0; - break; - case GX_ITM_1: - sMtx = GX_ITM_S1; - tMtx = GX_ITM_T1; - break; - case GX_ITM_2: - sMtx = GX_ITM_S2; - tMtx = GX_ITM_T2; - break; - default: - sMtx = GX_ITM_OFF; - tMtx = GX_ITM_OFF; - break; - } - // Stage 0: STU bias, S-dynamic matrix, wrap=0/0 - GXSetTevIndirect(tevStage, indStage, GX_ITF_8, GX_ITB_STU, sMtx, GX_ITW_0, GX_ITW_0, GX_FALSE, GX_FALSE, - GX_ITBA_OFF); - // Stage 1: STU bias, T-dynamic matrix, wrap=0/0, add prev - GXSetTevIndirect(static_cast(tevStage + 1), indStage, GX_ITF_8, GX_ITB_STU, tMtx, GX_ITW_0, GX_ITW_0, - GX_TRUE, GX_FALSE, GX_ITBA_OFF); - // Stage 2: no bias, matrix off, wrap off, add prev - GXSetTevIndirect(static_cast(tevStage + 2), indStage, GX_ITF_8, GX_ITB_NONE, GX_ITM_OFF, GX_ITW_OFF, - GX_ITW_OFF, GX_TRUE, GX_FALSE, GX_ITBA_OFF); -} - -void GXSetTevIndTile(GXTevStageID tevStage, GXIndTexStageID indStage, u16 tileSizeS, u16 tileSizeT, u16 tileSizeS_exp, - u16 tileSizeT_exp, GXIndTexFormat fmt, GXIndTexMtxID matrixSel, GXIndTexBiasSel biasSel, - GXIndTexAlphaSel alphaSel) { - // Convert tile size exponents to wrap modes - auto sizeToWrap = [](u16 sizeExp) -> GXIndTexWrap { - switch (sizeExp) { - case 8: return GX_ITW_256; - case 7: return GX_ITW_128; - case 6: return GX_ITW_64; - case 5: return GX_ITW_32; - case 4: return GX_ITW_16; - default: return GX_ITW_0; - } - }; - GXIndTexWrap wrapS = sizeToWrap(tileSizeS_exp); - GXIndTexWrap wrapT = sizeToWrap(tileSizeT_exp); - - // Set up the indirect matrix for tiling - f32 mtx[2][3] = {}; - s8 scaleExp = 0; - if (biasSel == GX_ITB_S || biasSel == GX_ITB_ST || biasSel == GX_ITB_SU || biasSel == GX_ITB_STU) { - mtx[0][0] = static_cast(tileSizeS); - scaleExp = tileSizeS_exp; - } - if (biasSel == GX_ITB_T || biasSel == GX_ITB_ST || biasSel == GX_ITB_TU || biasSel == GX_ITB_STU) { - mtx[1][1] = static_cast(tileSizeT); - scaleExp = tileSizeT_exp; - } - GXSetIndTexMtx(matrixSel, mtx, scaleExp); - GXSetTevIndirect(tevStage, indStage, fmt, biasSel, matrixSel, wrapS, wrapT, GX_FALSE, GX_FALSE, alphaSel); -} -} diff --git a/aurora-main/lib/dolphin/gx/GXCpu2Efb.cpp b/aurora-main/lib/dolphin/gx/GXCpu2Efb.cpp deleted file mode 100644 index 9815bd4..0000000 --- a/aurora-main/lib/dolphin/gx/GXCpu2Efb.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "gx.hpp" - -#include "../../gfx/depth_peek.hpp" - -#include - -void GXPeekZ(u16 x, u16 y, u32* z) { - aurora::gfx::depth_peek::poll(); - - if (z != nullptr) { - u32 value = 0; - if (aurora::gfx::depth_peek::read_latest(x, y, value)) { - *z = value; - } else { - *z = g_gxState.clearDepth & 0x00ffffffu; - } - } - - aurora::gfx::depth_peek::request_snapshot(); -} diff --git a/aurora-main/lib/dolphin/gx/GXCull.cpp b/aurora-main/lib/dolphin/gx/GXCull.cpp deleted file mode 100644 index 0611778..0000000 --- a/aurora-main/lib/dolphin/gx/GXCull.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "gx.hpp" -#include "__gx.h" - -extern "C" { - -void GXSetScissor(u32 left, u32 top, u32 width, u32 height) { - const u32 tp = top + 342; - const u32 lf = left + 342; - const u32 bm = tp + height - 1; - const u32 rt = lf + width - 1; - - SET_REG_FIELD(0, __gx->suScis0, 11, 0, tp); - SET_REG_FIELD(0, __gx->suScis0, 11, 12, lf); - SET_REG_FIELD(0, __gx->suScis1, 11, 0, bm); - SET_REG_FIELD(0, __gx->suScis1, 11, 12, rt); - - GX_WRITE_RAS_REG(__gx->suScis0); - GX_WRITE_RAS_REG(__gx->suScis1); - __gx->bpSent = 1; -} - -// TODO GXSetScissorBoxOffset - -void GXSetCullMode(GXCullMode mode) { - // Swap front/back to match hardware convention - GXCullMode hwMode; - switch (mode) { - case GX_CULL_FRONT: - hwMode = GX_CULL_BACK; - break; - case GX_CULL_BACK: - hwMode = GX_CULL_FRONT; - break; - default: - hwMode = mode; - break; - } - SET_REG_FIELD(0, __gx->genMode, 2, 14, hwMode); - __gx->dirtyState |= 4; // gen mode dirty -} - -void GXSetClipMode(GXClipMode mode) { - GX_WRITE_XF_REG(5, mode); - __gx->bpSent = 1; -} - -void GXSetCoPlanar(GXBool enable) { - u32 reg; - SET_REG_FIELD(0, __gx->genMode, 1, 19, enable); - - // This sets a mask that causes only one bit to be updated in genMode on the next write. - reg = 0x0008000; - SET_REG_FIELD(0, reg, 8, 24, 0xFE); - SET_REG_FIELD(0, reg, 24, 0, 1 << 19); - GX_WRITE_RAS_REG(reg); - - // immediately flush - GX_WRITE_RAS_REG(__gx->genMode); -} -} diff --git a/aurora-main/lib/dolphin/gx/GXDispList.cpp b/aurora-main/lib/dolphin/gx/GXDispList.cpp deleted file mode 100644 index e39cc10..0000000 --- a/aurora-main/lib/dolphin/gx/GXDispList.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "gx.hpp" -#include "__gx.h" - -#include "../../gx/command_processor.hpp" -#include "../../gx/fifo.hpp" - -#include - -static __GXData_struct sSavedGXData; - -extern "C" { -void GXBeginDisplayList(void* list, u32 size) { - CHECK(!aurora::gx::fifo::in_display_list(), "Display list began twice!"); - - // Flush any pending dirty state before recording - if (__gx->dirtyState != 0) { - __GXSetDirtyState(); - } - - // Save current shadow register state if requested - if (__gx->dlSaveContext != 0) { - std::memcpy(&sSavedGXData, __gx, sizeof(sSavedGXData)); - } - - __gx->inDispList = 1; - - // Redirect FIFO writes to the user-provided buffer - aurora::gx::fifo::begin_display_list(static_cast(list), size); -} - -u32 GXEndDisplayList() { - // Flush any pending dirty state into the display list - if (__gx->dirtyState != 0) { - __GXSetDirtyState(); - } - - // End FIFO redirection and get the byte count (ROUNDUP32) - u32 bytesWritten = aurora::gx::fifo::end_display_list(); - - // Restore saved shadow register state - if (__gx->dlSaveContext != 0) { - std::memcpy(__gx, &sSavedGXData, sizeof(*__gx)); - } - - __gx->inDispList = 0; - - return bytesWritten; -} - -void GXCallDisplayList(const void* data, u32 nbytes) { - // Flush any pending dirty state before calling - if (__gx->dirtyState != 0) { - __GXSetDirtyState(); - } - - // Flush pending primitives - if (*reinterpret_cast(&__gx->vNum) != 0) { - __GXSendFlushPrim(); - } - - // Nested display-list calls add bytes instead of changing live renderer state. - if (aurora::gx::fifo::in_display_list()) { - aurora::gx::fifo::write_data(data, nbytes); - return; - } - - // Decode the display list immediately while its borrowed resources are valid. - aurora::gx::fifo::drain(); - aurora::gx::fifo::process_all(static_cast(data), nbytes, true); -} - -void GXCallDisplayListLE(const void* data, u32 nbytes) { - // Flush any pending dirty state before calling - if (__gx->dirtyState != 0) { - __GXSetDirtyState(); - } - - // Flush pending primitives - if (*reinterpret_cast(&__gx->vNum) != 0) { - __GXSendFlushPrim(); - } - - // Decode little-endian lists separately after finishing the normal FIFO work. - aurora::gx::fifo::drain(); - - // Process the display list through the command processor (little-endian) - aurora::gx::fifo::process_all(static_cast(data), nbytes, false); -} -} diff --git a/aurora-main/lib/dolphin/gx/GXDraw.cpp b/aurora-main/lib/dolphin/gx/GXDraw.cpp deleted file mode 100644 index 314104c..0000000 --- a/aurora-main/lib/dolphin/gx/GXDraw.cpp +++ /dev/null @@ -1,549 +0,0 @@ -#include "gx.hpp" - -extern "C" { - -static GXVtxDescList vcd[27]; -static GXVtxAttrFmtList vat[27]; - -static void GetVertState(void) { - GXGetVtxDescv(vcd); - GXGetVtxAttrFmtv(GX_VTXFMT3, vat); - GXClearVtxDesc(); - GXSetVtxDesc(GX_VA_POS, GX_DIRECT); - GXSetVtxDesc(GX_VA_NRM, GX_DIRECT); - GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); - GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0); -} - -static void RestoreVertState(void) { - GXSetVtxDescv(vcd); - GXSetVtxAttrFmtv(GX_VTXFMT3, vat); -} - -static void vsub(f32 p1[3], f32 p2[3], f32 u[3]) { - u32 i; - - for (i = 0; i < 3; i++) { - u[i] = p2[i] - p1[i]; - } -} - -static void vcross(f32 u[3], f32 v[3], f32 n[3]) { - f32 n1[3]; - - n1[0] = (u[1] * v[2]) - (u[2] * v[1]); - n1[1] = (u[2] * v[0]) - (u[0] * v[2]); - n1[2] = (u[0] * v[1]) - (u[1] * v[0]); - n[0] = n1[0]; - n[1] = n1[1]; - n[2] = n1[2]; -} - -static void normalize(f32 v[3]) { - f32 d = sqrtf((v[0] * v[0]) + (v[1] * v[1]) + (v[2] * v[2])); - - CHECK(d != 0.0f, "normalize: zero length vector"); - v[0] /= d; - v[1] /= d; - v[2] /= d; -} - -static void myvertex(f32 v[3], f32 n[3]) { - GXPosition3f32(v[0], v[1], v[2]); - GXNormal3f32(n[0], n[1], n[2]); -} - -static void DumpTriangle(f32 v0[3], f32 v1[3], f32 v2[3]) { - GXBegin(GX_TRIANGLES, GX_VTXFMT3, 3); - myvertex(v0, v0); - myvertex(v1, v1); - myvertex(v2, v2); - GXEnd(); -} - -static void Subdivide(u8 depth, f32 v0[3], f32 v1[3], f32 v2[3]) { - f32 v01[3]; - f32 v12[3]; - f32 v20[3]; - u32 i; - - if (depth == 0) { - DumpTriangle(v0, v1, v2); - return; - } - - for (i = 0; i < 3; i++) { - v01[i] = v0[i] + v1[i]; - v12[i] = v1[i] + v2[i]; - v20[i] = v2[i] + v0[i]; - } - - normalize(v01); - normalize(v12); - normalize(v20); - Subdivide(depth - 1, v0, v01, v20); - Subdivide(depth - 1, v1, v12, v01); - Subdivide(depth - 1, v2, v20, v12); - Subdivide(depth - 1, v01, v12, v20); -} - -static void SubDivTriangle(u8 depth, u8 i, f32 (*data)[3], u8 (*ndx)[3]) { - f32 *x0 = data[ndx[i][0]]; - f32 *x1 = data[ndx[i][1]]; - f32 *x2 = data[ndx[i][2]]; - - Subdivide(depth, x0, x1, x2); -} - -void GXDrawCylinder(u8 numEdges) { - s32 i; - f32 top; - f32 bottom; - f32 x[100]; - f32 y[100]; - f32 angle; - - top = 1.0f; - bottom = -top; - CHECK(numEdges <= 99, "GXDrawCylinder: too many edges"); - - GetVertState(); - - for (i = 0; i <= numEdges; i++) { - angle = (3.1415927f * (2.0f * i)) / numEdges; - x[i] = cosf(angle); - y[i] = sinf(angle); - } - - GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT3, (numEdges + 1) * 2); - for (i = 0; i <= numEdges; i++) { - GXPosition3f32(x[i], y[i], bottom); - GXNormal3f32(x[i], y[i], 0.0f); - GXPosition3f32(x[i], y[i], top); - GXNormal3f32(x[i], y[i], 0.0f); - - } - GXEnd(); - - GXBegin(GX_TRIANGLEFAN, GX_VTXFMT3, numEdges + 2); - GXPosition3f32(0.0f, 0.0f, top); - GXNormal3f32(0.0f, 0.0f, 1.0f); - for (i = 0; i <= numEdges; i++) { - GXPosition3f32(x[i], -y[i], top); - GXNormal3f32(0.0f, 0.0f, 1.0f); - - } - GXEnd(); - - GXBegin(GX_TRIANGLEFAN, GX_VTXFMT3, numEdges + 2); - GXPosition3f32(0.0f, 0.0f, bottom); - GXNormal3f32(0.0f, 0.0f, -1.0f); - for (i = 0; i <= numEdges; i++) { - GXPosition3f32(x[i], y[i], bottom); - GXNormal3f32(0.0f, 0.0f, -1.0f); - } - GXEnd(); - - RestoreVertState(); -} - -void GXDrawTorus(f32 rc, u8 numc, u8 numt) { - GXAttrType ttype; - s32 i, j, k; - f32 s, t; - f32 x, y, z; - f32 twopi = 6.2831855f; - f32 rt; - - CHECK(rc < 1.0f, "GXDrawTorus: doughnut too fat"); - - rt = 1.0f - rc; - GXGetVtxDesc(GX_VA_TEX0, &ttype); - GetVertState(); - - if (ttype != GX_NONE) { - GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); - GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); - } - - for (i = 0; i < numc; i++) { - GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT3, (numt + 1) * 2); - for (j = 0; j <= numt; j++) { - for (k = 1; k >= 0; k--) { - s = (i + k) % numc; - t = j % numt; - x = (rt - rc * cosf(s * twopi / numc)) * cosf(t * twopi / numt); - y = (rt - rc * cosf(s * twopi / numc)) * sinf(t * twopi / numt); - z = rc * sinf(s * twopi / numc); - GXPosition3f32(x, y, z); - x = -cosf(t * twopi / numt) * cosf(s * twopi / numc); - y = -sinf(t * twopi / numt) * cosf(s * twopi / numc); - z = sinf(s * twopi / numc); - GXNormal3f32(x, y, z); - if (ttype != GX_NONE) { - GXTexCoord2f32((i + k) / (f32)numc, j / (f32)numt); - } - } - } - GXEnd(); - } - RestoreVertState(); -} - -void GXDrawSphere(u8 numMajor, u8 numMinor) { - GXAttrType ttype; - f32 radius = 1.0f; - f32 majorStep = 3.1415927f / numMajor; - f32 minorStep = 6.2831855f / numMinor; - s32 i, j; - f32 a, b; - f32 r0, r1; - f32 z0, z1; - f32 c; - f32 x, y; - - GXGetVtxDesc(GX_VA_TEX0, &ttype); - GetVertState(); - - if (ttype != GX_NONE) { - GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); - GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_TEX0, GX_TEX_ST, GX_RGBA6, 0); - } - - for (i = 0; i < numMajor; i++) { - a = i * majorStep; - b = a + majorStep; - r0 = radius * sinf(a); - r1 = radius * sinf(b); - z0 = radius * cosf(a); - z1 = radius * cosf(b); - GXBegin(GX_TRIANGLESTRIP, GX_VTXFMT3, (numMinor + 1) * 2); - for (j = 0; j <= numMinor; j++) { - c = j * minorStep; - x = cosf(c); - y = sinf(c); - GXPosition3f32(x * r1, y * r1, z1); - GXNormal3f32((x * r1) / radius, (y * r1) / radius, z1 / radius); - if (ttype != GX_NONE) { - GXTexCoord2f32((f32)j / (f32)numMinor, (f32)(i + 1) / (f32)numMajor); - } - GXPosition3f32(x * r0, y * r0, z0); - GXNormal3f32((x * r0) / radius, (y * r0) / radius, z0 / radius); - if (ttype != GX_NONE) { - GXTexCoord2f32((f32)j / (f32)numMinor, (f32)i / (f32)numMajor); - } - } - GXEnd(); - } - RestoreVertState(); -} - -static void GXDrawCubeFace(f32 nx, f32 ny, f32 nz, f32 tx, f32 ty, f32 tz, f32 bx, f32 by, f32 bz, GXAttrType binormal, GXAttrType texture) { - GXPosition3f32(0.57735026f * (nx + tx + bx), 0.57735026f * (ny + ty + by), 0.57735026f * (nz + tz + bz)); - GXNormal3f32(nx, ny, nz); - - if (binormal != GX_NONE) { - GXNormal3f32(tx, ty, tz); - GXNormal3f32(bx, by, bz); - } - - if (texture != GX_NONE) { - GXTexCoord2s8(1, 1); - } - - GXPosition3f32(0.57735026f * (nx - tx + bx), 0.57735026f * (ny - ty + by), 0.57735026f * (nz - tz + bz)); - GXNormal3f32(nx, ny, nz); - - if (binormal != GX_NONE) { - GXNormal3f32(tx, ty, tz); - GXNormal3f32(bx, by, bz); - } - - if (texture != GX_NONE) { - GXTexCoord2s8(0, 1); - } - - GXPosition3f32(0.57735026f * (nx - tx - bx), 0.57735026f * (ny - ty - by), 0.57735026f * (nz - tz - bz)); - GXNormal3f32(nx, ny, nz); - - if (binormal != GX_NONE) { - GXNormal3f32(tx, ty, tz); - GXNormal3f32(bx, by, bz); - } - - if (texture != GX_NONE) { - GXTexCoord2s8(0, 0); - } - - GXPosition3f32(0.57735026f * (nx + tx - bx), 0.57735026f * (ny + ty - by), 0.57735026f * (nz + tz - bz)); - GXNormal3f32(nx, ny, nz); - - if (binormal != GX_NONE) { - GXNormal3f32(tx, ty, tz); - GXNormal3f32(bx, by, bz); - } - - if (texture != GX_NONE) { - GXTexCoord2s8(1, 0); - } -} - -void GXDrawCube(void) { - GXAttrType ntype; - GXAttrType ttype; - - GXGetVtxDesc(GX_VA_NBT, &ntype); - GXGetVtxDesc(GX_VA_TEX0, &ttype); - GetVertState(); - if (ntype != GX_NONE) { - GXSetVtxDesc(GX_VA_NBT, GX_DIRECT); - GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_NBT, GX_TEX_ST, GX_RGBA6, 0); - } - if (ttype != GX_NONE) { - GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); - GXSetVtxAttrFmt(GX_VTXFMT3, GX_VA_TEX0, GX_TEX_ST, GX_RGB8, 0); - } - - GXBegin(GX_QUADS, GX_VTXFMT3, 24); - GXDrawCubeFace(-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, ntype, ttype); - GXDrawCubeFace(1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, ntype, ttype); - GXDrawCubeFace(0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, ntype, ttype); - GXDrawCubeFace(0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, ntype, ttype); - GXDrawCubeFace(0.0f, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, ntype, ttype); - GXDrawCubeFace(0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, ntype, ttype); - GXEnd(); - - RestoreVertState(); -} - -static u32 polygons[12][5] = { - { 0, 12, 10, 11, 16 }, - { 1, 17, 8, 9, 13 }, - { 2, 14, 9, 8, 18 }, - { 3, 19, 11, 10, 15 }, - { 4, 14, 2, 3, 15 }, - { 5, 12, 0, 1, 13 }, - { 6, 17, 1, 0, 16 }, - { 7, 19, 3, 2, 18 }, - { 8, 17, 6, 7, 18 }, - { 9, 14, 4, 5, 13 }, - { 10, 12, 5, 4, 15 }, - { 11, 19, 7, 6, 16 }, -}; - -static f32 verts[20][3] = { - { -0.809015f, 0.0f, 0.309015f }, - { -0.809015f, 0.0f, -0.309015f }, - { 0.809015f, 0.0f, -0.309015f }, - { 0.809015f, 0.0f, 0.309015f }, - { 0.309015f, -0.809015f, 0.0f }, - { -0.309015f, -0.809015f, 0.0f }, - { -0.309015f, 0.809015f, 0 }, - { 0.309015f, 0.809015f, 0 }, - { 0.0f, 0.309015f, -0.809015f }, - { 0.0f, -0.309015f, -0.809015f }, - { 0.0f, -0.309015f, 0.809015f }, - { 0.0f, 0.309015f, 0.809015f }, - { -0.5f, -0.5f, 0.5 }, - { -0.5f, -0.5f, -0.5 }, - { 0.5f, -0.5f, -0.5 }, - { 0.5f, -0.5f, 0.5 }, - { -0.5f, 0.5f, 0.5 }, - { -0.5f, 0.5f, -0.5 }, - { 0.5f, 0.5f, -0.5 }, - { 0.5f, 0.5f, 0.5 }, -}; - -void GXDrawDodeca(void) { - u32 i; - f32 *p0; - f32 *p1; - f32 *p2; - f32 u[3]; - f32 v[3]; - f32 n[3]; - - GetVertState(); - for (i = 0; i < 12; i++) { - p0 = verts[polygons[i][0]]; - p1 = verts[polygons[i][1]]; - p2 = verts[polygons[i][2]]; - vsub(p1, p2, u); - vsub(p1, p0, v); - vcross(u, v, n); - normalize(n); - GXBegin(GX_TRIANGLEFAN, GX_VTXFMT3, 5); - myvertex(verts[polygons[i][4]], n); - myvertex(verts[polygons[i][3]], n); - myvertex(p2, n); - myvertex(p1, n); - myvertex(p0, n); - GXEnd(); - } - RestoreVertState(); -} - -static f32 odata[6][3] = { - { 1.0f, 0.0f, 0.0f }, - { -1.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f }, - { 0.0f, -1.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f }, - { 0.0f, 0.0f, -1.0f }, -}; - -static u8 ondex[8][3] = { - { 0, 4, 2 }, - { 1, 2, 4 }, - { 0, 3, 4 }, - { 1, 4, 3 }, - { 0, 2, 5 }, - { 1, 5, 2 }, - { 0, 5, 3 }, - { 1, 3, 5 }, -}; - -void GXDrawOctahedron(void) { - s32 i; - - GetVertState(); - for (i = 7; i >= 0; i--) { - SubDivTriangle(0, i, odata, ondex); - } - RestoreVertState(); -} - -static f32 idata[12][3] = { - { -0.5257311f, 0.0f, 0.8506508f }, - { 0.5257311f, 0.0f, 0.8506508f }, - { -0.5257311f, 0.0f, -0.8506508f }, - { 0.5257311f, 0.0f, -0.8506508f }, - { 0.0f, 0.8506508f, 0.5257311f }, - { 0.0f, 0.8506508f, -0.5257311f }, - { 0.0f, -0.8506508f, 0.5257311f }, - { 0.0f, -0.8506508f, -0.5257311f }, - { 0.8506508f, 0.5257311f, 0.0f }, - { -0.8506508f, 0.5257311f, 0.0f }, - { 0.8506508f, -0.5257311f, 0.0f }, - { -0.8506508f, -0.5257311f, 0.0f }, -}; - -static u8 uindex[20][3] = { - { 0, 4, 1 }, - { 0, 9, 4 }, - { 9, 5, 4 }, - { 4, 5, 8 }, - { 4, 8, 1 }, - { 8, 10, 1 }, - { 8, 3, 10 }, - { 5, 3, 8 }, - { 5, 2, 3 }, - { 2, 7, 3 }, - { 7, 10, 3 }, - { 7, 6, 10 }, - { 7, 11, 6 }, - { 11, 0, 6 }, - { 0, 1, 6 }, - { 6, 1, 10 }, - { 9, 0, 11 }, - { 9, 11, 2 }, - { 9, 2, 5 }, - { 7, 2, 11 }, -}; - -void GXDrawIcosahedron(void) { - s32 i; - - GetVertState(); - for (i = 19; i >= 0; i--) { - SubDivTriangle(0, i, idata, uindex); - } - RestoreVertState(); -} - -void GXDrawSphere1(u8 depth) { - s32 i; - - GetVertState(); - for (i = 19; i >= 0; i--) { - SubDivTriangle(depth, i, idata, uindex); - } - RestoreVertState(); -} - -static u32 CmpNormal32(f32 n1[3], f32 n2[3]) { - u32 i; - - for (i = 0; i < 3; i++) { - if (n1[i] != n2[i]) - return FALSE; - } - return TRUE; -} - -static u32 nrm_cnt; -static f32* nrm_tab; - -static void AddNormal(f32 n[3]) { - u32 indx; - u32 i; - - for (i = 0; i < nrm_cnt; i++) { - if (CmpNormal32(n, &nrm_tab[i * 3])) - return; - } - indx = nrm_cnt * 3; - nrm_tab[indx + 0] = n[0]; - nrm_tab[indx + 1] = n[1]; - nrm_tab[indx + 2] = n[2]; - nrm_cnt++; -} - -static void SubdivideNrm(u8 depth, f32 v0[3], f32 v1[3], f32 v2[3]) { - f32 v01[3]; - f32 v12[3]; - f32 v20[3]; - u32 i; - - if (depth == 0) { - AddNormal(v0); - AddNormal(v1); - AddNormal(v2); - return; - } - - for (i = 0; i < 3; i++) { - v01[i] = v0[i] + v1[i]; - v12[i] = v1[i] + v2[i]; - v20[i] = v2[i] + v0[i]; - } - - normalize(v01); - normalize(v12); - normalize(v20); - SubdivideNrm(depth - 1, v0, v01, v20); - SubdivideNrm(depth - 1, v1, v12, v01); - SubdivideNrm(depth - 1, v2, v20, v12); - SubdivideNrm(depth - 1, v01, v12, v20); -} - -static void SubDivNrm(u8 depth, u8 i, f32 (*data)[3], u8 (*ndx)[3]) { - f32* x0 = data[ndx[i][0]]; - f32* x1 = data[ndx[i][1]]; - f32* x2 = data[ndx[i][2]]; - - SubdivideNrm(depth, x0, x1, x2); -} - -u32 GXGenNormalTable(u8 depth, f32* table) { - s32 i; - - nrm_cnt = 0; - nrm_tab = table; - for (i = 7; i >= 0; i--) { - SubDivNrm(depth, i, odata, ondex); - } - - return nrm_cnt; -} -} diff --git a/aurora-main/lib/dolphin/gx/GXExtra.cpp b/aurora-main/lib/dolphin/gx/GXExtra.cpp deleted file mode 100644 index 32c0a79..0000000 --- a/aurora-main/lib/dolphin/gx/GXExtra.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "gx.hpp" -#include "__gx.h" -#include "dolphin/gx/GXAurora.h" - -extern "C" { -void GXDestroyTexObj(GXTexObj* obj_) { - auto* obj = reinterpret_cast(obj_); - // Destroying a GX texture descriptor must not discard cached texture pixels. - obj->texObjId = 0; -} - -void GXDestroyTlutObj(GXTlutObj* obj_) { - auto* obj = reinterpret_cast(obj_); - if (obj->tlutObjId != 0) { - GX_WRITE_AURORA(GX_LOAD_AURORA_DESTROY_TLUT); - GX_WRITE_U32(obj->tlutObjId); - } - obj->tlutObjId = 0; -} - -void GXDestroyCopyTex(void* dest) { - if (dest != nullptr) { - GX_WRITE_AURORA(GX_LOAD_AURORA_DESTROY_COPY_TEX); - GX_WRITE_U64(reinterpret_cast(dest)); - } -} -} diff --git a/aurora-main/lib/dolphin/gx/GXFifo.cpp b/aurora-main/lib/dolphin/gx/GXFifo.cpp deleted file mode 100644 index ab86547..0000000 --- a/aurora-main/lib/dolphin/gx/GXFifo.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "gx.hpp" - -extern "C" { - -static GXFifoObj* GPFifo; -static GXFifoObj* CPUFifo; - -void GXGetGPStatus(GXBool* overhi, GXBool* underlow, GXBool* readIdle, GXBool* cmdIdle, GXBool* brkpt) { - *overhi = *underlow = *readIdle = *cmdIdle = *brkpt = false; - *readIdle = true; -} - -// TODO GXGetFifoStatus - -void GXGetFifoPtrs(GXFifoObj* fifo, void** readPtr, void** writePtr) { - *readPtr = NULL; - *writePtr = NULL; -} - -GXFifoObj* GXGetCPUFifo() { return CPUFifo; } - -GXFifoObj* GXGetGPFifo() { return GPFifo; } - -// TODO GXGetFifoBase -// TODO GXGetFifoSize -// TODO GXGetFifoLimits -// TODO GXSetBreakPtCallback -// TODO GXEnableBreakPt -// TODO GXDisableBreakPt - -void GXInitFifoBase(GXFifoObj* fifo, void* base, u32 size) {} - -void GXInitFifoPtrs(GXFifoObj* fifo, void* readPtr, void* writePtr) {} - -// TODO GXInitFifoLimits - -void GXSetCPUFifo(GXFifoObj* fifo) { CPUFifo = fifo; } - -void GXSetGPFifo(GXFifoObj* fifo) { GPFifo = fifo; } - -void GXSaveCPUFifo(GXFifoObj* fifo) {} - -// TODO GXSaveGPFifo -// TODO GXRedirectWriteGatherPipe -// TODO GXRestoreWriteGatherPipe -// TODO GXSetCurrentGXThread -// TODO GXGetCurrentGXThread -// TODO GXGetOverflowCount -// TODO GXResetOverflowCount -} \ No newline at end of file diff --git a/aurora-main/lib/dolphin/gx/GXFrameBuffer.cpp b/aurora-main/lib/dolphin/gx/GXFrameBuffer.cpp deleted file mode 100644 index abd9f6c..0000000 --- a/aurora-main/lib/dolphin/gx/GXFrameBuffer.cpp +++ /dev/null @@ -1,595 +0,0 @@ -#include "gx.hpp" -#include "__gx.h" - -#include "../../gfx/tex_copy_conv.hpp" -#include "../../gfx/efb_ram_copy.hpp" -#include "../../gfx/texture.hpp" -#include "../../gx/fifo.hpp" -#include "../../internal.hpp" -#include "../../window.hpp" -#include "../../gfx/clear.hpp" -#include "../../webgpu/gpu.hpp" -#include "../vi/vi_internal.hpp" - -#include -#include -#include -#include - -namespace { -struct CopyClearState { - bool clearColor = false; - bool clearAlpha = false; - bool clearDepth = false; - aurora::Vec4 clearColorValue{0.f, 0.f, 0.f, 1.f}; -}; - -CopyClearState get_copy_clear_state(GXBool clear) { - if (!clear) { - return {}; - } - - CopyClearState state{ - .clearColor = g_gxState.colorUpdate, - .clearAlpha = g_gxState.alphaUpdate, - .clearDepth = g_gxState.depthUpdate, - .clearColorValue = g_gxState.clearColor, - }; - - if (!aurora::gx::render_target_has_alpha(g_gxState.pixelFmt)) { - // RGB and depth EFB formats do not have an alpha channel to clear. - state.clearAlpha = false; - } - - return state; -} - -struct CopySourceRect { - aurora::gfx::ClipRect clearRect; - aurora::Vec4 sampleRect; -}; - -CopySourceRect map_texture_copy_source(const aurora::gfx::ClipRect& source, bool renderSpace) { - if (renderSpace || g_gxState.viewportPolicy == AURORA_VIEWPORT_NATIVE) { - return { - .clearRect = source, - .sampleRect = {static_cast(source.x), static_cast(source.y), static_cast(source.width), - static_cast(source.height)}, - }; - } - - const auto [logicalWidth, logicalHeight] = aurora::gx::logical_fb_size(); - const auto [targetWidth, targetHeight] = aurora::gfx::get_render_target_size(); - if (logicalWidth == 0 || logicalHeight == 0 || targetWidth == 0 || targetHeight == 0) { - return { - .clearRect = source, - .sampleRect = {static_cast(source.x), static_cast(source.y), static_cast(source.width), - static_cast(source.height)}, - }; - } - - struct MappedEdge { - float sample; - int32_t nearest; - }; - const auto mapEdge = [](int32_t edge, uint32_t logicalSize, uint32_t targetSize) { - // Round scaled copy edges consistently to avoid seams and off-by-one pixels. - const int64_t numerator = static_cast(edge) * static_cast(targetSize); - const int64_t denominator = static_cast(logicalSize); - const int64_t quotient = numerator / denominator; - const int64_t remainder = numerator % denominator; - const int64_t remainderMagnitude = remainder < 0 ? -remainder : remainder; - const int64_t roundingThreshold = (denominator + 1) / 2; - const int64_t nearestValue = - quotient + (remainderMagnitude >= roundingThreshold ? (numerator < 0 ? -1 : 1) : 0); - return MappedEdge{ - .sample = static_cast(static_cast(numerator) / static_cast(denominator)), - .nearest = static_cast(nearestValue), - }; - }; - const auto left = mapEdge(source.x, logicalWidth, targetWidth); - const auto top = mapEdge(source.y, logicalHeight, targetHeight); - const auto right = mapEdge(source.x + source.width, logicalWidth, targetWidth); - const auto bottom = mapEdge(source.y + source.height, logicalHeight, targetHeight); - return { - .clearRect = - { - .x = left.nearest, - .y = top.nearest, - .width = std::max(right.nearest - left.nearest, 1), - .height = std::max(bottom.nearest - top.nearest, 1), - }, - .sampleRect = {left.sample, top.sample, right.sample - left.sample, bottom.sample - top.sample}, - }; -} - - - - - -u32 pack_copy_filter_samples(u8 reg, const std::array, 12>& samplePattern, size_t first) { - u32 value = static_cast(reg) << 24; - for (size_t i = 0; i < 6; ++i) { - const size_t sample = first + i; - const u8 component = samplePattern[sample / 2][sample % 2] & 0x0fu; - value |= static_cast(component) << (i * 4); - } - return value; -} - -u32 pack_copy_filter0(const std::array& vfilter) { - return 0x53000000u | (static_cast(vfilter[0] & 0x3fu) << 0) | - (static_cast(vfilter[1] & 0x3fu) << 6) | (static_cast(vfilter[2] & 0x3fu) << 12) | - (static_cast(vfilter[3] & 0x3fu) << 18); -} - -u32 pack_copy_filter1(const std::array& vfilter) { - return 0x54000000u | (static_cast(vfilter[4] & 0x3fu) << 0) | - (static_cast(vfilter[5] & 0x3fu) << 6) | (static_cast(vfilter[6] & 0x3fu) << 12); -} - -std::array combined_copy_filter_coefficients(const std::array& vfilter) { - if (!g_gxState.copyFilterVf) { - return {0, 64, 0}; - } - - return { - static_cast(vfilter[0]) + static_cast(vfilter[1]), - static_cast(vfilter[2]) + static_cast(vfilter[3]) + static_cast(vfilter[4]), - static_cast(vfilter[5]) + static_cast(vfilter[6]), - }; -} - -aurora::Vec2 scale_copy_dst(u32 logicalWidth, u32 logicalHeight) { - if (g_gxState.viewportPolicy == AURORA_VIEWPORT_NATIVE) { - return {logicalWidth, logicalHeight}; - } - - const auto [logicalFbWidth, logicalFbHeight] = aurora::gx::logical_fb_size(); - const auto [targetWidth, targetHeight] = aurora::gfx::get_render_target_size(); - if (logicalFbWidth == 0 || logicalFbHeight == 0 || targetWidth == 0 || targetHeight == 0) { - return {logicalWidth, logicalHeight}; - } - - const float scaleX = static_cast(targetWidth) / static_cast(logicalFbWidth); - const float scaleY = static_cast(targetHeight) / static_cast(logicalFbHeight); - const auto scaledWidth = std::max(static_cast(std::lround(static_cast(logicalWidth) * scaleX)), 1); - const auto scaledHeight = std::max(static_cast(std::lround(static_cast(logicalHeight) * scaleY)), 1); - return {scaledWidth, scaledHeight}; -} - -aurora::gfx::TextureHandle create_copy_texture(u32 width, u32 height, GXTexFmt texCopyFmt) { - if (aurora::gfx::tex_copy_conv::needs_conversion(texCopyFmt)) { - return aurora::gfx::new_conv_texture(width, height, texCopyFmt, "Copy Conv Texture"); - } - - const auto fmt = texCopyFmt == GX_TF_RGB565 ? GX_TF_RGB565 : GX_TF_RGBA8; - return aurora::gfx::new_render_texture(width, height, fmt, "Resolved Texture"); -} - - // Reuse retired copy targets to avoid unbounded GPU texture allocation. -struct CopyTexturePoolEntry { - aurora::gx::GXState::CopyTextureKey key; - u32 scaledWidth = 0; - u32 scaledHeight = 0; - aurora::gfx::TextureHandle handle; -}; -std::vector g_copyTexturePool; - // Keep only a few reusable copy targets per destination. -constexpr size_t kCopyTexturePoolPerKey = 3; - -aurora::gfx::TextureHandle acquire_copy_texture(const aurora::gx::GXState::CopyTextureKey& key, u32 width, u32 height, - GXTexFmt texCopyFmt) { - size_t sameKey = 0; - for (auto it = g_copyTexturePool.begin(); it != g_copyTexturePool.end();) { - if (!(it->key == key)) { - ++it; - continue; - } - // Discard retired targets when their internal resolution changes. - if ((it->scaledWidth != width || it->scaledHeight != height) && it->handle.use_count() <= 1) { - it = g_copyTexturePool.erase(it); - continue; - } - ++sameKey; - if (it->scaledWidth == width && it->scaledHeight == height && it->handle.use_count() == 1) { - return it->handle; - } - ++it; - } - - auto handle = create_copy_texture(width, height, texCopyFmt); - if (sameKey < kCopyTexturePoolPerKey) { - g_copyTexturePool.push_back({key, width, height, handle}); - } - return handle; -} - -u16 get_num_xfb_lines_internal(u16 efbHeight, u32 iScale) { - CHECK(efbHeight != 0, "GXGetNumXfbLines requires non-zero EFB height"); - CHECK(iScale != 0, "invalid XFB line scale"); - - const u32 count = static_cast(efbHeight - 1u) * 0x100u; - u32 realHeight = (count / iScale) + 1u; - - u32 reducedScale = iScale; - if (reducedScale > 0x80u && reducedScale < 0x100u) { - while ((reducedScale & 1u) == 0u) { - reducedScale >>= 1; - } - if (reducedScale != 0u && (efbHeight % reducedScale) == 0u) { - ++realHeight; - } - } - - return static_cast(std::min(realHeight, 0x400u)); -} - -u32 y_scale_to_integer(f32 yScale) { - CHECK(yScale > 0.f, "GX display copy y-scale must be positive"); - return static_cast(256.f / yScale) & 0x1ffu; -} - -} // namespace - -namespace aurora::gx { -void prune_copy_texture_pool(const void* dest) noexcept { - if (dest == nullptr) { - g_copyTexturePool.clear(); - return; - } - std::erase_if(g_copyTexturePool, [dest](const CopyTexturePoolEntry& entry) { return entry.key.dest == dest; }); -} -} // namespace aurora::gx - -extern "C" { -GXRenderModeObj GXNtsc480IntDf = { - VI_TVMODE_NTSC_INT, - 640, - 480, - 480, - 40, - 0, - 640, - 480, - VI_XFBMODE_DF, - 0, - 0, - {6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}, - {8, 8, 10, 12, 10, 8, 8}, -}; -GXRenderModeObj GXNtsc480Int = { - VI_TVMODE_NTSC_INT, - 640, - 480, - 480, - 40, - 0, - 640, - 480, - VI_XFBMODE_DF, - 0, - 0, - {6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}, - {0, 0, 21, 22, 21, 0, 0}, -}; -GXRenderModeObj GXPal528IntDf = { - VI_TVMODE_PAL_INT, - 704, - 528, - 480, - 40, - 0, - 640, - 480, - VI_XFBMODE_DF, - 0, - 0, - {6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}, - {8, 8, 10, 12, 10, 8, 8}, -}; -GXRenderModeObj GXMpal480IntDf = { - VI_TVMODE_PAL_INT, - 640, - 480, - 480, - 40, - 0, - 640, - 480, - VI_XFBMODE_DF, - 0, - 0, - {6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}, - {8, 8, 10, 12, 10, 8, 8}, -}; - -void GXAdjustForOverscan(GXRenderModeObj* rmin, GXRenderModeObj* rmout, u16 hor, u16 ver) { - *rmout = *rmin; - const auto renderSize = aurora::gfx::get_render_target_size(); - rmout->fbWidth = static_cast(std::min(renderSize.x, UINT16_MAX)); - rmout->efbHeight = static_cast(std::min(renderSize.y, UINT16_MAX)); - rmout->xfbHeight = static_cast(std::min(renderSize.y, UINT16_MAX)); -} - -void GXSetDispCopySrc(u16 left, u16 top, u16 wd, u16 ht) { - g_gxState.dispCopySrc = {left, top, wd, ht}; - GX_WRITE_RAS_REG(0x49000000u | ((static_cast(top) & 0x3ffu) << 10) | (static_cast(left) & 0x3ffu)); - GX_WRITE_RAS_REG(0x4a000000u | (((static_cast(ht) - 1u) * 0x400u) & 0x000ffc00u) | - ((static_cast(wd) - 1u) & 0x3ffu)); -} - -void GXSetTexCopySrc(u16 left, u16 top, u16 wd, u16 ht) { - g_gxState.texCopySrc = {left, top, wd, ht}; - g_gxState.texCopySrcRenderSpace = false; -} - -void GXSetDispCopyDst(u16 wd, u16 ht) { - g_gxState.dispCopyDstWidth = wd; - g_gxState.dispCopyDstHeight = ht; - GX_WRITE_RAS_REG(0x4d000000u | ((((static_cast(wd) & 0x7fffu) << 1) >> 5) & 0x3ffu)); -} - -void GXSetTexCopyDst(u16 wd, u16 ht, GXTexFmt fmt, GXBool mipmap) { - g_gxState.texCopyFmt = fmt; - g_gxState.texCopyDstWidth = wd; - g_gxState.texCopyDstHeight = ht; - g_gxState.texCopyHalfScale = mipmap != GX_FALSE; -} - -void GXSetDispCopyFrame2Field(u32 mode) { - g_gxState.dispCopyFrame2Field = mode & 3; -} - -void GXSetCopyClamp(GXFBClamp clamp) { - g_gxState.copyClamp = static_cast(static_cast(clamp) & 3); -} - -u32 GXSetDispCopyYScale(f32 vscale) { - const u32 iScale = y_scale_to_integer(vscale); - g_gxState.dispCopyYScale = vscale; - GX_WRITE_RAS_REG(0x4e000000u | iScale); - __gx->bpSent = 0; - return get_num_xfb_lines_internal(static_cast(g_gxState.dispCopySrc.height), iScale); -} - -void GXSetCopyClear(GXColor color, u32 depth) { - // BP 0x4F: clear color R + A - u32 reg0 = 0; - SET_REG_FIELD(0, reg0, 8, 0, color.r); - SET_REG_FIELD(0, reg0, 8, 8, color.a); - SET_REG_FIELD(0, reg0, 8, 24, 0x4F); - GX_WRITE_RAS_REG(reg0); - - // BP 0x50: clear color B + G - u32 reg1 = 0; - SET_REG_FIELD(0, reg1, 8, 0, color.b); - SET_REG_FIELD(0, reg1, 8, 8, color.g); - SET_REG_FIELD(0, reg1, 8, 24, 0x50); - GX_WRITE_RAS_REG(reg1); - - // BP 0x51: clear Z (24-bit) - u32 reg2 = 0; - SET_REG_FIELD(0, reg2, 24, 0, depth); - SET_REG_FIELD(0, reg2, 8, 24, 0x51); - GX_WRITE_RAS_REG(reg2); - __gx->bpSent = 1; -} - -void GXSetCopyFilter(GXBool aa, u8 sample_pattern[12][2], GXBool vf, u8 vfilter[7]) { - g_gxState.copyFilterAa = aa; - g_gxState.copyFilterVf = vf; - if (sample_pattern) { - for (size_t i = 0; i < g_gxState.copyFilterSamplePattern.size(); ++i) { - g_gxState.copyFilterSamplePattern[i][0] = sample_pattern[i][0]; - g_gxState.copyFilterSamplePattern[i][1] = sample_pattern[i][1]; - } - } - if (vfilter) { - for (size_t i = 0; i < g_gxState.copyFilterVFilter.size(); ++i) { - g_gxState.copyFilterVFilter[i] = vfilter[i]; - } - } - - if (!aa) { - for (auto& sample : g_gxState.copyFilterSamplePattern) { - sample = {6, 6}; - } - } - if (!vf) { - g_gxState.copyFilterVFilter = {0, 0, 21, 22, 21, 0, 0}; - } - - GX_WRITE_RAS_REG(pack_copy_filter_samples(0x01, g_gxState.copyFilterSamplePattern, 0)); - GX_WRITE_RAS_REG(pack_copy_filter_samples(0x02, g_gxState.copyFilterSamplePattern, 6)); - GX_WRITE_RAS_REG(pack_copy_filter_samples(0x03, g_gxState.copyFilterSamplePattern, 12)); - GX_WRITE_RAS_REG(pack_copy_filter_samples(0x04, g_gxState.copyFilterSamplePattern, 18)); - GX_WRITE_RAS_REG(pack_copy_filter0(g_gxState.copyFilterVFilter)); - GX_WRITE_RAS_REG(pack_copy_filter1(g_gxState.copyFilterVFilter)); - __gx->bpSent = 0; -} - -void GXSetDispCopyGamma(GXGamma gamma) { - g_gxState.dispCopyGamma = static_cast(static_cast(gamma) & 3u); - g_gxState.bpRegCache[0x52] = (g_gxState.bpRegCache[0x52] & ~(3u << 7)) | - ((static_cast(g_gxState.dispCopyGamma) & 3u) << 7); -} - -void GXCopyDisp(void* dest, GXBool clear) { - (void)dest; - // Finish queued commands before this copy reads live EFB state. - if (aurora::gx::fifo::get_buffer_size() != 0) { - aurora::gx::fifo::drain(); - } - const auto rect = aurora::gx::map_logical_scissor(g_gxState.dispCopySrc); - const auto logicalDstWidth = - std::max(g_gxState.dispCopyDstWidth != 0 ? g_gxState.dispCopyDstWidth : static_cast(g_gxState.dispCopySrc.width), 1); - const auto logicalDstHeight = - std::max(g_gxState.dispCopyDstHeight != 0 ? g_gxState.dispCopyDstHeight : static_cast(g_gxState.dispCopySrc.height), 1); - const auto [dstWidth, dstHeight] = scale_copy_dst(logicalDstWidth, logicalDstHeight); - - if (!g_gxState.displayCopyTexture || g_gxState.displayCopyWidth != dstWidth || - g_gxState.displayCopyHeight != dstHeight) { - g_gxState.displayCopyTexture = aurora::gfx::new_render_texture(dstWidth, dstHeight, GX_TF_RGBA8, "Display Copy"); - g_gxState.displayCopyWidth = dstWidth; - g_gxState.displayCopyHeight = dstHeight; - } - - const auto clearState = get_copy_clear_state(clear); - auto copyFilter = combined_copy_filter_coefficients(g_gxState.copyFilterVFilter); - if (aurora::g_config.disableCopyFilter) { - copyFilter = {0, copyFilter[0] + copyFilter[1] + copyFilter[2], 0}; - } - aurora::gfx::resolve_pass(g_gxState.displayCopyTexture, rect, clearState.clearColor, clearState.clearAlpha, - clearState.clearDepth, clearState.clearColorValue, aurora::gx::clear_depth_value(), - GX_TF_RGBA8, nullptr, false, ©Filter, false, - static_cast(rect.height) / std::max(g_gxState.dispCopySrc.height, 1.0f), - (g_gxState.copyClamp & GX_CLAMP_TOP) != 0, - (g_gxState.copyClamp & GX_CLAMP_BOTTOM) != 0); - aurora::gx::set_display_copy_present_source(); -} - -void GXCopyTex(void* dest, GXBool clear) { - // Texture copies must see all earlier draws and state changes. - if (aurora::gx::fifo::get_buffer_size() != 0) { - aurora::gx::fifo::drain(); - } - const auto sourceRect = map_texture_copy_source(g_gxState.texCopySrc, g_gxState.texCopySrcRenderSpace); - const auto rect = sourceRect.clearRect; - // Keep guest dimensions for cache identity while preserving scaled GPU detail. - const auto logicalDstWidth = std::max(g_gxState.texCopyDstWidth, 1); - const auto logicalDstHeight = std::max(g_gxState.texCopyDstHeight, 1); - const auto [scaledDstWidth, scaledDstHeight] = scale_copy_dst(logicalDstWidth, logicalDstHeight); - const auto texCopyFmt = g_gxState.texCopyFmt; - const bool sourceHasAlpha = aurora::gx::render_target_has_alpha(g_gxState.pixelFmt); - const bool forceOpaqueAlpha = !sourceHasAlpha && !aurora::gx::is_depth_format(texCopyFmt); - const auto resolveFmt = texCopyFmt; - - const aurora::gx::GXState::CopyTextureKey key{ - .dest = dest, - .width = logicalDstWidth, - .height = logicalDstHeight, - .format = texCopyFmt, - }; - // Keep one live copy per destination and retire stale GPU textures. - for (auto cacheIt = g_gxState.copyTextureCache.begin(); cacheIt != g_gxState.copyTextureCache.end();) { - if (cacheIt->first.dest == dest && !(cacheIt->first == key)) { - g_gxState.copyTextureCache.erase(cacheIt++); - } else { - ++cacheIt; - } - } - auto it = g_gxState.copyTextureCache.find(key); - if (it == g_gxState.copyTextureCache.end()) { - auto handle = acquire_copy_texture(key, scaledDstWidth, scaledDstHeight, texCopyFmt); - it = g_gxState.copyTextureCache.emplace(key, aurora::gx::GXState::CopyTextureRef{.handle = handle, .revision = 0}).first; - } - auto& handle = it->second; - const u32 currentFrame = aurora::gfx::current_frame(); - const bool sampledThisFrame = handle.sampledThisFrame && handle.lastSampledFrame == currentFrame; - const bool scaledSizeChanged = !handle.handle || handle.handle->size.width != scaledDstWidth || - handle.handle->size.height != scaledDstHeight; - auto clearState = get_copy_clear_state(clear); - if (sampledThisFrame || scaledSizeChanged) { - const u32 revision = handle.revision; - const u32 lastProducedFrame = handle.lastProducedFrame; - handle = aurora::gx::GXState::CopyTextureRef{ - .handle = acquire_copy_texture(key, scaledDstWidth, scaledDstHeight, texCopyFmt), - .revision = revision, - .lastProducedFrame = lastProducedFrame, - }; - } - - const bool alphaUpdate = g_gxState.alphaUpdate && aurora::gx::render_target_has_alpha(g_gxState.pixelFmt); - if (alphaUpdate && g_gxState.dstAlpha != UINT32_MAX) { - if (!clear) { - // TODO: Confirm how this copy should handle alpha without changing the EFB. - } - // Clear alpha with a pipeline that matches the pass sample count. - aurora::gfx::push_draw_command(aurora::gfx::clear::DrawData{ - .pipeline = aurora::gfx::pipeline_ref(aurora::gfx::clear::PipelineConfig{ - .msaaSamples = aurora::gfx::get_sample_count(), - .clearColor = false, - .clearAlpha = true, - .clearDepth = false, - }), - .color = wgpu::Color{0.f, 0.f, 0.f, g_gxState.dstAlpha / 255.f}, - }); - } - if (aurora::gx::render_target_has_alpha(g_gxState.pixelFmt)) { - clearState.clearAlpha = clear && alphaUpdate; - } - const auto copyFilter = combined_copy_filter_coefficients(g_gxState.copyFilterVFilter); - // Skip only recurring color copies so one-shot copies are never lost. - const bool producedConsecutively = handle.revision != 0 && currentFrame - handle.lastProducedFrame <= 1; - const bool persistentCopy = !aurora::gx::is_depth_format(texCopyFmt) && !producedConsecutively; - aurora::gfx::resolve_pass(handle.handle, rect, clearState.clearColor, clearState.clearAlpha, clearState.clearDepth, - clearState.clearColorValue, aurora::gx::clear_depth_value(), resolveFmt, - &sourceRect.sampleRect, g_gxState.texCopyHalfScale, ©Filter, forceOpaqueAlpha, - sourceRect.sampleRect.w() / std::max(g_gxState.texCopySrc.height, 1.0f), - (g_gxState.copyClamp & GX_CLAMP_TOP) != 0, - (g_gxState.copyClamp & GX_CLAMP_BOTTOM) != 0, persistentCopy); - ++handle.revision; - handle.lastProducedFrame = currentFrame; - handle.width = logicalDstWidth; - handle.height = logicalDstHeight; - handle.format = texCopyFmt; - handle.dataSize = GXGetTexBufferSize(static_cast(logicalDstWidth), static_cast(logicalDstHeight), texCopyFmt, GX_FALSE, 0); - aurora::gx::notify_copy_texture_created(); - g_gxState.copyTextures[dest] = handle; - // Keep the GPU copy and download it only if guest code reads the destination. - aurora::gfx::efb_ram::schedule(dest, logicalDstWidth, logicalDstHeight, texCopyFmt, handle.handle); -} - -void GXClearBoundingBox() { - g_gxState.boundingBox = {1023, 0, 1023, 0}; - GX_WRITE_RAS_REG(0x550003FFu); - GX_WRITE_RAS_REG(0x560003FFu); - __gx->bpSent = 0; -} - -void GXReadBoundingBox(u16* left, u16* right, u16* top, u16* bottom) { - if (left) { - *left = g_gxState.boundingBox[0]; - } - if (right) { - *right = g_gxState.boundingBox[1]; - } - if (top) { - *top = g_gxState.boundingBox[2]; - } - if (bottom) { - *bottom = g_gxState.boundingBox[3]; - } -} - -u16 GXGetNumXfbLines(u16 efbHeight, f32 yScale) { - return get_num_xfb_lines_internal(efbHeight, y_scale_to_integer(yScale)); -} - -f32 GXGetYScaleFactor(u16 efbHeight, u16 xfbHeight) { - CHECK(efbHeight != 0, "GXGetYScaleFactor requires non-zero EFB height"); - CHECK(xfbHeight != 0 && xfbHeight <= 1024, "GXGetYScaleFactor requires 1..1024 XFB lines"); - - u32 targetHeight = xfbHeight; - f32 yScale = static_cast(targetHeight) / static_cast(efbHeight); - u16 realHeight = GXGetNumXfbLines(efbHeight, yScale); - - while (realHeight > xfbHeight && targetHeight > 1) { - --targetHeight; - yScale = static_cast(targetHeight) / static_cast(efbHeight); - realHeight = GXGetNumXfbLines(efbHeight, yScale); - } - - f32 resultScale = yScale; - while (realHeight < xfbHeight && targetHeight < 1024) { - resultScale = yScale; - ++targetHeight; - yScale = static_cast(targetHeight) / static_cast(efbHeight); - realHeight = GXGetNumXfbLines(efbHeight, yScale); - } - - return resultScale; -} - -} diff --git a/aurora-main/lib/dolphin/gx/GXGeometry.cpp b/aurora-main/lib/dolphin/gx/GXGeometry.cpp deleted file mode 100644 index 2e54e10..0000000 --- a/aurora-main/lib/dolphin/gx/GXGeometry.cpp +++ /dev/null @@ -1,455 +0,0 @@ -#include "gx.hpp" -#include "__gx.h" -#include "dolphin/gd/GDGeometry.h" -#include "../../gx/fifo.hpp" - -static inline void SETVCDATTR(GXAttr attr, GXAttrType type) { - switch (attr) { - case GX_VA_PNMTXIDX: - SET_REG_FIELD(0, __gx->vcdLo, 1, 0, type); - break; - case GX_VA_TEX0MTXIDX: - SET_REG_FIELD(0, __gx->vcdLo, 1, 1, type); - break; - case GX_VA_TEX1MTXIDX: - SET_REG_FIELD(0, __gx->vcdLo, 1, 2, type); - break; - case GX_VA_TEX2MTXIDX: - SET_REG_FIELD(0, __gx->vcdLo, 1, 3, type); - break; - case GX_VA_TEX3MTXIDX: - SET_REG_FIELD(0, __gx->vcdLo, 1, 4, type); - break; - case GX_VA_TEX4MTXIDX: - SET_REG_FIELD(0, __gx->vcdLo, 1, 5, type); - break; - case GX_VA_TEX5MTXIDX: - SET_REG_FIELD(0, __gx->vcdLo, 1, 6, type); - break; - case GX_VA_TEX6MTXIDX: - SET_REG_FIELD(0, __gx->vcdLo, 1, 7, type); - break; - case GX_VA_TEX7MTXIDX: - SET_REG_FIELD(0, __gx->vcdLo, 1, 8, type); - break; - case GX_VA_POS: - SET_REG_FIELD(0, __gx->vcdLo, 2, 9, type); - break; - case GX_VA_NRM: - __gx->hasNrms = (type != 0); - if (type != GX_NONE) { - __gx->nrmType = type; - } - break; - case GX_VA_NBT: - __gx->hasBiNrms = (type != 0); - if (type != GX_NONE) { - __gx->nrmType = type; - } - break; - case GX_VA_CLR0: - SET_REG_FIELD(0, __gx->vcdLo, 2, 13, type); - break; - case GX_VA_CLR1: - SET_REG_FIELD(0, __gx->vcdLo, 2, 15, type); - break; - case GX_VA_TEX0: - SET_REG_FIELD(0, __gx->vcdHi, 2, 0, type); - break; - case GX_VA_TEX1: - SET_REG_FIELD(0, __gx->vcdHi, 2, 2, type); - break; - case GX_VA_TEX2: - SET_REG_FIELD(0, __gx->vcdHi, 2, 4, type); - break; - case GX_VA_TEX3: - SET_REG_FIELD(0, __gx->vcdHi, 2, 6, type); - break; - case GX_VA_TEX4: - SET_REG_FIELD(0, __gx->vcdHi, 2, 8, type); - break; - case GX_VA_TEX5: - SET_REG_FIELD(0, __gx->vcdHi, 2, 10, type); - break; - case GX_VA_TEX6: - SET_REG_FIELD(0, __gx->vcdHi, 2, 12, type); - break; - case GX_VA_TEX7: - SET_REG_FIELD(0, __gx->vcdHi, 2, 14, type); - break; - default: - break; - } -} - -static inline void SETVAT(u32* va, u32* vb, u32* vc, GXAttr attr, GXCompCnt cnt, GXCompType type, u8 frac) { - switch (attr) { - case GX_VA_POS: - SET_REG_FIELD(0, *va, 1, 0, cnt); - SET_REG_FIELD(0, *va, 3, 1, type); - SET_REG_FIELD(0, *va, 5, 4, frac); - break; - case GX_VA_NRM: - case GX_VA_NBT: - SET_REG_FIELD(0, *va, 3, 10, type); - if (cnt == GX_NRM_NBT3) { - SET_REG_FIELD(0, *va, 1, 9, 1); - SET_REG_FIELD(0, *va, 1, 31, 1); - } else { - SET_REG_FIELD(0, *va, 1, 9, cnt); - SET_REG_FIELD(0, *va, 1, 31, 0); - } - break; - case GX_VA_CLR0: - SET_REG_FIELD(0, *va, 1, 13, cnt); - SET_REG_FIELD(0, *va, 3, 14, type); - break; - case GX_VA_CLR1: - SET_REG_FIELD(0, *va, 1, 17, cnt); - SET_REG_FIELD(0, *va, 3, 18, type); - break; - case GX_VA_TEX0: - SET_REG_FIELD(0, *va, 1, 21, cnt); - SET_REG_FIELD(0, *va, 3, 22, type); - SET_REG_FIELD(0, *va, 5, 25, frac); - break; - case GX_VA_TEX1: - SET_REG_FIELD(0, *vb, 1, 0, cnt); - SET_REG_FIELD(0, *vb, 3, 1, type); - SET_REG_FIELD(0, *vb, 5, 4, frac); - break; - case GX_VA_TEX2: - SET_REG_FIELD(0, *vb, 1, 9, cnt); - SET_REG_FIELD(0, *vb, 3, 10, type); - SET_REG_FIELD(0, *vb, 5, 13, frac); - break; - case GX_VA_TEX3: - SET_REG_FIELD(0, *vb, 1, 18, cnt); - SET_REG_FIELD(0, *vb, 3, 19, type); - SET_REG_FIELD(0, *vb, 5, 22, frac); - break; - case GX_VA_TEX4: - SET_REG_FIELD(0, *vb, 1, 27, cnt); - SET_REG_FIELD(0, *vb, 3, 28, type); - SET_REG_FIELD(0, *vc, 5, 0, frac); - break; - case GX_VA_TEX5: - SET_REG_FIELD(0, *vc, 1, 5, cnt); - SET_REG_FIELD(0, *vc, 3, 6, type); - SET_REG_FIELD(0, *vc, 5, 9, frac); - break; - case GX_VA_TEX6: - SET_REG_FIELD(0, *vc, 1, 14, cnt); - SET_REG_FIELD(0, *vc, 3, 15, type); - SET_REG_FIELD(0, *vc, 5, 18, frac); - break; - case GX_VA_TEX7: - SET_REG_FIELD(0, *vc, 1, 23, cnt); - SET_REG_FIELD(0, *vc, 3, 24, type); - SET_REG_FIELD(0, *vc, 5, 27, frac); - break; - default: - break; - } -} - -static inline bool AuroraVtxDescDiffers(GXAttr attr, GXAttrType type) { - return attr >= GX_VA_PNMTXIDX && attr < GX_VA_MAX_ATTR && g_gxState.vtxDesc[attr] != type; -} - -static inline bool AuroraVtxAttrFmtDiffers(GXVtxFmt vtxfmt, GXAttr attr, GXCompCnt cnt, GXCompType type, u8 frac) { - if (vtxfmt < GX_VTXFMT0 || vtxfmt >= GX_MAX_VTXFMT || attr < GX_VA_POS || attr >= GX_VA_MAX_ATTR) { - return true; - } - const auto& fmt = g_gxState.vtxFmts[vtxfmt].attrs[attr]; - return fmt.cnt != cnt || fmt.type != type || fmt.frac != frac; -} - -extern "C" { - -void GXSetVtxDesc(GXAttr attr, GXAttrType type) { - const u32 oldVcdLo = __gx->vcdLo; - const u32 oldVcdHi = __gx->vcdHi; - const u8 oldHasNrms = __gx->hasNrms; - const u8 oldHasBiNrms = __gx->hasBiNrms; - const u32 oldNrmType = __gx->nrmType; - const bool auroraStateChanged = AuroraVtxDescDiffers(attr, type); - - SETVCDATTR(attr, type); - if (__gx->hasNrms || __gx->hasBiNrms) { - SET_REG_FIELD(0, __gx->vcdLo, 2, 11, __gx->nrmType); - } else { - SET_REG_FIELD(0, __gx->vcdLo, 2, 11, 0); - } - if (aurora::gx::fifo::in_display_list() || auroraStateChanged || __gx->vcdLo != oldVcdLo || - __gx->vcdHi != oldVcdHi || __gx->hasNrms != oldHasNrms || __gx->hasBiNrms != oldHasBiNrms || - __gx->nrmType != oldNrmType) { - __gx->dirtyState |= 8; - } -} - -void GXSetSourceVtxDesc(GXAttr attr, GXAttrType type) { - if (attr >= GX_VA_PNMTXIDX && attr < GX_VA_MAX_ATTR) { - g_gxState.sourceVtxDesc[attr] = type; - } -} - -void GXSetVtxDescv(GXVtxDescList* list) { - const u32 oldVcdLo = __gx->vcdLo; - const u32 oldVcdHi = __gx->vcdHi; - const u8 oldHasNrms = __gx->hasNrms; - const u8 oldHasBiNrms = __gx->hasBiNrms; - const u32 oldNrmType = __gx->nrmType; - bool auroraStateChanged = false; - - while (list->attr != GX_VA_NULL) { - auroraStateChanged = auroraStateChanged || AuroraVtxDescDiffers(list->attr, list->type); - SETVCDATTR(list->attr, list->type); - ++list; - } - if (__gx->hasNrms || __gx->hasBiNrms) { - SET_REG_FIELD(0, __gx->vcdLo, 2, 11, __gx->nrmType); - } else { - SET_REG_FIELD(0, __gx->vcdLo, 2, 11, 0); - } - if (aurora::gx::fifo::in_display_list() || auroraStateChanged || __gx->vcdLo != oldVcdLo || - __gx->vcdHi != oldVcdHi || __gx->hasNrms != oldHasNrms || __gx->hasBiNrms != oldHasBiNrms || - __gx->nrmType != oldNrmType) { - __gx->dirtyState |= 8; - } -} - -void GXClearVtxDesc() { - __gx->vcdLo = 0; - SET_REG_FIELD(0, __gx->vcdLo, 2, 9, 1); // GX_VA_POS = GX_DIRECT - __gx->vcdHi = 0; - __gx->hasNrms = 0; - __gx->hasBiNrms = 0; - __gx->dirtyState |= 8; -} - -void GXSetVtxAttrFmt(GXVtxFmt vtxfmt, GXAttr attr, GXCompCnt cnt, GXCompType type, u8 frac) { - CHECK(vtxfmt >= GX_VTXFMT0 && vtxfmt < GX_MAX_VTXFMT, "invalid vtxfmt {}", underlying(vtxfmt)); - CHECK(attr >= GX_VA_POS && attr < GX_VA_MAX_ATTR, "invalid attr {}", underlying(attr)); - - u32* va = &__gx->vatA[vtxfmt]; - u32* vb = &__gx->vatB[vtxfmt]; - u32* vc = &__gx->vatC[vtxfmt]; - const u32 oldVa = *va; - const u32 oldVb = *vb; - const u32 oldVc = *vc; - const bool auroraStateChanged = AuroraVtxAttrFmtDiffers(vtxfmt, attr, cnt, type, frac); - SETVAT(va, vb, vc, attr, cnt, type, frac); - if (aurora::gx::fifo::in_display_list() || auroraStateChanged || *va != oldVa || *vb != oldVb || - *vc != oldVc) { - __gx->dirtyState |= 0x10; - __gx->dirtyVAT |= static_cast(1 << vtxfmt); - } -} - -void GXSetVtxAttrFmtv(GXVtxFmt vtxfmt, const GXVtxAttrFmtList* list) { - CHECK(vtxfmt >= GX_VTXFMT0 && vtxfmt < GX_MAX_VTXFMT, "invalid vtxfmt {}", underlying(vtxfmt)); - CHECK(list != nullptr, "null vtx attr fmt list"); - - u32* va = &__gx->vatA[vtxfmt]; - u32* vb = &__gx->vatB[vtxfmt]; - u32* vc = &__gx->vatC[vtxfmt]; - const u32 oldVa = *va; - const u32 oldVb = *vb; - const u32 oldVc = *vc; - bool auroraStateChanged = false; - while (list->attr != GX_VA_NULL) { - CHECK(list->attr >= GX_VA_POS && list->attr < GX_VA_MAX_ATTR, "invalid attr {}", underlying(list->attr)); - auroraStateChanged = - auroraStateChanged || AuroraVtxAttrFmtDiffers(vtxfmt, list->attr, list->cnt, list->type, list->frac); - SETVAT(va, vb, vc, list->attr, list->cnt, list->type, list->frac); - ++list; - } - - if (aurora::gx::fifo::in_display_list() || auroraStateChanged || *va != oldVa || *vb != oldVb || - *vc != oldVc) { - __gx->dirtyState |= 0x10; - __gx->dirtyVAT |= static_cast(1 << vtxfmt); - } -} - -void GXSetArray(GXAttr attr, const void* data, u32 size, u8 stride, bool le) { - GXAttr cpAttr = static_cast(attr); - if (attr == GX_VA_NBT) { - cpAttr = GX_VA_NRM; - } - u32 cpIdx = cpAttr - GX_VA_POS; - - assert((cpIdx & ~0xF) == 0); - - // Write array base - GX_WRITE_AURORA(GX_LOAD_AURORA_ARRAYBASE | cpIdx); - GX_WRITE_U64(reinterpret_cast(data)); - GX_WRITE_U32(size); - GX_WRITE_U8(le ? 1 : 0); - - // Write array stride - GX_WRITE_CP_REG(CP_REG_ARRAYSTRIDE_ID | cpIdx, stride); -} - -void GXSetTexCoordGen2(GXTexCoordID dst, GXTexGenType type, GXTexGenSrc src, u32 mtx, GXBool normalize, u32 postMtx) { - CHECK(dst >= GX_TEXCOORD0 && dst <= GX_TEXCOORD7, "invalid tex coord {}", underlying(dst)); - - u32 reg = 0; - u32 row = 5; - u32 form = 0; - - switch (src) { - case GX_TG_POS: - row = 0; - form = 1; - break; - case GX_TG_NRM: - row = 1; - form = 1; - break; - case GX_TG_BINRM: - row = 3; - form = 1; - break; - case GX_TG_TANGENT: - row = 4; - form = 1; - break; - case GX_TG_COLOR0: - row = 2; - break; - case GX_TG_COLOR1: - row = 2; - break; - case GX_TG_TEX0: - row = 5; - break; - case GX_TG_TEX1: - row = 6; - break; - case GX_TG_TEX2: - row = 7; - break; - case GX_TG_TEX3: - row = 8; - break; - case GX_TG_TEX4: - row = 9; - break; - case GX_TG_TEX5: - row = 10; - break; - case GX_TG_TEX6: - row = 11; - break; - case GX_TG_TEX7: - row = 12; - break; - default: - break; - } - - switch (type) { - case GX_TG_MTX2x4: - SET_REG_FIELD(0, reg, 1, 1, 0); - SET_REG_FIELD(0, reg, 1, 2, form); - SET_REG_FIELD(0, reg, 3, 4, 0); - SET_REG_FIELD(0, reg, 5, 7, row); - break; - case GX_TG_MTX3x4: - SET_REG_FIELD(0, reg, 1, 1, 1); - SET_REG_FIELD(0, reg, 1, 2, form); - SET_REG_FIELD(0, reg, 3, 4, 0); - SET_REG_FIELD(0, reg, 5, 7, row); - break; - case GX_TG_SRTG: - SET_REG_FIELD(0, reg, 1, 1, 0); - SET_REG_FIELD(0, reg, 1, 2, form); - if (src == GX_TG_COLOR0) { - SET_REG_FIELD(0, reg, 3, 4, 2); - } else { - SET_REG_FIELD(0, reg, 3, 4, 3); - } - SET_REG_FIELD(0, reg, 5, 7, 2); - break; - default: - // Bump mapping types - if (type >= 2 && type <= 9) { - SET_REG_FIELD(0, reg, 1, 1, 0); - SET_REG_FIELD(0, reg, 1, 2, form); - SET_REG_FIELD(0, reg, 3, 4, 1); - SET_REG_FIELD(0, reg, 5, 7, row); - SET_REG_FIELD(0, reg, 3, 12, src - 12); - SET_REG_FIELD(0, reg, 3, 15, type - 2); - } - break; - } - - GX_WRITE_XF_REG(dst + 0x40, reg); - - // Post-transform register - u32 postReg = 0; - SET_REG_FIELD(0, postReg, 6, 0, postMtx - 64); - SET_REG_FIELD(0, postReg, 1, 8, normalize); - GX_WRITE_XF_REG(dst + 0x50, postReg); - - // Update matrix index shadows - switch (dst) { - case GX_TEXCOORD0: - SET_REG_FIELD(0, __gx->matIdxA, 6, 6, mtx); - break; - case GX_TEXCOORD1: - SET_REG_FIELD(0, __gx->matIdxA, 6, 12, mtx); - break; - case GX_TEXCOORD2: - SET_REG_FIELD(0, __gx->matIdxA, 6, 18, mtx); - break; - case GX_TEXCOORD3: - SET_REG_FIELD(0, __gx->matIdxA, 6, 24, mtx); - break; - case GX_TEXCOORD4: - SET_REG_FIELD(0, __gx->matIdxB, 6, 0, mtx); - break; - case GX_TEXCOORD5: - SET_REG_FIELD(0, __gx->matIdxB, 6, 6, mtx); - break; - case GX_TEXCOORD6: - SET_REG_FIELD(0, __gx->matIdxB, 6, 12, mtx); - break; - default: - SET_REG_FIELD(0, __gx->matIdxB, 6, 18, mtx); - break; - } - __GXSetMatrixIndex(static_cast(dst + 1)); -} - -void GXSetNumTexGens(u8 num) { - SET_REG_FIELD(0, __gx->genMode, 4, 0, num); - GX_WRITE_XF_REG(0x3F, num); - __gx->dirtyState |= 4; -} - -void GXInvalidateVtxCache() { GX_WRITE_U8(0x48); } - -void GXSetLineWidth(u8 width, GXTexOffset offs) { - SET_REG_FIELD(0, __gx->lpSize, 8, 0, width); - SET_REG_FIELD(0, __gx->lpSize, 3, 16, offs); - GX_WRITE_RAS_REG(__gx->lpSize); - __gx->bpSent = 1; -} - -void GXSetPointSize(u8 pointSize, GXTexOffset texOffsets) { - SET_REG_FIELD(0, __gx->lpSize, 8, 8, pointSize); - SET_REG_FIELD(0, __gx->lpSize, 3, 19, texOffsets); - GX_WRITE_RAS_REG(__gx->lpSize); - __gx->bpSent = 1; -} - -void GXEnableTexOffsets(GXTexCoordID coord, GXBool line_enable, GXBool point_enable) { - SET_REG_FIELD(0, __gx->suTs0[coord], 1, 18, line_enable); - SET_REG_FIELD(0, __gx->suTs0[coord], 1, 19, point_enable); - GX_WRITE_RAS_REG(__gx->suTs0[coord]); - __gx->bpSent = 1; -} -} diff --git a/aurora-main/lib/dolphin/gx/GXGet.cpp b/aurora-main/lib/dolphin/gx/GXGet.cpp deleted file mode 100644 index ccefbbc..0000000 --- a/aurora-main/lib/dolphin/gx/GXGet.cpp +++ /dev/null @@ -1,337 +0,0 @@ -#include "gx.hpp" -#include "__gx.h" - -#include "../../gfx/common.hpp" -#include "../../gfx/texture.hpp" - -extern "C" { - -static inline u8 GetFracForNrm(GXCompType type) { - switch (type) { - case GX_S8: - return 6; - case GX_S16: - return 14; - default: - return 0; - } -} - -void GXGetVtxDesc(GXAttr attr, GXAttrType* type) { - CHECK(type != nullptr, "null vtx desc output"); - - u32 cpType = 0; - switch (attr) { - case GX_VA_PNMTXIDX: - cpType = GET_REG_FIELD(__gx->vcdLo, 1, 0); - break; - case GX_VA_TEX0MTXIDX: - cpType = GET_REG_FIELD(__gx->vcdLo, 1, 1); - break; - case GX_VA_TEX1MTXIDX: - cpType = GET_REG_FIELD(__gx->vcdLo, 1, 2); - break; - case GX_VA_TEX2MTXIDX: - cpType = GET_REG_FIELD(__gx->vcdLo, 1, 3); - break; - case GX_VA_TEX3MTXIDX: - cpType = GET_REG_FIELD(__gx->vcdLo, 1, 4); - break; - case GX_VA_TEX4MTXIDX: - cpType = GET_REG_FIELD(__gx->vcdLo, 1, 5); - break; - case GX_VA_TEX5MTXIDX: - cpType = GET_REG_FIELD(__gx->vcdLo, 1, 6); - break; - case GX_VA_TEX6MTXIDX: - cpType = GET_REG_FIELD(__gx->vcdLo, 1, 7); - break; - case GX_VA_TEX7MTXIDX: - cpType = GET_REG_FIELD(__gx->vcdLo, 1, 8); - break; - case GX_VA_POS: - cpType = GET_REG_FIELD(__gx->vcdLo, 2, 9); - break; - case GX_VA_NRM: - cpType = __gx->hasNrms ? GET_REG_FIELD(__gx->vcdLo, 2, 11) : GX_NONE; - break; - case GX_VA_NBT: - cpType = __gx->hasBiNrms ? GET_REG_FIELD(__gx->vcdLo, 2, 11) : GX_NONE; - break; - case GX_VA_CLR0: - cpType = GET_REG_FIELD(__gx->vcdLo, 2, 13); - break; - case GX_VA_CLR1: - cpType = GET_REG_FIELD(__gx->vcdLo, 2, 15); - break; - case GX_VA_TEX0: - cpType = GET_REG_FIELD(__gx->vcdHi, 2, 0); - break; - case GX_VA_TEX1: - cpType = GET_REG_FIELD(__gx->vcdHi, 2, 2); - break; - case GX_VA_TEX2: - cpType = GET_REG_FIELD(__gx->vcdHi, 2, 4); - break; - case GX_VA_TEX3: - cpType = GET_REG_FIELD(__gx->vcdHi, 2, 6); - break; - case GX_VA_TEX4: - cpType = GET_REG_FIELD(__gx->vcdHi, 2, 8); - break; - case GX_VA_TEX5: - cpType = GET_REG_FIELD(__gx->vcdHi, 2, 10); - break; - case GX_VA_TEX6: - cpType = GET_REG_FIELD(__gx->vcdHi, 2, 12); - break; - case GX_VA_TEX7: - cpType = GET_REG_FIELD(__gx->vcdHi, 2, 14); - break; - default: - break; - } - - *type = static_cast(cpType); -} - -void GXGetVtxDescv(GXVtxDescList* vcd) { - CHECK(vcd != nullptr, "null vtx desc list"); - - GXVtxDescList* out = vcd; - for (GXAttr attr = GX_VA_PNMTXIDX; attr <= GX_VA_TEX7; attr = static_cast(attr + 1), ++out) { - out->attr = attr; - GXGetVtxDesc(attr, &out->type); - } - out->attr = GX_VA_NBT; - GXGetVtxDesc(GX_VA_NBT, &out->type); - ++out; - out->attr = GX_VA_NULL; -} - -void GXGetVtxAttrFmt(GXVtxFmt idx, GXAttr attr, GXCompCnt* compCnt, GXCompType* compType, u8* shift) { - CHECK(compCnt != nullptr && compType != nullptr && shift != nullptr, "null vtx attr fmt output"); - - const u32 va = __gx->vatA[idx]; - const u32 vb = __gx->vatB[idx]; - const u32 vc = __gx->vatC[idx]; - - switch (attr) { - case GX_VA_POS: - *compCnt = static_cast(GET_REG_FIELD(va, 1, 0)); - *compType = static_cast(GET_REG_FIELD(va, 3, 1)); - *shift = static_cast(GET_REG_FIELD(va, 5, 4)); - return; - case GX_VA_NRM: - case GX_VA_NBT: - *compCnt = static_cast(GET_REG_FIELD(va, 1, 9)); - if (*compCnt == GX_TEX_ST && GET_REG_FIELD(va, 1, 31) != 0) { - *compCnt = GX_NRM_NBT3; - } - *compType = static_cast(GET_REG_FIELD(va, 3, 10)); - *shift = GetFracForNrm(*compType); - return; - case GX_VA_CLR0: - *compCnt = static_cast(GET_REG_FIELD(va, 1, 13)); - *compType = static_cast(GET_REG_FIELD(va, 3, 14)); - *shift = 0; - return; - case GX_VA_CLR1: - *compCnt = static_cast(GET_REG_FIELD(va, 1, 17)); - *compType = static_cast(GET_REG_FIELD(va, 3, 18)); - *shift = 0; - return; - case GX_VA_TEX0: - *compCnt = static_cast(GET_REG_FIELD(va, 1, 21)); - *compType = static_cast(GET_REG_FIELD(va, 3, 22)); - *shift = static_cast(GET_REG_FIELD(va, 5, 25)); - return; - case GX_VA_TEX1: - *compCnt = static_cast(GET_REG_FIELD(vb, 1, 0)); - *compType = static_cast(GET_REG_FIELD(vb, 3, 1)); - *shift = static_cast(GET_REG_FIELD(vb, 5, 4)); - return; - case GX_VA_TEX2: - *compCnt = static_cast(GET_REG_FIELD(vb, 1, 9)); - *compType = static_cast(GET_REG_FIELD(vb, 3, 10)); - *shift = static_cast(GET_REG_FIELD(vb, 5, 13)); - return; - case GX_VA_TEX3: - *compCnt = static_cast(GET_REG_FIELD(vb, 1, 18)); - *compType = static_cast(GET_REG_FIELD(vb, 3, 19)); - *shift = static_cast(GET_REG_FIELD(vb, 5, 22)); - return; - case GX_VA_TEX4: - *compCnt = static_cast(GET_REG_FIELD(vb, 1, 27)); - *compType = static_cast(GET_REG_FIELD(vb, 3, 28)); - *shift = static_cast(GET_REG_FIELD(vc, 5, 0)); - return; - case GX_VA_TEX5: - *compCnt = static_cast(GET_REG_FIELD(vc, 1, 5)); - *compType = static_cast(GET_REG_FIELD(vc, 3, 6)); - *shift = static_cast(GET_REG_FIELD(vc, 5, 9)); - return; - case GX_VA_TEX6: - *compCnt = static_cast(GET_REG_FIELD(vc, 1, 14)); - *compType = static_cast(GET_REG_FIELD(vc, 3, 15)); - *shift = static_cast(GET_REG_FIELD(vc, 5, 18)); - return; - case GX_VA_TEX7: - *compCnt = static_cast(GET_REG_FIELD(vc, 1, 23)); - *compType = static_cast(GET_REG_FIELD(vc, 3, 24)); - *shift = static_cast(GET_REG_FIELD(vc, 5, 27)); - return; - default: - *compCnt = GX_TEX_ST; - *compType = GX_RGB565; - *shift = 0; - return; - } -} - -void GXGetVtxAttrFmtv(GXVtxFmt fmt, GXVtxAttrFmtList* vat) { - CHECK(vat != nullptr, "null vtx attr fmt list"); - - GXVtxAttrFmtList* out = vat; - for (GXAttr attr = GX_VA_POS; attr <= GX_VA_TEX7; attr = static_cast(attr + 1), ++out) { - out->attr = attr; - GXGetVtxAttrFmt(fmt, attr, &out->cnt, &out->type, &out->frac); - } - out->attr = GX_VA_NULL; -} - -void GXGetLineWidth(u8* width, GXTexOffset* texOffsets) { - CHECK(width != nullptr && texOffsets != nullptr, "null line width output"); - - *width = static_cast(GET_REG_FIELD(__gx->lpSize, 8, 0)); - *texOffsets = static_cast(GET_REG_FIELD(__gx->lpSize, 3, 16)); -} - -void GXGetPointSize(u8* pointSize, GXTexOffset* texOffsets) { - CHECK(pointSize != nullptr && texOffsets != nullptr, "null point size output"); - - *pointSize = static_cast(GET_REG_FIELD(__gx->lpSize, 8, 8)); - *texOffsets = static_cast(GET_REG_FIELD(__gx->lpSize, 3, 19)); -} - -void GXGetViewportv(f32 *vp) { - CHECK(vp != nullptr, "null viewport output"); - - vp[0] = __gx->vpLeft; - vp[1] = __gx->vpTop; - vp[2] = __gx->vpWd; - vp[3] = __gx->vpHt; - vp[4] = __gx->vpNearz; - vp[5] = __gx->vpFarz; -} - -void GXGetProjectionv(f32* p) { - p[0] = __gx->projType == GX_PERSPECTIVE ? 0.0f : 1.0f; - p[1] = __gx->projMtx[0]; - p[2] = __gx->projMtx[1]; - p[3] = __gx->projMtx[2]; - p[4] = __gx->projMtx[3]; - p[5] = __gx->projMtx[4]; - p[6] = __gx->projMtx[5]; -} - -void GXGetScissor(u32* left, u32* top, u32* wd, u32* ht) { - CHECK(left != nullptr && top != nullptr && wd != nullptr && ht != nullptr, "null scissor output"); - - const u32 tp = GET_REG_FIELD(__gx->suScis0, 11, 0); - const u32 lf = GET_REG_FIELD(__gx->suScis0, 11, 12); - const u32 bm = GET_REG_FIELD(__gx->suScis1, 11, 0); - const u32 rt = GET_REG_FIELD(__gx->suScis1, 11, 12); - - *left = lf - 342; - *top = tp - 342; - *wd = rt - lf + 1; - *ht = bm - tp + 1; -} - -void GXGetCullMode(GXCullMode* mode) { - CHECK(mode != nullptr, "null cull mode output"); - - const auto hwMode = static_cast(GET_REG_FIELD(__gx->genMode, 2, 14)); - switch (hwMode) { - case GX_CULL_FRONT: - *mode = GX_CULL_BACK; - break; - case GX_CULL_BACK: - *mode = GX_CULL_FRONT; - break; - default: - *mode = hwMode; - break; - } -} - -void GXGetLightAttnA(GXLightObj* light_, float* a0, float* a1, float* a2) { - auto* light = reinterpret_cast(light_); - *a0 = light->a0; - *a1 = light->a1; - *a2 = light->a2; -} - -void GXGetLightAttnK(GXLightObj* light_, float* k0, float* k1, float* k2) { - auto* light = reinterpret_cast(light_); - *k0 = light->k0; - *k1 = light->k1; - *k2 = light->k2; -} - -void GXGetLightPos(GXLightObj* light_, float* x, float* y, float* z) { - auto* light = reinterpret_cast(light_); - *x = light->px; - *y = light->py; - *z = light->pz; -} - -void GXGetLightDir(GXLightObj* light_, float* nx, float* ny, float* nz) { - auto* light = reinterpret_cast(light_); - *nx = -light->nx; - *ny = -light->ny; - *nz = -light->nz; -} - -void GXGetLightColor(GXLightObj* light_, GXColor* col) { - auto* light = reinterpret_cast(light_); - *col = light->color; -} - -void* GXGetTexObjData(GXTexObj* tex_obj) { - return const_cast(reinterpret_cast(tex_obj)->data); -} - -u16 GXGetTexObjWidth(GXTexObj* tex_obj) { return static_cast(reinterpret_cast(tex_obj)->width()); } - -u16 GXGetTexObjHeight(GXTexObj* tex_obj) { return static_cast(reinterpret_cast(tex_obj)->height()); } - -GXTexFmt GXGetTexObjFmt(GXTexObj* tex_obj) { - return static_cast(reinterpret_cast(tex_obj)->format()); -} - -GXTexWrapMode GXGetTexObjWrapS(GXTexObj* tex_obj) { return reinterpret_cast(tex_obj)->wrap_s(); } - -GXTexWrapMode GXGetTexObjWrapT(GXTexObj* tex_obj) { return reinterpret_cast(tex_obj)->wrap_t(); } - -GXBool GXGetTexObjMipMap(GXTexObj* tex_obj) { return reinterpret_cast(tex_obj)->has_mips(); } - -// TODO GXGetTexObjAll -// TODO GXGetTexObjMinFilt -// TODO GXGetTexObjMagFilt -// TODO GXGetTexObjMinLOD -// TODO GXGetTexObjMaxLOD -// TODO GXGetTexObjLODBias -// TODO GXGetTexObjBiasClamp -// TODO GXGetTexObjEdgeLOD -// TODO GXGetTexObjMaxAniso -// TODO GXGetTexObjLODAll -u32 GXGetTexObjTlut(const GXTexObj* tex_obj) { return reinterpret_cast(tex_obj)->tlut; } -// TODO GXGetTlutObjData -// TODO GXGetTlutObjFmt -// TODO GXGetTlutObjNumEntries -// TODO GXGetTlutObjAll -// TODO GXGetTexRegionAll -// TODO GXGetTlutRegionAll -} diff --git a/aurora-main/lib/dolphin/gx/GXLighting.cpp b/aurora-main/lib/dolphin/gx/GXLighting.cpp deleted file mode 100644 index f7331c6..0000000 --- a/aurora-main/lib/dolphin/gx/GXLighting.cpp +++ /dev/null @@ -1,291 +0,0 @@ -#include "gx.hpp" -#include "__gx.h" - -extern "C" { -void GXInitLightAttn(GXLightObj* light_, float a0, float a1, float a2, float k0, float k1, float k2) { - auto* light = reinterpret_cast(light_); - light->a0 = a0; - light->a1 = a1; - light->a2 = a2; - light->k0 = k0; - light->k1 = k1; - light->k2 = k2; -} - -void GXInitLightAttnA(GXLightObj* light_, float a0, float a1, float a2) { - auto* light = reinterpret_cast(light_); - light->a0 = a0; - light->a1 = a1; - light->a2 = a2; -} - -void GXInitLightAttnK(GXLightObj* light_, float k0, float k1, float k2) { - auto* light = reinterpret_cast(light_); - light->k0 = k0; - light->k1 = k1; - light->k2 = k2; -} - -void GXInitLightSpot(GXLightObj* light_, float cutoff, GXSpotFn spotFn) { - if (cutoff <= 0.f || cutoff > 90.f) { - spotFn = GX_SP_OFF; - } - - float cr = std::cos((cutoff * M_PIF) / 180.f); - float a0 = 1.f; - float a1 = 0.f; - float a2 = 0.f; - switch (spotFn) { - default: - break; - case GX_SP_FLAT: - a0 = -1000.f * cr; - a1 = 1000.f; - a2 = 0.f; - break; - case GX_SP_COS: - a0 = -cr / (1.f - cr); - a1 = 1.f / (1.f - cr); - a2 = 0.f; - break; - case GX_SP_COS2: - a0 = 0.f; - a1 = -cr / (1.f - cr); - a2 = 1.f / (1.f - cr); - break; - case GX_SP_SHARP: { - const float d = (1.f - cr) * (1.f - cr); - a0 = cr * (cr - 2.f) / d; - a1 = 2.f / d; - a2 = -1.f / d; - break; - } - case GX_SP_RING1: { - const float d = (1.f - cr) * (1.f - cr); - a0 = -4.f * cr / d; - a1 = 4.f * (1.f + cr) / d; - a2 = -4.f / d; - break; - } - case GX_SP_RING2: { - const float d = (1.f - cr) * (1.f - cr); - a0 = 1.f - 2.f * cr * cr / d; - a1 = 4.f * cr / d; - a2 = -2.f / d; - break; - } - } - - auto* light = reinterpret_cast(light_); - light->a0 = a0; - light->a1 = a1; - light->a2 = a2; -} - -void GXInitLightDistAttn(GXLightObj* light_, float refDistance, float refBrightness, GXDistAttnFn distFunc) { - if (refDistance < 0.f || refBrightness < 0.f || refBrightness >= 1.f) { - distFunc = GX_DA_OFF; - } - float k0 = 1.f; - float k1 = 0.f; - float k2 = 0.f; - switch (distFunc) { - case GX_DA_GENTLE: - k0 = 1.0f; - k1 = (1.0f - refBrightness) / (refBrightness * refDistance); - k2 = 0.0f; - break; - case GX_DA_MEDIUM: - k0 = 1.0f; - k1 = 0.5f * (1.0f - refBrightness) / (refBrightness * refDistance); - k2 = 0.5f * (1.0f - refBrightness) / (refBrightness * refDistance * refDistance); - break; - case GX_DA_STEEP: - k0 = 1.0f; - k1 = 0.0f; - k2 = (1.0f - refBrightness) / (refBrightness * refDistance * refDistance); - break; - case GX_DA_OFF: - k0 = 1.0f; - k1 = 0.0f; - k2 = 0.0f; - break; - } - - auto* light = reinterpret_cast(light_); - light->k0 = k0; - light->k1 = k1; - light->k2 = k2; -} - -void GXInitLightPos(GXLightObj* light_, float x, float y, float z) { - auto* light = reinterpret_cast(light_); - light->px = x; - light->py = y; - light->pz = z; -} - -void GXInitLightColor(GXLightObj* light_, GXColor col) { - auto* light = reinterpret_cast(light_); - light->color = col; -} - -void GXLoadLightObjImm(GXLightObj* light_, GXLightID id) { - u32 idx = std::log2(id); - auto* light = reinterpret_cast(light_); - - // XF bulk write: 16 values at light base address - // Light addresses: 0x600 + idx * 0x10 - u32 addr = 0x600 + idx * 0x10; - u32 reg = addr | (0xF << 16); // 16-1=15 values - - // Convert color to packed u32 for XF - u32 colorPacked = (static_cast(light->color.r) << 24) | (static_cast(light->color.g) << 16) | - (static_cast(light->color.b) << 8) | static_cast(light->color.a); - - GX_WRITE_U8(0x10); - GX_WRITE_U32(reg); - // Padding (3 u32s) - GX_WRITE_U32(0); - GX_WRITE_U32(0); - GX_WRITE_U32(0); - // Color - GX_WRITE_U32(colorPacked); - // Cosine attenuation (a0, a1, a2) - GX_WRITE_F32(light->a0); - GX_WRITE_F32(light->a1); - GX_WRITE_F32(light->a2); - // Distance attenuation (k0, k1, k2) - GX_WRITE_F32(light->k0); - GX_WRITE_F32(light->k1); - GX_WRITE_F32(light->k2); - // Position (px, py, pz) - GX_WRITE_F32(light->px); - GX_WRITE_F32(light->py); - GX_WRITE_F32(light->pz); - // Direction (nx, ny, nz) - GX_WRITE_F32(light->nx); - GX_WRITE_F32(light->ny); - GX_WRITE_F32(light->nz); -} - -void GXSetChanAmbColor(GXChannelID id, GXColor color) { - if (id == GX_COLOR0A0) { - GXSetChanAmbColor(GX_COLOR0, color); - GXSetChanAmbColor(GX_ALPHA0, color); - return; - } else if (id == GX_COLOR1A1) { - GXSetChanAmbColor(GX_COLOR1, color); - GXSetChanAmbColor(GX_ALPHA1, color); - return; - } - CHECK(id >= GX_COLOR0 && id <= GX_ALPHA1, "bad channel {}", static_cast(id)); - - // XF ambient color registers: 0x100A (chan 0), 0x100B (chan 1) - u32 packed = (static_cast(color.r) << 24) | (static_cast(color.g) << 16) | - (static_cast(color.b) << 8) | static_cast(color.a); - if (id == GX_COLOR0 || id == GX_ALPHA0) { - __gx->ambColor[0] = packed; - GX_WRITE_XF_REG(0xA, packed); - } else { - __gx->ambColor[1] = packed; - GX_WRITE_XF_REG(0xB, packed); - } - __gx->bpSent = 0; -} - -void GXSetChanMatColor(GXChannelID id, GXColor color) { - if (id == GX_COLOR0A0) { - GXSetChanMatColor(GX_COLOR0, color); - GXSetChanMatColor(GX_ALPHA0, color); - return; - } else if (id == GX_COLOR1A1) { - GXSetChanMatColor(GX_COLOR1, color); - GXSetChanMatColor(GX_ALPHA1, color); - return; - } - CHECK(id >= GX_COLOR0 && id <= GX_ALPHA1, "bad channel {}", static_cast(id)); - - // XF material color registers: 0x100C (chan 0), 0x100D (chan 1) - u32 packed = (static_cast(color.r) << 24) | (static_cast(color.g) << 16) | - (static_cast(color.b) << 8) | static_cast(color.a); - if (id == GX_COLOR0 || id == GX_ALPHA0) { - __gx->matColor[0] = packed; - GX_WRITE_XF_REG(0xC, packed); - } else { - __gx->matColor[1] = packed; - GX_WRITE_XF_REG(0xD, packed); - } - __gx->bpSent = 0; -} - -void GXSetNumChans(u8 num) { - SET_REG_FIELD(0, __gx->genMode, 3, 4, num); - GX_WRITE_XF_REG(9, num); - __gx->dirtyState |= 4; -} - -void GXInitLightDir(GXLightObj* light_, float nx, float ny, float nz) { - auto* light = reinterpret_cast(light_); - light->nx = -nx; - light->ny = -ny; - light->nz = -nz; -} - -void GXInitSpecularDir(GXLightObj* light_, float nx, float ny, float nz) { - float hx = -nx; - float hy = -ny; - float hz = (-nz + 1.0f); - float mag = ((hx * hx) + (hy * hy) + (hz * hz)); - if (mag != 0.0f) { - mag = 1.0f / sqrtf(mag); - } - - auto* light = reinterpret_cast(light_); - light->px = (nx * GX_LARGE_NUMBER); - light->py = (ny * GX_LARGE_NUMBER); - light->pz = (nz * GX_LARGE_NUMBER); - light->nx = hx * mag; - light->ny = hy * mag; - light->nz = hz * mag; -} - -void GXInitSpecularDirHA(GXLightObj* light_, float nx, float ny, float nz, float hx, float hy, float hz) { - auto* light = reinterpret_cast(light_); - light->px = (nx * GX_LARGE_NUMBER); - light->py = (ny * GX_LARGE_NUMBER); - light->pz = (nz * GX_LARGE_NUMBER); - light->nx = hx; - light->ny = hy; - light->nz = hz; -} - -void GXSetChanCtrl(GXChannelID id, bool lightingEnabled, GXColorSrc ambSrc, GXColorSrc matSrc, u32 lightState, - GXDiffuseFn diffFn, GXAttnFn attnFn) { - if (id == GX_COLOR0A0) { - GXSetChanCtrl(GX_COLOR0, lightingEnabled, ambSrc, matSrc, lightState, diffFn, attnFn); - GXSetChanCtrl(GX_ALPHA0, lightingEnabled, ambSrc, matSrc, lightState, diffFn, attnFn); - return; - } else if (id == GX_COLOR1A1) { - GXSetChanCtrl(GX_COLOR1, lightingEnabled, ambSrc, matSrc, lightState, diffFn, attnFn); - GXSetChanCtrl(GX_ALPHA1, lightingEnabled, ambSrc, matSrc, lightState, diffFn, attnFn); - return; - } - CHECK(id >= GX_COLOR0 && id <= GX_ALPHA1, "bad channel {}", static_cast(id)); - - // Build XF channel control register - u32 reg = 0; - SET_REG_FIELD(0, reg, 1, 0, matSrc); - SET_REG_FIELD(0, reg, 1, 1, lightingEnabled); - SET_REG_FIELD(0, reg, 4, 2, lightState & 0xF); // lights 0-3 - SET_REG_FIELD(0, reg, 1, 6, ambSrc); - SET_REG_FIELD(0, reg, 2, 7, (attnFn == GX_AF_SPEC) ? GX_DF_NONE : diffFn); - SET_REG_FIELD(0, reg, 1, 9, (attnFn != GX_AF_NONE)); // raw XF attn bit 0 - SET_REG_FIELD(0, reg, 1, 10, (attnFn != GX_AF_SPEC)); // raw XF attn bit 1 - SET_REG_FIELD(0, reg, 4, 11, (lightState >> 4) & 0xF); // lights 4-7 - - // XF channel control registers: 0x100E-0x1011 - GX_WRITE_XF_REG(0xE + id, reg); - __gx->bpSent = 0; -} -} diff --git a/aurora-main/lib/dolphin/gx/GXManage.cpp b/aurora-main/lib/dolphin/gx/GXManage.cpp deleted file mode 100644 index 80b3b92..0000000 --- a/aurora-main/lib/dolphin/gx/GXManage.cpp +++ /dev/null @@ -1,502 +0,0 @@ -#include "gx.hpp" -#include "__gx.h" - -#include "../../gx/fifo.hpp" - -#include - -// Global shadow register instance -static __GXData_struct sGXData; -__GXData_struct* __gx = &sGXData; -static GXFifoObj sFifoObj; - -extern "C" { -static GXDrawDoneCallback DrawDoneCB = nullptr; - -GXFifoObj* GXInit(void* base, u32 size) { - GXRenderModeObj* rmode; - f32 identity_mtx[3][4]; - GXColor clear = {64, 64, 64, 255}; - GXColor black = {0, 0, 0, 0}; - GXColor white = {255, 255, 255, 255}; - u32 i; - - std::memset(&sGXData, 0, sizeof(sGXData)); - __gx = &sGXData; - __gx->inDispList = 0; - __gx->dlSaveContext = 1; - __gx->tcsManEnab = 0; - __gx->vNum = 0; - - // Initialize FIFO subsystem - aurora::gx::fifo::init(); - GXInitFifoBase(&sFifoObj, base, size); - GXSetCPUFifo(&sFifoObj); - GXSetGPFifo(&sFifoObj); - - // Initialize shadow registers: genMode, bpMask, lpSize - __gx->genMode = 0; - SET_REG_FIELD(0, __gx->genMode, 8, 24, 0x00); - __gx->bpMask = 0xFF; - SET_REG_FIELD(0, __gx->bpMask, 8, 24, 0x0F); - __gx->lpSize = 0; - SET_REG_FIELD(0, __gx->lpSize, 8, 24, 0x22); - - // TEV / tref / ksel shadow registers - for (i = 0; i < 16; i++) { - __gx->tevc[i] = 0; - __gx->teva[i] = 0; - __gx->tref[i / 2] = 0; - __gx->texmapId[i] = GX_TEXMAP_NULL; - SET_REG_FIELD(0, __gx->tevc[i], 8, 24, 0xC0 + i * 2); - SET_REG_FIELD(0, __gx->teva[i], 8, 24, 0xC1 + i * 2); - SET_REG_FIELD(0, __gx->tevKsel[i / 2], 8, 24, 0xF6 + i / 2); - SET_REG_FIELD(0, __gx->tref[i / 2], 8, 24, 0x28 + i / 2); - } - - // iref and SU texture scale registers - __gx->iref = 0; - SET_REG_FIELD(0, __gx->iref, 8, 24, 0x27); - for (i = 0; i < 8; i++) { - __gx->suTs0[i] = 0; - __gx->suTs1[i] = 0; - SET_REG_FIELD(0, __gx->suTs0[i], 8, 24, 0x30 + i * 2); - SET_REG_FIELD(0, __gx->suTs1[i], 8, 24, 0x31 + i * 2); - } - - // Other BP command byte init - SET_REG_FIELD(0, __gx->suScis0, 8, 24, 0x20); - SET_REG_FIELD(0, __gx->suScis1, 8, 24, 0x21); - SET_REG_FIELD(0, __gx->cmode0, 8, 24, 0x41); - SET_REG_FIELD(0, __gx->cmode1, 8, 24, 0x42); - SET_REG_FIELD(0, __gx->zmode, 8, 24, 0x40); - SET_REG_FIELD(0, __gx->peCtrl, 8, 24, 0x43); - SET_REG_FIELD(0, __gx->IndTexScale0, 8, 24, 0x25); - SET_REG_FIELD(0, __gx->IndTexScale1, 8, 24, 0x26); - - __gx->dirtyState = 0; - __gx->dirtyVAT = 0; - - // VAT initialization: set default bits and write vatB to CP - for (i = 0; i < GX_MAX_VTXFMT; i++) { - SET_REG_FIELD(0, __gx->vatA[i], 1, 30, 1); - SET_REG_FIELD(0, __gx->vatB[i], 1, 31, 1); - GX_WRITE_U8(8); - GX_WRITE_U8(i | 0x80); - GX_WRITE_U32(__gx->vatB[i]); - } - - // XF register init: error/mode control + dual-tex transform - { - u32 reg1 = 0; - u32 reg2 = 0; - SET_REG_FIELD(0, reg1, 1, 0, 1); - SET_REG_FIELD(0, reg1, 1, 1, 1); - SET_REG_FIELD(0, reg1, 1, 2, 1); - SET_REG_FIELD(0, reg1, 1, 3, 1); - SET_REG_FIELD(0, reg1, 1, 4, 1); - SET_REG_FIELD(0, reg1, 1, 5, 1); - GX_WRITE_XF_REG(0, reg1); - SET_REG_FIELD(0, reg2, 1, 0, 1); - GX_WRITE_XF_REG(0x12, reg2); - } - - // BP 0x58 register init - { - u32 reg = 0; - SET_REG_FIELD(0, reg, 1, 0, 1); - SET_REG_FIELD(0, reg, 1, 1, 1); - SET_REG_FIELD(0, reg, 1, 2, 1); - SET_REG_FIELD(0, reg, 1, 3, 1); - SET_REG_FIELD(0, reg, 8, 24, 0x58); - GX_WRITE_RAS_REG(reg); - } - - // Default render mode (NTSC) - rmode = &GXNtsc480IntDf; - - // Default state initialization via API calls - GXSetCopyClear(clear, 0xFFFFFF); - GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 0x3C); - GXSetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX1, 0x3C); - GXSetTexCoordGen(GX_TEXCOORD2, GX_TG_MTX2x4, GX_TG_TEX2, 0x3C); - GXSetTexCoordGen(GX_TEXCOORD3, GX_TG_MTX2x4, GX_TG_TEX3, 0x3C); - GXSetTexCoordGen(GX_TEXCOORD4, GX_TG_MTX2x4, GX_TG_TEX4, 0x3C); - GXSetTexCoordGen(GX_TEXCOORD5, GX_TG_MTX2x4, GX_TG_TEX5, 0x3C); - GXSetTexCoordGen(GX_TEXCOORD6, GX_TG_MTX2x4, GX_TG_TEX6, 0x3C); - GXSetTexCoordGen(GX_TEXCOORD7, GX_TG_MTX2x4, GX_TG_TEX7, 0x3C); - GXSetNumTexGens(1); - GXClearVtxDesc(); - GXInvalidateVtxCache(); - GXSetLineWidth(6, GX_TO_ZERO); - GXSetPointSize(6, GX_TO_ZERO); - GXEnableTexOffsets(GX_TEXCOORD0, GX_DISABLE, GX_DISABLE); - GXEnableTexOffsets(GX_TEXCOORD1, GX_DISABLE, GX_DISABLE); - GXEnableTexOffsets(GX_TEXCOORD2, GX_DISABLE, GX_DISABLE); - GXEnableTexOffsets(GX_TEXCOORD3, GX_DISABLE, GX_DISABLE); - GXEnableTexOffsets(GX_TEXCOORD4, GX_DISABLE, GX_DISABLE); - GXEnableTexOffsets(GX_TEXCOORD5, GX_DISABLE, GX_DISABLE); - GXEnableTexOffsets(GX_TEXCOORD6, GX_DISABLE, GX_DISABLE); - GXEnableTexOffsets(GX_TEXCOORD7, GX_DISABLE, GX_DISABLE); - - // Identity matrix - identity_mtx[0][0] = 1.0f; - identity_mtx[0][1] = 0.0f; - identity_mtx[0][2] = 0.0f; - identity_mtx[0][3] = 0.0f; - identity_mtx[1][0] = 0.0f; - identity_mtx[1][1] = 1.0f; - identity_mtx[1][2] = 0.0f; - identity_mtx[1][3] = 0.0f; - identity_mtx[2][0] = 0.0f; - identity_mtx[2][1] = 0.0f; - identity_mtx[2][2] = 1.0f; - identity_mtx[2][3] = 0.0f; - GXLoadPosMtxImm(identity_mtx, GX_PNMTX0); - GXLoadNrmMtxImm(identity_mtx, GX_PNMTX0); - GXSetCurrentMtx(GX_PNMTX0); - GXLoadTexMtxImm(identity_mtx, GX_IDENTITY, GX_MTX3x4); - GXLoadTexMtxImm(identity_mtx, GX_PTIDENTITY, GX_MTX3x4); - - GXSetViewport(0.0f, 0.0f, rmode->fbWidth, rmode->xfbHeight, 0.0f, 1.0f); - GXSetCoPlanar(GX_DISABLE); - GXSetCullMode(GX_CULL_BACK); - GXSetClipMode(GX_CLIP_ENABLE); - GXSetScissor(0, 0, rmode->fbWidth, rmode->efbHeight); - // GXSetScissorBoxOffset(0, 0); - - GXSetNumChans(0); - GXSetChanCtrl(GX_COLOR0A0, GX_DISABLE, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE); - GXSetChanAmbColor(GX_COLOR0A0, black); - GXSetChanMatColor(GX_COLOR0A0, white); - GXSetChanCtrl(GX_COLOR1A1, GX_DISABLE, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE); - GXSetChanAmbColor(GX_COLOR1A1, black); - GXSetChanMatColor(GX_COLOR1A1, white); - - GXInvalidateTexAll(); - // __gx->nextTexRgn = 0; - // for (i = 0; i < 8; i++) - // GXInitTexCacheRegion(&__gx->TexRegions[i], 0, i * 0x8000, 0, 0x80000 + i * 0x8000, 0); - // __gx->nextTexRgnCI = 0; - // for (i = 0; i < 4; i++) - // GXInitTexCacheRegion(&__gx->TexRegionsCI[i], 0, (i * 2 + 8) * 0x8000, 0, (i * 2 + 9) * 0x8000, 0); - // for (i = 0; i < 16; i++) - // GXInitTlutRegion(&__gx->TlutRegions[i], 0xC0000 + i * 0x2000, 16); - // for (i = 0; i < 4; i++) - // GXInitTlutRegion(&__gx->TlutRegions[i + 16], 0xE0000 + i * 0x8000, 64); - // GXSetTexRegionCallback(__GXDefaultTexRegionCallback); - // GXSetTlutRegionCallback(__GXDefaultTlutRegionCallback); - - GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); - GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD1, GX_TEXMAP1, GX_COLOR0A0); - GXSetTevOrder(GX_TEVSTAGE2, GX_TEXCOORD2, GX_TEXMAP2, GX_COLOR0A0); - GXSetTevOrder(GX_TEVSTAGE3, GX_TEXCOORD3, GX_TEXMAP3, GX_COLOR0A0); - GXSetTevOrder(GX_TEVSTAGE4, GX_TEXCOORD4, GX_TEXMAP4, GX_COLOR0A0); - GXSetTevOrder(GX_TEVSTAGE5, GX_TEXCOORD5, GX_TEXMAP5, GX_COLOR0A0); - GXSetTevOrder(GX_TEVSTAGE6, GX_TEXCOORD6, GX_TEXMAP6, GX_COLOR0A0); - GXSetTevOrder(GX_TEVSTAGE7, GX_TEXCOORD7, GX_TEXMAP7, GX_COLOR0A0); - GXSetTevOrder(GX_TEVSTAGE8, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL); - GXSetTevOrder(GX_TEVSTAGE9, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL); - GXSetTevOrder(GX_TEVSTAGE10, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL); - GXSetTevOrder(GX_TEVSTAGE11, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL); - GXSetTevOrder(GX_TEVSTAGE12, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL); - GXSetTevOrder(GX_TEVSTAGE13, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL); - GXSetTevOrder(GX_TEVSTAGE14, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL); - GXSetTevOrder(GX_TEVSTAGE15, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL); - - GXSetNumTevStages(1); - GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE); - GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); - GXSetZTexture(GX_ZT_DISABLE, GX_TF_Z8, 0); - - for (i = GX_TEVSTAGE0; i < GX_MAX_TEVSTAGE; i++) { - GXSetTevKColorSel(static_cast(i), GX_TEV_KCSEL_1_4); - GXSetTevKAlphaSel(static_cast(i), GX_TEV_KASEL_1); - GXSetTevSwapMode(static_cast(i), GX_TEV_SWAP0, GX_TEV_SWAP0); - } - GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); - GXSetTevSwapModeTable(GX_TEV_SWAP1, GX_CH_RED, GX_CH_RED, GX_CH_RED, GX_CH_ALPHA); - GXSetTevSwapModeTable(GX_TEV_SWAP2, GX_CH_GREEN, GX_CH_GREEN, GX_CH_GREEN, GX_CH_ALPHA); - GXSetTevSwapModeTable(GX_TEV_SWAP3, GX_CH_BLUE, GX_CH_BLUE, GX_CH_BLUE, GX_CH_ALPHA); - - for (i = GX_TEVSTAGE0; i < GX_MAX_TEVSTAGE; i++) - GXSetTevDirect(static_cast(i)); - GXSetNumIndStages(0); - GXSetIndTexCoordScale(GX_INDTEXSTAGE0, GX_ITS_1, GX_ITS_1); - GXSetIndTexCoordScale(GX_INDTEXSTAGE1, GX_ITS_1, GX_ITS_1); - GXSetIndTexCoordScale(GX_INDTEXSTAGE2, GX_ITS_1, GX_ITS_1); - GXSetIndTexCoordScale(GX_INDTEXSTAGE3, GX_ITS_1, GX_ITS_1); - - GXSetFog(GX_FOG_NONE, 0.0f, 1.0f, 0.1f, 1.0f, black); - GXSetFogRangeAdj(GX_DISABLE, 0, nullptr); - GXSetBlendMode(GX_BM_NONE, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR); - GXSetColorUpdate(GX_ENABLE); - GXSetAlphaUpdate(GX_ENABLE); - GXSetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE); - GXSetZCompLoc(GX_TRUE); - GXSetDither(GX_ENABLE); - GXSetDstAlpha(GX_DISABLE, 0); - GXSetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR); - GXSetFieldMask(GX_ENABLE, GX_ENABLE); - GXSetFieldMode(rmode->field_rendering, ((rmode->viHeight == 2 * rmode->xfbHeight) ? GX_ENABLE : GX_DISABLE)); - - GXSetDispCopySrc(0, 0, rmode->fbWidth, rmode->efbHeight); - GXSetDispCopyDst(rmode->fbWidth, rmode->efbHeight); - GXSetDispCopyYScale(static_cast(rmode->xfbHeight) / static_cast(rmode->efbHeight)); - // GXSetCopyClamp(static_cast(GX_CLAMP_TOP | GX_CLAMP_BOTTOM)); - GXSetCopyFilter(rmode->aa, rmode->sample_pattern, GX_TRUE, rmode->vfilter); - GXSetDispCopyGamma(GX_GM_1_0); - // GXSetDispCopyFrame2Field(GX_COPY_PROGRESSIVE); - // GXClearBoundingBox(); - - // GXPokeColorUpdate(GX_TRUE); - // GXPokeAlphaUpdate(GX_TRUE); - // GXPokeDither(GX_FALSE); - // GXPokeBlendMode(GX_BM_NONE, GX_BL_ZERO, GX_BL_ONE, GX_LO_SET); - // GXPokeAlphaMode(GX_ALWAYS, 0); - // GXPokeAlphaRead(GX_READ_FF); - // GXPokeDstAlpha(GX_DISABLE, 0); - // GXPokeZMode(GX_TRUE, GX_ALWAYS, GX_TRUE); - - return &sFifoObj; -} - -void GXDrawDone() { - aurora::gx::fifo::drain(); - if (DrawDoneCB != nullptr) - DrawDoneCB(); -} - -void GXSetDrawDone() { - aurora::gx::fifo::drain(); - if (DrawDoneCB != nullptr) - DrawDoneCB(); -} - -GXDrawDoneCallback GXSetDrawDoneCallback(GXDrawDoneCallback cb) { - GXDrawDoneCallback old = DrawDoneCB; - DrawDoneCB = cb; - return old; -} - -void GXFlush() { - if (__gx->dirtyState) { - __GXSetDirtyState(); - } -} - -void GXPixModeSync() { - GX_WRITE_RAS_REG(__gx->peCtrl); - __gx->bpSent = 1; -} - -void GXTexModeSync() { - GX_WRITE_RAS_REG(0x63000000); - __gx->bpSent = 1; -} - -// Dirty state flush functions - -void __GXSetDirtyState() { - if (__gx->dirtyState & 1) { - __GXSetSUTexRegs(); - } - if (__gx->dirtyState & 2) { - __GXUpdateBPMask(); - } - if (__gx->dirtyState & 4) { - __GXSetGenMode(); - } - if (__gx->dirtyState & 8) { - __GXSetVCD(); - } - if (__gx->dirtyState & 0x10) { - __GXSetVAT(); - } - __gx->dirtyState = 0; -} - -void __GXSetGenMode() { - GX_WRITE_RAS_REG(__gx->genMode); - __gx->bpSent = 1; -} - -void __GXSendFlushPrim() { - // Originally a dummy triangle strip to push the GP through the FIFO and flush pending BP - // register changes. We can skip the FIFO writes and just clear the bpSent flag. - - // GX_WRITE_U8(0x98); - // GX_WRITE_U16(__gx->vNum); - // for (u32 i = 0; i < __gx->vNum * __gx->vLim; i += 4) { - // GX_WRITE_U32(0); - // } - - __gx->bpSent = 0; -} - -void __GXSetVCD() { - // Write VCD lo and hi to CP registers - GX_WRITE_SOME_REG4(8, 0x50, __gx->vcdLo, -12); - GX_WRITE_SOME_REG4(8, 0x60, __gx->vcdHi, -12); - - // Write XF vertex specs - u32 nCols = 0; - nCols = GET_REG_FIELD(__gx->vcdLo, 2, 13) ? 1 : 0; - nCols += GET_REG_FIELD(__gx->vcdLo, 2, 15) ? 1 : 0; - u32 nNrm = __gx->hasBiNrms ? 2 : __gx->hasNrms ? 1 : 0; - u32 nTex = 0; - nTex += GET_REG_FIELD(__gx->vcdHi, 2, 0) ? 1 : 0; - nTex += GET_REG_FIELD(__gx->vcdHi, 2, 2) ? 1 : 0; - nTex += GET_REG_FIELD(__gx->vcdHi, 2, 4) ? 1 : 0; - nTex += GET_REG_FIELD(__gx->vcdHi, 2, 6) ? 1 : 0; - nTex += GET_REG_FIELD(__gx->vcdHi, 2, 8) ? 1 : 0; - nTex += GET_REG_FIELD(__gx->vcdHi, 2, 10) ? 1 : 0; - nTex += GET_REG_FIELD(__gx->vcdHi, 2, 12) ? 1 : 0; - nTex += GET_REG_FIELD(__gx->vcdHi, 2, 14) ? 1 : 0; - u32 reg = (nCols) | (nNrm << 2) | (nTex << 4); - GX_WRITE_XF_REG(8, reg); - __gx->bpSent = 0; - - // Calculate vertex data limit for flush prim - if (__gx->vNum != 0) { - static u8 tbl1[] = {0, 4, 1, 2}; - static u8 tbl2[] = {0, 8, 1, 2}; - static u8 tbl3[] = {0, 12, 1, 2}; - - u32 vl = __gx->vcdLo; - u32 vh = __gx->vcdHi; - u32 vlm = 0; - vlm = GET_REG_FIELD(vl, 1, 0); - vlm += static_cast(GET_REG_FIELD(vl, 1, 1)); - vlm += static_cast(GET_REG_FIELD(vl, 1, 2)); - vlm += static_cast(GET_REG_FIELD(vl, 1, 3)); - vlm += static_cast(GET_REG_FIELD(vl, 1, 4)); - vlm += static_cast(GET_REG_FIELD(vl, 1, 5)); - vlm += static_cast(GET_REG_FIELD(vl, 1, 6)); - vlm += static_cast(GET_REG_FIELD(vl, 1, 7)); - vlm += static_cast(GET_REG_FIELD(vl, 1, 8)); - vlm += tbl3[static_cast(GET_REG_FIELD(vl, 2, 9))]; - u32 b = (__gx->hasBiNrms << 1) + 1; - vlm += tbl3[static_cast(GET_REG_FIELD(vl, 2, 11))] * b; - vlm += tbl1[static_cast(GET_REG_FIELD(vl, 2, 13))]; - vlm += tbl1[static_cast(GET_REG_FIELD(vl, 2, 15))]; - vlm += tbl2[static_cast(GET_REG_FIELD(vh, 2, 0))]; - vlm += tbl2[static_cast(GET_REG_FIELD(vh, 2, 2))]; - vlm += tbl2[static_cast(GET_REG_FIELD(vh, 2, 4))]; - vlm += tbl2[static_cast(GET_REG_FIELD(vh, 2, 6))]; - vlm += tbl2[static_cast(GET_REG_FIELD(vh, 2, 8))]; - vlm += tbl2[static_cast(GET_REG_FIELD(vh, 2, 10))]; - vlm += tbl2[static_cast(GET_REG_FIELD(vh, 2, 12))]; - vlm += tbl2[static_cast(GET_REG_FIELD(vh, 2, 14))]; - __gx->vLim = vlm; - } -} - -void __GXSetVAT() { - for (u8 i = 0; i < 8; i++) { - if (__gx->dirtyVAT & (1 << i)) { - GX_WRITE_SOME_REG4(8, i | 0x70, __gx->vatA[i], i - 12); - GX_WRITE_SOME_REG4(8, i | 0x80, __gx->vatB[i], i - 12); - GX_WRITE_SOME_REG4(8, i | 0x90, __gx->vatC[i], i - 12); - } - } - __gx->dirtyVAT = 0; -} - -static void __SetSURegs(u32 tmap, u32 tcoord) { - // Copy texture dimensions from tImage0 to SU registers - u32 w = GET_REG_FIELD(__gx->tImage0[tmap], 10, 0); - u32 h = GET_REG_FIELD(__gx->tImage0[tmap], 10, 10); - SET_REG_FIELD(0, __gx->suTs0[tcoord], 16, 0, w); - SET_REG_FIELD(0, __gx->suTs1[tcoord], 16, 0, h); - // Bias from wrap mode - u8 s_bias = GET_REG_FIELD(__gx->tMode0[tmap], 2, 0) == 1; - u8 t_bias = GET_REG_FIELD(__gx->tMode0[tmap], 2, 2) == 1; - SET_REG_FIELD(0, __gx->suTs0[tcoord], 1, 16, s_bias); - SET_REG_FIELD(0, __gx->suTs1[tcoord], 1, 16, t_bias); - GX_WRITE_RAS_REG(__gx->suTs0[tcoord]); - GX_WRITE_RAS_REG(__gx->suTs1[tcoord]); - __gx->bpSent = 1; -} - -void __GXSetSUTexRegs() { - // SU texture size/bias registers for each active TEV and indirect stage, skipping coords with - // manual scale (tcsManEnab). If all coords are manual (0xFF), skip entirely. - if (__gx->tcsManEnab == 0xFF) { - return; - } - - u32 nStages = GET_REG_FIELD(__gx->genMode, 4, 10) + 1; - u32 nIndStages = GET_REG_FIELD(__gx->genMode, 3, 16); - - // Indirect texture stages - for (u32 i = 0; i < nIndStages; i++) { - u32 tmap, coord; - switch (i) { - case 0: - tmap = GET_REG_FIELD(__gx->iref, 3, 0); - coord = GET_REG_FIELD(__gx->iref, 3, 3); - break; - case 1: - tmap = GET_REG_FIELD(__gx->iref, 3, 6); - coord = GET_REG_FIELD(__gx->iref, 3, 9); - break; - case 2: - tmap = GET_REG_FIELD(__gx->iref, 3, 12); - coord = GET_REG_FIELD(__gx->iref, 3, 15); - break; - default: - tmap = GET_REG_FIELD(__gx->iref, 3, 18); - coord = GET_REG_FIELD(__gx->iref, 3, 21); - break; - } - if (!(__gx->tcsManEnab & (1 << coord))) { - __SetSURegs(tmap, coord); - } - } - - // Direct TEV stages - for (u32 i = 0; i < nStages; i++) { - u32* ptref = &__gx->tref[i / 2]; - u32 map = __gx->texmapId[i]; - u32 tmap = map & ~0x100u; - u32 coord; - if (i & 1) { - coord = GET_REG_FIELD(*ptref, 3, 15); - } else { - coord = GET_REG_FIELD(*ptref, 3, 3); - } - if (tmap != 0xFF && !(__gx->tcsManEnab & (1 << coord)) && (__gx->texmapValid & (1u << i))) { - __SetSURegs(tmap, coord); - } - } -} - -void __GXUpdateBPMask() { - // Mark texture maps used by indirect texture stages in the BP mask - u32 nIndStages = GET_REG_FIELD(__gx->genMode, 3, 16); - u32 newImask = 0; - - for (u32 i = 0; i < nIndStages; i++) { - u32 tmap = GET_REG_FIELD(__gx->iref, 3, i * 6); - newImask |= 1u << tmap; - } - - if (static_cast(__gx->bpMask) != static_cast(newImask)) { - SET_REG_FIELD(0, __gx->bpMask, 8, 0, newImask); - GX_WRITE_RAS_REG(__gx->bpMask); - __gx->bpSent = 1; - } -} - -void __GXSetMatrixIndex(GXAttr matIdxAttr) { - if (matIdxAttr < GX_VA_TEX4MTXIDX) { - GX_WRITE_SOME_REG4(8, 0x30, __gx->matIdxA, -12); - GX_WRITE_XF_REG(24, __gx->matIdxA); - } else { - GX_WRITE_SOME_REG4(8, 0x40, __gx->matIdxB, -12); - GX_WRITE_XF_REG(25, __gx->matIdxB); - } - __gx->bpSent = 0; -} -}; diff --git a/aurora-main/lib/dolphin/gx/GXPixel.cpp b/aurora-main/lib/dolphin/gx/GXPixel.cpp deleted file mode 100644 index d4f3fb5..0000000 --- a/aurora-main/lib/dolphin/gx/GXPixel.cpp +++ /dev/null @@ -1,247 +0,0 @@ -#include "gx.hpp" -#include "__gx.h" - -#include - -extern "C" { -void GXSetFog(GXFogType type, float startZ, float endZ, float nearZ, float farZ, GXColor color) { - // Compute fog coefficients matching SDK. - const bool orthographic = (static_cast(type) & 0x8u) != 0; - f32 a = 0.0f; - f32 c = 0.0f; - u32 b_m = 0; - u32 b_s = 0; - - if (!orthographic) { - f32 A; - f32 B; - f32 C; - if (farZ == nearZ || endZ == startZ) { - A = 0.0f; - B = 0.5f; - C = 0.0f; - } else { - A = (farZ * nearZ) / ((farZ - nearZ) * (endZ - startZ)); - B = farZ / (farZ - nearZ); - C = startZ / (endZ - startZ); - } - - // Normalize B mantissa. - f32 B_mant = B; - int B_expn = 0; - while (B_mant > 1.0f) { - B_mant *= 0.5f; - B_expn++; - } - while (B_mant > 0.0f && B_mant < 0.5f) { - B_mant *= 2.0f; - B_expn--; - } - - a = std::ldexp(A, -(B_expn + 1)); - b_m = static_cast(8.388638e6f * B_mant); - b_s = static_cast(B_expn + 1) & 0x1Fu; - c = C; - } else if (farZ != nearZ && endZ != startZ) { - const f32 invDepthRange = 1.0f / (endZ - startZ); - a = invDepthRange * (farZ - nearZ); - c = invDepthRange * (startZ - nearZ); - } - - u32 a_hex, c_hex; - std::memcpy(&a_hex, &a, sizeof(a_hex)); - std::memcpy(&c_hex, &c, sizeof(c_hex)); - - // BP FOG0 (0xEE) - A parameter - u32 fog0 = 0; - SET_REG_FIELD(0, fog0, 11, 0, (a_hex >> 12) & 0x7FF); - SET_REG_FIELD(0, fog0, 8, 11, (a_hex >> 23) & 0xFF); - SET_REG_FIELD(0, fog0, 1, 19, (a_hex >> 31)); - SET_REG_FIELD(0, fog0, 8, 24, 0xEE); - - // BP FOG1 (0xEF) - B mantissa - u32 fog1 = 0; - SET_REG_FIELD(0, fog1, 24, 0, b_m); - SET_REG_FIELD(0, fog1, 8, 24, 0xEF); - - // BP FOG2 (0xF0) - B scale - u32 fog2 = 0; - SET_REG_FIELD(0, fog2, 5, 0, b_s); - SET_REG_FIELD(0, fog2, 8, 24, 0xF0); - - // BP FOG3 (0xF1) - C parameter + type - u32 fog3 = 0; - SET_REG_FIELD(0, fog3, 11, 0, (c_hex >> 12) & 0x7FF); - SET_REG_FIELD(0, fog3, 8, 11, (c_hex >> 23) & 0xFF); - SET_REG_FIELD(0, fog3, 1, 19, (c_hex >> 31)); - SET_REG_FIELD(0, fog3, 1, 20, orthographic ? 1 : 0); - SET_REG_FIELD(0, fog3, 3, 21, static_cast(type) & 0x7u); - SET_REG_FIELD(0, fog3, 8, 24, 0xF1); - - // BP FOGCLR (0xF2) - color - u32 fogclr = 0; - SET_REG_FIELD(0, fogclr, 8, 0, color.b); - SET_REG_FIELD(0, fogclr, 8, 8, color.g); - SET_REG_FIELD(0, fogclr, 8, 16, color.r); - SET_REG_FIELD(0, fogclr, 8, 24, 0xF2); - - GX_WRITE_RAS_REG(fog0); - GX_WRITE_RAS_REG(fog1); - GX_WRITE_RAS_REG(fog2); - GX_WRITE_RAS_REG(fog3); - GX_WRITE_RAS_REG(fogclr); - __gx->bpSent = 1; -} - -void GXSetFogColor(GXColor color) { - // BP FOGCLR (0xF2) - u32 fogclr = 0; - SET_REG_FIELD(0, fogclr, 8, 0, color.b); - SET_REG_FIELD(0, fogclr, 8, 8, color.g); - SET_REG_FIELD(0, fogclr, 8, 16, color.r); - SET_REG_FIELD(0, fogclr, 8, 24, 0xF2); - GX_WRITE_RAS_REG(fogclr); - __gx->bpSent = 1; -} - -void GXSetFogRangeAdj(GXBool enable, u16 center, GXFogAdjTable* table) { - u32 i; - u32 range_adj; - u32 range_c; - - if (enable) { - for (i = 0; i < 10; i += 2) { - range_adj = 0; - SET_REG_FIELD(0x10D, range_adj, 12, 0, table->r[i]); - SET_REG_FIELD(0x10E, range_adj, 12, 12, table->r[i + 1]); - SET_REG_FIELD(0x10F, range_adj, 8, 24, (i >> 1) + 0xE9); - GX_WRITE_RAS_REG(range_adj); - } - } - range_c = 0; - SET_REG_FIELD(0x115, range_c, 10, 0, center + 342); - SET_REG_FIELD(0x116, range_c, 1, 10, enable); - SET_REG_FIELD(0x117, range_c, 8, 24, 0xE8); - GX_WRITE_RAS_REG(range_c); - __gx->bpSent = 1; -} - -void GXSetBlendMode(GXBlendMode mode, GXBlendFactor src, GXBlendFactor dst, GXLogicOp op) { - SET_REG_FIELD(0, __gx->cmode0, 1, 0, (mode == GX_BM_BLEND || mode == GX_BM_SUBTRACT)); - SET_REG_FIELD(0, __gx->cmode0, 1, 11, (mode == GX_BM_SUBTRACT)); - SET_REG_FIELD(0, __gx->cmode0, 1, 1, (mode == GX_BM_LOGIC)); - SET_REG_FIELD(0, __gx->cmode0, 4, 12, op); - SET_REG_FIELD(0, __gx->cmode0, 3, 8, src); - SET_REG_FIELD(0, __gx->cmode0, 3, 5, dst); - GX_WRITE_RAS_REG(__gx->cmode0); - __gx->bpSent = 1; -} - -void GXSetColorUpdate(GXBool enabled) { - SET_REG_FIELD(0, __gx->cmode0, 1, 3, enabled); - GX_WRITE_RAS_REG(__gx->cmode0); - __gx->bpSent = 1; -} - -void GXSetAlphaUpdate(bool enabled) { - SET_REG_FIELD(0, __gx->cmode0, 1, 4, enabled); - GX_WRITE_RAS_REG(__gx->cmode0); - __gx->bpSent = 1; -} - -void GXSetZMode(bool compare_enable, GXCompare func, bool update_enable) { - SET_REG_FIELD(0, __gx->zmode, 1, 0, compare_enable); - SET_REG_FIELD(0, __gx->zmode, 3, 1, func); - SET_REG_FIELD(0, __gx->zmode, 1, 4, update_enable); - GX_WRITE_RAS_REG(__gx->zmode); - __gx->bpSent = 1; -} - -void GXSetZCompLoc(GXBool before_tex) { - SET_REG_FIELD(0, __gx->peCtrl, 1, 6, before_tex); - GX_WRITE_RAS_REG(__gx->peCtrl); - __gx->bpSent = 1; -} - -void GXSetPixelFmt(GXPixelFmt pix_fmt, GXZFmt16 z_fmt) { - u32 oldPeCtrl = __gx->peCtrl; - u8 hwPixelFmt = 0; - - switch (pix_fmt) { - case GX_PF_RGB8_Z24: - hwPixelFmt = 0; - break; - case GX_PF_RGBA6_Z24: - hwPixelFmt = 1; - break; - case GX_PF_RGB565_Z16: - hwPixelFmt = 2; - break; - case GX_PF_Z24: - hwPixelFmt = 3; - break; - case GX_PF_Y8: - case GX_PF_U8: - case GX_PF_V8: - hwPixelFmt = 4; - break; - case GX_PF_YUV420: - hwPixelFmt = 5; - break; - default: - UNLIKELY FATAL("GXSetPixelFmt: unsupported pixel format {}", static_cast(pix_fmt)); - } - - SET_REG_FIELD(0, __gx->peCtrl, 3, 0, hwPixelFmt); - SET_REG_FIELD(0, __gx->peCtrl, 3, 3, z_fmt); - if (oldPeCtrl != __gx->peCtrl) { - GX_WRITE_RAS_REG(__gx->peCtrl); - SET_REG_FIELD(0, __gx->genMode, 1, 9, pix_fmt == GX_PF_RGB565_Z16); - __gx->dirtyState |= 4; - } - - if (hwPixelFmt == 4) { - SET_REG_FIELD(0, __gx->cmode1, 2, 9, (static_cast(pix_fmt) - GX_PF_Y8) & 0x3); - GX_WRITE_RAS_REG(__gx->cmode1); - } - - __gx->bpSent = 1; -} - -void GXSetDither(GXBool dither) { - SET_REG_FIELD(0, __gx->cmode0, 1, 2, dither); - GX_WRITE_RAS_REG(__gx->cmode0); - __gx->bpSent = 1; -} - -void GXSetDstAlpha(bool enabled, u8 value) { - SET_REG_FIELD(0, __gx->cmode1, 8, 0, value); - SET_REG_FIELD(0, __gx->cmode1, 1, 8, enabled); - GX_WRITE_RAS_REG(__gx->cmode1); - __gx->bpSent = 1; -} - -void GXSetFieldMask(GXBool odd_mask, GXBool even_mask) { - u32 reg; - - reg = 0; - SET_REG_FIELD(0x1FB, reg, 1, 0, even_mask); - SET_REG_FIELD(0x1FC, reg, 1, 1, odd_mask); - SET_REG_FIELD(0x1FD, reg, 8, 24, 0x44); - GX_WRITE_RAS_REG(reg); - __gx->bpSent = 1; -} - -void GXSetFieldMode(GXBool field_mode, GXBool half_aspect_ratio) { - u32 reg; - - SET_REG_FIELD(0x21A, __gx->lpSize, 1, 22, half_aspect_ratio); - GX_WRITE_RAS_REG(__gx->lpSize); - __GXFlushTextureState(); - - SET_REG_FIELD(0, reg, 8, 24, 0x68); - SET_REG_FIELD(0, reg, 1, 0, field_mode); - GX_WRITE_RAS_REG(reg); - __GXFlushTextureState(); -} -} diff --git a/aurora-main/lib/dolphin/gx/GXTev.cpp b/aurora-main/lib/dolphin/gx/GXTev.cpp deleted file mode 100644 index 8b021fe..0000000 --- a/aurora-main/lib/dolphin/gx/GXTev.cpp +++ /dev/null @@ -1,267 +0,0 @@ -#include "gx.hpp" -#include "__gx.h" - -extern "C" { -void GXSetTevOp(GXTevStageID id, GXTevMode mode) { - GXTevColorArg inputColor = GX_CC_RASC; - GXTevAlphaArg inputAlpha = GX_CA_RASA; - if (id != GX_TEVSTAGE0) { - inputColor = GX_CC_CPREV; - inputAlpha = GX_CA_APREV; - } - switch (mode) { - case GX_MODULATE: - GXSetTevColorIn(id, GX_CC_ZERO, GX_CC_TEXC, inputColor, GX_CC_ZERO); - GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_TEXA, inputAlpha, GX_CA_ZERO); - break; - case GX_DECAL: - GXSetTevColorIn(id, inputColor, GX_CC_TEXC, GX_CC_TEXA, GX_CC_ZERO); - GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, inputAlpha); - break; - case GX_BLEND: - GXSetTevColorIn(id, inputColor, GX_CC_ONE, GX_CC_TEXC, GX_CC_ZERO); - GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_TEXA, inputAlpha, GX_CA_ZERO); - break; - case GX_REPLACE: - GXSetTevColorIn(id, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_TEXC); - GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA); - break; - case GX_PASSCLR: - GXSetTevColorIn(id, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, inputColor); - GXSetTevAlphaIn(id, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, inputAlpha); - break; - } - GXSetTevColorOp(id, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); - GXSetTevAlphaOp(id, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); -} - -void GXSetTevColorIn(GXTevStageID stageId, GXTevColorArg a, GXTevColorArg b, GXTevColorArg c, GXTevColorArg d) { - u32* reg = &__gx->tevc[stageId]; - SET_REG_FIELD(0, *reg, 4, 12, a); - SET_REG_FIELD(0, *reg, 4, 8, b); - SET_REG_FIELD(0, *reg, 4, 4, c); - SET_REG_FIELD(0, *reg, 4, 0, d); - GX_WRITE_RAS_REG(*reg); - __gx->bpSent = 1; -} - -void GXSetTevAlphaIn(GXTevStageID stageId, GXTevAlphaArg a, GXTevAlphaArg b, GXTevAlphaArg c, GXTevAlphaArg d) { - u32* reg = &__gx->teva[stageId]; - SET_REG_FIELD(0, *reg, 3, 13, a); - SET_REG_FIELD(0, *reg, 3, 10, b); - SET_REG_FIELD(0, *reg, 3, 7, c); - SET_REG_FIELD(0, *reg, 3, 4, d); - GX_WRITE_RAS_REG(*reg); - __gx->bpSent = 1; -} - -void GXSetTevColorOp(GXTevStageID stageId, GXTevOp op, GXTevBias bias, GXTevScale scale, bool clamp, - GXTevRegID outReg) { - u32* reg = &__gx->tevc[stageId]; - SET_REG_FIELD(0, *reg, 1, 18, op & 1); - if (op <= 1) { - SET_REG_FIELD(0, *reg, 2, 20, scale); - SET_REG_FIELD(0, *reg, 2, 16, bias); - } else { - SET_REG_FIELD(0, *reg, 2, 20, (op >> 1) & 3); - SET_REG_FIELD(0, *reg, 2, 16, 3); - } - SET_REG_FIELD(0, *reg, 1, 19, clamp); - SET_REG_FIELD(0, *reg, 2, 22, outReg); - GX_WRITE_RAS_REG(*reg); - __gx->bpSent = 1; -} - -void GXSetTevAlphaOp(GXTevStageID stageId, GXTevOp op, GXTevBias bias, GXTevScale scale, bool clamp, - GXTevRegID outReg) { - u32* reg = &__gx->teva[stageId]; - SET_REG_FIELD(0, *reg, 1, 18, op & 1); - if (op <= 1) { - SET_REG_FIELD(0, *reg, 2, 20, scale); - SET_REG_FIELD(0, *reg, 2, 16, bias); - } else { - SET_REG_FIELD(0, *reg, 2, 20, (op >> 1) & 3); - SET_REG_FIELD(0, *reg, 2, 16, 3); - } - SET_REG_FIELD(0, *reg, 1, 19, clamp); - SET_REG_FIELD(0, *reg, 2, 22, outReg); - GX_WRITE_RAS_REG(*reg); - __gx->bpSent = 1; -} - -void GXSetTevColor(GXTevRegID id, GXColor color) { - CHECK(id >= GX_TEVPREV && id < GX_MAX_TEVREG, "bad tevreg {}", static_cast(id)); - - // Write BP registers (RA + BG pairs) - needed for display list capture - u32 regRA = 0; - SET_REG_FIELD(0, regRA, 11, 0, color.r); - SET_REG_FIELD(0, regRA, 11, 12, color.a); - SET_REG_FIELD(0, regRA, 8, 24, 0xE0 + id * 2); - u32 regBG = 0; - SET_REG_FIELD(0, regBG, 11, 0, color.b); - SET_REG_FIELD(0, regBG, 11, 12, color.g); - SET_REG_FIELD(0, regBG, 8, 24, 0xE1 + id * 2); - GX_WRITE_RAS_REG(regRA); - GX_WRITE_RAS_REG(regBG); - // NOTE: the SDK writes regBG three more times here for hardware timing. The value does not - // change and our software command processor needs no sync delay, so skip them. - __gx->bpSent = 1; -} - -void GXSetTevColorS10(GXTevRegID id, GXColorS10 color) { - // Write BP registers (RA + BG pairs) - needed for display list capture - u32 regRA = 0; - SET_REG_FIELD(0, regRA, 11, 0, color.r & 0x7FF); - SET_REG_FIELD(0, regRA, 11, 12, color.a & 0x7FF); - SET_REG_FIELD(0, regRA, 8, 24, 0xE0 + id * 2); - u32 regBG = 0; - SET_REG_FIELD(0, regBG, 11, 0, color.b & 0x7FF); - SET_REG_FIELD(0, regBG, 11, 12, color.g & 0x7FF); - SET_REG_FIELD(0, regBG, 8, 24, 0xE1 + id * 2); - GX_WRITE_RAS_REG(regRA); - GX_WRITE_RAS_REG(regBG); - // NOTE: the SDK writes regBG three more times here for hardware timing. The value does not - // change and our software command processor needs no sync delay, so skip them. - __gx->bpSent = 1; -} - -void GXSetAlphaCompare(GXCompare comp0, u8 ref0, GXAlphaOp op, GXCompare comp1, u8 ref1) { - // BP register 0xF3 - u32 reg = 0; - SET_REG_FIELD(0, reg, 8, 0, ref0); - SET_REG_FIELD(0, reg, 8, 8, ref1); - SET_REG_FIELD(0, reg, 3, 16, comp0); - SET_REG_FIELD(0, reg, 3, 19, comp1); - SET_REG_FIELD(0, reg, 2, 22, op); - SET_REG_FIELD(0, reg, 8, 24, 0xF3); - GX_WRITE_RAS_REG(reg); - __gx->bpSent = 1; -} - -void GXSetTevOrder(GXTevStageID id, GXTexCoordID tcid, GXTexMapID tmid, GXChannelID cid) { - // Channel ID mapping to hardware register values - static const u8 c2r[] = {0, 1, 0, 1, 0, 1, 7, 5, 6}; - u32* ptref = &__gx->tref[id / 2]; - __gx->texmapId[id] = tmid; - - u32 tmap = tmid & ~0x100u; - tmap = (tmap >= GX_MAX_TEXMAP) ? GX_TEXMAP0 : tmap; - const bool texCoordValid = tcid < GX_MAX_TEXCOORD; - if (texCoordValid) { - __gx->texmapValid |= 1u << id; - } else { - __gx->texmapValid &= ~(1u << id); - } - u32 tcoord = texCoordValid ? tcid : GX_TEXCOORD0; - u32 chanHw = (cid == GX_COLOR_NULL) ? 7 : c2r[cid]; - - if (id & 1) { - SET_REG_FIELD(0, *ptref, 3, 12, tmap); - SET_REG_FIELD(0, *ptref, 3, 15, tcoord); - SET_REG_FIELD(0, *ptref, 3, 19, chanHw); - SET_REG_FIELD(0, *ptref, 1, 18, (tmid != GX_TEXMAP_NULL && !(tmid & 0x100))); - } else { - SET_REG_FIELD(0, *ptref, 3, 0, tmap); - SET_REG_FIELD(0, *ptref, 3, 3, tcoord); - SET_REG_FIELD(0, *ptref, 3, 7, chanHw); - SET_REG_FIELD(0, *ptref, 1, 6, (tmid != GX_TEXMAP_NULL && !(tmid & 0x100))); - } - - GX_WRITE_RAS_REG(*ptref); - __gx->bpSent = 1; - __gx->dirtyState |= 1; // SU tex regs dirty -} - -void GXSetZTexture(GXZTexOp op, GXTexFmt fmt, u32 bias) { - u32 zfmt; - switch (fmt) { - case GX_TF_Z8: - zfmt = 0; - break; - case GX_TF_Z16: - zfmt = 1; - break; - case GX_TF_Z24X8: - zfmt = 2; - break; - default: - zfmt = 2; - break; - } - - GX_WRITE_RAS_REG(0xF4000000u | (bias & 0x00FFFFFFu)); - GX_WRITE_RAS_REG(0xF5000000u | ((static_cast(op) & 0x3u) << 2) | (zfmt & 0x3u)); - __gx->bpSent = 1; -} - -void GXSetNumTevStages(u8 num) { - SET_REG_FIELD(0, __gx->genMode, 4, 10, num - 1); - __gx->dirtyState |= 4; // gen mode dirty -} - -void GXSetTevKColor(GXTevKColorID id, GXColor color) { - CHECK(id >= GX_KCOLOR0 && id < GX_MAX_KCOLOR, "bad kcolor {}", static_cast(id)); - - // Write BP registers (RA + BG pairs with bit 23 set for K color) - u32 regRA = 0; - SET_REG_FIELD(0, regRA, 8, 0, color.r); - SET_REG_FIELD(0, regRA, 8, 12, color.a); - SET_REG_FIELD(0, regRA, 4, 20, 8); // K color flag - SET_REG_FIELD(0, regRA, 8, 24, 0xE0 + id * 2); - u32 regBG = 0; - SET_REG_FIELD(0, regBG, 8, 0, color.b); - SET_REG_FIELD(0, regBG, 8, 12, color.g); - SET_REG_FIELD(0, regBG, 4, 20, 8); // K color flag - SET_REG_FIELD(0, regBG, 8, 24, 0xE1 + id * 2); - GX_WRITE_RAS_REG(regRA); - GX_WRITE_RAS_REG(regBG); - __gx->bpSent = 1; -} - -void GXSetTevKColorSel(GXTevStageID id, GXTevKColorSel sel) { - // tevKsel registers: 2 stages per register - u32 kselIdx = id / 2; - if (id & 1) { - SET_REG_FIELD(0, __gx->tevKsel[kselIdx], 5, 14, sel); - } else { - SET_REG_FIELD(0, __gx->tevKsel[kselIdx], 5, 4, sel); - } - GX_WRITE_RAS_REG(__gx->tevKsel[kselIdx]); - __gx->bpSent = 1; -} - -void GXSetTevKAlphaSel(GXTevStageID id, GXTevKAlphaSel sel) { - u32 kselIdx = id / 2; - if (id & 1) { - SET_REG_FIELD(0, __gx->tevKsel[kselIdx], 5, 19, sel); - } else { - SET_REG_FIELD(0, __gx->tevKsel[kselIdx], 5, 9, sel); - } - GX_WRITE_RAS_REG(__gx->tevKsel[kselIdx]); - __gx->bpSent = 1; -} - -void GXSetTevSwapMode(GXTevStageID stageId, GXTevSwapSel rasSel, GXTevSwapSel texSel) { - // Swap mode is stored in teva register - u32* reg = &__gx->teva[stageId]; - SET_REG_FIELD(0, *reg, 2, 0, rasSel); - SET_REG_FIELD(0, *reg, 2, 2, texSel); - GX_WRITE_RAS_REG(*reg); - __gx->bpSent = 1; -} - -void GXSetTevSwapModeTable(GXTevSwapSel id, GXTevColorChan red, GXTevColorChan green, GXTevColorChan blue, - GXTevColorChan alpha) { - CHECK(id >= GX_TEV_SWAP0 && id < GX_MAX_TEVSWAP, "bad tev swap sel {}", static_cast(id)); - // Swap table is stored in tevKsel registers - u32 kselIdx = id * 2; - SET_REG_FIELD(0, __gx->tevKsel[kselIdx], 2, 0, red); - SET_REG_FIELD(0, __gx->tevKsel[kselIdx], 2, 2, green); - GX_WRITE_RAS_REG(__gx->tevKsel[kselIdx]); - - SET_REG_FIELD(0, __gx->tevKsel[kselIdx + 1], 2, 0, blue); - SET_REG_FIELD(0, __gx->tevKsel[kselIdx + 1], 2, 2, alpha); - GX_WRITE_RAS_REG(__gx->tevKsel[kselIdx + 1]); - __gx->bpSent = 1; -} -} diff --git a/aurora-main/lib/dolphin/gx/GXTexture.cpp b/aurora-main/lib/dolphin/gx/GXTexture.cpp deleted file mode 100644 index 684ba79..0000000 --- a/aurora-main/lib/dolphin/gx/GXTexture.cpp +++ /dev/null @@ -1,484 +0,0 @@ -#include "gx.hpp" -#include "__gx.h" - -#include "../../gfx/texture.hpp" -#include "../../gfx/texture_replacement.hpp" -#include "dolphin/gx/GXAurora.h" - -#include - -#include -#include -#include - -#include "tracy/Tracy.hpp" - -namespace { -constexpr u8 GXTexMode0Ids[8] = {0x80, 0x81, 0x82, 0x83, 0xA0, 0xA1, 0xA2, 0xA3}; -constexpr u8 GXTexMode1Ids[8] = {0x84, 0x85, 0x86, 0x87, 0xA4, 0xA5, 0xA6, 0xA7}; -constexpr u8 GXTexImage0Ids[8] = {0x88, 0x89, 0x8A, 0x8B, 0xA8, 0xA9, 0xAA, 0xAB}; -constexpr u8 GXTexImage1Ids[8] = {0x8C, 0x8D, 0x8E, 0x8F, 0xAC, 0xAD, 0xAE, 0xAF}; -constexpr u8 GXTexImage2Ids[8] = {0x90, 0x91, 0x92, 0x93, 0xB0, 0xB1, 0xB2, 0xB3}; -constexpr u8 GXTexImage3Ids[8] = {0x94, 0x95, 0x96, 0x97, 0xB4, 0xB5, 0xB6, 0xB7}; -constexpr u8 GXTexTlutIds[8] = {0x98, 0x99, 0x9A, 0x9B, 0xB8, 0xB9, 0xBA, 0xBB}; -constexpr u8 GX2HWFiltConv[6] = {0x00, 0x04, 0x01, 0x05, 0x02, 0x06}; - -u32 sNextTexObjId = 1; -u32 sNextTlutObjId = 1; - -u32 next_tex_obj_id() { - if (sNextTexObjId == 0) { - FATAL("texObj ID overflow"); - } - return sNextTexObjId++; -} - -u32 next_tlut_obj_id() { - if (sNextTlutObjId == 0) { - FATAL("tlutObj ID overflow"); - } - return sNextTlutObjId++; -} - - // Give each palette buffer a stable ID so its GPU cache can be reused. -struct TlutIdentity { - const void* data = nullptr; - u32 format = 0; - u32 entries = 0; - - bool operator==(const TlutIdentity& rhs) const noexcept { - return data == rhs.data && format == rhs.format && entries == rhs.entries; - } - - template - friend H AbslHashValue(H h, const TlutIdentity& key) { - return H::combine(std::move(h), key.data, key.format, key.entries); - } -}; - -struct TlutIdentityRecord { - u32 objId = 0; - u32 dataVersion = 0; - u64 digest = 0; -}; - - // Limit cached palette IDs; evicted palettes are safely uploaded again. -constexpr size_t MaxTlutIdentities = 4096; -absl::flat_hash_map sTlutIdentities; - - // Use separate high-range versions when a palette points to a new buffer. -u32 sNextRepointedTlutDataVersion = 0; - -u32 next_repointed_tlut_data_version() { - if (sNextRepointedTlutDataVersion == 0x7FFFFFFFu) { - sNextRepointedTlutDataVersion = 0; - } - return 0x80000000u | ++sNextRepointedTlutDataVersion; -} - -std::pair resolve_tlut_identity(const void* data, GXTlutFmt format, u16 entries) { - if (data == nullptr || entries == 0) { - return {next_tlut_obj_id(), 1}; - } - - const auto digest = - static_cast(aurora::xxh3_hash_s(data, static_cast(entries) * sizeof(u16))); - if (sTlutIdentities.size() >= MaxTlutIdentities) { - sTlutIdentities.clear(); - } - - const TlutIdentity key{ - .data = data, - .format = static_cast(format), - .entries = entries, - }; - auto [it, inserted] = sTlutIdentities.try_emplace(key); - auto& record = it->second; - if (inserted) { - record.objId = next_tlut_obj_id(); - record.dataVersion = 1; - record.digest = digest; - } else if (record.digest != digest) { - // Same buffer, different palette: invalidate everything keyed on this ID. - record.digest = digest; - if (record.dataVersion >= 0x7FFFFFFFu) { - record.dataVersion = 1; - } else { - ++record.dataVersion; - } - } - return {record.objId, record.dataVersion}; -} - -int __cntlzw(unsigned int val) { - if (val == 0) - return 32; // PowerPC returns 32 if the input is 0 -#ifdef _MSC_VER - unsigned long idx; - _BitScanReverse(&idx, val); - return 31 - (int)idx; -#else - return __builtin_clz(val); -#endif -} - -void init_texobj_common(GXTexObj_& obj, const void* data, u16 width, u16 height, u32 format, GXTexWrapMode wrapS, - GXTexWrapMode wrapT, GXBool mipmap) { - obj = {}; - obj.mWidth = width; - obj.mHeight = height; - obj.mFormat = format; - obj.tlut = GX_TLUT0; - obj.flags = 2; - obj.texObjId = next_tex_obj_id(); - obj.texDataVersion = 1; - - SET_REG_FIELD(0, obj.mode0, 2, 0, wrapS); - SET_REG_FIELD(0, obj.mode0, 2, 2, wrapT); - SET_REG_FIELD(0, obj.mode0, 1, 4, 1); - if (mipmap) { - obj.flags |= 1; - obj.mode0 = (obj.mode0 & 0xFFFFFF1F) | 0xC0; - const u32 maxDim = std::max(width, height); - const u8 lmax = static_cast(16.0f * static_cast(31 - __cntlzw(maxDim))); - SET_REG_FIELD(0, obj.mode1, 8, 8, lmax); - } else { - obj.mode0 = (obj.mode0 & 0xFFFFFF1F) | 0x80; - } - SET_REG_FIELD(0, obj.image0, 10, 0, static_cast(width - 1)); - SET_REG_FIELD(0, obj.image0, 10, 10, static_cast(height - 1)); - SET_REG_FIELD(0, obj.image0, 4, 20, format & 0xF); - - obj.data = data; -} - -void emit_loaded_texobj_metadata(const GXTexObj_& obj, GXTexMapID id) { - GX_WRITE_AURORA(GX_LOAD_AURORA_TEXOBJ); - GX_WRITE_U8(static_cast(id)); - GX_WRITE_U64(reinterpret_cast(obj.data)); - GX_WRITE_U32(obj.width()); - GX_WRITE_U32(obj.height()); - GX_WRITE_U32(obj.format()); - GX_WRITE_U32(static_cast(obj.tlut)); - GX_WRITE_U8(static_cast(obj.has_mips())); - GX_WRITE_U32(obj.texObjId); - GX_WRITE_U32(obj.texDataVersion); -} - -void emit_loaded_tlut_metadata(const GXTlutObj_& obj, u32 idx) { - GX_WRITE_AURORA(GX_LOAD_AURORA_TLUT); - GX_WRITE_U8(static_cast(idx)); - GX_WRITE_U64(reinterpret_cast(obj.data)); - GX_WRITE_U32(static_cast(obj.format)); - GX_WRITE_U16(obj.numEntries); - GX_WRITE_U32(obj.tlutObjId); - GX_WRITE_U32(obj.tlutDataVersion); -} -} // namespace - -extern "C" { -void GXInitTexObj(GXTexObj* obj_, const void* data, u16 width, u16 height, GXTexFmt format, GXTexWrapMode wrapS, - GXTexWrapMode wrapT, GXBool mipmap) { - auto* obj = reinterpret_cast(obj_); - init_texobj_common(*obj, data, width, height, format, wrapS, wrapT, mipmap); -} - -void GXInitTexObjCI(GXTexObj* obj_, const void* data, u16 width, u16 height, GXCITexFmt format, GXTexWrapMode wrapS, - GXTexWrapMode wrapT, GXBool mipmap, u32 tlut) { - auto* obj = reinterpret_cast(obj_); - init_texobj_common(*obj, data, width, height, format, wrapS, wrapT, mipmap); - obj->tlut = static_cast(tlut); - obj->flags &= ~2u; -} - -void GXInitTexObjLOD(GXTexObj* obj_, GXTexFilter minFilt, GXTexFilter magFilt, float minLod, float maxLod, - float lodBias, GXBool biasClamp, GXBool doEdgeLod, GXAnisotropy maxAniso) { - auto* obj = reinterpret_cast(obj_); - const float clampedBias = std::clamp(lodBias, -4.0f, 3.99f); - const auto lbias = static_cast(32.0f * clampedBias); - SET_REG_FIELD(0, obj->mode0, 8, 9, lbias); - SET_REG_FIELD(0, obj->mode0, 1, 4, magFilt == GX_LINEAR ? 1 : 0); - SET_REG_FIELD(0, obj->mode0, 3, 5, GX2HWFiltConv[minFilt]); - SET_REG_FIELD(0, obj->mode0, 1, 8, doEdgeLod ? 0 : 1); - obj->mode0 &= 0xFFFDFFFF; - obj->mode0 &= 0xFFFBFFFF; - SET_REG_FIELD(0, obj->mode0, 2, 19, maxAniso); - SET_REG_FIELD(0, obj->mode0, 1, 21, biasClamp); - - const auto clampedMin = std::clamp(minLod, 0.0f, 10.0f); - const auto clampedMax = std::clamp(maxLod, 0.0f, 10.0f); - SET_REG_FIELD(0, obj->mode1, 8, 0, static_cast(16.0f * clampedMin)); - SET_REG_FIELD(0, obj->mode1, 8, 8, static_cast(16.0f * clampedMax)); -} - -void GXInitTexObjData(GXTexObj* obj_, const void* data) { - auto* obj = reinterpret_cast(obj_); - obj->data = data; - ++obj->texDataVersion; -} - -void GXInitTexObjWrapMode(GXTexObj* obj_, GXTexWrapMode wrapS, GXTexWrapMode wrapT) { - auto* obj = reinterpret_cast(obj_); - SET_REG_FIELD(0, obj->mode0, 2, 0, wrapS); - SET_REG_FIELD(0, obj->mode0, 2, 2, wrapT); -} - -void GXInitTexObjTlut(GXTexObj* obj_, u32 tlut) { - auto* obj = reinterpret_cast(obj_); - obj->tlut = static_cast(tlut); -} - -void GXInitTexObjFilter(GXTexObj* obj_, GXTexFilter minFilt, GXTexFilter magFilt) { - auto* obj = reinterpret_cast(obj_); - SET_REG_FIELD(0, obj->mode0, 3, 5, GX2HWFiltConv[minFilt]); - SET_REG_FIELD(0, obj->mode0, 1, 4, magFilt == GX_LINEAR ? 1 : 0); -} - -void GXInitTexObjMaxLOD(GXTexObj* obj_, float maxLod) { - auto* obj = reinterpret_cast(obj_); - const auto clampedMax = std::clamp(maxLod, 0.0f, 10.0f); - SET_REG_FIELD(0, obj->mode1, 8, 8, static_cast(16.0f * clampedMax)); -} - -void GXInitTexObjMinLOD(GXTexObj* obj_, float minLod) { - auto* obj = reinterpret_cast(obj_); - const auto clampedMin = std::clamp(minLod, 0.0f, 10.0f); - SET_REG_FIELD(0, obj->mode1, 8, 0, static_cast(16.0f * clampedMin)); -} - -void GXInitTexObjLODBias(GXTexObj* obj_, float lodBias) { - auto* obj = reinterpret_cast(obj_); - const float clampedBias = std::clamp(lodBias, -4.0f, 3.99f); - const auto lbias = static_cast(32.0f * clampedBias); - SET_REG_FIELD(0, obj->mode0, 8, 9, lbias); -} - -void GXInitTexObjBiasClamp(GXTexObj* obj_, GXBool biasClamp) { - auto* obj = reinterpret_cast(obj_); - SET_REG_FIELD(0, obj->mode0, 1, 21, biasClamp); -} - -void GXInitTexObjEdgeLOD(GXTexObj* obj_, GXBool doEdgeLod) { - auto* obj = reinterpret_cast(obj_); - SET_REG_FIELD(0, obj->mode0, 1, 8, doEdgeLod ? 0 : 1); -} - -void GXInitTexObjMaxAniso(GXTexObj* obj_, GXAnisotropy maxAniso) { - auto* obj = reinterpret_cast(obj_); - SET_REG_FIELD(0, obj->mode0, 2, 19, maxAniso); -} - -void GXInitTexObjUserData(GXTexObj* obj_, void* userData) { - auto* obj = reinterpret_cast(obj_); - obj->userData = userData; -} - -void* GXGetTexObjUserData(const GXTexObj* obj_) { - const auto* obj = reinterpret_cast(obj_); - return const_cast(obj->userData); -} - -void GXLoadTexObj(GXTexObj* obj_, GXTexMapID id) { - auto* obj = reinterpret_cast(obj_); - SET_REG_FIELD(0, obj->mode0, 8, 24, GXTexMode0Ids[id]); - SET_REG_FIELD(0, obj->mode1, 8, 24, GXTexMode1Ids[id]); - SET_REG_FIELD(0, obj->image0, 8, 24, GXTexImage0Ids[id]); - - u32 image1 = 0; - u32 image2 = 0; - SET_REG_FIELD(0, image1, 8, 24, GXTexImage1Ids[id]); - SET_REG_FIELD(0, image2, 8, 24, GXTexImage2Ids[id]); - SET_REG_FIELD(0, obj->image3, 8, 24, GXTexImage3Ids[id]); - - GX_WRITE_RAS_REG(obj->mode0); - GX_WRITE_RAS_REG(obj->mode1); - GX_WRITE_RAS_REG(obj->image0); - GX_WRITE_RAS_REG(image1); - GX_WRITE_RAS_REG(image2); - GX_WRITE_RAS_REG(obj->image3); - - if ((obj->flags & 2) == 0) { - u32 tlut = 0; - SET_REG_FIELD(0, tlut, 10, 0, static_cast(obj->tlut)); - SET_REG_FIELD(0, tlut, 8, 24, GXTexTlutIds[id]); - GX_WRITE_RAS_REG(tlut); - } - - __gx->tImage0[id] = obj->image0; - __gx->tMode0[id] = obj->mode0; - __gx->dirtyState |= 1; - __gx->bpSent = 1; - - emit_loaded_texobj_metadata(*obj, id); -} - -u32 GXGetTexBufferSize(u16 width, u16 height, u32 fmt, GXBool mips, u8 maxLod) { - if (fmt == GX_TF_R8_PC || fmt == GX_TF_RGBA8_PC) { - const u32 bytesPerPixel = fmt == GX_TF_R8_PC ? 1u : 4u; - const u32 mipCount = mips ? static_cast(maxLod) + 1u : 1u; - u64 byteCount = 0; - for (u32 mip = 0; mip < mipCount; ++mip) { - byteCount += static_cast(width) * height * bytesPerPixel; - if (width == 1 && height == 1) { - break; - } - width = std::max(width / 2, 1); - height = std::max(height / 2, 1); - } - CHECK(byteCount <= UINT32_MAX, "GXGetTexBufferSize: linear PC texture is too large ({} bytes)", byteCount); - return static_cast(byteCount); - } - - s32 shiftX = 0; - s32 shiftY = 0; - switch (fmt) { - case GX_TF_I4: - case GX_TF_C4: - case GX_TF_CMPR: - case GX_CTF_R4: - case GX_CTF_Z4: - shiftX = 3; - shiftY = 3; - break; - case GX_TF_I8: - case GX_TF_IA4: - case GX_TF_C8: - case GX_TF_Z8: - case GX_CTF_RA4: - case GX_CTF_A8: - case GX_CTF_R8: - case GX_CTF_G8: - case GX_CTF_B8: - case GX_CTF_Z8M: - case GX_CTF_Z8L: - shiftX = 3; - shiftY = 2; - break; - case GX_TF_IA8: - case GX_TF_RGB565: - case GX_TF_RGB5A3: - case GX_TF_RGBA8: - case GX_TF_C14X2: - case GX_TF_Z16: - case GX_TF_Z24X8: - case GX_CTF_RA8: - case GX_CTF_RG8: - case GX_CTF_GB8: - case GX_CTF_Z16L: - shiftX = 2; - shiftY = 2; - break; - default: - break; - } - u32 bitSize = fmt == GX_TF_RGBA8 || fmt == GX_TF_Z24X8 ? 64 : 32; - u32 bufLen = 0; - if (mips) { - const u32 mipCount = static_cast(maxLod) + 1; - for (u32 mip = 0; mip < mipCount; ++mip) { - const u32 tileX = ((width + (1 << shiftX) - 1) >> shiftX); - const u32 tileY = ((height + (1 << shiftY) - 1) >> shiftY); - bufLen += bitSize * tileX * tileY; - - if (width == 1 && height == 1) { - return bufLen; - } - - width = (width < 2) ? 1 : width / 2; - height = (height < 2) ? 1 : height / 2; - } - } else { - const u32 tileX = ((width + (1 << shiftX) - 1) >> shiftX); - const u32 tileY = ((height + (1 << shiftY) - 1) >> shiftY); - bufLen = bitSize * tileX * tileY; - } - - return bufLen; -} - -void GXInitTlutObj(GXTlutObj* obj_, const void* data, GXTlutFmt format, u16 entries) { - memset(obj_, 0, sizeof(GXTlutObj)); - auto* obj = reinterpret_cast(obj_); - obj->data = data; - obj->format = format; - obj->numEntries = entries; - const auto [tlutObjId, tlutDataVersion] = resolve_tlut_identity(data, format, entries); - obj->tlutObjId = tlutObjId; - obj->tlutDataVersion = tlutDataVersion; - - SET_REG_FIELD(0, obj->tlut, 2, 10, format); - SET_REG_FIELD(0, obj->loadTlut0, 8, 24, 0x64); - aurora::gfx::texture_replacement::register_tlut(obj_, data, format, entries); -} - -void GXInitTlutObjData(GXTlutObj* obj_, const void* data) { - auto* obj = reinterpret_cast(obj_); - obj->data = data; - obj->tlutDataVersion = next_repointed_tlut_data_version(); -} - -void GXLoadTlut(const GXTlutObj* obj_, u32 idx) { - auto* obj = reinterpret_cast(obj_); - __GXFlushTextureState(); - GX_WRITE_RAS_REG(obj->loadTlut0); - - u32 loadTlut1 = 0; - SET_REG_FIELD(0, loadTlut1, 10, 0, idx); - SET_REG_FIELD(0, loadTlut1, 10, 10, obj->numEntries - 1); - SET_REG_FIELD(0, loadTlut1, 8, 24, 0x65); - GX_WRITE_RAS_REG(loadTlut1); - __GXFlushTextureState(); - - aurora::gfx::texture_replacement::load_tlut(obj_, idx); - emit_loaded_tlut_metadata(*obj, idx); -} - -// TODO GXInitTexCacheRegion -// TODO GXInitTexPreLoadRegion -// TODO GXInitTlutRegion -// TODO GXInvalidateTexRegion - -void GXInvalidateTexAll() { - GX_WRITE_AURORA(GX_LOAD_AURORA_INVALIDATE_TEX_ALL); -} - -// TODO GXPreLoadEntireTexture -// TODO GXSetTexRegionCallback -// TODO GXSetTlutRegionCallback -// TODO GXLoadTexObjPreLoaded -void GXSetTexCoordScaleManually(GXTexCoordID coord, GXBool enable, u16 ss, u16 ts) { - __gx->tcsManEnab = (__gx->tcsManEnab & ~(1 << coord)) | (enable << coord); - if (enable) { - SET_REG_FIELD(0, __gx->suTs0[coord], 16, 0, static_cast(ss - 1)); - SET_REG_FIELD(0, __gx->suTs1[coord], 16, 0, static_cast(ts - 1)); - GX_WRITE_RAS_REG(__gx->suTs0[coord]); - GX_WRITE_RAS_REG(__gx->suTs1[coord]); - __gx->bpSent = 1; - } -} - -void GXSetTexCoordCylWrap(GXTexCoordID coord, GXBool s_enable, GXBool t_enable) { - SET_REG_FIELD(0, __gx->suTs0[coord], 1, 17, s_enable); - SET_REG_FIELD(0, __gx->suTs1[coord], 1, 17, t_enable); - if (__gx->tcsManEnab & (1 << coord)) { - GX_WRITE_RAS_REG(__gx->suTs0[coord]); - GX_WRITE_RAS_REG(__gx->suTs1[coord]); - __gx->bpSent = 1; - } -} - -void GXSetTexCoordBias(GXTexCoordID coord, GXBool s_enable, GXBool t_enable) { - SET_REG_FIELD(0, __gx->suTs0[coord], 1, 16, s_enable); - SET_REG_FIELD(0, __gx->suTs1[coord], 1, 16, t_enable); - if (__gx->tcsManEnab & (1 << coord)) { - GX_WRITE_RAS_REG(__gx->suTs0[coord]); - GX_WRITE_RAS_REG(__gx->suTs1[coord]); - __gx->bpSent = 1; - } -} - -void __GXFlushTextureState() { - GX_WRITE_RAS_REG(__gx->bpMask); - __gx->bpSent = 1; -} -} diff --git a/aurora-main/lib/dolphin/gx/GXTransform.cpp b/aurora-main/lib/dolphin/gx/GXTransform.cpp deleted file mode 100644 index b881d38..0000000 --- a/aurora-main/lib/dolphin/gx/GXTransform.cpp +++ /dev/null @@ -1,216 +0,0 @@ -#include "gx.hpp" -#include "__gx.h" -#include "dolphin/mtx/GeoTypes.h" - -static inline void CacheProjectionVector(const f32* ptr, GXProjectionType type) { - __gx->projType = type; - for (int i = 0; i < 6; ++i) { - __gx->projMtx[i] = ptr[i + 1]; - } -} - -extern "C" { - -void GXSetProjection(const void* mtx_, GXProjectionType type) { - const auto& mtx = *reinterpret_cast*>(mtx_); - const f32 projVec[] = { - static_cast(type == GX_ORTHOGRAPHIC), - mtx[0][0], - type == GX_ORTHOGRAPHIC ? mtx[0][3] : mtx[0][2], - mtx[1][1], - type == GX_ORTHOGRAPHIC ? mtx[1][3] : mtx[1][2], - mtx[2][2], - mtx[2][3], - }; - CacheProjectionVector(projVec, type); - - // XF bulk write: 6 params + projection type at 0x1020-0x1026 - GX_WRITE_U8(0x10); - GX_WRITE_U32(0x00061020); - GX_WRITE_XF_REG_F(32, __gx->projMtx[0]); - GX_WRITE_XF_REG_F(33, __gx->projMtx[1]); - GX_WRITE_XF_REG_F(34, __gx->projMtx[2]); - GX_WRITE_XF_REG_F(35, __gx->projMtx[3]); - GX_WRITE_XF_REG_F(36, __gx->projMtx[4]); - GX_WRITE_XF_REG_F(37, __gx->projMtx[5]); - GX_WRITE_XF_REG_2(38, __gx->projType); - __gx->bpSent = 0; -} - -void GXSetProjectionv(const f32* ptr) { - CHECK(ptr != nullptr, "null projection vector"); - - const GXProjectionType type = ptr[0] == 0.0f ? GX_PERSPECTIVE : GX_ORTHOGRAPHIC; - CacheProjectionVector(ptr, type); - - // XF bulk write: 6 params + projection type at 0x1020-0x1026 - GX_WRITE_U8(0x10); - GX_WRITE_U32(0x00061020); - for (int i = 0; i < 6; ++i) { - GX_WRITE_F32(__gx->projMtx[i]); - } - GX_WRITE_U32(__gx->projType); - __gx->bpSent = 0; -} - -void GXLoadPosMtxImm(const void* mtx_, u32 id) { - CHECK(id >= GX_PNMTX0 && id <= GX_PNMTX9, "invalid pn mtx {}", static_cast(id)); - const auto* mtx = reinterpret_cast(mtx_); - - GX_WRITE_U8(0x10); - GX_WRITE_U32((id * 4) | 0xB0000); - for (int i = 0; i < 12; i++) { - GX_WRITE_F32(mtx[i]); - } -} - -void GXLoadNrmMtxImm(const void* mtx_, u32 id) { - CHECK(id >= GX_PNMTX0 && id <= GX_PNMTX9, "invalid pn mtx {}", static_cast(id)); - const auto* mtx = reinterpret_cast(mtx_); - - GX_WRITE_U8(0x10); - GX_WRITE_U32((id * 3 + 0x400) | 0x80000); - // Write 3x3 from 3x4 matrix (skip translation column) - GX_WRITE_F32(mtx[0]); - GX_WRITE_F32(mtx[1]); - GX_WRITE_F32(mtx[2]); - GX_WRITE_F32(mtx[4]); - GX_WRITE_F32(mtx[5]); - GX_WRITE_F32(mtx[6]); - GX_WRITE_F32(mtx[8]); - GX_WRITE_F32(mtx[9]); - GX_WRITE_F32(mtx[10]); -} - -void GXSetCurrentMtx(u32 id) { - CHECK(id >= GX_PNMTX0 && id <= GX_PNMTX9, "invalid pn mtx {}", id); - SET_REG_FIELD(0, __gx->matIdxA, 6, 0, id); - __GXSetMatrixIndex(GX_VA_PNMTXIDX); -} - -void GXLoadTexMtxImm(const void* mtx_, u32 id, GXTexMtxType type) { - CHECK((id >= GX_TEXMTX0 && id <= GX_IDENTITY) || (id >= GX_PTTEXMTX0 && id <= GX_PTIDENTITY), "invalid tex mtx {}", - id); - - u32 addr; - if (id >= GX_PTTEXMTX0) { - addr = (id - GX_PTTEXMTX0) * 4 + 0x500; - CHECK(type == GX_MTX3x4, "invalid pt mtx type {}", underlying(type)); - } else { - addr = id * 4; - } - - u32 count = (type == GX_MTX2x4) ? 8 : 12; - u32 reg = addr | ((count - 1) << 16); - - GX_WRITE_U8(0x10); - GX_WRITE_U32(reg); - - const auto* mtx = reinterpret_cast(mtx_); - for (u32 i = 0; i < count; i++) { - GX_WRITE_F32(mtx[i]); - } -} - -void GXSetViewport(float left, float top, float width, float height, float nearZ, float farZ) { - GXSetViewportJitter(left, top, width, height, nearZ, farZ, 1); -} - -void GXSetViewportJitter(float left, float top, float width, float height, float nearZ, float farZ, u32 field) { - float sx; - float sy; - float sz; - float ox; - float oy; - float oz; - float zmin; - float zmax; - - if (field == 0) { - top -= 0.5f; - } - - sx = width / 2.0f; - sy = -height / 2.0f; - ox = 340.0f + (left + width / 2.0f); - oy = 340.0f + (top + height / 2.0f); - zmin = 1.6777215e7f * nearZ; - zmax = 1.6777215e7f * farZ; - sz = zmax - zmin; - oz = zmax; - - __gx->vpLeft = left; - __gx->vpTop = top; - __gx->vpWd = width; - __gx->vpHt = height; - __gx->vpNearz = nearZ; - __gx->vpFarz = farZ; - - GX_WRITE_U8(0x10); - GX_WRITE_U32(0x0005101A); - GX_WRITE_XF_REG_F(26, sx); - GX_WRITE_XF_REG_F(27, sy); - GX_WRITE_XF_REG_F(28, sz); - GX_WRITE_XF_REG_F(29, ox); - GX_WRITE_XF_REG_F(30, oy); - GX_WRITE_XF_REG_F(31, oz); - __gx->bpSent = 0; -} - -void GXProject(f32 x, f32 y, f32 z, const f32 mtx[3][4], const f32* pm, const f32* vp, f32* sx, - f32* sy, f32* sz) { - Vec peye; - f32 xc; - f32 yc; - f32 zc; - f32 wc; - - peye.x = mtx[0][3] + ((mtx[0][2] * z) + ((mtx[0][0] * x) + (mtx[0][1] * y))); - peye.y = mtx[1][3] + ((mtx[1][2] * z) + ((mtx[1][0] * x) + (mtx[1][1] * y))); - peye.z = mtx[2][3] + ((mtx[2][2] * z) + ((mtx[2][0] * x) + (mtx[2][1] * y))); - if (pm[0] == 0.0f) { - xc = (peye.x * pm[1]) + (peye.z * pm[2]); - yc = (peye.y * pm[3]) + (peye.z * pm[4]); - zc = pm[6] + (peye.z * pm[5]); - wc = 1.0f / -peye.z; - } else { - xc = pm[2] + (peye.x * pm[1]); - yc = pm[4] + (peye.y * pm[3]); - zc = pm[6] + (peye.z * pm[5]); - wc = 1.0f; - } - *sx = (vp[2] / 2.0f) + (vp[0] + (wc * (xc * vp[2] / 2.0f))); - *sy = (vp[3] / 2.0f) + (vp[1] + (wc * (-yc * vp[3] / 2.0f))); - *sz = vp[5] + (wc * (zc * (vp[5] - vp[4]))); -} - -// TODO GXLoadPosMtxIndx -// TODO GXLoadNrmMtxImm3x3 -// TODO GXLoadNrmMtxIndx3x3 -// TODO GXLoadTexMtxIndx -void GXSetZScaleOffset(f32 scale, f32 offset) { - g_gxState.zScale = scale; - g_gxState.zOffset = offset; - constexpr f32 z24Scale = 16777215.0f; - const f32 sz = z24Scale * offset; - const f32 oz = 1.0f + z24Scale * scale; - - GX_WRITE_U8(0x10); - GX_WRITE_U32(0x101c); - GX_WRITE_F32(sz); - GX_WRITE_U8(0x10); - GX_WRITE_U32(0x101f); - GX_WRITE_F32(oz); - __gx->bpSent = 0; -} - -void GXSetScissorBoxOffset(s32 x_off, s32 y_off) { - g_gxState.scissorOffsetX = x_off; - g_gxState.scissorOffsetY = y_off; - - const u32 reg = 0x59000000u | (((static_cast(y_off + 0x156) * 0x200u) & 0x000ffc00u)) | - ((static_cast(x_off + 0x156) >> 1) & 0x000003ffu); - GX_WRITE_RAS_REG(reg); - __gx->bpSent = 0; -} -} diff --git a/aurora-main/lib/dolphin/gx/GXVert.cpp b/aurora-main/lib/dolphin/gx/GXVert.cpp deleted file mode 100644 index 6f71945..0000000 --- a/aurora-main/lib/dolphin/gx/GXVert.cpp +++ /dev/null @@ -1,733 +0,0 @@ -#include "gx.hpp" -#include "__gx.h" -#include "../../gx/fifo.hpp" - -#include -#include -#include -#include -#include - -// Track vertex count between GXBegin/GXEnd for mismatch detection -static u16 sBeginNVerts = 0; -static u32 sBeginFifoSize = 0; -static GXPrimitive sBeginPrimitive = GX_TRIANGLES; -static GXVtxFmt sBeginVtxFmt = GX_VTXFMT0; -static bool sInBegin = false; -static GXAttr sWriteAttr = GX_VA_NULL; -static u32 sWriteAttrComps = 0; - -namespace { - -static u8 normal_frac_bits(GXCompType type) { - switch (type) { - case GX_U8: - return 7; - case GX_S8: - return 6; - case GX_U16: - return 15; - case GX_S16: - return 14; - default: - return 0; - } -} - -struct ActiveAttrFmt { - GXCompCnt cnt = GX_POS_XYZ; - GXCompType type = GX_F32; - u8 frac = 0; -}; - -enum class ScalarKind { - Float, - Signed, - Unsigned, -}; - -struct Scalar { - ScalarKind kind = ScalarKind::Float; - float f = 0.0f; - int32_t s = 0; - uint32_t u = 0; -}; - -static Scalar scalar_f32(float value) { - return Scalar{.kind = ScalarKind::Float, .f = value, .s = static_cast(value), .u = static_cast(value)}; -} - -static Scalar scalar_u32(uint32_t value) { - return Scalar{.kind = ScalarKind::Unsigned, .f = static_cast(value), .s = static_cast(value), .u = value}; -} - -static Scalar scalar_s32(int32_t value) { - return Scalar{.kind = ScalarKind::Signed, .f = static_cast(value), .s = value, .u = static_cast(value)}; -} - -static bool is_matrix_index_attr(GXAttr attr) { - return attr >= GX_VA_PNMTXIDX && attr <= GX_VA_TEX7MTXIDX; -} - -static bool is_color_attr(GXAttr attr) { - return attr == GX_VA_CLR0 || attr == GX_VA_CLR1; -} - -static bool is_tex_attr(GXAttr attr) { - return attr >= GX_VA_TEX0 && attr <= GX_VA_TEX7; -} - -static GXAttrType active_attr_type(GXAttr attr) { - switch (attr) { - case GX_VA_PNMTXIDX: - case GX_VA_TEX0MTXIDX: - case GX_VA_TEX1MTXIDX: - case GX_VA_TEX2MTXIDX: - case GX_VA_TEX3MTXIDX: - case GX_VA_TEX4MTXIDX: - case GX_VA_TEX5MTXIDX: - case GX_VA_TEX6MTXIDX: - case GX_VA_TEX7MTXIDX: - return GET_REG_FIELD(__gx->vcdLo, 1, underlying(attr)) ? GX_DIRECT : GX_NONE; - case GX_VA_POS: - return static_cast(GET_REG_FIELD(__gx->vcdLo, 2, 9)); - case GX_VA_NRM: - return (__gx->hasNrms || __gx->hasBiNrms) ? static_cast(GET_REG_FIELD(__gx->vcdLo, 2, 11)) : GX_NONE; - case GX_VA_CLR0: - return static_cast(GET_REG_FIELD(__gx->vcdLo, 2, 13)); - case GX_VA_CLR1: - return static_cast(GET_REG_FIELD(__gx->vcdLo, 2, 15)); - case GX_VA_TEX0: - return static_cast(GET_REG_FIELD(__gx->vcdHi, 2, 0)); - case GX_VA_TEX1: - return static_cast(GET_REG_FIELD(__gx->vcdHi, 2, 2)); - case GX_VA_TEX2: - return static_cast(GET_REG_FIELD(__gx->vcdHi, 2, 4)); - case GX_VA_TEX3: - return static_cast(GET_REG_FIELD(__gx->vcdHi, 2, 6)); - case GX_VA_TEX4: - return static_cast(GET_REG_FIELD(__gx->vcdHi, 2, 8)); - case GX_VA_TEX5: - return static_cast(GET_REG_FIELD(__gx->vcdHi, 2, 10)); - case GX_VA_TEX6: - return static_cast(GET_REG_FIELD(__gx->vcdHi, 2, 12)); - case GX_VA_TEX7: - return static_cast(GET_REG_FIELD(__gx->vcdHi, 2, 14)); - default: - return GX_NONE; - } -} - -static ActiveAttrFmt active_attr_fmt(GXVtxFmt fmt, GXAttr attr) { - ActiveAttrFmt out{}; - const u32 va = __gx->vatA[fmt]; - const u32 vb = __gx->vatB[fmt]; - const u32 vc = __gx->vatC[fmt]; - - switch (attr) { - case GX_VA_POS: - out.cnt = GET_REG_FIELD(va, 1, 0) ? GX_POS_XYZ : GX_POS_XY; - out.type = static_cast(GET_REG_FIELD(va, 3, 1)); - out.frac = static_cast(GET_REG_FIELD(va, 5, 4)); - break; - case GX_VA_NRM: - out.type = static_cast(GET_REG_FIELD(va, 3, 10)); - if (GET_REG_FIELD(va, 1, 31)) { - out.cnt = GX_NRM_NBT3; - } else { - out.cnt = GET_REG_FIELD(va, 1, 9) ? GX_NRM_NBT : GX_NRM_XYZ; - } - out.frac = normal_frac_bits(out.type); - break; - case GX_VA_CLR0: - out.cnt = GET_REG_FIELD(va, 1, 13) ? GX_CLR_RGBA : GX_CLR_RGB; - out.type = static_cast(GET_REG_FIELD(va, 3, 14)); - out.frac = 0; - break; - case GX_VA_CLR1: - out.cnt = GET_REG_FIELD(va, 1, 17) ? GX_CLR_RGBA : GX_CLR_RGB; - out.type = static_cast(GET_REG_FIELD(va, 3, 18)); - out.frac = 0; - break; - case GX_VA_TEX0: - out.cnt = GET_REG_FIELD(va, 1, 21) ? GX_TEX_ST : GX_TEX_S; - out.type = static_cast(GET_REG_FIELD(va, 3, 22)); - out.frac = static_cast(GET_REG_FIELD(va, 5, 25)); - break; - case GX_VA_TEX1: - out.cnt = GET_REG_FIELD(vb, 1, 0) ? GX_TEX_ST : GX_TEX_S; - out.type = static_cast(GET_REG_FIELD(vb, 3, 1)); - out.frac = static_cast(GET_REG_FIELD(vb, 5, 4)); - break; - case GX_VA_TEX2: - out.cnt = GET_REG_FIELD(vb, 1, 9) ? GX_TEX_ST : GX_TEX_S; - out.type = static_cast(GET_REG_FIELD(vb, 3, 10)); - out.frac = static_cast(GET_REG_FIELD(vb, 5, 13)); - break; - case GX_VA_TEX3: - out.cnt = GET_REG_FIELD(vb, 1, 18) ? GX_TEX_ST : GX_TEX_S; - out.type = static_cast(GET_REG_FIELD(vb, 3, 19)); - out.frac = static_cast(GET_REG_FIELD(vb, 5, 22)); - break; - case GX_VA_TEX4: - out.cnt = GET_REG_FIELD(vb, 1, 27) ? GX_TEX_ST : GX_TEX_S; - out.type = static_cast(GET_REG_FIELD(vb, 3, 28)); - out.frac = static_cast(GET_REG_FIELD(vc, 5, 0)); - break; - case GX_VA_TEX5: - out.cnt = GET_REG_FIELD(vc, 1, 5) ? GX_TEX_ST : GX_TEX_S; - out.type = static_cast(GET_REG_FIELD(vc, 3, 6)); - out.frac = static_cast(GET_REG_FIELD(vc, 5, 9)); - break; - case GX_VA_TEX6: - out.cnt = GET_REG_FIELD(vc, 1, 14) ? GX_TEX_ST : GX_TEX_S; - out.type = static_cast(GET_REG_FIELD(vc, 3, 15)); - out.frac = static_cast(GET_REG_FIELD(vc, 5, 18)); - break; - case GX_VA_TEX7: - out.cnt = GET_REG_FIELD(vc, 1, 23) ? GX_TEX_ST : GX_TEX_S; - out.type = static_cast(GET_REG_FIELD(vc, 3, 24)); - out.frac = static_cast(GET_REG_FIELD(vc, 5, 27)); - break; - default: - break; - } - return out; -} - -static u32 expected_component_count(GXAttr attr, const ActiveAttrFmt& fmt, GXAttrType type) { - if (is_matrix_index_attr(attr) || is_color_attr(attr)) { - return 1; - } - if (type == GX_INDEX8 || type == GX_INDEX16) { - return (attr == GX_VA_NRM && fmt.cnt == GX_NRM_NBT3) ? 3u : 1u; - } - if (attr == GX_VA_POS) { - return fmt.cnt == GX_POS_XY ? 2u : 3u; - } - if (attr == GX_VA_NRM) { - return (fmt.cnt == GX_NRM_NBT || fmt.cnt == GX_NRM_NBT3) ? 9u : 3u; - } - if (is_tex_attr(attr)) { - return fmt.cnt == GX_TEX_S ? 1u : 2u; - } - return 1; -} - - // Cache decoded vertex settings and refresh them when their GX registers change. -struct AttrCacheEntry { - ActiveAttrFmt fmt{}; - GXAttrType type = GX_NONE; - u32 expected = 1; - GXAttr next = GX_VA_NULL; -}; - -struct VtxStateCache { - bool valid = false; - GXVtxFmt vtxFmt = GX_VTXFMT0; - u32 vcdLo = 0; - u32 vcdHi = 0; - u32 vatA = 0; - u32 vatB = 0; - u32 vatC = 0; - u8 hasNrms = 0; - u8 hasBiNrms = 0; - GXAttr first = GX_VA_NULL; - std::array attrs{}; -}; - -static VtxStateCache sVtxCache; - -static void rebuild_vtx_cache(GXVtxFmt vtxFmt) { - sVtxCache.valid = true; - sVtxCache.vtxFmt = vtxFmt; - sVtxCache.vcdLo = __gx->vcdLo; - sVtxCache.vcdHi = __gx->vcdHi; - sVtxCache.vatA = __gx->vatA[vtxFmt]; - sVtxCache.vatB = __gx->vatB[vtxFmt]; - sVtxCache.vatC = __gx->vatC[vtxFmt]; - sVtxCache.hasNrms = __gx->hasNrms; - sVtxCache.hasBiNrms = __gx->hasBiNrms; - - for (int i = 0; i < GX_VA_MAX_ATTR; ++i) { - const auto attr = static_cast(i); - AttrCacheEntry& entry = sVtxCache.attrs[i]; - entry.type = active_attr_type(attr); - entry.fmt = active_attr_fmt(vtxFmt, attr); - entry.expected = expected_component_count(attr, entry.fmt, entry.type); - entry.next = GX_VA_NULL; - } - - GXAttr running = GX_VA_NULL; - for (int i = GX_VA_TEX7; i >= GX_VA_PNMTXIDX; --i) { - sVtxCache.attrs[i].next = running; - if (sVtxCache.attrs[i].type != GX_NONE) { - running = static_cast(i); - } - } - sVtxCache.first = running; -} - -static inline void ensure_vtx_cache(GXVtxFmt vtxFmt) { - if (sVtxCache.valid && sVtxCache.vtxFmt == vtxFmt && sVtxCache.vcdLo == __gx->vcdLo && - sVtxCache.vcdHi == __gx->vcdHi && sVtxCache.vatA == __gx->vatA[vtxFmt] && - sVtxCache.vatB == __gx->vatB[vtxFmt] && sVtxCache.vatC == __gx->vatC[vtxFmt] && - sVtxCache.hasNrms == __gx->hasNrms && sVtxCache.hasBiNrms == __gx->hasBiNrms) { - return; - } - rebuild_vtx_cache(vtxFmt); -} - -static inline const AttrCacheEntry& attr_cache(GXAttr attr) { - static const AttrCacheEntry kDisabled{}; - const auto idx = static_cast(attr); - return idx < GX_VA_MAX_ATTR ? sVtxCache.attrs[idx] : kDisabled; -} - -static void reset_attr_writer() { - sWriteAttr = sVtxCache.first; - sWriteAttrComps = 0; -} - -static GXAttr select_implicit_attr(GXAttr first, GXAttr last) { - if (sInBegin && sWriteAttr >= first && sWriteAttr <= last && attr_cache(sWriteAttr).type != GX_NONE) { - return sWriteAttr; - } - if (sInBegin) { - for (int i = static_cast(sWriteAttr); i <= static_cast(last); ++i) { - const auto attr = static_cast(i); - if (attr >= first && attr_cache(attr).type != GX_NONE) { - sWriteAttr = attr; - sWriteAttrComps = 0; - return attr; - } - } - } - for (int i = static_cast(first); i <= static_cast(last); ++i) { - const auto attr = static_cast(i); - if (attr_cache(attr).type != GX_NONE) { - sWriteAttr = attr; - sWriteAttrComps = 0; - return attr; - } - } - return first; -} - -static void align_explicit_attr(GXAttr attr) { - if (!sInBegin || sWriteAttr == attr) { - return; - } - sWriteAttr = attr; - sWriteAttrComps = 0; -} - -static void advance_attr(GXAttr attr, u32 compsWritten) { - if (!sInBegin) { - return; - } - const AttrCacheEntry& entry = attr_cache(attr); - sWriteAttrComps += compsWritten; - if (sWriteAttrComps < entry.expected) { - return; - } - sWriteAttr = entry.next; - sWriteAttrComps = 0; - if (sWriteAttr == GX_VA_NULL) { - reset_attr_writer(); - } -} - -static int64_t encode_float_component(float value, bool isSigned, u8 bits, u8 frac) { - if (!std::isfinite(value)) { - value = 0.0f; - } - const double scaled = static_cast(value) * static_cast(uint64_t{1} << frac); - const double rounded = std::round(scaled); - if (isSigned) { - const int64_t minVal = -(int64_t{1} << (bits - 1)); - const int64_t maxVal = (int64_t{1} << (bits - 1)) - 1; - return std::clamp(static_cast(rounded), minVal, maxVal); - } - const int64_t maxVal = (int64_t{1} << bits) - 1; - return std::clamp(static_cast(rounded), int64_t{0}, maxVal); -} - -static int64_t scalar_to_signed_raw(const Scalar& value, u8 bits, u8 frac) { - if (value.kind == ScalarKind::Float) { - return encode_float_component(value.f, true, bits, frac); - } - const int64_t raw = value.kind == ScalarKind::Signed ? value.s : static_cast(value.u); - const int64_t minVal = -(int64_t{1} << (bits - 1)); - const int64_t maxVal = (int64_t{1} << (bits - 1)) - 1; - return std::clamp(raw, minVal, maxVal); -} - -static uint64_t scalar_to_unsigned_raw(const Scalar& value, u8 bits, u8 frac) { - if (value.kind == ScalarKind::Float) { - return static_cast(encode_float_component(value.f, false, bits, frac)); - } - const uint64_t raw = value.kind == ScalarKind::Signed ? static_cast(std::max(value.s, int32_t{0})) : value.u; - const uint64_t maxVal = (uint64_t{1} << bits) - 1; - return std::min(raw, maxVal); -} - -static float scalar_to_float(const Scalar& value) { - if (value.kind == ScalarKind::Float) { - return value.f; - } - if (value.kind == ScalarKind::Signed) { - return static_cast(value.s); - } - return static_cast(value.u); -} - -static void write_numeric_component(const ActiveAttrFmt& fmt, const Scalar& value) { - switch (fmt.type) { - case GX_U8: - GX_WRITE_U8(static_cast(scalar_to_unsigned_raw(value, 8, fmt.frac))); - break; - case GX_S8: - GX_WRITE_U8(static_cast(static_cast(scalar_to_signed_raw(value, 8, fmt.frac)))); - break; - case GX_U16: - GX_WRITE_U16(static_cast(scalar_to_unsigned_raw(value, 16, fmt.frac))); - break; - case GX_S16: - GX_WRITE_U16(static_cast(static_cast(scalar_to_signed_raw(value, 16, fmt.frac)))); - break; - case GX_F32: - default: - GX_WRITE_F32(scalar_to_float(value)); - break; - } -} - -template -static void write_numeric_attr(GXAttr attr, const std::array& values) { - ensure_vtx_cache(sBeginVtxFmt); - align_explicit_attr(attr); - const AttrCacheEntry& entry = attr_cache(attr); - if (entry.type == GX_NONE) { - return; - } - if (entry.type == GX_INDEX8 || entry.type == GX_INDEX16) { - return; - } - const u32 expected = entry.expected; - const u32 remaining = expected > sWriteAttrComps ? expected - sWriteAttrComps : expected; - const u32 count = std::min(static_cast(values.size()), remaining); - for (u32 i = 0; i < count; ++i) { - write_numeric_component(entry.fmt, values[i]); - } - advance_attr(attr, count); -} - -static u8 clamp_color_float(float value) { - if (!std::isfinite(value)) { - return 0; - } - return static_cast(std::clamp(std::round(value * 255.0f), 0.0f, 255.0f)); -} - -static u8 quantize_unorm(u8 value, u8 bits) { - const u32 maxValue = (1u << bits) - 1u; - return static_cast((static_cast(value) * maxValue + 127u) / 255u); -} - -static void write_color_attr(u8 r, u8 g, u8 b, u8 a) { - ensure_vtx_cache(sBeginVtxFmt); - const GXAttr attr = select_implicit_attr(GX_VA_CLR0, GX_VA_CLR1); - const AttrCacheEntry& entry = attr_cache(attr); - if (entry.type == GX_NONE) { - return; - } - if (entry.type == GX_INDEX8 || entry.type == GX_INDEX16) { - return; - } - - const ActiveAttrFmt& fmt = entry.fmt; - switch (fmt.type) { - case GX_RGB565: { - const u16 packed = static_cast((quantize_unorm(r, 5) << 11) | (quantize_unorm(g, 6) << 5) | - quantize_unorm(b, 5)); - GX_WRITE_U16(packed); - break; - } - case GX_RGB8: - GX_WRITE_U8(r); - GX_WRITE_U8(g); - GX_WRITE_U8(b); - break; - case GX_RGBX8: - GX_WRITE_U8(r); - GX_WRITE_U8(g); - GX_WRITE_U8(b); - GX_WRITE_U8(0xFF); - break; - case GX_RGBA4: { - const u16 packed = static_cast((quantize_unorm(r, 4) << 12) | (quantize_unorm(g, 4) << 8) | - (quantize_unorm(b, 4) << 4) | quantize_unorm(a, 4)); - GX_WRITE_U16(packed); - break; - } - case GX_RGBA6: { - const u32 packed = (quantize_unorm(r, 6) << 18) | (quantize_unorm(g, 6) << 12) | - (quantize_unorm(b, 6) << 6) | quantize_unorm(a, 6); - GX_WRITE_U8(static_cast((packed >> 16) & 0xFF)); - GX_WRITE_U8(static_cast((packed >> 8) & 0xFF)); - GX_WRITE_U8(static_cast(packed & 0xFF)); - break; - } - case GX_RGBA8: - default: - GX_WRITE_U8(r); - GX_WRITE_U8(g); - GX_WRITE_U8(b); - GX_WRITE_U8(a); - break; - } - advance_attr(attr, 1); -} - -template -static void write_tex_attr(const std::array& values) { - ensure_vtx_cache(sBeginVtxFmt); - const GXAttr attr = select_implicit_attr(GX_VA_TEX0, GX_VA_TEX7); - write_numeric_attr(attr, values); -} - -static void write_index_attr(GXAttr attr, u16 index, bool index16) { - ensure_vtx_cache(sBeginVtxFmt); - if (attr == GX_VA_TEX0) { - attr = select_implicit_attr(GX_VA_TEX0, GX_VA_TEX7); - } else if (attr == GX_VA_CLR0) { - attr = select_implicit_attr(GX_VA_CLR0, GX_VA_CLR1); - } else { - align_explicit_attr(attr); - } - - const GXAttrType type = attr_cache(attr).type; - if (type == GX_INDEX16 || (type != GX_INDEX8 && index16)) { - GX_WRITE_U16(index); - } else { - GX_WRITE_U8(static_cast(index)); - } - advance_attr(attr, 1); -} - -} // namespace - -extern "C" { - -void GXBegin(GXPrimitive primitive, GXVtxFmt vtxFmt, u16 nVerts) { - CHECK(!sInBegin, "GXBegin: called without matching GXEnd"); - - // Flush dirty state before starting a draw - if (__gx->dirtyState != 0) { - __GXSetDirtyState(); - } - - // Flush pending primitives if needed - if (*reinterpret_cast(&__gx->vNum) != 0) { - __GXSendFlushPrim(); - } - - GX_WRITE_U8(vtxFmt | primitive); - GX_WRITE_U16(nVerts); - - // Record state for vertex count validation in GXEnd - sBeginNVerts = nVerts; - sBeginFifoSize = aurora::gx::fifo::get_buffer_size(); - sBeginPrimitive = primitive; - sBeginVtxFmt = vtxFmt; - sInBegin = true; - ensure_vtx_cache(vtxFmt); - reset_attr_writer(); -} - -void GXEnd() { - if (sInBegin) { - u32 bytesWritten = aurora::gx::fifo::get_buffer_size() - sBeginFifoSize; - if (sBeginNVerts > 0 && bytesWritten > 0) { - u32 vtxSize = bytesWritten / sBeginNVerts; - u32 remainder = bytesWritten % sBeginNVerts; - if (remainder != 0) { - Log.warn("GXEnd: vertex data not evenly divisible: {} bytes for {} vertices prim={} fmt={} " - "vcdLo=0x{:08x} vcdHi=0x{:08x} vatA=0x{:08x} vatB=0x{:08x} vatC=0x{:08x}", - bytesWritten, sBeginNVerts, underlying(sBeginPrimitive), underlying(sBeginVtxFmt), - __gx->vcdLo, __gx->vcdHi, __gx->vatA[sBeginVtxFmt], __gx->vatB[sBeginVtxFmt], - __gx->vatC[sBeginVtxFmt]); - } - u32 actualVerts = (vtxSize > 0) ? bytesWritten / vtxSize : 0; - CHECK(actualVerts == sBeginNVerts, - "GXEnd: vertex count mismatch: GXBegin declared {} vertices ({}B each, {}B total) " - "but {} bytes were written ({} vertices)", - sBeginNVerts, vtxSize, sBeginNVerts * vtxSize, bytesWritten, actualVerts); - } - sInBegin = false; - sWriteAttr = GX_VA_NULL; - sWriteAttrComps = 0; - } - if (!aurora::gx::fifo::in_display_list()) { - aurora::gx::fifo::drain(); - } -} - -void GXPosition3f32(f32 x, f32 y, f32 z) { - write_numeric_attr(GX_VA_POS, std::array{scalar_f32(x), scalar_f32(y), scalar_f32(z)}); -} - -void GXPosition3u16(u16 x, u16 y, u16 z) { - write_numeric_attr(GX_VA_POS, std::array{scalar_u32(x), scalar_u32(y), scalar_u32(z)}); -} - -void GXPosition3s16(s16 x, s16 y, s16 z) { - write_numeric_attr(GX_VA_POS, std::array{scalar_s32(x), scalar_s32(y), scalar_s32(z)}); -} - -void GXPosition3u8(u8 x, u8 y, u8 z) { - write_numeric_attr(GX_VA_POS, std::array{scalar_u32(x), scalar_u32(y), scalar_u32(z)}); -} - -void GXPosition3s8(s8 x, s8 y, s8 z) { - write_numeric_attr(GX_VA_POS, std::array{scalar_s32(x), scalar_s32(y), scalar_s32(z)}); -} - -void GXPosition2f32(f32 x, f32 y) { - write_numeric_attr(GX_VA_POS, std::array{scalar_f32(x), scalar_f32(y)}); -} - -void GXPosition2u16(u16 x, u16 y) { - write_numeric_attr(GX_VA_POS, std::array{scalar_u32(x), scalar_u32(y)}); -} - -void GXPosition2s16(s16 x, s16 y) { - write_numeric_attr(GX_VA_POS, std::array{scalar_s32(x), scalar_s32(y)}); -} - -void GXPosition2u8(u8 x, u8 y) { - write_numeric_attr(GX_VA_POS, std::array{scalar_u32(x), scalar_u32(y)}); -} - -void GXPosition2s8(s8 x, s8 y) { - write_numeric_attr(GX_VA_POS, std::array{scalar_s32(x), scalar_s32(y)}); -} - -void GXPosition1x16(u16 idx) { write_index_attr(GX_VA_POS, idx, true); } - -void GXPosition1x8(u8 idx) { write_index_attr(GX_VA_POS, idx, false); } - -void GXNormal3f32(f32 x, f32 y, f32 z) { - write_numeric_attr(GX_VA_NRM, std::array{scalar_f32(x), scalar_f32(y), scalar_f32(z)}); -} - -void GXNormal3u16(u16 x, u16 y, u16 z) { - write_numeric_attr(GX_VA_NRM, std::array{scalar_u32(x), scalar_u32(y), scalar_u32(z)}); -} - -void GXNormal3s16(s16 x, s16 y, s16 z) { - write_numeric_attr(GX_VA_NRM, std::array{scalar_s32(x), scalar_s32(y), scalar_s32(z)}); -} - -void GXNormal3u8(u8 x, u8 y, u8 z) { - write_numeric_attr(GX_VA_NRM, std::array{scalar_u32(x), scalar_u32(y), scalar_u32(z)}); -} - -void GXNormal3s8(s8 x, s8 y, s8 z) { - write_numeric_attr(GX_VA_NRM, std::array{scalar_s32(x), scalar_s32(y), scalar_s32(z)}); -} - -void GXNormal1x16(u16 index) { write_index_attr(GX_VA_NRM, index, true); } - -void GXNormal1x8(u8 index) { write_index_attr(GX_VA_NRM, index, false); } - -void GXColor4f32(f32 r, f32 g, f32 b, f32 a) { - write_color_attr(clamp_color_float(r), clamp_color_float(g), clamp_color_float(b), clamp_color_float(a)); -} - -void GXColor4u8(u8 r, u8 g, u8 b, u8 a) { - write_color_attr(r, g, b, a); -} - -void GXColor3u8(u8 r, u8 g, u8 b) { - write_color_attr(r, g, b, 0xFF); -} - -void GXColor1u32(u32 clr) { - write_color_attr(static_cast((clr >> 24) & 0xFF), static_cast((clr >> 16) & 0xFF), - static_cast((clr >> 8) & 0xFF), static_cast(clr & 0xFF)); -} - -void GXColor1u16(u16 clr) { - const u8 r = static_cast(((clr >> 11) & 0x1F) * 255 / 31); - const u8 g = static_cast(((clr >> 5) & 0x3F) * 255 / 63); - const u8 b = static_cast((clr & 0x1F) * 255 / 31); - write_color_attr(r, g, b, 0xFF); -} - -void GXColor1x16(u16 index) { write_index_attr(GX_VA_CLR0, index, true); } - -void GXColor1x8(u8 index) { write_index_attr(GX_VA_CLR0, index, false); } - -void GXTexCoord2f32(f32 s, f32 t) { - write_tex_attr(std::array{scalar_f32(s), scalar_f32(t)}); -} - -void GXTexCoord2u16(u16 s, u16 t) { - write_tex_attr(std::array{scalar_u32(s), scalar_u32(t)}); -} - -void GXTexCoord2s16(s16 s, s16 t) { - write_tex_attr(std::array{scalar_s32(s), scalar_s32(t)}); -} - -void GXTexCoord2u8(u8 s, u8 t) { - write_tex_attr(std::array{scalar_u32(s), scalar_u32(t)}); -} - -void GXTexCoord2s8(s8 s, s8 t) { - write_tex_attr(std::array{scalar_s32(s), scalar_s32(t)}); -} - -void GXTexCoord1f32(f32 s) { write_tex_attr(std::array{scalar_f32(s)}); } - -void GXTexCoord1u16(u16 s) { write_tex_attr(std::array{scalar_u32(s)}); } - -void GXTexCoord1s16(s16 s) { write_tex_attr(std::array{scalar_s32(s)}); } - -void GXTexCoord1u8(u8 s) { write_tex_attr(std::array{scalar_u32(s)}); } - -void GXTexCoord1s8(s8 s) { write_tex_attr(std::array{scalar_s32(s)}); } - -void GXTexCoord1x16(u16 index) { write_index_attr(GX_VA_TEX0, index, true); } - -void GXTexCoord1x8(u8 index) { write_index_attr(GX_VA_TEX0, index, false); } - -void GXMatrixIndex1u8(GXAttr attr, u8 index) { write_index_attr(attr, index, false); } - -void GXCmd1u8(const u8 x) { aurora::gx::fifo::write_u8(x); } -void GXCmd1u16(const u16 x) { aurora::gx::fifo::write_u16(x); } -void GXCmd1u32(const u32 x) { aurora::gx::fifo::write_u32(x); } -void GXCmd1u64(const u64 x) { aurora::gx::fifo::write_u64(x); } - -void GXParam1u8(const u8 x) { aurora::gx::fifo::write_u8(x); } -void GXParam1u16(const u16 x) { aurora::gx::fifo::write_u16(x); } -void GXParam1u32(const u32 x) { aurora::gx::fifo::write_u32(x); } -void GXParam1s8(const s8 x) { aurora::gx::fifo::write_u8(static_cast(x)); } -void GXParam1s16(const s16 x) { aurora::gx::fifo::write_u16(static_cast(x)); } -void GXParam1s32(const s32 x) { aurora::gx::fifo::write_u32(static_cast(x)); } -void GXParam1f32(const f32 x) { aurora::gx::fifo::write_f32(x); } -void GXParam3f32(const f32 x, const f32 y, const f32 z) { - aurora::gx::fifo::write_f32(x); - aurora::gx::fifo::write_f32(y); - aurora::gx::fifo::write_f32(z); -} -void GXParam4f32(const f32 x, const f32 y, const f32 z, const f32 w) { - aurora::gx::fifo::write_f32(x); - aurora::gx::fifo::write_f32(y); - aurora::gx::fifo::write_f32(z); - aurora::gx::fifo::write_f32(w); -} - -} // extern "C" diff --git a/aurora-main/lib/dolphin/gx/__gx.h b/aurora-main/lib/dolphin/gx/__gx.h deleted file mode 100644 index 460791e..0000000 --- a/aurora-main/lib/dolphin/gx/__gx.h +++ /dev/null @@ -1,179 +0,0 @@ -#pragma once - -#include - -#include "../../gx/fifo.hpp" - -#define GX_WRITE_U8(ub) aurora::gx::fifo::write_u8(static_cast(ub)) -#define GX_WRITE_DATA(data, length) aurora::gx::fifo::write_data(data, length) -#define GX_WRITE_U16(us) aurora::gx::fifo::write_u16(static_cast(us)) -#define GX_WRITE_U32(ui) aurora::gx::fifo::write_u32(static_cast(ui)) -#define GX_WRITE_U64(ui) aurora::gx::fifo::write_u64(static_cast(ui)) -#define GX_WRITE_F32(f) aurora::gx::fifo::write_f32(static_cast(f)) - -// XF register write: opcode 0x10, address in XF space (0x1000+addr), then value -#define GX_WRITE_XF_REG(addr, value) \ - do { \ - GX_WRITE_U8(0x10); \ - GX_WRITE_U32(0x1000 + (addr)); \ - GX_WRITE_U32(value); \ - } while (0) - -// XF register write for u32 data (no address header - used in bulk writes) -#define GX_WRITE_XF_REG_2(addr, value) \ - do { \ - GX_WRITE_U32(value); \ - } while (0) - -// XF register write for f32 data (no address header - used in bulk writes) -#define GX_WRITE_XF_REG_F(addr, value) \ - do { \ - GX_WRITE_F32(value); \ - } while (0) - -// BP (RAS) register write: opcode 0x61, then 32-bit value (upper 8 bits = reg ID) -#define GX_WRITE_RAS_REG(value) \ - do { \ - GX_WRITE_U8(0x61); \ - GX_WRITE_U32(value); \ - } while (0) - -// CP register write with base/stride tracking for indexed arrays -// GX_WRITE_SOME_REG2: CP array base address -#define GX_WRITE_SOME_REG2(a, b, c, addr) \ - do { \ - GX_WRITE_U8(a); \ - GX_WRITE_U8(b); \ - GX_WRITE_U32(c); \ - } while (0) - -// GX_WRITE_SOME_REG3: CP array stride -#define GX_WRITE_SOME_REG3(a, b, c, addr) \ - do { \ - GX_WRITE_U8(a); \ - GX_WRITE_U8(b); \ - GX_WRITE_U32(c); \ - } while (0) - -// GX_WRITE_SOME_REG4: generic CP register write (VCD, VAT, matrix index) -#define GX_WRITE_SOME_REG4(a, b, c, addr) \ - do { \ - GX_WRITE_U8(a); \ - GX_WRITE_U8(b); \ - GX_WRITE_U32(c); \ - } while (0) - -#define GET_REG_FIELD(reg, size, shift) (static_cast(((reg) >> (shift)) & ((1 << (size)) - 1))) - -#define SET_REG_FIELD(line, reg, size, shift, val) \ - do { \ - (reg) = ((u32)(reg) & ~(((1u << (size)) - 1) << (shift))) | ((u32)(val) << (shift)); \ - } while (0) - -#define GX_WRITE_AURORA(cmd) \ - do { \ - GX_WRITE_U8(GX_LOAD_AURORA); \ - GX_WRITE_U16(cmd); \ - } while (0) - -#define GX_WRITE_CP_REG(addr, value) \ - do { \ - GX_WRITE_U8(GX_LOAD_CP_REG); \ - GX_WRITE_U8(addr); \ - GX_WRITE_U32(value); \ - } while (0) - -// This shadow register struct contains the GX state Aurora needs on PC. -struct __GXData_struct { - u16 vNum; // vertex count for flush prim - u16 bpSent; // BP register was sent (need flush prim before next draw) - u32 vLim; // vertex data size limit (bytes per vertex for flush prim) - - u32 vcdLo; // vertex component descriptor low - u32 vcdHi; // vertex component descriptor high - - u32 vatA[8]; // vertex attribute table A (per vtxfmt) - u32 vatB[8]; // vertex attribute table B - u32 vatC[8]; // vertex attribute table C - - u32 lpSize; // line/point size register - - u32 matIdxA; // matrix index A (pnmtx + texmtx 0-3) - u32 matIdxB; // matrix index B (texmtx 4-7) - - u32 ambColor[2]; // ambient colors (XF registers) - u32 matColor[2]; // material colors (XF registers) - - u32 suTs0[8]; // SU texture S0 registers - u32 suTs1[8]; // SU texture S1 registers - u8 tcsManEnab; // bitmask: manual tex coord scale enabled per coord - u32 suScis0; // scissor top-left - u32 suScis1; // scissor bottom-right - - u32 tref[8]; // TEV texture/color reference (2 stages per register) - u32 iref; // indirect texture reference - u32 bpMask; // BP mask register - - u32 IndTexScale0; // indirect texture scale 0 (stages 0-1) - u32 IndTexScale1; // indirect texture scale 1 (stages 2-3) - - u32 tevc[16]; // TEV color combiner registers - u32 teva[16]; // TEV alpha combiner registers - u32 tevKsel[8]; // TEV K color/alpha selection - - u32 cmode0; // blend mode register - u32 cmode1; // destination alpha register - u32 zmode; // Z-buffer mode register - u32 peCtrl; // pixel engine control - - u32 genMode; // general mode (numTexGens, numChans, numTevStages, cullMode, numIndStages) - - u32 tImage0[8]; // texture image 0 registers - u32 tMode0[8]; // texture mode 0 registers - u32 texmapId[16]; // texture map ID tracking - u32 texmapValid; // bitmask of TEV stages with a valid texture coordinate - - GXAttrType nrmType; // normal attribute type - u8 hasNrms; // has normal vectors - u8 hasBiNrms; // has binormal vectors - - u32 projType; // projection type (perspective/orthographic) - f32 projMtx[6]; // projection matrix (6 params) - - f32 vpLeft; // viewport left - f32 vpTop; // viewport top - f32 vpWd; // viewport width - f32 vpHt; // viewport height - f32 vpNearz; // viewport near Z - f32 vpFarz; // viewport far Z - - u8 fgRange; // fog range adjustment enabled - f32 fgSideX; // fog range side X - - u8 inDispList; // currently recording a display list - u8 dlSaveContext; // save/restore context around display lists - u8 dirtyVAT; // bitmask of dirty VAT entries - - u32 dirtyState; // dirty state flags: - // bit 0: SU tex regs - // bit 1: BP mask - // bit 2: gen mode - // bit 3: VCD - // bit 4: VAT -}; - -extern __GXData_struct* __gx; - -extern "C" { - -// Dirty state flush functions -void __GXSetVCD(); -void __GXSetVAT(); -void __GXUpdateBPMask(); -void __GXSetSUTexRegs(); -void __GXSetDirtyState(); -void __GXSetGenMode(); -void __GXSetMatrixIndex(GXAttr matIdxAttr); -void __GXSendFlushPrim(); -void __GXFlushTextureState(); -}; diff --git a/aurora-main/lib/dolphin/gx/gx.hpp b/aurora-main/lib/dolphin/gx/gx.hpp deleted file mode 100644 index 0319df0..0000000 --- a/aurora-main/lib/dolphin/gx/gx.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "../../internal.hpp" -#include "../../gx/gx.hpp" - -// Defined once in GXAurora.cpp. The FATAL/CHECK/TRY macros resolve `Log` unqualified, so it stays -// at global scope like the rest of this header's using-declarations. -extern aurora::Module Log; - -using aurora::gx::g_gxState; diff --git a/aurora-main/lib/dolphin/ms/mouse.cpp b/aurora-main/lib/dolphin/ms/mouse.cpp deleted file mode 100644 index a5b95f7..0000000 --- a/aurora-main/lib/dolphin/ms/mouse.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "dolphin/ms.h" -#include - -#include "../../input.hpp" - -extern "C" { -static MSStatus gStatus{}; - -void MSPoll() { - const uint32_t buttons = SDL_GetGlobalMouseState(&gStatus.x, &gStatus.y); - SDL_GetRelativeMouseState(&gStatus.xrel, &gStatus.yrel); - aurora::input::get_mouse_scroll(&gStatus.scrollX, &gStatus.scrollY); - - gStatus.buttons = 0; - if (buttons & SDL_BUTTON_LEFT) { - gStatus.buttons |= MS_BUTTON_LEFT; - } - if (buttons & SDL_BUTTON_MIDDLE) { - gStatus.buttons |= MS_BUTTON_MIDDLE; - } - if (buttons & SDL_BUTTON_RIGHT) { - gStatus.buttons |= MS_BUTTON_RIGHT; - } - if (buttons & SDL_BUTTON_X1) { - gStatus.buttons |= MS_BUTTON_X1; - } - if (buttons & SDL_BUTTON_X2) { - gStatus.buttons |= MS_BUTTON_X2; - } -} - -void MSRead(MSStatus* status) { *status = gStatus; } -} \ No newline at end of file diff --git a/aurora-main/lib/dolphin/mtx/mtx.c b/aurora-main/lib/dolphin/mtx/mtx.c deleted file mode 100644 index ba2796d..0000000 --- a/aurora-main/lib/dolphin/mtx/mtx.c +++ /dev/null @@ -1,618 +0,0 @@ -#include - -#include -#include - -void C_MTXIdentity(Mtx m) { - assert(m && "MtxIdentity(): NULL Mtx 'm' "); - m[0][0] = 1; - m[0][1] = 0; - m[0][2] = 0; - m[0][3] = 0; - m[1][0] = 0; - m[1][1] = 1; - m[1][2] = 0; - m[1][3] = 0; - m[2][0] = 0; - m[2][1] = 0; - m[2][2] = 1; - m[2][3] = 0; -} - -void C_MTXCopy(const Mtx src, Mtx dst) { - assert(src && "MTXCopy(): NULL MtxPtr 'src' "); - assert(dst && "MTXCopy(): NULL MtxPtr 'dst' "); - if (src != dst) { - dst[0][0] = src[0][0]; - dst[0][1] = src[0][1]; - dst[0][2] = src[0][2]; - dst[0][3] = src[0][3]; - dst[1][0] = src[1][0]; - dst[1][1] = src[1][1]; - dst[1][2] = src[1][2]; - dst[1][3] = src[1][3]; - dst[2][0] = src[2][0]; - dst[2][1] = src[2][1]; - dst[2][2] = src[2][2]; - dst[2][3] = src[2][3]; - } -} - -void C_MTXConcat(const Mtx a, const Mtx b, Mtx ab) { - Mtx mTmp; - MtxPtr m; - - assert(a && "MTXConcat(): NULL MtxPtr 'a' "); - assert(b && "MTXConcat(): NULL MtxPtr 'b' "); - assert(ab && "MTXConcat(): NULL MtxPtr 'ab' "); - - if (ab == a || ab == b) { - m = mTmp; - } else { - m = ab; - } - - m[0][0] = 0 + a[0][2] * b[2][0] + ((a[0][0] * b[0][0]) + (a[0][1] * b[1][0])); - m[0][1] = 0 + a[0][2] * b[2][1] + ((a[0][0] * b[0][1]) + (a[0][1] * b[1][1])); - m[0][2] = 0 + a[0][2] * b[2][2] + ((a[0][0] * b[0][2]) + (a[0][1] * b[1][2])); - m[0][3] = a[0][3] + (a[0][2] * b[2][3] + (a[0][0] * b[0][3] + (a[0][1] * b[1][3]))); - - m[1][0] = 0 + a[1][2] * b[2][0] + ((a[1][0] * b[0][0]) + (a[1][1] * b[1][0])); - m[1][1] = 0 + a[1][2] * b[2][1] + ((a[1][0] * b[0][1]) + (a[1][1] * b[1][1])); - m[1][2] = 0 + a[1][2] * b[2][2] + ((a[1][0] * b[0][2]) + (a[1][1] * b[1][2])); - m[1][3] = a[1][3] + (a[1][2] * b[2][3] + (a[1][0] * b[0][3] + (a[1][1] * b[1][3]))); - - m[2][0] = 0 + a[2][2] * b[2][0] + ((a[2][0] * b[0][0]) + (a[2][1] * b[1][0])); - m[2][1] = 0 + a[2][2] * b[2][1] + ((a[2][0] * b[0][1]) + (a[2][1] * b[1][1])); - m[2][2] = 0 + a[2][2] * b[2][2] + ((a[2][0] * b[0][2]) + (a[2][1] * b[1][2])); - m[2][3] = a[2][3] + (a[2][2] * b[2][3] + (a[2][0] * b[0][3] + (a[2][1] * b[1][3]))); - - if (m == mTmp) { - C_MTXCopy(mTmp, ab); - } -} - -void C_MTXConcatArray(const Mtx a, const Mtx* srcBase, Mtx* dstBase, u32 count) { - u32 i; - - assert(a != 0 && "MTXConcatArray(): NULL MtxPtr 'a' "); - assert(srcBase != 0 && "MTXConcatArray(): NULL MtxPtr 'srcBase' "); - assert(dstBase != 0 && "MTXConcatArray(): NULL MtxPtr 'dstBase' "); - assert(count > 1 && "MTXConcatArray(): count must be greater than 1."); - - for (i = 0; i < count; i++) { - C_MTXConcat(a, *srcBase, *dstBase); - srcBase++; - dstBase++; - } -} - -void C_MTXTranspose(const Mtx src, Mtx xPose) { - Mtx mTmp; - MtxPtr m; - - assert(src && "MTXTranspose(): NULL MtxPtr 'src' "); - assert(xPose && "MTXTranspose(): NULL MtxPtr 'xPose' "); - - if (src == xPose) { - m = mTmp; - } else { - m = xPose; - } - - m[0][0] = src[0][0]; - m[0][1] = src[1][0]; - m[0][2] = src[2][0]; - m[0][3] = 0; - m[1][0] = src[0][1]; - m[1][1] = src[1][1]; - m[1][2] = src[2][1]; - m[1][3] = 0; - m[2][0] = src[0][2]; - m[2][1] = src[1][2]; - m[2][2] = src[2][2]; - m[2][3] = 0; - if (m == mTmp) { - C_MTXCopy(mTmp, xPose); - } -} - -u32 C_MTXInverse(const Mtx src, Mtx inv) { - Mtx mTmp; - MtxPtr m; - f32 det; - - assert(src && "MTXInverse(): NULL MtxPtr 'src' "); - assert(inv && "MTXInverse(): NULL MtxPtr 'inv' "); - - if (src == inv) { - m = mTmp; - } else { - m = inv; - } - det = ((((src[2][1] * (src[0][2] * src[1][0])) - + ((src[2][2] * (src[0][0] * src[1][1])) - + (src[2][0] * (src[0][1] * src[1][2])))) - - (src[0][2] * (src[2][0] * src[1][1]))) - - (src[2][2] * (src[1][0] * src[0][1]))) - - (src[1][2] * (src[0][0] * src[2][1])); - if (0 == det) { - return 0; - } - det = 1 / det; - m[0][0] = (det * +((src[1][1] * src[2][2]) - (src[2][1] * src[1][2]))); - m[0][1] = (det * -((src[0][1] * src[2][2]) - (src[2][1] * src[0][2]))); - m[0][2] = (det * +((src[0][1] * src[1][2]) - (src[1][1] * src[0][2]))); - - m[1][0] = (det * -((src[1][0] * src[2][2]) - (src[2][0] * src[1][2]))); - m[1][1] = (det * +((src[0][0] * src[2][2]) - (src[2][0] * src[0][2]))); - m[1][2] = (det * -((src[0][0] * src[1][2]) - (src[1][0] * src[0][2]))); - - m[2][0] = (det * +((src[1][0] * src[2][1]) - (src[2][0] * src[1][1]))); - m[2][1] = (det * -((src[0][0] * src[2][1]) - (src[2][0] * src[0][1]))); - m[2][2] = (det * +((src[0][0] * src[1][1]) - (src[1][0] * src[0][1]))); - - m[0][3] = ((-m[0][0] * src[0][3]) - (m[0][1] * src[1][3])) - (m[0][2] * src[2][3]); - m[1][3] = ((-m[1][0] * src[0][3]) - (m[1][1] * src[1][3])) - (m[1][2] * src[2][3]); - m[2][3] = ((-m[2][0] * src[0][3]) - (m[2][1] * src[1][3])) - (m[2][2] * src[2][3]); - - if (m == mTmp) { - C_MTXCopy(mTmp, inv); - } - return 1; -} - -u32 C_MTXInvXpose(const Mtx src, Mtx invX) { - Mtx mTmp; - MtxPtr m; - f32 det; - - assert(src && "MTXInvXpose(): NULL MtxPtr 'src' "); - assert(invX && "MTXInvXpose(): NULL MtxPtr 'invX' "); - - if (src == invX) { - m = mTmp; - } else { - m = invX; - } - det = ((((src[2][1] * (src[0][2] * src[1][0])) - + ((src[2][2] * (src[0][0] * src[1][1])) - + (src[2][0] * (src[0][1] * src[1][2])))) - - (src[0][2] * (src[2][0] * src[1][1]))) - - (src[2][2] * (src[1][0] * src[0][1]))) - - (src[1][2] * (src[0][0] * src[2][1])); - if (0 == det) { - return 0; - } - det = 1 / det; - m[0][0] = (det * +((src[1][1] * src[2][2]) - (src[2][1] * src[1][2]))); - m[0][1] = (det * -((src[1][0] * src[2][2]) - (src[2][0] * src[1][2]))); - m[0][2] = (det * +((src[1][0] * src[2][1]) - (src[2][0] * src[1][1]))); - - m[1][0] = (det * -((src[0][1] * src[2][2]) - (src[2][1] * src[0][2]))); - m[1][1] = (det * +((src[0][0] * src[2][2]) - (src[2][0] * src[0][2]))); - m[1][2] = (det * -((src[0][0] * src[2][1]) - (src[2][0] * src[0][1]))); - - m[2][0] = (det * +((src[0][1] * src[1][2]) - (src[1][1] * src[0][2]))); - m[2][1] = (det * -((src[0][0] * src[1][2]) - (src[1][0] * src[0][2]))); - m[2][2] = (det * +((src[0][0] * src[1][1]) - (src[1][0] * src[0][1]))); - - m[0][3] = 0; - m[1][3] = 0; - m[2][3] = 0; - - if (m == mTmp) { - C_MTXCopy(mTmp, invX); - } - return 1; -} - -void C_MTXTrans(Mtx m, f32 xT, f32 yT, f32 zT) { - assert(m && "MTXTrans(): NULL MtxPtr 'm' "); - m[0][0] = 1; - m[0][1] = 0; - m[0][2] = 0; - m[0][3] = xT; - m[1][0] = 0; - m[1][1] = 1; - m[1][2] = 0; - m[1][3] = yT; - m[2][0] = 0; - m[2][1] = 0; - m[2][2] = 1; - m[2][3] = zT; -} - -void C_MTXFrustum(Mtx44 m, f32 t, f32 b, f32 l, f32 r, f32 n, f32 f) { - f32 tmp; - - assert(m && "MTXFrustum(): NULL Mtx44Ptr 'm' "); - assert(t != b && "MTXFrustum(): 't' and 'b' clipping planes are equal "); - assert(l != r && "MTXFrustum(): 'l' and 'r' clipping planes are equal "); - assert(n != f && "MTXFrustum(): 'n' and 'f' clipping planes are equal "); - tmp = 1 / (r - l); - m[0][0] = (2 * n * tmp); - m[0][1] = 0; - m[0][2] = (tmp * (r + l)); - m[0][3] = 0; - tmp = 1 / (t - b); - m[1][0] = 0; - m[1][1] = (2 * n * tmp); - m[1][2] = (tmp * (t + b)); - m[1][3] = 0; - m[2][0] = 0; - m[2][1] = 0; - tmp = 1 / (f - n); - m[2][2] = (-n * tmp); - m[2][3] = (tmp * -(f * n)); - m[3][0] = 0; - m[3][1] = 0; - m[3][2] = -1; - m[3][3] = 0; -} - -void C_MTXOrtho(Mtx44 m, f32 t, f32 b, f32 l, f32 r, f32 n, f32 f) { - f32 tmp; - - assert(m && "MTXOrtho(): NULL Mtx44Ptr 'm' "); - assert(t != b && "MTXOrtho(): 't' and 'b' clipping planes are equal "); - assert(l != r && "MTXOrtho(): 'l' and 'r' clipping planes are equal "); - assert(n != f && "MTXOrtho(): 'n' and 'f' clipping planes are equal "); - tmp = 1 / (r - l); - m[0][0] = 2 * tmp; - m[0][1] = 0; - m[0][2] = 0; - m[0][3] = (tmp * -(r + l)); - tmp = 1 / (t - b); - m[1][0] = 0; - m[1][1] = 2 * tmp; - m[1][2] = 0; - m[1][3] = (tmp * -(t + b)); - m[2][0] = 0; - m[2][1] = 0; - tmp = 1 / (f - n); - m[2][2] = (-1 * tmp); - m[2][3] = (-f * tmp); - m[3][0] = 0; - m[3][1] = 0; - m[3][2] = 0; - m[3][3] = 1; -} - -void C_MTXQuat(Mtx m, const Quaternion* q) { - f32 s; - f32 xs; - f32 ys; - f32 zs; - f32 wx; - f32 wy; - f32 wz; - f32 xx; - f32 xy; - f32 xz; - f32 yy; - f32 yz; - f32 zz; - - assert(m && "MTXQuat(): NULL MtxPtr 'm' "); - assert(q && "MTXQuat(): NULL QuaternionPtr 'q' "); - assert(q->x || q->y || q->z || q->w && "MTXQuat(): zero-value quaternion "); - s = 2 / ((q->w * q->w) + ((q->z * q->z) + ((q->x * q->x) + (q->y * q->y)))); - xs = q->x * s; - ys = q->y * s; - zs = q->z * s; - wx = q->w * xs; - wy = q->w * ys; - wz = q->w * zs; - xx = q->x * xs; - xy = q->x * ys; - xz = q->x * zs; - yy = q->y * ys; - yz = q->y * zs; - zz = q->z * zs; - m[0][0] = (1 - (yy + zz)); - m[0][1] = (xy - wz); - m[0][2] = (xz + wy); - m[0][3] = 0; - m[1][0] = (xy + wz); - m[1][1] = (1 - (xx + zz)); - m[1][2] = (yz - wx); - m[1][3] = 0; - m[2][0] = (xz - wy); - m[2][1] = (yz + wx); - m[2][2] = (1 - (xx + yy)); - m[2][3] = 0; -} - -void C_MTXReflect(Mtx m, const Vec* p, const Vec* n) { - f32 vxy; - f32 vxz; - f32 vyz; - f32 pdotn; - - vxy = -2 * n->x * n->y; - vxz = -2 * n->x * n->z; - vyz = -2 * n->y * n->z; - pdotn = 2 * C_VECDotProduct(p, n); - m[0][0] = (1 - (2 * n->x * n->x)); - m[0][1] = vxy; - m[0][2] = vxz; - m[0][3] = (pdotn * n->x); - m[1][0] = vxy; - m[1][1] = (1 - (2 * n->y * n->y)); - m[1][2] = vyz; - m[1][3] = (pdotn * n->y); - m[2][0] = vxz; - m[2][1] = vyz; - m[2][2] = (1 - (2 * n->z * n->z)); - m[2][3] = (pdotn * n->z); -} - -void C_MTXTransApply(const Mtx src, Mtx dst, f32 xT, f32 yT, f32 zT) { - assert(src && "MTXTransApply(): NULL MtxPtr 'src' "); - assert(dst && "MTXTransApply(): NULL MtxPtr 'src' "); //! wrong assert string - - if (src != dst) { - dst[0][0] = src[0][0]; - dst[0][1] = src[0][1]; - dst[0][2] = src[0][2]; - dst[1][0] = src[1][0]; - dst[1][1] = src[1][1]; - dst[1][2] = src[1][2]; - dst[2][0] = src[2][0]; - dst[2][1] = src[2][1]; - dst[2][2] = src[2][2]; - } - - dst[0][3] = (src[0][3] + xT); - dst[1][3] = (src[1][3] + yT); - dst[2][3] = (src[2][3] + zT); -} - -void C_MTXScale(Mtx m, f32 xS, f32 yS, f32 zS) { - assert(m && "MTXScale(): NULL MtxPtr 'm' "); - m[0][0] = xS; - m[0][1] = 0; - m[0][2] = 0; - m[0][3] = 0; - m[1][0] = 0; - m[1][1] = yS; - m[1][2] = 0; - m[1][3] = 0; - m[2][0] = 0; - m[2][1] = 0; - m[2][2] = zS; - m[2][3] = 0; -} - -void C_MTXScaleApply(const Mtx src, Mtx dst, f32 xS, f32 yS, f32 zS) { - assert(src && "MTXScaleApply(): NULL MtxPtr 'src' "); - assert(dst && "MTXScaleApply(): NULL MtxPtr 'dst' "); - dst[0][0] = (src[0][0] * xS); - dst[0][1] = (src[0][1] * xS); - dst[0][2] = (src[0][2] * xS); - dst[0][3] = (src[0][3] * xS); - dst[1][0] = (src[1][0] * yS); - dst[1][1] = (src[1][1] * yS); - dst[1][2] = (src[1][2] * yS); - dst[1][3] = (src[1][3] * yS); - dst[2][0] = (src[2][0] * zS); - dst[2][1] = (src[2][1] * zS); - dst[2][2] = (src[2][2] * zS); - dst[2][3] = (src[2][3] * zS); -} - -void C_MTXRotRad(Mtx m, char axis, f32 rad) { - f32 sinA; - f32 cosA; - - assert(m && "MTXRotRad(): NULL MtxPtr 'm' "); - sinA = sinf(rad); - cosA = cosf(rad); - C_MTXRotTrig(m, axis, sinA, cosA); -} - -void C_MTXRotTrig(Mtx m, char axis, f32 sinA, f32 cosA) { - assert(m && "MTXRotTrig(): NULL MtxPtr 'm' "); - switch(axis) { - case 'x': - case 'X': - m[0][0] = 1; - m[0][1] = 0; - m[0][2] = 0; - m[0][3] = 0; - m[1][0] = 0; - m[1][1] = cosA; - m[1][2] = -sinA; - m[1][3] = 0; - m[2][0] = 0; - m[2][1] = sinA; - m[2][2] = cosA; - m[2][3] = 0; - break; - case 'y': - case 'Y': - m[0][0] = cosA; - m[0][1] = 0; - m[0][2] = sinA; - m[0][3] = 0; - m[1][0] = 0; - m[1][1] = 1; - m[1][2] = 0; - m[1][3] = 0; - m[2][0] = -sinA; - m[2][1] = 0; - m[2][2] = cosA; - m[2][3] = 0; - break; - case 'z': - case 'Z': - m[0][0] = cosA; - m[0][1] = -sinA; - m[0][2] = 0; - m[0][3] = 0; - m[1][0] = sinA; - m[1][1] = cosA; - m[1][2] = 0; - m[1][3] = 0; - m[2][0] = 0; - m[2][1] = 0; - m[2][2] = 1; - m[2][3] = 0; - break; - default: - assert(0 && "MTXRotTrig(): invalid 'axis' value "); - break; - } -} - -void C_MTXRotAxisRad(Mtx m, const Vec* axis, f32 rad) { - Vec vN; - f32 s; - f32 c; - f32 t; - f32 x; - f32 y; - f32 z; - f32 xSq; - f32 ySq; - f32 zSq; - - assert(m && "MTXRotAxisRad(): NULL MtxPtr 'm' "); - assert(axis && "MTXRotAxisRad(): NULL VecPtr 'axis' "); - - s = sinf(rad); - c = cosf(rad); - t = 1 - c; - C_VECNormalize(axis, &vN); - x = vN.x; - y = vN.y; - z = vN.z; - xSq = (x * x); - ySq = (y * y); - zSq = (z * z); - m[0][0] = (c + (t * xSq)); - m[0][1] = (y * (t * x)) - (s * z); - m[0][2] = (z * (t * x)) + (s * y); - m[0][3] = 0; - m[1][0] = ((y * (t * x)) + (s * z)); - m[1][1] = (c + (t * ySq)); - m[1][2] = ((z * (t * y)) - (s * x)); - m[1][3] = 0; - m[2][0] = ((z * (t * x)) - (s * y)); - m[2][1] = ((z * (t * y)) + (s * x)); - m[2][2] = (c + (t * zSq)); - m[2][3] = 0; -} - -void C_MTXReorder(const Mtx src, ROMtx dst) -{ - u32 i; - u32 j; - for (i = 0; i < 3; i++) { - for (j = 0; j < 4; j++) { - dst[j][i] = src[i][j]; - } - } -} - -void C_MTXLookAt(Mtx m, const Point3d* camPos, const Vec* camUp, const Point3d* target) { - Vec vLook; - Vec vRight; - Vec vUp; - - assert(m && "MTXLookAt(): NULL MtxPtr 'm' "); - assert(camPos && "MTXLookAt(): NULL VecPtr 'camPos' "); - assert(camUp && "MTXLookAt(): NULL VecPtr 'camUp' "); - assert(target && "MTXLookAt(): NULL Point3dPtr 'target' "); - - vLook.x = camPos->x - target->x; - vLook.y = camPos->y - target->y; - vLook.z = camPos->z - target->z; - VECNormalize(&vLook, &vLook); - VECCrossProduct(camUp, &vLook, &vRight); - VECNormalize(&vRight, &vRight); - VECCrossProduct(&vLook, &vRight, &vUp); - m[0][0] = vRight.x; - m[0][1] = vRight.y; - m[0][2] = vRight.z; - m[0][3] = -((camPos->z * vRight.z) + ((camPos->x * vRight.x) + (camPos->y * vRight.y))); - m[1][0] = vUp.x; - m[1][1] = vUp.y; - m[1][2] = vUp.z; - m[1][3] = -((camPos->z * vUp.z) + ((camPos->x * vUp.x) + (camPos->y * vUp.y))); - m[2][0] = vLook.x; - m[2][1] = vLook.y; - m[2][2] = vLook.z; - m[2][3] = -((camPos->z * vLook.z) + ((camPos->x * vLook.x) + (camPos->y * vLook.y))); -} - -void C_MTXLightFrustum(Mtx m, f32 t, f32 b, f32 l, f32 r, f32 n, f32 scaleS, f32 scaleT, f32 transS, f32 transT) { - f32 tmp; - - assert(m && "MTXLightFrustum(): NULL MtxPtr 'm' "); - assert((t != b) && "MTXLightFrustum(): 't' and 'b' clipping planes are equal "); - assert((l != r) && "MTXLightFrustum(): 'l' and 'r' clipping planes are equal "); - - tmp = 1 / (r - l); - m[0][0] = (scaleS * (2 * n * tmp)); - m[0][1] = 0; - m[0][2] = (scaleS * (tmp * (r + l))) - transS; - m[0][3] = 0; - tmp = 1 / (t - b); - m[1][0] = 0; - m[1][1] = (scaleT * (2 * n * tmp)); - m[1][2] = (scaleT * (tmp * (t + b))) - transT; - m[1][3] = 0; - m[2][0] = 0; - m[2][1] = 0; - m[2][2] = -1; - m[2][3] = 0; -} - -void C_MTXLightPerspective(Mtx m, f32 fovY, f32 aspect, f32 scaleS, f32 scaleT, f32 transS, f32 transT) { - f32 angle; - f32 cot; - - assert(m && "MTXLightPerspective(): NULL MtxPtr 'm' "); - assert((fovY > 0.0) && (fovY < 180.0) && "MTXLightPerspective(): 'fovY' out of range "); - assert(0 != aspect && "MTXLightPerspective(): 'aspect' is 0 "); - - angle = (0.5f * fovY); - angle = MTXDegToRad(angle); - cot = 1 / tanf(angle); - m[0][0] = (scaleS * (cot / aspect)); - m[0][1] = 0; - m[0][2] = -transS; - m[0][3] = 0; - m[1][0] = 0; - m[1][1] = (cot * scaleT); - m[1][2] = -transT; - m[1][3] = 0; - m[2][0] = 0; - m[2][1] = 0; - m[2][2] = -1; - m[2][3] = 0; -} - -void C_MTXLightOrtho(Mtx m, f32 t, f32 b, f32 l, f32 r, f32 scaleS, f32 scaleT, f32 transS, f32 transT) { - f32 tmp; - - assert(m && "MTXLightOrtho(): NULL MtxPtr 'm' "); - assert((t != b) && "MTXLightOrtho(): 't' and 'b' clipping planes are equal "); - assert((l != r) && "MTXLightOrtho(): 'l' and 'r' clipping planes are equal "); - tmp = 1 / (r - l); - m[0][0] = (2 * tmp * scaleS); - m[0][1] = 0; - m[0][2] = 0; - m[0][3] = (transS + (scaleS * (tmp * -(r + l)))); - tmp = 1/ (t - b); - m[1][0] = 0; - m[1][1] = (2 * tmp * scaleT); - m[1][2] = 0; - m[1][3] = (transT + (scaleT * (tmp * -(t + b)))); - m[2][0] = 0; - m[2][1] = 0; - m[2][2] = 0; - m[2][3] = 1; -} diff --git a/aurora-main/lib/dolphin/mtx/mtx44.c b/aurora-main/lib/dolphin/mtx/mtx44.c deleted file mode 100644 index 1ca47cf..0000000 --- a/aurora-main/lib/dolphin/mtx/mtx44.c +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include -#include - -void C_MTXPerspective(Mtx44 m, f32 fovY, f32 aspect, f32 n, f32 f) { - f32 angle; - f32 cot; - f32 tmp; - - assert(m && "MTXPerspective(): NULL Mtx44Ptr 'm' "); - assert((fovY > 0.0) && (fovY < 180.0) && "MTXPerspective(): 'fovY' out of range "); - assert(0.0f != aspect && "MTXPerspective(): 'aspect' is 0 "); - - angle = (0.5f * fovY); - angle = MTXDegToRad(angle); - cot = 1 / tanf(angle); - m[0][0] = (cot / aspect); - m[0][1] = 0; - m[0][2] = 0; - m[0][3] = 0; - m[1][0] = 0; - m[1][1] = (cot); - m[1][2] = 0; - m[1][3] = 0; - m[2][0] = 0; - m[2][1] = 0; - tmp = 1 / (f - n); - m[2][2] = (-n * tmp); - m[2][3] = (tmp * -(f * n)); - m[3][0] = 0; - m[3][1] = 0; - m[3][2] = -1; - m[3][3] = 0; -} \ No newline at end of file diff --git a/aurora-main/lib/dolphin/mtx/mtxstack.c b/aurora-main/lib/dolphin/mtx/mtxstack.c deleted file mode 100644 index c026935..0000000 --- a/aurora-main/lib/dolphin/mtx/mtxstack.c +++ /dev/null @@ -1,108 +0,0 @@ -#include -#include -#include - -void MTXInitStack(MTXStack* sPtr, u32 numMtx) { - assert(sPtr && "MTXInitStack(): NULL MtxStackPtr 'sPtr' "); - assert(sPtr->stackBase && "MTXInitStack(): 'sPtr' contains a NULL ptr to stack memory "); - assert(numMtx && "MTXInitStack(): 'numMtx' is 0 "); - - sPtr->numMtx = numMtx; - sPtr->stackPtr = 0; -} - -MtxPtr MTXPush(MTXStack* sPtr, const Mtx m) { - assert(sPtr && "MTXPush(): NULL MtxStackPtr 'sPtr' "); - assert(sPtr->stackBase && "MTXPush(): 'sPtr' contains a NULL ptr to stack memory "); - assert(m && "MTXPush(): NULL MtxPtr 'm' "); - - if (sPtr->stackPtr == NULL) { - sPtr->stackPtr = sPtr->stackBase; - MTXCopy(m, sPtr->stackPtr); - } else { - assert(((((uintptr_t)sPtr->stackPtr - (uintptr_t)sPtr->stackBase) / 16) / 3) < (sPtr->numMtx - 1) && "MTXPush(): stack overflow "); - MTXCopy(m, sPtr->stackPtr + 3); - sPtr->stackPtr += 3; - } - - return sPtr->stackPtr; -} - -MtxPtr MTXPushFwd(MTXStack* sPtr, const Mtx m) { - assert(sPtr && "MTXPushFwd(): NULL MtxStackPtr 'sPtr' "); - assert(sPtr->stackBase && "MTXPushFwd(): 'sPtr' contains a NULL ptr to stack memory "); - assert(m && "MTXPushFwd(): NULL MtxPtr 'm' "); - - if (sPtr->stackPtr == NULL) { - sPtr->stackPtr = sPtr->stackBase; - MTXCopy(m, sPtr->stackPtr); - } else { - assert(((((uintptr_t)sPtr->stackPtr - (uintptr_t)sPtr->stackBase) / 16) / 3) < (sPtr->numMtx - 1) && "MTXPushFwd(): stack overflow"); - MTXConcat(sPtr->stackPtr, m, sPtr->stackPtr + 3); - sPtr->stackPtr += 3; - } - - return sPtr->stackPtr; -} - -MtxPtr MTXPushInv(MTXStack* sPtr, const Mtx m) { - Mtx mInv; - assert(sPtr && "MTXPushInv(): NULL MtxStackPtr 'sPtr' "); - assert(sPtr->stackBase && "MTXPushInv(): 'sPtr' contains a NULL ptr to stack memory "); - assert(m && "MTXPushInv(): NULL MtxPtr 'm' "); - - MTXInverse(m, mInv); - if (sPtr->stackPtr == NULL) { - sPtr->stackPtr = sPtr->stackBase; - MTXCopy(mInv, sPtr->stackPtr); - } else { - assert(((((uintptr_t)sPtr->stackPtr - (uintptr_t)sPtr->stackBase) / 16) / 3) < (sPtr->numMtx - 1) && "MTXPushInv(): stack overflow"); - MTXConcat(mInv, sPtr->stackPtr, sPtr->stackPtr + 3); - sPtr->stackPtr += 3; - } - - return sPtr->stackPtr; -} - -MtxPtr MTXPushInvXpose(MTXStack* sPtr, const Mtx m) { - Mtx mIT; - assert(sPtr && "MTXPushInvXpose(): NULL MtxStackPtr 'sPtr' "); - assert(sPtr->stackBase && "MTXPushInvXpose(): 'sPtr' contains a NULL ptr to stack memory "); - assert(m && "MTXPushInvXpose(): NULL MtxPtr 'm' "); - - MTXInverse(m, mIT); - MTXTranspose(mIT, mIT); - if (sPtr->stackPtr == NULL) { - sPtr->stackPtr = sPtr->stackBase; - MTXCopy(mIT, sPtr->stackPtr); - } else { - assert(((((uintptr_t)sPtr->stackPtr - (uintptr_t)sPtr->stackBase) / 16) / 3) < (sPtr->numMtx - 1) && "MTXPushInvXpose(): stack overflow "); - MTXConcat(sPtr->stackPtr, mIT, sPtr->stackPtr + 3); - sPtr->stackPtr += 3; - } - - return sPtr->stackPtr; -} - -MtxPtr MTXPop(MTXStack* sPtr) { - assert(sPtr && "MTXPop(): NULL MtxStackPtr 'sPtr' "); - assert(sPtr->stackBase && "MTXPop(): 'sPtr' contains a NULL ptr to stack memory "); - - if (sPtr->stackPtr == NULL) { - return NULL; - } - - if (sPtr->stackBase == sPtr->stackPtr) { - sPtr->stackPtr = NULL; - return NULL; - } - - sPtr->stackPtr -= 3; - return sPtr->stackPtr; -} - -MtxPtr MTXGetStackPtr(const MTXStack* sPtr) { - assert(sPtr && "MTXGetStackPtr(): NULL MtxStackPtr 'sPtr' "); - assert(sPtr->stackBase && "MTXGetStackPtr(): 'sPtr' contains a NULL ptr to stack memory "); - return sPtr->stackPtr; -} diff --git a/aurora-main/lib/dolphin/mtx/mtxvec.c b/aurora-main/lib/dolphin/mtx/mtxvec.c deleted file mode 100644 index fcb32e0..0000000 --- a/aurora-main/lib/dolphin/mtx/mtxvec.c +++ /dev/null @@ -1,95 +0,0 @@ -#include -#include - -void C_MTXMultVec(const Mtx m, const Vec* src, Vec* dst) { - Vec vTmp; - - assert(m && "MTXMultVec(): NULL MtxPtr 'm' "); - assert(src && "MTXMultVec(): NULL VecPtr 'src' "); - assert(dst && "MTXMultVec(): NULL VecPtr 'dst' "); - - vTmp.x = m[0][3] + ((m[0][2] * src->z) + ((m[0][0] * src->x) + (m[0][1] * src->y))); - vTmp.y = m[1][3] + ((m[1][2] * src->z) + ((m[1][0] * src->x) + (m[1][1] * src->y))); - vTmp.z = m[2][3] + ((m[2][2] * src->z) + ((m[2][0] * src->x) + (m[2][1] * src->y))); - dst->x = vTmp.x; - dst->y = vTmp.y; - dst->z = vTmp.z; -} - -void C_MTXMultVecArray(const Mtx m, const Vec* srcBase, Vec* dstBase, u32 count) { - u32 i; - Vec vTmp; - - assert(m && "MTXMultVecArray(): NULL MtxPtr 'm' "); - assert(srcBase && "MTXMultVecArray(): NULL VecPtr 'srcBase' "); - assert(dstBase && "MTXMultVecArray(): NULL VecPtr 'dstBase' "); - assert(count > 1 && "MTXMultVecArray(): count must be greater than 1."); - - for(i = 0; i < count; i++) { - vTmp.x = m[0][3] + ((m[0][2] * srcBase->z) + ((m[0][0] * srcBase->x) + (m[0][1] * srcBase->y))); - vTmp.y = m[1][3] + ((m[1][2] * srcBase->z) + ((m[1][0] * srcBase->x) + (m[1][1] * srcBase->y))); - vTmp.z = m[2][3] + ((m[2][2] * srcBase->z) + ((m[2][0] * srcBase->x) + (m[2][1] * srcBase->y))); - dstBase->x = vTmp.x; - dstBase->y = vTmp.y; - dstBase->z = vTmp.z; - srcBase++; - dstBase++; - } -} - -void C_MTXMultVecSR(const Mtx m, const Vec* src, Vec* dst) { - Vec vTmp; - - assert(m && "MTXMultVecSR(): NULL MtxPtr 'm' "); - assert(src && "MTXMultVecSR(): NULL VecPtr 'src' "); - assert(dst && "MTXMultVecSR(): NULL VecPtr 'dst' "); - - vTmp.x = (m[0][2] * src->z) + ((m[0][0] * src->x) + (m[0][1] * src->y)); - vTmp.y = (m[1][2] * src->z) + ((m[1][0] * src->x) + (m[1][1] * src->y)); - vTmp.z = (m[2][2] * src->z) + ((m[2][0] * src->x) + (m[2][1] * src->y)); - dst->x = vTmp.x; - dst->y = vTmp.y; - dst->z = vTmp.z; -} - -void C_MTXMultVecArraySR(const Mtx m, const Vec* srcBase, Vec* dstBase, u32 count) { - u32 i; - Vec vTmp; - - assert(m && "MTXMultVecArraySR(): NULL MtxPtr 'm' "); - assert(srcBase && "MTXMultVecArraySR(): NULL VecPtr 'srcBase' "); - assert(dstBase && "MTXMultVecArraySR(): NULL VecPtr 'dstBase' "); - assert(count > 1 && "MTXMultVecArraySR(): count must be greater than 1."); - - for(i = 0; i < count; i++) { - vTmp.x = (m[0][2] * srcBase->z) + ((m[0][0] * srcBase->x) + (m[0][1] * srcBase->y)); - vTmp.y = (m[1][2] * srcBase->z) + ((m[1][0] * srcBase->x) + (m[1][1] * srcBase->y)); - vTmp.z = (m[2][2] * srcBase->z) + ((m[2][0] * srcBase->x) + (m[2][1] * srcBase->y)); - dstBase->x = vTmp.x; - dstBase->y = vTmp.y; - dstBase->z = vTmp.z; - srcBase++; - dstBase++; - } -} - -void C_MTXROMultVecArray(const ROMtx m, const Vec *srcBase, Vec *dstBase, u32 count) -{ - u32 i; - Vec vTmp; - - assert(m && "MTXROMultVecArray(): NULL MtxPtr 'm' "); - assert(srcBase && "MTXROMultVecArray(): NULL VecPtr 'srcBase' "); - assert(dstBase && "MTXROMultVecArray(): NULL VecPtr 'dstBase' "); - - for(i = 0; i < count; i++) { - vTmp.x = (m[0][0] * srcBase->x) + (m[1][0] * srcBase->y) + (m[2][0] * srcBase->z) + m[3][0]; - vTmp.y = (m[0][1] * srcBase->x) + (m[1][1] * srcBase->y) + (m[2][1] * srcBase->z) + m[3][1]; - vTmp.z = (m[0][2] * srcBase->x) + (m[1][2] * srcBase->y) + (m[2][2] * srcBase->z) + m[3][2]; - dstBase->x = vTmp.x; - dstBase->y = vTmp.y; - dstBase->z = vTmp.z; - srcBase++; - dstBase++; - } -} diff --git a/aurora-main/lib/dolphin/mtx/quat.c b/aurora-main/lib/dolphin/mtx/quat.c deleted file mode 100644 index 80966d6..0000000 --- a/aurora-main/lib/dolphin/mtx/quat.c +++ /dev/null @@ -1,313 +0,0 @@ -#include -#include -#include - -void C_QUATAdd(const Quaternion* p, const Quaternion* q, Quaternion* r) { - assert(p && "QUATAdd(): NULL QuaternionPtr 'p' "); - assert(q && "QUATAdd(): NULL QuaternionPtr 'q' "); - assert(r && "QUATAdd(): NULL QuaternionPtr 'r' "); - - r->x = p->x + q->x; - r->y = p->y + q->y; - r->z = p->z + q->z; - r->w = p->w + q->w; -} - -void C_QUATSubtract(const Quaternion* p, const Quaternion* q, Quaternion* r) { - assert(p && "QUATSubtract(): NULL QuaternionPtr 'p' "); - assert(q && "QUATSubtract(): NULL QuaternionPtr 'q' "); - assert(r && "QUATSubtract(): NULL QuaternionPtr 'r' "); - - r->x = p->x - q->x; - r->y = p->y - q->y; - r->z = p->z - q->z; - r->w = p->w - q->w; -} - -void C_QUATMultiply(const Quaternion* p, const Quaternion* q, Quaternion* pq) { - Quaternion* r; - Quaternion pqTmp; - - assert(p && "QUATMultiply(): NULL QuaternionPtr 'p' "); - assert(q && "QUATMultiply(): NULL QuaternionPtr 'q' "); - assert(pq && "QUATMultiply(): NULL QuaternionPtr 'pq' "); - - if (p == pq || q == pq){ - r = &pqTmp; - } else { - r = pq; - } - - r->w = (p->w * q->w) - (p->x * q->x) - (p->y * q->y) - (p->z * q->z); - r->x = (p->w * q->x) + (p->x * q->w) + (p->y * q->z) - (p->z * q->y); - r->y = (p->w * q->y) + (p->y * q->w) + (p->z * q->x) - (p->x * q->z); - r->z = (p->w * q->z) + (p->z * q->w) + (p->x * q->y) - (p->y * q->x); - - if (r == &pqTmp) { - *pq = pqTmp; - } -} - -void C_QUATDivide(const Quaternion* p, const Quaternion* q, Quaternion* r) { - Quaternion qtmp; - assert(p && "QUATDivide(): NULL QuaternionPtr 'p' "); - assert(q && "QUATDivide(): NULL QuaternionPtr 'q' "); - assert(r && "QUATDivide(): NULL QuaternionPtr 'r' "); - - C_QUATInverse(q, &qtmp); - C_QUATMultiply(&qtmp, p, r); -} - -void C_QUATScale(const Quaternion* q, Quaternion* r, f32 scale) { - assert(q && "QUATScale(): NULL QuaternionPtr 'q' "); - assert(r && "QUATScale(): NULL QuaternionPtr 'r' "); - - r->x = q->x * scale; - r->y = q->y * scale; - r->z = q->z * scale; - r->w = q->w * scale; -} - -f32 C_QUATDotProduct(const Quaternion* p, const Quaternion* q) { - assert(p && "QUATDotProduct(): NULL QuaternionPtr 'p' "); - assert(q && "QUATDotProduct(): NULL QuaternionPtr 'q' "); - - return (q->x * p->x) + (q->y * p->y) + (q->z * p->z) + (q->w * p->w); -} - -void C_QUATNormalize(const Quaternion* src, Quaternion* unit) { - f32 mag; - assert(src && "QUATNormalize(): NULL QuaternionPtr 'src' "); - assert(unit && "QUATNormalize(): NULL QuaternionPtr 'unit' "); - - mag = (src->x * src->x) + (src->y * src->y) + (src->z * src->z) + (src->w * src->w); - if (mag >= 0.00001f) { - mag = 1.0f / sqrtf(mag); - - unit->x = src->x * mag; - unit->y = src->y * mag; - unit->z = src->z * mag; - unit->w = src->w * mag; - } else { - unit->x = unit->y = unit->z = unit->w = 0.0f; - } -} - -void C_QUATInverse(const Quaternion* src, Quaternion* inv) { - f32 mag, norminv; - assert(src && "QUATInverse(): NULL QuaternionPtr 'src' "); - assert(inv && "QUATInverse(): NULL QuaternionPtr 'inv' "); - - mag = (src->x * src->x) + (src->y * src->y) + (src->z * src->z) + (src->w * src->w); - if (mag == 0.0f) { - mag = 1.0f; - } - - norminv = 1.0f / mag; - inv->x = -src->x * norminv; - inv->y = -src->y * norminv; - inv->z = -src->z * norminv; - inv->w = src->w * norminv; -} - -void C_QUATExp(const Quaternion* q, Quaternion* r) { - f32 theta, scale; - assert(q && "QUATExp(): NULL QuaternionPtr 'q' "); - assert(r && "QUATExp(): NULL QuaternionPtr 'r' "); - assert(q->w == 0.0f && "QUATExp(): 'q' is not a pure quaternion. "); - - theta = sqrtf((q->x * q->x) + (q->y * q->y) + (q->z * q->z)); - scale = 1.0f; - - if (theta > 0.00001f) { - scale = sinf(theta) / theta; - } - - r->x = scale * q->x; - r->y = scale * q->y; - r->z = scale * q->z; - r->w = cosf(theta); -} - -void C_QUATLogN(const Quaternion* q, Quaternion* r) { - f32 theta, scale; - assert(q && "QUATLogN(): NULL QuaternionPtr 'q' "); - assert(r && "QUATLogN(): NULL QuaternionPtr 'r' "); - - scale = (q->x * q->x) + (q->y * q->y) + (q->z * q->z); - - scale = sqrtf(scale); - theta = atan2f(scale, q->w); - - if (scale > 0.0f) { - scale = theta / scale; - } - - r->x = scale * q->x; - r->y = scale * q->y; - r->z = scale * q->z; - r->w = 0.0f; -} - - -void C_QUATMakeClosest(const Quaternion* q, const Quaternion* qto, Quaternion* r) { - f32 dot; - assert(q && "QUATMakeClosest(): NULL QuaternionPtr 'q' "); - assert(qto && "QUATMakeClosest(): NULL QuaternionPtr 'qto' "); - assert(r && "QUATMakeClosest(): NULL QuaternionPtr 'r' "); - - dot = (q->x * qto->x) + (q->y * qto->y) + (q->z * qto->z) + (q->w * qto->w); - if (dot < 0.0f) { - r->x = -q->x; - r->y = -q->y; - r->z = -q->z; - r->w = -q->w; - } else { - *r = *q; - } -} - -void C_QUATRotAxisRad(Quaternion* r, const Vec* axis, f32 rad) { - f32 half, sh, ch; - Vec nAxis; - - assert(r && "QUATRotAxisRad(): NULL QuaternionPtr 'r' "); - assert(axis && "QUATRotAxisRad(): NULL VecPtr 'axis' "); - - VECNormalize(axis, &nAxis); - - half = rad * 0.5f; - sh = sinf(half); - ch = cosf(half); - - r->x = sh * nAxis.x; - r->y = sh * nAxis.y; - r->z = sh * nAxis.z; - r->w = ch; -} - -void C_QUATMtx(Quaternion* r, const Mtx m) { - f32 tr,s; - s32 i, j, k; - s32 nxt[3] = {1, 2, 0}; - f32 q[3]; - - assert(r && "QUATMtx(): NULL QuaternionPtr 'r' "); - assert(m && "QUATMtx(): NULL MtxPtr 'm' "); - - tr = m[0][0] + m[1][1] + m[2][2]; - if (tr > 0.0f) { - s = sqrtf(tr + 1.0f); - r->w = s * 0.5f; - s = 0.5f / s; - - r->x = (m[2][1] - m[1][2]) * s; - r->y = (m[0][2] - m[2][0]) * s; - r->z = (m[1][0] - m[0][1]) * s; - } else { - i = 0; - if (m[1][1] > m[0][0]) { - i = 1; - } - - if (m[2][2] > m[i][i]) { - i = 2; - } - - j = nxt[i]; - k = nxt[j]; - - s = sqrtf((m[i][i] - (m[j][j] + m[k][k])) + 1.0f); - q[i] = s * 0.5f; - - if (s != 0.0f) { - s = 0.5f / s; - } - - r->w = (m[k][j] - m[j][k]) * s; - q[j] = (m[i][j] + m[j][i]) * s; - q[k] = (m[i][k] + m[k][i]) * s; - - r->x = q[0]; - r->y = q[1]; - r->z = q[2]; - } -} - -void C_QUATLerp(const Quaternion* p, const Quaternion* q, Quaternion* r, f32 t) { - assert(p && "QUATLerp(): NULL QuaternionPtr 'p' "); - assert(q && "QUATLerp(): NULL QuaternionPtr 'q' "); - assert(r && "QUATLerp(): NULL QuaternionPtr 'r' "); - - r->x = t * (q->x - p->x) + p->x; - r->y = t * (q->y - p->y) + p->y; - r->z = t * (q->z - p->z) + p->z; - r->w = t * (q->w - p->w) + p->w; -} - -void C_QUATSlerp(const Quaternion* p, const Quaternion* q, Quaternion* r, f32 t) { - f32 theta, sin_th, cos_th; - f32 tp, tq; - - assert(p && "QUATSlerp(): NULL QuaternionPtr 'p' "); - assert(q && "QUATSlerp(): NULL QuaternionPtr 'q' "); - assert(r && "QUATSlerp(): NULL QuaternionPtr 'r' "); - - cos_th = p->x * q->x + p->y * q->y + p->z * q->z + p->w * q->w; - tq = 1.0f; - - if (cos_th < 0.0f) { - cos_th = -cos_th; - tq = -tq; - } - - if (cos_th <= 0.99999f) { - theta = acosf(cos_th); - sin_th = sinf(theta); - - tp = sinf((1.0f - t) * theta) / sin_th; - tq *= sinf(t * theta) / sin_th; - } else { - tp = 1.0f - t; - tq *= t; - } - - r->x = (tp * p->x) + (tq * q->x); - r->y = (tp * p->y) + (tq * q->y); - r->z = (tp * p->z) + (tq * q->z); - r->w = (tp * p->w) + (tq * q->w); -} - -void C_QUATSquad(const Quaternion* p, const Quaternion* a, const Quaternion* b, const Quaternion* q, Quaternion* r, f32 t) { - Quaternion pq, ab; - f32 t2; - - assert(p && "QUATSquad(): NULL QuaternionPtr 'p' "); - assert(a && "QUATSquad(): NULL QuaternionPtr 'a' "); - assert(b && "QUATSquad(): NULL QuaternionPtr 'b' "); - assert(q && "QUATSquad(): NULL QuaternionPtr 'q' "); - assert(r && "QUATSquad(): NULL QuaternionPtr 'r' "); - - t2 = 2.0f * t * (1.0f - t); - C_QUATSlerp(p, q, &pq, t); - C_QUATSlerp(a, b, &ab, t); - C_QUATSlerp(&pq, &ab, r, t2); -} - -void C_QUATCompA(const Quaternion* qprev, const Quaternion* q, const Quaternion* qnext, Quaternion* a) { - Quaternion qm, qp, lqm, lqp, qpqm, exq; - - assert(qprev && "QUATCompA(): NULL QuaternionPtr 'qprev' "); - assert(q && "QUATCompA(): NULL QuaternionPtr 'q' "); - assert(qnext && "QUATCompA(): NULL QuaternionPtr 'qnext' "); - assert(a && "QUATCompA(): NULL QuaternionPtr 'a' "); - - C_QUATDivide(qprev, q, &qm); - C_QUATLogN(&qm, &lqm); - C_QUATDivide(qnext, q, &qp); - C_QUATLogN(&qp, &lqp); - C_QUATAdd(&lqp, &lqm, &qpqm); - C_QUATScale(&qpqm, &qpqm, -0.25f); - C_QUATExp(&qpqm, &exq); - C_QUATMultiply(q, &exq, a); -} diff --git a/aurora-main/lib/dolphin/mtx/vec.c b/aurora-main/lib/dolphin/mtx/vec.c deleted file mode 100644 index 6dc1467..0000000 --- a/aurora-main/lib/dolphin/mtx/vec.c +++ /dev/null @@ -1,191 +0,0 @@ -#include -#include -#include -#include - -void C_VECAdd(const Vec* a, const Vec* b, Vec* ab) { - assert(a && "VECAdd(): NULL VecPtr 'a' "); - assert(b && "VECAdd(): NULL VecPtr 'b' "); - assert(ab && "VECAdd(): NULL VecPtr 'ab' "); - ab->x = a->x + b->x; - ab->y = a->y + b->y; - ab->z = a->z + b->z; -} - -void C_VECSubtract(const Vec* a, const Vec* b, Vec* a_b) { - assert(a && "VECSubtract(): NULL VecPtr 'a' "); - assert(b && "VECSubtract(): NULL VecPtr 'b' "); - assert(a_b && "VECSubtract(): NULL VecPtr 'a_b' "); - a_b->x = a->x - b->x; - a_b->y = a->y - b->y; - a_b->z = a->z - b->z; -} - -void C_VECScale(const Vec* src, Vec* dst, f32 scale) { - assert(src && "VECScale(): NULL VecPtr 'src' "); - assert(dst && "VECScale(): NULL VecPtr 'dst' "); - dst->x = (src->x * scale); - dst->y = (src->y * scale); - dst->z = (src->z * scale); -} - -void C_VECNormalize(const Vec* src, Vec* unit) { - f32 mag; - - assert(src && "VECNormalize(): NULL VecPtr 'src' "); - assert(unit && "VECNormalize(): NULL VecPtr 'unit' "); - - mag = (src->z * src->z) + ((src->x * src->x) + (src->y * src->y)); - assert(0.0f != mag && "VECNormalize(): zero magnitude vector "); - - mag = 1.0f/ sqrtf(mag); - unit->x = src->x * mag; - unit->y = src->y * mag; - unit->z = src->z * mag; -} - -void PSVECNormalize(const Vec* src, Vec* unit) { - f32 sqsum; - f32 rsqrt; - - assert(src && "VECNormalize(): NULL VecPtr 'src' "); - assert(unit && "VECNormalize(): NULL VecPtr 'unit' "); - - sqsum = (src->z * src->z + src->x * src->x) + src->y * src->y; - assert(0.0f != sqsum && "VECNormalize(): zero magnitude vector "); - - rsqrt = ppc_rsqrte(sqsum); - unit->x = src->x * rsqrt; - unit->y = src->y * rsqrt; - unit->z = src->z * rsqrt; -} - -f32 C_VECSquareMag(const Vec* v) { - f32 sqmag; - - assert(v && "VECMag(): NULL VecPtr 'v' "); - - sqmag = v->z * v->z + ((v->x * v->x) + (v->y * v->y)); - return sqmag; -} - -f32 PSVECSquareMag(const Vec* v) { - assert(v && "VECMag(): NULL VecPtr 'v' "); - return (v->z * v->z + v->x * v->x) + v->y * v->y; -} - -f32 C_VECMag(const Vec* v) { - return sqrtf(C_VECSquareMag(v)); -} - -f32 PSVECMag(const Vec* v) { - f32 sqmag; - sqmag = PSVECSquareMag(v); - if (sqmag == 0.0f) { - return 0.0f; - } - return sqmag * ppc_rsqrte(sqmag); -} - -f32 C_VECDotProduct(const Vec* a, const Vec* b) { - f32 dot; - - assert(a && "VECDotProduct(): NULL VecPtr 'a' "); - assert(b && "VECDotProduct(): NULL VecPtr 'b' "); - dot = (a->z * b->z) + ((a->x * b->x) + (a->y * b->y)); - return dot; -} - -void C_VECCrossProduct(const Vec* a, const Vec* b, Vec* axb) { - Vec vTmp; - - assert(a && "VECCrossProduct(): NULL VecPtr 'a' "); - assert(b && "VECCrossProduct(): NULL VecPtr 'b' "); - assert(axb && "VECCrossProduct(): NULL VecPtr 'axb' "); - - vTmp.x = (a->y * b->z) - (a->z * b->y); - vTmp.y = (a->z * b->x) - (a->x * b->z); - vTmp.z = (a->x * b->y) - (a->y * b->x); - axb->x = vTmp.x; - axb->y = vTmp.y; - axb->z = vTmp.z; -} - -void C_VECHalfAngle(const Vec* a, const Vec* b, Vec* half) { - Vec aTmp; - Vec bTmp; - Vec hTmp; - - assert(a && "VECHalfAngle(): NULL VecPtr 'a' "); - assert(b && "VECHalfAngle(): NULL VecPtr 'b' "); - assert(half && "VECHalfAngle(): NULL VecPtr 'half' "); - - aTmp.x = -a->x; - aTmp.y = -a->y; - aTmp.z = -a->z; - bTmp.x = -b->x; - bTmp.y = -b->y; - bTmp.z = -b->z; - - VECNormalize(&aTmp, &aTmp); - VECNormalize(&bTmp, &bTmp); - VECAdd(&aTmp, &bTmp, &hTmp); - - if (VECDotProduct(&hTmp, &hTmp) > 0.0f) { - VECNormalize(&hTmp, half); - return; - } - *half = hTmp; -} - -void C_VECReflect(const Vec* src, const Vec* normal, Vec* dst) { - f32 cosA; - Vec uI; - Vec uN; - - assert(src && "VECReflect(): NULL VecPtr 'src' "); - assert(normal && "VECReflect(): NULL VecPtr 'normal' "); - assert(dst && "VECReflect(): NULL VecPtr 'dst' "); - - uI.x = -src->x; - uI.y = -src->y; - uI.z = -src->z; - - VECNormalize(&uI, &uI); - VECNormalize(normal, &uN); - - cosA = VECDotProduct(&uI, &uN); - dst->x = (2.0f * uN.x * cosA) - uI.x; - dst->y = (2.0f * uN.y * cosA) - uI.y; - dst->z = (2.0f * uN.z * cosA) - uI.z; - VECNormalize(dst, dst); -} - -f32 C_VECSquareDistance(const Vec* a, const Vec* b) { - Vec diff; - - diff.x = a->x - b->x; - diff.y = a->y - b->y; - diff.z = a->z - b->z; - return (diff.z * diff.z) + ((diff.x * diff.x) + (diff.y * diff.y)); -} - -f32 PSVECSquareDistance(const Vec* a, const Vec* b) { - f32 dx = a->x - b->x; - f32 dy = a->y - b->y; - f32 dz = a->z - b->z; - return (dx * dx + dy * dy) + dz * dz; -} - -f32 C_VECDistance(const Vec* a, const Vec* b) { - return sqrtf(C_VECSquareDistance(a, b)); -} - -f32 PSVECDistance(const Vec* a, const Vec* b) { - f32 sqdist; - sqdist = PSVECSquareDistance(a, b); - if (sqdist == 0.0f) { - return 0.0f; - } - return sqdist * ppc_rsqrte(sqdist); -} diff --git a/aurora-main/lib/dolphin/os/OSAddress.cpp b/aurora-main/lib/dolphin/os/OSAddress.cpp deleted file mode 100644 index 8ca1b4a..0000000 --- a/aurora-main/lib/dolphin/os/OSAddress.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "internal.hpp" -#include - -#include - -#if NDEBUG -#undef OSPhysicalToCached -#undef OSPhysicalToUncached -#undef OSCachedToPhysical -#undef OSUncachedToPhysical -#undef OSCachedToUncached -#undef OSUncachedToCached -#endif - -void* OSPhysicalToCached(u32 paddr) { - assert (paddr <= aurora::g_config.mem1Size); - return POINTER_ADD(MEM1Start, paddr); -} - -void* OSPhysicalToUncached(u32 paddr) { - return OSPhysicalToCached(paddr); -} - -u32 OSCachedToPhysical(void* caddr) { - assert (caddr >= MEM1Start && caddr <= MEM1End); - - return (reinterpret_cast(caddr) - reinterpret_cast(MEM1Start)); -} - -u32 OSUncachedToPhysical(void* ucaddr) { - return OSCachedToPhysical(ucaddr); -} - -void* OSCachedToUncached(void* caddr) { - return caddr; -} - -void* OSUncachedToCached(void* ucaddr) { - return ucaddr; -} - diff --git a/aurora-main/lib/dolphin/os/OSAlloc.cpp b/aurora-main/lib/dolphin/os/OSAlloc.cpp deleted file mode 100644 index 790e300..0000000 --- a/aurora-main/lib/dolphin/os/OSAlloc.cpp +++ /dev/null @@ -1,564 +0,0 @@ -#include - -#include -#include - -#include "../../logging.hpp" - -extern "C" volatile OSHeapHandle __OSCurrHeap = -1; - -namespace { - -constexpr u32 kAlignment = 32; -constexpr u32 kHeaderSize = 32; -constexpr u32 kMinObjectSize = 64; - -struct HeapDesc; - -struct alignas(32) Cell { - Cell* prev; - Cell* next; - s32 size; - HeapDesc* owner; -}; - -static_assert(sizeof(Cell) == kHeaderSize, "Cell header must stay 32 bytes"); - -struct HeapDesc { - s32 size; - Cell* freeList; - Cell* allocated; -}; - -static aurora::Module AllocLog("aurora::os::alloc"); - -static HeapDesc* sHeapArray = nullptr; -static int sNumHeaps = 0; -static u8* sArenaStart = nullptr; -static u8* sArenaEnd = nullptr; - -static uintptr_t roundUp32(const uintptr_t value) { - return (value + (kAlignment - 1)) & ~(static_cast(kAlignment - 1)); -} - -static uintptr_t roundDown32(const uintptr_t value) { - return value & ~(static_cast(kAlignment - 1)); -} - -static bool inArena(const void* ptr) { - if (sArenaStart == nullptr || sArenaEnd == nullptr) { - return false; - } - const auto p = reinterpret_cast(ptr); - return p >= reinterpret_cast(sArenaStart) && p < reinterpret_cast(sArenaEnd); -} - -static bool validHeapHandle(const OSHeapHandle heap) { - return sHeapArray != nullptr && heap >= 0 && heap < sNumHeaps && sHeapArray[heap].size >= 0; -} - -static Cell* addFront(Cell* list, Cell* cell) { - cell->prev = nullptr; - cell->next = list; - if (list != nullptr) { - list->prev = cell; - } - return cell; -} - -static Cell* extract(Cell* list, Cell* cell) { - if (cell->next != nullptr) { - cell->next->prev = cell->prev; - } - if (cell->prev != nullptr) { - cell->prev->next = cell->next; - return list; - } - return cell->next; -} - -static bool containsCell(Cell* list, Cell* cell) { - for (Cell* it = list; it != nullptr; it = it->next) { - if (it == cell) { - return true; - } - } - return false; -} - -static Cell* insertAndCoalesce(Cell* list, Cell* cell) { - Cell* prev = nullptr; - Cell* next = list; - while (next != nullptr && next < cell) { - prev = next; - next = next->next; - } - - cell->prev = prev; - cell->next = next; - if (prev != nullptr) { - prev->next = cell; - } else { - list = cell; - } - if (next != nullptr) { - next->prev = cell; - } - - if (cell->next != nullptr) { - auto* right = cell->next; - if (reinterpret_cast(cell) + cell->size == reinterpret_cast(right)) { - cell->size += right->size; - cell->next = right->next; - if (right->next != nullptr) { - right->next->prev = cell; - } - } - } - - if (cell->prev != nullptr) { - auto* left = cell->prev; - if (reinterpret_cast(left) + left->size == reinterpret_cast(cell)) { - left->size += cell->size; - left->next = cell->next; - if (cell->next != nullptr) { - cell->next->prev = left; - } - return list; - } - } - - return list; -} - -static bool validateBlockRange(const uintptr_t start, const uintptr_t end) { - if (start >= end) { - return false; - } - if (sArenaStart == nullptr || sArenaEnd == nullptr) { - return false; - } - return start >= reinterpret_cast(sArenaStart) - && end <= reinterpret_cast(sArenaEnd) - && (end - start) >= kMinObjectSize; -} - -static void dropTinyCell(HeapDesc& hd, Cell* cell) { - hd.freeList = extract(hd.freeList, cell); - hd.size -= cell->size; -} - -static void carveRangeFromHeap(HeapDesc& hd, uintptr_t carveStart, uintptr_t carveEnd) { - Cell* cell = hd.freeList; - while (cell != nullptr) { - Cell* nextCell = cell->next; - const auto cellStart = reinterpret_cast(cell); - const auto cellEnd = cellStart + static_cast(cell->size); - - const auto overlapStart = carveStart > cellStart ? carveStart : cellStart; - const auto overlapEnd = carveEnd < cellEnd ? carveEnd : cellEnd; - if (overlapStart >= overlapEnd) { - cell = nextCell; - continue; - } - - const auto removed = static_cast(overlapEnd - overlapStart); - hd.size -= removed; - - const bool cutHead = overlapStart == cellStart; - const bool cutTail = overlapEnd == cellEnd; - - if (cutHead && cutTail) { - hd.freeList = extract(hd.freeList, cell); - } else if (cutHead) { - auto* newCell = reinterpret_cast(overlapEnd); - newCell->size = static_cast(cellEnd - overlapEnd); - newCell->owner = nullptr; - newCell->prev = cell->prev; - newCell->next = cell->next; - if (newCell->prev != nullptr) { - newCell->prev->next = newCell; - } else { - hd.freeList = newCell; - } - if (newCell->next != nullptr) { - newCell->next->prev = newCell; - } - if (newCell->size < static_cast(kMinObjectSize)) { - dropTinyCell(hd, newCell); - } - } else if (cutTail) { - cell->size = static_cast(overlapStart - cellStart); - if (cell->size < static_cast(kMinObjectSize)) { - dropTinyCell(hd, cell); - } - } else { - const auto leftSize = static_cast(overlapStart - cellStart); - const auto rightSize = static_cast(cellEnd - overlapEnd); - if (leftSize >= static_cast(kMinObjectSize) && rightSize >= static_cast(kMinObjectSize)) { - auto* right = reinterpret_cast(overlapEnd); - right->size = rightSize; - right->owner = nullptr; - right->prev = cell; - right->next = cell->next; - if (right->next != nullptr) { - right->next->prev = right; - } - cell->next = right; - cell->size = leftSize; - } else if (leftSize >= static_cast(kMinObjectSize)) { - cell->size = leftSize; - } else if (rightSize >= static_cast(kMinObjectSize)) { - auto* right = reinterpret_cast(overlapEnd); - right->size = rightSize; - right->owner = nullptr; - right->prev = cell->prev; - right->next = cell->next; - if (right->prev != nullptr) { - right->prev->next = right; - } else { - hd.freeList = right; - } - if (right->next != nullptr) { - right->next->prev = right; - } - } else { - hd.freeList = extract(hd.freeList, cell); - } - } - - cell = nextCell; - } -} - -} // namespace - -extern "C" { - -void* OSInitAlloc(void* arenaStart, void* arenaEnd, int maxHeaps) { - if (arenaStart == nullptr || arenaEnd == nullptr || maxHeaps <= 0) { - return nullptr; - } - - auto start = reinterpret_cast(arenaStart); - auto end = reinterpret_cast(arenaEnd); - if (start >= end) { - return nullptr; - } - - const auto arrayBytes = static_cast(maxHeaps) * sizeof(HeapDesc); - if ((end - start) < arrayBytes + kMinObjectSize) { - return nullptr; - } - - sHeapArray = reinterpret_cast(arenaStart); - sNumHeaps = maxHeaps; - for (int i = 0; i < sNumHeaps; ++i) { - sHeapArray[i].size = -1; - sHeapArray[i].freeList = nullptr; - sHeapArray[i].allocated = nullptr; - } - - __OSCurrHeap = -1; - sArenaStart = reinterpret_cast(roundUp32(start + arrayBytes)); - sArenaEnd = reinterpret_cast(roundDown32(end)); - if (sArenaEnd <= sArenaStart || static_cast(sArenaEnd - sArenaStart) < kMinObjectSize) { - sHeapArray = nullptr; - sNumHeaps = 0; - sArenaStart = nullptr; - sArenaEnd = nullptr; - return nullptr; - } - - return sArenaStart; -} - -OSHeapHandle OSCreateHeap(void* start, void* end) { - if (sHeapArray == nullptr) { - return -1; - } - - const auto blockStart = roundUp32(reinterpret_cast(start)); - const auto blockEnd = roundDown32(reinterpret_cast(end)); - if (!validateBlockRange(blockStart, blockEnd)) { - return -1; - } - - for (OSHeapHandle heap = 0; heap < sNumHeaps; ++heap) { - auto& hd = sHeapArray[heap]; - if (hd.size >= 0) { - continue; - } - - hd.size = static_cast(blockEnd - blockStart); - hd.allocated = nullptr; - hd.freeList = reinterpret_cast(blockStart); - hd.freeList->prev = nullptr; - hd.freeList->next = nullptr; - hd.freeList->size = hd.size; - hd.freeList->owner = nullptr; - return heap; - } - - return -1; -} - -void OSDestroyHeap(OSHeapHandle heap) { - if (!validHeapHandle(heap)) { - return; - } - - auto& hd = sHeapArray[heap]; - hd.size = -1; - hd.freeList = nullptr; - hd.allocated = nullptr; - if (__OSCurrHeap == heap) { - __OSCurrHeap = -1; - } -} - -void OSAddToHeap(OSHeapHandle heap, void* start, void* end) { - if (!validHeapHandle(heap)) { - return; - } - - const auto blockStart = roundUp32(reinterpret_cast(start)); - const auto blockEnd = roundDown32(reinterpret_cast(end)); - if (!validateBlockRange(blockStart, blockEnd)) { - return; - } - - auto& hd = sHeapArray[heap]; - auto* cell = reinterpret_cast(blockStart); - cell->prev = nullptr; - cell->next = nullptr; - cell->size = static_cast(blockEnd - blockStart); - cell->owner = nullptr; - hd.freeList = insertAndCoalesce(hd.freeList, cell); - hd.size += cell->size; -} - -void* OSAllocFromHeap(OSHeapHandle heap, u32 size) { - if (!validHeapHandle(heap) || size == 0) { - return nullptr; - } - - auto& hd = sHeapArray[heap]; - const auto requested = static_cast(roundUp32(static_cast(size) + kHeaderSize)); - - Cell* cell = hd.freeList; - while (cell != nullptr && cell->size < requested) { - cell = cell->next; - } - if (cell == nullptr) { - return nullptr; - } - - const auto leftover = cell->size - requested; - if (leftover < static_cast(kMinObjectSize)) { - hd.freeList = extract(hd.freeList, cell); - } else { - auto* split = reinterpret_cast(reinterpret_cast(cell) + requested); - split->size = leftover; - split->owner = nullptr; - split->prev = cell->prev; - split->next = cell->next; - if (split->prev != nullptr) { - split->prev->next = split; - } else { - hd.freeList = split; - } - if (split->next != nullptr) { - split->next->prev = split; - } - cell->size = requested; - } - - cell->owner = &hd; - hd.allocated = addFront(hd.allocated, cell); - return reinterpret_cast(cell) + kHeaderSize; -} - -void OSFreeToHeap(OSHeapHandle heap, void* ptr) { - if (!validHeapHandle(heap) || ptr == nullptr) { - return; - } - if (!inArena(ptr) || (reinterpret_cast(ptr) & (kAlignment - 1)) != 0) { - return; - } - - auto& hd = sHeapArray[heap]; - auto* cell = reinterpret_cast(reinterpret_cast(ptr) - kHeaderSize); - if (cell->owner != &hd || !containsCell(hd.allocated, cell)) { - return; - } - - hd.allocated = extract(hd.allocated, cell); - cell->owner = nullptr; - hd.freeList = insertAndCoalesce(hd.freeList, cell); -} - -OSHeapHandle OSSetCurrentHeap(OSHeapHandle heap) { - const auto prev = __OSCurrHeap; - if (heap == -1 || validHeapHandle(heap)) { - __OSCurrHeap = heap; - } - return prev; -} - -void* OSAllocFixed(void* rstart, void* rend) { - if (sHeapArray == nullptr || rstart == nullptr || rend == nullptr) { - return nullptr; - } - - for (int i = 0; i < sNumHeaps; ++i) { - if (sHeapArray[i].size >= 0 && sHeapArray[i].allocated != nullptr) { - return nullptr; - } - } - - const auto fixedStart = roundDown32(reinterpret_cast(rstart)); - const auto fixedEnd = roundUp32(reinterpret_cast(rend)); - if (fixedStart >= fixedEnd) { - return nullptr; - } - if (fixedStart < reinterpret_cast(sArenaStart) - || fixedEnd > reinterpret_cast(sArenaEnd)) { - return nullptr; - } - - for (int i = 0; i < sNumHeaps; ++i) { - auto& hd = sHeapArray[i]; - if (hd.size >= 0) { - carveRangeFromHeap(hd, fixedStart, fixedEnd); - } - } - - return reinterpret_cast(fixedStart); -} - -s32 OSCheckHeap(OSHeapHandle heap) { - if (!validHeapHandle(heap)) { - return -1; - } - - auto& hd = sHeapArray[heap]; - s32 total = 0; - s32 freeBytes = 0; - - if (hd.allocated != nullptr && hd.allocated->prev != nullptr) { - return -1; - } - - for (Cell* cell = hd.allocated; cell != nullptr; cell = cell->next) { - if (!inArena(cell) - || (reinterpret_cast(cell) & (kAlignment - 1)) != 0 - || cell->size < static_cast(kMinObjectSize) - || (cell->size & (kAlignment - 1)) != 0 - || cell->owner != &hd - || (cell->next != nullptr && cell->next->prev != cell)) { - return -1; - } - total += cell->size; - if (total <= 0 || total > hd.size) { - return -1; - } - } - - if (hd.freeList != nullptr && hd.freeList->prev != nullptr) { - return -1; - } - - for (Cell* cell = hd.freeList; cell != nullptr; cell = cell->next) { - if (!inArena(cell) - || (reinterpret_cast(cell) & (kAlignment - 1)) != 0 - || cell->size < static_cast(kMinObjectSize) - || (cell->size & (kAlignment - 1)) != 0 - || cell->owner != nullptr - || (cell->next != nullptr && cell->next->prev != cell)) { - return -1; - } - if (cell->next != nullptr) { - if (reinterpret_cast(cell) + static_cast(cell->size) - > reinterpret_cast(cell->next)) { - return -1; - } - } - - total += cell->size; - freeBytes += cell->size - static_cast(kHeaderSize); - if (total <= 0 || total > hd.size) { - return -1; - } - } - - if (total != hd.size) { - return -1; - } - return freeBytes; -} - -u32 OSReferentSize(void* ptr) { - if (ptr == nullptr || !inArena(ptr) || (reinterpret_cast(ptr) & (kAlignment - 1)) != 0) { - return 0; - } - auto* cell = reinterpret_cast(reinterpret_cast(ptr) - kHeaderSize); - if (cell->owner == nullptr) { - return 0; - } - return static_cast(cell->size - static_cast(kHeaderSize)); -} - -void OSDumpHeap(OSHeapHandle heap) { - AllocLog.info("OSDumpHeap({})", heap); - if (!validHeapHandle(heap)) { - AllocLog.info("--------Invalid"); - return; - } - - auto& hd = sHeapArray[heap]; - if (OSCheckHeap(heap) < 0) { - AllocLog.info("--------Broken"); - return; - } - - AllocLog.info("addr\tsize\t\tend\t\tprev\t\tnext"); - AllocLog.info("--------Allocated"); - for (Cell* cell = hd.allocated; cell != nullptr; cell = cell->next) { - AllocLog.info("{}\t{}\t{}\t{}\t{}", - reinterpret_cast(cell), - cell->size, - reinterpret_cast(reinterpret_cast(cell) + cell->size), - reinterpret_cast(cell->prev), - reinterpret_cast(cell->next)); - } - - AllocLog.info("--------Free"); - for (Cell* cell = hd.freeList; cell != nullptr; cell = cell->next) { - AllocLog.info("{}\t{}\t{}\t{}\t{}", - reinterpret_cast(cell), - cell->size, - reinterpret_cast(reinterpret_cast(cell) + cell->size), - reinterpret_cast(cell->prev), - reinterpret_cast(cell->next)); - } -} - -void OSVisitAllocated(void (*visitor)(void*, u32)) { - if (visitor == nullptr || sHeapArray == nullptr) { - return; - } - - for (int heap = 0; heap < sNumHeaps; ++heap) { - auto& hd = sHeapArray[heap]; - if (hd.size < 0) { - continue; - } - for (Cell* cell = hd.allocated; cell != nullptr; cell = cell->next) { - visitor(reinterpret_cast(cell) + kHeaderSize, - static_cast(cell->size - static_cast(kHeaderSize))); - } - } -} - -} // extern "C" diff --git a/aurora-main/lib/dolphin/os/OSArena.cpp b/aurora-main/lib/dolphin/os/OSArena.cpp deleted file mode 100644 index 5eeb861..0000000 --- a/aurora-main/lib/dolphin/os/OSArena.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include - -#include "internal.hpp" - -#include - -#define ROUND64(n, a) (((u64)(n) + (a)-1) & ~(u64)((a)-1)) -#define TRUNC64(n, a) (((u64)(n)) & ~(u64)((a)-1)) - -static void* ArenaLow; -static void* ArenaHigh; - -void* OSGetArenaHi() { - return ArenaHigh; -} - -void* OSGetArenaLo() { - return ArenaLow; -} - -void OSSetArenaHi(void* newHi) { - assert(newHi <= MEM1End && newHi >= MEM1Start); - ArenaHigh = newHi; -} - -void OSSetArenaLo(void* newLo) { - assert(newLo <= MEM1End && newLo >= MEM1Start); - ArenaLow = newLo; -} - -void* OSAllocFromArenaLo(const u32 size, const u32 align) { - void* ptr = OSGetArenaLo(); - auto arenaLo = static_cast(ptr = reinterpret_cast(ROUND64(ptr, align))); - arenaLo += size; - arenaLo = reinterpret_cast(ROUND64(arenaLo, align)); - OSSetArenaLo(arenaLo); - return ptr; -} - -void* OSAllocFromArenaHi(const u32 size, const u32 align) { - void* ptr; - - auto arenaHi = static_cast(OSGetArenaHi()); - arenaHi = reinterpret_cast(TRUNC64(arenaHi, align)); - arenaHi -= size; - arenaHi = static_cast(ptr = reinterpret_cast(TRUNC64(arenaHi, align))); - OSSetArenaHi(arenaHi); - return ptr; -} - -void AuroraInitArena() { - if (MEM1Start == nullptr) { - return; - } - - OSSetArenaLo(static_cast(MEM1Start) + ARENA_START_OFFSET); - OSSetArenaHi(MEM1End); -} diff --git a/aurora-main/lib/dolphin/os/OSBootInfo.cpp b/aurora-main/lib/dolphin/os/OSBootInfo.cpp deleted file mode 100644 index e13af46..0000000 --- a/aurora-main/lib/dolphin/os/OSBootInfo.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "internal.hpp" -#include - -void AuroraFillBootInfo() { - if (OSBaseAddress == 0) { - return; - } - - const auto info = static_cast(OSPhysicalToCached(0)); - - info->memorySize = aurora::g_config.mem1Size; -} diff --git a/aurora-main/lib/dolphin/os/OSInit.cpp b/aurora-main/lib/dolphin/os/OSInit.cpp deleted file mode 100644 index 361dd32..0000000 --- a/aurora-main/lib/dolphin/os/OSInit.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "internal.hpp" - -#include - -static bool AlreadyInitialized; - -void OSInit() { - if (AlreadyInitialized) { - return; - } - - AlreadyInitialized = true; - - AuroraOSInitMemory(); - AuroraFillBootInfo(); - AuroraInitClock(); - AuroraInitArena(); -} diff --git a/aurora-main/lib/dolphin/os/OSMemory.cpp b/aurora-main/lib/dolphin/os/OSMemory.cpp deleted file mode 100644 index dc5c429..0000000 --- a/aurora-main/lib/dolphin/os/OSMemory.cpp +++ /dev/null @@ -1,148 +0,0 @@ -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#define NOMINMAX -#include -#endif - -#include "fmt/base.h" - -#include - -#include "internal.hpp" -#include -#include "dolphin/types.h" - -#if !NDEBUG && (INTPTR_MAX > INT32_MAX) -#define GUARD_MEMORY 1 -#endif - -uintptr_t OSBaseAddress = 0; - -void* MEM1Start; -void* MEM1End; - -static void GuardGCMemory(); -static void* AllocMEM1(u32 size); - -void AuroraOSInitMemory() { - GuardGCMemory(); - - if (aurora::g_config.mem1Size > 0) { - MEM1Start = AllocMEM1(aurora::g_config.mem1Size); - MEM1End = reinterpret_cast(reinterpret_cast(MEM1Start) + aurora::g_config.mem1Size); - OSBaseAddress = reinterpret_cast(MEM1Start); - } -} - -#if GUARD_MEMORY -static uintptr_t GetAllocationGranularity() { -#if _WIN32 - SYSTEM_INFO sysInfo; - GetSystemInfo(&sysInfo); - - return sysInfo.dwAllocationGranularity; -#else - // TODO: posix impl - return 0; -#endif -} - -static void TryGuardRegion(const uintptr_t start, const uintptr_t end, char const* const name) { -#if _WIN32 - assert(start != 0); - const auto addr = VirtualAlloc( - reinterpret_cast(start), - end - start, - MEM_RESERVE, - PAGE_NOACCESS); - - if (addr == nullptr) { - Log.debug("Unable to guard memory region: {}", name); - } else { - assert(addr == reinterpret_cast(start)); - Log.debug("Successfully guarded memory range: {:08X}-{:08X} ({})", start, end, name); - } -#else - // TODO: posix impl -#endif -} - -static void GuardGCMemory() { - // Reserve the normal GC/Wii memory map so accesses are 100% guaranteed to fail. - // https://www.gc-forever.com/yagcd/chap5.html#sec5.11 - // https://wiibrew.org/wiki/Memory_map - - // We can't quite map at address 0 (for good reasons) but we *can* map at the next granularity over! - TryGuardRegion(0x00000000 + GetAllocationGranularity(), 0x017fffff, "MEM1 Physical"); - TryGuardRegion(0x80000000, 0x817fffff, "MEM1 Logical (cached)"); - TryGuardRegion(0xC0000000, 0xC17fffff, "MEM1 Logical (uncached)"); - TryGuardRegion(0x10000000, 0x18000000, "MEM2 Physical"); - TryGuardRegion(0x90000000, 0x98000000, "MEM2 Logical (cached)"); - TryGuardRegion(0xD0000000, 0xD8000000, "MEM2 Logical (uncached)"); - TryGuardRegion(0x08000000, 0x08300000, "EFB Physical"); - TryGuardRegion(0xC8000000, 0xC8300000, "EFB Logical"); - TryGuardRegion(0x0D000000, 0x0D008000, "Hollywood HW registers Physical"); - TryGuardRegion(0xCD000000, 0xCD008000, "Hollywood HW registers Logical"); - TryGuardRegion(0x0C000000, 0x0C008020, "Broadway/GC HW registers Physical"); - TryGuardRegion(0xCC000000, 0xCC008020, "Broadway/GC HW registers Logical"); - TryGuardRegion(0xe0000000, 0xe0003fff, "GC L2 cache"); - TryGuardRegion(0xfff00000, 0xffffffff, "GC IPL"); -} -#else -static void GuardGCMemory() { } -#endif - -#if _WIN64 && !NDEBUG -static void* AllocMEM1(u32 size) { - // Allocate an entire 32-bit's worth of memory and allocate the real MEM1 in that. - // This way, if a 64-bit pointer gets truncated to 32-bit, it will still fall in our guard pages. - - void* bulkChunk = VirtualAlloc( - nullptr, - 8ll * 1024 * 1024 * 1024, - MEM_RESERVE, - PAGE_NOACCESS); - - if (bulkChunk == nullptr) { - DWORD err = GetLastError(); - fmt::memory_buffer msg; - fmt::format_system_error( - msg, - static_cast(err), - "Failed to allocate bulk chunk for MEM1"); - Log.fatal("{}", fmt::to_string(msg)); - } - - uintptr_t memSpace = (reinterpret_cast(bulkChunk) | 0xFFFFFFFF) + 1; - void* mem1Address = reinterpret_cast(memSpace + 0x80000000); - - Log.debug("Reserved memory map at {:016X}-{:016X}", memSpace, memSpace + 0xFFFFFFFF); - Log.debug( - "MEM1 at {:016X}-{:016X}", - reinterpret_cast(mem1Address), - reinterpret_cast(mem1Address) + size); - - void* result = VirtualAlloc(mem1Address, size, MEM_COMMIT, PAGE_READWRITE); - if (result == nullptr) { - DWORD err = GetLastError(); - fmt::memory_buffer msg; - fmt::format_system_error( - msg, - static_cast(err), - "Failed to commit memory for MEM1"); - Log.fatal("{}", fmt::to_string(msg)); - } - - assert(result == mem1Address); - return result; -} -#else -static void* AllocMEM1(u32 size) { - return calloc(1, size); -} -#endif - -u32 OSGetPhysicalMemSize() { - const auto info = static_cast(OSPhysicalToCached(0)); - return info->memorySize; -} diff --git a/aurora-main/lib/dolphin/os/OSTime.cpp b/aurora-main/lib/dolphin/os/OSTime.cpp deleted file mode 100644 index 37689ef..0000000 --- a/aurora-main/lib/dolphin/os/OSTime.cpp +++ /dev/null @@ -1,178 +0,0 @@ -#include -#include - -#include "internal.hpp" -#include - -static const int YearDays[MONTH_MAX] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; - -static const int LeapYearDays[MONTH_MAX] = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}; - -namespace chrono = std::chrono; -using SystemTime = chrono::time_point; -using TickDuration = chrono::duration>; - -static const SystemTime startupTime = chrono::system_clock::now(); -static const chrono::time_point startupSteadyTime = chrono::steady_clock::now(); - -OSTick OSGetTick() { - return OSGetTime() & 0xFFFFFFFF; -} - -OSTime OSGetTime() { - // System time is provided in the number of timer ticks since 2000-01-01 00:00:00 - // Use time_t arithmetic to avoid chrono duration_cast overflow issues on some platforms. - - // GCN epoch: 2000-01-01 00:00:00 UTC = 946684800 seconds after Unix epoch - static constexpr s64 gcnEpochUnix = 946684800LL; - - // Get current wall-clock time - auto elapsed = chrono::steady_clock::now() - startupSteadyTime; - auto currentTime = startupTime + chrono::duration_cast(elapsed); - - // Convert to seconds since Unix epoch, then offset to GCN epoch - auto sinceUnix = chrono::duration_cast(currentTime.time_since_epoch()); - s64 totalMicros = sinceUnix.count(); - - // Apply local timezone offset - std::time_t wallClock = chrono::system_clock::to_time_t(currentTime); - std::tm localTm{}; - std::tm gmTm{}; -#if defined(_WIN32) - localtime_s(&localTm, &wallClock); - gmtime_s(&gmTm, &wallClock); -#else - localtime_r(&wallClock, &localTm); - gmtime_r(&wallClock, &gmTm); -#endif - // Compute UTC offset in seconds - s64 utcOffsetSec = static_cast(mktime(&localTm)) - static_cast(mktime(&gmTm)); - - s64 secondsSinceGcnEpoch = (totalMicros / 1000000LL) - gcnEpochUnix + utcOffsetSec; - s64 remainderMicros = totalMicros % 1000000LL; - - s64 ticksFromSeconds = secondsSinceGcnEpoch * static_cast(OS_TIMER_CLOCK); - s64 ticksFromRemainder = remainderMicros * static_cast(OS_TIMER_CLOCK) / 1000000LL; - - return ticksFromSeconds + ticksFromRemainder; -} - -void AuroraInitClock() { - if (OSBaseAddress == 0) { - return; - } - - __OSBusClock = OS_TIMER_CLOCK * OS_TIMER_CLOCK_DIVIDER; -} - - -static int IsLeapYear(int year) { - return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); -} - -static int GetYearDays(int year, int mon) { - const int* md = (IsLeapYear(year)) ? LeapYearDays : YearDays; - - return md[mon]; -} - -static int GetLeapDays(int year) { - ASSERT(0 <= year); - - if (year < 1) { - return 0; - } - return (year + 3) / 4 - (year - 1) / 100 + (year - 1) / 400; -} - -static void GetDates(int days, OSCalendarTime* td) { - int year; - int n; - int month; - const int* md; - - ASSERT(0 <= days); - - td->wday = (days + 6) % WEEK_DAY_MAX; - - for (year = days / YEAR_DAY_MAX; - days < (n = year * YEAR_DAY_MAX + GetLeapDays(year)); year--) { - ; - } - - days -= n; - td->year = year; - td->yday = days; - - md = IsLeapYear(year) ? LeapYearDays : YearDays; - for (month = MONTH_MAX; days < md[--month];) { - ; - } - td->mon = month; - td->mday = days - md[month] + 1; -} - -void OSTicksToCalendarTime(OSTime ticks, OSCalendarTime* td) { - int days; - int secs; - OSTime d; - - d = ticks % OS_SEC_TO_TICKS(1); - if (d < 0) { - d += OS_SEC_TO_TICKS(1); - ASSERT(0 <= d); - } - - td->usec = OS_TICKS_TO_USEC(d) % USEC_MAX; - td->msec = OS_TICKS_TO_MSEC(d) % MSEC_MAX; - - ASSERT(0 <= td->usec); - ASSERT(0 <= td->msec); - - ticks -= d; - - ASSERT(ticks % OSSecondsToTicks(1) == 0); - ASSERT(0 <= OSTicksToSeconds(ticks) / 86400 + BIAS && OSTicksToSeconds(ticks) / 86400 + BIAS <= INT_MAX); - - days = (OS_TICKS_TO_SEC(ticks) / SECS_IN_DAY) + BIAS; - secs = OS_TICKS_TO_SEC(ticks) % SECS_IN_DAY; - if (secs < 0) { - days -= 1; - secs += SECS_IN_DAY; - ASSERT(0 <= secs); - } - - GetDates(days, td); - td->hour = secs / 60 / 60; - td->min = secs / 60 % 60; - td->sec = secs % 60; -} - -OSTime OSCalendarTimeToTicks(OSCalendarTime* td) { - OSTime secs; - int ov_mon; - int mon; - int year; - - ov_mon = td->mon / MONTH_MAX; - mon = td->mon - (ov_mon * MONTH_MAX); - - if (mon < 0) { - mon += MONTH_MAX; - ov_mon--; - } - - ASSERT((ov_mon <= 0 && 0 <= td->year + ov_mon) || (0 < ov_mon && td->year <= INT_MAX - ov_mon)); - - year = td->year + ov_mon; - - secs = (OSTime)SECS_IN_YEAR * year + - (OSTime)SECS_IN_DAY * (GetLeapDays(year) + GetYearDays(year, mon) + td->mday - 1) + - (OSTime)SECS_IN_HOUR * td->hour + - (OSTime)SECS_IN_MIN * td->min + - td->sec - - (OSTime)0xEB1E1BF80ULL; - - return OS_SEC_TO_TICKS(secs) + OS_MSEC_TO_TICKS((OSTime)td->msec) + - OS_USEC_TO_TICKS((OSTime)td->usec); -} diff --git a/aurora-main/lib/dolphin/os/internal.hpp b/aurora-main/lib/dolphin/os/internal.hpp deleted file mode 100644 index b4311ea..0000000 --- a/aurora-main/lib/dolphin/os/internal.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "../../internal.hpp" -#include - -static aurora::Module Log("aurora::os"); - -constexpr uintptr_t ARENA_START_OFFSET = 0x4000; - -extern void* MEM1Start; -extern void* MEM1End; - -void AuroraOSInitMemory(); -void AuroraFillBootInfo(); -void AuroraInitClock(); -void AuroraInitArena(); diff --git a/aurora-main/lib/dolphin/pad/pad.cpp b/aurora-main/lib/dolphin/pad/pad.cpp deleted file mode 100644 index acdbe2a..0000000 --- a/aurora-main/lib/dolphin/pad/pad.cpp +++ /dev/null @@ -1,1860 +0,0 @@ -#include "../../fs_helper.hpp" -#include "../../input.hpp" -#include "../../internal.hpp" -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace { -constexpr int32_t k_mappingsFileVersion = 3; - -std::array g_defaultButtonsStandard{{ - {SDL_GAMEPAD_BUTTON_SOUTH, PAD_BUTTON_A}, - {SDL_GAMEPAD_BUTTON_EAST, PAD_BUTTON_B}, - {SDL_GAMEPAD_BUTTON_WEST, PAD_BUTTON_X}, - {SDL_GAMEPAD_BUTTON_NORTH, PAD_BUTTON_Y}, - {SDL_GAMEPAD_BUTTON_START, PAD_BUTTON_START}, - {SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, PAD_TRIGGER_Z}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_L}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_R}, - {SDL_GAMEPAD_BUTTON_DPAD_UP, PAD_BUTTON_UP}, - {SDL_GAMEPAD_BUTTON_DPAD_DOWN, PAD_BUTTON_DOWN}, - {SDL_GAMEPAD_BUTTON_DPAD_LEFT, PAD_BUTTON_LEFT}, - {SDL_GAMEPAD_BUTTON_DPAD_RIGHT, PAD_BUTTON_RIGHT}, -}}; - -std::array g_defaultButtonsXBox360{{ - {SDL_GAMEPAD_BUTTON_SOUTH, PAD_BUTTON_A}, - {SDL_GAMEPAD_BUTTON_EAST, PAD_BUTTON_B}, - {SDL_GAMEPAD_BUTTON_WEST, PAD_BUTTON_X}, - {SDL_GAMEPAD_BUTTON_NORTH, PAD_BUTTON_Y}, - {SDL_GAMEPAD_BUTTON_START, PAD_BUTTON_START}, - {SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, PAD_TRIGGER_Z}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_L}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_R}, - {SDL_GAMEPAD_BUTTON_DPAD_UP, PAD_BUTTON_UP}, - {SDL_GAMEPAD_BUTTON_DPAD_DOWN, PAD_BUTTON_DOWN}, - {SDL_GAMEPAD_BUTTON_DPAD_LEFT, PAD_BUTTON_LEFT}, - {SDL_GAMEPAD_BUTTON_DPAD_RIGHT, PAD_BUTTON_RIGHT}, -}}; - -std::array g_defaultButtonsXBoxOne{{ - {SDL_GAMEPAD_BUTTON_SOUTH, PAD_BUTTON_A}, - {SDL_GAMEPAD_BUTTON_EAST, PAD_BUTTON_B}, - {SDL_GAMEPAD_BUTTON_WEST, PAD_BUTTON_X}, - {SDL_GAMEPAD_BUTTON_NORTH, PAD_BUTTON_Y}, - {SDL_GAMEPAD_BUTTON_START, PAD_BUTTON_START}, - {SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, PAD_TRIGGER_Z}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_L}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_R}, - {SDL_GAMEPAD_BUTTON_DPAD_UP, PAD_BUTTON_UP}, - {SDL_GAMEPAD_BUTTON_DPAD_DOWN, PAD_BUTTON_DOWN}, - {SDL_GAMEPAD_BUTTON_DPAD_LEFT, PAD_BUTTON_LEFT}, - {SDL_GAMEPAD_BUTTON_DPAD_RIGHT, PAD_BUTTON_RIGHT}, -}}; - -std::array g_defaultButtonsPS3{{ - {SDL_GAMEPAD_BUTTON_SOUTH, PAD_BUTTON_A}, - {SDL_GAMEPAD_BUTTON_EAST, PAD_BUTTON_B}, - {SDL_GAMEPAD_BUTTON_WEST, PAD_BUTTON_X}, - {SDL_GAMEPAD_BUTTON_NORTH, PAD_BUTTON_Y}, - {SDL_GAMEPAD_BUTTON_START, PAD_BUTTON_START}, - {SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, PAD_TRIGGER_Z}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_L}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_R}, - {SDL_GAMEPAD_BUTTON_DPAD_UP, PAD_BUTTON_UP}, - {SDL_GAMEPAD_BUTTON_DPAD_DOWN, PAD_BUTTON_DOWN}, - {SDL_GAMEPAD_BUTTON_DPAD_LEFT, PAD_BUTTON_LEFT}, - {SDL_GAMEPAD_BUTTON_DPAD_RIGHT, PAD_BUTTON_RIGHT}, -}}; - -std::array g_defaultButtonsPS4{{ - {SDL_GAMEPAD_BUTTON_SOUTH, PAD_BUTTON_A}, - {SDL_GAMEPAD_BUTTON_EAST, PAD_BUTTON_B}, - {SDL_GAMEPAD_BUTTON_WEST, PAD_BUTTON_X}, - {SDL_GAMEPAD_BUTTON_NORTH, PAD_BUTTON_Y}, - {SDL_GAMEPAD_BUTTON_START, PAD_BUTTON_START}, - {SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, PAD_TRIGGER_Z}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_L}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_R}, - {SDL_GAMEPAD_BUTTON_DPAD_UP, PAD_BUTTON_UP}, - {SDL_GAMEPAD_BUTTON_DPAD_DOWN, PAD_BUTTON_DOWN}, - {SDL_GAMEPAD_BUTTON_DPAD_LEFT, PAD_BUTTON_LEFT}, - {SDL_GAMEPAD_BUTTON_DPAD_RIGHT, PAD_BUTTON_RIGHT}, -}}; - -std::array g_defaultButtonsPS5{{ - {SDL_GAMEPAD_BUTTON_SOUTH, PAD_BUTTON_A}, - {SDL_GAMEPAD_BUTTON_EAST, PAD_BUTTON_B}, - {SDL_GAMEPAD_BUTTON_WEST, PAD_BUTTON_X}, - {SDL_GAMEPAD_BUTTON_NORTH, PAD_BUTTON_Y}, - {SDL_GAMEPAD_BUTTON_START, PAD_BUTTON_START}, - {SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, PAD_TRIGGER_Z}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_L}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_R}, - {SDL_GAMEPAD_BUTTON_DPAD_UP, PAD_BUTTON_UP}, - {SDL_GAMEPAD_BUTTON_DPAD_DOWN, PAD_BUTTON_DOWN}, - {SDL_GAMEPAD_BUTTON_DPAD_LEFT, PAD_BUTTON_LEFT}, - {SDL_GAMEPAD_BUTTON_DPAD_RIGHT, PAD_BUTTON_RIGHT}, -}}; - -std::array g_defaultButtonsGamecube{{ - {SDL_GAMEPAD_BUTTON_SOUTH, PAD_BUTTON_A}, - {SDL_GAMEPAD_BUTTON_EAST, PAD_BUTTON_X}, - {SDL_GAMEPAD_BUTTON_WEST, PAD_BUTTON_B}, - {SDL_GAMEPAD_BUTTON_NORTH, PAD_BUTTON_Y}, - {SDL_GAMEPAD_BUTTON_START, PAD_BUTTON_START}, - {SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, PAD_TRIGGER_Z}, - {SDL_GAMEPAD_BUTTON_MISC3, PAD_TRIGGER_L}, - {SDL_GAMEPAD_BUTTON_MISC4, PAD_TRIGGER_R}, - {SDL_GAMEPAD_BUTTON_DPAD_UP, PAD_BUTTON_UP}, - {SDL_GAMEPAD_BUTTON_DPAD_DOWN, PAD_BUTTON_DOWN}, - {SDL_GAMEPAD_BUTTON_DPAD_LEFT, PAD_BUTTON_LEFT}, - {SDL_GAMEPAD_BUTTON_DPAD_RIGHT, PAD_BUTTON_RIGHT}, -}}; - -std::array g_defaultButtonsNSOGamecube{{ - {SDL_GAMEPAD_BUTTON_SOUTH, PAD_BUTTON_A}, - {SDL_GAMEPAD_BUTTON_EAST, PAD_BUTTON_X}, - {SDL_GAMEPAD_BUTTON_WEST, PAD_BUTTON_B}, - {SDL_GAMEPAD_BUTTON_NORTH, PAD_BUTTON_Y}, - {SDL_GAMEPAD_BUTTON_START, PAD_BUTTON_START}, - {SDL_GAMEPAD_BUTTON_BACK, PAD_TRIGGER_Z}, - {SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, PAD_TRIGGER_L}, - {SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, PAD_TRIGGER_R}, - {SDL_GAMEPAD_BUTTON_DPAD_UP, PAD_BUTTON_UP}, - {SDL_GAMEPAD_BUTTON_DPAD_DOWN, PAD_BUTTON_DOWN}, - {SDL_GAMEPAD_BUTTON_DPAD_LEFT, PAD_BUTTON_LEFT}, - {SDL_GAMEPAD_BUTTON_DPAD_RIGHT, PAD_BUTTON_RIGHT}, -}}; - -std::array g_defaultButtonsProCon{{ - {SDL_GAMEPAD_BUTTON_SOUTH, PAD_BUTTON_A}, - {SDL_GAMEPAD_BUTTON_EAST, PAD_BUTTON_B}, - {SDL_GAMEPAD_BUTTON_WEST, PAD_BUTTON_X}, - {SDL_GAMEPAD_BUTTON_NORTH, PAD_BUTTON_Y}, - {SDL_GAMEPAD_BUTTON_START, PAD_BUTTON_START}, - {SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, PAD_TRIGGER_Z}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_L}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_R}, - {SDL_GAMEPAD_BUTTON_DPAD_UP, PAD_BUTTON_UP}, - {SDL_GAMEPAD_BUTTON_DPAD_DOWN, PAD_BUTTON_DOWN}, - {SDL_GAMEPAD_BUTTON_DPAD_LEFT, PAD_BUTTON_LEFT}, - {SDL_GAMEPAD_BUTTON_DPAD_RIGHT, PAD_BUTTON_RIGHT}, -}}; - -std::array g_defaultButtonsJoyConRight{{ - {SDL_GAMEPAD_BUTTON_SOUTH, PAD_BUTTON_A}, - {SDL_GAMEPAD_BUTTON_EAST, PAD_BUTTON_B}, - {SDL_GAMEPAD_BUTTON_WEST, PAD_BUTTON_X}, - {SDL_GAMEPAD_BUTTON_NORTH, PAD_BUTTON_Y}, - {SDL_GAMEPAD_BUTTON_START, PAD_BUTTON_START}, - {SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, PAD_TRIGGER_Z}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_L}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_R}, - {SDL_GAMEPAD_BUTTON_DPAD_UP, PAD_BUTTON_UP}, - {SDL_GAMEPAD_BUTTON_DPAD_DOWN, PAD_BUTTON_DOWN}, - {SDL_GAMEPAD_BUTTON_DPAD_LEFT, PAD_BUTTON_LEFT}, - {SDL_GAMEPAD_BUTTON_DPAD_RIGHT, PAD_BUTTON_RIGHT}, -}}; - -std::array g_defaultButtonsJoyConLeft{{ - {SDL_GAMEPAD_BUTTON_SOUTH, PAD_BUTTON_A}, - {SDL_GAMEPAD_BUTTON_EAST, PAD_BUTTON_B}, - {SDL_GAMEPAD_BUTTON_WEST, PAD_BUTTON_X}, - {SDL_GAMEPAD_BUTTON_NORTH, PAD_BUTTON_Y}, - {SDL_GAMEPAD_BUTTON_START, PAD_BUTTON_START}, - {SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, PAD_TRIGGER_Z}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_L}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_R}, - {SDL_GAMEPAD_BUTTON_DPAD_UP, PAD_BUTTON_UP}, - {SDL_GAMEPAD_BUTTON_DPAD_DOWN, PAD_BUTTON_DOWN}, - {SDL_GAMEPAD_BUTTON_DPAD_LEFT, PAD_BUTTON_LEFT}, - {SDL_GAMEPAD_BUTTON_DPAD_RIGHT, PAD_BUTTON_RIGHT}, -}}; - -std::array g_defaultButtonsJoyPair{{ - {SDL_GAMEPAD_BUTTON_SOUTH, PAD_BUTTON_A}, - {SDL_GAMEPAD_BUTTON_EAST, PAD_BUTTON_B}, - {SDL_GAMEPAD_BUTTON_WEST, PAD_BUTTON_X}, - {SDL_GAMEPAD_BUTTON_NORTH, PAD_BUTTON_Y}, - {SDL_GAMEPAD_BUTTON_START, PAD_BUTTON_START}, - {SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, PAD_TRIGGER_Z}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_L}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_R}, - {SDL_GAMEPAD_BUTTON_DPAD_UP, PAD_BUTTON_UP}, - {SDL_GAMEPAD_BUTTON_DPAD_DOWN, PAD_BUTTON_DOWN}, - {SDL_GAMEPAD_BUTTON_DPAD_LEFT, PAD_BUTTON_LEFT}, - {SDL_GAMEPAD_BUTTON_DPAD_RIGHT, PAD_BUTTON_RIGHT}, -}}; - -// Wii U Pro Controllers through SDL's HIDAPI Wii driver. No SDL_GamepadType -// singles them out, so they are picked by name or USB id (see -// __PADSetDefaultMapping). Wii Remotes, with or without a Nunchuk or Classic -// Controller, are read by the game through KPAD instead and never get a -// GameCube mapping (the runtime hides those ports from PADRead). - -// Nintendo's labelled layout: A on the right accelerates, B at the bottom -// brakes. SDL's Wii driver reports ZL/ZR as the LEFT_TRIGGER/RIGHT_TRIGGER -// axes, never as shoulder buttons, so they are left unbound here and picked up -// by aurora's default axis mapping (g_defaultAxes) the same way every -// analog-trigger pad's L/R is. -std::array g_defaultButtonsWiiUPro{{ - {SDL_GAMEPAD_BUTTON_EAST, PAD_BUTTON_A}, - {SDL_GAMEPAD_BUTTON_SOUTH, PAD_BUTTON_B}, - {SDL_GAMEPAD_BUTTON_NORTH, PAD_BUTTON_X}, - {SDL_GAMEPAD_BUTTON_WEST, PAD_BUTTON_Y}, - {SDL_GAMEPAD_BUTTON_START, PAD_BUTTON_START}, - {SDL_GAMEPAD_BUTTON_BACK, PAD_TRIGGER_Z}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_L}, - {PAD_NATIVE_BUTTON_INVALID, PAD_TRIGGER_R}, - {SDL_GAMEPAD_BUTTON_DPAD_UP, PAD_BUTTON_UP}, - {SDL_GAMEPAD_BUTTON_DPAD_DOWN, PAD_BUTTON_DOWN}, - {SDL_GAMEPAD_BUTTON_DPAD_LEFT, PAD_BUTTON_LEFT}, - {SDL_GAMEPAD_BUTTON_DPAD_RIGHT, PAD_BUTTON_RIGHT}, -}}; - -std::array g_defaultKeys{{ - {PAD_KEY_INVALID, PAD_BUTTON_A}, - {PAD_KEY_INVALID, PAD_BUTTON_B}, - {PAD_KEY_INVALID, PAD_BUTTON_X}, - {PAD_KEY_INVALID, PAD_BUTTON_Y}, - {PAD_KEY_INVALID, PAD_BUTTON_START}, - {PAD_KEY_INVALID, PAD_TRIGGER_Z}, - {PAD_KEY_INVALID, PAD_TRIGGER_L}, - {PAD_KEY_INVALID, PAD_TRIGGER_R}, - {PAD_KEY_INVALID, PAD_BUTTON_UP}, - {PAD_KEY_INVALID, PAD_BUTTON_DOWN}, - {PAD_KEY_INVALID, PAD_BUTTON_LEFT}, - {PAD_KEY_INVALID, PAD_BUTTON_RIGHT}, -}}; - -std::array g_defaultKeyAxis{{ - {PAD_KEY_INVALID, PAD_AXIS_LEFT_X_POS, 0}, - {PAD_KEY_INVALID, PAD_AXIS_LEFT_X_NEG, 0}, - {PAD_KEY_INVALID, PAD_AXIS_LEFT_Y_POS, 0}, - {PAD_KEY_INVALID, PAD_AXIS_LEFT_Y_NEG, 0}, - {PAD_KEY_INVALID, PAD_AXIS_RIGHT_X_POS, 0}, - {PAD_KEY_INVALID, PAD_AXIS_RIGHT_X_NEG, 0}, - {PAD_KEY_INVALID, PAD_AXIS_RIGHT_Y_POS, 0}, - {PAD_KEY_INVALID, PAD_AXIS_RIGHT_Y_NEG, 0}, - {PAD_KEY_INVALID, PAD_AXIS_TRIGGER_L, 0}, - {PAD_KEY_INVALID, PAD_AXIS_TRIGGER_R, 0}, -}}; - -std::array g_defaultAxes{{ - {{SDL_GAMEPAD_AXIS_LEFTX, AXIS_SIGN_POSITIVE}, SDL_GAMEPAD_BUTTON_INVALID, PAD_AXIS_LEFT_X_POS}, - {{SDL_GAMEPAD_AXIS_LEFTX, AXIS_SIGN_NEGATIVE}, SDL_GAMEPAD_BUTTON_INVALID, PAD_AXIS_LEFT_X_NEG}, - // SDL's gamepad y-axis is inverted from GC's - {{SDL_GAMEPAD_AXIS_LEFTY, AXIS_SIGN_NEGATIVE}, SDL_GAMEPAD_BUTTON_INVALID, PAD_AXIS_LEFT_Y_POS}, - {{SDL_GAMEPAD_AXIS_LEFTY, AXIS_SIGN_POSITIVE}, SDL_GAMEPAD_BUTTON_INVALID, PAD_AXIS_LEFT_Y_NEG}, - {{SDL_GAMEPAD_AXIS_RIGHTX, AXIS_SIGN_POSITIVE}, SDL_GAMEPAD_BUTTON_INVALID, PAD_AXIS_RIGHT_X_POS}, - {{SDL_GAMEPAD_AXIS_RIGHTX, AXIS_SIGN_NEGATIVE}, SDL_GAMEPAD_BUTTON_INVALID, PAD_AXIS_RIGHT_X_NEG}, - // see above - {{SDL_GAMEPAD_AXIS_RIGHTY, AXIS_SIGN_NEGATIVE}, SDL_GAMEPAD_BUTTON_INVALID, PAD_AXIS_RIGHT_Y_POS}, - {{SDL_GAMEPAD_AXIS_RIGHTY, AXIS_SIGN_POSITIVE}, SDL_GAMEPAD_BUTTON_INVALID, PAD_AXIS_RIGHT_Y_NEG}, - {{SDL_GAMEPAD_AXIS_LEFT_TRIGGER, AXIS_SIGN_POSITIVE}, SDL_GAMEPAD_BUTTON_INVALID, PAD_AXIS_TRIGGER_L}, - {{SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, AXIS_SIGN_POSITIVE}, SDL_GAMEPAD_BUTTON_INVALID, PAD_AXIS_TRIGGER_R}, -}}; - -template -constexpr const std::array& toStdArray(const T (&array)[N]) { - static_assert(sizeof(array) == sizeof(std::array)); - return reinterpret_cast&>(array); -} - -struct PADKeyboardState { - std::array m_buttonMapping{}; - std::array m_axisMapping{}; - bool m_mappingsSet = false; -}; - -std::array g_keyboardBindings; - -struct PADCLampRegion { - uint8_t minTrigger; - uint8_t maxTrigger; - int8_t minStick; - int8_t maxStick; - int8_t xyStick; - int8_t minSubstick; - int8_t maxSubstick; - int8_t xySubstick; - int8_t radStick; - int8_t radSubstick; -}; - -constexpr PADCLampRegion ClampRegion{ - // Triggers - 30, - 180, - - // Left stick - 15, - 72, - 40, - - // Right stick - 15, - 59, - 31, - - // Stick radii - 56, - 44, -}; - -bool g_initialized; -bool g_keyboardBindingsLoaded = false; -std::atomic_bool g_blockPAD{false}; -bool g_suppressHeldOnRead = false; -std::array g_suppressedButtons{}; -std::array g_suppressLeftTrigger{}; -std::array g_suppressRightTrigger{}; - -bool is_mouse_scancode(const s32 scancode) { return scancode < PAD_KEY_INVALID; } -bool is_native_binding_pressed(SDL_Gamepad* gamepad, u32 binding) { - if (PADIsAxisButton(binding)) { - const u32 axis = PADAxisButtonAxis(binding); - const u32 threshold = PADAxisButtonThreshold(binding); - if (axis >= SDL_GAMEPAD_AXIS_COUNT || threshold < 1 || threshold > 100) return false; - int value = SDL_GetGamepadAxis(gamepad, static_cast(axis)); - if (PADAxisButtonNegative(binding)) value = -value; - return value > 0 && value * 100 >= static_cast(threshold) * 32767; - } - return binding < SDL_GAMEPAD_BUTTON_COUNT && - SDL_GetGamepadButton(gamepad, static_cast(binding)); -} -bool is_mouse_button_pressed(const s32 scancode) { - const int32_t buttonNum = -(scancode + 1); - if (buttonNum < 1 || buttonNum > 5) { - return false; - } - float x, y; - const auto buttons = SDL_GetMouseState(&x, &y); - return (buttons & 1u << (buttonNum - 1)) != 0u; -} -} // namespace - -void PADSetSpec(u32 spec [[maybe_unused]]) {} - -static void load_keyboard_bindings(); -static void save_keyboard_bindings(); - -// ReSharper disable once CppDFAConstantFunctionResult -BOOL PADInit() { - if (g_initialized) { - return true; - } - g_initialized = true; - - std::for_each(g_keyboardBindings.begin(), g_keyboardBindings.end(), [](auto& state) { - state.m_buttonMapping = g_defaultKeys; - state.m_axisMapping = g_defaultKeyAxis; - }); - - return true; -} - -BOOL PADRecalibrate(u32 mask [[maybe_unused]]) { return true; } - -BOOL PADReset(u32 mask [[maybe_unused]]) { return true; } - -void PADSetAnalogMode(u32 mode [[maybe_unused]]) {} - -aurora::input::GameController* __PADGetControllerForIndex(const u32 idx) /* NOLINT(*-reserved-identifier) */ -{ - if (idx >= aurora::input::g_GameControllers.size()) { - return nullptr; - } - - uint32_t tmp = 0; - auto iter = aurora::input::g_GameControllers.begin(); - while (tmp < idx) { - ++iter; - ++tmp; - } - if (iter == aurora::input::g_GameControllers.end()) { - return nullptr; - } - - return &iter->second; -} - -u32 PADCount() { return aurora::input::g_GameControllers.size(); } - -const char* PADGetNameForControllerIndex(const u32 idx) { - const auto* ctrl = __PADGetControllerForIndex(idx); - if (ctrl == nullptr) { - return nullptr; - } - - return SDL_GetGamepadName(ctrl->m_controller); -} - -void PADSetPortForIndex(const u32 idx, const u32 port) { - if (port >= PAD_MAX_CONTROLLERS) return; - const auto* ctrl = __PADGetControllerForIndex(idx); - if (ctrl == nullptr) { - return; - } - - const int32_t oldPort = aurora::input::player_index(ctrl->m_index); - if (const auto* dest = aurora::input::get_controller_for_player(port); dest != nullptr && dest != ctrl) { - aurora::input::set_player_index(dest->m_index, -1); - } - if (oldPort >= 0 && oldPort != port) { - aurora::input::persist_controller_for_player(oldPort, nullptr); - } - aurora::input::set_player_index(ctrl->m_index, static_cast(port)); - aurora::input::persist_controller_for_player(port, ctrl); -} - -int32_t PADGetIndexForPort(const u32 port) { - const auto* ctrl = aurora::input::get_controller_for_player(port); - if (ctrl == nullptr) { - return -1; - } - int32_t index = 0; - for (auto iter = aurora::input::g_GameControllers.begin(); iter != aurora::input::g_GameControllers.end(); - ++iter, ++index) { - if (&iter->second == ctrl) { - break; - } - } - - return index; -} - -void PADClearPort(const u32 port) { - aurora::input::persist_controller_for_player(port, nullptr); - const auto* ctrl = aurora::input::get_controller_for_player(port); - if (ctrl == nullptr) { - return; - } - aurora::input::set_player_index(ctrl->m_index, -1); -} - -// Secondary bindings live only in memory; the runtime re-applies them from its -// config after every (re)load, so any mapping reset also clears them. -static void reset_alt_button_mapping(aurora::input::GameController* controller) { - for (size_t i = 0; i < PAD_BUTTON_COUNT; ++i) { - controller->m_altButtonMapping[i] = {PAD_NATIVE_BUTTON_INVALID, controller->m_buttonMapping[i].padButton}; - } -} - -// SDL's hidapi Wii driver names the pad "Nintendo Wii U Pro Controller"; the -// other names it produces are Wii Remotes, which the game reads through KPAD -// and which therefore never take a GameCube mapping. The Linux kernel driver's -// "Nintendo Wii Remote Pro Controller" is only recognised by its USB id. -static bool wii_default_mapping(const aurora::input::GameController* controller, - std::array& out) { - const char* name = SDL_GetGamepadName(controller->m_controller); - const bool wiiUProId = SDL_GetGamepadVendor(controller->m_controller) == 0x057e && - SDL_GetGamepadProduct(controller->m_controller) == 0x0330; - if (!wiiUProId && (name == nullptr || SDL_strstr(name, "Wii U Pro Controller") == nullptr)) { - return false; - } - out = g_defaultButtonsWiiUPro; - return true; -} - -// Picks the default button table for a controller by name (Wii pads) or SDL gamepad type. -void __PADSetDefaultMapping(aurora::input::GameController* controller) /* NOLINT(*-reserved-identifier) */ -{ - if (wii_default_mapping(controller, controller->m_buttonMapping)) { - reset_alt_button_mapping(controller); - return; - } - switch (SDL_GetGamepadType(controller->m_controller)) { - case SDL_GAMEPAD_TYPE_XBOX360: - controller->m_buttonMapping = g_defaultButtonsXBox360; - break; - case SDL_GAMEPAD_TYPE_XBOXONE: - controller->m_buttonMapping = g_defaultButtonsXBoxOne; - break; - case SDL_GAMEPAD_TYPE_STANDARD: - controller->m_buttonMapping = g_defaultButtonsStandard; - break; - case SDL_GAMEPAD_TYPE_PS3: - controller->m_buttonMapping = g_defaultButtonsPS3; - break; - case SDL_GAMEPAD_TYPE_PS4: - controller->m_buttonMapping = g_defaultButtonsPS4; - break; - case SDL_GAMEPAD_TYPE_PS5: - controller->m_buttonMapping = g_defaultButtonsPS5; - break; - case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO: - if (controller->m_pid == 0x2073) { - controller->m_buttonMapping = g_defaultButtonsNSOGamecube; - } else { - controller->m_buttonMapping = g_defaultButtonsProCon; - } - break; - case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT: - controller->m_buttonMapping = g_defaultButtonsJoyConRight; - break; - case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT: - controller->m_buttonMapping = g_defaultButtonsJoyConLeft; - break; - case SDL_GAMEPAD_TYPE_GAMECUBE: - controller->m_buttonMapping = g_defaultButtonsGamecube; - break; - default: - controller->m_buttonMapping = g_defaultButtonsStandard; - break; - } - reset_alt_button_mapping(controller); -} - -static bool is_valid_native_axis(const PADSignedNativeAxis axis) { - return axis.nativeAxis == -1 || - (axis.nativeAxis >= 0 && axis.nativeAxis < SDL_GAMEPAD_AXIS_COUNT && - (axis.sign == AXIS_SIGN_POSITIVE || axis.sign == AXIS_SIGN_NEGATIVE)); -} - -static PADDeadZones default_dead_zones(const aurora::input::GameController& controller) { - return { - .emulateTriggers = !(controller.m_isGameCube || - (SDL_GetGamepadType(controller.m_controller) == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO && - controller.m_pid == 0x2073)), - .useDeadzones = true, - .stickDeadZone = 8000, - .substickDeadZone = 8000, - .leftTriggerActivationZone = 31150, - .rightTriggerActivationZone = 31150, - }; -} - -static void sanitize_dead_zones(aurora::input::GameController* controller, const int32_t playerIndex) { - PADDeadZones& deadZones = controller->m_deadZones; - const bool invalid = - deadZones.stickDeadZone > SDL_JOYSTICK_AXIS_MAX || deadZones.substickDeadZone > SDL_JOYSTICK_AXIS_MAX || - deadZones.leftTriggerActivationZone > SDL_JOYSTICK_AXIS_MAX || - deadZones.rightTriggerActivationZone > SDL_JOYSTICK_AXIS_MAX; - if (!invalid) { - return; - } - - aurora::input::Log.warn("__PADLoadMapping port={}: invalid deadzone data in file, resetting to defaults", - playerIndex); - deadZones = default_dead_zones(*controller); -} - -void __PADLoadMapping(aurora::input::GameController* controller) /* NOLINT(*-reserved-identifier) */ { - int32_t playerIndex = SDL_GetGamepadPlayerIndex(controller->m_controller); - if (playerIndex == -1) { - return; - } - - const std::filesystem::path basePath = fs_path_from_string(aurora::g_config.userPath); - if (!controller->m_mappingLoaded) { - __PADSetDefaultMapping(controller); - controller->m_axisMapping = g_defaultAxes; - } - - controller->m_mappingLoaded = true; - - const auto path = fs_path_to_string( - basePath / fmt::format("{}_{:04X}_{:04X}.controller", PADGetName(playerIndex), controller->m_vid, - controller->m_pid)); - SDL_IOStream* file = SDL_IOFromFile(path.c_str(), "rb"); - if (file == nullptr) { - return; - } - - uint32_t magic = 0; - SDL_ReadU32LE(file, &magic); - if (magic != SBIG('CTRL')) { - aurora::input::Log.warn("Invalid controller mapping magic!"); - SDL_CloseIO(file); - return; - } - - uint32_t version = 0; - SDL_ReadU32LE(file, &version); - if (version != k_mappingsFileVersion) { - aurora::input::Log.warn("Invalid controller mapping version! (Expected {0}, found {1})", k_mappingsFileVersion, - version); - SDL_CloseIO(file); - return; - } - - bool isGameCube = false; - SDL_ReadIO(file, &isGameCube, sizeof(bool)); - SDL_SeekIO(file, SDL_TellIO(file) + 31 & ~31, SDL_IO_SEEK_SET); - const auto dataStart = SDL_TellIO(file); - if (dataStart == -1) { - aurora::input::Log.warn("Unable to seek in controller bindings! Path: \"{}\"", path); - SDL_CloseIO(file); - return; - } - if (isGameCube) { - constexpr uint32_t dzSecLen = sizeof(PADDeadZones); - constexpr uint32_t btnSecLen = sizeof(PADButtonMapping) * PAD_BUTTON_COUNT; - constexpr uint32_t axisSecLen = sizeof(PADAxisMapping) * PAD_AXIS_COUNT; - SDL_SeekIO(file, dataStart + (dzSecLen + btnSecLen + axisSecLen) * playerIndex, SDL_IO_SEEK_SET); - } - - SDL_ReadIO(file, &controller->m_deadZones, sizeof(PADDeadZones)); - SDL_ReadIO(file, &controller->m_buttonMapping, sizeof(PADButtonMapping) * PAD_BUTTON_COUNT); - SDL_ReadIO(file, &controller->m_axisMapping, sizeof(PADAxisMapping) * PAD_AXIS_COUNT); - if (!isGameCube) { - SDL_ReadIO(file, &controller->m_rumbleIntensityLow, sizeof(u16)); - SDL_ReadIO(file, &controller->m_rumbleIntensityHigh, sizeof(u16)); - } - SDL_CloseIO(file); - sanitize_dead_zones(controller, playerIndex); - - bool axisCorrupt = false; - for (uint32_t i = 0; i < PAD_AXIS_COUNT; ++i) { - if (controller->m_axisMapping[i].padAxis != static_cast(i) || - !is_valid_native_axis(controller->m_axisMapping[i].nativeAxis)) { - axisCorrupt = true; - break; - } - } - if (axisCorrupt) { - aurora::input::Log.warn("__PADLoadMapping port={}: corrupt axis data in file, resetting axes to defaults", - playerIndex); - controller->m_axisMapping = g_defaultAxes; - } - - bool buttonCorrupt = false; - for (uint32_t i = 0; i < PAD_BUTTON_COUNT; ++i) { - if (controller->m_buttonMapping[i].padButton == 0) { - buttonCorrupt = true; - break; - } - } - if (buttonCorrupt) { - aurora::input::Log.warn("__PADLoadMapping port={}: corrupt button data in file, resetting buttons to defaults", - playerIndex); - __PADSetDefaultMapping(controller); - } - reset_alt_button_mapping(controller); -} - -static void EnsureMappingLoaded(aurora::input::GameController* controller) { - if (!controller->m_mappingLoaded) { - __PADLoadMapping(controller); - } -} - -static Sint16 _get_axis_value(const aurora::input::GameController* controller, // NOLINT(*-reserved-identifier) - PADAxis axis) { - const auto iter = std::find_if(controller->m_axisMapping.begin(), controller->m_axisMapping.end(), - [axis](const auto& pair) { return pair.padAxis == axis; }); - if (iter == controller->m_axisMapping.end()) { - return 0; - } - - if (iter->nativeAxis.nativeAxis != -1) { - const auto [nativeAxis, sign] = iter->nativeAxis; - const auto value = SDL_GetGamepadAxis(controller->m_controller, static_cast(nativeAxis)); - if (sign == AXIS_SIGN_POSITIVE) { - return value > 0 ? value : 0; - } - if (value >= 0) { - return 0; - } - // Clamp before negating so SDL's -32768 minimum fits in Sint16. - return static_cast(value == SDL_JOYSTICK_AXIS_MIN ? SDL_JOYSTICK_AXIS_MAX : -value); - } - - assert(iter->nativeButton != -1); - if (SDL_GetGamepadButton(controller->m_controller, static_cast(iter->nativeButton))) { - return SDL_JOYSTICK_AXIS_MAX; - } - return 0; -} - -static void neutralize_status(PADStatus& status) { - status.button = 0; - status.stickX = 0; - status.stickY = 0; - status.substickX = 0; - status.substickY = 0; - status.triggerLeft = 0; - status.triggerRight = 0; - status.analogA = 0; - status.analogB = 0; -} - -static void apply_unblock_suppression(PADStatus& status, const u32 port, const bool captureHeldInput) { - if (captureHeldInput) { - g_suppressedButtons[port] |= status.button; - g_suppressLeftTrigger[port] = g_suppressLeftTrigger[port] || status.triggerLeft > ClampRegion.minTrigger; - g_suppressRightTrigger[port] = g_suppressRightTrigger[port] || status.triggerRight > ClampRegion.minTrigger; - } - - g_suppressedButtons[port] &= status.button; - status.button &= ~g_suppressedButtons[port]; - - if (g_suppressLeftTrigger[port]) { - if (status.triggerLeft <= ClampRegion.minTrigger) { - g_suppressLeftTrigger[port] = false; - } else { - status.triggerLeft = 0; - } - } - - if (g_suppressRightTrigger[port]) { - if (status.triggerRight <= ClampRegion.minTrigger) { - g_suppressRightTrigger[port] = false; - } else { - status.triggerRight = 0; - } - } -} - -u32 PADRead(PADStatus* status) { - if (!g_keyboardBindingsLoaded) { - g_keyboardBindingsLoaded = true; - load_keyboard_bindings(); - } - - int numKeys = 0; - const bool* kbState = SDL_GetKeyboardState(&numKeys); - const bool inputBlocked = g_blockPAD.load(std::memory_order_acquire); - const bool captureHeldInput = g_suppressHeldOnRead && !inputBlocked; - g_suppressHeldOnRead = false; - - uint32_t rumbleSupport = 0; - for (uint32_t i = 0; i < PAD_CHANMAX; ++i) { - memset(&status[i], 0, sizeof(PADStatus)); - auto controller = aurora::input::get_controller_for_player(i); - if (controller == nullptr && !g_keyboardBindings[i].m_mappingsSet) { - status[i].err = PAD_ERR_NO_CONTROLLER; - g_suppressedButtons[i] = 0; - g_suppressLeftTrigger[i] = false; - g_suppressRightTrigger[i] = false; - continue; - } - - status[i].err = PAD_ERR_NONE; - if (g_keyboardBindings[i].m_mappingsSet && SDL_GetKeyboardFocus() != nullptr) { - std::for_each(g_keyboardBindings[i].m_buttonMapping.begin(), g_keyboardBindings[i].m_buttonMapping.end(), - [&kbState, &numKeys, &i, &status](const PADKeyButtonBinding& mapping) { - if (mapping.scancode > PAD_KEY_INVALID && mapping.scancode < numKeys && kbState[mapping.scancode]) { - status[i].button |= mapping.padButton; - } else if (is_mouse_scancode(mapping.scancode) && is_mouse_button_pressed(mapping.scancode)) { - status[i].button |= mapping.padButton; - } - }); - - int lx = 0, ly = 0, rx = 0, ry = 0, tl = 0, tr = 0; - for (const auto& binding : g_keyboardBindings[i].m_axisMapping) { - bool pressed = false; - if (binding.scancode > PAD_KEY_INVALID) { - pressed = binding.scancode < numKeys && kbState[binding.scancode]; - } else if (is_mouse_scancode(binding.scancode)) { - pressed = is_mouse_button_pressed(binding.scancode); - } - if (!pressed) { - continue; - } - switch (binding.padAxis) { - case PAD_AXIS_LEFT_X_POS: - lx += 127; - break; - case PAD_AXIS_LEFT_X_NEG: - lx -= 127; - break; - case PAD_AXIS_LEFT_Y_POS: - ly += 127; - break; - case PAD_AXIS_LEFT_Y_NEG: - ly -= 127; - break; - case PAD_AXIS_RIGHT_X_POS: - rx += 127; - break; - case PAD_AXIS_RIGHT_X_NEG: - rx -= 127; - break; - case PAD_AXIS_RIGHT_Y_POS: - ry += 127; - break; - case PAD_AXIS_RIGHT_Y_NEG: - ry -= 127; - break; - case PAD_AXIS_TRIGGER_L: - tl += 255; - break; - case PAD_AXIS_TRIGGER_R: - tr += 255; - break; - default: - break; - } - } - status[i].stickX = static_cast(std::clamp(static_cast(status[i].stickX) + lx, -127, 127)); - status[i].stickY = static_cast(std::clamp(static_cast(status[i].stickY) + ly, -127, 127)); - status[i].substickX = static_cast(std::clamp(static_cast(status[i].substickX) + rx, -127, 127)); - status[i].substickY = static_cast(std::clamp(static_cast(status[i].substickY) + ry, -127, 127)); - status[i].triggerLeft = static_cast(std::min(static_cast(status[i].triggerLeft) + tl, 255)); - status[i].triggerRight = static_cast(std::min(static_cast(status[i].triggerRight) + tr, 255)); - } - - if (controller && !g_keyboardBindings[i].m_mappingsSet) { - EnsureMappingLoaded(controller); - - // Wii U Pro Controller raw D-pad fallback. SDL's HIDAPI Wii driver posts - // the D-pad as joystick buttons 11-14 (the SDL_GAMEPAD_BUTTON_DPAD_* - // values) and never as a hat, but the mapping SDL generates for HIDAPI - // pads binds the D-pad to hat 0, so SDL_GetGamepadButton(DPAD_*) stays - // false. Keep this restricted to the Wii driver's pad so raw button - // indices don't interfere with other controller types. - const char* name = SDL_GetGamepadName(controller->m_controller); - const bool isWiiUPro = name != nullptr && SDL_strstr(name, "Wii U Pro Controller") != nullptr; - - if (isWiiUPro) { - SDL_Joystick* joystick = - SDL_GetGamepadJoystick(controller->m_controller); - - uint32_t raw = 0; - const int buttonCount = SDL_GetNumJoystickButtons(joystick); - - for (int b = 0; b < buttonCount && b < 32; ++b) { - if (SDL_GetJoystickButton(joystick, b)) { - raw |= (1u << b); - } - } - - // Up = button 11 - if (raw & (1u << 11)) { - status[i].button |= PAD_BUTTON_UP; - } - // Down = button 12 - if (raw & (1u << 12)) { - status[i].button |= PAD_BUTTON_DOWN; - } - // Left = button 13 - if (raw & (1u << 13)) { - status[i].button |= PAD_BUTTON_LEFT; - } - // Right = button 14 - if (raw & (1u << 14)) { - status[i].button |= PAD_BUTTON_RIGHT; - } - } - - bool leftTriggerSet = false; - bool rightTriggerSet = false; - std::for_each(controller->m_buttonMapping.begin(), controller->m_buttonMapping.end(), - [&controller, &i, &status, &leftTriggerSet, &rightTriggerSet](const auto& mapping) { - if (is_native_binding_pressed(controller->m_controller, mapping.nativeButton)) { - status[i].button |= mapping.padButton; - } - - if (mapping.padButton == PAD_TRIGGER_L && mapping.nativeButton != PAD_NATIVE_BUTTON_INVALID) { - leftTriggerSet = true; - } - if (mapping.padButton == PAD_TRIGGER_R && mapping.nativeButton != PAD_NATIVE_BUTTON_INVALID) { - rightTriggerSet = true; - } - }); - - std::for_each(controller->m_altButtonMapping.begin(), controller->m_altButtonMapping.end(), - [&controller, &i, &status, &leftTriggerSet, &rightTriggerSet](const auto& mapping) { - if (mapping.nativeButton == PAD_NATIVE_BUTTON_INVALID) { - return; - } - if (is_native_binding_pressed(controller->m_controller, mapping.nativeButton)) { - status[i].button |= mapping.padButton; - } - - if (mapping.padButton == PAD_TRIGGER_L) { - leftTriggerSet = true; - } - if (mapping.padButton == PAD_TRIGGER_R) { - rightTriggerSet = true; - } - }); - - - // TODO: Add serializable mappings for these (probably not necessary)? - static constexpr std::array, PAD_EXT_BUTTON_COUNT> kExtButtonMappings{{ - {SDL_GAMEPAD_BUTTON_BACK, PAD_BUTTON_BACK}, - {SDL_GAMEPAD_BUTTON_GUIDE, PAD_BUTTON_GUIDE}, - {SDL_GAMEPAD_BUTTON_MISC1, PAD_BUTTON_MISC1}, - {SDL_GAMEPAD_BUTTON_MISC2, PAD_BUTTON_MISC2}, - {SDL_GAMEPAD_BUTTON_MISC3, PAD_BUTTON_MISC3}, - {SDL_GAMEPAD_BUTTON_MISC4, PAD_BUTTON_MISC4}, - {SDL_GAMEPAD_BUTTON_MISC5, PAD_BUTTON_MISC5}, - {SDL_GAMEPAD_BUTTON_MISC6, PAD_BUTTON_MISC6}, - {SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1, PAD_BUTTON_RIGHT_PADDLE1}, - {SDL_GAMEPAD_BUTTON_LEFT_PADDLE1, PAD_BUTTON_LEFT_PADDLE1}, - {SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2, PAD_BUTTON_RIGHT_PADDLE2}, - {SDL_GAMEPAD_BUTTON_LEFT_PADDLE2, PAD_BUTTON_LEFT_PADDLE2}, - {SDL_GAMEPAD_BUTTON_RIGHT_STICK, PAD_BUTTON_RIGHT_STICK}, - {SDL_GAMEPAD_BUTTON_LEFT_STICK, PAD_BUTTON_LEFT_STICK}, - {SDL_GAMEPAD_BUTTON_TOUCHPAD, PAD_BUTTON_TOUCHPAD}, - }}; - - for (const auto& [native, button] : kExtButtonMappings) { - if (SDL_GetGamepadButton(controller->m_controller, native)) { - status[i].extButton |= button; - } - } - - const auto xlPos = _get_axis_value(controller, PAD_AXIS_LEFT_X_POS); - const auto xlNeg = _get_axis_value(controller, PAD_AXIS_LEFT_X_NEG); - const auto ylPos = _get_axis_value(controller, PAD_AXIS_LEFT_Y_POS); - const auto ylNeg = _get_axis_value(controller, PAD_AXIS_LEFT_Y_NEG); - - auto xl = static_cast(xlPos - xlNeg); - auto yl = static_cast(ylPos - ylNeg); - if (controller->m_deadZones.useDeadzones) { - if (std::abs(xl) > controller->m_deadZones.stickDeadZone) { - xl /= 256; - } else { - xl = 0; - } - if (std::abs(yl) > controller->m_deadZones.stickDeadZone) { - yl /= 256; - } else { - yl = 0; - } - } else { - xl /= 256; - yl /= 256; - } - - status[i].stickX = static_cast(xl); - status[i].stickY = static_cast(yl); - - const auto xrPos = _get_axis_value(controller, PAD_AXIS_RIGHT_X_POS); - const auto xrNeg = _get_axis_value(controller, PAD_AXIS_RIGHT_X_NEG); - const auto yrPos = _get_axis_value(controller, PAD_AXIS_RIGHT_Y_POS); - const auto yrNeg = _get_axis_value(controller, PAD_AXIS_RIGHT_Y_NEG); - - auto xr = static_cast(xrPos - xrNeg); - auto yr = static_cast(yrPos - yrNeg); - if (controller->m_deadZones.useDeadzones) { - if (std::abs(xr) > controller->m_deadZones.substickDeadZone) { - xr /= 256; - } else { - xr = 0; - } - - if (std::abs(yr) > controller->m_deadZones.substickDeadZone) { - yr /= 256; - } else { - yr = 0; - } - } else { - xr /= 256; - yr /= 256; - } - - status[i].substickX = static_cast(xr); - status[i].substickY = static_cast(yr); - - Sint16 tl = std::max(static_cast(0), _get_axis_value(controller, PAD_AXIS_TRIGGER_L)); - Sint16 tr = std::max(static_cast(0), _get_axis_value(controller, PAD_AXIS_TRIGGER_R)); - - // Games can read either the digital L/R bits or their analog pressure. - // An explicit button binding must drive both, otherwise the original - // L2/R2 axis still activates L/R even when it was rebound to L1/R1. - // Real GC pads retain independent analog travel and end-stop clicks. - if (!(controller->m_isGameCube || - (SDL_GetGamepadType(controller->m_controller) == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO && - controller->m_pid == 0x2073))) { - if (leftTriggerSet) tl = (status[i].button & PAD_TRIGGER_L) != 0 ? 32767 : 0; - if (rightTriggerSet) tr = (status[i].button & PAD_TRIGGER_R) != 0 ? 32767 : 0; - } - - if (controller->m_deadZones.emulateTriggers) { - if (!leftTriggerSet && tl > controller->m_deadZones.leftTriggerActivationZone) { - status[i].button |= PAD_TRIGGER_L; - } - if (!rightTriggerSet && tr > controller->m_deadZones.rightTriggerActivationZone) { - status[i].button |= PAD_TRIGGER_R; - } - } - tl /= 128; - tr /= 128; - - status[i].triggerLeft = static_cast(tl); - status[i].triggerRight = static_cast(tr); - - if (controller->m_hasRumble) { - rumbleSupport |= PAD_CHAN0_BIT >> i; - } - - // Update the LED colors when they exist and the controller is read (which should happen once per frame in most - // games) - if (controller->m_hasRgbLed && controller->m_isColorDirty) { - SDL_SetGamepadLED(controller->m_controller, controller->m_ledRed, controller->m_ledGreen, - controller->m_ledBlue); - controller->m_isColorDirty = false; - } - } - - if (inputBlocked) { - neutralize_status(status[i]); - } else { - apply_unblock_suppression(status[i], i, captureHeldInput); - } - } - return rumbleSupport; -} - -void PADControlMotor(const u32 chan, const u32 cmd) { - const auto controller = aurora::input::get_controller_for_player(chan); - const auto instance = aurora::input::get_instance_for_player(chan); - if (controller == nullptr) { - return; - } - - if (controller->m_isGameCube) { - if (cmd == PAD_MOTOR_STOP || cmd == PAD_MOTOR_STOP_HARD) { - // Use an unambiguous motor-off request. The (0, 1) coast encoding - // requires SDL's GameCube brake mode; other backends or an overridden - // hint interpret it as rumble and can leave the controller vibrating. - aurora::input::controller_rumble(instance, 0, 0, 0); - } else if (cmd == PAD_MOTOR_RUMBLE) { - aurora::input::controller_rumble(instance, 1, 1, 0); - } - } else { - if (cmd == PAD_MOTOR_STOP) { - aurora::input::controller_rumble(instance, 0, 0, 1); - } else if (cmd == PAD_MOTOR_RUMBLE) { - aurora::input::controller_rumble(instance, controller->m_rumbleIntensityLow, controller->m_rumbleIntensityHigh, - 0); - } else if (cmd == PAD_MOTOR_STOP_HARD) { - aurora::input::controller_rumble(instance, 0, 0, 0); - } - } -} - -void PADControlAllMotors(const u32* cmdArr) { - for (u32 i = 0; i < PAD_CHANMAX; ++i) { - PADControlMotor(i, cmdArr[i]); - } -} - -void ClampTrigger(u8* trigger, const u8 min, const u8 max) { - if (*trigger <= min) { - *trigger = 0; - } else { - if (*trigger > max) { - *trigger = max; - } - *trigger -= min; - } -} - -void ClampCircle(s8* px, s8* py, const s8 radius, const s8 min) { - int x = *px; // NOLINT(*-str34-c) - int y = *py; // NOLINT(*-str34-c) - - if (-min < x && x < min) { - x = 0; - } else if (0 < x) { - x -= min; - } else { - x += min; - } - - if (-min < y && y < min) { - y = 0; - } else if (0 < y) { - y -= min; - } else { - y += min; - } - - if (const int squared = x * x + y * y; radius * radius < squared) { - const auto length = static_cast(std::sqrt(squared)); - x = x * radius / length; - y = y * radius / length; - } - - *px = static_cast(x); - *py = static_cast(y); -} - -void ClampStick(s8* px, s8* py, const s8 max, const s8 xy, const s8 min) { - int32_t x = *px; // NOLINT(*-str34-c) - int32_t y = *py; // NOLINT(*-str34-c) - - int32_t signX = 0; - if (0 <= x) { - signX = 1; - } else { - signX = -1; - x = -x; - } - - int8_t signY = 0; - if (0 <= y) { - signY = 1; - } else { - signY = -1; - y = -y; - } - - if (x <= min) { - x = 0; - } else { - x -= min; - } - if (y <= min) { - y = 0; - } else { - y -= min; - } - - if (x == 0 && y == 0) { - *px = *py = 0; - return; - } - - x = x * max / (INT8_MAX - min); - y = y * max / (INT8_MAX - min); - - if (xy * y <= xy * x) { - if (const int32_t d = xy * x + (max - xy) * y; xy * max < d) { - x = xy * max * x / d; - y = xy * max * y / d; - } - } else { - if (const int32_t d = xy * y + (max - xy) * x; xy * max < d) { - x = xy * max * x / d; - y = xy * max * y / d; - } - } - - *px = static_cast(signX * x); - *py = static_cast(signY * y); -} - -void PADClamp(PADStatus* status) { - for (uint32_t i = 0; i < PAD_CHANMAX; ++i) { - if (status[i].err != PAD_ERR_NONE) { - continue; - } - - ClampStick(&status[i].stickX, &status[i].stickY, ClampRegion.maxStick, ClampRegion.xyStick, ClampRegion.minStick); - ClampStick(&status[i].substickX, &status[i].substickY, ClampRegion.maxSubstick, ClampRegion.xySubstick, - ClampRegion.minSubstick); - ClampTrigger(&status[i].triggerLeft, ClampRegion.minTrigger, ClampRegion.maxTrigger); - ClampTrigger(&status[i].triggerRight, ClampRegion.minTrigger, ClampRegion.maxTrigger); - } -} - -void PADClampCircle(PADStatus* status) { - for (uint32_t i = 0; i < PAD_CHANMAX; ++i) { - if (status[i].err != PAD_ERR_NONE) { - continue; - } - - ClampCircle(&status[i].stickX, &status[i].stickY, ClampRegion.radStick, ClampRegion.minStick); - ClampCircle(&status[i].substickX, &status[i].substickY, ClampRegion.radSubstick, ClampRegion.minSubstick); - ClampTrigger(&status[i].triggerLeft, ClampRegion.minTrigger, ClampRegion.maxTrigger); - ClampTrigger(&status[i].triggerRight, ClampRegion.minTrigger, ClampRegion.maxTrigger); - } -} - -void PADGetVidPid(const u32 port, u32* vid, u32* pid) { - *vid = 0; - *pid = 0; - const auto* controller = aurora::input::get_controller_for_player(port); - if (controller == nullptr) { - return; - } - - *vid = controller->m_vid; - *pid = controller->m_pid; -} - -const char* PADGetName(const u32 port) { - const auto* controller = aurora::input::get_controller_for_player(port); - if (controller == nullptr) { - return nullptr; - } - - return SDL_GetGamepadName(controller->m_controller); -} - -void PADSetButtonMapping(const u32 port, const PADButtonMapping mapping) { - auto* controller = aurora::input::get_controller_for_player(port); - if (controller == nullptr) { - return; - } - - const auto iter = std::find_if(controller->m_buttonMapping.begin(), controller->m_buttonMapping.end(), - [mapping](const auto& pair) { return mapping.padButton == pair.padButton; }); - if (iter == controller->m_buttonMapping.end()) { - return; - } - - *iter = mapping; -} - -void PADSetAllButtonMappings(const u32 port, const PADButtonMapping buttons[PAD_BUTTON_COUNT]) { - for (uint32_t i = 0; i < PAD_BUTTON_COUNT; ++i) { - PADSetButtonMapping(port, buttons[i]); - } -} - -PADButtonMapping* PADGetButtonMappings(const u32 port, u32* buttonCount) { - auto* controller = aurora::input::get_controller_for_player(port); - if (controller == nullptr) { - *buttonCount = 0; - return nullptr; - } - - EnsureMappingLoaded(controller); - - *buttonCount = PAD_BUTTON_COUNT; - return controller->m_buttonMapping.data(); -} - -void PADSetAltButtonMapping(const u32 port, const PADButtonMapping mapping) { - auto* controller = aurora::input::get_controller_for_player(port); - if (controller == nullptr) { - return; - } - - const auto iter = std::find_if(controller->m_altButtonMapping.begin(), controller->m_altButtonMapping.end(), - [mapping](const auto& pair) { return mapping.padButton == pair.padButton; }); - if (iter == controller->m_altButtonMapping.end()) { - return; - } - - *iter = mapping; -} - -PADButtonMapping* PADGetAltButtonMappings(const u32 port, u32* buttonCount) { - auto* controller = aurora::input::get_controller_for_player(port); - if (controller == nullptr) { - *buttonCount = 0; - return nullptr; - } - - EnsureMappingLoaded(controller); - *buttonCount = PAD_BUTTON_COUNT; - return controller->m_altButtonMapping.data(); -} - -void PADSetAxisMapping(const u32 port, const PADAxisMapping mapping) { - auto* controller = aurora::input::get_controller_for_player(port); - if (controller == nullptr) { - return; - } - - const auto iter = std::find_if(controller->m_axisMapping.begin(), controller->m_axisMapping.end(), - [mapping](const auto& pair) { return mapping.padAxis == pair.padAxis; }); - if (iter == controller->m_axisMapping.end()) { - return; - } - - *iter = mapping; -} - -void PADSetAllAxisMappings(const u32 port, const PADAxisMapping axes[PAD_AXIS_COUNT]) { - for (uint32_t i = 0; i < PAD_AXIS_COUNT; ++i) { - PADSetAxisMapping(port, axes[i]); - } -} - -PADAxisMapping* PADGetAxisMappings(const u32 port, u32* axisCount) { - auto* controller = aurora::input::get_controller_for_player(port); - if (controller == nullptr) { - *axisCount = 0; - return nullptr; - } - - EnsureMappingLoaded(controller); - *axisCount = PAD_AXIS_COUNT; - return controller->m_axisMapping.data(); -} - -BOOL PADSetKeyButtonBinding(const u32 port, const PADKeyButtonBinding binding) { - if (port >= PAD_MAX_CONTROLLERS) { - return FALSE; - } - - for (auto& state = g_keyboardBindings[port]; auto& [scancode, padButton] : state.m_buttonMapping) { - if (padButton == binding.padButton) { - scancode = binding.scancode; - return TRUE; - } - } - - return FALSE; -} - -BOOL PADSetKeyButtonBindings(const u32 port, PADKeyButtonBinding bindings[PAD_BUTTON_COUNT]) { - for (uint32_t i = 0; i < PAD_BUTTON_COUNT; ++i) { - if (!PADSetKeyButtonBinding(port, bindings[i])) { - return FALSE; - } - } - return TRUE; -} - -PADKeyButtonBinding* PADGetKeyButtonBindings(const u32 port, u32* buttonCount) { - PADInit(); - if (!g_keyboardBindingsLoaded) { - g_keyboardBindingsLoaded = true; - load_keyboard_bindings(); - } - if (port >= PAD_MAX_CONTROLLERS || !g_keyboardBindings[port].m_mappingsSet) { - return nullptr; - } - auto& state = g_keyboardBindings[port]; - *buttonCount = PAD_BUTTON_COUNT; - return state.m_buttonMapping.data(); -} - -BOOL PADSetKeyAxisBinding(const u32 port, const PADKeyAxisBinding binding) { - if (port >= PAD_MAX_CONTROLLERS) { - return FALSE; - } - - for (auto& state = g_keyboardBindings[port]; auto& b : state.m_axisMapping) { - if (b.padAxis == binding.padAxis) { - b.scancode = binding.scancode; - return TRUE; - } - } - - return FALSE; -} -BOOL PADSetKeyAxisBindings(const u32 port, PADKeyAxisBinding bindings[PAD_BUTTON_COUNT]) { - for (uint32_t i = 0; i < PAD_AXIS_COUNT; ++i) { - if (!PADSetKeyAxisBinding(port, bindings[i])) { - return FALSE; - } - } - return TRUE; -} - -PADKeyAxisBinding* PADGetKeyAxisBindings(const u32 port, u32* axisCount) { - if (port >= PAD_MAX_CONTROLLERS || !g_keyboardBindings[port].m_mappingsSet) { - return nullptr; - } - auto& state = g_keyboardBindings[port]; - *axisCount = PAD_AXIS_COUNT; - return state.m_axisMapping.data(); -} - -void PADSetKeyboardActive(const u32 port, const BOOL active) { - if (port >= PAD_MAX_CONTROLLERS) { - return; - } - g_keyboardBindings[port].m_mappingsSet = active != FALSE; -} - -void PADClearKeyBindings(const u32 port) { - if (port >= PAD_MAX_CONTROLLERS) { - return; - } - g_keyboardBindings[port].m_buttonMapping = g_defaultKeys; - g_keyboardBindings[port].m_axisMapping = g_defaultKeyAxis; - g_keyboardBindings[port].m_mappingsSet = false; -} - -constexpr uint32_t k_keyboardMagic = SBIG('KBND'); -constexpr int32_t k_keyboardVersion = 3; - -static void load_keyboard_bindings() { - const auto filePath = fs_path_from_string(aurora::g_config.userPath) / "keyboard_bindings.dat"; - SDL_IOStream* file = SDL_IOFromFile(fs_path_to_string(filePath).c_str(), "rb"); - if (file == nullptr) { - return; - } - - uint32_t magic = 0; - SDL_ReadU32LE(file, &magic); - if (magic != k_keyboardMagic) { - aurora::input::Log.warn("keyboard_bindings.dat: invalid magic"); - SDL_CloseIO(file); - return; - } - - uint32_t version = 0; - SDL_ReadU32LE(file, &version); - if (version != k_keyboardVersion) { - aurora::input::Log.warn("keyboard_bindings.dat: version mismatch (expected {}, got {})", k_keyboardVersion, - version); - SDL_CloseIO(file); - return; - } - - const int64_t dataStart = SDL_TellIO(file) + 31 & ~31; - SDL_SeekIO(file, dataStart, SDL_IO_SEEK_SET); - - for (uint32_t port = 0; port < g_keyboardBindings.size(); ++port) { - auto& [buttonMapping, axisMapping, mappingsSet] = g_keyboardBindings[port]; - SDL_ReadIO(file, &mappingsSet, sizeof(bool)); - SDL_ReadIO(file, buttonMapping.data(), sizeof(PADKeyButtonBinding) * PAD_BUTTON_COUNT); - SDL_ReadIO(file, axisMapping.data(), sizeof(PADKeyAxisBinding) * PAD_AXIS_COUNT); - - bool kbButtonCorrupt = false; - for (uint32_t i = 0; i < PAD_BUTTON_COUNT; ++i) { - if (buttonMapping[i].padButton != g_defaultKeys[i].padButton) { - kbButtonCorrupt = true; - break; - } - } - if (kbButtonCorrupt) { - aurora::input::Log.warn("keyboard_bindings.dat port={}: corrupt button identifiers, resetting to defaults", port); - buttonMapping = g_defaultKeys; - } - - bool kbAxisCorrupt = false; - for (uint32_t i = 0; i < PAD_AXIS_COUNT; ++i) { - if (axisMapping[i].padAxis != g_defaultKeyAxis[i].padAxis) { - kbAxisCorrupt = true; - break; - } - } - if (kbAxisCorrupt) { - aurora::input::Log.warn("keyboard_bindings.dat port={}: corrupt axis identifiers, resetting to defaults", port); - axisMapping = g_defaultKeyAxis; - } - - if (mappingsSet) { - const bool anyBound = - std::any_of(buttonMapping.begin(), buttonMapping.end(), - [](const PADKeyButtonBinding& b) { return b.scancode != PAD_KEY_INVALID; }) || - std::any_of(axisMapping.begin(), axisMapping.end(), - [](const PADKeyAxisBinding& b) { return b.scancode != PAD_KEY_INVALID; }); - if (!anyBound) { - mappingsSet = false; - } - } - } - SDL_CloseIO(file); -} - -static void save_keyboard_bindings() { - const auto filePath = fs_path_from_string(aurora::g_config.userPath) / "keyboard_bindings.dat"; - const auto filePathStr = fs_path_to_string(filePath); - SDL_IOStream* file = SDL_IOFromFile(filePathStr.c_str(), "wb"); - if (file == nullptr) { - aurora::input::Log.warn("save_keyboard_bindings: failed to open {} for writing", filePathStr); - return; - } - - SDL_WriteU32LE(file, k_keyboardMagic); - SDL_WriteS32LE(file, k_keyboardVersion); - - const int64_t dataStart = SDL_TellIO(file) + 31 & ~31; - SDL_SeekIO(file, dataStart, SDL_IO_SEEK_SET); - - for (const auto& [buttonMapping, axisMapping, mappingsSet] : g_keyboardBindings) { - SDL_WriteU8(file, mappingsSet); - SDL_WriteIO(file, buttonMapping.data(), sizeof(PADKeyButtonBinding) * PAD_BUTTON_COUNT); - SDL_WriteIO(file, axisMapping.data(), sizeof(PADKeyAxisBinding) * PAD_AXIS_COUNT); - } - SDL_CloseIO(file); -} - -void __PADWriteDeadZones(SDL_IOStream* file, // NOLINT(*-reserved-identifier) - const aurora::input::GameController& controller) { - SDL_WriteIO(file, &controller.m_deadZones, sizeof(PADDeadZones)); -} - -void PADSerializeMappings() { - const std::filesystem::path basePath = fs_path_from_string(aurora::g_config.userPath); - - // Avoid std::views::values here: older Apple libc++ releases implement the - // C++20 ranges algorithms we use but not this adaptor. - for (auto& entry : aurora::input::g_GameControllers) { - auto& controller = entry.second; - EnsureMappingLoaded(&controller); - const auto filePath = - basePath / fmt::format("{}_{:04X}_{:04X}.controller", aurora::input::controller_name(controller.m_index), - controller.m_vid, controller.m_pid); - std::string filePathStr = fs_path_to_string(filePath); - - // don't truncate the file if it already exists - const char* openMode = std::filesystem::exists(filePath) ? "r+b" : "wb"; - SDL_IOStream* file = SDL_IOFromFile(filePathStr.c_str(), openMode); - if (file == nullptr) { - return; - } - SDL_SeekIO(file, 0, SDL_IO_SEEK_SET); - - // write header - constexpr uint32_t magic = SBIG('CTRL'); - SDL_WriteU32LE(file, magic); - SDL_WriteU32LE(file, k_mappingsFileVersion); - SDL_WriteU8(file, controller.m_isGameCube); - - // start writing data at next 32-byte aligned offset - const int64_t dataStart = SDL_TellIO(file) + 31 & ~31; - if (dataStart == -1) { - aurora::input::Log.warn("Unable to seek in controller bindings! Path: \"{}\"", filePathStr); - return; - } - SDL_SeekIO(file, dataStart, SDL_IO_SEEK_SET); - if (controller.m_isGameCube) { - // GameCube adapters expose 4 input devices with the same vid/pid, we store all 4 in the same file - const auto port = aurora::input::player_index(controller.m_index); - constexpr int64_t dzSecLen = sizeof(PADDeadZones); - constexpr int64_t btnSecLen = sizeof(PADButtonMapping) * PAD_BUTTON_COUNT; - constexpr int64_t axisSecLen = sizeof(PADAxisMapping) * PAD_AXIS_COUNT; - // skip to offset in file for this particular port - SDL_SeekIO(file, dataStart + (dzSecLen + btnSecLen + axisSecLen) * port, SDL_IO_SEEK_SET); - } - __PADWriteDeadZones(file, controller); - SDL_WriteIO(file, controller.m_buttonMapping.data(), sizeof(PADButtonMapping) * PAD_BUTTON_COUNT); - SDL_WriteIO(file, controller.m_axisMapping.data(), sizeof(PADAxisMapping) * PAD_AXIS_COUNT); - - if (!controller.m_isGameCube) { - SDL_WriteIO(file, &controller.m_rumbleIntensityLow, sizeof(u16)); - SDL_WriteIO(file, &controller.m_rumbleIntensityHigh, sizeof(u16)); - } - SDL_CloseIO(file); - } - - save_keyboard_bindings(); -} - -PADDeadZones* PADGetDeadZones(const u32 port) { - auto* controller = aurora::input::get_controller_for_player(port); - if (controller == nullptr) { - return nullptr; - } - return &controller->m_deadZones; -} - -static constexpr std::array, PAD_BUTTON_COUNT> skButtonNames = {{ - {PAD_BUTTON_LEFT, "Left"sv}, - {PAD_BUTTON_RIGHT, "Right"sv}, - {PAD_BUTTON_DOWN, "Down"sv}, - {PAD_BUTTON_UP, "Up"sv}, - {PAD_TRIGGER_Z, "Z"sv}, - {PAD_TRIGGER_R, "R"sv}, - {PAD_TRIGGER_L, "L"sv}, - {PAD_BUTTON_A, "A"sv}, - {PAD_BUTTON_B, "B"sv}, - {PAD_BUTTON_X, "X"sv}, - {PAD_BUTTON_Y, "Y"sv}, - {PAD_BUTTON_START, "Start"sv}, -}}; - -static constexpr std::array, PAD_AXIS_COUNT> skAxisNames = {{ - {PAD_AXIS_LEFT_X_POS, "Left X+"sv}, - {PAD_AXIS_LEFT_X_NEG, "Left X-"sv}, - {PAD_AXIS_LEFT_Y_POS, "Left Y+"sv}, - {PAD_AXIS_LEFT_Y_NEG, "Left Y-"sv}, - {PAD_AXIS_RIGHT_X_POS, "Right X+"sv}, - {PAD_AXIS_RIGHT_X_NEG, "Right X-"sv}, - {PAD_AXIS_RIGHT_Y_POS, "Right Y+"sv}, - {PAD_AXIS_RIGHT_Y_NEG, "Right Y-"sv}, - {PAD_AXIS_TRIGGER_L, "Trigger L"sv}, - {PAD_AXIS_TRIGGER_R, "Trigger R"sv}, -}}; - -static constexpr std::array, PAD_AXIS_COUNT> skAxisDirLabels = {{ - {PAD_AXIS_LEFT_X_POS, "Right"sv}, - {PAD_AXIS_LEFT_X_NEG, "Left"sv}, - {PAD_AXIS_LEFT_Y_POS, "Up"sv}, - {PAD_AXIS_LEFT_Y_NEG, "Down"sv}, - {PAD_AXIS_RIGHT_X_POS, "Right"sv}, - {PAD_AXIS_RIGHT_X_NEG, "Left"sv}, - {PAD_AXIS_RIGHT_Y_POS, "Up"sv}, - {PAD_AXIS_RIGHT_Y_NEG, "Down"sv}, - {PAD_AXIS_TRIGGER_L, "N/A"sv}, - {PAD_AXIS_TRIGGER_R, "N/A"sv}, -}}; - -const char* PADGetButtonName(const PADButton button) { - - if (const auto iter = std::find_if(skButtonNames.begin(), skButtonNames.end(), - [&button](const auto& pair) { return button == pair.first; }); - iter != skButtonNames.end()) { - return iter->second.data(); - } - - return nullptr; -} - -const char* PADGetNativeButtonName(u32 button) { - return SDL_GetGamepadStringForButton(static_cast(button)); -} - -const char* PADGetAxisName(const PADAxis axis) { - if (const auto it = std::find_if(skAxisNames.begin(), skAxisNames.end(), - [&axis](const auto& pair) { return axis == pair.first; }); - it != skAxisNames.end()) { - return it->second.data(); - } - - return nullptr; -} - -const char* PADGetAxisDirectionLabel(const PADAxis axis) { - if (const auto it = std::find_if(skAxisDirLabels.begin(), skAxisDirLabels.end(), - [&axis](const auto& pair) { return axis == pair.first; }); - it != skAxisDirLabels.end()) { - return it->second.data(); - } - - return nullptr; -} - -const char* PADGetNativeAxisName(PADSignedNativeAxis axis) { - return SDL_GetGamepadStringForAxis(static_cast(axis.nativeAxis)); -} - -int32_t PADGetNativeButtonPressed(const u32 port) { - const auto* controller = aurora::input::get_controller_for_player(port); - if (controller == nullptr) { - return -1; - } - - for (int32_t i = 0; i < SDL_GAMEPAD_BUTTON_COUNT; ++i) { - if (SDL_GetGamepadButton(controller->m_controller, static_cast(i)) != 0u) { - return i; - } - } - return -1; -} - -PADSignedNativeAxis PADGetNativeAxisPulled(const u32 port) { - const auto* controller = aurora::input::get_controller_for_player(port); - if (controller == nullptr) { - return {-1, AXIS_SIGN_POSITIVE}; - } - - for (int32_t i = 0; i < SDL_GAMEPAD_AXIS_COUNT; ++i) { - const auto axisVal = SDL_GetGamepadAxis(controller->m_controller, static_cast(i)); - if (axisVal >= 16384) { - return {i, AXIS_SIGN_POSITIVE}; - } - - if (axisVal <= -16384) { - // SDL3 triggers rest at -32768, so skip their negative direction. - if (i == SDL_GAMEPAD_AXIS_LEFT_TRIGGER || i == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) { - continue; - } - return {i, AXIS_SIGN_NEGATIVE}; - } - } - return {-1, AXIS_SIGN_POSITIVE}; -} - -void PADRestoreDefaultMapping(const u32 port) { - auto* controller = aurora::input::get_controller_for_player(port); - if (controller == nullptr) { - return; - } - __PADSetDefaultMapping(controller); - controller->m_axisMapping = g_defaultAxes; -} - -void PADBlockInput(const bool block) { - if (g_blockPAD.exchange(block, std::memory_order_acq_rel) && !block) { - g_suppressHeldOnRead = true; - } -} - - -SDL_Gamepad* PADGetSDLGamepadForIndex(const u32 index) { - const auto* ctrl = __PADGetControllerForIndex(index); - if (ctrl == nullptr) { - return nullptr; - } - - return ctrl->m_controller; -} - -void PADSetDefaultMapping(const PADDefaultMapping* mapping, const PADControllerType type) { - if (g_initialized) { - aurora::input::Log.fatal("PADSetDefaultMapping called after PADInit()!"); - } - - switch (type) { - case PAD_TYPE_STANDARD: - g_defaultButtonsStandard = toStdArray(mapping->buttons); - break; - case PAD_TYPE_XBOX360: - g_defaultButtonsXBox360 = toStdArray(mapping->buttons); - break; - case PAD_TYPE_XBOXONE: - g_defaultButtonsXBoxOne = toStdArray(mapping->buttons); - break; - case PAD_TYPE_PS3: - g_defaultButtonsPS3 = toStdArray(mapping->buttons); - break; - case PAD_TYPE_PS4: - g_defaultButtonsPS4 = toStdArray(mapping->buttons); - break; - case PAD_TYPE_PS5: - g_defaultButtonsPS5 = toStdArray(mapping->buttons); - break; - case PAD_TYPE_SWITCH_PROCON: - g_defaultButtonsProCon = toStdArray(mapping->buttons); - break; - case PAD_TYPE_JOYCON_LEFT: - g_defaultButtonsJoyConLeft = toStdArray(mapping->buttons); - break; - case PAD_TYPE_JOYCON_RIGHT: - g_defaultButtonsJoyConRight = toStdArray(mapping->buttons); - break; - case PAD_TYPE_JOYCON_PAIR: - g_defaultButtonsJoyPair = toStdArray(mapping->buttons); - break; - case PAD_TYPE_GAMECUBE: - g_defaultButtonsGamecube = toStdArray(mapping->buttons); - break; - case PAD_TYPE_NSO_GAMECUBE: - g_defaultButtonsNSOGamecube = toStdArray(mapping->buttons); - break; - default: - break; - } - g_defaultAxes = toStdArray(mapping->axes); -} - -BOOL PADSetColor(const u32 port, const u8 red, const u8 green, const u8 blue) { - const auto ctrl = aurora::input::get_controller_for_player(port); - if (ctrl == nullptr) { - return FALSE; - } - - ctrl->m_ledRed = red; - ctrl->m_ledGreen = green; - ctrl->m_ledBlue = blue; - ctrl->m_isColorDirty = true; - return true; -} - -BOOL PADGetColor(const u32 port, u8* red, u8* green, u8* blue) { - const auto ctrl = aurora::input::get_controller_for_player(port); - if (ctrl == nullptr) { - return FALSE; - } - - *red = ctrl->m_ledRed; - *green = ctrl->m_ledGreen; - *blue = ctrl->m_ledBlue; - return TRUE; -} - -BOOL PADSetSensorEnabled(const u32 port, const PADSensorType sensor, const BOOL enabled) { - const auto* ctrl = aurora::input::get_controller_for_player(port); - - if (ctrl == nullptr) { - return FALSE; - } - - return SDL_SetGamepadSensorEnabled(ctrl->m_controller, static_cast(sensor), enabled ? true : false) - ? TRUE - : FALSE; -} - -BOOL PADHasSensor(const u32 port, const PADSensorType sensor) { - const auto* ctrl = aurora::input::get_controller_for_player(port); - if (ctrl == nullptr) { - return FALSE; - } - - return SDL_GamepadHasSensor(ctrl->m_controller, static_cast(sensor)) ? TRUE : FALSE; -} - -BOOL PADGetSensorData(const u32 port, const PADSensorType sensor, f32* data, const int nValues) { - const auto* ctrl = aurora::input::get_controller_for_player(port); - if (ctrl == nullptr) { - return FALSE; - } - - return SDL_GetGamepadSensorData(ctrl->m_controller, static_cast(sensor), data, nValues); -} - -BOOL PADSetRumbleIntensity(const u32 port, const u16 low, const u16 high) { - auto* ctrl = aurora::input::get_controller_for_player(port); - if (ctrl == nullptr || ctrl->m_isGameCube || !ctrl->m_hasRumble) { - return FALSE; - } - ctrl->m_rumbleIntensityLow = low; - ctrl->m_rumbleIntensityHigh = high; - - return TRUE; -} - -BOOL PADGetRumbleIntensity(const u32 port, u16* low, u16* high) { - const auto* ctrl = aurora::input::get_controller_for_player(port); - if (ctrl == nullptr || ctrl->m_isGameCube || !ctrl->m_hasRumble) { - *low = 0; - *high = 0; - return FALSE; - } - - *low = ctrl->m_rumbleIntensityLow; - *high = ctrl->m_rumbleIntensityHigh; - return TRUE; -} - -BOOL PADSupportsRumbleIntensity(const u32 port) { - const auto* ctrl = aurora::input::get_controller_for_player(port); - if (ctrl == nullptr) { - return FALSE; - } - - return !ctrl->m_isGameCube && ctrl->m_hasRumble; -} - -BOOL PADIsGCAdapter(const u32 port) { - const auto* ctrl = aurora::input::get_controller_for_player(port); - if (ctrl == nullptr) { - return FALSE; - } - return ctrl->m_isGameCube; -} - -PADBatteryState PADGetBatteryState(const u32 port, f32* perc) { - const auto* ctrl = aurora::input::get_controller_for_player(port); - if (ctrl == nullptr) { - return PAD_BATTERYSTATE_ERROR; - } - - int tmp = 0; - const auto ret = SDL_GetGamepadPowerInfo(ctrl->m_controller, &tmp); - if (tmp != -1) { - *perc = static_cast(tmp) / 100.f; - } else { - *perc = static_cast(tmp); - } - return static_cast(ret); -} - -PADControllerType PADGetControllerType(const u32 port) { - const auto* ctrl = aurora::input::get_controller_for_player(port); - if (ctrl == nullptr) { - return PAD_TYPE_UNKNOWN; - } - - auto type = SDL_GetGamepadType(ctrl->m_controller); - return static_cast(type); -} - -PADControllerType PADGetControllerTypeForIndex(const u32 index) { - const auto* ctrl = __PADGetControllerForIndex(index); - if (ctrl == nullptr) { - return PAD_TYPE_UNKNOWN; - } - - auto type = SDL_GetGamepadType(ctrl->m_controller); - if (type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO && ctrl->m_pid == 0x2073) { - return PAD_TYPE_NSO_GAMECUBE; - } - return static_cast(type); -} diff --git a/aurora-main/lib/dolphin/si/si.cpp b/aurora-main/lib/dolphin/si/si.cpp deleted file mode 100644 index 6164105..0000000 --- a/aurora-main/lib/dolphin/si/si.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include "../../input.hpp" - -#include - -uint32_t SIProbe(int32_t chan) { - auto* const controller = aurora::input::get_controller_for_player(chan); - if (controller == nullptr) { - return SI_ERROR_NO_RESPONSE; - } - - if (controller->m_isGameCube) { - auto level = SDL_GetJoystickPowerInfo(SDL_GetGamepadJoystick(controller->m_controller), nullptr); - if (level == SDL_POWERSTATE_UNKNOWN) { - return SI_GC_WAVEBIRD; - } - } - - return SI_GC_CONTROLLER; -} diff --git a/aurora-main/lib/dolphin/vi/vi.cpp b/aurora-main/lib/dolphin/vi/vi.cpp deleted file mode 100644 index 37f49d6..0000000 --- a/aurora-main/lib/dolphin/vi/vi.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include - -#include "../../window.hpp" -#include "aurora/math.hpp" -#include "vi_internal.hpp" - -#include -#include -#include -#include - -namespace aurora::vi { -std::optional g_renderMode; -namespace { -std::atomic g_presentAspectCorrection{1.f}; -std::mutex g_renderModeMutex; - -float calculate_present_aspect_correction(const GXRenderModeObj& rm) noexcept { - if (rm.viWidth == 0 || rm.viHeight == 0) { - return 1.f; - } - - // Dolphin derives the displayed aspect from the VI active region instead of assuming an exact - // 4:3 or 16:9 signal. These are its BT.601 active sample and line counts. - const auto format = (static_cast(rm.viTVmode) >> 2) & 0x7u; - const bool pal = format == VI_PAL || format == VI_DEBUG_PAL; - const float nominalActiveWidth = - pal ? 864.f * (52.f / 64.f) : 858.f * (52.655555f / 63.555555f); - const float nominalActiveHeight = pal ? 576.f : 486.f; - const float horizontalFill = static_cast(rm.viWidth) / nominalActiveWidth; - const float verticalFill = static_cast(rm.viHeight) / nominalActiveHeight; - return horizontalFill / verticalFill; -} - -Vec2 render_mode_size_locked() noexcept { - if (!g_renderMode) { - return {640, 528}; - } - // GX has a fixed 640x528 EFB workspace. Games can configure a narrower visible framebuffer, but - // effects such as MKW's DOF use the remaining EFB area as scratch. - return {std::max(g_renderMode->fbWidth, 640), std::max(g_renderMode->efbHeight, 528)}; -} - -} // namespace - -Vec2 render_mode_size() noexcept { - std::lock_guard lock(g_renderModeMutex); - return render_mode_size_locked(); -} - -void configure(const GXRenderModeObj* rm) noexcept { - bool sizeChanged = false; - { - std::lock_guard lock(g_renderModeMutex); - const auto oldSize = render_mode_size_locked(); - if (rm == nullptr) { - g_renderMode.reset(); - } else { - g_renderMode = *rm; - g_presentAspectCorrection.store(calculate_present_aspect_correction(*rm), std::memory_order_release); - } - if (rm == nullptr) { - g_presentAspectCorrection.store(1.f, std::memory_order_release); - } - sizeChanged = render_mode_size_locked() != oldSize; - } - // Never hold the mode lock across a resize request or a renderer callback. - if (sizeChanged) { - window::request_frame_buffer_resize(); - } -} - -Vec2 configured_fb_size() noexcept { - return render_mode_size(); -} - -Vec2 visible_fb_size() noexcept { - std::lock_guard lock(g_renderModeMutex); - if (!g_renderMode) { - return {640, 528}; - } - return {g_renderMode->fbWidth, g_renderMode->efbHeight}; -} - -float present_aspect_correction() noexcept { - return g_presentAspectCorrection.load(std::memory_order_acquire); -} -} // namespace aurora::vi - -extern "C" { -void VIInit() {} -void VIConfigure(const GXRenderModeObj* rm) { aurora::vi::configure(rm); } -void VIConfigurePan(u16 xOrg, u16 yOrg, u16 width, u16 height) { - (void)xOrg; - (void)yOrg; - (void)width; - (void)height; -} -u32 VIGetTvFormat() { return 0; } -void VIFlush() {} - -void VISetWindowTitle(const char* title) { aurora::window::set_title(title); } -void VISetWindowFullscreen(bool fullscreen) { aurora::window::set_fullscreen(fullscreen); } -bool VIGetWindowFullscreen() { return aurora::window::get_fullscreen(); } -void VISetWindowSize(uint32_t width, uint32_t height) { aurora::window::set_window_size(width, height); } -void VISetWindowPosition(uint32_t x, uint32_t y) { aurora::window::set_window_position(x, y); } -void VICenterWindow() { aurora::window::center_window(); } -void VISetFrameBufferScale(float scale) { aurora::window::set_frame_buffer_scale(scale); } -void VILockAspectRatio(int width, int height) { aurora::window::lock_present_aspect_ratio(width, height); } -void VIUnlockAspectRatio() { aurora::window::unlock_present_aspect_ratio(); } -} diff --git a/aurora-main/lib/dolphin/vi/vi_internal.hpp b/aurora-main/lib/dolphin/vi/vi_internal.hpp deleted file mode 100644 index d4fe1f6..0000000 --- a/aurora-main/lib/dolphin/vi/vi_internal.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include - -#include - -#include - -namespace aurora::vi { -void configure(const GXRenderModeObj* rm) noexcept; -Vec2 configured_fb_size() noexcept; -Vec2 visible_fb_size() noexcept; -float present_aspect_correction() noexcept; -} // namespace aurora::vi diff --git a/aurora-main/lib/fs_helper.hpp b/aurora-main/lib/fs_helper.hpp deleted file mode 100644 index 0346642..0000000 --- a/aurora-main/lib/fs_helper.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include -#include -#include - -/** - * Narrow path strings crossing the aurora boundary are UTF-8. path::string() and the - * char path constructor go through the ANSI codepage on Windows, so they must not be - * used for anything the host handed us or hands back to SDL, sqlite or ImGui. - */ -inline std::string fs_path_to_string(const std::filesystem::path& path) { - const auto u8str = path.u8string(); - return { reinterpret_cast(u8str.c_str()), u8str.size() }; -} - -inline std::filesystem::path fs_path_from_string(std::string_view utf8) { - return std::filesystem::path(std::u8string(utf8.begin(), utf8.end())); -} diff --git a/aurora-main/lib/gfx/clear.cpp b/aurora-main/lib/gfx/clear.cpp deleted file mode 100644 index f5964f9..0000000 --- a/aurora-main/lib/gfx/clear.cpp +++ /dev/null @@ -1,162 +0,0 @@ -#include "clear.hpp" - -#include "../webgpu/gpu.hpp" -#include "tracy/Tracy.hpp" - -#include -#include - -namespace { -wgpu::ColorWriteMask clear_write_mask(bool clearColor, bool clearAlpha) { - auto writeMask = wgpu::ColorWriteMask::None; - if (clearColor) { - writeMask |= wgpu::ColorWriteMask::Red | wgpu::ColorWriteMask::Green | wgpu::ColorWriteMask::Blue; - } - if (clearAlpha) { - writeMask |= wgpu::ColorWriteMask::Alpha; - } - return writeMask; -} -} // namespace - -namespace aurora::gfx::clear { - -using webgpu::g_device; -using webgpu::g_graphicsConfig; - -wgpu::RenderPipeline create_pipeline(const PipelineConfig& config) { - ZoneScoped; - wgpu::ShaderSourceWGSL sourceDescriptor{}; - sourceDescriptor.code = R"""( -struct VertexOutput { - @builtin(position) pos: vec4, -}; - -struct ClearUniform { - depth: f32, -}; - -struct FragmentOutput { - @location(0) color: vec4, - @builtin(frag_depth) depth: f32, -}; - -@group(1) @binding(0) var clear: ClearUniform; - -var pos: array, 3> = array, 3>( - vec2(-1.0, 1.0), - vec2(-1.0, -3.0), - vec2(3.0, 1.0), -); - -@vertex -fn vs_main(@builtin(vertex_index) vtxIdx: u32) -> VertexOutput { - var out: VertexOutput; - out.pos = vec4(pos[vtxIdx], 0.0, 1.0); - return out; -} - -@fragment -fn fs_main() -> FragmentOutput { - var out: FragmentOutput; - out.color = vec4(1.0); - out.depth = clear.depth; - return out; -} -)"""; - const wgpu::ShaderModuleDescriptor moduleDescriptor{ - .nextInChain = &sourceDescriptor, - .label = "EFB Clear Module", - }; - auto module = g_device.CreateShaderModule(&moduleDescriptor); - const std::array layouts{ - g_staticBindGroupLayout, - g_uniformBindGroupLayout, - }; - const wgpu::PipelineLayoutDescriptor layoutDescriptor{ - .label = "EFB Clear Pipeline Layout", - .bindGroupLayoutCount = layouts.size(), - .bindGroupLayouts = layouts.data(), - }; - auto pipelineLayout = g_device.CreatePipelineLayout(&layoutDescriptor); - constexpr wgpu::BlendState blendState{ - .color = - wgpu::BlendComponent{ - .operation = wgpu::BlendOperation::Add, - .srcFactor = wgpu::BlendFactor::Constant, - .dstFactor = wgpu::BlendFactor::Zero, - }, - .alpha = - wgpu::BlendComponent{ - .operation = wgpu::BlendOperation::Add, - .srcFactor = wgpu::BlendFactor::Constant, - .dstFactor = wgpu::BlendFactor::Zero, - }, - }; - const wgpu::ColorTargetState colorTarget{ - .format = g_graphicsConfig.surfaceConfiguration.format, - .blend = &blendState, - .writeMask = clear_write_mask(config.clearColor, config.clearAlpha), - }; - const wgpu::FragmentState fragmentState{ - .module = module, - .entryPoint = "fs_main", - .targetCount = 1, - .targets = &colorTarget, - }; - const wgpu::DepthStencilState depthStencil{ - .format = g_graphicsConfig.depthFormat, - .depthWriteEnabled = config.clearDepth, - .depthCompare = wgpu::CompareFunction::Always, - }; - const auto label = fmt::format("EFB Clear Pipeline (color {}, alpha {}, depth {})", config.clearColor, - config.clearAlpha, config.clearDepth); - const wgpu::RenderPipelineDescriptor pipelineDescriptor{ - .label = label.c_str(), - .layout = pipelineLayout, - .vertex = - wgpu::VertexState{ - .module = module, - .entryPoint = "vs_main", - }, - .primitive = - wgpu::PrimitiveState{ - .topology = wgpu::PrimitiveTopology::TriangleList, - }, - .depthStencil = &depthStencil, - .multisample = - wgpu::MultisampleState{ - .count = config.msaaSamples, - }, - .fragment = &fragmentState, - }; - return g_device.CreateRenderPipeline(&pipelineDescriptor); -} - -void render(const DrawData& data, const wgpu::RenderPassEncoder& pass, const wgpu::Extent3D& targetSize, - PipelineRef& currentPipeline) { - if (!bind_pipeline(data.pipeline, pass, currentPipeline)) { - return; - } - - const std::array offsets{data.uniformRange.offset}; - pass.SetBindGroup(1, g_uniformBindGroup, offsets.size(), offsets.data()); - pass.SetBlendConstant(&data.color); - pass.SetViewport(0.f, 0.f, static_cast(targetSize.width), static_cast(targetSize.height), 0.f, 1.f); - if (data.useScissor) { - const auto x = static_cast(std::clamp(data.scissor.x, 0, static_cast(targetSize.width))); - const auto y = static_cast(std::clamp(data.scissor.y, 0, static_cast(targetSize.height))); - const auto right = static_cast(std::clamp( - data.scissor.x + data.scissor.width, 0, static_cast(targetSize.width))); - const auto bottom = static_cast(std::clamp( - data.scissor.y + data.scissor.height, 0, static_cast(targetSize.height))); - if (right <= x || bottom <= y) { - return; - } - pass.SetScissorRect(x, y, right - x, bottom - y); - } else { - pass.SetScissorRect(0, 0, targetSize.width, targetSize.height); - } - pass.Draw(3); -} -} // namespace aurora::gfx::clear diff --git a/aurora-main/lib/gfx/clear.hpp b/aurora-main/lib/gfx/clear.hpp deleted file mode 100644 index 7aed97f..0000000 --- a/aurora-main/lib/gfx/clear.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "common.hpp" - -#include - -namespace aurora::gfx::clear { -struct DrawData { - PipelineRef pipeline; - Range uniformRange; - wgpu::Color color; - float depth = 0.f; - bool useScissor = false; - ClipRect scissor{}; -}; - -constexpr uint32_t ClearPipelineConfigVersion = 3; -struct PipelineConfig { - uint32_t version = ClearPipelineConfigVersion; - uint32_t msaaSamples = 1; - bool clearColor = true; - bool clearAlpha = true; - bool clearDepth = true; - uint8_t _pad = 0; -}; -static_assert(std::has_unique_object_representations_v); - -wgpu::RenderPipeline create_pipeline(const PipelineConfig& config); -void render(const DrawData& data, const wgpu::RenderPassEncoder& pass, const wgpu::Extent3D& targetSize, - PipelineRef& currentPipeline); -} // namespace aurora::gfx::clear diff --git a/aurora-main/lib/gfx/common.cpp b/aurora-main/lib/gfx/common.cpp deleted file mode 100644 index e093901..0000000 --- a/aurora-main/lib/gfx/common.cpp +++ /dev/null @@ -1,1770 +0,0 @@ -#include "common.hpp" -#include "staging_map.hpp" -#include "../gx/shader_info.hpp" - -#include "clear.hpp" -#include "depth_peek.hpp" -#include "efb_ram_copy.hpp" -#include "../internal.hpp" -#include "../webgpu/gpu.hpp" -#include "../gx/pipeline.hpp" -#include "pipeline_cache.hpp" -#include "tex_copy_conv.hpp" -#include "tex_palette_conv.hpp" -#include "texture_replacement.hpp" -#include "texture.hpp" -#include "../window.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "tracy/Tracy.hpp" - -namespace aurora::gfx { -static Module Log("aurora::gfx"); - -using webgpu::g_device; -using webgpu::g_instance; -using webgpu::g_queue; - -struct DebugFrameData { -#ifdef AURORA_GFX_DEBUG_GROUPS - std::vector groups; - std::vector markers; -#endif -}; -DebugFrameData g_debugFrame; - -constexpr uint64_t StagingBufferSize = UniformBufferSize + VertexBufferSize + IndexBufferSize + StorageBufferSize + - (UseTextureBuffer ? TextureUploadSize : 0); - -struct ShaderDrawCommand { - ShaderType type; - union { - clear::DrawData clear; - gx::DrawData gx; - }; -}; -enum class CommandType { - SetViewport, - SetScissor, - Draw, - DebugMarker, -}; -struct Command { - CommandType type; -#ifdef AURORA_GFX_DEBUG_GROUPS - std::vector debugGroupStack; -#endif - union Data { - Viewport setViewport; - ClipRect setScissor; - ShaderDrawCommand draw; - size_t debugMarkerIndex; - } data; -}; -} // namespace aurora::gfx - -void aurora_set_guest_write_hooks(AuroraGuestWriteGenerationCallback generation, - AuroraGuestWriteNotifyCallback notify) { - aurora::g_guestWriteGenerationHook = generation; - aurora::g_guestWriteNotifyHook = notify; -} - -namespace aurora { -// For types that we can't ensure are safe to hash with has_unique_object_representations, -// we create specialized methods to handle them. Note that these are highly dependent on -// the structure definition, which could easily change with Dawn updates. -template <> -inline HashType xxh3_hash(const WGPUBindGroupDescriptor& input, HashType seed) { - constexpr auto offset = offsetof(WGPUBindGroupDescriptor, layout); // skip nextInChain, label - const auto hash = xxh3_hash_s(reinterpret_cast(&input) + offset, - sizeof(WGPUBindGroupDescriptor) - offset - sizeof(void*) /* skip entries */, seed); - const size_t entryBytes = sizeof(WGPUBindGroupEntry) * input.entryCount; - // The entries are hashed unseeded so they stay off XXH3's seeded long path; - // the descriptor head still carries the caller's seed. - return hash_combine(hash, xxh3_hash_s(input.entries, entryBytes)); -} -template <> -inline HashType xxh3_hash(const wgpu::SamplerDescriptor& input, HashType seed) { - constexpr auto offset = offsetof(wgpu::SamplerDescriptor, addressModeU); // skip nextInChain, label - return xxh3_hash_s(reinterpret_cast(&input) + offset, - sizeof(wgpu::SamplerDescriptor) - offset - 2 /* skip padding */, seed); -} -} // namespace aurora - -namespace aurora::gfx { -namespace { -struct CachedBindGroup { - wgpu::BindGroup bindGroup; - uint32_t lastUsedFrame = 0; -}; - -constexpr uint32_t BindGroupCacheRetainFrames = 32; -constexpr uint32_t BindGroupCacheSweepPeriod = 16; -} // namespace - -static absl::flat_hash_map g_cachedBindGroups; -// Bind groups dropped from the cache by clear_caches() while a sealed frame's recorded draws -// still reference them. Ownership moves here and is released at the next seal. -static std::vector g_retiredBindGroups; -static absl::flat_hash_map g_cachedSamplers; - -static ByteBuffer g_verts; -static ByteBuffer g_uniforms; -static ByteBuffer g_indices; -static ByteBuffer g_storage; -static ByteBuffer g_textureUpload; -wgpu::Buffer g_vertexBuffer; -wgpu::Buffer g_uniformBuffer; -wgpu::Buffer g_indexBuffer; -wgpu::Buffer g_storageBuffer; -constexpr size_t FrameSlotCount = 3; -static std::array g_stagingBuffers; -static size_t currentStagingBuffer = 0; -static StagingMapState s_mappingState; -static wgpu::Limits g_cachedLimits; -// Advanced once per logical frame in the seal prologue, under the renderer GPU mutex and with the -// producer blocked, so every later reader sees a value that no longer moves. -static uint32_t g_frameIndex = UINT32_MAX; -wgpu::BindGroupLayout g_staticBindGroupLayout; -wgpu::BindGroup g_staticBindGroup; -wgpu::BindGroupLayout g_uniformBindGroupLayout; -wgpu::BindGroup g_uniformBindGroup; - -// for imgui debug -AuroraStats g_stats{}; -uint32_t g_drawCallCount = 0; -uint32_t g_mergedDrawCallCount = 0; - -using CommandList = std::vector; -struct RenderPass { - wgpu::TextureView colorView; - wgpu::TextureView resolveView; // MSAA resolve target; null if msaaSamples == 1 - wgpu::TextureView depthView; - wgpu::Texture copySourceTexture; - wgpu::TextureView copySourceView; - wgpu::TextureView copySourceDepthView; - wgpu::Extent3D targetSize; - uint32_t msaaSamples = 1; - - TextureHandle resolveTarget; - TextureHandle resolveSourceSnapshot; - GXTexFmt resolveFormat = GX_TF_RGBA8; - ClipRect resolveRect; - ClipRect resolveSnapshotRect; - Vec4 resolveSourceRect; - Range resolveUniformRange; - std::array resolveCopyFilterCoefficients{0, 64, 0}; - Vec4 clearColorValue{0.f, 0.f, 0.f, 0.f}; - // 1.f is the forward-Z "farthest" clear value; under UseReversedZ farthest is 0.f instead (see - // gx::clear_depth_value(), which the main render pass explicitly overrides this default with - - // any OTHER pass that keeps this default, e.g. an offscreen render-to-texture pass composited - // later, needs the same reversed-Z-aware value or its depth buffer starts "already nearest", - // failing every subsequent depth test and making whatever's drawn into it vanish). - float clearDepthValue = gx::UseReversedZ ? 0.f : 1.f; - CommandList commands; - bool clearColor = true; - bool clearDepth = true; - // The resolve destination outlives the frame with no re-issue path (one-shot - // bake), so this pass may not drop draws even in skip-unready-pipelines mode. - bool requireReadyPipelines = false; - bool resolveHalfScale = false; - bool resolveCopyFilterActive = false; - bool resolveForceOpaqueAlpha = false; - bool resolveNeedsConversion = false; - bool resolveNeedsShaderSampling = false; - bool resolveLinearSampling = false; - bool snapshotColorResolveSource = false; - std::vector paletteConvs; -}; -static std::vector g_renderPasses; -static u32 g_currentRenderPass = UINT32_MAX; - -// Recycle command storage: discarding passes used to free their command lists too, so each frame -// rebuilt hundreds of KB from zero capacity. The passes themselves are cheap to recreate. -using CommandListPool = std::vector; -static CommandListPool g_commandListPool; -static constexpr size_t MaxPooledCommandLists = 32; -// The pool is the only recording storage both sides touch, a few pointer moves per frame, so a -// plain mutex is cheaper than the alternatives and keeps the vector's invariants. -static std::mutex g_commandListPoolMutex; - -static CommandList acquire_command_list() noexcept { - std::lock_guard lock{g_commandListPoolMutex}; - if (g_commandListPool.empty()) { - return {}; - } - CommandList list = std::move(g_commandListPool.back()); - g_commandListPool.pop_back(); - list.clear(); - return list; -} - -static void release_command_list(CommandList&& list) noexcept { - if (list.capacity() == 0) { - return; - } - std::lock_guard lock{g_commandListPoolMutex}; - if (g_commandListPool.size() >= MaxPooledCommandLists) { - return; - } - list.clear(); - g_commandListPool.emplace_back(std::move(list)); -} - -static void release_render_pass(RenderPass& pass) noexcept { release_command_list(std::move(pass.commands)); } - -static void recycle_render_passes(std::vector& passes) noexcept { - for (auto& pass : passes) { - release_render_pass(pass); - } - passes.clear(); -} - -struct SealedFrameData { - depth_peek::FrameMapping depthMapping; - DebugFrameData debug; - std::vector passes; -}; - -SealedFrame::SealedFrame() : m_data(std::make_unique()) {} -SealedFrame::~SealedFrame() = default; -SealedFrame::SealedFrame(SealedFrame&&) noexcept = default; -SealedFrame& SealedFrame::operator=(SealedFrame&&) noexcept = default; - -static RenderPass& push_render_pass(RenderPass&& pass) { - auto& out = g_renderPasses.emplace_back(std::move(pass)); - if (out.commands.capacity() == 0) { - out.commands = acquire_command_list(); - } - return out; -} -// The producer may build the next frame's GX stream while the worker prepares the target, and -// this is the only renderer-owned property that path queries, so publish it explicitly. -static std::atomic_bool g_inOffscreen{false}; -static std::optional g_suspendedEfbPass; -static Viewport g_suspendedEfbViewport; -static ClipRect g_suspendedEfbScissor; -// Prefix referenced by a suspended EFB pass. Preserve its offsets across an -// offscreen split, without rendering it before the bake it may sample finishes. -static StagingSizes g_suspendedEfbBytes{}; -static constexpr StagingSizes PhysicalStagingCapacity{ - VertexBufferSize, UniformBufferSize, IndexBufferSize, StorageBufferSize}; -static StagingSizes g_stagingCapacity = PhysicalStagingCapacity; -static uint64_t g_stagingEpoch = 0; -static uint64_t g_stagingSplitCount = 0; -static StagingSizes g_stagingHighWater{}; - -StagingSizes staging_usage() noexcept { - return {g_verts.size(), g_uniforms.size(), g_indices.size(), g_storage.size()}; -} -StagingSizes staging_high_water() noexcept { return g_stagingHighWater; } -uint64_t staging_epoch() noexcept { return g_stagingEpoch; } -uint64_t staging_split_count() noexcept { return g_stagingSplitCount; } -uint64_t staging_uniform_bytes(uint64_t bytes) { - return staging_padded(bytes, g_cachedLimits.minUniformBufferOffsetAlignment); -} -uint64_t staging_storage_bytes(uint64_t bytes) { - return staging_padded(bytes, g_cachedLimits.minStorageBufferOffsetAlignment); -} -void set_staging_capacity_limits_for_testing(const StagingSizes& limits) { - for (unsigned i = 0; i < limits.size(); ++i) { - if (limits[i] > PhysicalStagingCapacity[i]) - throw StagingCapacityError("Test staging capacity exceeds physical buffer"); - } - g_stagingCapacity = limits; - g_stagingHighWater = {}; -} -bool staging_has_space(const StagingSizes& demand) { - // Async readback preparation runs in the worker's noexcept seal prologue. - // Reserve all 32 slots plus the uniform binding's 3840-byte trailing window. - const StagingSizes tail{0, gx::MaxUniformSize + efb_ram::MaxAsyncReadbackSlots * staging_uniform_bytes(48), 0, 0}; - const StagingSizes retained = g_suspendedEfbPass ? g_suspendedEfbBytes : StagingSizes{}; - if (!staging_fits(retained, demand, tail, g_stagingCapacity)) - throw StagingCapacityError("GPU operation exceeds staging capacity including retained EFB data"); - return staging_fits(staging_usage(), demand, tail, g_stagingCapacity); -} -void ensure_staging_space(const StagingSizes& demand) { - if (staging_has_space(demand)) return; - split_staging_batch(); - if (!staging_has_space(demand)) - throw StagingCapacityError("GPU operation still exceeds staging capacity after submission"); -} - -static void discard_suspended_efb_pass() noexcept { - if (g_suspendedEfbPass) { - release_render_pass(*g_suspendedEfbPass); - g_suspendedEfbPass.reset(); - } -} - -static bool has_current_render_pass() noexcept { return g_currentRenderPass < g_renderPasses.size(); } -static webgpu::TextureWithSampler g_offscreenColor; -static webgpu::TextureWithSampler g_offscreenDepth; - -struct ResolveSourceSnapshotPool { - TextureHandle entry; -}; - -// Snapshot resources live in the same safe frame slots as the mapped staging buffers, and copies -// within a frame are ordered, so one grow-only snapshot serves every resolve in that slot. -static std::array g_resolveSourceSnapshotPools; -static size_t g_recordingSnapshotSlot = 0; - -static TextureHandle new_resolve_source_snapshot(wgpu::Extent3D size, wgpu::TextureFormat format) noexcept { - const wgpu::TextureDescriptor textureDescriptor{ - .label = "GX Copy Source Snapshot", - .usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc | - wgpu::TextureUsage::CopyDst, - .dimension = wgpu::TextureDimension::e2D, - .size = size, - .format = format, - .mipLevelCount = 1, - .sampleCount = 1, - }; - auto texture = g_device.CreateTexture(&textureDescriptor); - constexpr wgpu::TextureViewDescriptor viewDescriptor{ - .label = "GX Copy Source Snapshot view", - .dimension = wgpu::TextureViewDimension::e2D, - }; - auto textureView = texture.CreateView(&viewDescriptor); - wgpu::TextureView sampleTextureView = textureView; - return std::make_shared(std::move(texture), std::move(sampleTextureView), std::move(textureView), size, - format, 1, GX_TF_RGBA8); -} - -static TextureHandle acquire_resolve_source_snapshot(uint32_t width, uint32_t height) noexcept { - auto& pool = g_resolveSourceSnapshotPools[g_recordingSnapshotSlot]; - const auto format = webgpu::g_graphicsConfig.surfaceConfiguration.format; - - if (pool.entry && pool.entry->size.width >= width && pool.entry->size.height >= height && - pool.entry->format == format) { - return pool.entry; - } - - const wgpu::Extent3D size{ - std::max(width, pool.entry ? pool.entry->size.width : 0u), - std::max(height, pool.entry ? pool.entry->size.height : 0u), - 1, - }; - pool.entry = new_resolve_source_snapshot(size, format); - return pool.entry; -} - -struct ResolveSamplingPlan { - bool needsConversion = false; - bool needsShaderSampling = false; - bool usesLinearSampling = false; -}; - -static ResolveSamplingPlan make_resolve_sampling_plan(const TextureHandle& target, GXTexFmt format, - const ClipRect& resolveRect, const Vec4& sourceRect, - bool halfScale, bool copyFilterActive, - bool forceOpaqueAlpha) noexcept { - const auto differs = [](float lhs, float rhs) { return std::abs(lhs - rhs) > 0.01f; }; - const auto differsFromDst = [&](uint32_t dst, float src) { - return differs(static_cast(dst), src); - }; - const bool sourceMatchesIntegerRect = - !differs(sourceRect.x(), static_cast(resolveRect.x)) && - !differs(sourceRect.y(), static_cast(resolveRect.y)) && - !differs(sourceRect.z(), static_cast(resolveRect.width)) && - !differs(sourceRect.w(), static_cast(resolveRect.height)); - const bool dstMatchesSource = target && !differsFromDst(target->size.width, sourceRect.z()) && - !differsFromDst(target->size.height, sourceRect.w()); - const bool needsShaderSampling = - halfScale || copyFilterActive || forceOpaqueAlpha || !sourceMatchesIntegerRect || !dstMatchesSource; - return { - .needsConversion = tex_copy_conv::needs_conversion(format), - .needsShaderSampling = needsShaderSampling, - .usesLinearSampling = halfScale || (needsShaderSampling && !copyFilterActive), - }; -} - -static ClipRect calculate_resolve_snapshot_rect(const wgpu::Extent3D& targetSize, - const Vec4& sourceRect, - const ResolveSamplingPlan& samplingPlan, - bool copyFilterActive) noexcept { - const ClipRect fullTarget{ - .x = 0, - .y = 0, - .width = static_cast(targetSize.width), - .height = static_cast(targetSize.height), - }; - // Shader-sampled and converted copies can feed effects that read outside the copy rectangle - // (MKW's DOF chain), so keep those full-target. Exact copies have a closed, crop-safe footprint. - if (samplingPlan.needsConversion || - samplingPlan.needsShaderSampling || - targetSize.width == 0 || targetSize.height == 0 || - !std::isfinite(sourceRect.x()) || !std::isfinite(sourceRect.y()) || - !std::isfinite(sourceRect.z()) || !std::isfinite(sourceRect.w()) || - sourceRect.z() <= 0.0f || sourceRect.w() <= 0.0f) { - return fullTarget; - } - - // Linear sampling can touch one neighbor on every edge. The vertical GX - // copy filter explicitly samples the previous and next rows. - const int32_t haloX = samplingPlan.usesLinearSampling ? 1 : 0; - const int32_t haloY = (samplingPlan.usesLinearSampling || copyFilterActive) ? 1 : 0; - const int32_t targetWidth = static_cast(targetSize.width); - const int32_t targetHeight = static_cast(targetSize.height); - const int32_t left = std::clamp(static_cast(std::floor(sourceRect.x())) - haloX, 0, targetWidth - 1); - const int32_t top = std::clamp(static_cast(std::floor(sourceRect.y())) - haloY, 0, targetHeight - 1); - const int32_t right = std::clamp(static_cast(std::ceil(sourceRect.x() + sourceRect.z())) + haloX, - left + 1, targetWidth); - const int32_t bottom = std::clamp(static_cast(std::ceil(sourceRect.y() + sourceRect.w())) + haloY, - top + 1, targetHeight); - return { - .x = left, - .y = top, - .width = right - left, - .height = bottom - top, - }; -} - -static void set_efb_targets(RenderPass& pass) { - pass.colorView = webgpu::g_frameBuffer.view; - pass.resolveView = webgpu::g_graphicsConfig.msaaSamples > 1 ? webgpu::g_frameBufferResolved.view : nullptr; - pass.depthView = webgpu::g_depthBuffer.view; - pass.copySourceTexture = - webgpu::g_graphicsConfig.msaaSamples > 1 ? webgpu::g_frameBufferResolved.texture : webgpu::g_frameBuffer.texture; - pass.copySourceView = - webgpu::g_graphicsConfig.msaaSamples > 1 ? webgpu::g_frameBufferResolved.view : webgpu::g_frameBuffer.view; - pass.copySourceDepthView = webgpu::g_depthBuffer.view; - pass.targetSize = webgpu::g_frameBuffer.size; - pass.msaaSamples = webgpu::g_graphicsConfig.msaaSamples; -} - -struct OffscreenCacheKey { - uint32_t width; - uint32_t height; - - bool operator==(const OffscreenCacheKey& rhs) const { return width == rhs.width && height == rhs.height; } - template - friend H AbslHashValue(H h, const OffscreenCacheKey& key) { - return H::combine(std::move(h), key.width, key.height); - } -}; -struct OffscreenCacheEntry { - webgpu::TextureWithSampler color; - webgpu::TextureWithSampler depth; -}; -static absl::flat_hash_map g_offscreenCache; -std::vector g_textureUploads; - -static inline void push_command(CommandType type, const Command::Data& data) { - if (!has_current_render_pass()) - UNLIKELY { - Log.warn("Dropping command {}", magic_enum::enum_name(type)); - return; - } - g_renderPasses[g_currentRenderPass].commands.push_back({ - .type = type, -#ifdef AURORA_GFX_DEBUG_GROUPS - .debugGroupStack = g_debugFrame.groups, -#endif - .data = data, - }); -} - -template <> -gx::DrawData* get_last_draw_command() { - if (g_currentRenderPass >= g_renderPasses.size()) { - return nullptr; - } - auto& last = g_renderPasses[g_currentRenderPass].commands.back(); - if (last.type != CommandType::Draw || last.data.draw.type != ShaderType::GX) { - return nullptr; - } - return &last.data.draw.gx; -} - -static void push_draw_command(ShaderDrawCommand data) { - push_command(CommandType::Draw, Command::Data{.draw = data}); - ++g_drawCallCount; -} - -Vec2 get_frame_buffer_size() noexcept { - if (webgpu::g_frameBuffer.size.width != 0 && webgpu::g_frameBuffer.size.height != 0) { - return {webgpu::g_frameBuffer.size.width, webgpu::g_frameBuffer.size.height}; - } - const auto windowSize = window::get_window_size(); - return {windowSize.fb_width, windowSize.fb_height}; -} - -// Render-thread only: the frame worker recycles g_renderPasses in end_frame, so an off-thread -// read is a use-after-free rather than a stale value. Use get_frame_buffer_size() instead. -Vec2 get_render_target_size() noexcept { - if (g_currentRenderPass < g_renderPasses.size()) { - const auto& size = g_renderPasses[g_currentRenderPass].targetSize; - return {size.width, size.height}; - } - return get_frame_buffer_size(); -} - -static Viewport g_cachedViewport; -void set_viewport(const Viewport& cmd) noexcept { - if (cmd != g_cachedViewport) { - push_command(CommandType::SetViewport, Command::Data{.setViewport = cmd}); - g_cachedViewport = cmd; - } -} - -static ClipRect g_cachedScissor; -void set_scissor(const ClipRect& cmd) noexcept { - if (cmd != g_cachedScissor) { - push_command(CommandType::SetScissor, Command::Data{.setScissor = cmd}); - g_cachedScissor = cmd; - } -} - -template <> -void push_draw_command(clear::DrawData data) { - if (data.uniformRange.size == 0) { - ensure_staging_space({0, staging_uniform_bytes(16), 0, 0}); - const std::array clearUniform{ - std::clamp(data.depth, 0.f, 1.f), - 0.f, - 0.f, - 0.f, - }; - data.uniformRange = push_uniform(clearUniform); - } - push_draw_command(ShaderDrawCommand{.type = ShaderType::Clear, .clear = data}); -} - -template <> -PipelineRef pipeline_ref(const clear::PipelineConfig& config) { - return find_pipeline(ShaderType::Clear, config, [=] { return create_pipeline(config); }); -} - -void resolve_pass(TextureHandle texture, ClipRect rect, bool clearColor, bool clearAlpha, bool clearDepth, - Vec4 clearColorValue, float clearDepthValue, GXTexFmt resolveFormat, - const Vec4* sourceRectPixels, bool halfScale, - const std::array* copyFilterCoefficients, bool forceOpaqueAlpha, - float copyFilterRowStride, bool clampTop, bool clampBottom, bool persistentCopy) { - // Resolve current render pass - if (!has_current_render_pass()) { - Log.warn("Dropping resolve pass without an active render pass"); - return; - } - ensure_staging_space({0, 2 * staging_uniform_bytes(48), 0, 0}); - auto& prevPass = g_renderPasses[g_currentRenderPass]; - const auto targetWidth = static_cast(prevPass.targetSize.width); - const auto targetHeight = static_cast(prevPass.targetSize.height); - if (targetWidth <= 0 || targetHeight <= 0) { - Log.warn("Dropping resolve pass with invalid target size {}x{}", targetWidth, targetHeight); - return; - } - Vec4 sourceRect = sourceRectPixels != nullptr - ? *sourceRectPixels - : Vec4{static_cast(rect.x), static_cast(rect.y), - static_cast(rect.width), static_cast(rect.height)}; - if (targetWidth > 0 && targetHeight > 0) { - const int32_t left = std::clamp(rect.x, 0, targetWidth - 1); - const int32_t top = std::clamp(rect.y, 0, targetHeight - 1); - const int32_t right = std::clamp(rect.x + rect.width, left + 1, targetWidth); - const int32_t bottom = std::clamp(rect.y + rect.height, top + 1, targetHeight); - rect = { - .x = left, - .y = top, - .width = right - left, - .height = bottom - top, - }; - - const float srcW = static_cast(targetWidth); - const float srcH = static_cast(targetHeight); - const float srcLeft = std::clamp(sourceRect.x(), 0.0f, srcW); - const float srcTop = std::clamp(sourceRect.y(), 0.0f, srcH); - const float srcRight = std::clamp(sourceRect.x() + sourceRect.z(), srcLeft, srcW); - const float srcBottom = std::clamp(sourceRect.y() + sourceRect.w(), srcTop, srcH); - sourceRect = {srcLeft, srcTop, std::max(srcRight - srcLeft, 1.0f), std::max(srcBottom - srcTop, 1.0f)}; - } - prevPass.resolveTarget = std::move(texture); - prevPass.requireReadyPipelines |= persistentCopy; - prevPass.resolveRect = rect; - prevPass.resolveSourceRect = sourceRect; - prevPass.resolveFormat = resolveFormat; - prevPass.resolveHalfScale = halfScale; - prevPass.resolveForceOpaqueAlpha = forceOpaqueAlpha; - prevPass.resolveCopyFilterCoefficients = - copyFilterCoefficients != nullptr ? *copyFilterCoefficients : std::array{0, 64, 0}; - prevPass.resolveCopyFilterActive = prevPass.resolveCopyFilterCoefficients[0] != 0 || - prevPass.resolveCopyFilterCoefficients[1] != 64 || - prevPass.resolveCopyFilterCoefficients[2] != 0; - const auto samplingPlan = make_resolve_sampling_plan( - prevPass.resolveTarget, resolveFormat, rect, sourceRect, halfScale, - prevPass.resolveCopyFilterActive, forceOpaqueAlpha); - prevPass.resolveNeedsConversion = samplingPlan.needsConversion; - prevPass.resolveNeedsShaderSampling = samplingPlan.needsShaderSampling; - prevPass.resolveLinearSampling = samplingPlan.usesLinearSampling; - prevPass.snapshotColorResolveSource = - !gx::is_depth_format(resolveFormat) && (clearColor || clearAlpha || clearDepth); - Vec4 uniformSourceRect = sourceRect; - float srcW = static_cast(prevPass.targetSize.width); - float srcH = static_cast(prevPass.targetSize.height); - if (prevPass.snapshotColorResolveSource) { - prevPass.resolveSnapshotRect = calculate_resolve_snapshot_rect( - prevPass.targetSize, sourceRect, samplingPlan, prevPass.resolveCopyFilterActive); - prevPass.resolveSourceSnapshot = acquire_resolve_source_snapshot( - static_cast(prevPass.resolveSnapshotRect.width), - static_cast(prevPass.resolveSnapshotRect.height)); - uniformSourceRect = { - sourceRect.x() - static_cast(prevPass.resolveSnapshotRect.x), - sourceRect.y() - static_cast(prevPass.resolveSnapshotRect.y), - sourceRect.z(), sourceRect.w()}; - srcW = static_cast(prevPass.resolveSourceSnapshot->size.width); - srcH = static_cast(prevPass.resolveSourceSnapshot->size.height); - } - // GX's copy-clamp bits pin every vertical filter tap to the first or last source texel; without - // it a filtered copy at internal resolution samples an unrelated EFB row as a visible border. - const float clampTopPixels = clampTop ? uniformSourceRect.y() : 0.0f; - const float clampBottomPixels = - clampBottom ? uniformSourceRect.y() + uniformSourceRect.w() : srcH; - const float clampTopUv = (clampTopPixels + 0.5f) / srcH; - const float clampBottomUv = (clampBottomPixels - 0.5f) / srcH; - // Push UV transform uniform for tex_copy_conv (crop region in UV space) - const std::array resolveUniform{ - uniformSourceRect.x() / srcW, - uniformSourceRect.y() / srcH, - uniformSourceRect.z() / srcW, - uniformSourceRect.w() / srcH, - static_cast(prevPass.resolveCopyFilterCoefficients[0]), - static_cast(prevPass.resolveCopyFilterCoefficients[1]), - static_cast(prevPass.resolveCopyFilterCoefficients[2]), - prevPass.resolveCopyFilterActive ? 1.0f : 0.0f, - prevPass.resolveForceOpaqueAlpha ? 1.0f : 0.0f, - std::max(copyFilterRowStride, 1.0f), - clampTopUv, - clampBottomUv, - }; - prevPass.resolveUniformRange = push_uniform(resolveUniform); - const bool clearFullTarget = rect.x <= 0 && rect.y <= 0 && - rect.width >= static_cast(prevPass.targetSize.width) && - rect.height >= static_cast(prevPass.targetSize.height); - const bool useAttachmentColorClear = clearFullTarget && clearColor && clearAlpha; - const bool useAttachmentDepthClear = clearFullTarget && clearDepth; - - // Populate new render pass from previous - const auto msaaSamples = prevPass.msaaSamples; - RenderPass newPass{ - .colorView = prevPass.colorView, - .resolveView = prevPass.resolveView, - .depthView = prevPass.depthView, - .copySourceTexture = prevPass.copySourceTexture, - .copySourceView = prevPass.copySourceView, - .copySourceDepthView = prevPass.copySourceDepthView, - .targetSize = prevPass.targetSize, - .msaaSamples = msaaSamples, - .clearColorValue = clearColorValue, - .clearDepthValue = clearDepthValue, - .clearColor = useAttachmentColorClear, - .clearDepth = useAttachmentDepthClear, - }; - push_render_pass(std::move(newPass)); - ++g_currentRenderPass; - - if ((!useAttachmentColorClear && (clearColor || clearAlpha)) || (!useAttachmentDepthClear && clearDepth)) { - // GX copy clears cover the copied EFB rectangle, not always the whole target, so use a scissored - // clear draw unless the load op can clear all of it. - push_draw_command(clear::DrawData{ - .pipeline = pipeline_ref(clear::PipelineConfig{ - .msaaSamples = msaaSamples, - .clearColor = clearColor, - .clearAlpha = clearAlpha, - .clearDepth = clearDepth, - }), - .color = - wgpu::Color{ - .r = clearColorValue.x(), - .g = clearColorValue.y(), - .b = clearColorValue.z(), - .a = clearColorValue.w(), - }, - .depth = clearDepthValue, - .useScissor = !clearFullTarget, - .scissor = rect, - }); - } - push_command(CommandType::SetViewport, Command::Data{.setViewport = g_cachedViewport}); - push_command(CommandType::SetScissor, Command::Data{.setScissor = g_cachedScissor}); -} - -void queue_palette_conv(tex_palette_conv::ConvRequest req) { - if (!has_current_render_pass()) { - Log.warn("Dropping palette conversion without an active render pass"); - return; - } - g_renderPasses[g_currentRenderPass].paletteConvs.push_back(std::move(req)); -} - -bool is_offscreen() noexcept { return g_inOffscreen; } - -uint32_t get_sample_count() noexcept { - if (!has_current_render_pass()) { - return webgpu::g_graphicsConfig.msaaSamples; - } - return g_renderPasses[g_currentRenderPass].msaaSamples; -} - -void clear_caches() noexcept { - g_offscreenCache.clear(); - // Retire rather than free; see g_retiredBindGroups. - g_retiredBindGroups.reserve(g_retiredBindGroups.size() + g_cachedBindGroups.size()); - for (auto& entry : g_cachedBindGroups) { - g_retiredBindGroups.emplace_back(std::move(entry.second)); - } - g_cachedBindGroups.clear(); -} - -static OffscreenCacheEntry get_offscreen_textures(uint32_t width, uint32_t height) { - OffscreenCacheKey key{width, height}; - if (const auto it = g_offscreenCache.find(key); it != g_offscreenCache.end()) { - return it->second; - } - const auto colorFormat = webgpu::g_graphicsConfig.surfaceConfiguration.format; - const wgpu::Extent3D size{width, height, 1}; - const wgpu::TextureDescriptor colorDesc{ - .label = "Offscreen Color", - .usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc | - wgpu::TextureUsage::CopyDst, - .dimension = wgpu::TextureDimension::e2D, - .size = size, - .format = colorFormat, - .mipLevelCount = 1, - .sampleCount = 1, - }; - auto colorTexture = g_device.CreateTexture(&colorDesc); - auto colorView = colorTexture.CreateView(); - webgpu::TextureWithSampler color{ - .texture = std::move(colorTexture), - .view = std::move(colorView), - .size = size, - .format = colorFormat, - }; - const auto depthFormat = webgpu::g_graphicsConfig.depthFormat; - const wgpu::TextureDescriptor depthDesc{ - .label = "Offscreen Depth", - .usage = wgpu::TextureUsage::RenderAttachment, - .dimension = wgpu::TextureDimension::e2D, - .size = size, - .format = depthFormat, - .mipLevelCount = 1, - .sampleCount = 1, - }; - auto depthTexture = g_device.CreateTexture(&depthDesc); - auto depthView = depthTexture.CreateView(); - webgpu::TextureWithSampler depth{ - .texture = std::move(depthTexture), - .view = std::move(depthView), - .size = size, - .format = depthFormat, - }; - OffscreenCacheEntry entry{ - .color = std::move(color), - .depth = std::move(depth), - }; - auto [insertIt, _] = g_offscreenCache.emplace(key, std::move(entry)); - return insertIt->second; -} - -void begin_offscreen(uint32_t width, uint32_t height) { - ZoneScoped; - CHECK(g_currentRenderPass != UINT32_MAX, "begin_offscreen called outside of a frame"); - - // If the current EFB pass has no resolve target, its output is unobservable. - // Suspend it so that we can resume it after the offscreen pass. - if (!g_inOffscreen) { - auto& currentPass = g_renderPasses[g_currentRenderPass]; - if (!currentPass.resolveTarget) { - g_suspendedEfbBytes = staging_usage(); - g_suspendedEfbPass = std::move(currentPass); - g_renderPasses.pop_back(); - --g_currentRenderPass; - } - g_suspendedEfbViewport = g_cachedViewport; - g_suspendedEfbScissor = g_cachedScissor; - } - - // Create offscreen textures - auto offscreenEntry = get_offscreen_textures(width, height); - g_offscreenColor = std::move(offscreenEntry.color); - g_offscreenDepth = std::move(offscreenEntry.depth); - - // Start a new pass with offscreen targets - RenderPass newPass{ - .colorView = g_offscreenColor.view, - .depthView = g_offscreenDepth.view, - .copySourceTexture = g_offscreenColor.texture, - .copySourceView = g_offscreenColor.view, - .copySourceDepthView = g_offscreenDepth.view, - .targetSize = {width, height, 1}, - .msaaSamples = 1, - .clearColorValue = {0.f, 0.f, 0.f, 0.f}, - // See the RenderPass::clearDepthValue default's comment: this offscreen pass gets its own - // depth buffer, and the farthest clear value is 0.f, not 1.f, under UseReversedZ. - .clearDepthValue = gx::UseReversedZ ? 0.f : 1.f, - .clearColor = true, - .clearDepth = true, - }; - push_render_pass(std::move(newPass)); - ++g_currentRenderPass; - - g_inOffscreen = true; - - g_cachedViewport = {0.f, 0.f, static_cast(width), static_cast(height), 0.f, 1.f}; - g_cachedScissor = {0, 0, static_cast(width), static_cast(height)}; - push_command(CommandType::SetViewport, Command::Data{.setViewport = g_cachedViewport}); - push_command(CommandType::SetScissor, Command::Data{.setScissor = g_cachedScissor}); -} - -void end_offscreen() { - ZoneScoped; - CHECK(g_inOffscreen, "end_offscreen called without begin_offscreen"); - - g_inOffscreen = false; - g_offscreenColor = {}; - g_offscreenDepth = {}; - - // Resume suspended EFB pass, or start a new one (load existing content) - if (g_suspendedEfbPass) { - // Keeps its own recorded commands. - g_renderPasses.emplace_back(std::move(*g_suspendedEfbPass)); - g_suspendedEfbPass.reset(); - } else { - auto& pass = push_render_pass(RenderPass{}); - pass.clearColor = false; - pass.clearDepth = false; - } - ++g_currentRenderPass; - set_efb_targets(g_renderPasses[g_currentRenderPass]); - - g_cachedViewport = g_suspendedEfbViewport; - g_cachedScissor = g_suspendedEfbScissor; - push_command(CommandType::SetViewport, Command::Data{.setViewport = g_cachedViewport}); - push_command(CommandType::SetScissor, Command::Data{.setScissor = g_cachedScissor}); -} - -template <> -void push_draw_command(gx::DrawData data) { - push_draw_command(ShaderDrawCommand{.type = ShaderType::GX, .gx = data}); -} - -template <> -PipelineRef pipeline_ref(const gx::PipelineConfig& config) { - return find_pipeline(ShaderType::GX, config, [=] { return create_pipeline(config); }); -} - -void initialize() { - g_frameIndex = 0; - depth_peek::initialize(); - tex_copy_conv::initialize(); - tex_palette_conv::initialize(); - texture_replacement::initialize(); - - // For uniform & storage buffer offset alignments - g_device.GetLimits(&g_cachedLimits); - - const auto createBuffer = [](wgpu::Buffer& out, wgpu::BufferUsage usage, uint64_t size, const char* label) { - if (size <= 0) { - return; - } - const wgpu::BufferDescriptor descriptor{ - .label = label, - .usage = usage, - .size = size, - }; - out = g_device.CreateBuffer(&descriptor); - }; - createBuffer(g_uniformBuffer, wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst, UniformBufferSize, - "Shared Uniform Buffer"); - createBuffer(g_vertexBuffer, wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopyDst, VertexBufferSize, - "Shared Vertex Buffer"); - createBuffer(g_indexBuffer, wgpu::BufferUsage::Index | wgpu::BufferUsage::CopyDst, IndexBufferSize, - "Shared Index Buffer"); - createBuffer(g_storageBuffer, wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopyDst, StorageBufferSize, - "Shared Storage Buffer"); - for (int i = 0; i < g_stagingBuffers.size(); ++i) { - const auto label = fmt::format("Staging Buffer {}", i); - createBuffer(g_stagingBuffers[i], wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc, StagingBufferSize, - label.c_str()); - } - currentStagingBuffer = 0; - s_mappingState.reset(); - map_staging_buffer(); - - { - constexpr std::array layoutEntries{ - // Vertex data buffer - wgpu::BindGroupLayoutEntry{ - .binding = 0, - .visibility = wgpu::ShaderStage::Vertex, - .buffer = - wgpu::BufferBindingLayout{ - .type = wgpu::BufferBindingType::ReadOnlyStorage, - }, - }, - // Storage data buffer - wgpu::BindGroupLayoutEntry{ - .binding = 1, - .visibility = wgpu::ShaderStage::Vertex, - .buffer = - wgpu::BufferBindingLayout{ - .type = wgpu::BufferBindingType::ReadOnlyStorage, - }, - }, - }; - const wgpu::BindGroupLayoutDescriptor layoutDesc{ - .label = "Static bind group layout", - .entryCount = layoutEntries.size(), - .entries = layoutEntries.data(), - }; - g_staticBindGroupLayout = g_device.CreateBindGroupLayout(&layoutDesc); - const std::array entries{ - wgpu::BindGroupEntry{ - .binding = 0, - .buffer = g_vertexBuffer, - }, - wgpu::BindGroupEntry{ - .binding = 1, - .buffer = g_storageBuffer, - }, - }; - const wgpu::BindGroupDescriptor bindGroupDescriptor{ - .label = "Static bind group", - .layout = g_staticBindGroupLayout, - .entryCount = entries.size(), - .entries = entries.data(), - }; - g_staticBindGroup = g_device.CreateBindGroup(&bindGroupDescriptor); - } - - { - constexpr std::array layoutEntries{ - // Uniform buffer (dynamic offset) - wgpu::BindGroupLayoutEntry{ - .binding = 0, - .visibility = wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment, - .buffer = - wgpu::BufferBindingLayout{ - .type = wgpu::BufferBindingType::Uniform, - .hasDynamicOffset = true, - }, - }, - }; - const wgpu::BindGroupLayoutDescriptor layoutDesc{ - .label = "Uniform bind group layout", - .entryCount = layoutEntries.size(), - .entries = layoutEntries.data(), - }; - g_uniformBindGroupLayout = g_device.CreateBindGroupLayout(&layoutDesc); - const std::array entries{ - wgpu::BindGroupEntry{ - .binding = 0, - .buffer = g_uniformBuffer, - .size = gx::MaxUniformSize, - }, - }; - const wgpu::BindGroupDescriptor bindGroupDescriptor{ - .label = "Uniform bind group", - .layout = g_uniformBindGroupLayout, - .entryCount = entries.size(), - .entries = entries.data(), - }; - g_uniformBindGroup = g_device.CreateBindGroup(&bindGroupDescriptor); - } - - gx::initialize(); - initialize_pipeline_cache(); -} - -void shutdown() { - shutdown_pipeline_cache(); - gx::clear_shader_module_cache(); - efb_ram::shutdown(); - depth_peek::shutdown(); - tex_copy_conv::shutdown(); - tex_palette_conv::shutdown(); - texture_replacement::shutdown(); - gx::shutdown(); - - g_textureUploads.clear(); - g_cachedBindGroups.clear(); - g_retiredBindGroups.clear(); - g_cachedSamplers.clear(); - g_vertexBuffer = {}; - g_uniformBuffer = {}; - g_indexBuffer = {}; - g_storageBuffer = {}; - // Invalidate outstanding callbacks before releasing their buffers. - s_mappingState.reset(); - g_stagingBuffers.fill({}); - for (auto& pool : g_resolveSourceSnapshotPools) { - pool.entry.reset(); - } - discard_suspended_efb_pass(); - g_renderPasses.clear(); - g_commandListPool.clear(); - g_currentRenderPass = UINT32_MAX; - g_offscreenCache.clear(); - g_offscreenColor = {}; - g_offscreenDepth = {}; - g_staticBindGroup = {}; - g_staticBindGroupLayout = {}; - g_uniformBindGroup = {}; - g_uniformBindGroupLayout = {}; - g_inOffscreen = false; - g_frameIndex = UINT32_MAX; - currentStagingBuffer = 0; -} - -void map_staging_buffer() { - const auto generation = s_mappingState.request(); - if (generation == 0) { - return; - } - - g_stagingBuffers[currentStagingBuffer].MapAsync( - wgpu::MapMode::Write, 0, StagingBufferSize, wgpu::CallbackMode::AllowSpontaneous, - [generation](wgpu::MapAsyncStatus status, wgpu::StringView message) { - const auto result = status == wgpu::MapAsyncStatus::Success - ? BufferMapState::Mapped : BufferMapState::Unmapped; - if (!s_mappingState.complete(generation, result)) return; - if (status == wgpu::MapAsyncStatus::CallbackCancelled || status == wgpu::MapAsyncStatus::Aborted) { - Log.warn("Buffer mapping {}: {}", magic_enum::enum_name(status), message); - return; - } - ASSERT(status == wgpu::MapAsyncStatus::Success, "Buffer mapping failed: {} {}", magic_enum::enum_name(status), - message); - }); -} - -static bool begin_frame_impl(bool clearEfb, bool capacityResume = false) { - ZoneScoped; - { - ZoneScopedN("Wait for buffer map"); - map_staging_buffer(); - while (true) { - const auto mappingState = s_mappingState.state(); - if (mappingState == BufferMapState::Mapped) { - break; - } - if (mappingState == BufferMapState::Unmapped) { - // Frame begin failed because the staging map was aborted; the caller's retry loop drops the frame - // and any one-shot bakes recorded into it. Rate-limited. - static uint32_t s_beginFrameMapFailCount = 0; - if (s_beginFrameMapFailCount < 64 || (s_beginFrameMapFailCount & 255) == 0) { - Log.warn("begin_frame aborted: staging buffer unmapped (frame={} occurrences={})", g_frameIndex, - s_beginFrameMapFailCount + 1); - } - ++s_beginFrameMapFailCount; - return false; - } - g_instance.ProcessEvents(); - webgpu::fail_if_device_lost(); - s_mappingState.wait_for_progress(); - } - } - ++g_stagingEpoch; - g_recordingSnapshotSlot = currentStagingBuffer; - size_t bufferOffset = 0; - const auto& stagingBuf = g_stagingBuffers[currentStagingBuffer]; - const auto mapBuffer = [&](ByteBuffer& buf, uint64_t size) { - if (size <= 0) { - return; - } - buf = ByteBuffer{static_cast(stagingBuf.GetMappedRange(bufferOffset, size)), static_cast(size)}; - bufferOffset += size; - }; - mapBuffer(g_verts, VertexBufferSize); - mapBuffer(g_uniforms, UniformBufferSize); - mapBuffer(g_indices, IndexBufferSize); - mapBuffer(g_storage, StorageBufferSize); - if constexpr (UseTextureBuffer) { - mapBuffer(g_textureUpload, TextureUploadSize); - } - - g_drawCallCount = 0; - g_mergedDrawCallCount = 0; - if (clearEfb) { - gx::begin_frame_interpolation(); - } - discard_suspended_efb_pass(); - if (!capacityResume) webgpu::clear_present_source_override(); - - push_render_pass(RenderPass{}); - set_efb_targets(g_renderPasses[0]); - g_renderPasses[0].clearColorValue = gx::g_gxState.clearColor; - g_renderPasses[0].clearDepthValue = gx::clear_depth_value(); - g_renderPasses[0].clearColor = clearEfb; - g_renderPasses[0].clearDepth = clearEfb; - g_currentRenderPass = 0; - // Refresh paired render viewport/scissor from logical state in case the FB size changed. - const auto mappedRenderState = gx::map_logical_render_state(); - const bool renderStateChanged = gx::g_gxState.renderViewport != mappedRenderState.viewport || - gx::g_gxState.renderScissor != mappedRenderState.scissor; - gx::g_gxState.renderViewport = mappedRenderState.viewport; - gx::g_gxState.renderScissor = mappedRenderState.scissor; - gx::g_gxState.stateDirty = gx::g_gxState.stateDirty || renderStateChanged; - g_cachedViewport = mappedRenderState.viewport; - g_cachedScissor = mappedRenderState.scissor; - push_command(CommandType::SetViewport, Command::Data{.setViewport = g_cachedViewport}); - push_command(CommandType::SetScissor, Command::Data{.setScissor = g_cachedScissor}); - begin_pipeline_frame(); - return true; -} - -bool begin_frame() { return begin_frame_impl(true); } - -bool resume_frame() { return begin_frame_impl(false); } - -void abort_frame() noexcept { - efb_ram::cancel(); - efb_ram::abort_async(); - g_verts.release(); - g_uniforms.release(); - g_indices.release(); - g_storage.release(); - if constexpr (UseTextureBuffer) { - g_textureUploads.clear(); - g_textureUpload.release(); - } - if (s_mappingState.state() == BufferMapState::Mapped) { - // Pending interpolation tasks hold raw pointers into the mapped staging - // range; they must be dropped before the buffer is unmapped and rotated. - gx::drop_pending_frame_interpolation_uniforms(); - g_stagingBuffers[currentStagingBuffer].Unmap(); - s_mappingState.reset(); - currentStagingBuffer = (currentStagingBuffer + 1) % g_stagingBuffers.size(); - map_staging_buffer(); - } - recycle_render_passes(g_renderPasses); - g_currentRenderPass = UINT32_MAX; - discard_suspended_efb_pass(); - g_inOffscreen = false; - for (auto& array : gx::g_gxState.arrays) { - array.cachedRange = {}; - } - webgpu::clear_present_source_override(); - end_pipeline_frame(); -} - -static void end_batch_impl(const wgpu::CommandEncoder& cmd, bool advanceFrame) { - ZoneScoped; - ASSERT(!advanceFrame || !g_inOffscreen, "end_frame called while offscreen rendering is active"); - if (advanceFrame) { - gx::finalize_frame_interpolation(); - } else { - // Mid-frame batch split: the staging buffer is about to be unmapped and rotated, so pending - // interpolation tasks pointing into it would dangle. Tie the clear to the rotation itself. - gx::drop_pending_frame_interpolation_uniforms(); - } - g_uniforms.append_zeroes(gx::MaxUniformSize); // Pad the end of the buffer - const auto used = staging_usage(); - for (unsigned i = 0; i < used.size(); ++i) g_stagingHighWater[i] = std::max(g_stagingHighWater[i], used[i]); - uint64_t bufferOffset = 0; - const auto writeBuffer = [&](ByteBuffer& buf, wgpu::Buffer& out, uint64_t size, std::string_view label) { - const auto writeSize = buf.size(); // Only need to copy this many bytes - if (writeSize > 0) { - cmd.CopyBufferToBuffer(g_stagingBuffers[currentStagingBuffer], bufferOffset, out, 0, AURORA_ALIGN(writeSize, 4)); - buf.release(); - } - bufferOffset += size; - return writeSize; - }; - g_stagingBuffers[currentStagingBuffer].Unmap(); - s_mappingState.reset(); - g_stats.drawCallCount = g_drawCallCount; - g_stats.mergedDrawCallCount = g_mergedDrawCallCount; - g_stats.lastVertSize = writeBuffer(g_verts, g_vertexBuffer, VertexBufferSize, "Vertex"); - g_stats.lastUniformSize = writeBuffer(g_uniforms, g_uniformBuffer, UniformBufferSize, "Uniform"); - g_stats.lastIndexSize = writeBuffer(g_indices, g_indexBuffer, IndexBufferSize, "Index"); - g_stats.lastStorageSize = writeBuffer(g_storage, g_storageBuffer, StorageBufferSize, "Storage"); - if constexpr (UseTextureBuffer) { - g_stats.lastTextureUploadSize = g_textureUpload.size(); - { - // Perform texture copies - for (const auto& item : g_textureUploads) { - const wgpu::TexelCopyBufferInfo buf{ - .layout = - wgpu::TexelCopyBufferLayout{ - .offset = item.layout.offset + bufferOffset, - .bytesPerRow = AURORA_ALIGN(item.layout.bytesPerRow, 256), - .rowsPerImage = item.layout.rowsPerImage, - }, - .buffer = g_stagingBuffers[currentStagingBuffer], - }; - cmd.CopyBufferToTexture(&buf, &item.tex, &item.size); - } - g_textureUploads.clear(); - g_textureUpload.release(); - } - } - currentStagingBuffer = (currentStagingBuffer + 1) % g_stagingBuffers.size(); - map_staging_buffer(); - g_currentRenderPass = UINT32_MAX; - for (auto& array : gx::g_gxState.arrays) { - array.cachedRange = {}; - } - end_pipeline_frame(); - if (advanceFrame) { - ++g_frameIndex; - } -} - -void end_frame(const wgpu::CommandEncoder& cmd) { end_batch_impl(cmd, true); } - -void end_batch(const wgpu::CommandEncoder& cmd) { end_batch_impl(cmd, false); } - -void split_staging_batch() { - // Never called under the decoder's renderer lock: the worker needs that lock - // to reach DONE. FIFO admission yields its unconsumed command first. - aurora::wait_for_frame_worker(); - std::lock_guard gpuLock(aurora::renderer_gpu_mutex()); - if (!has_current_render_pass()) - throw StagingCapacityError("Cannot split staging outside an active render pass"); - gx::mark_frame_interpolation_replay_unsafe(); - const bool offscreen = g_inOffscreen; - const auto viewport = g_cachedViewport; - const auto scissor = g_cachedScissor; - const auto renderViewport = gx::g_gxState.renderViewport; - const auto renderScissor = gx::g_gxState.renderScissor; - const auto& active = g_renderPasses[g_currentRenderPass]; - RenderPass continuation{ - .colorView = active.colorView, .resolveView = active.resolveView, - .depthView = active.depthView, .copySourceTexture = active.copySourceTexture, - .copySourceView = active.copySourceView, .copySourceDepthView = active.copySourceDepthView, - .targetSize = active.targetSize, .msaaSamples = active.msaaSamples, - .clearColor = false, .clearDepth = false, - .requireReadyPipelines = active.requireReadyPipelines || offscreen, - }; - auto suspended = std::move(g_suspendedEfbPass); - g_suspendedEfbPass.reset(); - std::array, 4> retained; - std::array buffers{&g_verts, &g_uniforms, &g_indices, &g_storage}; - if (suspended) { - for (unsigned i = 0; i < buffers.size(); ++i) { - if (g_suspendedEfbBytes[i]) - retained[i].assign(buffers[i]->data(), buffers[i]->data() + g_suspendedEfbBytes[i]); - } - } - auto encoder = g_device.CreateCommandEncoder(); - end_batch(encoder); - render(encoder); - aurora::submit_staging_commands(encoder.Finish()); - after_submit(); - if (!begin_frame_impl(false, true)) - throw StagingCapacityError("Staging remap failed after capacity submission"); - recycle_render_passes(g_renderPasses); - push_render_pass(std::move(continuation)); - g_currentRenderPass = 0; - g_suspendedEfbPass = std::move(suspended); - for (unsigned i = 0; i < buffers.size(); ++i) { - if (!retained[i].empty()) buffers[i]->append(retained[i].data(), retained[i].size()); - } - g_inOffscreen = offscreen; - g_cachedViewport = viewport; - g_cachedScissor = scissor; - gx::g_gxState.renderViewport = renderViewport; - gx::g_gxState.renderScissor = renderScissor; - gx::g_gxState.stateDirty = true; - push_command(CommandType::SetViewport, Command::Data{.setViewport = viewport}); - push_command(CommandType::SetScissor, Command::Data{.setScissor = scissor}); - ++g_stagingSplitCount; -} - -uint32_t current_frame() noexcept { return g_frameIndex; } - -// The only place that erases from g_cachedBindGroups, whose handles the frame being encoded still -// holds, so it runs in the seal prologue with the renderer mutex held and the producer excluded. -void expire_bind_group_cache() noexcept { - if (g_cachedBindGroups.empty() || g_frameIndex == UINT32_MAX || g_frameIndex % BindGroupCacheSweepPeriod != 0) { - return; - } - - ZoneScoped; - for (auto it = g_cachedBindGroups.begin(); it != g_cachedBindGroups.end();) { - if (g_frameIndex - it->second.lastUsedFrame > BindGroupCacheRetainFrames) { - g_cachedBindGroups.erase(it++); - } else { - ++it; - } - } -} - -// Debug labels for the render passes. Formatting them per pass per slot costs a heap-allocating -// fmt::format for a name nothing reads outside a capture. -static const char* render_pass_label(u32 index) noexcept { - static constexpr std::array kRenderPassLabels{ - "Render pass 0", "Render pass 1", "Render pass 2", "Render pass 3", - "Render pass 4", "Render pass 5", "Render pass 6", "Render pass 7", - "Render pass 8", "Render pass 9", "Render pass 10", "Render pass 11", - "Render pass 12", "Render pass 13", "Render pass 14", "Render pass 15", - }; - return index < kRenderPassLabels.size() ? kRenderPassLabels[index] : "Render pass"; -} - -static void render_pass_impl(const wgpu::RenderPassEncoder& pass, const std::vector& passes, u32 idx, - int32_t interpolatedFrame, DebugFrameData& debugFrame); - -static void render_impl(std::vector& renderPasses, wgpu::CommandEncoder& cmd, int32_t interpolatedFrame, - bool finalize, DebugFrameData& debugFrame, const depth_peek::FrameMapping& depthMapping) { - ZoneScoped; - // Palette conversions, MSAA resolves and EFB copies depend on sealed frame state, not on the - // interpolation weight, so encode them on the native render and let replay slots sample them. - const bool encodeTextureBakes = interpolatedFrame < 0; - for (u32 i = 0; i < renderPasses.size(); ++i) { - const auto& passInfo = renderPasses[i]; - if (encodeTextureBakes) { - for (const auto& conv : passInfo.paletteConvs) { - tex_palette_conv::run(cmd, conv); - } - } - const bool hasRenderWork = passInfo.clearColor || passInfo.clearDepth || !passInfo.commands.empty(); - if (i == renderPasses.size() - 1) { - ASSERT(!passInfo.resolveTarget, "Final render pass must not have resolve target"); - } else if (!(passInfo.resolveTarget && encodeTextureBakes) && !hasRenderWork) { - // Skip only empty intermediate passes: offscreen and scratch passes with resolves still have to - // run for later samplers, and on a replay slot a resolve-only pass has nothing to encode. - continue; - } - - const std::array attachments{ - wgpu::RenderPassColorAttachment{ - .view = passInfo.colorView, - .resolveTarget = passInfo.resolveView, - .loadOp = passInfo.clearColor ? wgpu::LoadOp::Clear : wgpu::LoadOp::Load, - .storeOp = wgpu::StoreOp::Store, - .clearValue = - { - .r = passInfo.clearColorValue.x(), - .g = passInfo.clearColorValue.y(), - .b = passInfo.clearColorValue.z(), - .a = passInfo.clearColorValue.w(), - }, - }, - }; - const wgpu::RenderPassDepthStencilAttachment depthStencilAttachment{ - .view = passInfo.depthView, - .depthLoadOp = passInfo.clearDepth ? wgpu::LoadOp::Clear : wgpu::LoadOp::Load, - .depthStoreOp = wgpu::StoreOp::Store, - .depthClearValue = passInfo.clearDepthValue, - }; - const wgpu::RenderPassDescriptor renderPassDescriptor{ - .label = render_pass_label(i), - .colorAttachmentCount = attachments.size(), - .colorAttachments = attachments.data(), - .depthStencilAttachment = &depthStencilAttachment, - }; - - auto pass = cmd.BeginRenderPass(&renderPassDescriptor); - render_pass_impl(pass, renderPasses, i, interpolatedFrame, debugFrame); - pass.End(); - - if (finalize && i == renderPasses.size() - 1) { - depth_peek::encode_frame_snapshot(cmd, passInfo.copySourceDepthView, passInfo.targetSize, passInfo.msaaSamples, depthMapping); - } - - if (passInfo.resolveTarget) { - const bool isDepth = gx::is_depth_format(passInfo.resolveFormat); - wgpu::Texture resolveSourceTexture = passInfo.copySourceTexture; - wgpu::TextureView resolveSourceView = isDepth ? passInfo.copySourceDepthView : passInfo.copySourceView; - if (passInfo.snapshotColorResolveSource && passInfo.resolveSourceSnapshot) { - const wgpu::TexelCopyTextureInfo src{ - .texture = passInfo.copySourceTexture, - .origin = wgpu::Origin3D{ - .x = static_cast(passInfo.resolveSnapshotRect.x), - .y = static_cast(passInfo.resolveSnapshotRect.y), - }, - }; - const wgpu::TexelCopyTextureInfo dst{ - .texture = passInfo.resolveSourceSnapshot->texture, - }; - const wgpu::Extent3D size{ - .width = static_cast(passInfo.resolveSnapshotRect.width), - .height = static_cast(passInfo.resolveSnapshotRect.height), - .depthOrArrayLayers = 1, - }; - cmd.CopyTextureToTexture(&src, &dst, &size); - resolveSourceTexture = passInfo.resolveSourceSnapshot->texture; - resolveSourceView = passInfo.resolveSourceSnapshot->sampleTextureView; - } - if (isDepth && passInfo.msaaSamples > 1) { - Log.fatal("Depth tex copies from multisampled EFB targets are not supported"); - } - const tex_copy_conv::ConvRequest convReq{ - .fmt = passInfo.resolveFormat, - .srcView = resolveSourceView, - .uniformRange = passInfo.resolveUniformRange, - .dst = passInfo.resolveTarget, - .sampleFilter = passInfo.resolveLinearSampling - ? tex_copy_conv::SampleFilter::Linear - : tex_copy_conv::SampleFilter::Nearest, - .forceOpaqueAlpha = passInfo.resolveForceOpaqueAlpha, - }; - if (passInfo.resolveNeedsConversion) { - tex_copy_conv::run(cmd, convReq); - } else if (passInfo.resolveNeedsShaderSampling) { - tex_copy_conv::blit(cmd, convReq); - } else { - const wgpu::TexelCopyTextureInfo src{ - .texture = resolveSourceTexture, - .origin = - wgpu::Origin3D{ - .x = static_cast(passInfo.resolveRect.x - - (passInfo.snapshotColorResolveSource - ? passInfo.resolveSnapshotRect.x : 0)), - .y = static_cast(passInfo.resolveRect.y - - (passInfo.snapshotColorResolveSource - ? passInfo.resolveSnapshotRect.y : 0)), - }, - }; - const wgpu::TexelCopyTextureInfo dst{ - .texture = passInfo.resolveTarget->texture, - }; - const wgpu::Extent3D size{ - .width = static_cast(passInfo.resolveRect.width), - .height = static_cast(passInfo.resolveRect.height), - .depthOrArrayLayers = 1, - }; - cmd.CopyTextureToTexture(&src, &dst, &size); - } - } - } - if (finalize) { - recycle_render_passes(renderPasses); - } - -#if defined(AURORA_GFX_DEBUG_GROUPS) - if (finalize && !debugFrame.groups.empty()) { - for (auto it = debugFrame.groups.rbegin(); it != debugFrame.groups.rend(); ++it) { - Log.warn("Debug group was not popped at end of frame: {}", *it); - } - debugFrame.groups.clear(); - } - - if (finalize && debugFrame.markers.size() > 0) { - debugFrame.markers.clear(); - } -#endif -} - -void seal_frame(SealedFrame& out) noexcept { - out.data().depthMapping = depth_peek::capture_frame_mapping(); - ZoneScoped; - // The encode that could still have been holding these has completed: the - // producer joins the worker's DONE phase before it seals another frame. - g_retiredBindGroups.clear(); - auto& passes = out.data().passes; - // The previous cycle already recycled these, so this normally just hands the empty vector, its - // capacity included, back to the producer. - recycle_render_passes(passes); - passes.swap(g_renderPasses); -#ifdef AURORA_GFX_DEBUG_GROUPS - // Marker indices and unmatched-group warnings belong to these detached passes. - // The next producer frame must not modify strings still read by this encoder. - auto& debug = out.data().debug; - debug.groups.clear(); - debug.markers.clear(); - debug.groups.swap(g_debugFrame.groups); - debug.markers.swap(g_debugFrame.markers); -#endif - g_currentRenderPass = UINT32_MAX; -} - -void render(SealedFrame& frame, wgpu::CommandEncoder& cmd, int32_t interpolatedFrame, bool finalize) { - render_impl(frame.data().passes, cmd, interpolatedFrame, finalize, frame.data().debug, frame.data().depthMapping); -} - -void render(wgpu::CommandEncoder& cmd, int32_t interpolatedFrame, bool finalize) { - render_impl(g_renderPasses, cmd, interpolatedFrame, finalize, g_debugFrame, depth_peek::capture_frame_mapping()); - if (finalize) { - g_currentRenderPass = UINT32_MAX; - expire_bind_group_cache(); - } -} - -void after_submit() noexcept { - depth_peek::after_submit(); - efb_ram::after_submit(); - // Retire this frame's completed GPU work. Dawn only reclaims destroyed resources inside a device - // tick, and a frame that never ticks keeps every released image and its memory for the run. - if (g_instance) { - g_instance.ProcessEvents(); - } -} - -static void render_pass_impl(const wgpu::RenderPassEncoder& pass, const std::vector& renderPasses, u32 idx, - int32_t interpolatedFrame, DebugFrameData& debugFrame) { - // Per-invocation, not per-process: two encoders can be recording at once. - gx::DrawEncodeState encodeState{}; - encodeState.boundTextureBindGroup = gx::g_emptyTextureBindGroup.Get(); -#ifdef AURORA_GFX_DEBUG_GROUPS - std::vector lastDebugGroupStack; -#endif - - // Bind static bind group for the whole pass - pass.SetBindGroup(0, g_staticBindGroup); - pass.SetBindGroup(2, gx::g_emptyTextureBindGroup); - - for (const auto& cmd : renderPasses[idx].commands) { -#ifdef AURORA_GFX_DEBUG_GROUPS - { - size_t firstDiff = lastDebugGroupStack.size(); - for (size_t i = 0; i < lastDebugGroupStack.size(); ++i) { - if (i >= cmd.debugGroupStack.size() || cmd.debugGroupStack[i] != lastDebugGroupStack[i]) { - firstDiff = i; - break; - } - } - for (size_t i = firstDiff; i < lastDebugGroupStack.size(); ++i) { - pass.PopDebugGroup(); - } - for (size_t i = firstDiff; i < cmd.debugGroupStack.size(); ++i) { - pass.PushDebugGroup(cmd.debugGroupStack[i].c_str()); - } - lastDebugGroupStack = cmd.debugGroupStack; - } -#endif - switch (cmd.type) { - case CommandType::SetViewport: { - const auto& vp = cmd.data.setViewport; - // WebGPU requires 0 <= minDepth <= maxDepth <= 1. vp.znear/vp.zfar are in GX's own distance - // terms (0 = near); under UseReversedZ the host depth-buffer storage direction is flipped - // (near = 1, far = 0), so this range has to be remapped through 1-x the same way the - // projection matrix, depth compare function, and clear value all are - a plain min/max clamp - // (the previous code here) maps a *restricted* range (e.g. a viewport deliberately narrowed - // to force something to draw "in front of everything") to the wrong end of the buffer: what - // should land near the near-storage-extreme (1.0) instead lands near the far-storage-extreme - // (0.0), so anything else drawn afterward at its true depth wins the compare test and the - // "in front" geometry silently vanishes. A full [0,1] viewport is unaffected either way, - // which is why this only broke specific elements, not the whole scene. Matches upstream - // aurora's apply_viewport (lib/gfx/encoding.cpp) exactly. - const float minDepth = gx::UseReversedZ ? 1.0f - vp.zfar : vp.znear; - const float maxDepth = gx::UseReversedZ ? 1.0f - vp.znear : vp.zfar; - pass.SetViewport(vp.left, vp.top, vp.width, vp.height, minDepth, maxDepth); - } break; - case CommandType::SetScissor: { - const auto& sc = cmd.data.setScissor; - const auto& size = renderPasses[idx].targetSize; - const auto left = std::clamp(sc.x, 0, static_cast(size.width)); - const auto top = std::clamp(sc.y, 0, static_cast(size.height)); - const auto right = - std::clamp(sc.x + sc.width, left, static_cast(size.width)); - const auto bottom = - std::clamp(sc.y + sc.height, top, static_cast(size.height)); - pass.SetScissorRect(static_cast(left), static_cast(top), - static_cast(right - left), static_cast(bottom - top)); - } break; - case CommandType::Draw: { - const auto& draw = cmd.data.draw; - switch (draw.type) { - case ShaderType::GX: { - const gfx::Range* uniformOverride = nullptr; - if (interpolatedFrame >= 0 && - static_cast(interpolatedFrame) < draw.gx.interpolatedUniformRanges.size() && - draw.gx.interpolatedUniformRanges[interpolatedFrame].size != 0) { - uniformOverride = &draw.gx.interpolatedUniformRanges[interpolatedFrame]; - } - gx::render(draw.gx, pass, encodeState, renderPasses[idx].requireReadyPipelines, uniformOverride); - } break; - case ShaderType::Clear: - clear::render(draw.clear, pass, renderPasses[idx].targetSize, encodeState.currentPipeline); - break; - } - } break; - case CommandType::DebugMarker: { -#if defined(AURORA_GFX_DEBUG_GROUPS) - pass.InsertDebugMarker(wgpu::StringView(debugFrame.markers[cmd.data.debugMarkerIndex])); -#endif - } break; - } - } - -#ifdef AURORA_GFX_DEBUG_GROUPS - for (size_t i = 0; i < lastDebugGroupStack.size(); ++i) { - pass.PopDebugGroup(); - } -#endif -} - -bool bind_pipeline(PipelineRef ref, const wgpu::RenderPassEncoder& pass, PipelineRef& currentPipeline, - bool requireReady) { - if (ref == currentPipeline) { - return true; - } - wgpu::RenderPipeline pipeline; - bool pipelineReady; - if (!skip_unready_pipelines()) { - pipelineReady = wait_pipeline(ref, pipeline); - } else if (requireReady) { - // The pass resolves into a persistent texture (a one-shot bake such as MKW's minimap), so a - // skipped draw would never be re-issued. These run behind loads, not mid-race. - pipelineReady = wait_pipeline_for_persistent_pass(ref, pipeline); - } else { - pipelineReady = try_pipeline(ref, pipeline); - } - if (!pipelineReady) { - return false; - } - pass.SetPipeline(pipeline); - currentPipeline = ref; - return true; -} - -static inline Range push(ByteBuffer& target, const uint8_t* data, size_t length, size_t alignment) { - size_t padding = 0; - if (alignment != 0) { - const size_t remainder = length % alignment; - if (remainder != 0) { - padding = alignment - remainder; - } - } - auto begin = target.size(); - if (length == 0) { - length = alignment; - target.append_zeroes(alignment); - } else { - target.append(data, length); - if (padding > 0) { - target.append_zeroes(padding); - } - } - return {static_cast(begin), static_cast(length + padding)}; -} -static inline Range map(ByteBuffer& target, size_t length, size_t alignment) { - size_t padding = 0; - if (alignment != 0) { - const size_t remainder = length % alignment; - if (remainder != 0) { - padding = alignment - remainder; - } - } - auto begin = target.size(); - if (length == 0) { - length = alignment; - target.append_zeroes(length); - } else { - // The caller fills [0, length); only the alignment padding needs clearing, - // otherwise it hands the next frame's readers whatever was there before. - target.append_uninitialized(length); - target.append_zeroes(padding); - } - return {static_cast(begin), static_cast(length + padding)}; -} -Range push_verts(const uint8_t* data, size_t length) { return push(g_verts, data, length, 0); } -Range push_indices(const uint8_t* data, size_t length) { return push(g_indices, data, length, 0); } -Range push_uniform(const uint8_t* data, size_t length) { - return push(g_uniforms, data, length, g_cachedLimits.minUniformBufferOffsetAlignment); -} -Range push_storage(const uint8_t* data, size_t length) { - return push(g_storage, data, length, g_cachedLimits.minStorageBufferOffsetAlignment); -} -Range push_texture_data(const uint8_t* data, size_t length, u32 bytesPerRow, u32 rowsPerImage) { - // For CopyBufferToTexture, we need an alignment of 256 per row (see Dawn kTextureBytesPerRowAlignment) - const auto copyBytesPerRow = AURORA_ALIGN(bytesPerRow, 256); - const auto range = map(g_textureUpload, copyBytesPerRow * rowsPerImage, 0); - u8* dst = g_textureUpload.data() + range.offset; - for (u32 i = 0; i < rowsPerImage; ++i) { - memcpy(dst, data, bytesPerRow); - data += bytesPerRow; - dst += copyBytesPerRow; - } - return range; -} -std::pair map_verts(size_t length) { - const auto range = map(g_verts, length, 4); - return {ByteBuffer{g_verts.data() + range.offset, range.size}, range}; -} -std::pair map_indices(size_t length) { - const auto range = map(g_indices, length, 4); - return {ByteBuffer{g_indices.data() + range.offset, range.size}, range}; -} -std::pair map_uniform(size_t length) { - const auto range = map(g_uniforms, length, g_cachedLimits.minUniformBufferOffsetAlignment); - return {ByteBuffer{g_uniforms.data() + range.offset, range.size}, range}; -} -std::pair copy_uniform(Range source) { - const auto destination = map(g_uniforms, source.size, g_cachedLimits.minUniformBufferOffsetAlignment); - std::memcpy(g_uniforms.data() + destination.offset, g_uniforms.data() + source.offset, source.size); - return {ByteBuffer{g_uniforms.data() + destination.offset, destination.size}, destination}; -} -std::pair map_storage(size_t length) { - const auto range = map(g_storage, length, g_cachedLimits.minStorageBufferOffsetAlignment); - return {ByteBuffer{g_storage.data() + range.offset, range.size}, range}; -} - -BindGroupRef bind_group_ref(const WGPUBindGroupDescriptor& descriptor) { - const auto id = xxh3_hash(descriptor); - const auto it = g_cachedBindGroups.find(id); - if (it == g_cachedBindGroups.end()) { - auto bg = wgpu::BindGroup::Acquire(wgpuDeviceCreateBindGroup(g_device.Get(), &descriptor)); - g_cachedBindGroups.emplace(id, CachedBindGroup{ - .bindGroup = std::move(bg), - .lastUsedFrame = g_frameIndex, - }); - } else { - it->second.lastUsedFrame = g_frameIndex; - } - return id; -} - -wgpu::BindGroup& find_bind_group(BindGroupRef id) { - const auto it = g_cachedBindGroups.find(id); - CHECK(it != g_cachedBindGroups.end(), "get_bind_group: failed to locate {:x}", id); - return it->second.bindGroup; -} - -wgpu::Sampler& sampler_ref(const wgpu::SamplerDescriptor& descriptor) { - const auto id = xxh3_hash(descriptor); - auto it = g_cachedSamplers.find(id); - if (it == g_cachedSamplers.end()) { - it = g_cachedSamplers.try_emplace(id, g_device.CreateSampler(&descriptor)).first; - } - return it->second; -} - -uint32_t align_uniform(uint32_t value) { return AURORA_ALIGN(value, g_cachedLimits.minUniformBufferOffsetAlignment); } - -void insert_debug_marker(std::string label) { -#if defined(AURORA_GFX_DEBUG_GROUPS) - auto idx = g_debugFrame.markers.size(); - g_debugFrame.markers.emplace_back(std::move(label)); - push_command(CommandType::DebugMarker, {.debugMarkerIndex = idx}); -#endif -} - -} // namespace aurora::gfx - -void aurora::gfx::push_debug_group(std::string label) { -#if defined(AURORA_GFX_DEBUG_GROUPS) - g_debugFrame.groups.push_back(std::move(label)); -#endif -} -void aurora_push_debug_group(const char* label) { -#ifdef AURORA_GFX_DEBUG_GROUPS - aurora::gfx::g_debugFrame.groups.emplace_back(label); -#endif -} -void aurora_pop_debug_group() { -#ifdef AURORA_GFX_DEBUG_GROUPS - if (aurora::gfx::g_debugFrame.groups.empty()) { - aurora::gfx::Log.error("Debug group stack underflowed!"); - return; - } - - aurora::gfx::g_debugFrame.groups.pop_back(); -#endif -} - -const AuroraStats* aurora_get_stats() { return &aurora::gfx::g_stats; } diff --git a/aurora-main/lib/gfx/common.hpp b/aurora-main/lib/gfx/common.hpp deleted file mode 100644 index b2993a8..0000000 --- a/aurora-main/lib/gfx/common.hpp +++ /dev/null @@ -1,422 +0,0 @@ -#pragma once -#include "staging_capacity.hpp" - -#include "../internal.hpp" -#include "../webgpu/gpu.hpp" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#define XXH_STATIC_LINKING_ONLY -#include - -namespace aurora { -#if INTPTR_MAX == INT32_MAX -using HashType = XXH32_hash_t; -#else -using HashType = XXH64_hash_t; -#endif -static inline HashType xxh3_hash_s(const void* input, size_t len, HashType seed = 0) { - return static_cast(XXH3_64bits_withSeed(input, len, seed)); -} -template -static inline HashType xxh3_hash(const T& input, HashType seed = 0) { - // Validate that the type has no padding bytes, which can easily cause - // hash mismatches. This also disallows floats, but that's okay for us. - static_assert(std::has_unique_object_representations_v); - return xxh3_hash_s(&input, sizeof(T), seed); -} - -// Folds two 64-bit hashes. Chaining them instead drops XXH3 onto its seeded long path past 240 -// bytes, and that path regenerates a 192-byte secret on every call. -static inline HashType hash_combine(HashType lhs, HashType rhs) { - uint64_t mixed = static_cast(lhs) ^ (static_cast(rhs) + 0x9E3779B97F4A7C15ull + - (static_cast(lhs) << 6) + (static_cast(lhs) >> 2)); - mixed ^= mixed >> 33; - mixed *= 0xFF51AFD7ED558CCDull; - mixed ^= mixed >> 29; - return static_cast(mixed); -} - -// Guest-RAM write tracking hooks (see aurora_set_guest_write_hooks). A digest samples the -// generation before reading the bytes, so a racing write costs an extra digest, never a skipped one. -inline constexpr uint64_t kGuestWriteUntracked = AURORA_GUEST_WRITE_UNTRACKED; -inline AuroraGuestWriteGenerationCallback g_guestWriteGenerationHook = nullptr; -inline AuroraGuestWriteNotifyCallback g_guestWriteNotifyHook = nullptr; - -inline uint64_t guest_write_generation(const void* data, size_t size) noexcept { - if (g_guestWriteGenerationHook == nullptr || data == nullptr || size == 0) { - return kGuestWriteUntracked; - } - return g_guestWriteGenerationHook(data, size); -} - -inline void notify_guest_write(const void* data, size_t size) noexcept { - if (g_guestWriteNotifyHook == nullptr || data == nullptr || size == 0) { - return; - } - g_guestWriteNotifyHook(data, size); -} - -// True when `stored` was taken over the same untouched bytes, so its digest still describes them. -// The untracked sentinel never matches: a source aurora cannot watch is always re-digested. -inline bool guest_write_generation_matches(uint64_t stored, uint64_t current) noexcept { - return current != kGuestWriteUntracked && stored == current; -} - -class Hasher { -public: - explicit Hasher(const XXH64_hash_t seed = 0) { - XXH3_INITSTATE(&state); - XXH3_64bits_reset_withSeed(&state, seed); - } - - void update(const void* data, const size_t size) { XXH3_64bits_update(&state, data, size); } - - template - void update(const T& data) { - static_assert(std::has_unique_object_representations_v); - update(&data, sizeof(T)); - } - - [[nodiscard]] XXH64_hash_t digest() const { return XXH3_64bits_digest(&state); } - -private: - XXH3_state_t state; -}; - -class ByteBuffer { -public: - ByteBuffer() noexcept = default; - explicit ByteBuffer(size_t size) noexcept - : m_data(static_cast(calloc(1, size))), m_length(size), m_capacity(size) {} - explicit ByteBuffer(uint8_t* data, size_t size) noexcept : m_data(data), m_capacity(size), m_owned(false) {} - ~ByteBuffer() noexcept { - if (m_data != nullptr && m_owned) { - free(m_data); - } - } - ByteBuffer(ByteBuffer&& rhs) noexcept - : m_data(rhs.m_data), m_length(rhs.m_length), m_capacity(rhs.m_capacity), m_owned(rhs.m_owned) { - rhs.m_data = nullptr; - rhs.m_length = 0; - rhs.m_capacity = 0; - rhs.m_owned = true; - } - ByteBuffer& operator=(ByteBuffer&& rhs) noexcept { - if (m_data != nullptr && m_owned) { - free(m_data); - } - m_data = rhs.m_data; - m_length = rhs.m_length; - m_capacity = rhs.m_capacity; - m_owned = rhs.m_owned; - rhs.m_data = nullptr; - rhs.m_length = 0; - rhs.m_capacity = 0; - rhs.m_owned = true; - return *this; - } - ByteBuffer(ByteBuffer const&) = delete; - ByteBuffer& operator=(ByteBuffer const&) = delete; - operator ArrayRef() const noexcept { return {m_data, m_length}; } - - [[nodiscard]] uint8_t* data() noexcept { return m_data; } - [[nodiscard]] const uint8_t* data() const noexcept { return m_data; } - [[nodiscard]] size_t size() const noexcept { return m_length; } - [[nodiscard]] bool empty() const noexcept { return m_length == 0; } - - void append(const void* data, size_t size) { - resize(m_length + size, false); - memcpy(m_data + m_length, data, size); - m_length += size; - } - - template - void append(const T& obj) { - append(&obj, sizeof(T)); - } - - void append_zeroes(size_t size) { - resize(m_length + size, true); - m_length += size; - } - - // Extend the buffer without clearing the new bytes. Only for callers that overwrite the whole - // region: the mapped staging buffers are megabytes of write-combine memory. - void append_uninitialized(size_t size) { - resize(m_length + size, false); - m_length += size; - } - - void release() { - if (m_data != nullptr && m_owned) { - free(m_data); - } - m_data = nullptr; - m_length = 0; - m_capacity = 0; - m_owned = true; - } - - void clear() { - m_length = 0; - } - - void reserve_extra(size_t size) { resize(m_length + size, true); } - - ByteBuffer clone() const { - ByteBuffer clone{m_length}; - std::memcpy(clone.data(), m_data, m_length); - return clone; - } - -private: - uint8_t* m_data = nullptr; - size_t m_length = 0; - size_t m_capacity = 0; - bool m_owned = true; - - // `size` is the total capacity needed. When `zeroed` is set, [m_length, size) has to read back as - // zero on every branch; the early return used to leave the previous frame's bytes in the padding. - void resize(size_t size, bool zeroed) { - if (size == 0) { - clear(); - return; - } - const size_t zeroBegin = m_length; - if (m_data == nullptr) { - if (zeroed) { - m_data = static_cast(calloc(1, size)); - } else { - m_data = static_cast(malloc(size)); - } - m_owned = true; - m_capacity = size; - // calloc already cleared the whole allocation. - return; - } - if (size > m_capacity) { - if (!m_owned) { - abort(); - } - // Exponential expansion to avoid O(n^2) time complexity. - size_t capacity = size; - if (capacity < m_capacity * 2) { - capacity = m_capacity * 2; - } - m_data = static_cast(realloc(m_data, capacity)); - m_capacity = capacity; - } - if (zeroed && size > zeroBegin) { - memset(m_data + zeroBegin, 0, size - zeroBegin); - } - } -}; -} // namespace aurora - -namespace aurora::gfx { -inline constexpr bool UseTextureBuffer = false; -inline constexpr uint64_t UniformBufferSize = 25165824; // 24mb -inline constexpr uint64_t VertexBufferSize = 3145728; // 3mb -inline constexpr uint64_t IndexBufferSize = 2097152; // 2mb -inline constexpr uint64_t StorageBufferSize = 8388608; // 8mb -inline constexpr uint64_t TextureUploadSize = 25165824; // 24mb - -extern AuroraStats g_stats; -extern uint32_t g_drawCallCount; -extern uint32_t g_mergedDrawCallCount; -extern wgpu::Buffer g_vertexBuffer; -extern wgpu::Buffer g_uniformBuffer; -extern wgpu::Buffer g_indexBuffer; -extern wgpu::Buffer g_storageBuffer; -extern wgpu::BindGroupLayout g_staticBindGroupLayout; -extern wgpu::BindGroup g_staticBindGroup; -extern wgpu::BindGroupLayout g_uniformBindGroupLayout; -extern wgpu::BindGroup g_uniformBindGroup; - -using BindGroupRef = HashType; -using PipelineRef = HashType; -using SamplerRef = HashType; -using ShaderRef = HashType; -struct Range { - uint32_t offset = 0; - uint32_t size = 0; - - bool operator==(const Range& rhs) const { return memcmp(this, &rhs, sizeof(*this)) == 0; } - bool operator!=(const Range& rhs) const { return !(*this == rhs); } -}; - -struct ClipRect { - int32_t x; - int32_t y; - int32_t width; - int32_t height; - - bool operator==(const ClipRect& rhs) const { return memcmp(this, &rhs, sizeof(*this)) == 0; } - bool operator!=(const ClipRect& rhs) const { return !(*this == rhs); } -}; - -using webgpu::Viewport; - -struct TextureRef; -using TextureHandle = std::shared_ptr; - -enum class ShaderType : uint8_t { - Clear = 0, - GX = 1, -}; - -void initialize(); -void shutdown(); - -bool begin_frame(); -bool resume_frame(); -void abort_frame() noexcept; -void end_frame(const wgpu::CommandEncoder& cmd); -void end_batch(const wgpu::CommandEncoder& cmd); -uint32_t current_frame() noexcept; - -// One frame's recorded render passes, detached from the guest-visible -// recording state. The contents are private to common.cpp. -struct SealedFrameData; - -// Owns the recorded passes of a sealed frame, touched only by the thread that sealed it. -// seal_frame() runs with the producer excluded, and the object is reused to keep its capacity. -class SealedFrame { -public: - SealedFrame(); - ~SealedFrame(); - SealedFrame(SealedFrame&&) noexcept; - SealedFrame& operator=(SealedFrame&&) noexcept; - SealedFrame(const SealedFrame&) = delete; - SealedFrame& operator=(const SealedFrame&) = delete; - - [[nodiscard]] SealedFrameData& data() const noexcept { return *m_data; } - -private: - std::unique_ptr m_data; -}; - -// Detach the recorded passes of the frame that just ended into `out`. Must be -// called with the renderer GPU mutex held; see SealedFrame. -void seal_frame(SealedFrame& out) noexcept; - -// Encode a sealed frame. Never touches the producer-visible recording state, -// so this may run concurrently with the producer's FIFO drains. -void render(SealedFrame& frame, wgpu::CommandEncoder& cmd, int32_t interpolatedFrame = -1, bool finalize = true); - -// Encode the frame that is still being recorded. Only for the synchronous -// EFB-readback split path, which runs on the producer thread. -void render(wgpu::CommandEncoder& cmd, int32_t interpolatedFrame = -1, bool finalize = true); - -// Sweep bind groups that have not been used for a while. Mutates the cache the producer inserts -// into, so it may only run with the producer excluded, inside the seal prologue. -void expire_bind_group_cache() noexcept; -void after_submit() noexcept; -void map_staging_buffer(); -// `persistentCopy` marks resolves whose destination outlives the frame with no re-issue path, so -// the pass waits for its pipelines instead of dropping draws that would be baked in permanently. -void resolve_pass(TextureHandle texture, ClipRect rect, bool clearColor, bool clearAlpha, bool clearDepth, - Vec4 clearColorValue, float clearDepthValue, GXTexFmt resolveFormat = GX_TF_RGBA8, - const Vec4* sourceRectPixels = nullptr, bool halfScale = false, - const std::array* copyFilterCoefficients = nullptr, bool forceOpaqueAlpha = false, - float copyFilterRowStride = 1.0f, bool clampTop = false, bool clampBottom = false, - bool persistentCopy = false); - -void begin_offscreen(uint32_t width, uint32_t height); -void end_offscreen(); -bool is_offscreen() noexcept; -uint32_t get_sample_count() noexcept; -void clear_caches() noexcept; - -namespace tex_palette_conv { -struct ConvRequest; -} // namespace tex_palette_conv -void queue_palette_conv(tex_palette_conv::ConvRequest req); - -Range push_verts(const uint8_t* data, size_t length); -template -static Range push_verts(ArrayRef data) { - return push_verts(reinterpret_cast(data.data()), data.size() * sizeof(T)); -} -Range push_indices(const uint8_t* data, size_t length); -template -static Range push_indices(ArrayRef data) { - return push_indices(reinterpret_cast(data.data()), data.size() * sizeof(T)); -} -Range push_uniform(const uint8_t* data, size_t length); -template -static Range push_uniform(const T& data) { - return push_uniform(reinterpret_cast(&data), sizeof(T)); -} -Range push_storage(const uint8_t* data, size_t length); -template -static Range push_storage(ArrayRef data) { - return push_storage(reinterpret_cast(data.data()), data.size() * sizeof(T)); -} -template -static Range push_storage(const T& data) { - return push_storage(reinterpret_cast(&data), sizeof(T)); -} -Range push_texture_data(const uint8_t* data, size_t length, uint32_t bytesPerRow, uint32_t rowsPerImage); -std::pair map_verts(size_t length); -std::pair map_indices(size_t length); -std::pair map_uniform(size_t length); -std::pair copy_uniform(Range source); -std::pair map_storage(size_t length); - -template -const State& get_state(); -template -void push_draw_command(DrawData data); -template -DrawData* get_last_draw_command(); - -template -PipelineRef pipeline_ref(const PipelineConfig& config); -// `currentPipeline` is the caller's per-pass dedupe slot; as a file-static, two concurrent encoders -// skipped each other's SetPipeline. `requireReady` refuses the skip-unready shortcut for bakes. -bool bind_pipeline(PipelineRef ref, const wgpu::RenderPassEncoder& pass, PipelineRef& currentPipeline, - bool requireReady = false); - -BindGroupRef bind_group_ref(const WGPUBindGroupDescriptor& descriptor); -wgpu::BindGroup& find_bind_group(BindGroupRef id); - -wgpu::Sampler& sampler_ref(const wgpu::SamplerDescriptor& descriptor); - -uint32_t align_uniform(uint32_t value); -uint64_t staging_uniform_bytes(uint64_t bytes); -uint64_t staging_storage_bytes(uint64_t bytes); -// Admission does not allocate. A false result requires a producer-side split. -// Oversized operations fail before mutating the current draw/pass. -bool staging_has_space(const StagingSizes& demand); -void ensure_staging_space(const StagingSizes& demand); -void split_staging_batch(); -uint64_t staging_epoch() noexcept; -StagingSizes staging_usage() noexcept; -StagingSizes staging_high_water() noexcept; -uint64_t staging_split_count() noexcept; -// Internal integration-test seam: never increases the physical allocation. -void set_staging_capacity_limits_for_testing(const StagingSizes& limits); - - -Vec2 get_render_target_size() noexcept; -// Same value as get_render_target_size() outside a render pass, but never -// touches the frame worker's render-pass list, so it is safe off-thread. -Vec2 get_frame_buffer_size() noexcept; -void set_viewport(const Viewport& viewport) noexcept; -void set_scissor(const ClipRect& scissor) noexcept; - -void push_debug_group(std::string label); -void insert_debug_marker(std::string label); -} // namespace aurora::gfx diff --git a/aurora-main/lib/gfx/dds_io.cpp b/aurora-main/lib/gfx/dds_io.cpp deleted file mode 100644 index 84eecc2..0000000 --- a/aurora-main/lib/gfx/dds_io.cpp +++ /dev/null @@ -1,256 +0,0 @@ -#include "dds_io.hpp" - -#include -#include -#include - -#include "texture.hpp" - -namespace aurora::gfx::dds { -struct ParsedDDSLayout { - wgpu::TextureFormat format = wgpu::TextureFormat::Undefined; - size_t dataOffset = 0; -}; - -struct DDSPixelFormat { - uint32_t size; - uint32_t flags; - uint32_t fourCC; - uint32_t rgbBitCount; - uint32_t rBitMask; - uint32_t gBitMask; - uint32_t bBitMask; - uint32_t aBitMask; -}; -static_assert(sizeof(DDSPixelFormat) == 32); - -struct DDSHeader { - uint32_t size; - uint32_t flags; - uint32_t height; - uint32_t width; - uint32_t pitchOrLinearSize; - uint32_t depth; - uint32_t mipMapCount; - uint32_t reserved1[11]; - DDSPixelFormat ddspf; - uint32_t caps; - uint32_t caps2; - uint32_t caps3; - uint32_t caps4; - uint32_t reserved2; -}; -static_assert(sizeof(DDSHeader) == 124); - -struct DDSHeaderDX10 { - uint32_t dxgiFormat; - uint32_t resourceDimension; - uint32_t miscFlag; - uint32_t arraySize; - uint32_t miscFlags2; -}; -static_assert(sizeof(DDSHeaderDX10) == 20); - -constexpr uint32_t kDDSMagic = 0x20534444; // "DDS" - -bool ensure_directory(const std::filesystem::path& dir) noexcept { - std::error_code ec; - std::filesystem::create_directories(dir, ec); - return !ec; -} - -bool write_binary_file(const std::filesystem::path& path, ArrayRef data) noexcept { - if (!ensure_directory(path.parent_path())) { - return false; - } - - std::ofstream out(path, std::ios::binary | std::ios::trunc); - if (!out) { - return false; - } - - out.write(reinterpret_cast(data.data()), data.size()); - return static_cast(out); -} - -std::optional read_binary_file(const std::filesystem::path& path) noexcept { - std::ifstream file(path, std::ios::binary | std::ios::ate); - if (!file) { - return std::nullopt; - } - - const auto size = static_cast(file.tellg()); - if (size == 0) { - return std::nullopt; - } - - ByteBuffer bytes{size}; - file.seekg(0, std::ios::beg); - file.read(reinterpret_cast(bytes.data()), static_cast(bytes.size())); - if (!file) { - return std::nullopt; - } - - return bytes; -} - -bool validate_dds_header(const DDSHeader& header) noexcept { - if (header.size != sizeof(DDSHeader) || header.ddspf.size != sizeof(DDSPixelFormat)) { - return false; - } - if (header.width == 0 || header.height == 0) { - return false; - } - if ((header.caps2 & (0x00000200 | 0x00200000)) != 0) { // Unsupported - return false; - } - return true; -} - -std::optional resolve_dx10_format(uint32_t dxgiFormat) noexcept { - switch (dxgiFormat) { - case 28: - return wgpu::TextureFormat::RGBA8Unorm; - case 87: - return wgpu::TextureFormat::BGRA8Unorm; - case 71: - return wgpu::TextureFormat::BC1RGBAUnorm; - case 77: - return wgpu::TextureFormat::BC3RGBAUnorm; - case 83: - return wgpu::TextureFormat::BC5RGUnorm; - case 98: - return wgpu::TextureFormat::BC7RGBAUnorm; - default: - return std::nullopt; - } -} - -std::optional resolve_dds_layout(ArrayRef bytes, const DDSHeader& header) noexcept { - ParsedDDSLayout out{.dataOffset = sizeof(uint32_t) + sizeof(DDSHeader)}; - - if ((header.ddspf.flags & 0x00000004) != 0) { // DDS has FourCC - switch (header.ddspf.fourCC) { - case 0x31545844: - out.format = wgpu::TextureFormat::BC1RGBAUnorm; - return out; - case 0x35545844: - out.format = wgpu::TextureFormat::BC3RGBAUnorm; - return out; - case 0x32495441: - out.format = wgpu::TextureFormat::BC5RGUnorm; - return out; - case 0x30315844: { - if (bytes.size() < out.dataOffset + sizeof(DDSHeaderDX10)) { - return std::nullopt; - } - const auto* dx10 = reinterpret_cast(bytes.data() + out.dataOffset); - out.dataOffset += sizeof(DDSHeaderDX10); - if (dx10->resourceDimension != 3 || dx10->arraySize != 1) { - return std::nullopt; - } - const auto format = resolve_dx10_format(dx10->dxgiFormat); - if (!format.has_value()) { - return std::nullopt; - } - out.format = *format; - return out; - } - default: - return std::nullopt; - } - } - - if ((header.ddspf.flags & 0x00000040) != 0 && header.ddspf.rgbBitCount == 32) { - if (header.ddspf.rBitMask == 0x000000FF && header.ddspf.gBitMask == 0x0000FF00 && - header.ddspf.bBitMask == 0x00FF0000 && header.ddspf.aBitMask == 0xFF000000) { - out.format = wgpu::TextureFormat::RGBA8Unorm; - return out; - } - if (header.ddspf.rBitMask == 0x00FF0000 && header.ddspf.gBitMask == 0x0000FF00 && - header.ddspf.bBitMask == 0x000000FF && header.ddspf.aBitMask == 0xFF000000) { - out.format = wgpu::TextureFormat::BGRA8Unorm; - return out; - } - } - - return std::nullopt; -} - -std::optional parse_dds_bytes(ArrayRef bytes) noexcept { - if (bytes.size() < sizeof(uint32_t) + sizeof(DDSHeader)) { - return std::nullopt; - } - - const uint32_t magic = *reinterpret_cast(bytes.data()); - if (magic != kDDSMagic) { - return std::nullopt; - } - - const auto* header = reinterpret_cast(bytes.data() + sizeof(uint32_t)); - if (!validate_dds_header(*header)) { - return std::nullopt; - } - - const auto parsedLayout = resolve_dds_layout(bytes, *header); - if (!parsedLayout.has_value()) { - return std::nullopt; - } - - const uint32_t mipCount = 1u; - const auto expectedSize = calc_texture_size(parsedLayout->format, header->width, header->height, mipCount); - if (expectedSize == 0 || parsedLayout->dataOffset + expectedSize > bytes.size()) { - return std::nullopt; - } - - ByteBuffer data{expectedSize}; - std::memcpy(data.data(), bytes.data() + parsedLayout->dataOffset, expectedSize); - return ConvertedTexture{ - .format = parsedLayout->format, - .width = header->width, - .height = header->height, - .mips = mipCount, - .data = std::move(data), - }; -} - -std::optional load_dds_file(const std::filesystem::path& path) noexcept { - const auto bytes = read_binary_file(path); - if (!bytes.has_value()) { - return std::nullopt; - } - return parse_dds_bytes(*bytes); -} - -ByteBuffer encode_rgba8_dds(uint32_t width, uint32_t height, ArrayRef pixels) { - DDSHeader header{}; - header.size = sizeof(DDSHeader); - header.flags = 0x1 | 0x2 | 0x4 | 0x1000 | 0x8; - header.height = height; - header.width = width; - header.pitchOrLinearSize = width * 4; - header.mipMapCount = 1; - header.ddspf = { - .size = sizeof(DDSPixelFormat), - .flags = 0x00000040 | 0x00000001, - .fourCC = 0, - .rgbBitCount = 32, - .rBitMask = 0x000000FF, - .gBitMask = 0x0000FF00, - .bBitMask = 0x00FF0000, - .aBitMask = 0xFF000000, - }; - header.caps = 0x00001000; - - ByteBuffer bytes{sizeof(uint32_t) + sizeof(DDSHeader) + pixels.size()}; - std::memcpy(bytes.data(), &kDDSMagic, sizeof(kDDSMagic)); - std::memcpy(bytes.data() + sizeof(uint32_t), &header, sizeof(header)); - std::memcpy(bytes.data() + sizeof(uint32_t) + sizeof(DDSHeader), pixels.data(), pixels.size()); - return bytes; -} - -bool write_rgba8_dds(const std::filesystem::path& path, uint32_t width, uint32_t height, - ArrayRef pixels) noexcept { - return write_binary_file(path, encode_rgba8_dds(width, height, pixels)); -} -} // namespace aurora::gfx::dds diff --git a/aurora-main/lib/gfx/dds_io.hpp b/aurora-main/lib/gfx/dds_io.hpp deleted file mode 100644 index 2f275f2..0000000 --- a/aurora-main/lib/gfx/dds_io.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "common.hpp" -#include "texture_convert.hpp" - -#include -#include - -namespace aurora::gfx::dds { -std::optional parse_dds_bytes(ArrayRef bytes) noexcept; -std::optional load_dds_file(const std::filesystem::path& path) noexcept; -ByteBuffer encode_rgba8_dds(uint32_t width, uint32_t height, ArrayRef pixels); -bool write_rgba8_dds(const std::filesystem::path& path, uint32_t width, uint32_t height, ArrayRef pixels) noexcept; - -std::optional read_binary_file(const std::filesystem::path& path) noexcept; - -} // namespace aurora::gfx::dds diff --git a/aurora-main/lib/gfx/depth_peek.cpp b/aurora-main/lib/gfx/depth_peek.cpp deleted file mode 100644 index 1cd357b..0000000 --- a/aurora-main/lib/gfx/depth_peek.cpp +++ /dev/null @@ -1,475 +0,0 @@ -#include "depth_peek.hpp" - -#include "../dolphin/vi/vi_internal.hpp" -#include "../gx/gx.hpp" -#include "../webgpu/gpu.hpp" - -#include -#include -#include -#include -#include - -#include -#include - -namespace aurora::gfx::depth_peek { -namespace { -Module Log("aurora::gfx::depth_peek"); - -using webgpu::g_device; -using webgpu::g_instance; -using webgpu::g_queue; - -using Clock = std::chrono::steady_clock; - -constexpr size_t SlotCount = 3; -constexpr uint32_t WorkgroupSizeX = 8; -constexpr uint32_t WorkgroupSizeY = 8; -constexpr uint32_t DepthPeekSnapshotHz = 30; -constexpr auto SnapshotInterval = std::chrono::nanoseconds{1'000'000'000 / DepthPeekSnapshotHz}; - -struct Params { - uint32_t dstWidth = 0; - uint32_t dstHeight = 0; - uint32_t srcWidth = 0; - uint32_t srcHeight = 0; - float offsetX = 0.f; - float offsetY = 0.f; - float scaleX = 1.f; - float scaleY = 1.f; -}; -static_assert(sizeof(Params) == 32); - -struct LatestSnapshot { - uint32_t width = 0; - uint32_t height = 0; - std::vector data; -}; - -enum class SlotState : uint8_t { - Available, - CopySubmitted, - MapPending, -}; - -struct Slot { - wgpu::Buffer storageBuffer; - wgpu::Buffer readbackBuffer; - wgpu::Buffer paramsBuffer; - uint32_t width = 0; - uint32_t height = 0; - uint64_t byteSize = 0; - SlotState state = SlotState::Available; -}; - -struct PendingMap { - size_t slotIdx = 0; - wgpu::Buffer readbackBuffer; - uint64_t byteSize = 0; -}; - -std::array g_slots; -size_t g_nextSlot = 0; -wgpu::BindGroupLayout g_bindGroupLayout; -wgpu::ComputePipeline g_pipeline; -bool g_snapshotRequested = false; -Clock::time_point g_nextSnapshotTime; -LatestSnapshot g_latest; -std::mutex g_mutex; - -constexpr std::string_view ShaderPreamble = R"( -struct Params { - dstSize: vec2u, - srcSize: vec2u, - offset: vec2f, - scale: vec2f, -}; - -@group(0) @binding(1) var out_z: array; -@group(0) @binding(2) var params: Params; -)"sv; - -constexpr std::string_view ReversedZBody = R"( -fn gx_z24(depth: f32) -> u32 { - return min(u32(clamp(1.0 - depth, 0.0, 1.0) * 16777215.0 + 0.5), 0x00ffffffu); -} -)"sv; - -constexpr std::string_view ForwardZBody = R"( -fn gx_z24(depth: f32) -> u32 { - return min(u32(clamp(depth, 0.0, 1.0) * 16777215.0 + 0.5), 0x00ffffffu); -} -)"sv; - -constexpr std::string_view ShaderMain = R"( -@group(0) @binding(0) var src: texture_depth_2d; - -fn load_depth(coord: vec2i) -> f32 { - return textureLoad(src, coord, 0); -} - -@compute @workgroup_size(8, 8, 1) -fn cs_main(@builtin(global_invocation_id) id: vec3u) { - if (id.x >= params.dstSize.x || id.y >= params.dstSize.y) { - return; - } - - let dstCenter = vec2f(vec2u(id.xy)) + vec2f(0.5, 0.5); - let srcPixel = clamp(vec2i(floor(params.offset + dstCenter * params.scale)), vec2i(0, 0), - vec2i(params.srcSize) - vec2i(1, 1)); - let depth = load_depth(srcPixel); - out_z[id.y * params.dstSize.x + id.x] = gx_z24(depth); -} -)"sv; - -std::string build_shader_source() { - std::string source; - source.reserve(ShaderPreamble.size() + ReversedZBody.size() + ShaderMain.size()); - source += ShaderPreamble; - source += gx::UseReversedZ ? ReversedZBody : ForwardZBody; - source += ShaderMain; - return source; -} - -wgpu::ComputePipeline create_pipeline(const wgpu::BindGroupLayout& bindGroupLayout, const char* label) { - const auto shaderSource = build_shader_source(); - const wgpu::ShaderSourceWGSL wgslSource{wgpu::ShaderSourceWGSL::Init{ - .code = shaderSource.c_str(), - }}; - const wgpu::ShaderModuleDescriptor moduleDescriptor{ - .nextInChain = &wgslSource, - .label = label, - }; - const auto module = g_device.CreateShaderModule(&moduleDescriptor); - - const wgpu::PipelineLayoutDescriptor layoutDescriptor{ - .bindGroupLayoutCount = 1, - .bindGroupLayouts = &bindGroupLayout, - }; - const auto pipelineLayout = g_device.CreatePipelineLayout(&layoutDescriptor); - const wgpu::ComputePipelineDescriptor pipelineDescriptor{ - .label = label, - .layout = pipelineLayout, - .compute = - wgpu::ComputeState{ - .module = module, - .entryPoint = "cs_main", - }, - }; - return g_device.CreateComputePipeline(&pipelineDescriptor); -} - -wgpu::BindGroupLayout create_bind_group_layout(const char* label) { - constexpr std::array entries{ - wgpu::BindGroupLayoutEntry{ - .binding = 0, - .visibility = wgpu::ShaderStage::Compute, - .texture = - wgpu::TextureBindingLayout{ - .sampleType = wgpu::TextureSampleType::Depth, - .viewDimension = wgpu::TextureViewDimension::e2D, - }, - }, - wgpu::BindGroupLayoutEntry{ - .binding = 1, - .visibility = wgpu::ShaderStage::Compute, - .buffer = - wgpu::BufferBindingLayout{ - .type = wgpu::BufferBindingType::Storage, - }, - }, - wgpu::BindGroupLayoutEntry{ - .binding = 2, - .visibility = wgpu::ShaderStage::Compute, - .buffer = - wgpu::BufferBindingLayout{ - .type = wgpu::BufferBindingType::Uniform, - }, - }, - }; - const wgpu::BindGroupLayoutDescriptor descriptor{ - .label = label, - .entryCount = entries.size(), - .entries = entries.data(), - }; - return g_device.CreateBindGroupLayout(&descriptor); -} - -Params make_params(wgpu::Extent3D sourceSize, const FrameMapping& mapping) noexcept { - const auto dstSize = mapping.logicalSize; - Params params{ - .dstWidth = dstSize.x, - .dstHeight = dstSize.y, - .srcWidth = sourceSize.width, - .srcHeight = sourceSize.height, - }; - - if (mapping.viewportPolicy == AURORA_VIEWPORT_NATIVE) { - return params; - } - - const auto logicalSize = mapping.logicalSize; - if (logicalSize.x == 0 || logicalSize.y == 0 || sourceSize.width == 0 || sourceSize.height == 0) { - return params; - } - - const bool stretch = mapping.viewportPolicy == AURORA_VIEWPORT_STRETCH || - mapping.viewportPolicy == AURORA_VIEWPORT_16_9; - const float scaleX = static_cast(sourceSize.width) / static_cast(logicalSize.x); - const float scaleY = static_cast(sourceSize.height) / static_cast(logicalSize.y); - const float scale = std::min(scaleX, scaleY); - params.scaleX = stretch ? scaleX : scale; - params.scaleY = stretch ? scaleY : scale; - params.offsetX = - stretch ? 0.f : (static_cast(sourceSize.width) - static_cast(logicalSize.x) * scale) * 0.5f; - params.offsetY = - stretch ? 0.f : (static_cast(sourceSize.height) - static_cast(logicalSize.y) * scale) * 0.5f; - return params; -} - -bool ensure_slot(Slot& slot, uint32_t width, uint32_t height) { - const uint64_t byteSize = static_cast(width) * static_cast(height) * sizeof(uint32_t); - if (slot.storageBuffer && slot.width == width && slot.height == height && slot.byteSize == byteSize) { - return true; - } - - slot.storageBuffer = {}; - slot.readbackBuffer = {}; - slot.paramsBuffer = {}; - slot.width = width; - slot.height = height; - slot.byteSize = byteSize; - - if (byteSize == 0 || byteSize > UINT32_MAX) { - return false; - } - - const wgpu::BufferDescriptor storageDescriptor{ - .label = "Depth Peek Storage Buffer", - .usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc, - .size = byteSize, - }; - slot.storageBuffer = g_device.CreateBuffer(&storageDescriptor); - - const wgpu::BufferDescriptor readbackDescriptor{ - .label = "Depth Peek Readback Buffer", - .usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst, - .size = byteSize, - }; - slot.readbackBuffer = g_device.CreateBuffer(&readbackDescriptor); - - const wgpu::BufferDescriptor paramsDescriptor{ - .label = "Depth Peek Params Buffer", - .usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst, - .size = sizeof(Params), - }; - slot.paramsBuffer = g_device.CreateBuffer(¶msDescriptor); - return slot.storageBuffer && slot.readbackBuffer && slot.paramsBuffer; -} - -Slot* find_available_slot(uint32_t width, uint32_t height) { - for (size_t i = 0; i < g_slots.size(); ++i) { - const size_t idx = (g_nextSlot + i) % g_slots.size(); - auto& slot = g_slots[idx]; - if (slot.state != SlotState::Available) { - continue; - } - if (!ensure_slot(slot, width, height)) { - continue; - } - g_nextSlot = (idx + 1) % g_slots.size(); - return &slot; - } - return nullptr; -} - -void complete_slot(size_t slotIdx, wgpu::MapAsyncStatus status, wgpu::StringView message) { - std::lock_guard lock{g_mutex}; - auto& slot = g_slots[slotIdx]; - if (status == wgpu::MapAsyncStatus::Success) { - const auto valueCount = static_cast(slot.width) * static_cast(slot.height); - const auto* mapped = - static_cast(slot.readbackBuffer.GetConstMappedRange(0, valueCount * sizeof(uint32_t))); - if (mapped != nullptr) { - g_latest.width = slot.width; - g_latest.height = slot.height; - g_latest.data.assign(mapped, mapped + valueCount); - } - slot.readbackBuffer.Unmap(); - } else if (status != wgpu::MapAsyncStatus::CallbackCancelled && status != wgpu::MapAsyncStatus::Aborted) { - Log.warn("Depth Peek readback mapping failed {}: {}", magic_enum::enum_name(status), message); - } - slot.state = SlotState::Available; -} -} // namespace - -void initialize() { - g_bindGroupLayout = create_bind_group_layout("Depth Peek Bind Group Layout"); - g_pipeline = create_pipeline(g_bindGroupLayout, "Depth Peek Pipeline"); -} - -void shutdown() { - testing::reset(); - g_pipeline = {}; - g_bindGroupLayout = {}; - for (auto& slot : g_slots) { - slot = {}; - } -} - -void request_snapshot() noexcept { - std::lock_guard lock{g_mutex}; - g_snapshotRequested = true; -} - -bool read_latest(uint16_t x, uint16_t y, uint32_t& z) noexcept { - std::lock_guard lock{g_mutex}; - if (x >= g_latest.width || y >= g_latest.height || g_latest.data.empty()) { - return false; - } - z = g_latest.data[static_cast(y) * g_latest.width + x] & 0x00ffffffu; - return true; -} - -void poll() noexcept { - if (g_instance) { - g_instance.ProcessEvents(); - } -} - -FrameMapping capture_frame_mapping() noexcept { - return {vi::configured_fb_size(), gx::g_gxState.viewportPolicy}; -} - -void encode_frame_snapshot(const wgpu::CommandEncoder& cmd, const wgpu::TextureView& depthView, - wgpu::Extent3D sourceSize, uint32_t msaaSamples, const FrameMapping& mapping) noexcept { - ZoneScoped; - const auto now = Clock::now(); - { - std::lock_guard lock{g_mutex}; - if (!g_snapshotRequested || now < g_nextSnapshotTime) { - return; - } - g_snapshotRequested = false; - g_nextSnapshotTime = now + SnapshotInterval; - } - - const auto dstSize = mapping.logicalSize; - if (!depthView || dstSize.x == 0 || dstSize.y == 0 || sourceSize.width == 0 || sourceSize.height == 0) { - return; - } - if (msaaSamples > 1) { - Log.fatal("Depth Peek from multisampled EFB targets is not supported"); - } - - const Params params = make_params(sourceSize, mapping); - wgpu::Buffer storageBuffer; - wgpu::Buffer readbackBuffer; - wgpu::Buffer paramsBuffer; - uint64_t byteSize = 0; - { - std::lock_guard lock{g_mutex}; - auto* slot = find_available_slot(dstSize.x, dstSize.y); - if (slot == nullptr) { - return; - } - slot->state = SlotState::CopySubmitted; - storageBuffer = slot->storageBuffer; - readbackBuffer = slot->readbackBuffer; - paramsBuffer = slot->paramsBuffer; - byteSize = slot->byteSize; - } - - g_queue.WriteBuffer(paramsBuffer, 0, ¶ms, sizeof(params)); - - const std::array bindGroupEntries{ - wgpu::BindGroupEntry{ - .binding = 0, - .textureView = depthView, - }, - wgpu::BindGroupEntry{ - .binding = 1, - .buffer = storageBuffer, - .size = byteSize, - }, - wgpu::BindGroupEntry{ - .binding = 2, - .buffer = paramsBuffer, - .size = sizeof(Params), - }, - }; - const wgpu::BindGroupDescriptor bindGroupDescriptor{ - .label = "Depth Peek Bind Group", - .layout = g_bindGroupLayout, - .entryCount = bindGroupEntries.size(), - .entries = bindGroupEntries.data(), - }; - const auto bindGroup = g_device.CreateBindGroup(&bindGroupDescriptor); - - const wgpu::ComputePassDescriptor passDescriptor{ - .label = "Depth Peek Compute Pass", - }; - const auto pass = cmd.BeginComputePass(&passDescriptor); - pass.SetPipeline(g_pipeline); - pass.SetBindGroup(0, bindGroup); - pass.DispatchWorkgroups((dstSize.x + WorkgroupSizeX - 1) / WorkgroupSizeX, - (dstSize.y + WorkgroupSizeY - 1) / WorkgroupSizeY); - pass.End(); - - cmd.CopyBufferToBuffer(storageBuffer, 0, readbackBuffer, 0, byteSize); -} - -void after_submit() noexcept { - std::vector pendingMaps; - { - std::lock_guard lock{g_mutex}; - for (size_t i = 0; i < g_slots.size(); ++i) { - auto& slot = g_slots[i]; - if (slot.state != SlotState::CopySubmitted) { - continue; - } - slot.state = SlotState::MapPending; - pendingMaps.push_back({ - .slotIdx = i, - .readbackBuffer = slot.readbackBuffer, - .byteSize = slot.byteSize, - }); - } - } - - for (const auto& pending : pendingMaps) { - pending.readbackBuffer.MapAsync( - wgpu::MapMode::Read, 0, pending.byteSize, wgpu::CallbackMode::AllowSpontaneous, - [slotIdx = pending.slotIdx](wgpu::MapAsyncStatus status, wgpu::StringView message) { - complete_slot(slotIdx, status, message); - }); - } -} - -namespace testing { -void reset() noexcept { - std::lock_guard lock{g_mutex}; - g_snapshotRequested = false; - g_nextSlot = 0; - g_nextSnapshotTime = {}; - g_latest = {}; - for (auto& slot : g_slots) { - slot.state = SlotState::Available; - } -} - -bool snapshot_requested() noexcept { - std::lock_guard lock{g_mutex}; - return g_snapshotRequested; -} - -void set_latest(uint32_t width, uint32_t height, const std::vector& data) { - std::lock_guard lock{g_mutex}; - g_latest.width = width; - g_latest.height = height; - g_latest.data = data; -} -} // namespace testing - -} // namespace aurora::gfx::depth_peek diff --git a/aurora-main/lib/gfx/depth_peek.hpp b/aurora-main/lib/gfx/depth_peek.hpp deleted file mode 100644 index 246afd8..0000000 --- a/aurora-main/lib/gfx/depth_peek.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include "common.hpp" -#include - -#include - -namespace aurora::gfx::depth_peek { - -void initialize(); -void shutdown(); - -void request_snapshot() noexcept; -bool read_latest(uint16_t x, uint16_t y, uint32_t& z) noexcept; -void poll() noexcept; - -// Captured before SEALED; the producer may configure the next frame during encode. -struct FrameMapping { - Vec2 logicalSize{}; - AuroraViewportPolicy viewportPolicy = AURORA_VIEWPORT_FIT; -}; -FrameMapping capture_frame_mapping() noexcept; - -void encode_frame_snapshot(const wgpu::CommandEncoder& cmd, const wgpu::TextureView& depthView, - wgpu::Extent3D sourceSize, uint32_t msaaSamples, const FrameMapping& mapping) noexcept; -void after_submit() noexcept; - -namespace testing { -void reset() noexcept; -bool snapshot_requested() noexcept; -void set_latest(uint32_t width, uint32_t height, const std::vector& data); -} // namespace testing - -} // namespace aurora::gfx::depth_peek diff --git a/aurora-main/lib/gfx/efb_ram_copy.cpp b/aurora-main/lib/gfx/efb_ram_copy.cpp deleted file mode 100644 index 29aac8f..0000000 --- a/aurora-main/lib/gfx/efb_ram_copy.cpp +++ /dev/null @@ -1,493 +0,0 @@ -#include "efb_ram_copy.hpp" - -#include "efb_ram_encoder.hpp" -#include "tex_copy_conv.hpp" -#include "../internal.hpp" -#include "../webgpu/gpu.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace aurora::gfx::efb_ram { -namespace { - -Module Log("aurora::gfx::efb_ram"); - -using webgpu::g_device; -using webgpu::g_instance; - -// A CPU-consumed EFB copy this small is the lens-flare occlusion probe (4x4 Z24X8, 64 bytes). -// Resolving it synchronously stalls the producer and kills interpolation, so read it back async. -constexpr size_t kAsyncReadbackMaxBytes = 256; -// Each destination keeps its readback buffer forever. Only a handful are expected, and the cap -// stops an unexpected pattern of one-shot destinations from leaking GPU buffers. -constexpr size_t kMaxAsyncSlots = MaxAsyncReadbackSlots; - -struct PendingCopy { - void* dest = nullptr; - uint32_t width = 0; - uint32_t height = 0; - GXTexFmt format = GX_TF_RGBA8; - TextureHandle texture; - TextureHandle nativeTexture; - Range nativeBlitUniform; - uint64_t nativeUniformEpoch = 0; -}; - -struct Download { - PendingCopy copy; - wgpu::Buffer buffer; - uint32_t bytesPerRow = 0; - uint64_t bufferSize = 0; -}; - -enum class AsyncState : uint8_t { - Idle, - CopySubmitted, - MapPending, -}; - -// One readback per destination address, reused for that destination's lifetime: the probe hits -// the same buffer every frame, so pooling avoids a per-frame allocation. -struct AsyncSlot { - wgpu::Buffer buffer; - TextureHandle nativeTexture; - uint64_t bufferSize = 0; - uint32_t bytesPerRow = 0; - // Latched at encode time and read by the map callback. - void* dest = nullptr; - GXTexFmt format = GX_TF_RGBA8; - uint32_t width = 0; - uint32_t height = 0; - uint32_t hostWidth = 0; - uint32_t hostHeight = 0; - HostPixelOrder order = HostPixelOrder::RGBA; - AsyncState state = AsyncState::Idle; -}; - -std::vector g_pending; -std::vector g_downloads; - -// Recorded by the producer, moved to the worker-private sealed list while the -// producer is excluded. -std::vector g_asyncPending; -std::vector g_asyncSealed; - -std::mutex g_asyncMutex; -std::unordered_map g_asyncSlots; -uint32_t g_asyncMapsInFlight = 0; -uint64_t g_asyncGeneration = 1; - -uint32_t align_to(uint32_t value, uint32_t alignment) noexcept { return (value + alignment - 1) & ~(alignment - 1); } - -// An internally scaled copy cannot be read back directly, so blit it down to native-resolution -// RGBA8 first. Pushes a uniform, so it must run while the staging buffers are still mapped. -void ensure_native_texture(PendingCopy& pending, TextureHandle* cache = nullptr) noexcept { - if (pending.texture->size.width == pending.width && pending.texture->size.height == pending.height) { - return; - } - if (pending.nativeTexture && pending.nativeUniformEpoch == staging_epoch()) return; - if (pending.nativeTexture) { - // Keep the texture; its old staging range belongs to a submitted batch. - } else if (cache != nullptr && *cache && (*cache)->size.width == pending.width && - (*cache)->size.height == pending.height) { - pending.nativeTexture = *cache; - } else { - pending.nativeTexture = new_conv_texture(pending.width, pending.height, GX_TF_RGBA8, "GX EFB RAM native readback"); - if (cache != nullptr) { - *cache = pending.nativeTexture; - } - } - // The shared blit shader clamps Y to flags.z/w; preserve the full source. - const std::array nativeBlitUniform{ - 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 64.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, - }; - pending.nativeBlitUniform = push_uniform(nativeBlitUniform); - pending.nativeUniformEpoch = staging_epoch(); -} - -void encode_native_blit(const wgpu::CommandEncoder& encoder, const PendingCopy& pending) noexcept { - const tex_copy_conv::ConvRequest blitRequest{ - .fmt = GX_TF_RGBA8, - .srcView = pending.texture->sampleTextureView, - .uniformRange = pending.nativeBlitUniform, - .dst = pending.nativeTexture, - .sampleFilter = pending.format == GX_TF_Z16 || pending.format == GX_TF_Z24X8 - ? tex_copy_conv::SampleFilter::Nearest - : tex_copy_conv::SampleFilter::Linear, - }; - tex_copy_conv::blit(encoder, blitRequest); -} - -HostPixelOrder texture_pixel_order(const TextureHandle& texture) noexcept { - return texture->format == wgpu::TextureFormat::BGRA8Unorm ? HostPixelOrder::BGRA : HostPixelOrder::RGBA; -} - -void complete_async_slot(void* dest, uint64_t generation, wgpu::MapAsyncStatus status, - wgpu::StringView message) noexcept { - std::lock_guard lock{g_asyncMutex}; - if (generation != g_asyncGeneration) return; - const auto it = g_asyncSlots.find(dest); - if (it == g_asyncSlots.end()) { - return; - } - auto& slot = it->second; - if (slot.state != AsyncState::MapPending) return; - if (g_asyncMapsInFlight > 0) --g_asyncMapsInFlight; - if (status == wgpu::MapAsyncStatus::Success) { - const auto* pixels = static_cast(slot.buffer.GetConstMappedRange(0, slot.bufferSize)); - if (pixels != nullptr) { - // Writes guest RAM from the event-queue thread while the guest may be reading it. The only - // consumer min/maxes depth for a fade factor, so a torn tile just mixes two frames' depths. - const size_t outputSize = encoded_size(slot.format, slot.width, slot.height); - if (!encode(slot.dest, outputSize, slot.format, slot.width, slot.height, pixels, slot.hostWidth, slot.hostHeight, - slot.bytesPerRow, slot.order)) { - Log.error("Failed to encode async EFB RAM copy format=0x{:x} size={}x{}", static_cast(slot.format), - slot.width, slot.height); - } - // Guest RAM written from outside the embedder, so nothing bumps its write generation and a - // texture cached over this range would keep its digest. - notify_guest_write(slot.dest, outputSize); - } - slot.buffer.Unmap(); - } else if (status != wgpu::MapAsyncStatus::CallbackCancelled && status != wgpu::MapAsyncStatus::Aborted) { - Log.warn("Async EFB RAM readback mapping failed {}: {}", magic_enum::enum_name(status), message); - } - slot.state = AsyncState::Idle; -} - -// Runs the completion callbacks for maps whose GPU work has finished. Must not -// be called while g_asyncMutex is held: complete_async_slot takes it. -void drain_async_events() noexcept { - { - std::lock_guard lock{g_asyncMutex}; - if (g_asyncMapsInFlight == 0) { - return; - } - } - if (g_instance) { - g_instance.ProcessEvents(); - } -} - -} // namespace - -void schedule(void* dest, uint32_t width, uint32_t height, GXTexFmt format, TextureHandle texture) noexcept { - if (dest == nullptr || width == 0 || height == 0 || !texture) { - return; - } - if (!supports_format(format)) { - Log.fatal("Unsupported CPU-visible EFB copy format 0x{:x}", static_cast(format)); - } - - PendingCopy request{ - .dest = dest, - .width = width, - .height = height, - .format = format, - .texture = std::move(texture), - }; - - const size_t encodedSize = encoded_size(format, width, height); - // Offscreen copies resolve on a separate pass list that the sealed frame's - // native render does not replay, so they stay on the lazy path. - bool async = !is_offscreen() && encodedSize != 0 && encodedSize <= kAsyncReadbackMaxBytes; - if (async) { - std::lock_guard lock{g_asyncMutex}; - const auto it = g_asyncSlots.find(dest); - if (it == g_asyncSlots.end()) { - if (g_asyncSlots.size() >= kMaxAsyncSlots) { - async = false; - } else { - g_asyncSlots.try_emplace(dest); - // No readback has landed here yet. 0xff decodes to far Z, which the probe reads as unobstructed - // so a new flare fades in; zero-filled RAM would decode as fully occluded. - std::memset(dest, 0xff, encodedSize); - notify_guest_write(dest, encodedSize); - } - } - } - - auto& list = async ? g_asyncPending : g_pending; - if (auto it = std::find_if(list.begin(), list.end(), - [dest](const PendingCopy& pending) { return pending.dest == dest; }); - it != list.end()) { - *it = std::move(request); - } else { - list.push_back(std::move(request)); - } -} - -bool has_pending(void* dest) noexcept { - if (dest == nullptr) return !g_pending.empty() || !g_downloads.empty(); - return std::any_of(g_pending.begin(), g_pending.end(), - [dest](const PendingCopy& pending) { return pending.dest == dest; }) || - std::any_of(g_downloads.begin(), g_downloads.end(), - [dest](const Download& download) { return download.copy.dest == dest; }); -} - -bool prepare_downloads(void* dest) { - uint64_t copies = 0; - for (const auto& pending : g_pending) { - if (dest != nullptr && pending.dest != dest) continue; - if (pending.texture->size.width != pending.width || pending.texture->size.height != pending.height) ++copies; - } - // Reserve all copies, even already-prepared ones: a split retires their ranges. - ensure_staging_space({0, copies * staging_uniform_bytes(48), 0, 0}); - bool found = false; - for (auto& pending : g_pending) { - if (dest != nullptr && pending.dest != dest) continue; - found = true; - ensure_native_texture(pending); - } - return found; -} - -void encode_downloads(const wgpu::CommandEncoder& encoder, void* dest) noexcept { - if (!g_downloads.empty()) { - Log.fatal("Attempted to encode new EFB RAM downloads before completing the previous batch"); - } - - g_downloads.reserve(g_pending.size()); - for (auto it = g_pending.begin(); it != g_pending.end();) { - if (dest != nullptr && it->dest != dest) { - ++it; - continue; - } - PendingCopy pending = std::move(*it); - it = g_pending.erase(it); - if (pending.nativeTexture) { - encode_native_blit(encoder, pending); - } - const auto& texture = pending.nativeTexture ? pending.nativeTexture : pending.texture; - const uint32_t bytesPerRow = align_to(texture->size.width * 4, 256); - const uint64_t bufferSize = static_cast(bytesPerRow) * texture->size.height; - const wgpu::BufferDescriptor descriptor{ - .label = "GX EFB RAM copy readback", - .usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::MapRead, - .size = bufferSize, - }; - auto buffer = g_device.CreateBuffer(&descriptor); - const wgpu::TexelCopyTextureInfo source{ - .texture = texture->texture, - .mipLevel = 0, - .origin = {0, 0, 0}, - .aspect = wgpu::TextureAspect::All, - }; - const wgpu::TexelCopyBufferInfo destination{ - .layout = - wgpu::TexelCopyBufferLayout{ - .offset = 0, - .bytesPerRow = bytesPerRow, - .rowsPerImage = texture->size.height, - }, - .buffer = buffer, - }; - encoder.CopyTextureToBuffer(&source, &destination, &texture->size); - g_downloads.push_back({ - .copy = std::move(pending), - .buffer = std::move(buffer), - .bytesPerRow = bytesPerRow, - .bufferSize = bufferSize, - }); - } -} - -bool complete_downloads() noexcept { - bool success = true; - for (auto& download : g_downloads) { - // WaitAny may time out before Dawn delivers cancellation. The callback must - // own its result rather than retaining references to this stack frame. - struct MapResult { - std::mutex mutex; - wgpu::MapAsyncStatus status = wgpu::MapAsyncStatus::CallbackCancelled; - std::string message; - }; - const auto result = std::make_shared(); - const auto future = - download.buffer.MapAsync(wgpu::MapMode::Read, 0, download.bufferSize, wgpu::CallbackMode::WaitAnyOnly, - [result](wgpu::MapAsyncStatus status, wgpu::StringView message) { - std::lock_guard lock{result->mutex}; - result->status = status; - if (message.data != nullptr) { - size_t length = 0; - while (length < 512 && length < message.length && message.data[length] != '\0') { - ++length; - } - result->message.assign(message.data, length); - } - }); - const auto waitStatus = g_instance.WaitAny(future, 5000000000); - wgpu::MapAsyncStatus mapStatus; - std::string mapMessage; - { - std::lock_guard lock{result->mutex}; - mapStatus = result->status; - mapMessage = result->message; - } - if (waitStatus != wgpu::WaitStatus::Success || mapStatus != wgpu::MapAsyncStatus::Success) { - Log.error("EFB RAM readback failed wait={} map={} message={}", magic_enum::enum_name(waitStatus), - magic_enum::enum_name(mapStatus), mapMessage); - success = false; - continue; - } - - const auto* pixels = static_cast(download.buffer.GetConstMappedRange(0, download.bufferSize)); - const auto& readbackTexture = download.copy.nativeTexture ? download.copy.nativeTexture : download.copy.texture; - const auto order = texture_pixel_order(readbackTexture); - const size_t outputSize = encoded_size(download.copy.format, download.copy.width, download.copy.height); - if (!encode(download.copy.dest, outputSize, download.copy.format, download.copy.width, download.copy.height, pixels, - readbackTexture->size.width, readbackTexture->size.height, download.bytesPerRow, order)) { - Log.error("Failed to encode EFB RAM copy format=0x{:x} size={}x{}", static_cast(download.copy.format), - download.copy.width, download.copy.height); - success = false; - } - notify_guest_write(download.copy.dest, outputSize); - download.buffer.Unmap(); - } - g_downloads.clear(); - return success; -} - -void cancel() noexcept { - g_pending.clear(); - g_downloads.clear(); - g_asyncPending.clear(); -} - -void seal_async_downloads() noexcept { - { - std::lock_guard lock{g_asyncMutex}; - for (auto& pending : g_asyncPending) { - const auto it = g_asyncSlots.find(pending.dest); - ensure_native_texture(pending, it != g_asyncSlots.end() ? &it->second.nativeTexture : nullptr); - } - } - g_asyncSealed = std::move(g_asyncPending); - g_asyncPending.clear(); -} - -void encode_async_downloads(const wgpu::CommandEncoder& encoder) noexcept { - if (g_asyncSealed.empty()) { - return; - } - // Retire the previous frame's map first so its slot is free here, otherwise a single-slot - // destination could only be sampled every other frame. - drain_async_events(); - std::lock_guard lock{g_asyncMutex}; - for (auto& pending : g_asyncSealed) { - const auto it = g_asyncSlots.find(pending.dest); - if (it == g_asyncSlots.end()) { - continue; - } - auto& slot = it->second; - // Only one readback per destination may be outstanding and the previous map still owns the pooled - // buffer. Dropping this request just leaves the guest on a slightly older probe. - if (slot.state != AsyncState::Idle) { - continue; - } - if (pending.nativeTexture) { - encode_native_blit(encoder, pending); - } - const auto& texture = pending.nativeTexture ? pending.nativeTexture : pending.texture; - const uint32_t bytesPerRow = align_to(texture->size.width * 4, 256); - const uint64_t bufferSize = static_cast(bytesPerRow) * texture->size.height; - if (!slot.buffer || slot.bufferSize != bufferSize) { - const wgpu::BufferDescriptor descriptor{ - .label = "GX EFB RAM async readback", - .usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::MapRead, - .size = bufferSize, - }; - slot.buffer = g_device.CreateBuffer(&descriptor); - slot.bufferSize = bufferSize; - } - if (!slot.buffer) { - continue; - } - const wgpu::TexelCopyTextureInfo source{ - .texture = texture->texture, - .mipLevel = 0, - .origin = {0, 0, 0}, - .aspect = wgpu::TextureAspect::All, - }; - const wgpu::TexelCopyBufferInfo destination{ - .layout = - wgpu::TexelCopyBufferLayout{ - .offset = 0, - .bytesPerRow = bytesPerRow, - .rowsPerImage = texture->size.height, - }, - .buffer = slot.buffer, - }; - encoder.CopyTextureToBuffer(&source, &destination, &texture->size); - slot.bytesPerRow = bytesPerRow; - slot.dest = pending.dest; - slot.format = pending.format; - slot.width = pending.width; - slot.height = pending.height; - slot.hostWidth = texture->size.width; - slot.hostHeight = texture->size.height; - slot.order = texture_pixel_order(texture); - slot.state = AsyncState::CopySubmitted; - } - g_asyncSealed.clear(); -} - -void after_submit() noexcept { - struct PendingMap { - void* dest; - wgpu::Buffer buffer; - uint64_t bufferSize; - uint64_t generation; - }; - std::vector pendingMaps; - { - std::lock_guard lock{g_asyncMutex}; - for (auto& [dest, slot] : g_asyncSlots) { - if (slot.state != AsyncState::CopySubmitted) { - continue; - } - slot.state = AsyncState::MapPending; - ++g_asyncMapsInFlight; - pendingMaps.push_back({dest, slot.buffer, slot.bufferSize, g_asyncGeneration}); - } - } - - for (const auto& pending : pendingMaps) { - pending.buffer.MapAsync(wgpu::MapMode::Read, 0, pending.bufferSize, wgpu::CallbackMode::AllowSpontaneous, - [dest = pending.dest, generation = pending.generation](wgpu::MapAsyncStatus status, - wgpu::StringView message) { - complete_async_slot(dest, generation, status, message); - }); - } - - // Nothing else pumps the WebGPU event queue on this thread, so a completed map would sit - // unharvested with its slot busy. ProcessEvents does not block. - drain_async_events(); -} - -void abort_async() noexcept { g_asyncSealed.clear(); } - -void shutdown() noexcept { - cancel(); - g_asyncSealed.clear(); - // Retire callbacks before releasing buffers, and release outside their mutex: - // destruction may itself deliver an AllowSpontaneous cancellation callback. - decltype(g_asyncSlots) retiredSlots; - { - std::lock_guard lock{g_asyncMutex}; - ++g_asyncGeneration; - retiredSlots.swap(g_asyncSlots); - g_asyncMapsInFlight = 0; - } -} - -} // namespace aurora::gfx::efb_ram diff --git a/aurora-main/lib/gfx/efb_ram_copy.hpp b/aurora-main/lib/gfx/efb_ram_copy.hpp deleted file mode 100644 index 3828d3c..0000000 --- a/aurora-main/lib/gfx/efb_ram_copy.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "common.hpp" -#include "texture.hpp" - -#include - -namespace aurora::gfx::efb_ram { - -inline constexpr size_t MaxAsyncReadbackSlots = 32; - -void schedule(void* dest, uint32_t width, uint32_t height, GXTexFmt format, TextureHandle texture) noexcept; -bool has_pending(void* dest = nullptr) noexcept; -bool prepare_downloads(void* dest = nullptr); -void encode_downloads(const wgpu::CommandEncoder& encoder, void* dest = nullptr) noexcept; -bool complete_downloads() noexcept; -void cancel() noexcept; - -// Frame-latent readbacks for probe-sized CPU-consumed copies: they ride the frame's own encode and -// land in guest RAM a frame later. Per frame, from the worker: seal, encode, then after_submit. -void seal_async_downloads() noexcept; -void encode_async_downloads(const wgpu::CommandEncoder& encoder) noexcept; -void after_submit() noexcept; -// Drops requests sealed for a frame that will never be encoded. -void abort_async() noexcept; -void shutdown() noexcept; - -} // namespace aurora::gfx::efb_ram diff --git a/aurora-main/lib/gfx/efb_ram_encoder.cpp b/aurora-main/lib/gfx/efb_ram_encoder.cpp deleted file mode 100644 index f57486c..0000000 --- a/aurora-main/lib/gfx/efb_ram_encoder.cpp +++ /dev/null @@ -1,211 +0,0 @@ -#include "efb_ram_encoder.hpp" - -#include -#include -#include - -namespace aurora::gfx::efb_ram { -namespace { - -struct Pixel { - uint8_t r; - uint8_t g; - uint8_t b; - uint8_t a; -}; - -struct BlockInfo { - uint32_t width; - uint32_t height; - uint32_t bytes; -}; - -enum class Layout { - I4, - I8, - IA4, - IA8, - RGB565, - RGB5A3, - RGBA8, -}; - -bool describe(GXTexFmt format, Layout& layout, BlockInfo& block) noexcept { - switch (format) { - case GX_TF_I4: - case GX_CTF_R4: - layout = Layout::I4; - block = {8, 8, 32}; - return true; - case GX_TF_I8: - case GX_CTF_A8: - case GX_CTF_R8: - case GX_CTF_G8: - case GX_CTF_B8: - layout = Layout::I8; - block = {8, 4, 32}; - return true; - case GX_TF_IA4: - case GX_CTF_RA4: - layout = Layout::IA4; - block = {8, 4, 32}; - return true; - case GX_TF_IA8: - case GX_TF_Z16: - case GX_CTF_RA8: - case GX_CTF_RG8: - case GX_CTF_GB8: - layout = Layout::IA8; - block = {4, 4, 32}; - return true; - case GX_TF_RGB565: - layout = Layout::RGB565; - block = {4, 4, 32}; - return true; - case GX_TF_RGB5A3: - layout = Layout::RGB5A3; - block = {4, 4, 32}; - return true; - case GX_TF_RGBA8: - case GX_TF_Z24X8: - layout = Layout::RGBA8; - block = {4, 4, 64}; - return true; - default: - return false; - } -} - -Pixel read_pixel(const uint8_t* pixels, uint32_t hostWidth, uint32_t hostHeight, uint32_t bytesPerRow, - HostPixelOrder order, uint32_t guestX, uint32_t guestY, uint32_t guestWidth, - uint32_t guestHeight) noexcept { - const uint32_t clampedGuestX = std::min(guestX, guestWidth - 1); - const uint32_t clampedGuestY = std::min(guestY, guestHeight - 1); - const uint64_t sampleXNumerator = (static_cast(clampedGuestX) * 2 + 1) * hostWidth; - const uint64_t sampleYNumerator = (static_cast(clampedGuestY) * 2 + 1) * hostHeight; - const uint32_t hostX = - std::min(static_cast(sampleXNumerator / (guestWidth * 2ull)), hostWidth - 1); - const uint32_t hostY = - std::min(static_cast(sampleYNumerator / (guestHeight * 2ull)), hostHeight - 1); - const auto* src = pixels + static_cast(hostY) * bytesPerRow + static_cast(hostX) * 4; - if (order == HostPixelOrder::BGRA) { - return {src[2], src[1], src[0], src[3]}; - } - return {src[0], src[1], src[2], src[3]}; -} - -void write_be16(uint8_t*& dst, uint16_t value) noexcept { - *dst++ = static_cast(value >> 8); - *dst++ = static_cast(value); -} - -} // namespace - -bool supports_format(GXTexFmt format) noexcept { - Layout layout{}; - BlockInfo block{}; - return describe(format, layout, block); -} - -size_t encoded_size(GXTexFmt format, uint32_t width, uint32_t height) noexcept { - Layout layout{}; - BlockInfo block{}; - if (width == 0 || height == 0 || !describe(format, layout, block)) { - return 0; - } - const uint64_t blocksX = (static_cast(width) + block.width - 1) / block.width; - const uint64_t blocksY = (static_cast(height) + block.height - 1) / block.height; - const uint64_t size = blocksX * blocksY * block.bytes; - return size <= SIZE_MAX ? static_cast(size) : 0; -} - -bool encode(void* dstValue, size_t dstSize, GXTexFmt format, uint32_t guestWidth, uint32_t guestHeight, - const uint8_t* hostPixels, uint32_t hostWidth, uint32_t hostHeight, uint32_t hostBytesPerRow, - HostPixelOrder order) noexcept { - Layout layout{}; - BlockInfo block{}; - const size_t required = encoded_size(format, guestWidth, guestHeight); - if (dstValue == nullptr || hostPixels == nullptr || required == 0 || dstSize < required || hostWidth == 0 || - hostHeight == 0 || hostBytesPerRow < hostWidth * 4 || !describe(format, layout, block)) { - return false; - } - - auto* dst = static_cast(dstValue); - std::memset(dst, 0, required); - const uint32_t blocksX = (guestWidth + block.width - 1) / block.width; - const uint32_t blocksY = (guestHeight + block.height - 1) / block.height; - - for (uint32_t blockY = 0; blockY < blocksY; ++blockY) { - for (uint32_t blockX = 0; blockX < blocksX; ++blockX) { - uint8_t* blockDst = dst + (static_cast(blockY) * blocksX + blockX) * block.bytes; - if (layout == Layout::RGBA8) { - uint8_t* ar = blockDst; - uint8_t* gb = blockDst + 32; - for (uint32_t y = 0; y < 4; ++y) { - for (uint32_t x = 0; x < 4; ++x) { - const Pixel pixel = read_pixel(hostPixels, hostWidth, hostHeight, hostBytesPerRow, order, blockX * 4 + x, - blockY * 4 + y, guestWidth, guestHeight); - *ar++ = pixel.a; - *ar++ = pixel.r; - *gb++ = pixel.g; - *gb++ = pixel.b; - } - } - continue; - } - - uint8_t* out = blockDst; - for (uint32_t y = 0; y < block.height; ++y) { - if (layout == Layout::I4) { - for (uint32_t x = 0; x < block.width; x += 2) { - const Pixel first = - read_pixel(hostPixels, hostWidth, hostHeight, hostBytesPerRow, order, blockX * block.width + x, - blockY * block.height + y, guestWidth, guestHeight); - const Pixel second = - read_pixel(hostPixels, hostWidth, hostHeight, hostBytesPerRow, order, blockX * block.width + x + 1, - blockY * block.height + y, guestWidth, guestHeight); - *out++ = static_cast((first.r & 0xf0) | (second.r >> 4)); - } - continue; - } - - for (uint32_t x = 0; x < block.width; ++x) { - const Pixel pixel = read_pixel(hostPixels, hostWidth, hostHeight, hostBytesPerRow, order, - blockX * block.width + x, blockY * block.height + y, guestWidth, guestHeight); - switch (layout) { - case Layout::I8: - *out++ = pixel.r; - break; - case Layout::IA4: - *out++ = static_cast((pixel.a & 0xf0) | (pixel.r >> 4)); - break; - case Layout::IA8: - *out++ = pixel.a; - *out++ = pixel.r; - break; - case Layout::RGB565: { - const uint16_t packed = - static_cast(((pixel.r >> 3) << 11) | ((pixel.g >> 2) << 5) | (pixel.b >> 3)); - write_be16(out, packed); - break; - } - case Layout::RGB5A3: { - const uint16_t packed = - pixel.a >= 224 - ? static_cast(0x8000 | ((pixel.r >> 3) << 10) | ((pixel.g >> 3) << 5) | (pixel.b >> 3)) - : static_cast(((pixel.a >> 5) << 12) | ((pixel.r >> 4) << 8) | ((pixel.g >> 4) << 4) | - (pixel.b >> 4)); - write_be16(out, packed); - break; - } - default: - return false; - } - } - } - } - } - return true; -} - -} // namespace aurora::gfx::efb_ram diff --git a/aurora-main/lib/gfx/efb_ram_encoder.hpp b/aurora-main/lib/gfx/efb_ram_encoder.hpp deleted file mode 100644 index 85982b4..0000000 --- a/aurora-main/lib/gfx/efb_ram_encoder.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include - -#include -#include - -namespace aurora::gfx::efb_ram { - -enum class HostPixelOrder : uint8_t { - RGBA, - BGRA, -}; - -bool supports_format(GXTexFmt format) noexcept; -size_t encoded_size(GXTexFmt format, uint32_t width, uint32_t height) noexcept; - -// Encodes a decoded host texture back into the tiled layout a GX EFB copy writes. Host dimensions -// may be internally scaled; guest dimensions are always the native copy dimensions. -bool encode(void* dst, size_t dstSize, GXTexFmt format, uint32_t guestWidth, uint32_t guestHeight, - const uint8_t* hostPixels, uint32_t hostWidth, uint32_t hostHeight, uint32_t hostBytesPerRow, - HostPixelOrder order) noexcept; - -} // namespace aurora::gfx::efb_ram diff --git a/aurora-main/lib/gfx/pipeline_cache.cpp b/aurora-main/lib/gfx/pipeline_cache.cpp deleted file mode 100644 index d995e00..0000000 --- a/aurora-main/lib/gfx/pipeline_cache.cpp +++ /dev/null @@ -1,1304 +0,0 @@ -#include "pipeline_cache.hpp" - -#include "clear.hpp" -#include "../gx/pipeline.hpp" -#include "../fs_helper.hpp" -#include "../sqlite_utils.hpp" -#include "../webgpu/gpu.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace aurora::gfx { -static Module Log("aurora::gfx::pipeline_cache"); - -constexpr int PipelineCacheSchema = 1; -constexpr const char* InitialPipelineCacheName = "initial_pipeline_cache.db"; -constexpr const char* SdlVfsName = "aurora_pipeline_cache_sdl_vfs"; - -struct CachedPipeline { - wgpu::RenderPipeline pipeline; - uint32_t firstFrameUsed = UINT32_MAX; -}; - -struct PendingPipeline { - PipelineRef hash; - uint32_t firstFrameUsed = UINT32_MAX; - NewPipelineCallback create; -}; - -struct PipelineCacheWrite { - ShaderType type; - PipelineRef hash; - uint32_t configVersion; - ByteBuffer config; - uint32_t firstFrameUsed = UINT32_MAX; -}; - -struct SdlVfsSqliteFile { - sqlite3_file base; - SDL_IOStream* io = nullptr; -}; - -static std::mutex g_pipelineMutex; -static bool g_hasPipelineThread = false; -static bool g_pipelineFrameActive = false; -static std::atomic_bool g_skipUnreadyGxPipelines = false; -static size_t g_pipelinesPerFrame = 0; -// Keep first-use compilation bounded. The render command stream remains ordered; -// it waits for a queued pipeline only when the corresponding draw is consumed. -constexpr size_t MaxQueuedPipelineBuilds = 256; -// First-use compilation works best as a short parallel burst. Leave two logical processors for the -// render and game threads, and cap large hosts to limit driver submissions and memory use. -constexpr size_t ReservedLogicalProcessors = 2; -constexpr size_t MaxPipelineWorkers = 22; -// Cached clear and GX pipelines are prewarmed using the full worker pool. -constexpr size_t MaxBackgroundPipelineWorkers = MaxPipelineWorkers; -// For synchronous pipeline fallback (OpenGL) -#ifdef NDEBUG -constexpr size_t BuildPipelinesPerFrame = 5; -#else -constexpr size_t BuildPipelinesPerFrame = 1; -#endif -static std::vector g_pipelineThreads; -static bool g_pipelineThreadEnd = false; -static size_t g_activeBackgroundPipelineWorkers = 0; -static std::condition_variable g_pipelineCv; -static absl::flat_hash_map g_pipelines; -static std::deque g_priorityPipelines; -static std::deque g_backgroundPipelines; -static absl::flat_hash_set g_pendingPipelines; - -static sqlite3* g_pipelineCacheDb = nullptr; -static sqlite3_stmt* g_pipelineCacheLoadStmt = nullptr; -static sqlite3_stmt* g_pipelineCacheUpsertStmt = nullptr; -static bool g_pipelineCacheBroken = false; -static std::thread g_pipelineCacheWriterThread; -static std::condition_variable g_pipelineCacheWriterCv; -static std::mutex g_pipelineCacheWriterMutex; -static std::deque g_pipelineCacheWriteQueue; -static absl::flat_hash_set g_pipelineCachePendingWrites; -static bool g_pipelineCacheWriterStop = false; -static int g_sdlVfsRegisterResult = SQLITE_ERROR; - -static SdlVfsSqliteFile* sdl_vfs_file(sqlite3_file* file) { - return reinterpret_cast(file); -} - -static sqlite3_vfs* default_vfs(sqlite3_vfs* vfs) { - return static_cast(vfs->pAppData); -} - -static int sdl_vfs_close(sqlite3_file* file) { - auto* vfsFile = sdl_vfs_file(file); - if (vfsFile->io != nullptr) { - SDL_CloseIO(vfsFile->io); - vfsFile->io = nullptr; - } - return SQLITE_OK; -} - -static int sdl_vfs_read(sqlite3_file* file, void* buffer, int amount, sqlite3_int64 offset) { - auto* vfsFile = sdl_vfs_file(file); - if (vfsFile->io == nullptr || offset < 0 || amount < 0) { - return SQLITE_IOERR_READ; - } - if (SDL_SeekIO(vfsFile->io, offset, SDL_IO_SEEK_SET) < 0) { - return SQLITE_IOERR_SEEK; - } - - auto* dst = static_cast(buffer); - int total = 0; - while (total < amount) { - const size_t read = SDL_ReadIO(vfsFile->io, dst + total, static_cast(amount - total)); - if (read == 0) { - if (SDL_GetIOStatus(vfsFile->io) == SDL_IO_STATUS_EOF) { - std::memset(dst + total, 0, static_cast(amount - total)); - return SQLITE_IOERR_SHORT_READ; - } - return SQLITE_IOERR_READ; - } - if (read > static_cast(std::numeric_limits::max() - total)) { - return SQLITE_IOERR_READ; - } - total += static_cast(read); - } - return SQLITE_OK; -} - -static int sdl_vfs_write(sqlite3_file*, const void*, int, sqlite3_int64) { return SQLITE_READONLY; } - -static int sdl_vfs_truncate(sqlite3_file*, sqlite3_int64) { return SQLITE_READONLY; } - -static int sdl_vfs_sync(sqlite3_file*, int) { return SQLITE_OK; } - -static int sdl_vfs_file_size(sqlite3_file* file, sqlite3_int64* size) { - auto* vfsFile = sdl_vfs_file(file); - if (vfsFile->io == nullptr || size == nullptr) { - return SQLITE_IOERR_FSTAT; - } - - const auto ioSize = SDL_GetIOSize(vfsFile->io); - if (ioSize < 0) { - return SQLITE_IOERR_FSTAT; - } - *size = static_cast(ioSize); - return SQLITE_OK; -} - -static int sdl_vfs_lock(sqlite3_file*, int) { return SQLITE_OK; } - -static int sdl_vfs_unlock(sqlite3_file*, int) { return SQLITE_OK; } - -static int sdl_vfs_check_reserved_lock(sqlite3_file*, int* reserved) { - if (reserved != nullptr) { - *reserved = 0; - } - return SQLITE_OK; -} - -static int sdl_vfs_file_control(sqlite3_file*, int op, void* arg) { - switch (op) { - case SQLITE_FCNTL_LOCKSTATE: - *static_cast(arg) = SQLITE_LOCK_NONE; - return SQLITE_OK; - case SQLITE_FCNTL_HAS_MOVED: - *static_cast(arg) = 0; - return SQLITE_OK; - case SQLITE_FCNTL_SIZE_HINT: - return SQLITE_OK; - default: - return SQLITE_NOTFOUND; - } -} - -static int sdl_vfs_sector_size(sqlite3_file*) { return 4096; } - -static int sdl_vfs_device_characteristics(sqlite3_file*) { - return SQLITE_IOCAP_IMMUTABLE | SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN; -} - -static constexpr sqlite3_io_methods SdlVfsIoMethods{ - .iVersion = 1, - .xClose = sdl_vfs_close, - .xRead = sdl_vfs_read, - .xWrite = sdl_vfs_write, - .xTruncate = sdl_vfs_truncate, - .xSync = sdl_vfs_sync, - .xFileSize = sdl_vfs_file_size, - .xLock = sdl_vfs_lock, - .xUnlock = sdl_vfs_unlock, - .xCheckReservedLock = sdl_vfs_check_reserved_lock, - .xFileControl = sdl_vfs_file_control, - .xSectorSize = sdl_vfs_sector_size, - .xDeviceCharacteristics = sdl_vfs_device_characteristics, -}; - -static int sdl_vfs_open(sqlite3_vfs*, sqlite3_filename name, sqlite3_file* file, int flags, int* outFlags) { - auto* vfsFile = sdl_vfs_file(file); - vfsFile->base.pMethods = nullptr; - vfsFile->io = nullptr; - - if (name == nullptr || (flags & SQLITE_OPEN_READWRITE) != 0 || (flags & SQLITE_OPEN_READONLY) == 0) { - return SQLITE_CANTOPEN; - } - - vfsFile->io = SDL_IOFromFile(name, "rb"); - if (vfsFile->io == nullptr) { - return SQLITE_CANTOPEN; - } - - vfsFile->base.pMethods = &SdlVfsIoMethods; - if (outFlags != nullptr) { - *outFlags = SQLITE_OPEN_READONLY; - } - return SQLITE_OK; -} - -static int sdl_vfs_delete(sqlite3_vfs*, const char*, int) { return SQLITE_READONLY; } - -static int sdl_vfs_access(sqlite3_vfs*, const char* name, int flags, int* result) { - if (result == nullptr) { - return SQLITE_IOERR_ACCESS; - } - if (name == nullptr || flags == SQLITE_ACCESS_READWRITE) { - *result = 0; - return SQLITE_OK; - } - - auto* io = SDL_IOFromFile(name, "rb"); - *result = io != nullptr ? 1 : 0; - if (io != nullptr) { - SDL_CloseIO(io); - } - return SQLITE_OK; -} - -static int sdl_vfs_full_pathname(sqlite3_vfs*, const char* name, int outSize, char* out) { - if (name == nullptr || out == nullptr || outSize <= 0) { - return SQLITE_CANTOPEN; - } - sqlite3_snprintf(outSize, out, "%s", name); - return SQLITE_OK; -} - -static void* sdl_vfs_dl_open(sqlite3_vfs*, const char*) { return nullptr; } - -static void sdl_vfs_dl_error(sqlite3_vfs*, int bytes, char* message) { - if (message != nullptr && bytes > 0) { - sqlite3_snprintf(bytes, message, "%s", "Dynamic loading is unsupported"); - } -} - -static void (*sdl_vfs_dl_sym(sqlite3_vfs*, void*, const char*))(void) { return nullptr; } - -static void sdl_vfs_dl_close(sqlite3_vfs*, void*) {} - -static int sdl_vfs_randomness(sqlite3_vfs* vfs, int bytes, char* out) { - if (auto* base = default_vfs(vfs); base != nullptr && base->xRandomness != nullptr) { - return base->xRandomness(base, bytes, out); - } - if (out != nullptr && bytes > 0) { - std::memset(out, 0, static_cast(bytes)); - } - return bytes; -} - -static int sdl_vfs_sleep(sqlite3_vfs* vfs, int microseconds) { - if (auto* base = default_vfs(vfs); base != nullptr && base->xSleep != nullptr) { - return base->xSleep(base, microseconds); - } - return microseconds; -} - -static int sdl_vfs_current_time(sqlite3_vfs* vfs, double* time) { - if (auto* base = default_vfs(vfs); base != nullptr && base->xCurrentTime != nullptr) { - return base->xCurrentTime(base, time); - } - if (time != nullptr) { - *time = 2440587.5; - } - return SQLITE_OK; -} - -static int sdl_vfs_get_last_error(sqlite3_vfs*, int, char*) { return SQLITE_OK; } - -static bool register_sdl_vfs() { - static std::once_flag registerOnce; - std::call_once(registerOnce, [] { - auto* baseVfs = sqlite3_vfs_find(nullptr); - static sqlite3_vfs sdlVfs{ - .iVersion = 1, - .szOsFile = static_cast(sizeof(SdlVfsSqliteFile)), - .mxPathname = 4096, - .pNext = nullptr, - .zName = SdlVfsName, - .pAppData = baseVfs, - .xOpen = sdl_vfs_open, - .xDelete = sdl_vfs_delete, - .xAccess = sdl_vfs_access, - .xFullPathname = sdl_vfs_full_pathname, - .xDlOpen = sdl_vfs_dl_open, - .xDlError = sdl_vfs_dl_error, - .xDlSym = sdl_vfs_dl_sym, - .xDlClose = sdl_vfs_dl_close, - .xRandomness = sdl_vfs_randomness, - .xSleep = sdl_vfs_sleep, - .xCurrentTime = sdl_vfs_current_time, - .xGetLastError = sdl_vfs_get_last_error, - }; - g_sdlVfsRegisterResult = sqlite3_vfs_register(&sdlVfs, 0); - }); - return g_sdlVfsRegisterResult == SQLITE_OK; -} - -#if defined(__cpp_lib_atomic_ref) -static std::atomic_ref queuedPipelines{g_stats.queuedPipelines}; -static std::atomic_ref createdPipelines{g_stats.createdPipelines}; -#else -struct AtomicStatRef { - uint32_t& ref; - void operator++() { __atomic_fetch_add(&ref, 1, __ATOMIC_RELAXED); } - void operator--() { __atomic_fetch_sub(&ref, 1, __ATOMIC_RELAXED); } - void operator++(int) { __atomic_fetch_add(&ref, 1, __ATOMIC_RELAXED); } - void operator--(int) { __atomic_fetch_sub(&ref, 1, __ATOMIC_RELAXED); } - void operator=(uint32_t val) { __atomic_store_n(&ref, val, __ATOMIC_RELAXED); } - uint32_t load() const { return __atomic_load_n(&ref, __ATOMIC_RELAXED); } -}; -static AtomicStatRef queuedPipelines{g_stats.queuedPipelines}; -static AtomicStatRef createdPipelines{g_stats.createdPipelines}; -#endif - -template -static PipelineCacheWrite make_pipeline_cache_write(ShaderType type, PipelineRef hash, const PipelineConfig& config, - uint32_t firstFrameUsed) { - static_assert(std::has_unique_object_representations_v); - - PipelineCacheWrite write{ - .type = type, - .hash = hash, - .configVersion = config.version, - .config = ByteBuffer(sizeof(config)), - .firstFrameUsed = firstFrameUsed, - }; - std::memcpy(write.config.data(), &config, sizeof(config)); - return write; -} - -static void enqueue_pipeline_cache_write(PipelineCacheWrite write) { - if (g_pipelineCacheBroken || g_pipelineCacheDb == nullptr) { - return; - } - - { - std::lock_guard lock{g_pipelineCacheWriterMutex}; - if (!g_pipelineCachePendingWrites.insert(write.hash).second) { - return; - } - g_pipelineCacheWriteQueue.emplace_back(std::move(write)); - } - g_pipelineCacheWriterCv.notify_one(); -} - -template -static auto find_pending_pipeline(Queue& queue, PipelineRef hash) { - return std::find_if(queue.begin(), queue.end(), [=](const PendingPipeline& pending) { return pending.hash == hash; }); -} - -static PendingPipeline* touch_pending_pipeline(PipelineRef hash, bool prioritize) { - auto priorityIt = find_pending_pipeline(g_priorityPipelines, hash); - if (priorityIt != g_priorityPipelines.end()) { - return &*priorityIt; - } - - auto backgroundIt = find_pending_pipeline(g_backgroundPipelines, hash); - if (backgroundIt == g_backgroundPipelines.end()) { - return nullptr; - } - - if (!prioritize) { - return &*backgroundIt; - } - - g_priorityPipelines.emplace_back(std::move(*backgroundIt)); - g_backgroundPipelines.erase(backgroundIt); - g_pipelineCv.notify_all(); - return &g_priorityPipelines.back(); -} - -// A persistent resolve is the last chance to complete its producing draw, so promote its queued -// build ahead of first-use work. One already taken by a worker is compiling and has no entry. -static bool promote_pending_pipeline_for_wait(PipelineRef hash) { - auto priorityIt = find_pending_pipeline(g_priorityPipelines, hash); - if (priorityIt != g_priorityPipelines.end()) { - if (priorityIt != g_priorityPipelines.begin()) { - PendingPipeline pending = std::move(*priorityIt); - g_priorityPipelines.erase(priorityIt); - g_priorityPipelines.emplace_front(std::move(pending)); - } - return true; - } - - auto backgroundIt = find_pending_pipeline(g_backgroundPipelines, hash); - if (backgroundIt == g_backgroundPipelines.end()) { - return false; - } - PendingPipeline pending = std::move(*backgroundIt); - g_backgroundPipelines.erase(backgroundIt); - g_priorityPipelines.emplace_front(std::move(pending)); - return true; -} - -template -static bool remove_pending_pipeline(Queue& queue, PipelineRef hash) { - const auto it = find_pending_pipeline(queue, hash); - if (it == queue.end()) { - return false; - } - queue.erase(it); - return true; -} - -template -static PipelineRef find_pipeline_impl(ShaderType type, const PipelineConfig& config, NewPipelineCallback&& cb, - bool persist, std::optional firstFrameUsedOverride) { - ZoneScoped; - - const PipelineRef hash = xxh3_hash(config, static_cast(type)); - const uint32_t firstFrameUsed = firstFrameUsedOverride.value_or(current_frame()); - const bool cachePreload = firstFrameUsedOverride.has_value(); - bool notifyWorker = false; - bool syncCreate = false; - bool removedPending = false; - bool notifyWaiters = false; - std::optional cacheWrite; - { - std::scoped_lock guard{g_pipelineMutex}; - const bool deferGxPipeline = g_hasPipelineThread && g_pipelineFrameActive && type == ShaderType::GX; - const bool skipUnreadyGxPipeline = deferGxPipeline && g_skipUnreadyGxPipelines.load(std::memory_order_relaxed); - auto pipelineIt = g_pipelines.find(hash); - if (pipelineIt != g_pipelines.end()) { - if (persist && firstFrameUsed < pipelineIt->second.firstFrameUsed) { - pipelineIt->second.firstFrameUsed = firstFrameUsed; - cacheWrite = make_pipeline_cache_write(type, hash, config, firstFrameUsed); - } - } else if (g_pendingPipelines.contains(hash)) { - auto* pending = touch_pending_pipeline(hash, g_pipelineFrameActive); - if (pending != nullptr && firstFrameUsed < pending->firstFrameUsed) { - pending->firstFrameUsed = firstFrameUsed; - if (persist) { - cacheWrite = make_pipeline_cache_write(type, hash, config, firstFrameUsed); - } - } - if (g_pipelineFrameActive && !deferGxPipeline) { - syncCreate = true; - } - } else { - if (g_pipelineFrameActive && !deferGxPipeline) { - syncCreate = true; - } else { - if (!cachePreload && deferGxPipeline && g_pendingPipelines.size() >= MaxQueuedPipelineBuilds && - !g_backgroundPipelines.empty()) { - g_pendingPipelines.erase(g_backgroundPipelines.back().hash); - g_backgroundPipelines.pop_back(); - --queuedPipelines; - } - - // Keep the pipeline queued past the cap rather than compiling synchronously: the recorded draw - // references this hash forever, and dropping it baked one-shot EFB copies incomplete. - if (!cachePreload && g_pendingPipelines.size() >= MaxQueuedPipelineBuilds && !skipUnreadyGxPipeline) { - syncCreate = true; - } else { - auto& targetQueue = deferGxPipeline ? g_priorityPipelines : g_backgroundPipelines; - targetQueue.emplace_back(PendingPipeline{ - .hash = hash, - .firstFrameUsed = firstFrameUsed, - .create = std::move(cb), - }); - g_pendingPipelines.insert(hash); - ++queuedPipelines; - if (persist) { - cacheWrite = make_pipeline_cache_write(type, hash, config, firstFrameUsed); - } - notifyWorker = true; - } - } - } - } - - if (syncCreate) { - const auto pipeline = cb(); - { - std::scoped_lock guard{g_pipelineMutex}; - removedPending = remove_pending_pipeline(g_priorityPipelines, hash); - removedPending = remove_pending_pipeline(g_backgroundPipelines, hash) || removedPending; - if (removedPending) { - g_pendingPipelines.erase(hash); - } - auto [it, inserted] = g_pipelines.try_emplace(hash, CachedPipeline{ - .pipeline = pipeline, - .firstFrameUsed = firstFrameUsed, - }); - if (!inserted && persist && firstFrameUsed < it->second.firstFrameUsed) { - it->second.firstFrameUsed = firstFrameUsed; - } - if (inserted) { - ++createdPipelines; - } - if (persist) { - cacheWrite = make_pipeline_cache_write(type, hash, config, firstFrameUsed); - } - notifyWaiters = true; - } - } - - if (cacheWrite) { - enqueue_pipeline_cache_write(std::move(*cacheWrite)); - } - - if (notifyWorker) { - // Compiler workers and renderer waiters share this condition variable. - g_pipelineCv.notify_all(); - } - if (notifyWaiters) { - g_pipelineCv.notify_all(); - } - if (removedPending) { - --queuedPipelines; - } - - return hash; -} - -static void pipeline_cache_abort() { - g_pipelineCacheBroken = true; - if (g_pipelineCacheLoadStmt != nullptr) { - sqlite3_finalize(g_pipelineCacheLoadStmt); - g_pipelineCacheLoadStmt = nullptr; - } - if (g_pipelineCacheUpsertStmt != nullptr) { - sqlite3_finalize(g_pipelineCacheUpsertStmt); - g_pipelineCacheUpsertStmt = nullptr; - } - if (g_pipelineCacheDb != nullptr) { - sqlite3_close(g_pipelineCacheDb); - g_pipelineCacheDb = nullptr; - } -} - -static bool write_pipeline_cache_record(const PipelineCacheWrite& write); - -static std::string pipeline_cache_seed_path() { - if (g_config.resourcesPath == nullptr || g_config.resourcesPath[0] == '\0') { - return InitialPipelineCacheName; - } - - std::string path{g_config.resourcesPath}; - if (path.back() != '/' && path.back() != '\\') { - path += '/'; - } - path += InitialPipelineCacheName; - return path; -} - -static sqlite3* open_pipeline_cache_seed_db(const std::string& path) { - if (!register_sdl_vfs()) { - Log.warn("Failed to register SDL pipeline cache seed VFS"); - return nullptr; - } - - sqlite3* seedDb = nullptr; - const auto ret = - sqlite3_open_v2(path.c_str(), &seedDb, SQLITE_OPEN_READONLY | SQLITE_OPEN_PRIVATECACHE, SdlVfsName); - if (ret != SQLITE_OK) { - if (seedDb != nullptr) { - sqlite3_close(seedDb); - } - Log.info("No bundled initial pipeline cache found at '{}'", path); - return nullptr; - } - - bool schemaMatch = false; - const auto schemaQuery = fmt::format("SELECT 1 FROM aurora_schema WHERE value = {}", PipelineCacheSchema); - const auto schemaRet = - sqlite::exec(seedDb, schemaQuery.c_str(), [&schemaMatch](int, char**, char**) { schemaMatch = true; }); - if (schemaRet != SQLITE_OK) { - Log.warn("Failed to read bundled pipeline cache schema from '{}': {}", path, sqlite3_errmsg(seedDb)); - sqlite3_close(seedDb); - return nullptr; - } - if (!schemaMatch) { - Log.warn("Bundled pipeline cache '{}' does not use schema version {}", path, PipelineCacheSchema); - sqlite3_close(seedDb); - return nullptr; - } - - return seedDb; -} - -static void seed_pipeline_cache() { - if (g_pipelineCacheBroken || g_pipelineCacheDb == nullptr || g_pipelineCacheUpsertStmt == nullptr) { - return; - } - - const auto seedPath = pipeline_cache_seed_path(); - sqlite3* seedDb = open_pipeline_cache_seed_db(seedPath); - if (seedDb == nullptr) { - return; - } - - sqlite3_stmt* seedStmt = nullptr; - auto closeSeed = [&] { - if (seedStmt != nullptr) { - sqlite3_finalize(seedStmt); - seedStmt = nullptr; - } - sqlite3_close(seedDb); - }; - - auto ret = sqlite3_prepare_v3(seedDb, - "SELECT type, hash, config_version, config_size, config, first_frame_used " - "FROM pipeline_cache", - -1, 0, &seedStmt, nullptr); - if (ret != SQLITE_OK) { - Log.warn("Failed to read bundled pipeline cache rows from '{}': {}", seedPath, sqlite3_errmsg(seedDb)); - closeSeed(); - return; - } - - bool writeFailed = false; - bool readFailed = false; - uint32_t mergedRows = 0; - uint32_t skippedRows = 0; - { - sqlite::Transaction tx(g_pipelineCacheDb, Log, true); - if (!tx) { - Log.error("Failed to begin pipeline cache seed transaction"); - closeSeed(); - pipeline_cache_abort(); - return; - } - - while ((ret = sqlite3_step(seedStmt)) == SQLITE_ROW) { - const auto typeValue = sqlite3_column_int(seedStmt, 0); - const auto hashValue = sqlite3_column_int64(seedStmt, 1); - const auto configVersionValue = sqlite3_column_int(seedStmt, 2); - const auto configSizeValue = sqlite3_column_int(seedStmt, 3); - const auto* configBlob = static_cast(sqlite3_column_blob(seedStmt, 4)); - const auto configBlobSize = sqlite3_column_bytes(seedStmt, 4); - const auto firstFrameUsedValue = sqlite3_column_int64(seedStmt, 5); - constexpr auto MaxShaderTypeValue = std::numeric_limits>::max(); - if (typeValue < 0 || typeValue > MaxShaderTypeValue || configVersionValue < 0 || configSizeValue < 0 || - configSizeValue != configBlobSize || (configBlobSize > 0 && configBlob == nullptr) || - firstFrameUsedValue < 0 || firstFrameUsedValue > std::numeric_limits::max()) { - ++skippedRows; - continue; - } - - PipelineCacheWrite write{ - .type = static_cast(typeValue), - .hash = static_cast(hashValue), - .configVersion = static_cast(configVersionValue), - .config = ByteBuffer(static_cast(configBlobSize)), - .firstFrameUsed = static_cast(firstFrameUsedValue), - }; - if (configBlobSize > 0) { - std::memcpy(write.config.data(), configBlob, static_cast(configBlobSize)); - } - - if (!write_pipeline_cache_record(write)) { - writeFailed = true; - break; - } - ++mergedRows; - } - - if (!writeFailed && ret != SQLITE_DONE) { - Log.warn("Failed while reading bundled pipeline cache rows from '{}': {}", seedPath, sqlite3_errmsg(seedDb)); - readFailed = true; - } - - if (!writeFailed && !readFailed) { - tx.commit(); - } - } - - closeSeed(); - - if (writeFailed) { - pipeline_cache_abort(); - return; - } - - if (!readFailed) { - Log.info("Seeded pipeline cache from '{}' ({} rows merged, {} rows skipped)", seedPath, mergedRows, - skippedRows); - } -} - -static bool prepare_pipeline_cache_db() { - if (g_pipelineCacheBroken) { - return false; - } - if (g_pipelineCacheDb != nullptr) { - return true; - } - - const auto path = fs_path_to_string(fs_path_from_string(g_config.pipelineCachePath) / "pipeline_cache.db"); - auto ret = sqlite3_open(path.c_str(), &g_pipelineCacheDb); - if (ret != SQLITE_OK) { - Log.error("Failed to open pipeline cache database: {}", sqlite3_errmsg(g_pipelineCacheDb)); - pipeline_cache_abort(); - return false; - } - - ret = sqlite::exec(g_pipelineCacheDb, "PRAGMA journal_mode=WAL; PRAGMA synchronous=NORMAL;"); - if (ret != SQLITE_OK) { - Log.error("Failed to set pipeline cache pragmas: {}", sqlite3_errmsg(g_pipelineCacheDb)); - pipeline_cache_abort(); - return false; - } - - bool schemaFailed = false; - { - sqlite::Transaction tx(g_pipelineCacheDb, Log, true); - if (!tx) { - Log.error("Failed to begin pipeline cache schema transaction"); - schemaFailed = true; - } else { - ret = sqlite::exec(g_pipelineCacheDb, "CREATE TABLE IF NOT EXISTS aurora_schema(value INTEGER);"); - if (ret != SQLITE_OK) { - Log.error("Failed to create pipeline cache schema table: {}", sqlite3_errmsg(g_pipelineCacheDb)); - schemaFailed = true; - } - } - - bool schemaMatch = false; - if (!schemaFailed) { - const auto schemaQuery = fmt::format("SELECT 1 FROM aurora_schema WHERE value = {}", PipelineCacheSchema); - ret = sqlite::exec(g_pipelineCacheDb, schemaQuery.c_str(), - [&schemaMatch](int, char**, char**) { schemaMatch = true; }); - if (ret != SQLITE_OK) { - Log.error("Failed to read pipeline cache schema version: {}", sqlite3_errmsg(g_pipelineCacheDb)); - schemaFailed = true; - } - } - - if (!schemaFailed && !schemaMatch) { - const auto schemaSql = fmt::format( - R"(DROP TABLE IF EXISTS pipeline_cache; -CREATE TABLE pipeline_cache ( - type INTEGER NOT NULL, - hash INTEGER NOT NULL, - config_version INTEGER NOT NULL, - config_size INTEGER NOT NULL, - config BLOB NOT NULL, - first_frame_used INTEGER NOT NULL, - PRIMARY KEY (type, hash) -); -CREATE INDEX pipeline_cache_load_order_idx - ON pipeline_cache(type, config_version, first_frame_used); -DELETE FROM aurora_schema; -INSERT INTO aurora_schema VALUES ({});)", - PipelineCacheSchema); - ret = sqlite::exec(g_pipelineCacheDb, schemaSql.c_str()); - if (ret != SQLITE_OK) { - Log.error("Failed to initialize pipeline cache schema: {}", sqlite3_errmsg(g_pipelineCacheDb)); - schemaFailed = true; - } - } - - if (!schemaFailed) { - tx.commit(); - } - } - - if (schemaFailed) { - pipeline_cache_abort(); - return false; - } - - ret = sqlite3_prepare_v3(g_pipelineCacheDb, - "SELECT hash, config, first_frame_used FROM pipeline_cache " - "WHERE type = ? AND config_version = ? " - "ORDER BY first_frame_used ASC, rowid ASC", - -1, SQLITE_PREPARE_PERSISTENT, &g_pipelineCacheLoadStmt, nullptr); - if (ret != SQLITE_OK) { - Log.error("Failed to prepare pipeline cache load statement: {}", sqlite3_errmsg(g_pipelineCacheDb)); - pipeline_cache_abort(); - return false; - } - - ret = sqlite3_prepare_v3( - g_pipelineCacheDb, - "INSERT INTO pipeline_cache (type, hash, config_version, config_size, config, first_frame_used) " - "VALUES (?, ?, ?, ?, ?, ?) " - "ON CONFLICT(type, hash) DO UPDATE SET " - "config_version = excluded.config_version, " - "config_size = excluded.config_size, " - "config = excluded.config, " - "first_frame_used = MIN(pipeline_cache.first_frame_used, excluded.first_frame_used)", - -1, SQLITE_PREPARE_PERSISTENT, &g_pipelineCacheUpsertStmt, nullptr); - if (ret != SQLITE_OK) { - Log.error("Failed to prepare pipeline cache upsert statement: {}", sqlite3_errmsg(g_pipelineCacheDb)); - pipeline_cache_abort(); - return false; - } - - seed_pipeline_cache(); - if (g_pipelineCacheBroken) { - return false; - } - - return true; -} - -static void prune_old_pipeline_cache_versions() { - if (!prepare_pipeline_cache_db()) { - return; - } - - const auto clearDelete = fmt::format("DELETE FROM pipeline_cache WHERE type = {} AND config_version < {}", - underlying(ShaderType::Clear), clear::ClearPipelineConfigVersion); - auto ret = sqlite::exec(g_pipelineCacheDb, clearDelete.c_str()); - if (ret != SQLITE_OK) { - Log.error("Failed to prune clear pipeline cache rows: {}", sqlite3_errmsg(g_pipelineCacheDb)); - pipeline_cache_abort(); - return; - } - - const auto gxDelete = fmt::format("DELETE FROM pipeline_cache WHERE type = {} AND config_version < {}", - underlying(ShaderType::GX), gx::GXPipelineConfigVersion); - ret = sqlite::exec(g_pipelineCacheDb, gxDelete.c_str()); - if (ret != SQLITE_OK) { - Log.error("Failed to prune GX pipeline cache rows: {}", sqlite3_errmsg(g_pipelineCacheDb)); - pipeline_cache_abort(); - } -} - -static bool write_pipeline_cache_record(const PipelineCacheWrite& write) { - const auto fail = [&]() { - sqlite3_reset(g_pipelineCacheUpsertStmt); - sqlite3_clear_bindings(g_pipelineCacheUpsertStmt); - return false; - }; - - auto ret = sqlite3_bind_int(g_pipelineCacheUpsertStmt, 1, underlying(write.type)); - if (ret != SQLITE_OK) { - Log.error("Failed to bind pipeline cache type: {}", sqlite3_errmsg(g_pipelineCacheDb)); - return fail(); - } - ret = sqlite3_bind_int64(g_pipelineCacheUpsertStmt, 2, static_cast(write.hash)); - if (ret != SQLITE_OK) { - Log.error("Failed to bind pipeline cache hash: {}", sqlite3_errmsg(g_pipelineCacheDb)); - return fail(); - } - ret = sqlite3_bind_int(g_pipelineCacheUpsertStmt, 3, static_cast(write.configVersion)); - if (ret != SQLITE_OK) { - Log.error("Failed to bind pipeline cache config version: {}", sqlite3_errmsg(g_pipelineCacheDb)); - return fail(); - } - ret = sqlite3_bind_int(g_pipelineCacheUpsertStmt, 4, static_cast(write.config.size())); - if (ret != SQLITE_OK) { - Log.error("Failed to bind pipeline cache config size: {}", sqlite3_errmsg(g_pipelineCacheDb)); - return fail(); - } - ret = sqlite3_bind_blob64(g_pipelineCacheUpsertStmt, 5, write.config.data(), write.config.size(), SQLITE_TRANSIENT); - if (ret != SQLITE_OK) { - Log.error("Failed to bind pipeline cache config blob: {}", sqlite3_errmsg(g_pipelineCacheDb)); - return fail(); - } - ret = sqlite3_bind_int64(g_pipelineCacheUpsertStmt, 6, static_cast(write.firstFrameUsed)); - if (ret != SQLITE_OK) { - Log.error("Failed to bind pipeline cache first-frame-used: {}", sqlite3_errmsg(g_pipelineCacheDb)); - return fail(); - } - - ret = sqlite3_step(g_pipelineCacheUpsertStmt); - if (ret != SQLITE_DONE) { - Log.error("Failed to upsert pipeline cache row: {}", sqlite3_errmsg(g_pipelineCacheDb)); - return fail(); - } - - sqlite3_reset(g_pipelineCacheUpsertStmt); - sqlite3_clear_bindings(g_pipelineCacheUpsertStmt); - return true; -} - -static void pipeline_cache_writer() { -#ifdef TRACY_ENABLE - tracy::SetThreadName("Pipeline cache writer thread"); -#endif - - while (true) { - std::deque batch; - { - std::unique_lock lock{g_pipelineCacheWriterMutex}; - g_pipelineCacheWriterCv.wait(lock, - [] { return g_pipelineCacheWriterStop || !g_pipelineCacheWriteQueue.empty(); }); - if (g_pipelineCacheWriterStop && g_pipelineCacheWriteQueue.empty()) { - return; - } - batch.swap(g_pipelineCacheWriteQueue); - g_pipelineCachePendingWrites.clear(); - } - - bool writeFailed = false; - { - sqlite::Transaction tx(g_pipelineCacheDb, Log, true); - if (!tx) { - Log.error("Failed to begin pipeline cache write transaction"); - writeFailed = true; - } else { - for (const auto& write : batch) { - if (!write_pipeline_cache_record(write)) { - writeFailed = true; - break; - } - } - - if (!writeFailed) { - tx.commit(); - } - } - } - - if (writeFailed) { - pipeline_cache_abort(); - return; - } - } -} - -// Boot prewarm telemetry: how long the cached-recipe rebuild takes and how well the -// Dawn blob cache served it. Logged once, when the launch queue first drains. -static std::atomic_bool g_prewarmActive{false}; -static std::chrono::steady_clock::time_point g_prewarmStart{}; -static uint32_t g_prewarmCount = 0; - -static void note_pipeline_queue_drained() { - if (!g_prewarmActive.exchange(false, std::memory_order_acq_rel)) { - return; - } - // Persist the monolithic Vulkan pipeline cache once after boot prewarm only; doing it on - // every drained burst stalls the device lock mid-race. Later first-use compiles are - // covered by the shutdown serialize. - webgpu::serialize_pipeline_caches(); - const auto elapsed = - std::chrono::duration_cast(std::chrono::steady_clock::now() - g_prewarmStart); - const auto stats = webgpu::blob_cache_stats(); - Log.info("Pipeline prewarm finished: {} pipelines in {:.1f} s (Dawn blob cache: {}/{} hits, {} stores, {:.1f} MiB " - "loaded)", - g_prewarmCount, elapsed.count() / 1000.0, stats.hits, stats.lookups, stats.stores, - static_cast(stats.hitBytes) / (1024.0 * 1024.0)); -} - -static void compile_pending_pipeline(PendingPipeline pending) { - auto result = pending.create(); - { - std::lock_guard lock{g_pipelineMutex}; - const auto [_, inserted] = g_pipelines.try_emplace(pending.hash, CachedPipeline{ - .pipeline = std::move(result), - .firstFrameUsed = pending.firstFrameUsed, - }); - g_pendingPipelines.erase(pending.hash); - if (inserted) { - ++createdPipelines; - } - } - g_pipelineCv.notify_all(); - --queuedPipelines; - if (queuedPipelines.load() == 0) { - note_pipeline_queue_drained(); - } -} - -static void pipeline_worker() { -#ifdef TRACY_ENABLE - tracy::SetThreadName("Pipeline compilation thread"); -#endif - - while (true) { - PendingPipeline pending; - bool background = false; - { - std::unique_lock lock{g_pipelineMutex}; - g_pipelineCv.wait(lock, [] { - return !g_priorityPipelines.empty() || - (!g_backgroundPipelines.empty() && - g_activeBackgroundPipelineWorkers < MaxBackgroundPipelineWorkers) || - g_pipelineThreadEnd; - }); - if (g_pipelineThreadEnd) { - return; - } - background = g_priorityPipelines.empty(); - auto& source = background ? g_backgroundPipelines : g_priorityPipelines; - pending = std::move(source.front()); - source.pop_front(); - if (background) { - ++g_activeBackgroundPipelineWorkers; - } - } - compile_pending_pipeline(std::move(pending)); - if (background) { - { - std::lock_guard lock{g_pipelineMutex}; - --g_activeBackgroundPipelineWorkers; - } - g_pipelineCv.notify_all(); - } - } -} - -static void build_synchronous_pipelines_for_frame() { - while (g_pipelinesPerFrame < BuildPipelinesPerFrame) { - PendingPipeline pending; - { - std::lock_guard lock{g_pipelineMutex}; - if (g_priorityPipelines.empty() && g_backgroundPipelines.empty()) { - return; - } - auto& source = !g_priorityPipelines.empty() ? g_priorityPipelines : g_backgroundPipelines; - pending = std::move(source.front()); - source.pop_front(); - } - compile_pending_pipeline(std::move(pending)); - ++g_pipelinesPerFrame; - } -} - -static size_t pipeline_worker_count() { - const size_t logicalProcessors = std::thread::hardware_concurrency(); - if (logicalProcessors == 0) { - return 1; - } - const size_t availableWorkers = - logicalProcessors > ReservedLogicalProcessors ? logicalProcessors - ReservedLogicalProcessors : 1; - return std::clamp(availableWorkers, size_t{1}, MaxPipelineWorkers); -} - -template -static void load_pipeline_cache_entries(ShaderType type, uint32_t configVersion, CreateFn&& create) { - if (!prepare_pipeline_cache_db()) { - return; - } - - auto ret = sqlite3_bind_int(g_pipelineCacheLoadStmt, 1, underlying(type)); - if (ret != SQLITE_OK) { - Log.error("Failed to bind pipeline cache load type: {}", sqlite3_errmsg(g_pipelineCacheDb)); - pipeline_cache_abort(); - return; - } - ret = sqlite3_bind_int(g_pipelineCacheLoadStmt, 2, static_cast(configVersion)); - if (ret != SQLITE_OK) { - Log.error("Failed to bind pipeline cache load config version: {}", sqlite3_errmsg(g_pipelineCacheDb)); - pipeline_cache_abort(); - return; - } - - while ((ret = sqlite3_step(g_pipelineCacheLoadStmt)) == SQLITE_ROW) { - const auto storedHash = static_cast(sqlite3_column_int64(g_pipelineCacheLoadStmt, 0)); - const auto* configBlob = static_cast(sqlite3_column_blob(g_pipelineCacheLoadStmt, 1)); - const auto configSize = sqlite3_column_bytes(g_pipelineCacheLoadStmt, 1); - const auto firstFrameUsed = static_cast(sqlite3_column_int64(g_pipelineCacheLoadStmt, 2)); - if (configSize != static_cast(sizeof(PipelineConfig)) || (configSize != 0 && configBlob == nullptr)) { - continue; - } - if (xxh3_hash_s(configBlob, static_cast(configSize), static_cast(type)) != storedHash) { - Log.warn("Skipping cached pipeline configuration with mismatched content hash"); - continue; - } - PipelineConfig config; - std::memcpy(&config, configBlob, sizeof(config)); - if (config.version != configVersion) { - continue; - } - if constexpr (std::is_same_v) { - if (!gx::valid_pipeline_config(config)) { - Log.warn("Skipping invalid cached GX pipeline configuration"); - continue; - } - } - - find_pipeline_impl(type, config, [=] { return create(config); }, false, firstFrameUsed); - } - - if (ret != SQLITE_DONE) { - Log.error("Failed to read pipeline cache rows: {}", sqlite3_errmsg(g_pipelineCacheDb)); - pipeline_cache_abort(); - } - - sqlite3_reset(g_pipelineCacheLoadStmt); - sqlite3_clear_bindings(g_pipelineCacheLoadStmt); -} - -static void load_pipeline_cache() { - if (!prepare_pipeline_cache_db()) { - return; - } - prune_old_pipeline_cache_versions(); - if (g_pipelineCacheBroken) { - return; - } - load_pipeline_cache_entries(ShaderType::Clear, clear::ClearPipelineConfigVersion, - clear::create_pipeline); - load_pipeline_cache_entries(ShaderType::GX, gx::GXPipelineConfigVersion, - gx::create_pipeline); - const auto queued = queuedPipelines.load(); - if (queued > 0) { - g_prewarmCount = queued; - g_prewarmStart = std::chrono::steady_clock::now(); - g_prewarmActive.store(true, std::memory_order_release); - } -} - -static void start_pipeline_cache_writer() { - if (!prepare_pipeline_cache_db()) { - return; - } - - g_pipelineCacheWriterStop = false; - g_pipelineCacheWriterThread = std::thread(pipeline_cache_writer); -} - -static void stop_pipeline_cache_writer() { - if (g_pipelineCacheWriterThread.joinable()) { - { - std::lock_guard lock{g_pipelineCacheWriterMutex}; - g_pipelineCacheWriterStop = true; - } - g_pipelineCacheWriterCv.notify_one(); - g_pipelineCacheWriterThread.join(); - } else { - g_pipelineCacheWriterStop = false; - } - - g_pipelineCacheWriteQueue.clear(); - g_pipelineCachePendingWrites.clear(); -} - -template <> -PipelineRef find_pipeline(ShaderType type, const clear::PipelineConfig& config, NewPipelineCallback&& cb) { - return find_pipeline_impl(type, config, std::move(cb), true, std::nullopt); -} - -template <> -PipelineRef find_pipeline(ShaderType type, const gx::PipelineConfig& config, NewPipelineCallback&& cb) { - return find_pipeline_impl(type, config, std::move(cb), true, std::nullopt); -} - -void initialize_pipeline_cache() { - g_pipelineCacheBroken = false; - g_pipelineCacheWriterStop = false; - g_pipelineFrameActive = false; - g_pipelineThreadEnd = false; - g_activeBackgroundPipelineWorkers = 0; - - if (webgpu::g_backendType == wgpu::BackendType::OpenGL || webgpu::g_backendType == wgpu::BackendType::OpenGLES || - webgpu::g_backendType == wgpu::BackendType::WebGPU) { - g_hasPipelineThread = false; - } else { - g_hasPipelineThread = true; - const size_t workerCount = pipeline_worker_count(); - g_pipelineThreads.reserve(workerCount); - for (size_t i = 0; i < workerCount; ++i) { - g_pipelineThreads.emplace_back(pipeline_worker); - } - Log.info("Enabled {} priority pipeline compilation workers ({} background prewarm)", - workerCount, MaxBackgroundPipelineWorkers); - } - - load_pipeline_cache(); - if (!g_pipelineCacheBroken) { - start_pipeline_cache_writer(); - } -} - -void shutdown_pipeline_cache() { - if (g_hasPipelineThread) { - { - std::lock_guard lock{g_pipelineMutex}; - g_pipelineThreadEnd = true; - } - g_pipelineCv.notify_all(); - for (auto& thread : g_pipelineThreads) { - thread.join(); - } - } - g_pipelineThreads.clear(); - g_hasPipelineThread = false; - g_activeBackgroundPipelineWorkers = 0; - - stop_pipeline_cache_writer(); - pipeline_cache_abort(); - g_pipelineCacheBroken = false; - g_pipelineFrameActive = false; - g_pipelinesPerFrame = 0; - g_pipelines.clear(); - g_priorityPipelines.clear(); - g_backgroundPipelines.clear(); - g_pendingPipelines.clear(); - - queuedPipelines = 0; - createdPipelines = 0; -} - -void begin_pipeline_frame() { - g_pipelineFrameActive = true; - if (!g_hasPipelineThread) { - g_pipelinesPerFrame = 0; - } -} - -void end_pipeline_frame() { - g_pipelineFrameActive = false; - if (!g_hasPipelineThread) { - build_synchronous_pipelines_for_frame(); - } -} - -void set_skip_unready_pipelines(bool enabled) noexcept { - g_skipUnreadyGxPipelines.store(enabled, std::memory_order_relaxed); -} - -bool skip_unready_pipelines() noexcept { return g_skipUnreadyGxPipelines.load(std::memory_order_relaxed); } - -uint32_t queued_pipeline_count() noexcept { -#if defined(__cpp_lib_atomic_ref) - return queuedPipelines.load(std::memory_order_relaxed); -#else - return queuedPipelines.load(); -#endif -} - -bool try_pipeline(PipelineRef ref, wgpu::RenderPipeline& pipeline) { - std::scoped_lock lock{g_pipelineMutex}; - const auto it = g_pipelines.find(ref); - if (it == g_pipelines.end()) { - return false; - } - pipeline = it->second.pipeline; - return true; -} - -static bool wait_pipeline_impl(PipelineRef ref, wgpu::RenderPipeline& pipeline, bool fatalIfMissing, - bool persistentPass) { - std::unique_lock lock{g_pipelineMutex}; - if (!g_pipelines.contains(ref) && g_pendingPipelines.contains(ref)) { - ZoneScopedN("wait_pipeline"); - const auto finished = [ref] { - return g_pipelines.contains(ref) || !g_pendingPipelines.contains(ref) || g_pipelineThreadEnd; - }; - if (persistentPass) { - if (promote_pending_pipeline_for_wait(ref)) { - g_pipelineCv.notify_all(); - } - // A persistent resolve is the last chance to produce its texture, so timing out here corrupts it - // permanently. Only a pass marked requireReadyPipelines takes this path. - } - g_pipelineCv.wait(lock, finished); - } - const auto it = g_pipelines.find(ref); - if (it == g_pipelines.end()) { - lock.unlock(); - if (fatalIfMissing) { - Log.fatal("Pipeline 0x{:x} is unavailable at its ordered draw boundary", static_cast(ref)); - } - Log.error("Pipeline 0x{:x} is unavailable for a persistent resolve pass; dropping its draw", - static_cast(ref)); - return false; - } - pipeline = it->second.pipeline; - return true; -} - -bool wait_pipeline(PipelineRef ref, wgpu::RenderPipeline& pipeline) { - return wait_pipeline_impl(ref, pipeline, true, false); -} - -bool wait_pipeline_for_persistent_pass(PipelineRef ref, wgpu::RenderPipeline& pipeline) { - return wait_pipeline_impl(ref, pipeline, false, true); -} - -} // namespace aurora::gfx - -void aurora_set_skip_unready_pipelines(const bool enabled) { aurora::gfx::set_skip_unready_pipelines(enabled); } - -bool aurora_get_skip_unready_pipelines() { return aurora::gfx::skip_unready_pipelines(); } - -uint32_t aurora_get_queued_pipeline_count() { return aurora::gfx::queued_pipeline_count(); } diff --git a/aurora-main/lib/gfx/pipeline_cache.hpp b/aurora-main/lib/gfx/pipeline_cache.hpp deleted file mode 100644 index 737e531..0000000 --- a/aurora-main/lib/gfx/pipeline_cache.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include "common.hpp" - -#include - -namespace aurora::gfx::clear { -struct PipelineConfig; -} // namespace aurora::gfx::clear - -namespace aurora::gx { -struct PipelineConfig; -} // namespace aurora::gx - -namespace aurora::gfx { - -using NewPipelineCallback = std::function; - -void initialize_pipeline_cache(); -void shutdown_pipeline_cache(); -void begin_pipeline_frame(); -void end_pipeline_frame(); -void set_skip_unready_pipelines(bool enabled) noexcept; -bool skip_unready_pipelines() noexcept; -uint32_t queued_pipeline_count() noexcept; - -template -PipelineRef find_pipeline(ShaderType type, const Config& config, NewPipelineCallback&& cb); - -bool wait_pipeline(PipelineRef ref, wgpu::RenderPipeline& pipeline); -bool try_pipeline(PipelineRef ref, wgpu::RenderPipeline& pipeline); -// Waits indefinitely for a draw about to be committed to a persistent texture with no re-issue -// path. Separate from wait_pipeline so skip-unready mode never becomes blocking for other passes. -bool wait_pipeline_for_persistent_pass(PipelineRef ref, wgpu::RenderPipeline& pipeline); - -} // namespace aurora::gfx diff --git a/aurora-main/lib/gfx/png_io.cpp b/aurora-main/lib/gfx/png_io.cpp deleted file mode 100644 index ea3ac62..0000000 --- a/aurora-main/lib/gfx/png_io.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#include "png_io.hpp" - -#include - -#include "dds_io.hpp" -#include "png.h" -#include "../fs_helper.hpp" - -static aurora::Module Log("aurora::gfx::png"); - -namespace aurora::gfx::png { - -struct PngStructs { - png_structp pStruct; - png_infop pInfo; - std::ifstream file; - - ~PngStructs() { - png_destroy_read_struct(&pStruct, &pInfo, nullptr); - } -}; - -static void readPngData(png_structp png, png_bytep data, const size_t length) { - auto structs = static_cast(png_get_io_ptr(png)); - structs->file.read(reinterpret_cast(data), static_cast(length)); - - if (structs->file.eof() || structs->file.fail()) { - png_error(png, "file read failed!"); - } -} - -std::optional -load_png_file(const std::filesystem::path& path) noexcept { - PngStructs structs{}; - - structs.file = std::move(std::ifstream(path, std::ifstream::in | std::ifstream::binary)); - if (!structs.file) { - Log.error("failed to open file: {}", fs_path_to_string(path)); - return std::nullopt; - } - - structs.pStruct = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); - if (!structs.pStruct) { - Log.error("png_create_read_struct failed"); - return std::nullopt; - } - - structs.pInfo = png_create_info_struct(structs.pStruct); - if (!structs.pInfo) { - Log.error("png_create_info_struct failed"); - return std::nullopt; - } - - // I'm scared of putting any locals after that setjmp. - std::vector rowPointers; - ByteBuffer imageData{}; - png_uint_32 width, height; - int bit_depth, color_type, interlace_type, compression_type, filter_type; - size_t rowBytes; - int i; - - if (setjmp(png_jmpbuf(structs.pStruct))) { - Log.error("libpng encountered an error"); - return std::nullopt; - } - - png_set_read_fn(structs.pStruct, &structs, readPngData); - png_read_info(structs.pStruct, structs.pInfo); - - if (!png_get_IHDR(structs.pStruct, structs.pInfo, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type)) { - Log.error("libpng unable to read IHDR"); - return std::nullopt; - } - - // Always read as RGBA8. - png_set_gray_to_rgb(structs.pStruct); - png_set_filler(structs.pStruct, 0xFF, PNG_FILLER_AFTER); - png_set_expand(structs.pStruct); - png_set_strip_16(structs.pStruct); - - png_read_update_info(structs.pStruct, structs.pInfo); - rowBytes = png_get_rowbytes(structs.pStruct, structs.pInfo); - rowPointers.resize(height); - - imageData.append_zeroes(rowBytes * height); - - for (i = 0; i < height; i++) { - rowPointers[i] = imageData.data() + i * rowBytes; - } - - png_read_image(structs.pStruct, rowPointers.data()); - png_read_end(structs.pStruct, nullptr); - - return ConvertedTexture{ - .format = wgpu::TextureFormat::RGBA8Unorm, - .width = width, - .height = height, - .mips = 1, - .data = std::move(imageData) - }; -} -} \ No newline at end of file diff --git a/aurora-main/lib/gfx/png_io.hpp b/aurora-main/lib/gfx/png_io.hpp deleted file mode 100644 index a0f32a7..0000000 --- a/aurora-main/lib/gfx/png_io.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include -#include - -#include "texture_convert.hpp" - -namespace aurora::gfx::png { -std::optional load_png_file(const std::filesystem::path& path) noexcept; -} diff --git a/aurora-main/lib/gfx/staging_capacity.hpp b/aurora-main/lib/gfx/staging_capacity.hpp deleted file mode 100644 index 4bceb11..0000000 --- a/aurora-main/lib/gfx/staging_capacity.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace aurora::gfx { -// Byte counts after each allocation's own trailing alignment, in V/U/I/S order. -using StagingSizes = std::array; -class StagingCapacityError : public std::runtime_error { -public: - using std::runtime_error::runtime_error; -}; -struct StagingBatchFull {}; -inline uint64_t staging_padded(uint64_t bytes, uint64_t alignment) { - if (!bytes) return alignment; - const auto remainder = alignment ? bytes % alignment : 0; - const auto padding = remainder ? alignment - remainder : 0; - if (bytes > UINT64_MAX - padding) throw StagingCapacityError("Staging allocation size overflow"); - return bytes + padding; -} -inline bool staging_fits(const StagingSizes& used, const StagingSizes& demand, - const StagingSizes& tail, const StagingSizes& capacity) noexcept { - for (unsigned i = 0; i < used.size(); ++i) { - const auto limit = capacity[i] < UINT32_MAX ? capacity[i] : UINT32_MAX; - // The final GPU copy rounds to four bytes. Subtractions avoid wraparound. - const auto alignedLimit = limit & ~uint64_t(3); - if (tail[i] > alignedLimit || used[i] > alignedLimit - tail[i] || - demand[i] > alignedLimit - tail[i] - used[i]) return false; - } - return true; -} -} // namespace aurora::gfx diff --git a/aurora-main/lib/gfx/staging_map.hpp b/aurora-main/lib/gfx/staging_map.hpp deleted file mode 100644 index 2c79e7f..0000000 --- a/aurora-main/lib/gfx/staging_map.hpp +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace aurora::gfx { - -enum class BufferMapState { Unmapped, Mapping, Mapped }; - -// The renderer owns request/reset; Dawn may complete a request on another thread. -// An old callback must never publish readiness for a different staging slot. -class StagingMapState { - mutable std::mutex mutex_; - std::condition_variable changed_; - uint64_t generation_ = 0; - BufferMapState state_ = BufferMapState::Unmapped; - -public: - uint64_t request() { - std::lock_guard lock(mutex_); - if (state_ != BufferMapState::Unmapped) return 0; - state_ = BufferMapState::Mapping; - return ++generation_; - } - - bool complete(uint64_t generation, BufferMapState state) { - { - std::lock_guard lock(mutex_); - if (generation != generation_ || state_ != BufferMapState::Mapping) return false; - state_ = state; - } - changed_.notify_all(); - return true; - } - - void reset() { - { - std::lock_guard lock(mutex_); - ++generation_; - state_ = BufferMapState::Unmapped; - } - changed_.notify_all(); - } - - BufferMapState state() const { - std::lock_guard lock(mutex_); - return state_; - } - - void wait_for_progress() { - std::unique_lock lock(mutex_); - // ProcessEvents is still serviced between waits for implementations that - // need it. A spontaneous completion wakes immediately, without polling. - changed_.wait_for(lock, std::chrono::milliseconds(1), - [&] { return state_ != BufferMapState::Mapping; }); - } -}; - -} // namespace aurora::gfx diff --git a/aurora-main/lib/gfx/tex_copy_conv.cpp b/aurora-main/lib/gfx/tex_copy_conv.cpp deleted file mode 100644 index 77b5a97..0000000 --- a/aurora-main/lib/gfx/tex_copy_conv.cpp +++ /dev/null @@ -1,616 +0,0 @@ -#include "tex_copy_conv.hpp" -#include "tex_copy_format_contract.hpp" - -#include "../internal.hpp" -#include "../gx/gx.hpp" -#include "../webgpu/gpu.hpp" -#include "texture.hpp" -#include "../gx/gx_fmt.hpp" - -#include - -#include "texture_convert.hpp" - -using namespace std::string_literals; - -namespace aurora::gfx::tex_copy_conv { -static Module Log("aurora::gfx::tex_copy_conv"); - -using webgpu::g_device; - -static constexpr std::string_view ShaderPreamble = R"( -@group(0) @binding(0) var src_samp: sampler; -@group(0) @binding(1) var src: texture_2d; - -struct UVTransform { - offset: vec2f, - scale: vec2f, - copy_filter: vec4f, - flags: vec4f, -}; -@group(0) @binding(2) var uv_xf: UVTransform; - -struct VertexOutput { - @builtin(position) pos: vec4f, - @location(0) uv: vec2f, -}; - -var positions: array = array( - vec2f(-1.0, 1.0), - vec2f(-1.0, -3.0), - vec2f(3.0, 1.0), -); -var uvs: array = array( - vec2f(0.0, 0.0), - vec2f(0.0, 2.0), - vec2f(2.0, 0.0), -); - -@vertex fn vs_main(@builtin(vertex_index) vi: u32) -> VertexOutput { - var out: VertexOutput; - out.pos = vec4f(positions[vi], 0.0, 1.0); - out.uv = uvs[vi] * uv_xf.scale + uv_xf.offset; - return out; -} - -fn intensity(rgb: vec3f) -> f32 { - // ITU-R BT.601 luma coefficients - return dot(rgb, vec3f(0.257, 0.504, 0.098)) + 16.0 / 255.0; -} - -fn quantize4(v: f32) -> f32 { - return floor(v * 16.0) / 15.0; -} - -fn apply_opaque_alpha(c: vec4f) -> vec4f { - if (uv_xf.flags.x != 0.0) { - return vec4f(c.rgb, 1.0); - } - return c; -} - -fn clamp_copy_uv(uv: vec2f) -> vec2f { - return vec2f(uv.x, clamp(uv.y, uv_xf.flags.z, uv_xf.flags.w)); -} - -fn sample_copy(uv: vec2f) -> vec4f { - let current = textureSample(src, src_samp, clamp_copy_uv(uv)); - if (uv_xf.copy_filter.w == 0.0) { - return apply_opaque_alpha(current); - } - - let tex_size = vec2f(textureDimensions(src)); - let pixel_size = vec2f(1.0, 1.0) / tex_size; - let row_stride = max(uv_xf.flags.y, 1.0); - let prev = textureSample(src, src_samp, - clamp_copy_uv(uv - vec2f(0.0, pixel_size.y * row_stride))); - let next = textureSample(src, src_samp, - clamp_copy_uv(uv + vec2f(0.0, pixel_size.y * row_stride))); - let prev_rgb = floor(prev.rgb * 255.0 + vec3f(0.5)); - let current_rgb = floor(current.rgb * 255.0 + vec3f(0.5)); - let next_rgb = floor(next.rgb * 255.0 + vec3f(0.5)); - let filtered_rgb = min( - floor((prev_rgb * uv_xf.copy_filter.x + - current_rgb * uv_xf.copy_filter.y + - next_rgb * uv_xf.copy_filter.z) / 64.0), - vec3f(255.0)); - let filtered = vec4f(filtered_rgb / 255.0, current.a); - return apply_opaque_alpha(filtered); -} -)"sv; - -static const std::string DepthShaderPreamble = R"( -@group(0) @binding(0) var src: texture_depth_2d; - -struct UVTransform { - offset: vec2f, - scale: vec2f, - copy_filter: vec4f, - flags: vec4f, -}; -@group(0) @binding(1) var uv_xf: UVTransform; - -struct VertexOutput { - @builtin(position) pos: vec4f, - @location(0) uv: vec2f, -}; - -var positions: array = array( - vec2f(-1.0, 1.0), - vec2f(-1.0, -3.0), - vec2f(3.0, 1.0), -); -var uvs: array = array( - vec2f(0.0, 0.0), - vec2f(0.0, 2.0), - vec2f(2.0, 0.0), -); - -@vertex fn vs_main(@builtin(vertex_index) vi: u32) -> VertexOutput { - var out: VertexOutput; - out.pos = vec4f(positions[vi], 0.0, 1.0); - out.uv = uvs[vi] * uv_xf.scale + uv_xf.offset; - return out; -} -)"s + (gx::UseReversedZ ? R"( -fn gx_z24_at_coord(unclamped_coord: vec2i) -> u32 { - let tex_size = vec2i(textureDimensions(src)); - let coord = clamp(unclamped_coord, vec2i(0), tex_size - vec2i(1)); - let depth = textureLoad(src, coord, 0); - return min(u32(clamp(1.0 - depth, 0.0, 1.0) * 16777215.0 + 0.5), 0x00ffffffu); -} -)"s - : R"( -fn gx_z24_at_coord(unclamped_coord: vec2i) -> u32 { - let tex_size = vec2i(textureDimensions(src)); - let coord = clamp(unclamped_coord, vec2i(0), tex_size - vec2i(1)); - let depth = textureLoad(src, coord, 0); - return min(u32(clamp(depth, 0.0, 1.0) * 16777215.0 + 0.5), 0x00ffffffu); -} -)"s) + R"( -fn gx_depth_bytes(z24: u32) -> vec3u { - return vec3u((z24 >> 16u) & 0xffu, (z24 >> 8u) & 0xffu, z24 & 0xffu); -} - -fn clamp_copy_coord(coord: vec2i, tex_size: vec2i) -> vec2i { - let top = i32(floor(uv_xf.flags.z * f32(tex_size.y))); - let bottom = i32(floor(uv_xf.flags.w * f32(tex_size.y))); - return vec2i(coord.x, clamp(coord.y, top, bottom)); -} - -fn sample_depth_copy(uv: vec2f) -> vec4u { - let tex_size = vec2i(textureDimensions(src)); - let current_coord = clamp_copy_coord(vec2i(floor(uv * vec2f(tex_size))), tex_size); - let current = gx_depth_bytes(gx_z24_at_coord(current_coord)); - if (uv_xf.copy_filter.w == 0.0) { - return vec4u(current, 255u); - } - - // GX applies its vertical copy filter to depth copies too, filtering the high/middle/low Z bytes - // independently before the destination format picks bytes. Alpha is unfiltered and 255. - let row_stride = max(i32(round(uv_xf.flags.y)), 1); - let prev = gx_depth_bytes(gx_z24_at_coord( - clamp_copy_coord(current_coord - vec2i(0, row_stride), tex_size))); - let next = gx_depth_bytes(gx_z24_at_coord( - clamp_copy_coord(current_coord + vec2i(0, row_stride), tex_size))); - let coefficients = vec3u(uv_xf.copy_filter.xyz); - let combined = prev * coefficients.x + current * coefficients.y + next * coefficients.z; - var filtered = combined >> vec3u(6u); - - // The copy-filter accumulator wraps to nine bits when coefficients can - // produce values at or above 512, before saturating to an eight-bit byte. - if (coefficients.x + coefficients.y + coefficients.z >= 128u) { - filtered = filtered & vec3u(0x1ffu); - } - filtered = min(filtered, vec3u(255u)); - return vec4u(filtered, 255u); -} -)"s; - -// Passthrough blit (for scaling) -static constexpr std::string_view FragPassthrough = R"( -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - return sample_copy(in.uv); -} -)"sv; - -// GX_TF_I4: 4-bit intensity -> R8Unorm (quantized) -static constexpr std::string_view FragI4 = R"( -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let rgb = sample_copy(in.uv).rgb; - let i = quantize4(intensity(rgb)); - return vec4f(i, i, i, i); -} -)"sv; - -// GX_TF_I8: 8-bit intensity -> R8Unorm -static constexpr std::string_view FragI8 = R"( -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let rgb = sample_copy(in.uv).rgb; - let i = intensity(rgb); - return vec4f(i, i, i, i); -} -)"sv; - -// GX_TF_IA4: 4-bit intensity + 4-bit alpha -> RG8Unorm -static constexpr std::string_view FragIA4 = R"( -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let c = sample_copy(in.uv); - let i = quantize4(intensity(c.rgb)); - let a = quantize4(c.a); - return vec4f(i, i, i, a); -} -)"sv; - -// GX_TF_IA8: 8-bit intensity + 8-bit alpha -> RG8Unorm -static constexpr std::string_view FragIA8 = R"( -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let c = sample_copy(in.uv); - let i = intensity(c.rgb); - return vec4f(i, i, i, c.a); -} -)"sv; - -// GX_TF_RGB565: Blit alpha to 1.0 -static constexpr std::string_view FragRGB565 = R"( -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let c = sample_copy(in.uv); - return vec4f(c.rgb, 1.0); -} -)"sv; - -// GX_CTF_R4: 4-bit red -> R8Unorm -static constexpr std::string_view FragR4 = R"( -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let r = quantize4(sample_copy(in.uv).r); - return vec4f(r, r, r, r); -} -)"sv; - -// GX_CTF_RA4: 4-bit red + 4-bit alpha -> RG8Unorm -static constexpr std::string_view FragRA4 = R"( -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let c = sample_copy(in.uv); - let r = quantize4(c.r); - return vec4f(r, r, r, quantize4(c.a)); -} -)"sv; - -// GX_CTF_RA8: 8-bit red + 8-bit alpha -> RG8Unorm -static constexpr std::string_view FragRA8 = R"( -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let c = sample_copy(in.uv); - return vec4f(c.r, c.r, c.r, c.a); -} -)"sv; - -// GX_CTF_A8: 8-bit alpha -> R8Unorm -static constexpr std::string_view FragA8 = R"( -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let a = sample_copy(in.uv).a; - return vec4f(a, a, a, a); -} -)"sv; - -// GX_CTF_R8: 8-bit red -> R8Unorm -static constexpr std::string_view FragR8 = R"( -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let r = sample_copy(in.uv).r; - return vec4f(r, r, r, r); -} -)"sv; - -// GX_CTF_G8: 8-bit green -> R8Unorm -static constexpr std::string_view FragG8 = R"( -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let g = sample_copy(in.uv).g; - return vec4f(g, g, g, g); -} -)"sv; - -// GX_CTF_B8: 8-bit blue -> R8Unorm -static constexpr std::string_view FragB8 = R"( -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let b = sample_copy(in.uv).b; - return vec4f(b, b, b, b); -} -)"sv; - -// GX_CTF_RG8: 8-bit red + 8-bit green -> RG8Unorm -static constexpr std::string_view FragRG8 = R"( -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let c = sample_copy(in.uv); - return vec4f(c.r, c.r, c.r, c.g); -} -)"sv; - -// GX_CTF_GB8: 8-bit green + 8-bit blue -> RG8Unorm -static constexpr std::string_view FragGB8 = R"( -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let c = sample_copy(in.uv); - return vec4f(c.g, c.g, c.g, c.b); -} -)"sv; - -// GX_TF_Z8 stores the high-Z byte in I8 storage, which samples as intensity -// replicated across all four channels. -static constexpr std::string_view FragZ8 = R"( -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let depth_bytes = sample_depth_copy(in.uv); - let z8 = f32(depth_bytes.r) / 255.0; - return vec4f(z8, z8, z8, z8); -} -)"sv; - -// GX_TF_Z16 is the depth RA8 copy path: depth samples have opaque alpha and their high-Z byte in -// red, so the encoded [A, R] pair samples through IA8 as high-Z intensity with opaque alpha. -static constexpr std::string_view FragZ16 = detail::Z16FragmentShader; - -// GX_TF_Z24X8 uses the RGBA8 storage shape for copies, with the 24-bit depth -// value available to z-texture sampling through RGB. -static constexpr std::string_view FragZ24X8 = R"( -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let depth_bytes = sample_depth_copy(in.uv); - let r = f32(depth_bytes.r) / 255.0; - let g = f32(depth_bytes.g) / 255.0; - let b = f32(depth_bytes.b) / 255.0; - return vec4f(r, g, b, 1.0); -} -)"sv; - -struct ConvPipeline { - GXTexFmt fmt; - std::string_view fragShader; - wgpu::TextureFormat outputFormat; - const char* label; -}; - -static constexpr std::array ConvPipelines{ - ConvPipeline{GX_TF_I4, FragI4, wgpu::TextureFormat::RGBA8Unorm, "TexCopyConv I4"}, - ConvPipeline{GX_TF_I8, FragI8, wgpu::TextureFormat::RGBA8Unorm, "TexCopyConv I8"}, - ConvPipeline{GX_TF_IA4, FragIA4, wgpu::TextureFormat::RGBA8Unorm, "TexCopyConv IA4"}, - ConvPipeline{GX_TF_IA8, FragIA8, wgpu::TextureFormat::RGBA8Unorm, "TexCopyConv IA8"}, - ConvPipeline{GX_TF_RGB565, FragRGB565, wgpu::TextureFormat::RGBA8Unorm, "TexCopyConv RGB565"}, - ConvPipeline{GX_CTF_R4, FragR4, wgpu::TextureFormat::RGBA8Unorm, "TexCopyConv R4"}, - ConvPipeline{GX_CTF_RA4, FragRA4, wgpu::TextureFormat::RGBA8Unorm, "TexCopyConv RA4"}, - ConvPipeline{GX_CTF_RA8, FragRA8, wgpu::TextureFormat::RGBA8Unorm, "TexCopyConv RA8"}, - ConvPipeline{GX_CTF_A8, FragA8, wgpu::TextureFormat::RGBA8Unorm, "TexCopyConv A8"}, - ConvPipeline{GX_CTF_R8, FragR8, wgpu::TextureFormat::RGBA8Unorm, "TexCopyConv R8"}, - ConvPipeline{GX_CTF_G8, FragG8, wgpu::TextureFormat::RGBA8Unorm, "TexCopyConv G8"}, - ConvPipeline{GX_CTF_B8, FragB8, wgpu::TextureFormat::RGBA8Unorm, "TexCopyConv B8"}, - ConvPipeline{GX_CTF_RG8, FragRG8, wgpu::TextureFormat::RGBA8Unorm, "TexCopyConv RG8"}, - ConvPipeline{GX_CTF_GB8, FragGB8, wgpu::TextureFormat::RGBA8Unorm, "TexCopyConv GB8"}, -}; - -static constexpr std::array DepthConvPipelines{ - ConvPipeline{GX_TF_Z8, FragZ8, wgpu::TextureFormat::RGBA8Unorm, "TexCopyConv Z8"}, - ConvPipeline{GX_TF_Z16, FragZ16, wgpu::TextureFormat::RGBA8Unorm, "TexCopyConv Z16"}, - ConvPipeline{GX_TF_Z24X8, FragZ24X8, wgpu::TextureFormat::RGBA8Unorm, "TexCopyConv Z24X8"}, -}; - -static wgpu::BindGroupLayout g_bindGroupLayout; -static wgpu::BindGroupLayout g_depthBindGroupLayout; -static wgpu::Sampler g_nearestSampler; -static wgpu::Sampler g_linearSampler; -static absl::flat_hash_map g_pipelines; -static absl::flat_hash_map g_blitPipelines; - -static wgpu::RenderPipeline create_pipeline(const ConvPipeline& conv, const std::string_view shaderPreamble, - const wgpu::BindGroupLayout& bindGroupLayout) { - std::string shaderSource; - shaderSource.reserve(shaderPreamble.size() + conv.fragShader.size()); - shaderSource += shaderPreamble; - shaderSource += conv.fragShader; - - const wgpu::ShaderSourceWGSL wgslSource{wgpu::ShaderSourceWGSL::Init{ - .code = shaderSource.c_str(), - }}; - const wgpu::ShaderModuleDescriptor moduleDescriptor{ - .nextInChain = &wgslSource, - .label = conv.label, - }; - const auto module = g_device.CreateShaderModule(&moduleDescriptor); - - const std::array colorTargets{wgpu::ColorTargetState{ - .format = conv.outputFormat, - }}; - const wgpu::FragmentState fragmentState{ - .module = module, - .entryPoint = "fs_main", - .targetCount = colorTargets.size(), - .targets = colorTargets.data(), - }; - - const wgpu::PipelineLayoutDescriptor layoutDescriptor{ - .bindGroupLayoutCount = 1, - .bindGroupLayouts = &bindGroupLayout, - }; - const auto pipelineLayout = g_device.CreatePipelineLayout(&layoutDescriptor); - - const wgpu::RenderPipelineDescriptor pipelineDescriptor{ - .label = conv.label, - .layout = pipelineLayout, - .vertex = - wgpu::VertexState{ - .module = module, - .entryPoint = "vs_main", - }, - .primitive = - wgpu::PrimitiveState{ - .topology = wgpu::PrimitiveTopology::TriangleList, - }, - .fragment = &fragmentState, - }; - return g_device.CreateRenderPipeline(&pipelineDescriptor); -} - -bool needs_conversion(const GXTexFmt fmt) { return g_pipelines.contains(fmt); } - -void initialize() { - static constexpr std::array bindGroupLayoutEntries{ - wgpu::BindGroupLayoutEntry{ - .binding = 0, - .visibility = wgpu::ShaderStage::Fragment, - .sampler = - wgpu::SamplerBindingLayout{ - .type = wgpu::SamplerBindingType::Filtering, - }, - }, - wgpu::BindGroupLayoutEntry{ - .binding = 1, - .visibility = wgpu::ShaderStage::Fragment, - .texture = - wgpu::TextureBindingLayout{ - .sampleType = wgpu::TextureSampleType::Float, - .viewDimension = wgpu::TextureViewDimension::e2D, - }, - }, - wgpu::BindGroupLayoutEntry{ - .binding = 2, - .visibility = wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment, - .buffer = - wgpu::BufferBindingLayout{ - .type = wgpu::BufferBindingType::Uniform, - }, - }, - }; - static constexpr wgpu::BindGroupLayoutDescriptor bindGroupLayoutDescriptor{ - .label = "TexCopyConv Bind Group Layout", - .entryCount = bindGroupLayoutEntries.size(), - .entries = bindGroupLayoutEntries.data(), - }; - g_bindGroupLayout = g_device.CreateBindGroupLayout(&bindGroupLayoutDescriptor); - - static constexpr std::array depthBindGroupLayoutEntries{ - wgpu::BindGroupLayoutEntry{ - .binding = 0, - .visibility = wgpu::ShaderStage::Fragment, - .texture = - wgpu::TextureBindingLayout{ - .sampleType = wgpu::TextureSampleType::Depth, - .viewDimension = wgpu::TextureViewDimension::e2D, - }, - }, - wgpu::BindGroupLayoutEntry{ - .binding = 1, - .visibility = wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment, - .buffer = - wgpu::BufferBindingLayout{ - .type = wgpu::BufferBindingType::Uniform, - }, - }, - }; - static constexpr wgpu::BindGroupLayoutDescriptor depthBindGroupLayoutDescriptor{ - .label = "TexCopyConv Depth Bind Group Layout", - .entryCount = depthBindGroupLayoutEntries.size(), - .entries = depthBindGroupLayoutEntries.data(), - }; - g_depthBindGroupLayout = g_device.CreateBindGroupLayout(&depthBindGroupLayoutDescriptor); - - // Native RAM readback uses RGBA even when the EFB/surface uses BGRA. - // Build both variants here; frame workers only read the completed map. - for (const auto format : {wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureFormat::BGRA8Unorm}) { - g_blitPipelines[format] = create_pipeline( - {GX_TF_RGBA8, FragPassthrough, format, "TexCopyConv Blit"}, ShaderPreamble, g_bindGroupLayout); - } - for (const auto& conv : ConvPipelines) { - g_pipelines[conv.fmt] = create_pipeline(conv, ShaderPreamble, g_bindGroupLayout); - if (conv.outputFormat != to_wgpu(conv.fmt)) { - Log.fatal("Output format mismatch for {}", conv.fmt); - } - } - for (const auto& conv : DepthConvPipelines) { - g_pipelines[conv.fmt] = create_pipeline(conv, DepthShaderPreamble, g_depthBindGroupLayout); - if (conv.outputFormat != to_wgpu(conv.fmt)) { - Log.fatal("Output format mismatch for {}", conv.fmt); - } - } - - static constexpr wgpu::SamplerDescriptor nearestSamplerDescriptor{ - .label = "TexCopyConv Nearest Sampler", - .magFilter = wgpu::FilterMode::Nearest, - .minFilter = wgpu::FilterMode::Nearest, - }; - g_nearestSampler = g_device.CreateSampler(&nearestSamplerDescriptor); - - static constexpr wgpu::SamplerDescriptor linearSamplerDescriptor{ - .label = "TexCopyConv Linear Sampler", - .magFilter = wgpu::FilterMode::Linear, - .minFilter = wgpu::FilterMode::Linear, - }; - g_linearSampler = g_device.CreateSampler(&linearSamplerDescriptor); -} - -void shutdown() { - g_pipelines.clear(); - g_blitPipelines.clear(); - g_bindGroupLayout = {}; - g_depthBindGroupLayout = {}; - g_nearestSampler = {}; - g_linearSampler = {}; -} - -static void execute(const wgpu::CommandEncoder& cmd, const ConvRequest& req, const wgpu::RenderPipeline& pipeline) { - wgpu::BindGroup bindGroup; - if (gx::is_depth_format(req.fmt)) { - const std::array bindGroupEntries{ - wgpu::BindGroupEntry{ - .binding = 0, - .textureView = req.srcView, - }, - wgpu::BindGroupEntry{ - .binding = 1, - .buffer = g_uniformBuffer, - .offset = req.uniformRange.offset, - .size = req.uniformRange.size, - }, - }; - const wgpu::BindGroupDescriptor bindGroupDescriptor{ - .layout = g_depthBindGroupLayout, - .entryCount = bindGroupEntries.size(), - .entries = bindGroupEntries.data(), - }; - bindGroup = g_device.CreateBindGroup(&bindGroupDescriptor); - } else { - const auto& sampler = req.sampleFilter == SampleFilter::Linear ? g_linearSampler : g_nearestSampler; - const std::array bindGroupEntries{ - wgpu::BindGroupEntry{ - .binding = 0, - .sampler = sampler, - }, - wgpu::BindGroupEntry{ - .binding = 1, - .textureView = req.srcView, - }, - wgpu::BindGroupEntry{ - .binding = 2, - .buffer = g_uniformBuffer, - .offset = req.uniformRange.offset, - .size = req.uniformRange.size, - }, - }; - const wgpu::BindGroupDescriptor bindGroupDescriptor{ - .layout = g_bindGroupLayout, - .entryCount = bindGroupEntries.size(), - .entries = bindGroupEntries.data(), - }; - bindGroup = g_device.CreateBindGroup(&bindGroupDescriptor); - } - - const std::array colorAttachments{ - wgpu::RenderPassColorAttachment{ - .view = req.dst->attachmentTextureView, - .loadOp = wgpu::LoadOp::Clear, - .storeOp = wgpu::StoreOp::Store, - .clearValue = {0.0, 0.0, 0.0, 0.0}, - }, - }; - const wgpu::RenderPassDescriptor renderPassDescriptor{ - .label = "TexCopyConv Pass", - .colorAttachmentCount = colorAttachments.size(), - .colorAttachments = colorAttachments.data(), - }; - const auto pass = cmd.BeginRenderPass(&renderPassDescriptor); - pass.SetPipeline(pipeline); - pass.SetBindGroup(0, bindGroup); - pass.Draw(3); - pass.End(); -} - -void run(const wgpu::CommandEncoder& cmd, const ConvRequest& req) { - const auto it = g_pipelines.find(req.fmt); - if (it == g_pipelines.end()) { - Log.fatal("No copy conversion pipeline for format {}", static_cast(req.fmt)); - } - execute(cmd, req, it->second); -} - -void blit(const wgpu::CommandEncoder& cmd, const ConvRequest& req) { - const auto it = g_blitPipelines.find(req.dst->format); - if (it == g_blitPipelines.end()) { - Log.fatal("Unsupported blit destination format {}", static_cast(req.dst->format)); - } - execute(cmd, req, it->second); -} - -} // namespace aurora::gfx::tex_copy_conv diff --git a/aurora-main/lib/gfx/tex_copy_conv.hpp b/aurora-main/lib/gfx/tex_copy_conv.hpp deleted file mode 100644 index 29965be..0000000 --- a/aurora-main/lib/gfx/tex_copy_conv.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "common.hpp" - -#include - -namespace aurora::gfx::tex_copy_conv { - -enum class SampleFilter : uint8_t { - Nearest, - Linear, -}; - -struct ConvRequest { - GXTexFmt fmt; - wgpu::TextureView srcView; // View of resolved EFB / offscreen color/depth - Range uniformRange; // UV transform uniform (offset + scale) - TextureHandle dst; // Destination texture - SampleFilter sampleFilter = SampleFilter::Nearest; - bool forceOpaqueAlpha = false; -}; - -bool needs_conversion(GXTexFmt fmt); - -void initialize(); -void shutdown(); -void run(const wgpu::CommandEncoder& cmd, const ConvRequest& req); -void blit(const wgpu::CommandEncoder& cmd, const ConvRequest& req); - -} // namespace aurora::gfx::tex_copy_conv diff --git a/aurora-main/lib/gfx/tex_copy_format_contract.hpp b/aurora-main/lib/gfx/tex_copy_format_contract.hpp deleted file mode 100644 index be10c9a..0000000 --- a/aurora-main/lib/gfx/tex_copy_format_contract.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace aurora::gfx::tex_copy_conv::detail { - -// GX_TF_Z16 selects the depth RA8 copy format: the encoder writes alpha (255) then the high-Z -// byte, so sampling as IA8 gives high-Z as intensity. Middle and low depth bytes are not stored. -constexpr std::array z16_ra8_as_ia8_rgba(std::uint8_t high) noexcept { - return {high, high, high, 0xff}; -} - -inline constexpr std::string_view Z16FragmentShader = R"( -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let depth_bytes = sample_depth_copy(in.uv); - let i = f32(depth_bytes.r) / 255.0; - return vec4f(i, i, i, 1.0); -} -)"; - -} // namespace aurora::gfx::tex_copy_conv::detail diff --git a/aurora-main/lib/gfx/tex_palette_conv.cpp b/aurora-main/lib/gfx/tex_palette_conv.cpp deleted file mode 100644 index 842cca3..0000000 --- a/aurora-main/lib/gfx/tex_palette_conv.cpp +++ /dev/null @@ -1,260 +0,0 @@ -#include "tex_palette_conv.hpp" - -#include "../internal.hpp" -#include "../webgpu/gpu.hpp" -#include "texture.hpp" - -#include - -namespace aurora::gfx::tex_palette_conv { -static Module Log("aurora::gfx::tex_palette_conv"); - -using webgpu::g_device; - -static constexpr std::string_view ShaderPreambleVtx = R"( -struct VertexOutput { - @builtin(position) pos: vec4f, - @location(0) uv: vec2f, -}; - -var positions: array = array( - vec2f(-1.0, 1.0), - vec2f(-1.0, -3.0), - vec2f(3.0, 1.0), -); -var uvs: array = array( - vec2f(0.0, 0.0), - vec2f(0.0, 2.0), - vec2f(2.0, 0.0), -); - -@vertex fn vs_main(@builtin(vertex_index) vi: u32) -> VertexOutput { - var out: VertexOutput; - out.pos = vec4f(positions[vi], 0.0, 1.0); - out.uv = uvs[vi]; - return out; -} - -fn intensity(rgb: vec3f) -> f32 { - // ITU-R BT.601 luma coefficients - return dot(rgb, vec3f(0.257, 0.504, 0.098)) + 16.0 / 255.0; -} -)"sv; - -// Direct: R16Sint index texture + TLUT -> RGBA8 -static constexpr std::string_view ShaderDirect = R"( -@group(0) @binding(0) var src_samp: sampler; -@group(0) @binding(1) var src: texture_2d; -@group(0) @binding(2) var tlut: texture_2d; - -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let texSize = vec2f(textureDimensions(src)); - let coord = vec2i(floor(in.uv * texSize)); - let idx = textureLoad(src, coord, 0).r; - return textureLoad(tlut, vec2i(idx, 0), 0); -} -)"sv; - -// FromFloat8: f32 texture (R8Unorm) -> 8-bit index -> TLUT -> RGBA8 -static constexpr std::string_view ShaderFromFloat8 = R"( -@group(0) @binding(0) var src_samp: sampler; -@group(0) @binding(1) var src: texture_2d; -@group(0) @binding(2) var tlut: texture_2d; - -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let texSize = vec2f(textureDimensions(src)); - let coord = vec2i(floor(in.uv * texSize)); - let r = textureLoad(src, coord, 0).r; - return textureLoad(tlut, vec2i(i32(r * 255.0), 0), 0); -} -)"sv; - -// FromFloat4: f32 texture (R8Unorm) -> 4-bit index -> TLUT -> RGBA8 -static constexpr std::string_view ShaderFromFloat4 = R"( -@group(0) @binding(0) var src_samp: sampler; -@group(0) @binding(1) var src: texture_2d; -@group(0) @binding(2) var tlut: texture_2d; - -@fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let texSize = vec2f(textureDimensions(src)); - let coord = vec2i(floor(in.uv * texSize)); - let r = textureLoad(src, coord, 0).r; - return textureLoad(tlut, vec2i(i32(r * 15.0), 0), 0); -} -)"sv; - -struct PipelineInfo { - wgpu::RenderPipeline pipeline; - wgpu::BindGroupLayout bindGroupLayout; -}; - -static PipelineInfo g_directPipeline; -static PipelineInfo g_fromFloat8Pipeline; -static PipelineInfo g_fromFloat4Pipeline; -static wgpu::Sampler g_sampler; - -static PipelineInfo create_pipeline(std::string_view fragBindingsAndShader, wgpu::TextureSampleType srcSampleType, - const char* label) { - std::string shaderSource; - shaderSource.reserve(ShaderPreambleVtx.size() + fragBindingsAndShader.size()); - shaderSource += ShaderPreambleVtx; - shaderSource += fragBindingsAndShader; - - wgpu::ShaderSourceWGSL wgslSource{}; - wgslSource.code = shaderSource.c_str(); - const wgpu::ShaderModuleDescriptor moduleDescriptor{ - .nextInChain = &wgslSource, - .label = label, - }; - auto module = g_device.CreateShaderModule(&moduleDescriptor); - - const std::array bindGroupLayoutEntries{ - wgpu::BindGroupLayoutEntry{ - .binding = 0, - .visibility = wgpu::ShaderStage::Fragment, - .sampler = - wgpu::SamplerBindingLayout{ - .type = wgpu::SamplerBindingType::NonFiltering, - }, - }, - wgpu::BindGroupLayoutEntry{ - .binding = 1, - .visibility = wgpu::ShaderStage::Fragment, - .texture = - wgpu::TextureBindingLayout{ - .sampleType = srcSampleType, - .viewDimension = wgpu::TextureViewDimension::e2D, - }, - }, - wgpu::BindGroupLayoutEntry{ - .binding = 2, - .visibility = wgpu::ShaderStage::Fragment, - .texture = - wgpu::TextureBindingLayout{ - .sampleType = wgpu::TextureSampleType::Float, - .viewDimension = wgpu::TextureViewDimension::e2D, - }, - }, - }; - const auto bindGroupLayoutLabel = fmt::format("{} Bind Group Layout", label); - const wgpu::BindGroupLayoutDescriptor bindGroupLayoutDescriptor{ - .label = bindGroupLayoutLabel.c_str(), - .entryCount = bindGroupLayoutEntries.size(), - .entries = bindGroupLayoutEntries.data(), - }; - auto bindGroupLayout = g_device.CreateBindGroupLayout(&bindGroupLayoutDescriptor); - - const wgpu::PipelineLayoutDescriptor layoutDescriptor{ - .bindGroupLayoutCount = 1, - .bindGroupLayouts = &bindGroupLayout, - }; - auto pipelineLayout = g_device.CreatePipelineLayout(&layoutDescriptor); - - constexpr std::array colorTargets{wgpu::ColorTargetState{ - .format = wgpu::TextureFormat::RGBA8Unorm, - }}; - const wgpu::FragmentState fragmentState{ - .module = module, - .entryPoint = "fs_main", - .targetCount = colorTargets.size(), - .targets = colorTargets.data(), - }; - const wgpu::RenderPipelineDescriptor pipelineDescriptor{ - .label = label, - .layout = pipelineLayout, - .vertex = - wgpu::VertexState{ - .module = module, - .entryPoint = "vs_main", - }, - .primitive = - wgpu::PrimitiveState{ - .topology = wgpu::PrimitiveTopology::TriangleList, - }, - .fragment = &fragmentState, - }; - - return PipelineInfo{ - .pipeline = g_device.CreateRenderPipeline(&pipelineDescriptor), - .bindGroupLayout = std::move(bindGroupLayout), - }; -} - -static const PipelineInfo& pipeline_for_variant(Variant variant) { - switch (variant) { - case Variant::Direct: - return g_directPipeline; - case Variant::FromFloat8: - return g_fromFloat8Pipeline; - case Variant::FromFloat4: - return g_fromFloat4Pipeline; - } - FATAL("invalid palette conv variant {}", static_cast(variant)); -} - -void initialize() { - g_directPipeline = create_pipeline(ShaderDirect, wgpu::TextureSampleType::Sint, "TexPaletteConv Direct"); - g_fromFloat8Pipeline = - create_pipeline(ShaderFromFloat8, wgpu::TextureSampleType::UnfilterableFloat, "TexPaletteConv FromFloat8"); - g_fromFloat4Pipeline = - create_pipeline(ShaderFromFloat4, wgpu::TextureSampleType::UnfilterableFloat, "TexPaletteConv FromFloat4"); - constexpr wgpu::SamplerDescriptor samplerDesc{ - .label = "TexPaletteConv Sampler", - .magFilter = wgpu::FilterMode::Nearest, - .minFilter = wgpu::FilterMode::Nearest, - }; - g_sampler = g_device.CreateSampler(&samplerDesc); -} - -void shutdown() { - g_directPipeline = {}; - g_fromFloat8Pipeline = {}; - g_fromFloat4Pipeline = {}; - g_sampler = {}; -} - -void run(const wgpu::CommandEncoder& cmd, const ConvRequest& req) { - const auto& [pipeline, bindGroupLayout] = pipeline_for_variant(req.variant); - - const std::array bindGroupEntries{ - wgpu::BindGroupEntry{ - .binding = 0, - .sampler = g_sampler, - }, - wgpu::BindGroupEntry{ - .binding = 1, - .textureView = req.src->sampleTextureView, - }, - wgpu::BindGroupEntry{ - .binding = 2, - .textureView = req.tlut->sampleTextureView, - }, - }; - const wgpu::BindGroupDescriptor bindGroupDescriptor{ - .layout = bindGroupLayout, - .entryCount = bindGroupEntries.size(), - .entries = bindGroupEntries.data(), - }; - const auto bindGroup = g_device.CreateBindGroup(&bindGroupDescriptor); - - const std::array colorAttachments{ - wgpu::RenderPassColorAttachment{ - .view = req.dst->attachmentTextureView, - .loadOp = wgpu::LoadOp::Clear, - .storeOp = wgpu::StoreOp::Store, - .clearValue = {0.0, 0.0, 0.0, 0.0}, - }, - }; - const wgpu::RenderPassDescriptor renderPassDescriptor{ - .label = "TexPaletteConv Pass", - .colorAttachmentCount = colorAttachments.size(), - .colorAttachments = colorAttachments.data(), - }; - const auto pass = cmd.BeginRenderPass(&renderPassDescriptor); - pass.SetPipeline(pipeline); - pass.SetBindGroup(0, bindGroup); - pass.Draw(3); - pass.End(); -} - -} // namespace aurora::gfx::tex_palette_conv diff --git a/aurora-main/lib/gfx/tex_palette_conv.hpp b/aurora-main/lib/gfx/tex_palette_conv.hpp deleted file mode 100644 index fca8a38..0000000 --- a/aurora-main/lib/gfx/tex_palette_conv.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "common.hpp" - -namespace aurora::gfx::tex_palette_conv { - -enum class Variant : uint8_t { - Direct, // R16Sint index texture -> TLUT -> RGBA8 - FromFloat8, // f32 texture, R channel * 255 -> 8-bit index -> TLUT -> RGBA8 - FromFloat4, // f32 texture, R channel * 15 -> 4-bit index -> TLUT -> RGBA8 -}; - -struct ConvRequest { - Variant variant; - TextureHandle src; - TextureHandle dst; - TextureHandle tlut; -}; - -void initialize(); -void shutdown(); -void run(const wgpu::CommandEncoder& cmd, const ConvRequest& req); - -} // namespace aurora::gfx::tex_palette_conv diff --git a/aurora-main/lib/gfx/texture.cpp b/aurora-main/lib/gfx/texture.cpp deleted file mode 100644 index f465f36..0000000 --- a/aurora-main/lib/gfx/texture.cpp +++ /dev/null @@ -1,303 +0,0 @@ -#include "common.hpp" - -#include "../internal.hpp" -#include "../webgpu/gpu.hpp" -#include "aurora/aurora.h" -#include "texture.hpp" -#include "texture_convert.hpp" -#include "../gx/gx_fmt.hpp" - -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace aurora::gfx { -using webgpu::g_device; -using webgpu::g_queue; - -namespace { -Module Log("aurora::gfx"); - -constexpr u32 div_ceil(u32 value, u32 divisor) noexcept { return (value + divisor - 1) / divisor; } - -uint32_t clamp_mip_count(uint32_t width, uint32_t height, uint32_t mips, const char* label) noexcept { - const uint32_t maxMips = max_texture_mip_count(width, height); - const uint32_t safeMips = std::clamp(mips, 1u, maxMips); - if (safeMips != mips) { - Log.warn("{}: clamping mip count {} to {} for {}x{} texture", label, mips, safeMips, width, height); - } - return safeMips; -} - -wgpu::Extent3D physical_size(wgpu::Extent3D size, TextureFormatInfo info) { - const uint32_t width = ((size.width + info.blockWidth - 1) / info.blockWidth) * info.blockWidth; - const uint32_t height = ((size.height + info.blockHeight - 1) / info.blockHeight) * info.blockHeight; - return {.width = width, .height = height, .depthOrArrayLayers = size.depthOrArrayLayers}; -} -} // namespace - -TextureFormatInfo format_info(wgpu::TextureFormat format) noexcept { - switch (format) { - DEFAULT_FATAL("unimplemented texture format {}", magic_enum::enum_name(format)); - case wgpu::TextureFormat::R8Unorm: - return {1, 1, 1, false}; - case wgpu::TextureFormat::RG8Unorm: - case wgpu::TextureFormat::R16Sint: - return {1, 1, 2, false}; - case wgpu::TextureFormat::RGBA8Unorm: - case wgpu::TextureFormat::BGRA8Unorm: - case wgpu::TextureFormat::R32Float: - return {1, 1, 4, false}; - case wgpu::TextureFormat::BC1RGBAUnorm: - return {4, 4, 8, true}; - case wgpu::TextureFormat::BC3RGBAUnorm: - case wgpu::TextureFormat::BC5RGUnorm: - case wgpu::TextureFormat::BC7RGBAUnorm: - return {4, 4, 16, true}; - } -} - -uint64_t calc_texture_size(wgpu::TextureFormat format, u32 width, u32 height, u32 mips) noexcept { - const auto info = format_info(format); - uint64_t total = 0; - for (uint32_t mip = 0; mip < mips; ++mip) { - const uint32_t mipWidth = std::max(width >> mip, 1u); - const uint32_t mipHeight = std::max(height >> mip, 1u); - const uint64_t widthBlocks = div_ceil(mipWidth, info.blockWidth); - const uint64_t heightBlocks = div_ceil(mipHeight, info.blockHeight); - const uint64_t mipBytes = widthBlocks * heightBlocks * info.blockSize; - total += mipBytes; - } - return total; -} - -TextureHandle new_static_texture_2d(uint32_t width, uint32_t height, uint32_t mips, u32 format, ArrayRef data, - bool tlut, const char* label) noexcept { - ZoneScoped; - - mips = clamp_mip_count(width, height, mips, label); - auto handle = new_dynamic_texture_2d(width, height, mips, format, label); - auto& ref = *handle; - - ConvertedTexture converted; - if (ref.gxFormat != InvalidTextureFormat) { - if (tlut) { - CHECK(ref.size.height == 1, "new_static_texture_2d[{}]: expected tlut height 1, got {}", label, ref.size.height); - CHECK(ref.mipCount == 1, "new_static_texture_2d[{}]: expected tlut mipCount 1, got {}", label, ref.mipCount); - converted = convert_tlut(ref.gxFormat, ref.size.width, data); - } else { - converted = convert_texture(ref.gxFormat, ref.size.width, ref.size.height, ref.mipCount, data); - } - if (!converted.data.empty()) { - data = converted.data; - ref.hasArbitraryMips = converted.hasArbitraryMips; - } - } - - uint32_t offset = 0; - for (uint32_t mip = 0; mip < mips; ++mip) { - const wgpu::Extent3D mipSize{ - .width = std::max(ref.size.width >> mip, 1u), - .height = std::max(ref.size.height >> mip, 1u), - .depthOrArrayLayers = ref.size.depthOrArrayLayers, - }; - const auto info = format_info(ref.format); - const auto physicalSize = physical_size(mipSize, info); - const uint32_t widthBlocks = physicalSize.width / info.blockWidth; - const uint32_t heightBlocks = physicalSize.height / info.blockHeight; - const uint32_t bytesPerRow = widthBlocks * info.blockSize; - const uint32_t dataSize = bytesPerRow * heightBlocks * mipSize.depthOrArrayLayers; - if (offset > data.size() || dataSize > data.size() - offset) { - Log.warn("new_static_texture_2d[{}]: stopping at mip {}: expected at least {} bytes, got {}", label, mip, - static_cast(offset) + dataSize, data.size()); - return handle; - } - const wgpu::TexelCopyTextureInfo dstView{ - .texture = ref.texture, - .mipLevel = mip, - }; - if constexpr (UseTextureBuffer) { - const auto range = push_texture_data(data.data() + offset, dataSize, bytesPerRow, heightBlocks); - const wgpu::TexelCopyBufferLayout dataLayout{ - .offset = range.offset, - .bytesPerRow = bytesPerRow, - .rowsPerImage = heightBlocks, - }; - g_textureUploads.emplace_back(dataLayout, std::move(dstView), physicalSize); - } else { - const wgpu::TexelCopyBufferLayout dataLayout{ - .bytesPerRow = bytesPerRow, - .rowsPerImage = heightBlocks, - }; - g_queue.WriteTexture(&dstView, data.data() + offset, dataSize, &dataLayout, &physicalSize); - } - offset += dataSize; - } - if (data.size() != UINT32_MAX && offset < data.size()) { - Log.warn("new_static_texture_2d[{}]: texture used {} bytes, but given {} bytes", label, offset, data.size()); - } - return handle; -} - -TextureHandle new_dynamic_texture_2d(uint32_t width, uint32_t height, uint32_t mips, u32 gxFormat, - const char* label) noexcept { - ZoneScopedS(3); - mips = clamp_mip_count(width, height, mips, label); - const auto wgpuFormat = to_wgpu(gxFormat); - const wgpu::Extent3D size{ - .width = width, - .height = height, - .depthOrArrayLayers = 1, - }; - const wgpu::TextureDescriptor textureDescriptor{ - .label = label, - .usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopyDst, - .dimension = wgpu::TextureDimension::e2D, - .size = size, - .format = wgpuFormat, - .mipLevelCount = mips, - .sampleCount = 1, - }; - auto texture = g_device.CreateTexture(&textureDescriptor); - const auto viewLabel = fmt::format("{} view", label); - wgpu::TextureViewDescriptor textureViewDescriptor{ - .label = viewLabel.c_str(), - .format = wgpuFormat, - .dimension = wgpu::TextureViewDimension::e2D, - .mipLevelCount = mips, - }; - auto textureView = texture.CreateView(&textureViewDescriptor); - return std::make_shared(std::move(texture), std::move(textureView), wgpu::TextureView{}, size, wgpuFormat, - mips, gxFormat); -} - -TextureHandle new_render_texture(uint32_t width, uint32_t height, u32 gxFormat, const char* label) noexcept { - ZoneScoped; - - const auto wgpuFormat = webgpu::g_graphicsConfig.surfaceConfiguration.format; - const wgpu::Extent3D size{ - .width = width, - .height = height, - .depthOrArrayLayers = 1, - }; - const wgpu::TextureDescriptor textureDescriptor{ - .label = label, - .usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst | - wgpu::TextureUsage::RenderAttachment, - .dimension = wgpu::TextureDimension::e2D, - .size = size, - .format = wgpuFormat, - .mipLevelCount = 1, - .sampleCount = 1, - }; - auto texture = g_device.CreateTexture(&textureDescriptor); - - // Create texture view for color attachments - const auto viewLabel = fmt::format("{} view", label); - wgpu::TextureViewDescriptor textureViewDescriptor{ - .label = viewLabel.c_str(), - .format = wgpuFormat, - .dimension = wgpu::TextureViewDimension::e2D, - }; - auto attachmentTextureView = texture.CreateView(&textureViewDescriptor); - wgpu::TextureView sampleTextureView = attachmentTextureView; - return std::make_shared(std::move(texture), std::move(sampleTextureView), - std::move(attachmentTextureView), size, wgpuFormat, 1, gxFormat); -} - -TextureHandle new_conv_texture(uint32_t width, uint32_t height, u32 gxFormat, const char* label) noexcept { - ZoneScoped; - - const auto wgpuFormat = to_wgpu(gxFormat); - const wgpu::Extent3D size{ - .width = width, - .height = height, - .depthOrArrayLayers = 1, - }; - const wgpu::TextureDescriptor textureDescriptor{ - .label = label, - .usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc | - wgpu::TextureUsage::RenderAttachment, - .dimension = wgpu::TextureDimension::e2D, - .size = size, - .format = wgpuFormat, - .mipLevelCount = 1, - .sampleCount = 1, - }; - auto texture = g_device.CreateTexture(&textureDescriptor); - - // Create texture view for color attachments - const auto viewLabel = fmt::format("{} view", label); - wgpu::TextureViewDescriptor textureViewDescriptor{ - .label = viewLabel.c_str(), - .format = wgpuFormat, - .dimension = wgpu::TextureViewDimension::e2D, - }; - auto attachmentTextureView = texture.CreateView(&textureViewDescriptor); - wgpu::TextureView sampleTextureView = attachmentTextureView; - return std::make_shared(std::move(texture), std::move(sampleTextureView), - std::move(attachmentTextureView), size, wgpuFormat, 1, gxFormat); -} - -void write_texture(TextureRef& ref, ArrayRef data) noexcept { - ZoneScoped; - - ConvertedTexture converted; - if (ref.gxFormat != InvalidTextureFormat) { - converted = convert_texture(ref.gxFormat, ref.size.width, ref.size.height, ref.mipCount, data); - ref.hasArbitraryMips = converted.hasArbitraryMips; - if (!converted.data.empty()) { - data = converted.data; - } - } - - uint32_t offset = 0; - for (uint32_t mip = 0; mip < ref.mipCount; ++mip) { - const wgpu::Extent3D mipSize{ - .width = std::max(ref.size.width >> mip, 1u), - .height = std::max(ref.size.height >> mip, 1u), - .depthOrArrayLayers = ref.size.depthOrArrayLayers, - }; - const auto info = format_info(ref.format); - const auto physicalSize = physical_size(mipSize, info); - const uint32_t widthBlocks = physicalSize.width / info.blockWidth; - const uint32_t heightBlocks = physicalSize.height / info.blockHeight; - const uint32_t bytesPerRow = widthBlocks * info.blockSize; - const uint32_t dataSize = bytesPerRow * heightBlocks * mipSize.depthOrArrayLayers; - if (offset > data.size() || dataSize > data.size() - offset) { - Log.warn("write_texture: stopping at mip {}: expected at least {} bytes, got {}", mip, - static_cast(offset) + dataSize, data.size()); - return; - } - const wgpu::TexelCopyTextureInfo dstView{ - .texture = ref.texture, - .mipLevel = mip, - }; - if constexpr (UseTextureBuffer) { - const auto range = push_texture_data(data.data() + offset, dataSize, bytesPerRow, heightBlocks); - const wgpu::TexelCopyBufferLayout dataLayout{ - .offset = range.offset, - .bytesPerRow = bytesPerRow, - .rowsPerImage = heightBlocks, - }; - g_textureUploads.emplace_back(dataLayout, std::move(dstView), physicalSize); - } else { - const wgpu::TexelCopyBufferLayout dataLayout{ - .bytesPerRow = bytesPerRow, - .rowsPerImage = heightBlocks, - }; - g_queue.WriteTexture(&dstView, data.data() + offset, dataSize, &dataLayout, &physicalSize); - } - offset += dataSize; - } - if (data.size() != UINT32_MAX && offset < data.size()) { - Log.warn("write_texture: texture used {} bytes, but given {} bytes", offset, data.size()); - } -} -} // namespace aurora::gfx diff --git a/aurora-main/lib/gfx/texture.hpp b/aurora-main/lib/gfx/texture.hpp deleted file mode 100644 index 4c1d4cc..0000000 --- a/aurora-main/lib/gfx/texture.hpp +++ /dev/null @@ -1,147 +0,0 @@ -#pragma once -#include - -#include - -#include "common.hpp" - -namespace aurora::gfx { -constexpr uint32_t max_texture_mip_count(uint32_t width, uint32_t height) noexcept { - uint32_t dimension = std::max(width, height); - uint32_t count = 1; - while (dimension > 1) { - dimension >>= 1; - ++count; - } - return count; -} - -struct TextureUpload { - wgpu::TexelCopyBufferLayout layout; - wgpu::TexelCopyTextureInfo tex; - wgpu::Extent3D size; - - TextureUpload(wgpu::TexelCopyBufferLayout layout, wgpu::TexelCopyTextureInfo tex, wgpu::Extent3D size) noexcept - : layout(layout), tex(std::move(tex)), size(size) {} -}; -extern std::vector g_textureUploads; - -struct TextureFormatInfo { - uint8_t blockWidth; - uint8_t blockHeight; - uint8_t blockSize; - bool compressed; -}; -TextureFormatInfo format_info(wgpu::TextureFormat format) noexcept; -uint64_t calc_texture_size(wgpu::TextureFormat format, uint32_t width, uint32_t height, uint32_t mips) noexcept; - -constexpr u32 InvalidTextureFormat = -1; -struct TextureRef { - wgpu::Texture texture; - wgpu::TextureView sampleTextureView; - wgpu::TextureView attachmentTextureView; - wgpu::Extent3D size; - wgpu::TextureFormat format; - uint32_t mipCount; - u32 gxFormat; - bool hasArbitraryMips = false; - bool isReplacement = false; - - TextureRef(wgpu::Texture texture, wgpu::TextureView sampleTextureView, wgpu::TextureView attachmentTextureView, - wgpu::Extent3D size, wgpu::TextureFormat format, uint32_t mipCount, u32 gxFormat) - : texture(std::move(texture)) - , sampleTextureView(std::move(sampleTextureView)) - , attachmentTextureView(std::move(attachmentTextureView)) - , size(size) - , format(format) - , mipCount(mipCount) - , gxFormat(gxFormat) {} -}; - -TextureHandle new_static_texture_2d(uint32_t width, uint32_t height, uint32_t mips, u32 gxFormat, - ArrayRef data, bool tlut, const char* label) noexcept; -TextureHandle new_dynamic_texture_2d(uint32_t width, uint32_t height, uint32_t mips, u32 gxFormat, - const char* label) noexcept; -TextureHandle new_render_texture(uint32_t width, uint32_t height, u32 gxFormat, const char* label) noexcept; -TextureHandle new_conv_texture(uint32_t width, uint32_t height, u32 gxFormat, const char* label) noexcept; -void write_texture(TextureRef& ref, ArrayRef data) noexcept; -}; // namespace aurora::gfx - -struct GXTexObj_ { - u32 mode0 = 0; - u32 mode1 = 0; - u32 image0 = UINT32_MAX; - u32 image3 = 0; - const void* userData = nullptr; - const void* data = nullptr; - u32 mWidth = 0; - u32 mHeight = 0; - u32 mFormat = aurora::gfx::InvalidTextureFormat; - GXTlut tlut = GX_TLUT0; - u32 texObjId = 0; - u32 texDataVersion = 0; - u8 flags = 0; - - static constexpr u32 get_bits(u32 reg, u32 size, u32 shift) noexcept { return (reg >> shift) & ((1u << size) - 1); } - - u32 width() const noexcept { return mWidth != 0 ? mWidth : get_bits(image0, 10, 0) + 1 & 0x3FF; } - u32 height() const noexcept { return mHeight != 0 ? mHeight : get_bits(image0, 10, 10) + 1 & 0x3FF; } - u32 raw_format() const noexcept { return get_bits(image0, 4, 20); } - u32 format() const noexcept { return mFormat != aurora::gfx::InvalidTextureFormat ? mFormat : raw_format(); } - GXTexWrapMode wrap_s() const noexcept { return static_cast(get_bits(mode0, 2, 0)); } - GXTexWrapMode wrap_t() const noexcept { return static_cast(get_bits(mode0, 2, 2)); } - GXTexFilter min_filter() const noexcept { - constexpr GXTexFilter kHwToGxFilter[8] = { - GX_NEAR, GX_NEAR_MIP_NEAR, GX_NEAR_MIP_LIN, GX_NEAR, GX_LINEAR, GX_LIN_MIP_NEAR, GX_LIN_MIP_LIN, GX_NEAR, - }; - return kHwToGxFilter[get_bits(mode0, 3, 5)]; - } - GXTexFilter mag_filter() const noexcept { return get_bits(mode0, 1, 4) != 0 ? GX_LINEAR : GX_NEAR; } - GXBool has_mips() const noexcept { return (flags & 1u) != 0 ? GX_TRUE : GX_FALSE; } - u32 mip_count() const noexcept { - if (!has_mips()) { - return 1; - } - const u32 requested = std::max(static_cast(max_lod()) + 1, 1u); - return std::min(requested, aurora::gfx::max_texture_mip_count(width(), height())); - } - GXBool do_edge_lod() const noexcept { return get_bits(mode0, 1, 8) == 0 ? GX_TRUE : GX_FALSE; } - float lod_bias() const noexcept { return static_cast(static_cast(get_bits(mode0, 8, 9))) / 32.0f; } - GXAnisotropy max_aniso() const noexcept { return static_cast(get_bits(mode0, 2, 19)); } - GXBool bias_clamp() const noexcept { return get_bits(mode0, 1, 21) != 0 ? GX_TRUE : GX_FALSE; } - float min_lod() const noexcept { return static_cast(get_bits(mode1, 8, 0)) / 16.0f; } - float max_lod() const noexcept { return static_cast(get_bits(mode1, 8, 8)) / 16.0f; } - - // Custom flag for texture caching - bool no_cache() const noexcept { return (flags & 0x80) != 0; } - void set_no_cache(bool value) noexcept { flags = value ? flags | 0x80 : flags & ~0x80; } -}; -static_assert(sizeof(GXTexObj_) <= sizeof(GXTexObj), "GXTexObj too small!"); -struct GXTlutObj_ { - u32 tlut = 0; - u32 loadTlut0 = 0; - u16 numEntries = 0; - const void* data = nullptr; - GXTlutFmt format = GX_TL_IA8; - u32 tlutObjId = 0; - u32 tlutDataVersion = 0; - u8 flags = 0; - - // Custom flag for texture caching - bool no_cache() const noexcept { return (flags & 0x80) != 0; } - void set_no_cache(bool value) noexcept { flags = value ? flags | 0x80 : flags & ~0x80; } -}; -static_assert(sizeof(GXTlutObj_) <= sizeof(GXTlutObj), "GXTlutObj too small!"); - -namespace aurora::gfx { -struct TextureBind { - TextureHandle ref; - GXTexObj_ texObj; - - TextureBind() noexcept = default; - TextureBind(const GXTexObj_& obj, TextureHandle handle) noexcept : ref(std::move(handle)), texObj(obj) {} - void reset() noexcept { ref.reset(); } - [[nodiscard]] wgpu::SamplerDescriptor get_descriptor() const noexcept; - operator bool() const noexcept { return ref.operator bool(); } -}; -} // namespace aurora::gfx diff --git a/aurora-main/lib/gfx/texture_convert.cpp b/aurora-main/lib/gfx/texture_convert.cpp deleted file mode 100644 index f61bbeb..0000000 --- a/aurora-main/lib/gfx/texture_convert.cpp +++ /dev/null @@ -1,726 +0,0 @@ -#include "texture_convert.hpp" - -#include "../internal.hpp" -#include "../gx/gx_fmt.hpp" - -#include -#include -#include -#include -#include -#include - -namespace aurora::gfx { -static Module Log("aurora::gfx"); - -struct RGBA8 { - uint8_t r; - uint8_t g; - uint8_t b; - uint8_t a; -}; - -namespace { -constexpr float kArbMipThreshold = 15.0f; - -size_t calc_size_rgba8(uint32_t width, uint32_t height) { - return static_cast(width) * static_cast(height) * sizeof(RGBA8); -} - -size_t calc_offset_rgba8(uint32_t x, uint32_t y, uint32_t width) { - return (static_cast(y) * static_cast(width) + static_cast(x)) * sizeof(RGBA8); -} - -/** - * Downscales RGBA8 data using a simple box filter. - */ -ByteBuffer downscale(const uint8_t* src, uint32_t srcWidth, uint32_t srcHeight, uint32_t dstWidth, uint32_t dstHeight) { - ByteBuffer dst{calc_size_rgba8(dstWidth, dstHeight)}; - auto* dstPixels = dst.data(); - for (uint32_t y = 0; y < dstHeight; ++y) { - const uint32_t srcY0 = std::min(y * 2, srcHeight - 1); - const uint32_t srcY1 = std::min(srcY0 + 1, srcHeight - 1); - for (uint32_t x = 0; x < dstWidth; ++x) { - const uint32_t srcX0 = std::min(x * 2, srcWidth - 1); - const uint32_t srcX1 = std::min(srcX0 + 1, srcWidth - 1); - const size_t sampleOffsets[4] = { - calc_offset_rgba8(srcX0, srcY0, srcWidth), - calc_offset_rgba8(srcX1, srcY0, srcWidth), - calc_offset_rgba8(srcX0, srcY1, srcWidth), - calc_offset_rgba8(srcX1, srcY1, srcWidth), - }; - uint8_t* out = dstPixels + calc_offset_rgba8(x, y, dstWidth); - for (size_t channel = 0; channel < 4; ++channel) { - uint32_t sum = 0; - for (const size_t offset : sampleOffsets) { - sum += src[offset + channel]; - } - out[channel] = static_cast((sum + 2) / 4); - } - } - } - return dst; -} - -float avg_diff(const uint8_t* lhs, const uint8_t* rhs, uint32_t width, uint32_t height) { - double diffSum = 0.0; - const size_t byteCount = calc_size_rgba8(width, height); - for (size_t i = 0; i < byteCount; ++i) { - const int diff = static_cast(lhs[i]) - static_cast(rhs[i]); - diffSum += static_cast(diff * diff); - } - const double sampleCount = static_cast(width) * static_cast(height) * 4.0; - return static_cast(std::sqrt(diffSum / sampleCount) / 2.56); -} - -/** - * Attempts to detect whether the mipmaps of a texture are manually-authored, which is sometimes used for mipmap-based - * distance effects. This is achieved by downscaling the mipmaps using a box filter and comparing the average pixel - * difference between the original and downscaled mipmaps. - */ -bool arb_mip_check(uint32_t width, uint32_t height, uint32_t mips, ArrayRef data) { - if (mips < 2) { - return false; - } - - const uint32_t maxMips = max_texture_mip_count(width, height); - if (mips > maxMips) { - Log.warn("arb_mip_check: mip count {} exceeds the {} levels supported by {}x{}", mips, maxMips, width, height); - return false; - } - - struct MipLevel { - const uint8_t* data; - uint32_t width; - uint32_t height; - }; - std::vector levels; - levels.reserve(mips); - - size_t offset = 0; - for (uint32_t mip = 0; mip < mips; ++mip) { - const size_t mipSize = calc_size_rgba8(width, height); - if (offset > data.size() || mipSize > data.size() - offset) { - Log.warn("arb_mip_check: expected at least {} bytes, got {}", offset + mipSize, data.size()); - return false; - } - levels.push_back({data.data() + offset, width, height}); - offset += mipSize; - width = std::max(width >> 1, 1u); - height = std::max(height >> 1, 1u); - } - - ByteBuffer downscaled; - float totalDiff = 0.0f; - for (uint32_t mip = 0; mip + 1 < mips; ++mip) { - const uint8_t* src = mip == 0 ? levels[mip].data : downscaled.data(); - downscaled = downscale(src, levels[mip].width, levels[mip].height, levels[mip + 1].width, - levels[mip + 1].height); - totalDiff += avg_diff(levels[mip + 1].data, downscaled.data(), levels[mip + 1].width, - levels[mip + 1].height); - } - return (totalDiff / static_cast(mips - 1)) > kArbMipThreshold; -} -} // namespace - -// http://www.mindcontrol.org/~hplus/graphics/expand-bits.html -template -constexpr uint8_t ExpandTo8(uint8_t n) { - if constexpr (v == 3) { - return (n << (8 - 3)) | (n << (8 - 6)) | (n >> (9 - 8)); - } else { - return (n << (8 - v)) | (n >> ((v * 2) - 8)); - } -} - -constexpr uint8_t S3TCBlend(uint32_t a, uint32_t b) { - return static_cast((((a << 1) + a) + ((b << 2) + b)) >> 3); -} - -constexpr uint8_t HalfBlend(uint8_t a, uint8_t b) { - return static_cast((static_cast(a) + static_cast(b)) >> 1); -} - -static size_t ComputeMippedTexelCount(uint32_t w, uint32_t h, uint32_t mips) { - size_t ret = w * h; - for (uint32_t i = mips; i > 1; --i) { - if (w > 1) { - w /= 2; - } - if (h > 1) { - h /= 2; - } - ret += w * h; - } - return ret; -} - -static std::optional RequiredTextureDataSize(u32 format, uint32_t width, uint32_t height, uint32_t mips) { - if (width == 0 || height == 0 || mips == 0) { - return std::nullopt; - } - - uint32_t blockWidth = 1; - uint32_t blockHeight = 1; - uint32_t blockSize = 0; - switch (format) { - DEFAULT_FATAL("RequiredTextureDataSize: unknown texture format {}", format); - case GX_TF_R8_PC: - blockSize = 1; - break; - case GX_TF_RGBA8_PC: - blockSize = 4; - break; - case GX_TF_I4: - case GX_TF_C4: - case GX_TF_CMPR: - blockWidth = 8; - blockHeight = 8; - blockSize = 32; - break; - case GX_TF_I8: - case GX_TF_IA4: - case GX_TF_C8: - case GX_TF_Z8: - blockWidth = 8; - blockHeight = 4; - blockSize = 32; - break; - case GX_TF_IA8: - case GX_TF_RGB565: - case GX_TF_RGB5A3: - case GX_TF_C14X2: - case GX_TF_Z16: - blockWidth = 4; - blockHeight = 4; - blockSize = 32; - break; - case GX_TF_RGBA8: - case GX_TF_Z24X8: - blockWidth = 4; - blockHeight = 4; - blockSize = 64; - break; - } - - size_t total = 0; - for (uint32_t mip = 0; mip < mips; ++mip) { - const size_t widthBlocks = (static_cast(width) + blockWidth - 1) / blockWidth; - const size_t heightBlocks = (static_cast(height) + blockHeight - 1) / blockHeight; - if (widthBlocks > std::numeric_limits::max() / heightBlocks || - widthBlocks * heightBlocks > (std::numeric_limits::max() - total) / blockSize) { - return std::nullopt; - } - total += widthBlocks * heightBlocks * blockSize; - width = std::max(width >> 1, 1u); - height = std::max(height >> 1, 1u); - } - return total; -} - -template -concept TextureDecoder = requires(T) { - typename T::Source; - typename T::Target; - { T::Frac } -> std::convertible_to; - { T::BlockWidth } -> std::convertible_to; - { T::BlockHeight } -> std::convertible_to; - { T::decode_texel(std::declval(), std::declval(), 0u) }; -}; - -template -static ByteBuffer DecodeTiled(uint32_t width, uint32_t height, uint32_t mips, ArrayRef data) { - const size_t texelCount = ComputeMippedTexelCount(width, height, mips); - ByteBuffer buf{texelCount * sizeof(typename T::Target)}; - - uint32_t w = width; - uint32_t h = height; - auto* targetMip = reinterpret_cast(buf.data()); - const auto* in = reinterpret_cast(data.data()); - for (uint32_t mip = 0; mip < mips; ++mip) { - const uint32_t bwidth = (w + (T::BlockWidth - 1)) / T::BlockWidth; - const uint32_t bheight = (h + (T::BlockHeight - 1)) / T::BlockHeight; - for (uint32_t by = 0; by < bheight; ++by) { - const uint32_t baseY = by * T::BlockHeight; - const uint32_t numRows = std::min(h - baseY, T::BlockHeight); - for (uint32_t bx = 0; bx < bwidth; ++bx) { - const uint32_t baseX = bx * T::BlockWidth; - for (uint32_t y = 0; y < numRows; ++y) { - auto* target = targetMip + (baseY + y) * w + baseX; - const auto n = std::min(w - baseX, T::BlockWidth); - for (uint32_t x = 0; x < n; ++x) { - T::decode_texel(target, in, x); - } - in += T::BlockWidth / T::Frac; - } - const uint32_t extraY = T::BlockHeight - numRows; - in += T::BlockWidth * extraY / T::Frac; - } - } - targetMip += w * h; - if (w > 1) { - w /= 2; - } - if (h > 1) { - h /= 2; - } - } - - return buf; -} - -template -static ByteBuffer DecodeLinear(uint32_t width, ArrayRef data) { - ByteBuffer buf{width * sizeof(typename T::Target)}; - auto* target = reinterpret_cast(buf.data()); - const auto* in = reinterpret_cast(data.data()); - for (uint32_t x = 0; x < width; ++x) { - T::decode_texel(target, in, x); - } - return buf; -} - -struct TextureDecoderI4 { - using Source = uint8_t; - using Target = RGBA8; - - static constexpr uint32_t Frac = 2; - static constexpr uint32_t BlockWidth = 8; - static constexpr uint32_t BlockHeight = 8; - - static void decode_texel(Target* target, const Source* in, const uint32_t x) { - const uint8_t intensity = ExpandTo8<4>(in[x / 2] >> (x & 1 ? 0 : 4) & 0xf); - target[x].r = intensity; - target[x].g = intensity; - target[x].b = intensity; - target[x].a = intensity; - } -}; - -struct TextureDecoderI8 { - using Source = uint8_t; - using Target = RGBA8; - - static constexpr uint32_t Frac = 1; - static constexpr uint32_t BlockWidth = 8; - static constexpr uint32_t BlockHeight = 4; - - static void decode_texel(Target* target, const Source* in, const uint32_t x) { - const uint8_t intensity = in[x]; - target[x].r = intensity; - target[x].g = intensity; - target[x].b = intensity; - target[x].a = intensity; - } -}; - -struct TextureDecoderIA4 { - using Source = uint8_t; - using Target = RGBA8; - - static constexpr uint32_t Frac = 1; - static constexpr uint32_t BlockWidth = 8; - static constexpr uint32_t BlockHeight = 4; - - static void decode_texel(Target* target, const Source* in, const uint32_t x) { - const uint8_t intensity = ExpandTo8<4>(in[x] & 0xf); - target[x].r = intensity; - target[x].g = intensity; - target[x].b = intensity; - target[x].a = ExpandTo8<4>(in[x] >> 4); - } -}; - -struct TextureDecoderIA8 { - using Source = uint16_t; - using Target = RGBA8; - - static constexpr uint32_t Frac = 1; - static constexpr uint32_t BlockWidth = 4; - static constexpr uint32_t BlockHeight = 4; - - static void decode_texel(Target* target, const Source* in, const uint32_t x) { - const uint8_t intensity = in[x] >> 8; - target[x].r = intensity; - target[x].g = intensity; - target[x].b = intensity; - target[x].a = in[x] & 0xff; - } -}; - -struct TextureDecoderC4 { - using Source = uint8_t; - using Target = uint16_t; - - static constexpr uint32_t Frac = 2; - static constexpr uint32_t BlockWidth = 8; - static constexpr uint32_t BlockHeight = 8; - - static void decode_texel(Target* target, const Source* in, const uint32_t x) { - target[x] = in[x / 2] >> (x & 1 ? 0 : 4) & 0xf; - } -}; - -struct TextureDecoderC8 { - using Source = uint8_t; - using Target = uint16_t; - - static constexpr uint32_t Frac = 1; - static constexpr uint32_t BlockWidth = 8; - static constexpr uint32_t BlockHeight = 4; - - static void decode_texel(Target* target, const Source* in, const uint32_t x) { target[x] = in[x]; } -}; - -struct TextureDecoderC14X2 { - using Source = uint16_t; - using Target = uint16_t; - - static constexpr uint32_t Frac = 1; - static constexpr uint32_t BlockWidth = 4; - static constexpr uint32_t BlockHeight = 4; - - static void decode_texel(Target* target, const Source* in, const uint32_t x) { target[x] = bswap(in[x]) & 0x3fff; } -}; - -struct TextureDecoderRGB565 { - using Source = uint16_t; - using Target = RGBA8; - - static constexpr uint32_t Frac = 1; - static constexpr uint32_t BlockWidth = 4; - static constexpr uint32_t BlockHeight = 4; - - static void decode_texel(Target* target, const Source* in, const uint32_t x) { - const auto texel = bswap(in[x]); - target[x].r = ExpandTo8<5>(texel >> 11 & 0x1f); - target[x].g = ExpandTo8<6>(texel >> 5 & 0x3f); - target[x].b = ExpandTo8<5>(texel & 0x1f); - target[x].a = 0xff; - } -}; - -struct TextureDecoderRGB5A3 { - using Source = uint16_t; - using Target = RGBA8; - - static constexpr uint32_t Frac = 1; - static constexpr uint32_t BlockWidth = 4; - static constexpr uint32_t BlockHeight = 4; - - static void decode_texel(Target* target, const Source* in, const uint32_t x) { - const auto texel = bswap(in[x]); - if ((texel & 0x8000) != 0) { - target[x].r = ExpandTo8<5>(texel >> 10 & 0x1f); - target[x].g = ExpandTo8<5>(texel >> 5 & 0x1f); - target[x].b = ExpandTo8<5>(texel & 0x1f); - target[x].a = 0xff; - } else { - target[x].r = ExpandTo8<4>(texel >> 8 & 0xf); - target[x].g = ExpandTo8<4>(texel >> 4 & 0xf); - target[x].b = ExpandTo8<4>(texel & 0xf); - target[x].a = ExpandTo8<3>(texel >> 12 & 0x7); - } - } -}; - -static ByteBuffer BuildRGBA8FromGCN(uint32_t width, uint32_t height, uint32_t mips, ArrayRef data) { - const size_t texelCount = ComputeMippedTexelCount(width, height, mips); - ByteBuffer buf{sizeof(RGBA8) * texelCount}; - - uint32_t w = width; - uint32_t h = height; - auto* targetMip = reinterpret_cast(buf.data()); - const uint8_t* in = data.data(); - for (uint32_t mip = 0; mip < mips; ++mip) { - const uint32_t bwidth = (w + 3) / 4; - const uint32_t bheight = (h + 3) / 4; - for (uint32_t by = 0; by < bheight; ++by) { - const uint32_t baseY = by * 4; - for (uint32_t bx = 0; bx < bwidth; ++bx) { - const uint32_t baseX = bx * 4; - for (uint32_t c = 0; c < 2; ++c) { - for (uint32_t y = 0; y < 4; ++y) { - for (size_t x = 0; x < 4; ++x) { - if (baseX + x >= w || baseY + y >= h) { - continue; - } - RGBA8* target = targetMip + (baseY + y) * w + baseX; - if (c != 0) { - target[x].g = in[x * 2]; - target[x].b = in[x * 2 + 1]; - } else { - target[x].a = in[x * 2]; - target[x].r = in[x * 2 + 1]; - } - } - in += 8; - } - } - } - } - targetMip += w * h; - if (w > 1) { - w /= 2; - } - if (h > 1) { - h /= 2; - } - } - - return buf; -} - -static ByteBuffer BuildRGBA8FromCMPR(uint32_t width, uint32_t height, uint32_t mips, ArrayRef data) { - const size_t texelCount = ComputeMippedTexelCount(width, height, mips); - ByteBuffer buf{sizeof(RGBA8) * texelCount}; - - uint32_t h = height; - uint32_t w = width; - uint8_t* dst = buf.data(); - const uint8_t* src = data.data(); - for (uint32_t mip = 0; mip < mips; ++mip) { - for (uint32_t yy = 0; yy < h; yy += 8) { - for (uint32_t xx = 0; xx < w; xx += 8) { - for (uint32_t yb = 0; yb < 8; yb += 4) { - for (uint32_t xb = 0; xb < 8; xb += 4) { - // CMPR difference: Big-endian color1/2 - const uint16_t color1 = bswap(*reinterpret_cast(src)); - const uint16_t color2 = bswap(*reinterpret_cast(src + 2)); - src += 4; - - // Fill in first two colors in color table. - std::array color_table{}; - - color_table[0] = ExpandTo8<5>(static_cast((color1 >> 11) & 0x1F)); - color_table[1] = ExpandTo8<6>(static_cast((color1 >> 5) & 0x3F)); - color_table[2] = ExpandTo8<5>(static_cast(color1 & 0x1F)); - color_table[3] = 0xFF; - - color_table[4] = ExpandTo8<5>(static_cast((color2 >> 11) & 0x1F)); - color_table[5] = ExpandTo8<6>(static_cast((color2 >> 5) & 0x3F)); - color_table[6] = ExpandTo8<5>(static_cast(color2 & 0x1F)); - color_table[7] = 0xFF; - if (color1 > color2) { - // Predict gradients. - color_table[8] = S3TCBlend(color_table[4], color_table[0]); - color_table[9] = S3TCBlend(color_table[5], color_table[1]); - color_table[10] = S3TCBlend(color_table[6], color_table[2]); - color_table[11] = 0xFF; - - color_table[12] = S3TCBlend(color_table[0], color_table[4]); - color_table[13] = S3TCBlend(color_table[1], color_table[5]); - color_table[14] = S3TCBlend(color_table[2], color_table[6]); - color_table[15] = 0xFF; - } else { - color_table[8] = HalfBlend(color_table[0], color_table[4]); - color_table[9] = HalfBlend(color_table[1], color_table[5]); - color_table[10] = HalfBlend(color_table[2], color_table[6]); - color_table[11] = 0xFF; - - // CMPR difference: GX fills with an alpha 0 midway point here. - color_table[12] = color_table[8]; - color_table[13] = color_table[9]; - color_table[14] = color_table[10]; - color_table[15] = 0; - } - - for (uint32_t y = 0; y < 4; ++y) { - uint8_t bits = src[y]; - for (uint32_t x = 0; x < 4; ++x) { - if (xx + xb + x >= w || yy + yb + y >= h) { - continue; - } - uint8_t* dstOffs = dst + ((yy + yb + y) * w + (xx + xb + x)) * 4; - const uint8_t* colorTableOffs = &color_table[static_cast((bits >> 6) & 3) * 4]; - memcpy(dstOffs, colorTableOffs, 4); - bits <<= 2; - } - } - src += 4; - } - } - } - } - dst += w * h * 4; - if (w > 1) { - w /= 2; - } - if (h > 1) { - h /= 2; - } - } - - return buf; -} - -ConvertedTexture convert_texture(u32 format, uint32_t width, uint32_t height, uint32_t mips, ArrayRef data) { - const uint32_t maxMips = max_texture_mip_count(width, height); - const uint32_t safeMips = std::clamp(mips, 1u, maxMips); - if (safeMips != mips) { - Log.warn("convert_texture: clamping mip count {} to {} for {}x{} texture", mips, safeMips, width, height); - mips = safeMips; - } - - const auto requiredDataSize = RequiredTextureDataSize(format, width, height, mips); - if (!requiredDataSize) { - Log.warn("convert_texture: invalid {}x{} texture with {} mip levels", width, height, mips); - return {}; - } - if (*requiredDataSize > data.size()) { - Log.warn("convert_texture: invalid data size {} for {}x{} texture with {} mip levels (expected at least {} bytes)", - data.size(), width, height, mips, *requiredDataSize); - return {}; - } - - ByteBuffer converted; - switch (format) { - DEFAULT_FATAL("convert_texture: unknown texture format {}", format); - case GX_TF_R8_PC: - converted = DecodeLinear(static_cast(ComputeMippedTexelCount(width, height, mips)), - data); - break; - case GX_TF_RGBA8_PC: - return {}; // No conversion - case GX_TF_I4: - converted = DecodeTiled(width, height, mips, data); - break; - case GX_TF_I8: - case GX_TF_Z8: - converted = DecodeTiled(width, height, mips, data); - break; - case GX_TF_IA4: - converted = DecodeTiled(width, height, mips, data); - break; - case GX_TF_IA8: - case GX_TF_Z16: - converted = DecodeTiled(width, height, mips, data); - break; - case GX_TF_C4: - converted = DecodeTiled(width, height, mips, data); - break; - case GX_TF_C8: - converted = DecodeTiled(width, height, mips, data); - break; - case GX_TF_C14X2: - converted = DecodeTiled(width, height, mips, data); - break; - case GX_TF_RGB565: - converted = DecodeTiled(width, height, mips, data); - break; - case GX_TF_RGB5A3: - converted = DecodeTiled(width, height, mips, data); - break; - case GX_TF_RGBA8: - case GX_TF_Z24X8: - converted = BuildRGBA8FromGCN(width, height, mips, data); - break; - case GX_TF_CMPR: - converted = BuildRGBA8FromCMPR(width, height, mips, data); - break; - } - const auto wgpuFormat = to_wgpu(format); - bool hasArbitraryMips = false; - if (wgpuFormat == wgpu::TextureFormat::RGBA8Unorm && mips > 1) { - hasArbitraryMips = arb_mip_check(width, height, mips, converted); - } - return { - .format = wgpuFormat, - .width = width, - .height = height, - .mips = mips, - .data = std::move(converted), - .hasArbitraryMips = hasArbitraryMips, - }; -} - -ConvertedTexture convert_tlut(u32 format, uint32_t width, ArrayRef data) { - const size_t requiredDataSize = static_cast(width) * sizeof(uint16_t); - if (requiredDataSize > data.size()) { - Log.warn("convert_tlut: invalid data size {} for {} entries (expected at least {} bytes)", data.size(), width, - requiredDataSize); - return {}; - } - - ByteBuffer converted; - switch (format) { - DEFAULT_FATAL("convert_tlut: unsupported tlut format {}", format); - case GX_TF_IA8: // GX_TL_IA8 - converted = DecodeLinear(width, data); - break; - case GX_TF_RGB565: // GX_TL_RGB565 - converted = DecodeLinear(width, data); - break; - case GX_TF_RGB5A3: // GX_TL_RGB5A3 - converted = DecodeLinear(width, data); - break; - } - return { - .format = wgpu::TextureFormat::RGBA8Unorm, - .width = width, - .height = 1, - .mips = 1, - .data = std::move(converted), - }; -} - -GXTexFmt tlut_texture_format(GXTlutFmt format) noexcept { - switch (format) { - DEFAULT_FATAL("tlut_texture_format: unsupported tlut format {}", format); - case GX_TL_IA8: - return GX_TF_IA8; - case GX_TL_RGB565: - return GX_TF_RGB565; - case GX_TL_RGB5A3: - return GX_TF_RGB5A3; - } -} - -ConvertedTexture convert_texture_palette(u32 textureFormat, uint32_t width, uint32_t height, uint32_t mips, - ArrayRef textureData, GXTlutFmt tlutFormat, uint16_t tlutEntries, - ArrayRef tlutData) { - const auto indices = convert_texture(textureFormat, width, height, mips, textureData); - if (indices.data.empty()) { - return {}; - } - mips = indices.mips; - const auto palette = convert_tlut(tlut_texture_format(tlutFormat), tlutEntries, tlutData); - if (palette.data.empty()) { - return {}; - } - - ByteBuffer pixels; - pixels.reserve_extra(indices.data.size() / sizeof(u16) * 4); - - const auto* indexData = reinterpret_cast(indices.data.data()); - const uint32_t baseWidth = width; - const uint32_t baseHeight = height; - size_t offset = 0; - for (u32 mip = 0; mip < mips; ++mip) { - const size_t pixelCount = static_cast(width) * height; - for (size_t i = 0; i < pixelCount; ++i) { - const u32 index = indexData[offset + i]; - if (index >= tlutEntries) { - constexpr uint8_t transparent[4] = {0, 0, 0, 0}; - pixels.append(transparent, sizeof(transparent)); - continue; - } - const size_t src = static_cast(index) * 4; - pixels.append(palette.data.data() + src, 4); - } - offset += pixelCount; - width = std::max(width >> 1, 1u); - height = std::max(height >> 1, 1u); - } - - bool hasArbitraryMips = arb_mip_check(baseWidth, baseHeight, mips, pixels); - return { - .format = wgpu::TextureFormat::RGBA8Unorm, - .width = baseWidth, - .height = baseHeight, - .mips = mips, - .data = std::move(pixels), - .hasArbitraryMips = hasArbitraryMips, - }; -} -} // namespace aurora::gfx diff --git a/aurora-main/lib/gfx/texture_convert.hpp b/aurora-main/lib/gfx/texture_convert.hpp deleted file mode 100644 index aff4da8..0000000 --- a/aurora-main/lib/gfx/texture_convert.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include "common.hpp" -#include "texture.hpp" -#include "../webgpu/gpu.hpp" - -namespace aurora::gfx { -static constexpr wgpu::TextureFormat to_wgpu(u32 gxFormat) { - switch (gxFormat) { - case GX_TF_C4: - case GX_TF_C8: - case GX_TF_C14X2: - return wgpu::TextureFormat::R16Sint; - default: - return wgpu::TextureFormat::RGBA8Unorm; - } -} - -struct ConvertedTexture { - wgpu::TextureFormat format; - uint32_t width; - uint32_t height; - uint32_t mips = 1; - ByteBuffer data; - bool hasArbitraryMips = false; -}; - -ConvertedTexture convert_texture(u32 format, uint32_t width, uint32_t height, uint32_t mips, ArrayRef data); -ConvertedTexture convert_texture_palette(u32 textureFormat, uint32_t width, uint32_t height, uint32_t mips, - ArrayRef textureData, GXTlutFmt tlutFormat, uint16_t tlutEntries, - ArrayRef tlutData); -ConvertedTexture convert_tlut(u32 format, uint32_t width, ArrayRef data); -GXTexFmt tlut_texture_format(GXTlutFmt format) noexcept; -} // namespace aurora::gfx diff --git a/aurora-main/lib/gfx/texture_replacement.cpp b/aurora-main/lib/gfx/texture_replacement.cpp deleted file mode 100644 index e8d0fbf..0000000 --- a/aurora-main/lib/gfx/texture_replacement.cpp +++ /dev/null @@ -1,800 +0,0 @@ -#include "texture_replacement.hpp" - -#include "../internal.hpp" -#include "../gx/gx.hpp" -#include "../webgpu/gpu.hpp" -#include "dds_io.hpp" -#include "texture_convert.hpp" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "png_io.hpp" -#include "../fs_helper.hpp" - -using namespace aurora::gx; -using aurora::webgpu::g_device; - -namespace aurora::gfx::texture_replacement { -Module Log("aurora::gfx::texture_replacement"); - -struct RuntimeTextureKey { - uint64_t textureHash = 0; - uint64_t tlutHash = 0; - uint32_t width = 0; - uint32_t height = 0; - bool hasTlut = false; - uint32_t format = 0; - - bool operator==(const RuntimeTextureKey& rhs) const = default; - - template - friend H AbslHashValue(H h, const RuntimeTextureKey& key) { - return H::combine(std::move(h), key.textureHash, key.tlutHash, key.width, key.height, key.hasTlut, key.format); - } -}; - -struct TlutMetadata { - uint32_t size = 0; - uint32_t format = 0; - uint16_t entries = 0; - bool valid = false; - // Object the palette was registered from. GXLoadTlut consumes the registration, so this is what - // lets the same object be loaded into more than one hardware slot. - const GXTlutObj* source = nullptr; - ByteBuffer data; -}; - -struct CachedReplacement { - gfx::TextureHandle handle; - uint64_t bytes = 0; - std::list::iterator lruIt; -}; - -struct ReplacementIndexEntry { - std::filesystem::path path; -}; - -absl::flat_hash_map s_replacementIndex; -absl::flat_hash_map s_replacementCache; -absl::flat_hash_set s_failedKeys; -absl::flat_hash_set s_reportedMisses; -absl::flat_hash_map s_pendingTluts; -std::array s_loadedTluts{}; -std::list s_replacementLru; -std::filesystem::path s_replacementRoot; -std::filesystem::path s_dumpRoot; -uint64_t s_replacementCacheBytes = 0; -constexpr uint64_t kReplacementCacheBudgetBytes = 4294967296; // 4GB, reasonable for modern hardware? -constexpr uint64_t kReplacementWildcardTextureHash = 0xFFFFFFFFFFFFFFFFull; -constexpr uint64_t kReplacementWildcardTlutHash = 0xFFFFFFFFFFFFFFFEull; - -bool iequals_ascii(std::string_view lhs, std::string_view rhs) noexcept { - if (lhs.size() != rhs.size()) { - return false; - } - for (size_t i = 0; i < lhs.size(); ++i) { - if (std::tolower(static_cast(lhs[i])) != std::tolower(static_cast(rhs[i]))) { - return false; - } - } - return true; -} - -bool is_relative_to(const std::filesystem::path& path, const std::filesystem::path& root) noexcept { - if (root.empty()) { - return false; - } - auto pathIt = path.begin(); - auto rootIt = root.begin(); - for (; rootIt != root.end(); ++rootIt, ++pathIt) { - if (pathIt == path.end() || !iequals_ascii(fs_path_to_string(*pathIt), fs_path_to_string(*rootIt))) { - return false; - } - } - return true; -} - -bool is_sidecar_mip(std::string_view stem) noexcept { - constexpr std::string_view tag = "_mip"; - size_t i = stem.size(); - while (i > 0 && stem[i - 1] >= '0' && stem[i - 1] <= '9') { - --i; - } - - if (i == stem.size() || i < tag.size()) { - return false; - } - - return stem.substr(i - tag.size(), tag.size()) == tag; -} - -std::optional parse_hex(std::string_view text) noexcept { - if (text.empty()) { - return std::nullopt; - } - uint64_t value = 0; - for (const char ch : text) { - value <<= 4; - if (ch >= '0' && ch <= '9') { - value |= static_cast(ch - '0'); - } else if (ch >= 'a' && ch <= 'f') { - value |= static_cast(ch - 'a' + 10); - } else if (ch >= 'A' && ch <= 'F') { - value |= static_cast(ch - 'A' + 10); - } else { - return std::nullopt; - } - } - return value; -} - -std::optional parse_u32(std::string_view text, int base = 10) noexcept { - if (text.empty()) { - return std::nullopt; - } - - uint32_t value = 0; - const auto* begin = text.data(); - const auto* end = begin + text.size(); - const auto [ptr, ec] = std::from_chars(begin, end, value, base); - if (ec != std::errc{} || ptr != end) { - return std::nullopt; - } - return value; -} - -std::optional> parse_dimensions(std::string_view text) noexcept { - const size_t sep = text.find('x'); - if (sep == std::string_view::npos) { - return std::nullopt; - } - - const auto width = parse_u32(text.substr(0, sep)); - const auto height = parse_u32(text.substr(sep + 1)); - if (!width.has_value() || !height.has_value()) { - return std::nullopt; - } - return std::pair{*width, *height}; -} - -uint32_t texture_base_level_size(const GXTexObj_& obj) noexcept { - switch (obj.format()) { - case GX_TF_R8_PC: - return obj.width() * obj.height(); - case GX_TF_RGBA8_PC: - return obj.width() * obj.height() * 4; - default: - return GXGetTexBufferSize(obj.width(), obj.height(), obj.format(), false, 0); - } -} - -std::optional compute_referenced_tlut_hash(const GXTexObj_& obj) noexcept { - if (!is_palette_format(obj.format()) || obj.tlut >= s_loadedTluts.size()) { - return std::nullopt; - } - - const auto& tlut = s_loadedTluts[obj.tlut]; - const uint32_t textureSize = texture_base_level_size(obj); - const auto* textureData = static_cast(obj.data); - if (!tlut.valid || textureData == nullptr || textureSize == 0) { - return std::nullopt; - } - - uint32_t minIndex = 0xffff; - uint32_t maxIndex = 0; - switch (obj.format()) { - case GX_TF_C4: - for (uint32_t i = 0; i < textureSize; ++i) { - const uint32_t lowNibble = textureData[i] & 0xf; - const uint32_t highNibble = textureData[i] >> 4; - minIndex = std::min({minIndex, lowNibble, highNibble}); - maxIndex = std::max({maxIndex, lowNibble, highNibble}); - } - break; - case GX_TF_C8: - for (uint32_t i = 0; i < textureSize; ++i) { - const uint32_t index = textureData[i]; - minIndex = std::min(minIndex, index); - maxIndex = std::max(maxIndex, index); - } - break; - case GX_TF_C14X2: - for (uint32_t i = 0; i + sizeof(uint16_t) <= textureSize; i += sizeof(uint16_t)) { - uint16_t value = 0; - std::memcpy(&value, textureData + i, sizeof(value)); - const uint32_t index = bswap(value) & 0x3fff; - minIndex = std::min(minIndex, index); - maxIndex = std::max(maxIndex, index); - } - break; - default: - return std::nullopt; - } - - size_t tlutSize = 2 * (static_cast(maxIndex) + 1 - minIndex); - const size_t tlutOffset = 2 * static_cast(minIndex); - if (tlutOffset + tlutSize > tlut.data.size()) { - return std::nullopt; - } - return XXH64(tlut.data.data() + tlutOffset, tlutSize, 0); -} - -const TlutMetadata* get_loaded_tlut(const GXTexObj_& obj) noexcept { - if (!is_palette_format(obj.format()) || obj.tlut >= s_loadedTluts.size()) { - return nullptr; - } - - const auto& tlut = s_loadedTluts[obj.tlut]; - return tlut.valid ? &tlut : nullptr; -} - -bool ensure_directory(const std::filesystem::path& dir) noexcept { - std::error_code ec; - std::filesystem::create_directories(dir, ec); - return !ec; -} - -RuntimeTextureKey build_runtime_key(const GXTexObj_& obj) noexcept { - RuntimeTextureKey key{ - .width = obj.width(), - .height = obj.height(), - .hasTlut = is_palette_format(obj.format()), - .format = obj.format(), - }; - - const uint32_t textureSize = texture_base_level_size(obj); - if (obj.data != nullptr && textureSize != 0) { - key.textureHash = XXH64(obj.data, textureSize, 0); - } - if (key.hasTlut) { - key.tlutHash = compute_referenced_tlut_hash(obj).value_or(0); - } - return key; -} - -std::string format_replacement_filename(const RuntimeTextureKey& key) { - if (key.hasTlut) { - return fmt::format("tex1_{}x{}_{:016x}_{:016x}_{}.dds", key.width, key.height, - key.textureHash, key.tlutHash, key.format); - } - return fmt::format("tex1_{}x{}_{:016x}_{}.dds", key.width, key.height, key.textureHash, key.format); -} - -std::optional parse_replacement_filename(std::string_view filename) noexcept { - const size_t dot = filename.rfind('.'); - if (dot == std::string_view::npos) { - return std::nullopt; - } - - if (!iequals_ascii(filename.substr(dot), ".dds") && !iequals_ascii(filename.substr(dot), ".png")) { - return std::nullopt; - } - - const std::string_view stem = filename.substr(0, dot); - constexpr std::string_view prefix = "tex1_"; - if (!stem.starts_with(prefix)) { - return std::nullopt; - } - - std::array parts{}; - size_t partCount = 0; - size_t offset = 0; - bool consumedAll = false; - while (offset <= stem.size() && partCount < parts.size()) { - const size_t next = stem.find('_', offset); - parts[partCount++] = stem.substr(offset, next == std::string_view::npos ? stem.size() - offset : next - offset); - if (next == std::string_view::npos) { - consumedAll = true; - break; - } - offset = next + 1; - } - if (!consumedAll || partCount < 4 || partCount > 6 || parts[0] != "tex1") { - return std::nullopt; - } - - const auto dimensions = parse_dimensions(parts[1]); - if (!dimensions.has_value()) { - return std::nullopt; - } - - size_t index = 2; - if (parts[index] == "m") { - ++index; - } - - size_t remaining = partCount - index; - if (remaining != 2 && remaining != 3) { - return std::nullopt; - } - - uint64_t textureHash = 0; - if (parts[index] == "$") { - textureHash = kReplacementWildcardTextureHash; - } else { - const auto parsedTex = parse_hex(parts[index]); - if (!parsedTex.has_value()) { - return std::nullopt; - } - textureHash = *parsedTex; - } - - auto formatPart = parts[partCount - 1]; - if (formatPart == "arb") { - formatPart = parts[partCount - 2]; - remaining -= 1; - } - const auto format = parse_u32(formatPart); - if (!format.has_value()) { - return std::nullopt; - } - - uint64_t tlutHash = 0; - const bool hasTlut = remaining == 3; - if (hasTlut) { - const std::string_view tlutPart = parts[index + 1]; - if (tlutPart == "$") { - tlutHash = kReplacementWildcardTlutHash; - } else { - const auto parsedTlutHash = parse_hex(tlutPart); - if (!parsedTlutHash.has_value()) { - return std::nullopt; - } - tlutHash = *parsedTlutHash; - } - } - - return RuntimeTextureKey{ - .textureHash = textureHash, - .tlutHash = tlutHash, - .width = dimensions->first, - .height = dimensions->second, - .hasTlut = hasTlut, - .format = *format, - }; -} - -static std::optional load_texture_file(const std::filesystem::path& path) { - if (path.extension() == ".png") { - return png::load_png_file(path); - } else { - return dds::load_dds_file(path); - } -} - -constexpr bool isUnsupportedTextureFormat(const ConvertedTexture& texture) { - switch (texture.format) { - case wgpu::TextureFormat::BC1RGBAUnorm: - case wgpu::TextureFormat::BC1RGBAUnormSrgb: - case wgpu::TextureFormat::BC2RGBAUnorm: - case wgpu::TextureFormat::BC2RGBAUnormSrgb: - case wgpu::TextureFormat::BC3RGBAUnorm: - case wgpu::TextureFormat::BC3RGBAUnormSrgb: - case wgpu::TextureFormat::BC4RUnorm: - case wgpu::TextureFormat::BC4RSnorm: - case wgpu::TextureFormat::BC5RGUnorm: - case wgpu::TextureFormat::BC5RGSnorm: - case wgpu::TextureFormat::BC6HRGBUfloat: - case wgpu::TextureFormat::BC6HRGBFloat: - case wgpu::TextureFormat::BC7RGBAUnorm: - case wgpu::TextureFormat::BC7RGBAUnormSrgb: - return !webgpu::g_bcTexturesSupported; - default: - return false; - } -} - -std::optional load_replacement(const ReplacementIndexEntry& entry) noexcept { - auto base = load_texture_file(entry.path); - if (!base.has_value()) { - Log.warn("texture_replacement: failed to load texture {}", fs_path_to_string(entry.path)); - return std::nullopt; - } - if (isUnsupportedTextureFormat(base.value())) { - Log.warn( - "texture_replacement: failed to load texture {} due to unsupported format: {}", - fs_path_to_string(entry.path), - static_cast(base->format)); - return std::nullopt; - } - - std::vector more; - std::error_code ec; - for (uint32_t mipLevel = 1;; ++mipLevel) { - const auto mipPath = entry.path.parent_path() / fmt::format("{}_mip{}{}", fs_path_to_string(entry.path.stem()), mipLevel, fs_path_to_string(entry.path.extension())); - if (!std::filesystem::is_regular_file(mipPath, ec)) { - break; - } - - auto lvl = load_texture_file(mipPath); - const uint32_t ew = std::max(base->width >> mipLevel, 1u); - const uint32_t eh = std::max(base->height >> mipLevel, 1u); - const bool ok = lvl.has_value() && lvl->format == base->format && lvl->width == ew && lvl->height == eh; - if (!ok) { - if (!lvl.has_value()) { - Log.warn("texture_replacement: could not load mip {}", fs_path_to_string(mipPath)); - } else { - Log.warn("texture_replacement: expected {}x{} for mip {}, got {}x{}", ew, eh, fs_path_to_string(mipPath), - lvl->width, lvl->height); - } - - break; - } - more.push_back(std::move(*lvl)); - } - - if (more.empty()) { - return base; - } - - const uint32_t mips = 1u + static_cast(more.size()); - const uint64_t n = calc_texture_size(base->format, base->width, base->height, mips); - if (n == 0) { - return std::nullopt; - } - - ByteBuffer blob{static_cast(n)}; - uint8_t* const dst = blob.data(); - uint64_t o = 0; - const auto append = [&](const ByteBuffer& d) noexcept -> bool { - if (o + d.size() > n) { - return false; - } - std::memcpy(dst + o, d.data(), d.size()); - o += d.size(); - return true; - }; - if (!append(base->data)) { - return std::nullopt; - } - for (const auto& mip : more) { - if (!append(mip.data)) { - return std::nullopt; - } - } - if (o != n) { - return std::nullopt; - } - - return ConvertedTexture{ - .format = base->format, - .width = base->width, - .height = base->height, - .mips = mips, - .data = std::move(blob), - }; -} - -void touch_cached_replacement(decltype(s_replacementCache)::iterator it) noexcept { - if (it->second.lruIt != s_replacementLru.begin()) { - s_replacementLru.splice(s_replacementLru.begin(), s_replacementLru, it->second.lruIt); - it->second.lruIt = s_replacementLru.begin(); - } -} - -void evict_replacement_cache_if_needed() noexcept { - while (s_replacementCacheBytes > kReplacementCacheBudgetBytes && !s_replacementLru.empty()) { - const RuntimeTextureKey key = s_replacementLru.back(); - s_replacementLru.pop_back(); - - const auto it = s_replacementCache.find(key); - if (it == s_replacementCache.end()) { - continue; - } - - const uint64_t entryBytes = it->second.bytes; - s_replacementCache.erase(it); - s_replacementCacheBytes -= std::min(s_replacementCacheBytes, entryBytes); - } -} - -void build_index() noexcept { - if (!g_config.allowTextureReplacements) { - return; - } - - auto userPath = fs_path_from_string(g_config.userPath); - auto cachePath = fs_path_from_string(g_config.cachePath); - - s_replacementRoot = userPath / "texture_replacements"; - s_dumpRoot = cachePath / "texture_dumps"; - - if (!ensure_directory(s_replacementRoot)) { - return; - } - if (g_config.allowTextureDumps && !ensure_directory(s_dumpRoot)) { - return; - } - - std::error_code ec; - for (std::filesystem::recursive_directory_iterator it( - s_replacementRoot, - std::filesystem::directory_options::skip_permission_denied | - std::filesystem::directory_options::follow_directory_symlink, - ec); - it != std::filesystem::recursive_directory_iterator(); it.increment(ec)) { - if (ec) { - break; - } - - if (!it->is_regular_file()) { - continue; - } - - const auto& path = it->path(); - - if (is_relative_to(path, s_dumpRoot)) { - continue; - } - - if (!iequals_ascii(fs_path_to_string(path.extension()), ".dds") && !iequals_ascii(fs_path_to_string(path.extension()), ".png")) { - continue; - } - - if (is_sidecar_mip(fs_path_to_string(path.stem()))) { - continue; - } - - const auto parsed = parse_replacement_filename(fs_path_to_string(path.filename())); - if (!parsed.has_value()) { - continue; - } - - s_replacementIndex.try_emplace(*parsed, ReplacementIndexEntry{path}); - } - - Log.info("Indexed {} texture replacements", s_replacementIndex.size()); -} - -const ReplacementIndexEntry* find_replacement_path(const RuntimeTextureKey& key) noexcept { - if (const auto it = s_replacementIndex.find(key); it != s_replacementIndex.end()) { - return &it->second; - } - - if (key.hasTlut) { - RuntimeTextureKey tlutWildcardKey = key; - tlutWildcardKey.tlutHash = kReplacementWildcardTlutHash; - if (const auto it = s_replacementIndex.find(tlutWildcardKey); it != s_replacementIndex.end()) { - return &it->second; - } - } - - RuntimeTextureKey textureWildcardKey = key; - textureWildcardKey.textureHash = kReplacementWildcardTextureHash; - if (const auto it = s_replacementIndex.find(textureWildcardKey); it != s_replacementIndex.end()) { - return &it->second; - } - - return nullptr; -} - -const gfx::TextureHandle* find_cached_replacement(const RuntimeTextureKey& key) noexcept { - const auto cached = s_replacementCache.find(key); - if (cached == s_replacementCache.end()) { - return nullptr; - } - - touch_cached_replacement(cached); - return &cached->second.handle; -} - -gfx::TextureHandle load_replacement_texture(const RuntimeTextureKey& key, const ReplacementIndexEntry& entry) noexcept { - const auto replacement = load_replacement(entry); - if (!replacement.has_value()) { - s_failedKeys.insert(key); - return {}; - } - - const auto label = fmt::format("TextureReplacement {}", format_replacement_filename(key)); - const wgpu::Extent3D size{ - .width = replacement->width, - .height = replacement->height, - .depthOrArrayLayers = 1, - }; - const wgpu::TextureDescriptor textureDescriptor{ - .label = label.c_str(), - .usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopyDst, - .dimension = wgpu::TextureDimension::e2D, - .size = size, - .format = replacement->format, - .mipLevelCount = replacement->mips, - .sampleCount = 1, - }; - auto texture = g_device.CreateTexture(&textureDescriptor); - const auto viewLabel = fmt::format("{} view", label); - const wgpu::TextureViewDescriptor textureViewDescriptor{ - .label = viewLabel.c_str(), - .format = replacement->format, - .dimension = wgpu::TextureViewDimension::e2D, - .mipLevelCount = replacement->mips, - }; - auto textureView = texture.CreateView(&textureViewDescriptor); - auto handle = std::make_shared(std::move(texture), std::move(textureView), wgpu::TextureView{}, size, - replacement->format, replacement->mips, gfx::InvalidTextureFormat); - handle->isReplacement = true; - gfx::write_texture(*handle, replacement->data); - return handle; -} - -void cache_replacement(const RuntimeTextureKey& key, const gfx::TextureHandle& handle) noexcept { - const uint64_t replacementBytes = - calc_texture_size(handle->format, handle->size.width, handle->size.height, handle->mipCount); - s_replacementLru.push_front(key); - s_replacementCache.emplace( - key, CachedReplacement{.handle = handle, .bytes = replacementBytes, .lruIt = s_replacementLru.begin()}); - s_replacementCacheBytes += replacementBytes; - evict_replacement_cache_if_needed(); -} - -bool dump_editable_texture_dds(const RuntimeTextureKey& key, const GXTexObj_& obj) noexcept { - const ArrayRef texData{static_cast(obj.data), UINT32_MAX}; - const uint32_t texWidth = obj.width(); - const uint32_t texHeight = obj.height(); - - ConvertedTexture pixels; - if (is_palette_format(obj.format())) { - const TlutMetadata* tlut = get_loaded_tlut(obj); - if (tlut == nullptr) { - return false; - } - pixels = - convert_texture_palette(obj.format(), texWidth, texHeight, 1, texData, static_cast(tlut->format), - tlut->entries, {tlut->data.data(), tlut->data.size()}); - } else { - pixels = convert_texture(obj.format(), texWidth, texHeight, 1, texData); - } - - const uint64_t rgbaBytes = calc_texture_size(wgpu::TextureFormat::RGBA8Unorm, texWidth, texHeight, 1); - - if (pixels.data.empty() || pixels.format != wgpu::TextureFormat::RGBA8Unorm || pixels.data.size() != rgbaBytes) { - return false; - } - - const auto path = s_dumpRoot / format_replacement_filename(key); - return dds::write_rgba8_dds(path, texWidth, texHeight, pixels.data); -} - -bool report_missing_key(const RuntimeTextureKey& key, const GXTexObj_& obj) noexcept { - if (!s_reportedMisses.insert(key).second) { - return false; - } - - if (g_config.allowTextureDumps) { - dump_editable_texture_dds(key, obj); - } - return true; -} - -void initialize() noexcept { build_index(); } - -void shutdown() noexcept { - s_replacementIndex.clear(); - s_replacementCache.clear(); - s_failedKeys.clear(); - s_reportedMisses.clear(); - s_pendingTluts.clear(); - for (auto& tlut : s_loadedTluts) { - tlut = {}; - } - s_replacementLru.clear(); - s_replacementCacheBytes = 0; - s_replacementRoot.clear(); - s_dumpRoot.clear(); -} - -// Mirrors of the guest palettes, kept only so find_replacement can hash and the DDS dump decode a -// CI palette. The renderer uploads from the guest pointer, so skip this work when replacement is off. -void register_tlut(const GXTlutObj* obj, const void* data, GXTlutFmt format, uint16_t entries) noexcept { - if (!g_config.allowTextureReplacements) { - return; - } - if (obj == nullptr || data == nullptr) { - return; - } - - // A registration is only consumed by a matching load_tlut, and the map is keyed by a guest address - // the game may free and reuse, so a table this large means stale entries: drop them wholesale. - constexpr size_t kMaxPendingTluts = 4096; - if (s_pendingTluts.size() >= kMaxPendingTluts && !s_pendingTluts.contains(obj)) { - s_pendingTluts.clear(); - } - - const size_t sz = static_cast(entries) * 2; - ByteBuffer buffer{sz}; - std::memcpy(buffer.data(), static_cast(data), sz); - s_pendingTluts[obj] = { - .size = static_cast(entries) * 2, - .format = static_cast(format), - .entries = entries, - .valid = true, - .source = obj, - .data = std::move(buffer), - }; -} - -void load_tlut(const GXTlutObj* obj, uint32_t idx) noexcept { - if (!g_config.allowTextureReplacements) { - return; - } - if (idx >= s_loadedTluts.size()) { - return; - } - - // Consume the pending registration. The map is keyed by a guest object address that can be freed - // or reused at any time, and entries used to live until shutdown. - if (const auto it = s_pendingTluts.find(obj); it != s_pendingTluts.end()) { - s_loadedTluts[idx] = std::move(it->second); - s_pendingTluts.erase(it); - return; - } - - // The same object may legally be loaded into several hardware slots; only the first load finds the - // pending entry, so recover the palette from whichever slot already holds it. - for (const auto& loaded : s_loadedTluts) { - if (!loaded.valid || loaded.source != obj) { - continue; - } - s_loadedTluts[idx] = { - .size = loaded.size, - .format = loaded.format, - .entries = loaded.entries, - .valid = loaded.valid, - .source = loaded.source, - .data = loaded.data.clone(), - }; - return; - } - - s_loadedTluts[idx] = {}; -} - -std::optional find_replacement(const GXTexObj_& obj) noexcept { - ZoneScoped; - - if (!g_config.allowTextureReplacements) { - return std::nullopt; - } - - const RuntimeTextureKey key = build_runtime_key(obj); - const auto* path = find_replacement_path(key); - if (path == nullptr) { - report_missing_key(key, obj); - return std::nullopt; - } - - if (const auto* cached = find_cached_replacement(key); cached != nullptr) { - return *cached; - } - - if (s_failedKeys.contains(key)) { - return std::nullopt; - } - - auto handle = load_replacement_texture(key, *path); - if (!handle) { - return std::nullopt; - } - - cache_replacement(key, handle); - return handle; -} - -std::string build_texture_replacement_name(const GXTexObj_& obj) noexcept { - const RuntimeTextureKey key = build_runtime_key(obj); - return format_replacement_filename(key); -} - -} // namespace aurora::gfx::texture_replacement diff --git a/aurora-main/lib/gfx/texture_replacement.hpp b/aurora-main/lib/gfx/texture_replacement.hpp deleted file mode 100644 index 4b9ee06..0000000 --- a/aurora-main/lib/gfx/texture_replacement.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "texture.hpp" -#include - -namespace aurora::gfx::texture_replacement { -void initialize() noexcept; -void shutdown() noexcept; -void register_tlut(const GXTlutObj* obj, const void* data, GXTlutFmt format, uint16_t entries) noexcept; -void load_tlut(const GXTlutObj* obj, uint32_t idx) noexcept; -std::optional find_replacement(const GXTexObj_& obj) noexcept; -std::string build_texture_replacement_name(const GXTexObj_& obj) noexcept; -} // namespace aurora::gfx::texture_replacement diff --git a/aurora-main/lib/gx/command_processor.cpp b/aurora-main/lib/gx/command_processor.cpp deleted file mode 100644 index d94f26c..0000000 --- a/aurora-main/lib/gx/command_processor.cpp +++ /dev/null @@ -1,2515 +0,0 @@ -#include "command_processor.hpp" - -#include "../gfx/common.hpp" -#include "../dolphin/gx/__gx.h" -#include "../gfx/texture_replacement.hpp" -#include "dolphin/gx/GXAurora.h" -#include "gx.hpp" -#include "gx_fmt.hpp" -#include "pipeline.hpp" -#include "shader_info.hpp" -#include "../internal.hpp" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace aurora::gx::fifo { -static Module Log("aurora::gx::fifo"); - -using IndexBuffer = std::vector; - -static u32 prepare_idx_template(IndexBuffer& buf, GXPrimitive prim, u16 vtxCount) { - size_t writePos = 0; - if (prim == GX_QUADS) { - // GX renders a three-vertex remainder as a triangle. One/two are ignored. - const u32 completeVertices = static_cast(vtxCount) & ~3u; - buf.resize((completeVertices / 4u) * 6u + (vtxCount % 4u == 3u ? 3u : 0u)); - - for (u32 v = 0; v < completeVertices; v += 4) { - const u16 idx0 = v; - const u16 idx1 = static_cast(v + 1); - const u16 idx2 = static_cast(v + 2); - const u16 idx3 = static_cast(v + 3); - buf[writePos++] = idx0; - buf[writePos++] = idx1; - buf[writePos++] = idx2; - buf[writePos++] = idx2; - buf[writePos++] = idx3; - buf[writePos++] = idx0; - } - if (vtxCount % 4u == 3u) { - buf[writePos++] = static_cast(completeVertices); - buf[writePos++] = static_cast(completeVertices + 1u); - buf[writePos++] = static_cast(completeVertices + 2u); - } - } else if (prim == GX_TRIANGLES) { - const u32 completeVertices = (static_cast(vtxCount) / 3u) * 3u; - buf.resize(completeVertices); - for (u32 v = 0; v < completeVertices; ++v) { - buf[writePos++] = v; - } - } else if (prim == GX_TRIANGLEFAN) { - const u32 indexCount = vtxCount < 3 ? 0u : (static_cast(vtxCount) - 2u) * 3u; - buf.resize(indexCount); - for (u32 v = 0; indexCount != 0 && v < vtxCount; ++v) { - if (v < 3) { - buf[writePos++] = v; - continue; - } - buf[writePos++] = 0; - buf[writePos++] = static_cast(v - 1); - buf[writePos++] = v; - } - } else if (prim == GX_TRIANGLESTRIP) { - const u32 indexCount = vtxCount < 3 ? 0u : (static_cast(vtxCount) - 2u) * 3u; - buf.resize(indexCount); - for (u32 v = 0; indexCount != 0 && v < vtxCount; ++v) { - if (v < 3) { - buf[writePos++] = v; - continue; - } - if ((v & 1) == 0) { - buf[writePos++] = static_cast(v - 2); - buf[writePos++] = static_cast(v - 1); - } else { - buf[writePos++] = static_cast(v - 1); - buf[writePos++] = static_cast(v - 2); - } - buf[writePos++] = v; - } - } else if (prim == GX_LINES || prim == GX_LINESTRIP || prim == GX_POINTS) { - buf = {0, 1, 3, 3, 2, 0}; - writePos = 6; - } else - UNLIKELY FATAL("unsupported primitive type {}", static_cast(prim)); - CHECK(writePos == buf.size(), "index template size mismatch ({} != {})", writePos, buf.size()); - return static_cast(writePos); -} - -// Empty/incomplete draws consume FIFO bytes but cannot produce a primitive. -static bool has_complete_primitive(GXPrimitive prim, u16 count) { - if (prim == GX_POINTS) return count >= 1; - if (prim == GX_LINES || prim == GX_LINESTRIP) return count >= 2; - return count >= 3; -} - -// GX FIFO opcodes - use CP_ prefix to avoid clashing with GXCommandList.h macros -static constexpr u8 CP_CMD_NOP = GX_NOP; -static constexpr u8 CP_CMD_LOAD_CP_REG = GX_LOAD_CP_REG; -static constexpr u8 CP_CMD_LOAD_XF_REG = GX_LOAD_XF_REG; -static constexpr u8 CP_CMD_LOAD_INDX_A = GX_LOAD_INDX_A; -static constexpr u8 CP_CMD_LOAD_INDX_B = GX_LOAD_INDX_B; -static constexpr u8 CP_CMD_LOAD_INDX_C = GX_LOAD_INDX_C; -static constexpr u8 CP_CMD_LOAD_INDX_D = GX_LOAD_INDX_D; -static constexpr u8 CP_CMD_CALL_DL = GX_CMD_CALL_DL; -static constexpr u8 CP_CMD_INVAL_VTX = GX_CMD_INVL_VC; -static constexpr u8 CP_CMD_LOAD_BP_REG = GX_LOAD_BP_REG & GX_OPCODE_MASK; - -// Primitive type mask -static constexpr u8 CP_OPCODE_MASK = GX_OPCODE_MASK; -static constexpr u8 CP_VAT_MASK = GX_VAT_MASK; -static constexpr u8 CP_PRIMITIVE_START = 0x80; -static constexpr u8 CP_PRIMITIVE_END = 0xBF; - -// Read helpers for big/little endian -#if _MSC_VER -template -__forceinline // Yes, this was necessary. -inline T unaligned_load(const T* ptr) { - return *static_cast(ptr); -} -#else -template -inline T unaligned_load(const T* ptr) { - T copy; - memcpy(©, ptr, sizeof(T)); - return copy; -} -#endif - -static inline u16 read_u16(const u8* ptr, bool bigEndian) { - const u16 val = unaligned_load(reinterpret_cast(ptr)); - if (bigEndian) { - return bswap(val); - } - return val; -} - -static inline u32 read_u32(const u8* ptr, bool bigEndian) { - const u32 val = unaligned_load(reinterpret_cast(ptr)); - if (bigEndian) { - return bswap(val); - } - return val; -} - -static bool is_draw_cmd(u8 cmd) { - return cmd >= CP_PRIMITIVE_START && cmd <= CP_PRIMITIVE_END; -} - -static GXPrimitive primitive_from_draw_cmd(u8 cmd) { - switch (cmd & CP_OPCODE_MASK) { - case GX_DRAW_QUADS: - case 0x88: - return GX_QUADS; - case GX_DRAW_TRIANGLES: - return GX_TRIANGLES; - case GX_DRAW_TRIANGLE_STRIP: - return GX_TRIANGLESTRIP; - case GX_DRAW_TRIANGLE_FAN: - return GX_TRIANGLEFAN; - case GX_DRAW_LINES: - return GX_LINES; - case GX_DRAW_LINE_STRIP: - return GX_LINESTRIP; - case GX_DRAW_POINTS: - return GX_POINTS; - default: - UNLIKELY FATAL("unsupported primitive command 0x{:02X}", cmd); - } -} - - - - -static u32 bp_get(u32 reg, u32 size, u32 shift); -static inline f32 read_f32(const u8* ptr, bool bigEndian); - -static GXPixelFmt decode_pixel_fmt(u32 peCtrl, u32 cmode1) { - switch (bp_get(peCtrl, 3, 0)) { - case 0: - return GX_PF_RGB8_Z24; - case 1: - return GX_PF_RGBA6_Z24; - case 2: - return GX_PF_RGB565_Z16; - case 3: - return GX_PF_Z24; - case 4: - switch (bp_get(cmode1, 2, 9)) { - case 0: - return GX_PF_Y8; - case 1: - return GX_PF_U8; - case 2: - return GX_PF_V8; - default: - Log.warn("command_processor: unsupported cmode1 pixel subtype {}", bp_get(cmode1, 2, 9)); - return GX_PF_Y8; - } - case 5: - return GX_PF_YUV420; - default: - Log.warn("command_processor: unsupported PE pixel format {}", bp_get(peCtrl, 3, 0)); - return GX_PF_RGB8_Z24; - } -} - -static inline u64 read_u64(const u8* ptr, bool bigEndian) { - u64 loaded; - // Unaligned-safe load - memcpy(&loaded, ptr, sizeof(u64)); - - if (bigEndian) { - return bswap(loaded); - } - - return loaded; -} - -struct TexBpRegMapping { - u8 texMapId; - enum class Kind : uint8_t { Mode0, Mode1, Image0, Image1, Image2, Image3, Tlut } kind; -}; - -static std::optional decode_tex_bp_reg(u32 regId) { - constexpr std::array mode0Ids{0x80u, 0x81u, 0x82u, 0x83u, 0xA0u, 0xA1u, 0xA2u, 0xA3u}; - constexpr std::array mode1Ids{0x84u, 0x85u, 0x86u, 0x87u, 0xA4u, 0xA5u, 0xA6u, 0xA7u}; - constexpr std::array image0Ids{0x88u, 0x89u, 0x8Au, 0x8Bu, 0xA8u, 0xA9u, 0xAAu, 0xABu}; - constexpr std::array image1Ids{0x8Cu, 0x8Du, 0x8Eu, 0x8Fu, 0xACu, 0xADu, 0xAEu, 0xAFu}; - constexpr std::array image2Ids{0x90u, 0x91u, 0x92u, 0x93u, 0xB0u, 0xB1u, 0xB2u, 0xB3u}; - constexpr std::array image3Ids{0x94u, 0x95u, 0x96u, 0x97u, 0xB4u, 0xB5u, 0xB6u, 0xB7u}; - constexpr std::array tlutIds{0x98u, 0x99u, 0x9Au, 0x9Bu, 0xB8u, 0xB9u, 0xBAu, 0xBBu}; - - for (u8 i = 0; i < MaxTextures; ++i) { - if (regId == mode0Ids[i]) { - return TexBpRegMapping{.texMapId = i, .kind = TexBpRegMapping::Kind::Mode0}; - } - if (regId == mode1Ids[i]) { - return TexBpRegMapping{.texMapId = i, .kind = TexBpRegMapping::Kind::Mode1}; - } - if (regId == image0Ids[i]) { - return TexBpRegMapping{.texMapId = i, .kind = TexBpRegMapping::Kind::Image0}; - } - if (regId == image1Ids[i]) { - return TexBpRegMapping{.texMapId = i, .kind = TexBpRegMapping::Kind::Image1}; - } - if (regId == image2Ids[i]) { - return TexBpRegMapping{.texMapId = i, .kind = TexBpRegMapping::Kind::Image2}; - } - if (regId == image3Ids[i]) { - return TexBpRegMapping{.texMapId = i, .kind = TexBpRegMapping::Kind::Image3}; - } - if (regId == tlutIds[i]) { - return TexBpRegMapping{.texMapId = i, .kind = TexBpRegMapping::Kind::Tlut}; - } - } - return std::nullopt; -} - -// Helper to convert packed RGBA8 to Vec4 -static Vec4 unpack_color(u32 packed) { - return { - static_cast(packed >> 24 & 0xFF) / 255.f, - static_cast(packed >> 16 & 0xFF) / 255.f, - static_cast(packed >> 8 & 0xFF) / 255.f, - static_cast(packed & 0xFF) / 255.f, - }; -} - -static inline f32 read_f32(const u8* ptr, bool bigEndian) { - u32 bits = read_u32(ptr, bigEndian); - f32 val; - std::memcpy(&val, &bits, sizeof(val)); - return val; -} - -// Marks draw state dirty *and* invalidates the resolved-pipeline memo. -static inline void mark_pipeline_state_dirty() noexcept { - g_gxState.stateDirty = true; - g_gxState.pipelineStateGeneration = next_gx_state_epoch(); -} - -// Rejects a malformed XF write in release builds. -#define XF_REQUIRE(cond, msg, ...) \ - do { \ - if (!(cond)) UNLIKELY { \ - CHECK(cond, msg, ##__VA_ARGS__); \ - Log.warn(msg, ##__VA_ARGS__); \ - return true; \ - } \ - } while (0) - -static bool copy_xf_data(u32 addr, const u8* data, u32 len, bool bigEndian) { - if (addr < 0x78) { - // Position matrices (0x0000 - 0x0077) - u32 mtxIdx = addr / 12; - u32 startOffset = addr % 12; - // We only support full writes to matrices - XF_REQUIRE(mtxIdx < MaxPnMtx, "XF: PosMtx copy oob; mtxIdx={}", mtxIdx); - XF_REQUIRE(startOffset == 0 && len == 12, "XF: PosMtx sub-copy unsupported: offs={}, len={}", startOffset, len); - auto& mtx = g_gxState.pnMtx[mtxIdx].pos; - f32* flat = reinterpret_cast(&mtx); - for (u32 i = 0; i < len; i++) { - flat[i] = read_f32(data + i * 4, bigEndian); - } - g_gxState.stateDirty = true; - return true; - } else if (addr < 0x0F0) { - // Texture matrices (0x078-0x0EF) - u32 texBase = addr - 0x078; - u32 mtxIdx = texBase / 12; - u32 startOffset = texBase % 12; - XF_REQUIRE(mtxIdx < MaxTexMtx, "XF TexMtx copy oob; mtxIdx={}", mtxIdx); - XF_REQUIRE(startOffset == 0 && (len == 8 || len == 12), "XF TexMtx sub-copy unsupported: offs={}, len={}", - startOffset, len); - - // Determine if 2x4 or 3x4 from count - auto& mtx = g_gxState.texMtxs[mtxIdx]; - f32* flat = reinterpret_cast(&mtx); - for (u32 i = 0; i < len; i++) { - flat[i] = read_f32(data + i * 4, bigEndian); - } - g_gxState.stateDirty = true; - return true; - } else if (addr >= 0x400 && addr < 0x45A) { - // Normal matrices (0x400-0x459) - u32 nrmBase = addr - 0x400; - u32 mtxIdx = nrmBase / 9; - u32 startOffset = nrmBase % 9; - // We only support full writes to matrices - XF_REQUIRE(mtxIdx < MaxPnMtx, "XF: NrmMtx copy oob; mtxIdx={}", mtxIdx); - XF_REQUIRE(startOffset == 0 && len == 9, "XF: NrmMtx sub-copy unsupported: offs={}, len={}", startOffset, len); - auto& mtx = g_gxState.pnMtx[mtxIdx].nrm; - f32* flat = reinterpret_cast(&mtx); - for (u32 i = 0; i < len; i++) { - u32 xfIdx = i; - u32 row = xfIdx / 3; - u32 col = xfIdx % 3; - if (row < 3) { - flat[row * 4 + col] = read_f32(data + i * 4, bigEndian); - } - } - g_gxState.stateDirty = true; - return true; - } else if (addr >= 0x500 && addr < 0x5F0) { - // Post-transform texture matrices (0x500-0x5EF) - u32 ptBase = addr - 0x500; - u32 mtxIdx = ptBase / 12; - u32 startOffset = ptBase % 12; - XF_REQUIRE(mtxIdx < MaxPTTexMtx, "XF: PTTexMtx copy oob; mtxIdx={}", mtxIdx); - XF_REQUIRE(startOffset == 0 && len == 12, "XF: PTTexMtx sub-copy unsupported: offs={}, len={}", startOffset, len); - auto& mtx = g_gxState.ptTexMtxs[mtxIdx]; - f32* flat = reinterpret_cast(&mtx); - for (u32 i = 0; i < len; i++) { - flat[startOffset + i] = read_f32(data + i * 4, bigEndian); - } - g_gxState.stateDirty = true; - return true; - } else if (addr >= 0x600 && addr < 0x680) { - // Lights (0x600-0x67F) - 8 lights, 16 values each - u32 lightBase = addr - 0x600; - u32 lightIdx = lightBase / 0x10; - u32 startOffset = lightBase % 0x10; - XF_REQUIRE(lightIdx < GX::MaxLights, "XF: Light copy oob; lightIdx={}", lightIdx); - XF_REQUIRE(startOffset + len <= 0x10, - "XF: Light copy that crosses across light boundaries unsupported: offs={}, len={}", startOffset, len); - auto& light = g_gxState.lights[lightIdx]; - for (u32 i = 0; i < len; i++) { - u32 field = startOffset + i; - f32 val = read_f32(data + i * 4, bigEndian); - u32 ival = read_u32(data + i * 4, bigEndian); - switch (field) { - case 3: // Color (packed u32) - light.color = unpack_color(ival); - break; - case 4: - light.cosAtt[0] = val; - break; // a0 - case 5: - light.cosAtt[1] = val; - break; // a1 - case 6: - light.cosAtt[2] = val; - break; // a2 - case 7: - light.distAtt[0] = val; - break; // k0 - case 8: - light.distAtt[1] = val; - break; // k1 - case 9: - light.distAtt[2] = val; - break; // k2 - case 10: - light.pos[0] = val; - break; // px - case 11: - light.pos[1] = val; - break; // py - case 12: - light.pos[2] = val; - break; // pz - case 13: - light.dir[0] = val; - break; // nx - case 14: - light.dir[1] = val; - break; // ny - case 15: - light.dir[2] = val; - break; // nz - default: - break; // padding (0-2) - } - } - g_gxState.preparedLightsDirty = true; - g_gxState.stateDirty = true; - return true; - } - return false; -} - -static void apply_xf_viewport() { - const auto& vp = g_gxState.xfViewport; - const f32 sx = vp[0]; - const f32 sy = vp[1]; - const f32 sz = vp[2]; - const f32 ox = vp[3]; - const f32 oy = vp[4]; - const f32 oz = vp[5]; - const f32 width = sx * 2.0f; - const f32 height = -sy * 2.0f; - constexpr f32 z24Scale = 16777216.0f; - - set_logical_viewport({ - .left = ox - 340.0f - width / 2.0f, - .top = oy - 340.0f - height / 2.0f, - .width = width, - .height = height, - .znear = (oz - sz) / z24Scale, - .zfar = oz / z24Scale, - }); -} - -static void apply_xf_projection() { - const auto& raw = g_gxState.xfProjection; - auto& proj = g_gxState.proj; - proj = {}; - proj.m0[0] = raw[0]; - proj.m1[1] = raw[2]; - proj.m2[2] = raw[4]; - proj.m2[3] = raw[5]; - - if (g_gxState.projType == GX_ORTHOGRAPHIC) { - proj.m0[3] = raw[1]; - proj.m1[3] = raw[3]; - proj.m3[3] = 1.0f; - } else { - proj.m0[2] = raw[1]; - proj.m1[2] = raw[3]; - proj.m3[2] = -1.0f; - } - - g_gxState.stateDirty = true; -} - -// Forward declarations for register handlers -static void handle_bp(u32 value, bool bigEndian); -static void handle_cp(u8 addr, u32 value, bool bigEndian); -static void handle_xf(const u8* data, u32& pos, u32 size, bool bigEndian); -static bool handle_draw(u8 cmd, const u8* data, u32& pos, u32 size, bool bigEndian); -static bool handle_aurora(const u8* data, u32& pos, u32 size, bool bigEndian); - -uint32_t process(const u8* data, u32 size, bool bigEndian) { - ZoneScoped; - // Everything decoded here mutates renderer state (GX state, the recorded command lists and the mapped staging buffers), so take the renderer GPU mutex once for the whole drain rather than once per draw command. - std::lock_guard gpuLock(aurora::renderer_gpu_mutex()); - u32 pos = 0; - - while (pos < size) { - const u32 commandStart = pos; - u8 cmd = data[pos++]; - u8 opcode = cmd & CP_OPCODE_MASK; - // Log.warn("Processing opcode {:02x} at pos {} (size {})", opcode, pos - 1, size); - - switch (opcode) { - case CP_CMD_NOP: - continue; - - case CP_CMD_LOAD_BP_REG: { - CHECK(pos + 4 <= size, "BP reg read overrun"); - u32 value = read_u32(data + pos, bigEndian); - pos += 4; - handle_bp(value, bigEndian); - break; - } - - case CP_CMD_LOAD_CP_REG: { - CHECK(pos + 5 <= size, "CP reg read overrun"); - u8 addr = data[pos++]; - u32 value = read_u32(data + pos, bigEndian); - pos += 4; - handle_cp(addr, value, bigEndian); - break; - } - - case CP_CMD_LOAD_XF_REG: { - handle_xf(data, pos, size, bigEndian); - break; - } - - case CP_CMD_LOAD_INDX_A: - case CP_CMD_LOAD_INDX_B: - case CP_CMD_LOAD_INDX_C: - case CP_CMD_LOAD_INDX_D: { - ZoneScopedN("LOAD_INDX"); - CHECK(pos + 4 <= size, "indexed XF read overrun"); - const u32 value = read_u32(data + pos, bigEndian); - pos += 4; - - const u32 arrayType = GX_POS_MTX_ARRAY + ((opcode - CP_CMD_LOAD_INDX_A) / 0x08); - const u32 srcArrayIdx = value >> 16; - const u16 len = static_cast(((value >> 12) & 0x0f) + 1); - const u16 dstAddr = static_cast(value & 0x0fff); - auto const& array = g_gxState.arrays[arrayType]; - const u32 byteOffset = srcArrayIdx * array.stride; - const u32 byteCount = static_cast(len) * 4u; - if (array.data == nullptr || array.stride == 0 || byteOffset + byteCount > array.size) { - static u32 invalidIndexedXfLogCount = 0; - if (invalidIndexedXfLogCount < 16) { - Log.warn("Skipping indexed XF load with invalid source array: array={} idx={} stride={} offset={} bytes={} " - "size={} dst=0x{:04X}", - arrayType, srcArrayIdx, array.stride, byteOffset, byteCount, array.size, dstAddr); - ++invalidIndexedXfLogCount; - } - break; - } - u8* srcData = ((u8*)array.data) + byteOffset; - if (!copy_xf_data(dstAddr, srcData, len, bigEndian)) { -#ifndef NDEBUG - Log.debug("Unimplemented indexed XF load (opcode 0x{:02X}, dstAddr=0x{:04X})", opcode, dstAddr); -#endif - } - break; - } - - case CP_CMD_CALL_DL: { - // Call display list: 8 bytes (address + size) - CHECK(pos + 8 <= size, "call DL read overrun"); - Log.warn("Ignoring nested GX_CMD_CALL_DL"); - pos += 8; - break; - } - - case CP_CMD_INVAL_VTX: { - // GXInvalidateVtxCache tells the GPU that CPU-written indexed vertex arrays must be observed by subsequent draws. - for (int i = GX_VA_POS; i <= GX_VA_TEX7; ++i) { - g_gxState.arrays[i].cachedRange = {}; - } - // A merged draw retains its previous array uploads. Force a new draw so - // handle_draw_unmerged observes the invalidation and uploads fresh data. - // Pipeline configuration itself did not change. - g_gxState.stateDirty = true; - break; - } - - case GX_LOAD_AURORA: { - if (!handle_aurora(data, pos, size, bigEndian)) { - return size; - } - break; - } - - default: - // Draw commands occupy the full 0x80-0xBF range. - if (is_draw_cmd(cmd)) { - try { - if (!handle_draw(cmd, data, pos, size, bigEndian)) return size; - } catch (const gfx::StagingBatchFull&) { - return commandStart; - } - } else { - static u32 unknownLogCount = 0; - if (unknownLogCount < 16) { - // Hex dump surrounding bytes for debugging - u32 dumpStart = (pos > 17) ? pos - 17 : 0; - u32 dumpEnd = (pos + 16 < size) ? pos + 16 : size; - std::string hex; - for (u32 i = dumpStart; i < dumpEnd; i++) { - if (i == pos - 1) - hex += fmt::format("[{:02x}]", data[i]); - else - hex += fmt::format(" {:02x}", data[i]); - } - Log.warn(" hex dump (pos {}-{}):{}", dumpStart, dumpEnd - 1, hex); - Log.warn("command_processor: unknown opcode 0x{:02X} at pos {}", cmd, pos - 1); - ++unknownLogCount; - } - } - break; - } - } - return size; -} - -// Helper to extract bit fields from a 32-bit register -inline static u32 bp_get(u32 reg, u32 size, u32 shift) { return reg >> shift & (1u << size) - 1; } - -static u8 normal_frac_bits(GXCompType type) { - switch (type) { - case GX_U8: - return 7; - case GX_S8: - return 6; - case GX_U16: - return 15; - case GX_S16: - return 14; - default: - return 0; - } -} - -static void refresh_copy_filter_flags() { - bool aa = false; - for (const auto& sample : g_gxState.copyFilterSamplePattern) { - aa |= sample[0] != 6 || sample[1] != 6; - } - g_gxState.copyFilterAa = aa; - - static constexpr std::array DefaultVFilter{0, 0, 21, 22, 21, 0, 0}; - bool vf = false; - for (size_t i = 0; i < DefaultVFilter.size(); ++i) { - vf |= g_gxState.copyFilterVFilter[i] != DefaultVFilter[i]; - } - g_gxState.copyFilterVf = vf; -} - -// BP register handler - decodes BP (RAS/pixel engine) register writes and updates g_gxState -static void handle_bp(u32 value, bool bigEndian) { - u32 regId = (value >> 24) & 0xFF; - // Mask off the register ID from the value for field extraction - // (the regId is stored in bits 24-31, data is in bits 0-23) - - if (regId == 0xFE) { - g_gxState.bpRegCache[regId] = value & 0x00FFFFFF; - return; - } else { - const u32 ssMask = g_gxState.bpRegCache[0xFE]; - // A preceding 0xFE write is rare; the common path only has to prove the mask is already wide open. - if (ssMask != 0x00FFFFFF) UNLIKELY { - g_gxState.bpRegCache[0xFE] = 0x00FFFFFF; - } - const u32 merged = (g_gxState.bpRegCache[regId] & ~ssMask) | (value & ssMask); - value = (regId << 24) | (merged & 0x00FFFFFF); - if (g_gxState.bpRegCache[regId] == value) return; - g_gxState.bpRegCache[regId] = value; - } - // TEV color combiner stages (0xC0, 0xC2, 0xC4, ... 0xDE) - if (regId >= 0xC0 && regId <= 0xDE && (regId & 1) == 0) { - u32 stage = (regId - 0xC0) / 2; - if (stage < MaxTevStages) { - auto& s = g_gxState.tevStages[stage]; - s.colorPass.d = static_cast(bp_get(value, 4, 0)); - s.colorPass.c = static_cast(bp_get(value, 4, 4)); - s.colorPass.b = static_cast(bp_get(value, 4, 8)); - s.colorPass.a = static_cast(bp_get(value, 4, 12)); - s.colorOp.clamp = bp_get(value, 1, 19) != 0; - s.colorOp.outReg = static_cast(bp_get(value, 2, 22)); - if (bp_get(value, 2, 16) == 3) { - // Bias==3 means compare mode: reconstruct GXTevOp enum (8 + 3-bit hw value) - u32 hwOp = bp_get(value, 1, 18) | (bp_get(value, 2, 20) << 1); - s.colorOp.op = static_cast(hwOp + 8); - s.colorOp.bias = GX_TB_ZERO; - s.colorOp.scale = GX_CS_SCALE_1; - } else { - // Normal mode: bit18 is op (0=ADD, 1=SUB), bits16-17 is bias, bits20-21 is scale - s.colorOp.op = static_cast(bp_get(value, 1, 18)); - s.colorOp.bias = static_cast(bp_get(value, 2, 16)); - s.colorOp.scale = static_cast(bp_get(value, 2, 20)); - } - mark_pipeline_state_dirty(); - } - return; - } - - // TEV alpha combiner stages (0xC1, 0xC3, 0xC5, ... 0xDF) - if (regId >= 0xC1 && regId <= 0xDF && (regId & 1) == 1) { - u32 stage = (regId - 0xC1) / 2; - if (stage < MaxTevStages) { - auto& s = g_gxState.tevStages[stage]; - s.tevSwapRas = static_cast(bp_get(value, 2, 0)); - s.tevSwapTex = static_cast(bp_get(value, 2, 2)); - s.alphaPass.d = static_cast(bp_get(value, 3, 4)); - s.alphaPass.c = static_cast(bp_get(value, 3, 7)); - s.alphaPass.b = static_cast(bp_get(value, 3, 10)); - s.alphaPass.a = static_cast(bp_get(value, 3, 13)); - s.alphaOp.clamp = bp_get(value, 1, 19) != 0; - s.alphaOp.outReg = static_cast(bp_get(value, 2, 22)); - if (bp_get(value, 2, 16) == 3) { - u32 hwOp = bp_get(value, 1, 18) | (bp_get(value, 2, 20) << 1); - s.alphaOp.op = static_cast(hwOp + 8); - s.alphaOp.bias = GX_TB_ZERO; - s.alphaOp.scale = GX_CS_SCALE_1; - } else { - s.alphaOp.op = static_cast(bp_get(value, 1, 18)); - s.alphaOp.bias = static_cast(bp_get(value, 2, 16)); - s.alphaOp.scale = static_cast(bp_get(value, 2, 20)); - } - mark_pipeline_state_dirty(); - } - return; - } - - switch (regId) { - // genMode (0x00) - case 0x00: { - g_gxState.numTexGens = bp_get(value, 4, 0); - g_gxState.numChans = bp_get(value, 3, 4); - // genMode owns the same numTexGens/numChans that XF 0x3F/0x09 decode, so the XF cache can no longer vouch for those two slots. - g_gxState.invalidateXfReg(0x3F); - g_gxState.invalidateXfReg(0x09); - g_gxState.numTevStages = bp_get(value, 4, 10) + 1; - u32 hwCull = bp_get(value, 2, 14); - // Swap front/back to match GX convention - switch (hwCull) { - case GX_CULL_FRONT: - g_gxState.cullMode = GX_CULL_BACK; - break; - case GX_CULL_BACK: - g_gxState.cullMode = GX_CULL_FRONT; - break; - default: - g_gxState.cullMode = static_cast(hwCull); - break; - } - g_gxState.numIndStages = bp_get(value, 3, 16); - mark_pipeline_state_dirty(); - break; - } - - // Display copy sample pattern (0x01-0x04), six 4-bit samples per BP reg. - case 0x01: - case 0x02: - case 0x03: - case 0x04: { - const size_t first = static_cast(regId - 0x01) * 6; - for (size_t i = 0; i < 6; ++i) { - const size_t sample = first + i; - g_gxState.copyFilterSamplePattern[sample / 2][sample % 2] = static_cast(bp_get(value, 4, i * 4)); - } - refresh_copy_filter_flags(); - break; - } - - // Indirect texture mask (0x0F). - case 0x0F: - g_gxState.indTexMask = static_cast(value & 0xFF); - g_gxState.stateDirty = true; - break; - - // TEV indirect stages (0x10-0x1F) - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: { - u32 stage = regId - 0x10; - if (stage < MaxTevStages) { - auto& s = g_gxState.tevStages[stage]; - s.indTexStage = static_cast(bp_get(value, 2, 0)); - s.indTexFormat = static_cast(bp_get(value, 2, 2)); - s.indTexBiasSel = static_cast(bp_get(value, 3, 4)); - s.indTexAlphaSel = static_cast(bp_get(value, 2, 7)); - s.indTexMtxId = static_cast(bp_get(value, 4, 9)); - s.indTexWrapS = static_cast(bp_get(value, 3, 13)); - s.indTexWrapT = static_cast(bp_get(value, 3, 16)); - s.indTexUseOrigLOD = bp_get(value, 1, 19) != 0; - s.indTexAddPrev = bp_get(value, 1, 20) != 0; - mark_pipeline_state_dirty(); - } - break; - } - - // Scissor registers (0x20, 0x21) - case 0x20: - case 0x21: { - const u32 scis0 = g_gxState.bpRegCache[0x20]; - const u32 scis1 = g_gxState.bpRegCache[0x21]; - const int32_t tp = static_cast(bp_get(scis0, 11, 0)) - 342; - const int32_t lf = static_cast(bp_get(scis0, 11, 12)) - 342; - const int32_t bm = static_cast(bp_get(scis1, 11, 0)) - 342; - const int32_t rt = static_cast(bp_get(scis1, 11, 12)) - 342; - const int32_t wd = std::max(rt - lf + 1, 0); - const int32_t ht = std::max(bm - tp + 1, 0); - set_logical_scissor({lf, tp, wd, ht}); - break; - } - - // Line/point size (0x22) - case 0x22: { - g_gxState.lineWidth = static_cast(bp_get(value, 8, 0)); - g_gxState.pointSize = static_cast(bp_get(value, 8, 8)); - g_gxState.lineTexOffset = static_cast(bp_get(value, 3, 16)); - g_gxState.pointTexOffset = static_cast(bp_get(value, 3, 19)); - g_gxState.lineHalfAspect = bp_get(value, 1, 22) != 0; - g_gxState.stateDirty = true; - break; - } - - // Indirect texture scale (0x25, 0x26) - case 0x25: { - if (MaxIndStages > 0) { - g_gxState.indStages[0].scaleS = static_cast(bp_get(value, 4, 0)); - g_gxState.indStages[0].scaleT = static_cast(bp_get(value, 4, 4)); - } - if (MaxIndStages > 1) { - g_gxState.indStages[1].scaleS = static_cast(bp_get(value, 4, 8)); - g_gxState.indStages[1].scaleT = static_cast(bp_get(value, 4, 12)); - } - mark_pipeline_state_dirty(); - break; - } - case 0x26: { - if (MaxIndStages > 2) { - g_gxState.indStages[2].scaleS = static_cast(bp_get(value, 4, 0)); - g_gxState.indStages[2].scaleT = static_cast(bp_get(value, 4, 4)); - } - if (MaxIndStages > 3) { - g_gxState.indStages[3].scaleS = static_cast(bp_get(value, 4, 8)); - g_gxState.indStages[3].scaleT = static_cast(bp_get(value, 4, 12)); - } - mark_pipeline_state_dirty(); - break; - } - - // Indirect texture reference (0x27) - case 0x27: { - for (u32 i = 0; i < MaxIndStages; i++) { - g_gxState.indStages[i].texMapId = static_cast(bp_get(value, 3, i * 6)); - g_gxState.indStages[i].texCoordId = static_cast(bp_get(value, 3, i * 6 + 3)); - } - mark_pipeline_state_dirty(); - break; - } - - // TEV order / tref (0x28-0x2F) - 2 stages per register - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: { - u32 idx = regId - 0x28; - u32 stage0 = idx * 2; - u32 stage1 = idx * 2 + 1; - - // Channel ID reverse mapping from hardware to GX - static const GXChannelID r2c[] = {GX_COLOR0A0, GX_COLOR1A1, GX_COLOR0A0, GX_COLOR1A1, - GX_COLOR0A0, GX_ALPHA_BUMP, GX_ALPHA_BUMPN, GX_COLOR_ZERO}; - - if (stage0 < MaxTevStages) { - auto& s = g_gxState.tevStages[stage0]; - s.texMapId = static_cast(bp_get(value, 3, 0)); - s.texCoordId = static_cast(bp_get(value, 3, 3)); - // bit 6 = tex enable - if (!bp_get(value, 1, 6)) { - s.texMapId = GX_TEXMAP_NULL; - } - u32 chanHw = bp_get(value, 3, 7); - s.channelId = (chanHw < 8) ? r2c[chanHw] : GX_COLOR_NULL; - } - if (stage1 < MaxTevStages) { - auto& s = g_gxState.tevStages[stage1]; - s.texMapId = static_cast(bp_get(value, 3, 12)); - s.texCoordId = static_cast(bp_get(value, 3, 15)); - if (!bp_get(value, 1, 18)) { - s.texMapId = GX_TEXMAP_NULL; - } - u32 chanHw = bp_get(value, 3, 19); - s.channelId = (chanHw < 8) ? r2c[chanHw] : GX_COLOR_NULL; - } - mark_pipeline_state_dirty(); - break; - } - - // Z mode (0x40) - case 0x40: { - g_gxState.depthCompare = bp_get(value, 1, 0) != 0; - g_gxState.depthFunc = static_cast(bp_get(value, 3, 1)); - g_gxState.depthUpdate = bp_get(value, 1, 4) != 0; - mark_pipeline_state_dirty(); - break; - } - - // Blend mode / cmode0 (0x41) - case 0x41: { - bool blendEn = bp_get(value, 1, 0) != 0; - bool logicEn = bp_get(value, 1, 1) != 0; - bool dither = bp_get(value, 1, 2) != 0; - g_gxState.colorUpdate = bp_get(value, 1, 3) != 0; - g_gxState.alphaUpdate = bp_get(value, 1, 4) != 0; - g_gxState.blendFacDst = static_cast(bp_get(value, 3, 5)); - g_gxState.blendFacSrc = static_cast(bp_get(value, 3, 8)); - bool subtract = bp_get(value, 1, 11) != 0; - g_gxState.blendOp = static_cast(bp_get(value, 4, 12)); - - if (subtract) { - g_gxState.blendMode = GX_BM_SUBTRACT; - } else if (blendEn) { - g_gxState.blendMode = GX_BM_BLEND; - } else if (logicEn) { - g_gxState.blendMode = GX_BM_LOGIC; - } else { - g_gxState.blendMode = GX_BM_NONE; - } - mark_pipeline_state_dirty(); - break; - } - - // Dst alpha / cmode1 (0x42) - case 0x42: { - u8 alpha = bp_get(value, 8, 0); - bool enabled = bp_get(value, 1, 8) != 0; - g_gxState.dstAlpha = enabled ? alpha : UINT32_MAX; - g_gxState.pixelFmt = decode_pixel_fmt(g_gxState.bpRegCache[0x43], value); - mark_pipeline_state_dirty(); - break; - } - - // PE control (0x43) - pixel format, z format, zcomp location - case 0x43: { - g_gxState.pixelFmt = decode_pixel_fmt(value, g_gxState.bpRegCache[0x42]); - g_gxState.zFmt = static_cast(bp_get(value, 3, 3)); - g_gxState.zCompLocBeforeTex = bp_get(value, 1, 6) != 0; - mark_pipeline_state_dirty(); - break; - } - case 0x44: - g_gxState.fieldMask = value & 0x3u; - break; - - // Bounding box clear/update registers (0x55, 0x56) - case 0x55: - case 0x56: { - const u32 offset = (regId & 2u); - g_gxState.boundingBox[offset] = static_cast(value & 0x3ffu); - g_gxState.boundingBox[offset + 1] = static_cast((value >> 10) & 0x3ffu); - break; - } - case 0x58: - g_gxState.revBits = value & 0x00FFFFFFu; - break; - - // Scissor box offset (0x59) - case 0x59: { - g_gxState.scissorOffsetX = static_cast(((value & 0x3ffu) << 1) - 0x156u); - g_gxState.scissorOffsetY = static_cast(((value & 0xffc00u) >> 9) - 0x156u); - set_logical_scissor(g_gxState.logicalScissor); - break; - } - - // TLUT load address / execute (0x64, 0x65) - case 0x64: - break; - case 0x65: { - const auto idx = bp_get(value, 10, 0); - if (idx < MaxTluts) { - auto& slot = g_gxState.loadedTluts[idx]; - slot.loadTlut0 = g_gxState.bpRegCache[0x64]; - slot.numEntries = static_cast(bp_get(value, 10, 10) + 1); - } - break; - } - case 0x68: - g_gxState.fieldMode = value & 0x1u; - break; - - // Alpha compare (0xF3) - case 0xF3: { - g_gxState.alphaCompare.ref0 = bp_get(value, 8, 0); - g_gxState.alphaCompare.ref1 = bp_get(value, 8, 8); - g_gxState.alphaCompare.comp0 = static_cast(bp_get(value, 3, 16)); - g_gxState.alphaCompare.comp1 = static_cast(bp_get(value, 3, 19)); - g_gxState.alphaCompare.op = static_cast(bp_get(value, 2, 22)); - mark_pipeline_state_dirty(); - break; - } - - // TEV K color/alpha select (0xF6-0xFD) - case 0xF6: - case 0xF7: - case 0xF8: - case 0xF9: - case 0xFA: - case 0xFB: - case 0xFC: - case 0xFD: { - u32 kselIdx = regId - 0xF6; - // Swap table entries (packed into pairs of ksel registers) - if (kselIdx < MaxTevSwap * 2) { - u32 swapIdx = kselIdx / 2; - if (kselIdx & 1) { - g_gxState.tevSwapTable[swapIdx].blue = static_cast(bp_get(value, 2, 0)); - g_gxState.tevSwapTable[swapIdx].alpha = static_cast(bp_get(value, 2, 2)); - } else { - g_gxState.tevSwapTable[swapIdx].red = static_cast(bp_get(value, 2, 0)); - g_gxState.tevSwapTable[swapIdx].green = static_cast(bp_get(value, 2, 2)); - } - } - // K color/alpha selection for 2 stages per register - u32 stage0 = kselIdx * 2; - u32 stage1 = kselIdx * 2 + 1; - if (stage0 < MaxTevStages) { - g_gxState.tevStages[stage0].kcSel = static_cast(bp_get(value, 5, 4)); - g_gxState.tevStages[stage0].kaSel = static_cast(bp_get(value, 5, 9)); - } - if (stage1 < MaxTevStages) { - g_gxState.tevStages[stage1].kcSel = static_cast(bp_get(value, 5, 14)); - g_gxState.tevStages[stage1].kaSel = static_cast(bp_get(value, 5, 19)); - } - mark_pipeline_state_dirty(); - break; - } - - // Fog A/B parameters (0xEE-0xF0) - // FOG0 (0xEE): A parameter - sign(1)|exp(8)|mantissa(11) partial IEEE 754 float - case 0xEE: { - g_gxState.fog.fog0Raw = value; - u32 a_mant = bp_get(value, 11, 0); - u32 a_exp = bp_get(value, 8, 11); - u32 a_sign = bp_get(value, 1, 19); - u32 a_bits = (a_sign << 31) | (a_exp << 23) | (a_mant << 12); - std::memcpy(&g_gxState.fog.aRaw, &a_bits, sizeof(g_gxState.fog.aRaw)); - u32 b_s = g_gxState.fog.fog2Raw & 0x1F; - g_gxState.fog.a = std::ldexp(g_gxState.fog.aRaw, static_cast(b_s)); - g_gxState.stateDirty = true; - break; - } - // FOG1 (0xEF): B mantissa (24-bit) - case 0xEF: { - g_gxState.fog.fog1Raw = value; - g_gxState.fog.bMagnitude = bp_get(value, 24, 0); - u32 b_s = g_gxState.fog.fog2Raw & 0x1F; - float B_mant = static_cast(g_gxState.fog.bMagnitude) / 8388638.0f; - g_gxState.fog.b = std::ldexp(B_mant, static_cast(b_s) - 1); - g_gxState.stateDirty = true; - break; - } - // FOG2 (0xF0): B shift/exponent (5-bit) - case 0xF0: { - g_gxState.fog.fog2Raw = value; - u32 b_s = bp_get(value, 5, 0); - g_gxState.fog.bShift = b_s; - u32 a_mant = bp_get(g_gxState.fog.fog0Raw, 11, 0); - u32 a_exp = bp_get(g_gxState.fog.fog0Raw, 8, 11); - u32 a_sign = bp_get(g_gxState.fog.fog0Raw, 1, 19); - u32 a_bits = (a_sign << 31) | (a_exp << 23) | (a_mant << 12); - std::memcpy(&g_gxState.fog.aRaw, &a_bits, sizeof(g_gxState.fog.aRaw)); - g_gxState.fog.a = std::ldexp(g_gxState.fog.aRaw, static_cast(b_s)); - g_gxState.fog.bMagnitude = bp_get(g_gxState.fog.fog1Raw, 24, 0); - float B_mant = static_cast(g_gxState.fog.bMagnitude) / 8388638.0f; - g_gxState.fog.b = std::ldexp(B_mant, static_cast(b_s) - 1); - g_gxState.stateDirty = true; - break; - } - - // Fog type + C parameter from FOG3 (0xF1) - case 0xF1: { - const u32 fogFunc = bp_get(value, 3, 21); - const u32 fogProj = bp_get(value, 1, 20); - GXFogType fogType = static_cast(fogFunc | (fogProj << 3)); - g_gxState.fog.type = fogType; - // Decode C parameter (same partial float encoding as A) - u32 c_mant = bp_get(value, 11, 0); - u32 c_exp = bp_get(value, 8, 11); - u32 c_sign = bp_get(value, 1, 19); - u32 c_bits = (c_sign << 31) | (c_exp << 23) | (c_mant << 12); - std::memcpy(&g_gxState.fog.c, &c_bits, sizeof(g_gxState.fog.c)); - mark_pipeline_state_dirty(); - break; - } - - // Fog color from FOGCLR (0xF2) - case 0xF2: { - u8 b = bp_get(value, 8, 0); - u8 g = bp_get(value, 8, 8); - u8 r = bp_get(value, 8, 16); - g_gxState.fog.color = { - static_cast(r) / 255.f, - static_cast(g) / 255.f, - static_cast(b) / 255.f, - 1.f, - }; - g_gxState.stateDirty = true; - break; - } - - // TEV and K color registers (0xE0-0xE7): even are RA, odd are BG. - // Bit 23 selects a K color register over a TEV color register. - case 0xE0: - case 0xE1: - case 0xE2: - case 0xE3: - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: { - u32 idx = (regId - 0xE0) / 2; - bool isRA = (regId & 1) == 0; - bool isKColor = bp_get(value, 1, 23) != 0; - - if (isKColor) { - // K color register (8-bit components) - if (idx < GX_MAX_KCOLOR) { - auto& kc = g_gxState.kcolors[idx]; - if (isRA) { - kc[0] = static_cast(bp_get(value, 8, 0)) / 255.f; // R - kc[3] = static_cast(bp_get(value, 8, 12)) / 255.f; // A - } else { - kc[2] = static_cast(bp_get(value, 8, 0)) / 255.f; // B - kc[1] = static_cast(bp_get(value, 8, 12)) / 255.f; // G - } - g_gxState.stateDirty = true; - } - } else { - // TEV color register (11-bit signed components) - if (idx < MaxTevRegs) { - auto& cr = g_gxState.colorRegs[idx]; - if (isRA) { - // 11-bit signed: sign-extend from 11 bits - s32 r = bp_get(value, 11, 0); - if (r & 0x400) - r |= ~0x7FF; // sign extend - s32 a = bp_get(value, 11, 12); - if (a & 0x400) - a |= ~0x7FF; - cr[0] = static_cast(r) / 255.f; - cr[3] = static_cast(a) / 255.f; - } else { - s32 b = bp_get(value, 11, 0); - if (b & 0x400) - b |= ~0x7FF; - s32 g = bp_get(value, 11, 12); - if (g & 0x400) - g |= ~0x7FF; - cr[2] = static_cast(b) / 255.f; - cr[1] = static_cast(g) / 255.f; - } - g_gxState.stateDirty = true; - } - } - break; - } - - // Indirect texture matrices (0x06-0x0E), three consecutive registers per 3x2 matrix: - // matrix 0 at 0x06, matrix 1 at 0x09, matrix 2 at 0x0C. - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: { - u32 idx = (regId - 0x06) / 3; // matrix index (0-2) - u32 column = (regId - 0x06) % 3; // column index (0-2) - auto& info = g_gxState.indTexMtxs[idx]; - - // Decode one packed matrix column: [m[0][column], m[1][column]]. - s32 col0 = bp_get(value, 11, 0); - if (col0 & 0x400) - col0 |= ~0x7FF; // sign-extend from 11 bits - s32 col1 = bp_get(value, 11, 11); - if (col1 & 0x400) - col1 |= ~0x7FF; - - auto& packedColumn = column == 0 ? info.mtx.m0 : (column == 1 ? info.mtx.m1 : info.mtx.m2); - packedColumn.x = static_cast(col0) / 1024.0f; - packedColumn.y = static_cast(col1) / 1024.0f; - - // Accumulate the indirect matrix scale exponent. The SDK writes two bits per column, but the - // hardware ignores the third column's top bit, leaving 5 bits for adjScale = scaleExp + 17. - u32 scaleBits = bp_get(value, 2, 22); - u32 shift = column * 2; - if (column == 2) { - info.adjScaleRaw = (info.adjScaleRaw & ~(1u << shift)) | ((scaleBits & 1u) << shift); - } else { - info.adjScaleRaw = (info.adjScaleRaw & ~(3u << shift)) | (scaleBits << shift); - } - info.scaleExp = static_cast(info.adjScaleRaw) - 17; - - g_gxState.stateDirty = true; - break; - } - - // SU texture coordinate scale registers (0x30-0x3F): even (suTs0) carry S-axis scale, bias, cyl - // wrap and line/point offset; odd (suTs1) carry the T-axis equivalents. - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: { - u32 coordIdx = (regId - 0x30) / 2; - bool isT = (regId & 1) != 0; - auto& tcs = g_gxState.texCoordScales[coordIdx]; - if (isT) { - tcs.scaleT = static_cast(bp_get(value, 16, 0)); - tcs.biasT = bp_get(value, 1, 16) != 0; - tcs.cylWrapT = bp_get(value, 1, 17) != 0; - } else { - tcs.scaleS = static_cast(bp_get(value, 16, 0)); - tcs.biasS = bp_get(value, 1, 16) != 0; - tcs.cylWrapS = bp_get(value, 1, 17) != 0; - tcs.lineOffset = bp_get(value, 1, 18) != 0; - tcs.pointOffset = bp_get(value, 1, 19) != 0; - } - g_gxState.stateDirty = true; - break; - } - - // Copy clear color (0x4F-0x50) and depth (0x51) - case 0x49: { - g_gxState.dispCopySrc.x = static_cast(bp_get(value, 10, 0)); - g_gxState.dispCopySrc.y = static_cast(bp_get(value, 10, 10)); - break; - } - case 0x4A: { - g_gxState.dispCopySrc.width = static_cast(bp_get(value, 10, 0) + 1u); - g_gxState.dispCopySrc.height = static_cast(bp_get(value, 10, 10) + 1u); - break; - } - case 0x4D: { - g_gxState.dispCopyDstWidth = static_cast(((bp_get(value, 10, 0) << 5) + 31u) >> 1); - break; - } - case 0x4E: { - const u32 iScale = bp_get(value, 9, 0); - if (iScale != 0) { - g_gxState.dispCopyYScale = 256.f / static_cast(iScale); - } - break; - } - case 0x4F: { - u8 r = bp_get(value, 8, 0); - u8 a = bp_get(value, 8, 8); - g_gxState.clearColor[0] = static_cast(r) / 255.f; - g_gxState.clearColor[3] = static_cast(a) / 255.f; - g_gxState.stateDirty = true; - break; - } - case 0x50: { - u8 b = bp_get(value, 8, 0); - u8 g = bp_get(value, 8, 8); - g_gxState.clearColor[2] = static_cast(b) / 255.f; - g_gxState.clearColor[1] = static_cast(g) / 255.f; - g_gxState.stateDirty = true; - break; - } - case 0x51: { - g_gxState.clearDepth = bp_get(value, 24, 0); - g_gxState.stateDirty = true; - break; - } - case 0xF4: { - g_gxState.zTextureBias = value & 0x00FFFFFFu; - mark_pipeline_state_dirty(); - break; - } - case 0xF5: { - g_gxState.zTextureFmt = static_cast(bp_get(value, 2, 0)); - g_gxState.zTextureOp = static_cast(bp_get(value, 2, 2)); - mark_pipeline_state_dirty(); - break; - } - case 0x52: { - g_gxState.copyClamp = static_cast(bp_get(value, 2, 0)); - g_gxState.texCopyFmt = static_cast(bp_get(value, 4, 3)); - g_gxState.dispCopyGamma = static_cast(bp_get(value, 2, 7)); - g_gxState.texCopyHalfScale = bp_get(value, 1, 9) != 0; - g_gxState.dispCopyFrame2Field = bp_get(value, 2, 12); - break; - } - case 0x53: { - g_gxState.copyFilterVFilter[0] = static_cast(bp_get(value, 6, 0)); - g_gxState.copyFilterVFilter[1] = static_cast(bp_get(value, 6, 6)); - g_gxState.copyFilterVFilter[2] = static_cast(bp_get(value, 6, 12)); - g_gxState.copyFilterVFilter[3] = static_cast(bp_get(value, 6, 18)); - refresh_copy_filter_flags(); - break; - } - case 0x54: { - g_gxState.copyFilterVFilter[4] = static_cast(bp_get(value, 6, 0)); - g_gxState.copyFilterVFilter[5] = static_cast(bp_get(value, 6, 6)); - g_gxState.copyFilterVFilter[6] = static_cast(bp_get(value, 6, 12)); - refresh_copy_filter_flags(); - break; - } - case 0xE8: - case 0xE9: - case 0xEA: - case 0xEB: - case 0xEC: - case 0xED: - g_gxState.fogRange[regId - 0xE8] = value & 0x00FFFFFFu; - mark_pipeline_state_dirty(); - break; - - default: - if (const auto mapping = decode_tex_bp_reg(regId); mapping.has_value()) { - auto& slot = g_gxState.loadedTextures[mapping->texMapId]; - bool changed = false; - switch (mapping->kind) { - case TexBpRegMapping::Kind::Mode0: - changed = slot.mode0 != value; - if (changed) { - slot.mode0 = value; - } - break; - case TexBpRegMapping::Kind::Mode1: - changed = slot.mode1 != value; - if (changed) { - slot.mode1 = value; - } - break; - case TexBpRegMapping::Kind::Image0: - changed = slot.image0 != value; - if (changed) { - slot.image0 = value; - slot.mWidth = 0; - slot.mHeight = 0; - slot.mFormat = gfx::InvalidTextureFormat; - } - break; - case TexBpRegMapping::Kind::Image3: - changed = slot.image3 != value; - if (changed) { - slot.image3 = value; - } - break; - case TexBpRegMapping::Kind::Tlut: - // TLUT region's TMEM offset - break; - case TexBpRegMapping::Kind::Image1: - case TexBpRegMapping::Kind::Image2: - // GXTexRegion regs - break; - } - if (changed) { - g_gxState.stateDirty = true; - } - } else { -#ifndef NDEBUG - Log.debug("Unhandled BP register 0x{:02X} (value 0x{:06X})", regId, value & 0xFFFFFF); -#endif - } - break; - } -} - -extern "C" void GXApplyBPReg(u8 reg, u32 value) { - handle_bp((static_cast(reg) << 24) | (value & 0x00FFFFFFu), true); -} - -static bool cacheable_cp_register(u8 addr) { - return addr == 0x30 || addr == 0x40 || addr == 0x50 || addr == 0x60 || (addr >= 0x70 && addr <= 0x97); -} - -static std::array s_cpRegisterCache{}; -static std::array s_cpRegisterCacheValid{}; - -void reset_cp_register_cache() { - s_cpRegisterCache.fill(0); - s_cpRegisterCacheValid.fill(false); -} - -static bool cp_register_write_unchanged(u8 addr, u32 value) { - if (!cacheable_cp_register(addr)) return false; - - if (s_cpRegisterCacheValid[addr] && s_cpRegisterCache[addr] == value) { - return true; - } - s_cpRegisterCacheValid[addr] = true; - s_cpRegisterCache[addr] = value; - return false; -} - -// CP register handler - decodes CP register writes and updates g_gxState -static void handle_cp(u8 addr, u32 value, bool bigEndian) { - if (cp_register_write_unchanged(addr, value)) return; - - switch (addr) { - // VCD low (0x50) - case 0x50: { - auto& vd = g_gxState.vtxDesc; - auto& svd = g_gxState.sourceVtxDesc; - vd[GX_VA_PNMTXIDX] = static_cast(bp_get(value, 1, 0)); - vd[GX_VA_TEX0MTXIDX] = static_cast(bp_get(value, 1, 1)); - vd[GX_VA_TEX1MTXIDX] = static_cast(bp_get(value, 1, 2)); - vd[GX_VA_TEX2MTXIDX] = static_cast(bp_get(value, 1, 3)); - vd[GX_VA_TEX3MTXIDX] = static_cast(bp_get(value, 1, 4)); - vd[GX_VA_TEX4MTXIDX] = static_cast(bp_get(value, 1, 5)); - vd[GX_VA_TEX5MTXIDX] = static_cast(bp_get(value, 1, 6)); - vd[GX_VA_TEX6MTXIDX] = static_cast(bp_get(value, 1, 7)); - vd[GX_VA_TEX7MTXIDX] = static_cast(bp_get(value, 1, 8)); - vd[GX_VA_POS] = static_cast(bp_get(value, 2, 9)); - vd[GX_VA_NRM] = static_cast(bp_get(value, 2, 11)); - vd[GX_VA_CLR0] = static_cast(bp_get(value, 2, 13)); - vd[GX_VA_CLR1] = static_cast(bp_get(value, 2, 15)); - for (int attr = GX_VA_PNMTXIDX; attr <= GX_VA_CLR1; ++attr) { - svd[attr] = vd[attr]; - } - mark_pipeline_state_dirty(); - g_gxState.clearVtxSizeCache(); - break; - } - - // VCD high (0x60) - case 0x60: { - auto& vd = g_gxState.vtxDesc; - auto& svd = g_gxState.sourceVtxDesc; - vd[GX_VA_TEX0] = static_cast(bp_get(value, 2, 0)); - vd[GX_VA_TEX1] = static_cast(bp_get(value, 2, 2)); - vd[GX_VA_TEX2] = static_cast(bp_get(value, 2, 4)); - vd[GX_VA_TEX3] = static_cast(bp_get(value, 2, 6)); - vd[GX_VA_TEX4] = static_cast(bp_get(value, 2, 8)); - vd[GX_VA_TEX5] = static_cast(bp_get(value, 2, 10)); - vd[GX_VA_TEX6] = static_cast(bp_get(value, 2, 12)); - vd[GX_VA_TEX7] = static_cast(bp_get(value, 2, 14)); - for (int attr = GX_VA_TEX0; attr <= GX_VA_TEX7; ++attr) { - svd[attr] = vd[attr]; - } - mark_pipeline_state_dirty(); - g_gxState.clearVtxSizeCache(); - break; - } - - // Matrix index A (0x30) - case 0x30: { - g_gxState.currentPnMtx = bp_get(value, 6, 0) / 3; - for (u32 i = 0; i < 4 && i < MaxTexCoord; i++) { - auto texMtx = static_cast(bp_get(value, 6, 6 + i * 6)); - assert(texMtx >= 0 && texMtx <= GXTexMtx::GX_IDENTITY); - g_gxState.tcgs[i].mtx = texMtx; - } - // Same matrix indices as XF 0x18, written from a different bank. - g_gxState.invalidateXfReg(0x18); - mark_pipeline_state_dirty(); - break; - } - - // Matrix index B (0x40) - case 0x40: { - for (u32 i = 0; i < 4 && (i + 4) < MaxTexCoord; i++) { - auto texMtx = static_cast(bp_get(value, 6, i * 6)); - assert(texMtx >= 0 && texMtx <= GXTexMtx::GX_IDENTITY); - g_gxState.tcgs[i + 4].mtx = texMtx; - } - // Same matrix indices as XF 0x19, written from a different bank. - g_gxState.invalidateXfReg(0x19); - mark_pipeline_state_dirty(); - break; - } - - default: - // VAT A registers (0x70-0x77) - if (addr >= 0x70 && addr <= 0x77) { - u32 fmt = addr - 0x70; - auto& vf = g_gxState.vtxFmts[fmt]; - vf.attrs[GX_VA_POS].cnt = static_cast(bp_get(value, 1, 0)); - vf.attrs[GX_VA_POS].type = static_cast(bp_get(value, 3, 1)); - vf.attrs[GX_VA_POS].frac = static_cast(bp_get(value, 5, 4)); - vf.attrs[GX_VA_NRM].type = static_cast(bp_get(value, 3, 10)); - if (bp_get(value, 1, 31) != 0) { - vf.attrs[GX_VA_NRM].cnt = GX_NRM_NBT3; - } else { - vf.attrs[GX_VA_NRM].cnt = bp_get(value, 1, 9) != 0 ? GX_NRM_NBT : GX_NRM_XYZ; - } - vf.attrs[GX_VA_NRM].frac = normal_frac_bits(vf.attrs[GX_VA_NRM].type); - vf.attrs[GX_VA_CLR0].cnt = static_cast(bp_get(value, 1, 13)); - vf.attrs[GX_VA_CLR0].type = static_cast(bp_get(value, 3, 14)); - vf.attrs[GX_VA_CLR0].frac = 0; - vf.attrs[GX_VA_CLR1].cnt = static_cast(bp_get(value, 1, 17)); - vf.attrs[GX_VA_CLR1].type = static_cast(bp_get(value, 3, 18)); - vf.attrs[GX_VA_CLR1].frac = 0; - vf.attrs[GX_VA_TEX0].cnt = static_cast(bp_get(value, 1, 21)); - vf.attrs[GX_VA_TEX0].type = static_cast(bp_get(value, 3, 22)); - vf.attrs[GX_VA_TEX0].frac = static_cast(bp_get(value, 5, 25)); - mark_pipeline_state_dirty(); - g_gxState.clearVtxSizeCache(); - } - // VAT B registers (0x80-0x87) - else if (addr >= 0x80 && addr <= 0x87) { - u32 fmt = addr - 0x80; - auto& vf = g_gxState.vtxFmts[fmt]; - vf.attrs[GX_VA_TEX1].cnt = static_cast(bp_get(value, 1, 0)); - vf.attrs[GX_VA_TEX1].type = static_cast(bp_get(value, 3, 1)); - vf.attrs[GX_VA_TEX1].frac = static_cast(bp_get(value, 5, 4)); - vf.attrs[GX_VA_TEX2].cnt = static_cast(bp_get(value, 1, 9)); - vf.attrs[GX_VA_TEX2].type = static_cast(bp_get(value, 3, 10)); - vf.attrs[GX_VA_TEX2].frac = static_cast(bp_get(value, 5, 13)); - vf.attrs[GX_VA_TEX3].cnt = static_cast(bp_get(value, 1, 18)); - vf.attrs[GX_VA_TEX3].type = static_cast(bp_get(value, 3, 19)); - vf.attrs[GX_VA_TEX3].frac = static_cast(bp_get(value, 5, 22)); - vf.attrs[GX_VA_TEX4].cnt = static_cast(bp_get(value, 1, 27)); - vf.attrs[GX_VA_TEX4].type = static_cast(bp_get(value, 3, 28)); - // TEX4 frac is in VAT C - mark_pipeline_state_dirty(); - g_gxState.clearVtxSizeCache(); - } - // VAT C registers (0x90-0x97) - else if (addr >= 0x90 && addr <= 0x97) { - u32 fmt = addr - 0x90; - auto& vf = g_gxState.vtxFmts[fmt]; - vf.attrs[GX_VA_TEX4].frac = static_cast(bp_get(value, 5, 0)); - vf.attrs[GX_VA_TEX5].cnt = static_cast(bp_get(value, 1, 5)); - vf.attrs[GX_VA_TEX5].type = static_cast(bp_get(value, 3, 6)); - vf.attrs[GX_VA_TEX5].frac = static_cast(bp_get(value, 5, 9)); - vf.attrs[GX_VA_TEX6].cnt = static_cast(bp_get(value, 1, 14)); - vf.attrs[GX_VA_TEX6].type = static_cast(bp_get(value, 3, 15)); - vf.attrs[GX_VA_TEX6].frac = static_cast(bp_get(value, 5, 18)); - vf.attrs[GX_VA_TEX7].cnt = static_cast(bp_get(value, 1, 23)); - vf.attrs[GX_VA_TEX7].type = static_cast(bp_get(value, 3, 24)); - vf.attrs[GX_VA_TEX7].frac = static_cast(bp_get(value, 5, 27)); - mark_pipeline_state_dirty(); - g_gxState.clearVtxSizeCache(); - } - // Array base addresses (0xA0-0xAF) - else if (addr >= 0xA0 && addr <= 0xAF) { - Log.error("CP_REG_ARRAYBASE_ID is not supported on Aurora. Use GX_LOAD_AURORA_ARRAYBASE instead."); - } - // Array strides (0xB0-0xBF) - else if (addr >= 0xB0 && addr <= 0xBF) { - u32 attrIdx = addr - 0xB0 + GX_VA_POS; - if (attrIdx < GX_VA_MAX_ATTR) { - auto& array = g_gxState.arrays[attrIdx]; - const auto newStride = static_cast(value); - if (array.stride != newStride) { - array.stride = newStride; - mark_pipeline_state_dirty(); - } - } - } - break; - } -} - -// XF register handler - decodes XF (transform unit) register writes and updates g_gxState -static void handle_xf(const u8* data, u32& pos, u32 size, bool bigEndian) { - // These bounds must hold in release too: CHECK() is a no-op under NDEBUG, so relying on it alone let a truncated guest display list read past `data`. - if (pos > size || size - pos < 4) UNLIKELY { - CHECK(false, "XF header read overrun"); - pos = size; - return; - } - u32 header = read_u32(data + pos, bigEndian); - pos += 4; - - u32 count = ((header >> 16) & 0xFFFF) + 1; - u32 addr = header & 0xFFFF; - u32 dataBytes = count * 4; - // Log.warn(" xf: addr {:04x} count {} dataBytes {} pos {} -> {}", addr, count, dataBytes, pos, pos + dataBytes); - if (size - pos < dataBytes) UNLIKELY { - CHECK(false, "XF data read overrun: need {} bytes at pos {}", dataBytes, pos); - pos = size; - return; - } - - const u8* xfData = data + pos; - - if (copy_xf_data(addr, xfData, count, bigEndian)) { - // copy_xf_data handled everything. - } else if (addr >= 0x1000) { - // XF registers (0x1000+) - u32 xfAddr = addr - 0x1000; - bool viewportUpdated = false; - bool projectionUpdated = false; - for (u32 i = 0; i < count; i++) { - u32 reg = xfAddr + i; - u32 val = read_u32(xfData + i * 4, bigEndian); - - // Skip register writes that decode to state we already hold. - const bool cacheable = reg < g_gxState.xfRegCache.size(); - const bool unchanged = cacheable && g_gxState.xfRegMatches(reg, val); - if (cacheable) g_gxState.storeXfReg(reg, val); - // Viewport (0x1A-0x1F) and projection (0x20-0x26) keep their unconditional apply below; only the banks that already had skip semantics and the TexGen bank drop out here. - if (unchanged && (reg <= 0x19 || reg >= 0x3F)) continue; - - switch (reg) { - case 0x00: - g_gxState.xfError = val; - break; - case 0x08: - // XF vertex specs (numColors, numNormals, numTexCoords) - informational - break; - case 0x09: - // numChans - g_gxState.numChans = val; - g_gxState.stateDirty = true; - break; - case 0x0A: - // Ambient color 0 - g_gxState.colorChannelState[GX_COLOR0].ambColor = unpack_color(val); - g_gxState.colorChannelState[GX_ALPHA0].ambColor = unpack_color(val); - g_gxState.stateDirty = true; - break; - case 0x0B: - // Ambient color 1 - g_gxState.colorChannelState[GX_COLOR1].ambColor = unpack_color(val); - g_gxState.colorChannelState[GX_ALPHA1].ambColor = unpack_color(val); - g_gxState.stateDirty = true; - break; - case 0x0C: - // Material color 0 - g_gxState.colorChannelState[GX_COLOR0].matColor = unpack_color(val); - g_gxState.colorChannelState[GX_ALPHA0].matColor = unpack_color(val); - g_gxState.stateDirty = true; - break; - case 0x0D: - // Material color 1 - g_gxState.colorChannelState[GX_COLOR1].matColor = unpack_color(val); - g_gxState.colorChannelState[GX_ALPHA1].matColor = unpack_color(val); - g_gxState.stateDirty = true; - break; - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: { - // Channel control registers - u32 chanId = reg - 0x0E; - if (chanId < MaxColorChannels) { - auto& chan = g_gxState.colorChannelConfig[chanId]; - chan.matSrc = static_cast(bp_get(val, 1, 0)); - chan.lightingEnabled = bp_get(val, 1, 1) != 0; - u32 lightsLo = bp_get(val, 4, 2); - chan.ambSrc = static_cast(bp_get(val, 1, 6)); - chan.diffFn = static_cast(bp_get(val, 2, 7)); - u32 lightsHi = bp_get(val, 4, 11); - switch (bp_get(val, 2, 9)) { - case 1: - chan.attnFn = GX_AF_SPEC; - break; - case 3: - chan.attnFn = GX_AF_SPOT; - break; - case 0: - case 2: - default: - chan.attnFn = GX_AF_NONE; - break; - } - u32 lightMask = lightsLo | (lightsHi << 4); - g_gxState.colorChannelState[chanId].lightMask = GX::LightMask{lightMask}; - mark_pipeline_state_dirty(); - } - break; - } - case 0x12: - g_gxState.dualTex = val; - mark_pipeline_state_dirty(); - break; - case 0x18: { - // Matrix index A: PnMtx + TexCoord0-3 matrix indices - g_gxState.currentPnMtx = bp_get(val, 6, 0) / 3; - for (u32 i = 0; i < 4 && i < MaxTexCoord; i++) { - auto texMtx = static_cast(bp_get(val, 6, 6 + i * 6)); - assert(texMtx >= 0 && texMtx <= GXTexMtx::GX_IDENTITY); - g_gxState.tcgs[i].mtx = texMtx; - } - mark_pipeline_state_dirty(); - break; - } - case 0x19: { - // Matrix index B: TexCoord4-7 matrix indices - for (u32 i = 0; i < 4 && (i + 4) < MaxTexCoord; i++) { - g_gxState.tcgs[i + 4].mtx = static_cast(bp_get(val, 6, i * 6)); - } - mark_pipeline_state_dirty(); - break; - } - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: { - // Viewport: sx, sy, sz, ox, oy, oz at XF 0x101A-0x101F - const u32 vpOff = reg - 0x1A; - g_gxState.xfViewport[vpOff] = read_f32(xfData + i * 4, bigEndian); - viewportUpdated = true; - break; - } - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x24: - case 0x25: - case 0x26: { - // Projection: 6 params + type at XF 0x1020-0x1026 - const u32 projOff = reg - 0x20; - if (projOff < g_gxState.xfProjection.size()) { - g_gxState.xfProjection[projOff] = read_f32(xfData + i * 4, bigEndian); - } else { - g_gxState.projType = static_cast(val); - } - projectionUpdated = true; - break; - } - case 0x3F: - // numTexGens - g_gxState.numTexGens = val; - mark_pipeline_state_dirty(); - break; - default: - // TexGen config (0x40-0x4F) and post-transform (0x50-0x5F) - if (reg >= 0x40 && reg <= 0x4F) { - u32 tcIdx = reg - 0x40; - if (tcIdx < MaxTexCoord) { - auto& tcg = g_gxState.tcgs[tcIdx]; - bool proj = bp_get(val, 1, 1) != 0; - u32 form = bp_get(val, 1, 2); - u32 tgType = bp_get(val, 3, 4); - u32 srcRow = bp_get(val, 5, 7); - tcg.inputFormAB11 = form == 0; - - if (tgType == 0) { - tcg.type = proj ? GX_TG_MTX3x4 : GX_TG_MTX2x4; - } else if (tgType == 1) { - // Bump mapping - tcg.type = static_cast(bp_get(val, 3, 15) + 2); - } else if (tgType == 2 || tgType == 3) { - tcg.type = GX_TG_SRTG; - } - - // Decode source from row - static const GXTexGenSrc rowToSrc[] = {GX_TG_POS, GX_TG_NRM, GX_TG_COLOR0, GX_TG_BINRM, GX_TG_TANGENT, - GX_TG_TEX0, GX_TG_TEX1, GX_TG_TEX2, GX_TG_TEX3, GX_TG_TEX4, - GX_TG_TEX5, GX_TG_TEX6, GX_TG_TEX7}; - if (srcRow < 13) { - tcg.src = rowToSrc[srcRow]; - } - mark_pipeline_state_dirty(); - } - } else if (reg >= 0x50 && reg <= 0x5F) { - u32 tcIdx = reg - 0x50; - if (tcIdx < MaxTexCoord) { - g_gxState.tcgs[tcIdx].postMtx = static_cast(bp_get(val, 6, 0) + 64); - g_gxState.tcgs[tcIdx].normalize = bp_get(val, 1, 8) != 0; - mark_pipeline_state_dirty(); - } - } else { -#ifndef NDEBUG - Log.debug("Unhandled XF register 0x{:04X} (value 0x{:08X})", reg, val); -#endif - } - break; - } - } - if (viewportUpdated) { - apply_xf_viewport(); - } - if (projectionUpdated) { - apply_xf_projection(); - } - } - - pos += dataBytes; -} - -static void handle_draw_overrun(u8 cmd, u16 vtxCount, u32 vtxSize, u32 totalVtxBytes, const u8* data, const u32& pos, - u32 size) { - static u32 truncatedDrawLogCount = 0; - if (truncatedDrawLogCount >= 64) { - if (truncatedDrawLogCount == 64) { - Log.warn("suppressing further truncated draw diagnostics"); - } - ++truncatedDrawLogCount; - return; - } - ++truncatedDrawLogCount; - - // Hex dump around the draw command for debugging - u32 cmdPos = pos - 2 - 1; // opcode byte position (before vtxCount and pos++) - u32 dumpStart = (cmdPos > 16) ? cmdPos - 16 : 0; - u32 dumpEnd = (cmdPos + 32 < size) ? cmdPos + 32 : size; - std::string hex; - for (u32 i = dumpStart; i < dumpEnd; i++) { - if (i == cmdPos) - hex += fmt::format("[{:02x}]", data[i]); - else - hex += fmt::format(" {:02x}", data[i]); - } - Log.warn(" hex dump around truncated draw cmd (pos {}-{}):{}", dumpStart, dumpEnd - 1, hex); - const auto fmt = static_cast(cmd & CP_VAT_MASK); - const auto& vtxFmt = g_gxState.vtxFmts[fmt]; - Log.warn(" truncated draw cmd=0x{:02X} fmt={} vtxCount={} vtxSize={} desc pn={} pos={} nrm={} clr0={} clr1={} " - "tex0={} tex1={} tex2={} tex3={} tex4={} tex5={} tex6={} tex7={}", - cmd, static_cast(fmt), vtxCount, vtxSize, g_gxState.vtxDesc[GX_VA_PNMTXIDX], - g_gxState.vtxDesc[GX_VA_POS], g_gxState.vtxDesc[GX_VA_NRM], g_gxState.vtxDesc[GX_VA_CLR0], - g_gxState.vtxDesc[GX_VA_CLR1], g_gxState.vtxDesc[GX_VA_TEX0], g_gxState.vtxDesc[GX_VA_TEX1], - g_gxState.vtxDesc[GX_VA_TEX2], g_gxState.vtxDesc[GX_VA_TEX3], g_gxState.vtxDesc[GX_VA_TEX4], - g_gxState.vtxDesc[GX_VA_TEX5], g_gxState.vtxDesc[GX_VA_TEX6], g_gxState.vtxDesc[GX_VA_TEX7]); - Log.warn(" fmt {} attrs pos({},{}) nrm({},{}) clr0({},{}) tex0({},{}) tex1({},{})", - static_cast(fmt), static_cast(vtxFmt.attrs[GX_VA_POS].cnt), - static_cast(vtxFmt.attrs[GX_VA_POS].type), static_cast(vtxFmt.attrs[GX_VA_NRM].cnt), - static_cast(vtxFmt.attrs[GX_VA_NRM].type), static_cast(vtxFmt.attrs[GX_VA_CLR0].cnt), - static_cast(vtxFmt.attrs[GX_VA_CLR0].type), static_cast(vtxFmt.attrs[GX_VA_TEX0].cnt), - static_cast(vtxFmt.attrs[GX_VA_TEX0].type), static_cast(vtxFmt.attrs[GX_VA_TEX1].cnt), - static_cast(vtxFmt.attrs[GX_VA_TEX1].type)); - Log.warn("stopping FIFO decode at truncated draw: need {} bytes at pos {}, have {}", totalVtxBytes, pos, size); -} - -// Draw command handler - parses vertices inline and caches results -static u32 calculate_last_vtx_size(GXVtxFmt fmt) { - u32 vtxSize = 0; - const auto& vtxFmt = g_gxState.vtxFmts[fmt]; - for (int i = GX_VA_PNMTXIDX; i <= GX_VA_TEX7; ++i) { - const auto attr = static_cast(i); - const auto& attrFmt = vtxFmt.attrs[i]; - switch (g_gxState.vtxDesc[i]) { - case GX_NONE: - break; - case GX_DIRECT: { - vtxSize += comp_type_size(attr, attrFmt.type) * comp_cnt_count(attr, attrFmt.cnt); - break; - } - case GX_INDEX8: - vtxSize += (attr == GX_VA_NRM && attrFmt.cnt == GX_NRM_NBT3) ? 3 : 1; - break; - case GX_INDEX16: - vtxSize += (attr == GX_VA_NRM && attrFmt.cnt == GX_NRM_NBT3) ? 6 : 2; - break; - } - } - - g_gxState.lastVtxFmt = fmt; - g_gxState.lastVtxSize = vtxSize; - // The format is selected by the draw opcode, without a register write. - // Even equal-stride formats may decode bytes differently, so do not merge - // into a draw using the previous format's shader and uniform layout. - g_gxState.stateDirty = true; - - return vtxSize; -} - -static void handle_draw_unmerged(GXPrimitive prim, GXVtxFmt fmt, u16 vtxCount, - gfx::Range vertRange, uint16_t usedPnMtxMask, - HashType matrixTopologySignature, - HashType geometrySignature, bool interpolationIdentityActive); - -// The per-draw geometry signature, matrix-usage mask and draw-identity hashes exist purely to feed frame interpolation (build_uniform consumes them only after its `frame_interpolation_fps() == 0` early-out). -static inline bool frame_interpolation_identity_needed() noexcept { - return frame_interpolation_active() && g_gxState.projType == GX_PERSPECTIVE; -} - -static uint32_t matrix_index_prefix_size(GXVtxFmt fmt) noexcept { - const auto& vtxFmt = g_gxState.vtxFmts[fmt]; - uint32_t size = 0; - for (int i = GX_VA_PNMTXIDX; i < GX_VA_POS; ++i) { - const auto attr = static_cast(i); - switch (g_gxState.vtxDesc[i]) { - case GX_NONE: - break; - case GX_DIRECT: - size += comp_type_size(attr, vtxFmt.attrs[i].type) * - comp_cnt_count(attr, vtxFmt.attrs[i].cnt); - break; - case GX_INDEX8: - ++size; - break; - case GX_INDEX16: - size += 2; - break; - } - } - return size; -} - -static HashType draw_geometry_signature(GXVtxFmt fmt, const uint8_t* vertices, - uint16_t vtxCount, uint32_t vtxStride) noexcept { - Hasher hasher; - hasher.update(vtxCount); - hasher.update(vtxStride); - - // Matrix-index bytes select an instance's current XF palette slots, so they are deliberately excluded from mesh identity. - const uint32_t matrixPrefix = std::min(matrix_index_prefix_size(fmt), vtxStride); - if (matrixPrefix == 0) { - // Most draws have no direct matrix-index prefix. - hasher.update(vertices, static_cast(vtxCount) * vtxStride); - } else { - for (uint16_t vertex = 0; vertex < vtxCount; ++vertex) { - hasher.update(vertices + static_cast(vertex) * vtxStride + matrixPrefix, - vtxStride - matrixPrefix); - } - } - - // Identical index streams can address different vertex arrays. - for (int i = GX_VA_POS; i <= GX_VA_TEX7; ++i) { - if (g_gxState.vtxDesc[i] != GX_INDEX8 && g_gxState.vtxDesc[i] != GX_INDEX16) { - continue; - } - const auto& array = g_gxState.arrays[i]; - const auto attribute = static_cast(i); - const auto source = reinterpret_cast(array.data); - hasher.update(attribute); - hasher.update(source); - hasher.update(array.stride); - } - return static_cast(hasher.digest()); -} - -struct PnMtxUsage { - uint16_t mask = 0; - HashType topologySignature = 0; -}; - -// Slot mask only. -static uint16_t pn_mtx_mask(const uint8_t* vertices, uint16_t vtxCount, - uint32_t vtxStride) noexcept { - if (g_gxState.vtxDesc[GX_VA_PNMTXIDX] != GX_DIRECT) { - return static_cast(1u << std::min(g_gxState.currentPnMtx, MaxPnMtx - 1)); - } - uint16_t mask = 0; - for (uint16_t vertex = 0; vertex < vtxCount; ++vertex) { - const uint32_t matrixIndex = vertices[static_cast(vertex) * vtxStride] / 3u; - if (matrixIndex < MaxPnMtx) { - mask |= static_cast(1u << matrixIndex); - } - } - return mask; -} - -static PnMtxUsage pn_mtx_usage(const uint8_t* vertices, uint16_t vtxCount, - uint32_t vtxStride) noexcept { - if (g_gxState.vtxDesc[GX_VA_PNMTXIDX] != GX_DIRECT) { - const uint32_t matrixIndex = std::min(g_gxState.currentPnMtx, MaxPnMtx - 1); - return { - .mask = static_cast(1u << matrixIndex), - // There is no vertex matrix-index topology in this path. - .topologySignature = 0, - }; - } - - Hasher topologyHasher; - topologyHasher.update(vtxCount); - uint16_t mask = 0; - for (uint16_t vertex = 0; vertex < vtxCount; ++vertex) { - // GX matrix-index attributes precede every other vertex attribute and are always one byte. - const uint8_t rawMatrixIndex = vertices[static_cast(vertex) * vtxStride]; - topologyHasher.update(rawMatrixIndex); - const uint32_t matrixIndex = rawMatrixIndex / 3u; - if (matrixIndex < MaxPnMtx) { - mask |= static_cast(1u << matrixIndex); - } - } - return { - .mask = mask, - .topologySignature = static_cast(topologyHasher.digest()), - }; -} - -// Whether the most recent unmerged draw recorded an interpolation snapshot, so a draw merged into it knows there is a snapshot to extend. -static bool s_lastDrawRecordedInterpolation = false; - -struct CachedIndexTemplate { - bool valid = false; - GXPrimitive prim = static_cast(0); - u16 vtxCount = 0; - u32 indexCount = 0; - IndexBuffer indices{}; -}; - -static const CachedIndexTemplate& cached_index_template(GXPrimitive prim, u16 vtxCount) { - // Topology expansion is immutable for a primitive/count pair. - constexpr size_t CacheSize = 256; - static std::array cache{}; - const u32 key = (static_cast(underlying(prim)) << 16) | vtxCount; - auto& entry = cache[(key ^ (key >> 9)) & (CacheSize - 1)]; - if (entry.valid && entry.prim == prim && entry.vtxCount == vtxCount) LIKELY { - return entry; - } - - entry.valid = true; - entry.prim = prim; - entry.vtxCount = vtxCount; - entry.indexCount = prepare_idx_template(entry.indices, prim, vtxCount); - return entry; -} - -static IndexBuffer handle_draw_idx_buf; - -static ArrayRef offset_index_template(const CachedIndexTemplate& indexTemplate, - u16 vtxStart) { - // Grow-only: resizing down and back up made every merge zero-fill the buffer before the transform immediately overwrote it. - const size_t count = indexTemplate.indices.size(); - if (handle_draw_idx_buf.size() < count) { - handle_draw_idx_buf.resize(count); - } - const u16* src = indexTemplate.indices.data(); - u16* dst = handle_draw_idx_buf.data(); - for (size_t i = 0; i < count; ++i) { - dst[i] = static_cast(src[i] + vtxStart); - } - return {dst, count}; -} - -struct CachedPipelineState { - gfx::PipelineRef ref = 0; - HashType configHash = 0; - // Carried here so the draw can be recorded without keeping the PipelineConfig that produced it alive; it is the only field of the config the draw itself still needs. - u32 dstAlpha = UINT32_MAX; - ShaderInfo shaderInfo{}; -}; - -static const CachedPipelineState& cached_pipeline_state(const PipelineConfig& config) { - constexpr size_t CacheSize = 1024; - struct Entry { - bool valid = false; - PipelineConfig config{}; - CachedPipelineState state{}; - }; - static std::array cache{}; - - const HashType hash = xxh3_hash(config, static_cast(gfx::ShaderType::GX)); - auto& entry = cache[hash & (CacheSize - 1)]; - if (entry.valid && entry.state.configHash == hash && - std::memcmp(&entry.config, &config, sizeof(config)) == 0) LIKELY { - return entry.state; - } - - entry.valid = true; - entry.config = config; - entry.state = { - .ref = gfx::pipeline_ref(config), - .configHash = hash, - .dstAlpha = config.dstAlpha, - .shaderInfo = build_shader_info(config.shaderConfig), - }; - return entry.state; -} - -// Resolving a pipeline the long way costs a ~2.7KB zero-init, a full populate_pipeline_config, an XXH3 over the whole config and a memcmp against the hash-indexed slot -- roughly 11KB of memory traffic for a result that is almost always identical to the previous draw's. -static const CachedPipelineState& resolve_pipeline_state(GXPrimitive prim, GXVtxFmt fmt) { - struct Memo { - const CachedPipelineState* state = nullptr; - u32 generation = 0; - u32 sampleCount = 0; - GXPrimitive prim = static_cast(0); - GXVtxFmt fmt = static_cast(0); - }; - static Memo memo{}; - - const u32 sampleCount = gfx::get_sample_count(); - const u32 generation = g_gxState.pipelineStateGeneration; - if (memo.state != nullptr && memo.generation == generation && memo.sampleCount == sampleCount && - memo.prim == prim && memo.fmt == fmt) LIKELY { - return *memo.state; - } - - PipelineConfig config{}; - populate_pipeline_config(config, prim, fmt); - // cached_pipeline_state hands back a reference into a fixed direct-mapped table, so the address stays valid; the entry it points at can only be rewritten by another call to that function, and every such call goes through this miss path and replaces the memo in the same breath. - const CachedPipelineState& state = cached_pipeline_state(config); - memo = Memo{ - .state = &state, - .generation = generation, - .sampleCount = sampleCount, - .prim = prim, - .fmt = fmt, - }; - return state; -} - -static bool admit_draw(GXPrimitive prim, GXVtxFmt fmt, u16 count, uint32_t vertexBytes, bool merged = false) { - const auto& indexTemplate = cached_index_template(prim, count); - gfx::StagingSizes demand{vertexBytes, 0, indexTemplate.indices.size() * sizeof(u16), 0}; - if (merged) return gfx::staging_has_space(demand); - const auto& info = resolve_pipeline_state(prim, fmt).shaderInfo; - demand[1] = gfx::staging_uniform_bytes(info.uniformSize); - if (frame_interpolation_identity_needed() && frame_interpolation_replay_safe()) - demand[1] *= 1 + MaxInterpolatedFrames; - for (int i = GX_VA_POS; i <= GX_VA_TEX7; ++i) { - if ((g_gxState.vtxDesc[i] == GX_INDEX8 || g_gxState.vtxDesc[i] == GX_INDEX16) && - g_gxState.arrays[i].cachedRange.size == 0) - demand[3] += gfx::staging_storage_bytes(g_gxState.arrays[i].size); - } - return gfx::staging_has_space(demand); -} - -bool submit_raw_draw(GXPrimitive prim, GXVtxFmt fmt, const uint8_t* vertices, uint16_t vtxCount, - uint32_t vertexBytes) { - ZoneScoped; - if (vertices == nullptr || vtxCount == 0 || vertexBytes == 0) { - return false; - } - - if (__gx->dirtyState != 0) UNLIKELY { - __GXSetDirtyState(); - } - - // Raw bridge draws consume live decoded GX state that is also maintained by the HLE producer. - drain(); - - u32 vtxSize; - if (g_gxState.lastVtxFmt == fmt) LIKELY { - vtxSize = g_gxState.lastVtxSize; - } else UNLIKELY { - vtxSize = calculate_last_vtx_size(fmt); - } - - const u32 expectedVertexBytes = static_cast(vtxCount) * vtxSize; - if (expectedVertexBytes == 0 || expectedVertexBytes != vertexBytes) { - static uint32_t rawVertexSizeMismatchCount = 0; - if (rawVertexSizeMismatchCount++ < 64) { - Log.warn("raw draw vertex-size mismatch prim={} fmt={} count={} cached_stride={} expected={} supplied={}", - static_cast(prim), static_cast(fmt), vtxCount, vtxSize, - expectedVertexBytes, vertexBytes); - } - return false; - } - - if (!has_complete_primitive(prim, vtxCount)) return true; - - // This entry point bypasses process(), so it owns the renderer lock itself. - std::unique_lock gpuLock(aurora::renderer_gpu_mutex()); - if (!admit_draw(prim, fmt, vtxCount, vertexBytes)) { - gpuLock.unlock(); - gfx::split_staging_batch(); - gpuLock.lock(); - if (!admit_draw(prim, fmt, vtxCount, vertexBytes)) - throw gfx::StagingCapacityError("Raw draw does not fit after capacity submission"); - } - const gfx::Range vertRange = gfx::push_verts(vertices, vertexBytes); - const bool interpolationIdentityActive = frame_interpolation_identity_needed(); - const PnMtxUsage matrixUsage = interpolationIdentityActive - ? pn_mtx_usage(vertices, vtxCount, vtxSize) - : PnMtxUsage{}; - handle_draw_unmerged(prim, fmt, vtxCount, vertRange, - matrixUsage.mask, matrixUsage.topologySignature, - interpolationIdentityActive ? draw_geometry_signature(fmt, vertices, vtxCount, vtxSize) : 0, - interpolationIdentityActive); - return true; -} - -static bool handle_draw(u8 cmd, const u8* data, u32& pos, u32 size, bool bigEndian) { - ZoneScoped; - GXVtxFmt fmt = static_cast(cmd & CP_VAT_MASK); - GXPrimitive prim = primitive_from_draw_cmd(cmd); - - if (pos + 2 > size) { - return false; - } - u16 vtxCount = read_u16(data + pos, bigEndian); - pos += 2; - - u32 vtxSize; - if (g_gxState.lastVtxFmt == fmt) LIKELY { - vtxSize = g_gxState.lastVtxSize; - } else UNLIKELY { - vtxSize = calculate_last_vtx_size(fmt); - } - - u32 totalVtxBytes = vtxCount * vtxSize; - if (pos + totalVtxBytes > size) UNLIKELY { - handle_draw_overrun(cmd, vtxCount, vtxSize, totalVtxBytes, data, pos, size); - return false; - } - - - if (!has_complete_primitive(prim, vtxCount)) { - pos += totalVtxBytes; - return true; - } - - DrawData* mergeTarget = nullptr; - // Decide admission before allocating anything. The merged path needs only - // vertices and indices; it must not resolve pipelines or upload arrays. - // Try to merge with previous draw call - if (!g_gxState.stateDirty) LIKELY { - auto* lastDraw = gfx::get_last_draw_command(); - // Expanded lines/points have different vertex interpretation even with one instance. - // Triangle-list output has no restart index; index 65535 is usable. - // Overflow would address earlier vertices instead of the appended geometry. - if (lastDraw != nullptr && prim != GX_LINES && prim != GX_LINESTRIP && prim != GX_POINTS && - !lastDraw->expandedPrimitive && lastDraw->instanceCount == 1 && - uint64_t(lastDraw->vtxCount) + - vtxCount <= 65536u) LIKELY { - mergeTarget = lastDraw; - } - } - if (!admit_draw(prim, fmt, vtxCount, totalVtxBytes, mergeTarget != nullptr)) throw gfx::StagingBatchFull{}; - const uint8_t* vertices = data + pos; - gfx::Range vertRange = gfx::push_verts(vertices, totalVtxBytes); - pos += totalVtxBytes; - if (auto* lastDraw = mergeTarget) { - const auto& indexTemplate = cached_index_template(prim, vtxCount); - const auto indices = offset_index_template(indexTemplate, lastDraw->vtxCount); - const u32 numIndices = indexTemplate.indexCount; - const gfx::Range idxRange = gfx::push_indices(indices); - CHECK(lastDraw->vertRange.offset + lastDraw->vertRange.size == vertRange.offset, - "Non-consecutive vertex ranges ({} < {})", lastDraw->vertRange.offset + lastDraw->vertRange.size, - vertRange.offset); - CHECK(lastDraw->idxRange.offset + lastDraw->idxRange.size == idxRange.offset, - "Non-consecutive index ranges ({} < {})", lastDraw->idxRange.offset + lastDraw->idxRange.size, - idxRange.offset); - lastDraw->vertRange.size += vertRange.size; - lastDraw->idxRange.size += idxRange.size; - lastDraw->vtxCount += vtxCount; - lastDraw->indexCount += numIndices; - ++gfx::g_mergedDrawCallCount; - // This primitive now renders through the draw we merged into, so its palette slots belong to that draw's interpolation snapshot as well. - if (s_lastDrawRecordedInterpolation) UNLIKELY { - extend_interpolation_draw(pn_mtx_mask(vertices, vtxCount, vtxSize)); - } - return true; - } - - const bool interpolationIdentityActive = frame_interpolation_identity_needed(); - const PnMtxUsage matrixUsage = interpolationIdentityActive - ? pn_mtx_usage(vertices, vtxCount, vtxSize) - : PnMtxUsage{}; - handle_draw_unmerged(prim, fmt, vtxCount, vertRange, - matrixUsage.mask, matrixUsage.topologySignature, - interpolationIdentityActive ? draw_geometry_signature(fmt, vertices, vtxCount, vtxSize) : 0, - interpolationIdentityActive); - return true; -} - -static void handle_draw_unmerged(GXPrimitive prim, GXVtxFmt fmt, u16 vtxCount, - gfx::Range vertRange, uint16_t usedPnMtxMask, - HashType matrixTopologySignature, - HashType geometrySignature, bool interpolationIdentityActive) { - ZoneScoped; - // GX_CULL_ALL rasterizes nothing on hardware - no color, no depth. - if (g_gxState.cullMode == GX_CULL_ALL && prim != GX_LINES && prim != GX_LINESTRIP && prim != GX_POINTS) - UNLIKELY { - // Leave stateDirty alone: the next draw re-resolving its pipeline is the safe direction, and nothing about this draw reached the GPU. - return; - } - // Callers hold the renderer GPU mutex for the whole drain (process() and submit_raw_draw); taking it again per draw only cost a recursive re-entry. - const auto& indexTemplate = cached_index_template(prim, vtxCount); - const u32 numIndices = indexTemplate.indexCount; - const gfx::Range idxRange = gfx::push_indices(ArrayRef{ - indexTemplate.indices.data(), indexTemplate.indices.size()}); - - // Build pipeline, bind groups, and push draw command - BindGroupRanges ranges{}; - for (int i = GX_VA_POS; i <= GX_VA_TEX7; ++i) { - if (g_gxState.vtxDesc[i] != GX_INDEX8 && g_gxState.vtxDesc[i] != GX_INDEX16) { - continue; - } - auto& array = g_gxState.arrays[i]; - if (array.cachedRange.size > 0) { - ranges.vaRanges[i - GX_VA_POS] = array.cachedRange; - } else { - const auto range = gfx::push_storage(static_cast(array.data), array.size); - ranges.vaRanges[i - GX_VA_POS] = range; - array.cachedRange = range; - } - } - - const auto& pipelineState = resolve_pipeline_state(prim, fmt); - const auto& info = pipelineState.shaderInfo; - - resolve_sampled_textures(info); - - const auto bindGroups = build_bind_groups(info); - - const auto pipeline = pipelineState.ref; - - // Draw-identity hashing only feeds frame interpolation, and only for perspective draws: build_uniform reads the identity exclusively past its `!perspective || frame_interpolation_fps() == 0` early-out. - FrameInterpolationDrawIdentity drawIdentity{}; - if (interpolationIdentityActive) UNLIKELY { - const HashType drawShape = static_cast(vtxCount) | - (static_cast(underlying(prim)) << 16) | - (static_cast(underlying(fmt)) << 24); - const HashType pipelineDrawSignature = xxh3_hash(pipelineState.configHash, drawShape); - const HashType textureSignature = xxh3_hash(bindGroups.textureBindGroup); - const HashType materialAndTopology = - xxh3_hash(matrixTopologySignature, - xxh3_hash(bindGroups.textureBindGroup, pipelineDrawSignature)); - drawIdentity = FrameInterpolationDrawIdentity{ - .combined = xxh3_hash(geometrySignature, materialAndTopology), - .pipeline = pipelineDrawSignature, - .texture = textureSignature, - .matrixTopology = matrixTopologySignature, - }; - } - const auto uniformRanges = - build_uniform(info, vertRange.offset, ranges, drawIdentity, interpolationIdentityActive, - usedPnMtxMask); - s_lastDrawRecordedInterpolation = interpolationIdentityActive; - - uint32_t instanceCount = 1; - if (prim == GX_LINES) { - instanceCount = vtxCount / 2; - } else if (prim == GX_LINESTRIP) { - instanceCount = vtxCount - 1; - } else if (prim == GX_POINTS) { - instanceCount = vtxCount; - } - gfx::push_draw_command(DrawData{ - .pipeline = pipeline, - .vertRange = vertRange, - .idxRange = idxRange, - .uniformRange = uniformRanges.current, - .interpolatedUniformRanges = uniformRanges.interpolated, - .vtxCount = vtxCount, - .indexCount = numIndices, - .instanceCount = instanceCount, - .expandedPrimitive = prim == GX_LINES || prim == GX_LINESTRIP || prim == GX_POINTS, - .bindGroups = bindGroups, - .dstAlpha = pipelineState.dstAlpha, - }); - g_gxState.stateDirty = false; -} - -std::string read_string(const u8* data, u32& pos, u32 size, bool bigEndian) { - CHECK(pos + 2 <= size, "Aurora string length read overrun"); - const u16 length = read_u16(data + pos, bigEndian); - pos += 2; - - CHECK(pos + length <= size, "Aurora string read overrun"); - std::string str(reinterpret_cast(data) + pos, length); - pos += length; - return str; -} - -bool handle_aurora(const u8* data, u32& pos, u32 size, bool bigEndian) { - ZoneScoped; - if (pos + 2 > size) { - return false; - } - u16 subCmd = read_u16(data + pos, bigEndian); - pos += 2; - - // Setting of vertex array bases. - if (subCmd == GX_LOAD_AURORA_VIEWPORT_RENDER) { - CHECK(pos + 24 <= size, "GX_LOAD_AURORA_VIEWPORT_RENDER read overrun"); - const f32 left = read_f32(data + pos, bigEndian); - pos += 4; - const f32 top = read_f32(data + pos, bigEndian); - pos += 4; - const f32 width = read_f32(data + pos, bigEndian); - pos += 4; - const f32 height = read_f32(data + pos, bigEndian); - pos += 4; - const f32 nearZ = read_f32(data + pos, bigEndian); - pos += 4; - const f32 farZ = read_f32(data + pos, bigEndian); - pos += 4; - set_render_viewport({ - .left = left, - .top = top, - .width = width, - .height = height, - .znear = nearZ, - .zfar = farZ, - }); - } else if (subCmd == GX_LOAD_AURORA_SCISSOR_RENDER) { - CHECK(pos + 16 <= size, "GX_LOAD_AURORA_SCISSOR_RENDER read overrun"); - const int32_t left = static_cast(read_u32(data + pos, bigEndian)); - pos += 4; - const int32_t top = static_cast(read_u32(data + pos, bigEndian)); - pos += 4; - const int32_t width = static_cast(read_u32(data + pos, bigEndian)); - pos += 4; - const int32_t height = static_cast(read_u32(data + pos, bigEndian)); - pos += 4; - set_render_scissor({left, top, width, height}); - } else if (subCmd >= GX_LOAD_AURORA_ARRAYBASE && subCmd <= (GX_LOAD_AURORA_ARRAYBASE | 0x0f)) { - CHECK(pos + 13 <= size, "GX_LOAD_AURORA_ARRAYBASE read overrun"); - u32 attrIdx = subCmd - GX_LOAD_AURORA_ARRAYBASE + GX_VA_POS; - - u64 arrayAddr = read_u64(data + pos, bigEndian); - pos += 8; - u32 arraySize = read_u32(data + pos, bigEndian); - pos += 4; - bool le = data[pos] == 1; - pos += 1; - - auto& array = g_gxState.arrays[attrIdx]; - const auto newData = reinterpret_cast(arrayAddr); - if (array.data != newData || array.size != arraySize || array.le != le) { - array.data = newData; - array.size = arraySize; - array.le = le; - // Only drop the cached upload when the backing array actually changes. - array.cachedRange = {}; - mark_pipeline_state_dirty(); - } - } else if (subCmd == GX_LOAD_AURORA_TEXOBJ) { - CHECK(pos + 34 <= size, "GX_LOAD_AURORA_TEXOBJ read overrun"); - const auto texMapId = data[pos]; - pos += 1; - CHECK(texMapId < MaxTextures, "invalid texture map id {}", texMapId); - auto& slot = g_gxState.loadedTextures[texMapId]; - GXTexObj_ next = slot; - next.data = reinterpret_cast(read_u64(data + pos, bigEndian)); - pos += 8; - next.mWidth = read_u32(data + pos, bigEndian); - pos += 4; - next.mHeight = read_u32(data + pos, bigEndian); - pos += 4; - next.mFormat = static_cast(read_u32(data + pos, bigEndian)); - pos += 4; - next.tlut = static_cast(read_u32(data + pos, bigEndian)); - pos += 4; - if (data[pos] != 0) { - next.flags |= 1u; - } else { - next.flags &= ~1u; - } - pos += 1; - next.texObjId = read_u32(data + pos, bigEndian); - pos += 4; - next.texDataVersion = read_u32(data + pos, bigEndian); - pos += 4; - next.set_no_cache(false); // Reset no-cache flag - const bool changed = slot.data != next.data || slot.mWidth != next.mWidth || slot.mHeight != next.mHeight || - slot.mFormat != next.mFormat || slot.tlut != next.tlut || slot.flags != next.flags || - slot.texObjId != next.texObjId || slot.texDataVersion != next.texDataVersion; - slot = next; - if (changed) { - g_gxState.stateDirty = true; - } - } else if (subCmd == GX_LOAD_AURORA_TLUT) { - CHECK(pos + 23 <= size, "GX_LOAD_AURORA_TLUT read overrun"); - const auto idx = data[pos]; - pos += 1; - CHECK(idx < MaxTluts, "invalid tlut slot {}", idx); - auto& slot = g_gxState.loadedTluts[idx]; - slot.data = reinterpret_cast(read_u64(data + pos, bigEndian)); - pos += 8; - slot.format = static_cast(read_u32(data + pos, bigEndian)); - pos += 4; - slot.numEntries = read_u16(data + pos, bigEndian); - pos += 2; - slot.tlutObjId = read_u32(data + pos, bigEndian); - pos += 4; - slot.tlutDataVersion = read_u32(data + pos, bigEndian); - pos += 4; - slot.set_no_cache(false); // Reset no-cache flag - g_gxState.stateDirty = true; - } else if (subCmd == GX_LOAD_AURORA_DESTROY_TEXOBJ) { - CHECK(pos + 4 <= size, "GX_LOAD_AURORA_DESTROY_TEXOBJ read overrun"); - evict_texture_object(read_u32(data + pos, bigEndian)); - pos += 4; - } else if (subCmd == GX_LOAD_AURORA_DESTROY_TLUT) { - CHECK(pos + 4 <= size, "GX_LOAD_AURORA_DESTROY_TLUT read overrun"); - evict_tlut_object(read_u32(data + pos, bigEndian)); - pos += 4; - } else if (subCmd == GX_LOAD_AURORA_DESTROY_COPY_TEX) { - CHECK(pos + 8 <= size, "GX_LOAD_AURORA_DESTROY_COPY_TEX read overrun"); - evict_copy_texture(reinterpret_cast(read_u64(data + pos, bigEndian))); - pos += 8; - } else if (subCmd == GX_LOAD_AURORA_INVALIDATE_TEX_ALL) { - invalidate_static_texture_cache(); - } else if (subCmd == GX_LOAD_AURORA_DEBUG_GROUP_PUSH) { - auto label = read_string(data, pos, size, bigEndian); - gfx::push_debug_group(std::move(label)); - } else if (subCmd == GX_LOAD_AURORA_DEBUG_GROUP_POP) { - aurora_pop_debug_group(); - } else if (subCmd == GX_LOAD_AURORA_DEBUG_MARKER_INSERT) { - auto label = read_string(data, pos, size, bigEndian); - gfx::insert_debug_marker(std::move(label)); - } - - else { - static u32 unknownAuroraLogCount = 0; - if (unknownAuroraLogCount < 16) { - Log.warn("Unknown Aurora subcommand: {:04X}; stopping FIFO decode", subCmd); - ++unknownAuroraLogCount; - } - return false; - } - return true; -} - -} // namespace aurora::gx::fifo diff --git a/aurora-main/lib/gx/command_processor.hpp b/aurora-main/lib/gx/command_processor.hpp deleted file mode 100644 index 7ff4fe2..0000000 --- a/aurora-main/lib/gx/command_processor.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "dolphin/gx/GXEnum.h" -#include "../internal.hpp" - -namespace aurora::gx::fifo { - -// Reset the CP write-deduplication state whenever the GX shadow state is reinitialized. -void reset_cp_register_cache(); - -// Process a buffer of GX FIFO commands -uint32_t process(const uint8_t* data, uint32_t size, bool bigEndian); - -// Submit already-packed direct vertex bytes against the current GX state. -bool submit_raw_draw(GXPrimitive prim, GXVtxFmt fmt, const uint8_t* vertices, uint16_t vtxCount, - uint32_t vertexBytes); - -} // namespace aurora::gx::fifo diff --git a/aurora-main/lib/gx/fifo.cpp b/aurora-main/lib/gx/fifo.cpp deleted file mode 100644 index 37065b8..0000000 --- a/aurora-main/lib/gx/fifo.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "fifo.hpp" -#include "command_processor.hpp" -#include "../gfx/common.hpp" -#include "../internal.hpp" - -#include -#include -#include -#include - -#include "tracy/Tracy.hpp" - -namespace aurora::gx::fifo { -static Module Log("aurora::gx::fifo"); - -namespace detail { -uint8_t* sBufferData = nullptr; -uint32_t sBufferSize = 0; -uint32_t sBufferCapacity = 0; -bool sInDisplayList = false; -uint8_t* sDlBuffer = nullptr; -uint32_t sDlSize = 0; -uint32_t sDlWritePos = 0; -} // namespace detail - -void init() { - constexpr uint32_t initialCapacity = 64 * 1024; - reset_cp_register_cache(); - free(detail::sBufferData); - detail::sBufferData = static_cast(malloc(initialCapacity)); - detail::sBufferSize = 0; - detail::sBufferCapacity = initialCapacity; - detail::sInDisplayList = false; - detail::sDlBuffer = nullptr; - detail::sDlSize = 0; - detail::sDlWritePos = 0; -} - -void write_data_grow(const void* data, uint32_t length) { - uint32_t needed = detail::sBufferSize + length; - uint32_t newCap = std::max(detail::sBufferCapacity * 2, needed); - detail::sBufferData = static_cast(realloc(detail::sBufferData, newCap)); - std::memcpy(detail::sBufferData + detail::sBufferSize, data, length); - detail::sBufferSize = needed; - detail::sBufferCapacity = newCap; -} - -void begin_display_list(uint8_t* buf, uint32_t size) { - detail::sInDisplayList = true; - detail::sDlBuffer = buf; - detail::sDlSize = size; - detail::sDlWritePos = 0; -} - -uint32_t end_display_list() { - detail::sInDisplayList = false; - uint32_t bytesWritten = detail::sDlWritePos; - uint32_t padded = (bytesWritten + 31) & ~31u; - while (detail::sDlWritePos < padded && detail::sDlWritePos < detail::sDlSize) { - detail::sDlBuffer[detail::sDlWritePos++] = 0; - } - detail::sDlBuffer = nullptr; - detail::sDlSize = 0; - detail::sDlWritePos = 0; - return padded; -} - -bool in_display_list() { return detail::sInDisplayList; } - -// How much of the producer's frame is spent blocked before it may decode the next batch of GX commands. -static void note_drain_wait(uint64_t nanos) noexcept { - ZoneScopedN("FIFO drain wait"); - TracyPlot("aurora: fifoDrainWaitUs", static_cast(nanos / 1000)); -} - -void drain() { - // SEALED, not DONE. - const auto waited = aurora::wait_for_frame_worker_sealed(); - if (waited.count() > 0) UNLIKELY { - note_drain_wait(static_cast(waited.count())); - } - if (detail::sBufferSize == 0) { - return; - } - process_all(detail::sBufferData, detail::sBufferSize, true); - detail::sBufferSize = 0; -} - -void process_all(const uint8_t* data, uint32_t size, bool bigEndian) { - uint32_t consumed = 0; - bool retried = false; - while (consumed < size) { - const auto count = process(data + consumed, size - consumed, bigEndian); - if (count == 0 && retried) - throw gfx::StagingCapacityError("FIFO draw does not fit after capacity submission"); - consumed += count; - if (consumed == size) break; - // process returned with its renderer lock released. No recursive drain. - gfx::split_staging_batch(); - retried = true; - } -} - -const uint8_t* get_buffer_data() { return detail::sBufferData; } -uint32_t get_buffer_size() { return detail::sBufferSize; } -void clear_buffer() { - detail::sBufferSize = 0; -} - -} // namespace aurora::gx::fifo diff --git a/aurora-main/lib/gx/fifo.hpp b/aurora-main/lib/gx/fifo.hpp deleted file mode 100644 index 08110dc..0000000 --- a/aurora-main/lib/gx/fifo.hpp +++ /dev/null @@ -1,93 +0,0 @@ -#pragma once - -#include "../internal.hpp" - -#include - -namespace aurora::gx::fifo { - -namespace detail { -extern uint8_t* sBufferData; -extern uint32_t sBufferSize; -extern uint32_t sBufferCapacity; -extern bool sInDisplayList; -extern uint8_t* sDlBuffer; -extern uint32_t sDlSize; -extern uint32_t sDlWritePos; -} // namespace detail - -void init(); - -// Out-of-line slow path: grows internal buffer then appends data -void write_data_grow(const void* data, uint32_t length); - -inline void write_data(const void* data, const uint32_t length) { - if (!detail::sInDisplayList) - LIKELY { - if (detail::sBufferSize + length <= detail::sBufferCapacity) - LIKELY { - std::memcpy(detail::sBufferData + detail::sBufferSize, data, length); - detail::sBufferSize += length; - return; - } - write_data_grow(data, length); - } - else if (detail::sDlWritePos + length <= detail::sDlSize) { - std::memcpy(detail::sDlBuffer + detail::sDlWritePos, data, length); - detail::sDlWritePos += length; - } -} - -inline void write_u8(const uint8_t val) { - if (!detail::sInDisplayList) - LIKELY { - if (detail::sBufferSize < detail::sBufferCapacity) - LIKELY { - detail::sBufferData[detail::sBufferSize++] = val; - return; - } - write_data_grow(&val, 1); - } - else if (detail::sDlWritePos < detail::sDlSize) { - detail::sDlBuffer[detail::sDlWritePos++] = val; - } -} - -inline void write_u16(const uint16_t val) { - const auto out = bswap(val); - write_data(&out, sizeof(out)); -} - -inline void write_u32(const uint32_t val) { - const auto out = bswap(val); - write_data(&out, sizeof(out)); -} - -inline void write_u64(const uint64_t val) { - const auto out = bswap(val); - write_data(&out, sizeof(out)); -} - -inline void write_f32(const float val) { - const auto out = bswap(val); - write_data(&out, sizeof(out)); -} - -// Display list recording -void begin_display_list(uint8_t* buf, uint32_t size); -uint32_t end_display_list(); -bool in_display_list(); - -// Drain the internal FIFO buffer through the command processor -void drain(); - -// Decode a whole command stream, submitting the staging batch whenever a draw does not fit. -// process() alone stops at that draw, so a caller that ignores its count drops the rest. -void process_all(const uint8_t* data, uint32_t size, bool bigEndian); - -// Internal buffer inspection -const uint8_t* get_buffer_data(); -uint32_t get_buffer_size(); -void clear_buffer(); - -} // namespace aurora::gx::fifo diff --git a/aurora-main/lib/gx/frame_interpolation.cpp b/aurora-main/lib/gx/frame_interpolation.cpp deleted file mode 100644 index cd2d339..0000000 --- a/aurora-main/lib/gx/frame_interpolation.cpp +++ /dev/null @@ -1,1536 +0,0 @@ -#include "frame_interpolation.hpp" - -#include "../internal.hpp" -#include "aurora/gfx.h" - -// Guest matrices really do carry NaN/Inf, and the isfinite guards here keep them -// out of the MatchEdge sort. Needs -fno-finite-math-only (see runtime/CMakeLists.txt). -#if defined(__FINITE_MATH_ONLY__) && __FINITE_MATH_ONLY__ -#error "frame_interpolation.cpp must be compiled with -fno-finite-math-only; its NaN filtering is load-bearing for memory safety (see comment above)." -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace aurora::gx { -namespace detail { -std::atomic_uint32_t g_frameInterpolationFps{0}; -} // namespace detail - -namespace { -static Module Log("aurora::gx::interp"); - -// Diagnostics for aurora_get_frame_interpolation_diagnostics. Individually atomic: -// one writer, and a torn read is harmless for an overlay. -std::atomic_uint32_t s_diagCandidates{0}; -std::atomic_uint32_t s_diagMatchable{0}; -std::atomic_uint32_t s_diagMatches{0}; -std::atomic_bool s_diagEligible{false}; -std::atomic_bool s_diagReplaySafe{true}; -std::atomic_uint64_t s_diagFramesSealed{0}; -std::atomic_uint64_t s_diagFramesLowMatch{0}; -std::atomic_uint64_t s_diagFramesReplayUnsafe{0}; -std::atomic_uint64_t s_diagSlotReductions{0}; -std::atomic_uint64_t s_diagLateSealDrops{0}; -// Persistent worker pool for the per-sample interpolation tasks. libc++ has no -// parallel execution policies, so without it the seal loop runs serially. Leaked. -class InterpolationWorkerPool { -public: - static InterpolationWorkerPool& instance() { - static InterpolationWorkerPool* pool = new InterpolationWorkerPool(); - return *pool; - } - - // Runs fn(index) for every index in [0, count). Returns once every index has - // been processed. Not reentrant; only the producer/seal thread dispatches. - template - void run(size_t count, const Fn& fn) { - if (count == 0) { - return; - } - if (m_workers.empty()) { - for (size_t i = 0; i < count; ++i) { - fn(i); - } - return; - } - { - // Job state and the generation bump publish under one lock, so a late worker - // can never observe a half-written job. - std::lock_guard lock(m_mutex); - m_invoke = [&fn](size_t index) { fn(index); }; - m_count.store(count, std::memory_order_relaxed); - m_next.store(0, std::memory_order_relaxed); - m_remaining.store(count, std::memory_order_relaxed); - ++m_generation; - } - m_wake.notify_all(); - consume(); - // Wait for stragglers to leave consume() entirely, not just finish their chunks, - // so the next dispatch can safely reset the shared counters. - while (m_remaining.load(std::memory_order_acquire) != 0 || - m_active.load(std::memory_order_acquire) != 0) { - std::this_thread::yield(); - } - m_invoke = nullptr; - } - -private: - static constexpr size_t kChunk = 16; - - InterpolationWorkerPool() { - const unsigned hardware = std::thread::hardware_concurrency(); - // The caller helps too. Cap the helpers: tasks are short memcpy+math, so dispatch - // overhead and memory bandwidth dominate past a few threads. - const unsigned helpers = hardware > 2 ? std::min(hardware - 1, 6u) : 0; - m_workers.reserve(helpers); - for (unsigned i = 0; i < helpers; ++i) { - m_workers.emplace_back([this] { worker_loop(); }); - } - } - - void consume() { - const size_t count = m_count.load(std::memory_order_relaxed); - while (true) { - const size_t begin = m_next.fetch_add(kChunk, std::memory_order_relaxed); - if (begin >= count) { - return; - } - const size_t end = std::min(begin + kChunk, count); - for (size_t index = begin; index < end; ++index) { - m_invoke(index); - } - m_remaining.fetch_sub(end - begin, std::memory_order_release); - } - } - - void worker_loop() { - uint64_t seenGeneration = 0; - while (true) { - { - std::unique_lock lock(m_mutex); - m_wake.wait(lock, [&] { return m_generation != seenGeneration; }); - seenGeneration = m_generation; - // Counted under the mutex: when the dispatcher sees m_active == 0 every worker is - // parked or has not read the current generation, so a counter reset is safe. - m_active.fetch_add(1, std::memory_order_relaxed); - } - consume(); - m_active.fetch_sub(1, std::memory_order_release); - } - } - - std::vector m_workers; - std::mutex m_mutex; - std::condition_variable m_wake; - uint64_t m_generation = 0; - std::function m_invoke; - std::atomic_size_t m_count{0}; - std::atomic_size_t m_next{0}; - std::atomic_size_t m_remaining{0}; - std::atomic_size_t m_active{0}; -}; -struct FrameTransformSnapshot { - Mat4x4 projection{}; - HashType viewportIdentity = 0; - Mat3x4 position{}; - Mat3x4 normal{}; - uint16_t usedMatrixMask = 1; - struct IndexedMatrices { - std::array, MaxPnMtx> position{}; - std::array, MaxPnMtx> normal{}; - // Content hash of each used slot's position/normal pair. A mesh split across draws - // repeats bone matrices byte for byte, so the seal can pair slots across draws. - std::array slotHash{}; - }; - std::unique_ptr indexedMatrices; -}; - -struct FrameTransformEntry { - FrameInterpolationDrawIdentity identity; - FrameTransformSnapshot transform; - // Constant-velocity prediction of a non-indexed transform, so repeated meshes match - // on where they will be. Not for indexed draws: PNMTXIDX slot identity pairs those. - Mat3x4 predictedPosition{}; - bool hasPrediction = false; -}; - -struct Quaternion { - float x = 0.0f; - float y = 0.0f; - float z = 0.0f; - float w = 1.0f; -}; - -struct PendingUniformInterpolation { - size_t currentTransformIndex = 0; - const uint8_t* sourceUniformData = nullptr; - uint8_t* uniformData = nullptr; - size_t uniformSize = 0; - size_t projectionOffset = 0; - size_t positionOffset = 0; - size_t normalOffset = 0; - size_t currentMatrix = 0; - uint32_t numerator = 0; - uint32_t denominator = 1; - bool indexedMatrices = false; -}; - -std::vector s_previousFrameTransforms; -std::vector s_currentFrameTransforms; -std::unordered_map> s_previousTransformIndices; -std::unordered_map> s_currentTransformIndices; -std::unordered_map> s_previousStableTransformIndices; -std::unordered_map> s_currentStableTransformIndices; - -// Free list for the indexed-matrix snapshots; per-draw heap allocation was the -// hottest cost in this path. Unused slots keep stale data, consumers mask first. -std::vector> s_indexedMatricesPool; -constexpr size_t kMaximumPooledIndexedMatrices = 4096; - -std::unique_ptr acquire_indexed_matrices() { - if (s_indexedMatricesPool.empty()) { - return std::make_unique(); - } - auto block = std::move(s_indexedMatricesPool.back()); - s_indexedMatricesPool.pop_back(); - return block; -} - -void recycle_transform_entries(std::vector& entries) noexcept { - for (auto& entry : entries) { - if (entry.transform.indexedMatrices && - s_indexedMatricesPool.size() < kMaximumPooledIndexedMatrices) { - s_indexedMatricesPool.push_back(std::move(entry.transform.indexedMatrices)); - } - } - entries.clear(); -} - -// Whether the frame in s_previousFrameTransforms recorded any palette draw; -// record_interpolation_draw uses it to decide whether staging can pay off. -bool s_previousFrameHasIndexedMatrices = false; - -// Hands the frame that just sealed to the next frame's matching and returns -// the retiring one's matrix blocks to the pool. -void retire_frame_transforms() noexcept { - s_previousFrameHasIndexedMatrices = - std::any_of(s_currentFrameTransforms.begin(), s_currentFrameTransforms.end(), - [](const FrameTransformEntry& entry) noexcept { - return static_cast(entry.transform.indexedMatrices); - }); - s_previousFrameTransforms.swap(s_currentFrameTransforms); - recycle_transform_entries(s_currentFrameTransforms); -} - -// clear() destroys every node, so empty the vectors in place and let a stable scene -// reuse them. Fall back to a real clear once the map outgrows the live set. -void clear_index_map_keep_nodes(std::unordered_map>& map, - size_t liveEntries) { - if (map.size() > liveEntries + 256) { - map.clear(); - return; - } - for (auto& entry : map) { - entry.second.clear(); - } -} -uint32_t s_perspectiveCandidates = 0; -// Candidates that also existed last frame. Freshly spawned effects have no partner -// by definition, so counting them measured spawn churn instead of matcher health. -uint32_t s_perspectiveMatchable = 0; -uint32_t s_perspectiveMatches = 0; -std::vector s_pendingUniformInterpolations; -std::atomic_bool s_hasInterpolatedFrame{false}; -std::atomic_bool s_frameInterpolationReplaySafe{true}; -uint32_t s_previousInterpolationFps = 0; - -// Adaptive slot count: the target moves at most one step per pacing window, while -// s_activeInterpolationSamples is latched per frame and must not move mid-frame. -std::atomic_uint32_t s_interpolationSampleTarget{0}; -std::atomic_uint32_t s_activeInterpolationSamples{0}; - -// Set when the producer already overran its retrace budget; the next seal then skips -// inserted slots for that one frame, which helps the late frame catch back up. -std::atomic_bool s_dropInterpolationAtSeal{false}; - -// Windowed backstop for sustained overload. The wide reduce/restore gap is the -// hysteresis, so a scene that can sustain N slots settles there instead of flapping. -std::atomic_uint32_t s_pacingWindowFrames{0}; -std::atomic_uint32_t s_pacingWindowMisses{0}; -constexpr uint32_t kPacingWindowFrames = 60; // ~1 second of guest frames -constexpr uint32_t kPacingReducePercent = 75; -constexpr uint32_t kPacingRestorePercent = 25; - -uint32_t maximum_interpolation_samples() noexcept { - const uint32_t targetFps = frame_interpolation_fps(); - if (targetFps == 0) { - return 0; - } - return std::min(targetFps / 60 - 1, MaxInterpolatedFrames); -} - -constexpr float kMinimumScale = 1.0e-5f; -constexpr float kMaximumTranslationPerFrame = 1500.0f; -constexpr float kMinimumQuaternionDot = 0.70710678f; -constexpr size_t kNoPreparedPair = std::numeric_limits::max(); - -HashType combine_identity(HashType first, HashType second) noexcept { - return xxh3_hash(second, first); -} - -HashType stable_identity(const FrameInterpolationDrawIdentity& identity) noexcept { - return combine_identity(combine_identity(identity.pipeline, identity.texture), - identity.matrixTopology); -} - -float dot3(const std::array& a, const std::array& b) noexcept { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; -} - -std::array cross3(const std::array& a, const std::array& b) noexcept { - return { - a[1] * b[2] - a[2] * b[1], - a[2] * b[0] - a[0] * b[2], - a[0] * b[1] - a[1] * b[0], - }; -} - -Quaternion quaternion_from_rotation(const std::array, 3>& m) noexcept { - Quaternion q; - const float trace = m[0][0] + m[1][1] + m[2][2]; - if (trace > 0.0f) { - const float s = std::sqrt(trace + 1.0f) * 2.0f; - q.w = 0.25f * s; - q.x = (m[2][1] - m[1][2]) / s; - q.y = (m[0][2] - m[2][0]) / s; - q.z = (m[1][0] - m[0][1]) / s; - } else if (m[0][0] > m[1][1] && m[0][0] > m[2][2]) { - const float s = std::sqrt(1.0f + m[0][0] - m[1][1] - m[2][2]) * 2.0f; - q.w = (m[2][1] - m[1][2]) / s; - q.x = 0.25f * s; - q.y = (m[0][1] + m[1][0]) / s; - q.z = (m[0][2] + m[2][0]) / s; - } else if (m[1][1] > m[2][2]) { - const float s = std::sqrt(1.0f + m[1][1] - m[0][0] - m[2][2]) * 2.0f; - q.w = (m[0][2] - m[2][0]) / s; - q.x = (m[0][1] + m[1][0]) / s; - q.y = 0.25f * s; - q.z = (m[1][2] + m[2][1]) / s; - } else { - const float s = std::sqrt(1.0f + m[2][2] - m[0][0] - m[1][1]) * 2.0f; - q.w = (m[1][0] - m[0][1]) / s; - q.x = (m[0][2] + m[2][0]) / s; - q.y = (m[1][2] + m[2][1]) / s; - q.z = 0.25f * s; - } - return q; -} - -bool decompose_affine(const Mat3x4& matrix, std::array, 3>& rotation, - std::array& scale, std::array& translation, - Quaternion& quaternion) noexcept { - const std::array, 3> rows{matrix.m0, matrix.m1, matrix.m2}; - // V*T*R*S puts non-uniform model scale on the columns, so scale must be read off the - // columns; row extraction misreads R*S as shear whenever the rotation tilts an axis. - for (size_t row = 0; row < 3; ++row) { - translation[row] = rows[row].w(); - if (!std::isfinite(translation[row])) { - return false; - } - } - for (size_t column = 0; column < 3; ++column) { - const float x = rows[0][column]; - const float y = rows[1][column]; - const float z = rows[2][column]; - scale[column] = std::sqrt(x * x + y * y + z * z); - if (!std::isfinite(scale[column]) || scale[column] < kMinimumScale) { - return false; - } - rotation[0][column] = x / scale[column]; - rotation[1][column] = y / scale[column]; - rotation[2][column] = z / scale[column]; - } - - const auto rotationColumn = [&rotation](size_t column) noexcept { - return std::array{rotation[0][column], rotation[1][column], rotation[2][column]}; - }; - if (std::abs(dot3(rotationColumn(0), rotationColumn(1))) > 0.05f || - std::abs(dot3(rotationColumn(0), rotationColumn(2))) > 0.05f || - std::abs(dot3(rotationColumn(1), rotationColumn(2))) > 0.05f) { - return false; - } - - const float determinant = dot3(rotation[0], cross3(rotation[1], rotation[2])); - if (!std::isfinite(determinant) || std::abs(std::abs(determinant) - 1.0f) > 0.1f) { - return false; - } - if (determinant < 0.0f) { - scale[0] = -scale[0]; - for (size_t row = 0; row < 3; ++row) { - rotation[row][0] = -rotation[row][0]; - } - } - - quaternion = quaternion_from_rotation(rotation); - return std::isfinite(quaternion.x) && std::isfinite(quaternion.y) && std::isfinite(quaternion.z) && - std::isfinite(quaternion.w); -} - -std::array, 3> rotation_from_quaternion(const Quaternion& q) noexcept { - const float xx = q.x * q.x; - const float yy = q.y * q.y; - const float zz = q.z * q.z; - const float xy = q.x * q.y; - const float xz = q.x * q.z; - const float yz = q.y * q.z; - const float wx = q.w * q.x; - const float wy = q.w * q.y; - const float wz = q.w * q.z; - return {{ - {{1.0f - 2.0f * (yy + zz), 2.0f * (xy - wz), 2.0f * (xz + wy)}}, - {{2.0f * (xy + wz), 1.0f - 2.0f * (xx + zz), 2.0f * (yz - wx)}}, - {{2.0f * (xz - wy), 2.0f * (yz + wx), 1.0f - 2.0f * (xx + yy)}}, - }}; -} - -struct PreparedAffinePair { - Mat3x4 previous{}; - Mat3x4 current{}; - std::array previousScale{}; - std::array currentScale{}; - std::array previousTranslation{}; - std::array currentTranslation{}; - Quaternion previousQuaternion{}; - Quaternion currentQuaternion{}; - bool linear = false; - bool identical = false; - bool valid = false; -}; - -struct PreparedTransformInterpolation { - size_t nonIndexedPairOffset = kNoPreparedPair; - std::array indexedPairOffsets{}; - // Previous-frame entry the projection interpolates from. For a draw that borrowed - // its matrices from a sibling, that is the sibling's partner. - size_t previousProjectionEntry = kNoPreparedPair; - bool indexedValid = false; - - PreparedTransformInterpolation() { - indexedPairOffsets.fill(kNoPreparedPair); - } -}; - -PreparedAffinePair prepare_affine_pair(const Mat3x4& previous, - const Mat3x4& current) noexcept { - PreparedAffinePair pair{.previous = previous, .current = current}; - if (std::memcmp(&previous, ¤t, sizeof(current)) == 0) { - pair.identical = true; - pair.valid = true; - return pair; - } - - std::array, 3> previousRotation{}; - std::array, 3> currentRotation{}; - if (!decompose_affine(previous, previousRotation, pair.previousScale, - pair.previousTranslation, pair.previousQuaternion) || - !decompose_affine(current, currentRotation, pair.currentScale, - pair.currentTranslation, pair.currentQuaternion)) { - return pair; - } - - float translationDeltaSquared = 0.0f; - for (size_t i = 0; i < 3; ++i) { - const float delta = pair.currentTranslation[i] - pair.previousTranslation[i]; - translationDeltaSquared += delta * delta; - } - if (!std::isfinite(translationDeltaSquared) || - translationDeltaSquared > kMaximumTranslationPerFrame * kMaximumTranslationPerFrame) { - return pair; - } - - float quaternionDot = pair.previousQuaternion.x * pair.currentQuaternion.x + - pair.previousQuaternion.y * pair.currentQuaternion.y + - pair.previousQuaternion.z * pair.currentQuaternion.z + - pair.previousQuaternion.w * pair.currentQuaternion.w; - if (quaternionDot < 0.0f) { - pair.currentQuaternion.x = -pair.currentQuaternion.x; - pair.currentQuaternion.y = -pair.currentQuaternion.y; - pair.currentQuaternion.z = -pair.currentQuaternion.z; - pair.currentQuaternion.w = -pair.currentQuaternion.w; - quaternionDot = -quaternionDot; - } - if (!std::isfinite(quaternionDot) || quaternionDot < kMinimumQuaternionDot) { - return pair; - } - pair.valid = true; - return pair; -} - -// Indexed matrices are final palette transforms, so interpolate coefficients instead -// of decomposing: ((1-t)M0 + tM1)v keeps a shared mesh boundary shared. -PreparedAffinePair prepare_indexed_pair(const Mat3x4& previous, - const Mat3x4& current) noexcept { - PreparedAffinePair pair{ - .previous = previous, - .current = current, - .linear = true, - }; - if (std::memcmp(&previous, ¤t, sizeof(current)) == 0) { - pair.identical = true; - pair.valid = true; - return pair; - } - - const std::array, 3> previousRows{previous.m0, previous.m1, previous.m2}; - const std::array, 3> currentRows{current.m0, current.m1, current.m2}; - for (size_t row = 0; row < 3; ++row) { - for (size_t column = 0; column < 4; ++column) { - if (!std::isfinite(previousRows[row][column]) || - !std::isfinite(currentRows[row][column])) { - return pair; - } - } - } - - const float dx = current.m0.w() - previous.m0.w(); - const float dy = current.m1.w() - previous.m1.w(); - const float dz = current.m2.w() - previous.m2.w(); - const float translationDeltaSquared = dx * dx + dy * dy + dz * dz; - if (!(translationDeltaSquared <= - kMaximumTranslationPerFrame * kMaximumTranslationPerFrame)) { - return pair; - } - pair.valid = true; - return pair; -} - -bool evaluate_affine_pair(const PreparedAffinePair& pair, float weight, - Mat3x4& output) noexcept { - if (!pair.valid || pair.identical) { - output = pair.current; - return pair.valid; - } - - if (pair.linear) { - const std::array*, 3> previousRows{ - &pair.previous.m0, &pair.previous.m1, &pair.previous.m2}; - const std::array*, 3> currentRows{ - &pair.current.m0, &pair.current.m1, &pair.current.m2}; - const std::array*, 3> outputRows{&output.m0, &output.m1, &output.m2}; - for (size_t row = 0; row < 3; ++row) { - for (size_t column = 0; column < 4; ++column) { - const float before = (*previousRows[row])[column]; - (*outputRows[row])[column] = - before + ((*currentRows[row])[column] - before) * weight; - } - } - return true; - } - - // Consecutive 60 Hz transforms stay in one hemisphere and within 90 degrees, so - // normalized lerp is stable and skips three transcendentals per matrix. - const float previousWeight = 1.0f - weight; - const float currentWeight = weight; - Quaternion interpolated{ - pair.previousQuaternion.x * previousWeight + pair.currentQuaternion.x * currentWeight, - pair.previousQuaternion.y * previousWeight + pair.currentQuaternion.y * currentWeight, - pair.previousQuaternion.z * previousWeight + pair.currentQuaternion.z * currentWeight, - pair.previousQuaternion.w * previousWeight + pair.currentQuaternion.w * currentWeight, - }; - const float quaternionLength = std::sqrt(interpolated.x * interpolated.x + - interpolated.y * interpolated.y + - interpolated.z * interpolated.z + - interpolated.w * interpolated.w); - if (!std::isfinite(quaternionLength) || quaternionLength < kMinimumScale) { - output = pair.current; - return false; - } - interpolated.x /= quaternionLength; - interpolated.y /= quaternionLength; - interpolated.z /= quaternionLength; - interpolated.w /= quaternionLength; - - const auto interpolatedRotation = rotation_from_quaternion(interpolated); - std::array interpolatedScale{}; - std::array interpolatedTranslation{}; - for (size_t i = 0; i < 3; ++i) { - interpolatedScale[i] = pair.previousScale[i] + - (pair.currentScale[i] - pair.previousScale[i]) * weight; - interpolatedTranslation[i] = - pair.previousTranslation[i] + - (pair.currentTranslation[i] - pair.previousTranslation[i]) * weight; - } - // Column scale mirrors decompose_affine: the reconstruction is R*S, with - // each scale component applied down its column. - output = { - {interpolatedRotation[0][0] * interpolatedScale[0], - interpolatedRotation[0][1] * interpolatedScale[1], - interpolatedRotation[0][2] * interpolatedScale[2], interpolatedTranslation[0]}, - {interpolatedRotation[1][0] * interpolatedScale[0], - interpolatedRotation[1][1] * interpolatedScale[1], - interpolatedRotation[1][2] * interpolatedScale[2], interpolatedTranslation[1]}, - {interpolatedRotation[2][0] * interpolatedScale[0], - interpolatedRotation[2][1] * interpolatedScale[1], - interpolatedRotation[2][2] * interpolatedScale[2], interpolatedTranslation[2]}, - }; - return true; -} - -bool interpolate_affine_impl(const Mat3x4& previous, const Mat3x4& current, - float weight, Mat3x4& output) noexcept { - return evaluate_affine_pair(prepare_affine_pair(previous, current), weight, output); -} - -Mat4x4 interpolate_projection(const Mat4x4& previous, const Mat4x4& current, - float weight) noexcept { - Mat4x4 result = current; - for (size_t row = 0; row < 4; ++row) { - for (size_t column = 0; column < 4; ++column) { - const float before = previous[row][column]; - const float after = current[row][column]; - if (std::isfinite(before) && std::isfinite(after)) { - result[row][column] = before + (after - before) * weight; - } - } - } - return result; -} -} // namespace - -bool interpolate_transform(const Mat3x4& previous, const Mat3x4& current, - float weight, Mat3x4& output) noexcept { - return interpolate_affine_impl(previous, current, std::clamp(weight, 0.0f, 1.0f), output); -} - -bool interpolate_transform_midpoint(const Mat3x4& previous, const Mat3x4& current, - Mat3x4& output) noexcept { - return interpolate_transform(previous, current, 0.5f, output); -} - -bool interpolate_indexed_transform(const Mat3x4& previous, - const Mat3x4& current, float weight, - Mat3x4& output) noexcept { - return evaluate_affine_pair(prepare_indexed_pair(previous, current), - std::clamp(weight, 0.0f, 1.0f), output); -} - -float transform_match_distance_squared(const Mat3x4& previous, - const Mat3x4& current) noexcept { - // Translation dominates in game units; the 3x3 part only breaks ties between - // repeated meshes at the same origin. - double distance = 0.0; - const std::array, 3> previousRows{previous.m0, previous.m1, previous.m2}; - const std::array, 3> currentRows{current.m0, current.m1, current.m2}; - for (size_t row = 0; row < 3; ++row) { - for (size_t column = 0; column < 4; ++column) { - const double before = previousRows[row][column]; - const double after = currentRows[row][column]; - if (!std::isfinite(before) || !std::isfinite(after)) { - return std::numeric_limits::infinity(); - } - const double delta = after - before; - distance += delta * delta; - } - } - if (!std::isfinite(distance) || distance > std::numeric_limits::max()) { - return std::numeric_limits::infinity(); - } - return static_cast(distance); -} - -namespace { -// Translation-only delta, matching the kMaximumTranslationPerFrame gate. Non-finite -// inputs propagate NaN; callers compare with `<=` so NaN fails the gate. -float translation_delta_squared(const Mat3x4& previous, - const Mat3x4& current) noexcept { - const float dx = current.m0.w() - previous.m0.w(); - const float dy = current.m1.w() - previous.m1.w(); - const float dz = current.m2.w() - previous.m2.w(); - return dx * dx + dy * dy + dz * dz; -} - -// 2*current - previous. Not a valid rigid transform, but it is only a matching -// reference and its one-frame error stays far below instance spacing. -Mat3x4 extrapolate_transform(const Mat3x4& previous, - const Mat3x4& current) noexcept { - Mat3x4 predicted{}; - const std::array*, 3> previousRows{&previous.m0, &previous.m1, &previous.m2}; - const std::array*, 3> currentRows{¤t.m0, ¤t.m1, ¤t.m2}; - const std::array*, 3> predictedRows{&predicted.m0, &predicted.m1, &predicted.m2}; - for (size_t row = 0; row < 3; ++row) { - for (size_t column = 0; column < 4; ++column) { - (*predictedRows[row])[column] = - 2.0f * (*currentRows[row])[column] - (*previousRows[row])[column]; - } - } - return predicted; -} -} // namespace - -float snapshot_match_distance_squared(const FrameTransformEntry& previousEntry, - const FrameTransformSnapshot& current) noexcept { - const FrameTransformSnapshot& previous = previousEntry.transform; - if (static_cast(previous.indexedMatrices) != static_cast(current.indexedMatrices)) { - return std::numeric_limits::infinity(); - } - if (!current.indexedMatrices) { - // Match against the predicted position, falling back to the last known one for - // entries with no motion history. - const Mat3x4& reference = - previousEntry.hasPrediction ? previousEntry.predictedPosition : previous.position; - return transform_match_distance_squared(reference, current.position); - } - - if (previous.usedMatrixMask == 0 || current.usedMatrixMask == 0) { - return std::numeric_limits::infinity(); - } - - // PNMTXIDX is an absolute palette slot baked into the vertices, so nearest matching - // swaps joint histories. A changed mask has no safe correspondence: leave the draw. - if (previous.usedMatrixMask != current.usedMatrixMask) { - return std::numeric_limits::infinity(); - } - - double distance = 0.0; - size_t matchedMatrices = 0; - for (size_t currentIndex = 0; currentIndex < MaxPnMtx; ++currentIndex) { - if ((current.usedMatrixMask & (1u << currentIndex)) == 0) { - continue; - } - const float matrixDistance = transform_match_distance_squared( - previous.indexedMatrices->position[currentIndex], - current.indexedMatrices->position[currentIndex]); - if (!std::isfinite(matrixDistance)) { - return std::numeric_limits::infinity(); - } - distance += matrixDistance; - ++matchedMatrices; - } - if (matchedMatrices == 0 || !std::isfinite(distance) || - distance > std::numeric_limits::max()) { - return std::numeric_limits::infinity(); - } - return static_cast(distance / static_cast(matchedMatrices)); -} - -void set_frame_interpolation_fps(uint32_t targetFps) noexcept { - if (targetFps != 120 && targetFps != 180 && targetFps != 240) { - targetFps = 0; - } - detail::g_frameInterpolationFps.store(targetFps, std::memory_order_release); - // Start at the configured quality; the controller only ever backs off from here. - s_interpolationSampleTarget.store(targetFps == 0 ? 0u : std::min(targetFps / 60 - 1, MaxInterpolatedFrames), - std::memory_order_release); - s_dropInterpolationAtSeal.store(false, std::memory_order_release); - s_pacingWindowFrames.store(0, std::memory_order_release); - s_pacingWindowMisses.store(0, std::memory_order_release); - // A reconfiguration starts a fresh diagnostic window. - s_diagFramesSealed.store(0, std::memory_order_relaxed); - s_diagFramesLowMatch.store(0, std::memory_order_relaxed); - s_diagFramesReplayUnsafe.store(0, std::memory_order_relaxed); - s_diagSlotReductions.store(0, std::memory_order_relaxed); - s_diagLateSealDrops.store(0, std::memory_order_relaxed); -} - -void report_producer_paced(bool paced) noexcept { - const uint32_t maximumSamples = maximum_interpolation_samples(); - if (maximumSamples == 0) { - s_dropInterpolationAtSeal.store(false, std::memory_order_release); - s_pacingWindowFrames.store(0, std::memory_order_release); - s_pacingWindowMisses.store(0, std::memory_order_release); - s_interpolationSampleTarget.store(0, std::memory_order_release); - return; - } - - // Per-frame decision, no streaks: a late frame seals without its inserted slots and - // the next one is back at full count. See s_dropInterpolationAtSeal. - s_dropInterpolationAtSeal.store(!paced, std::memory_order_release); - - const uint32_t frames = s_pacingWindowFrames.load(std::memory_order_acquire) + 1; - const uint32_t misses = - s_pacingWindowMisses.load(std::memory_order_acquire) + (paced ? 0u : 1u); - if (frames < kPacingWindowFrames) { - s_pacingWindowFrames.store(frames, std::memory_order_release); - s_pacingWindowMisses.store(misses, std::memory_order_release); - return; - } - // Window complete: adjust the target one step at most, then start over. At - // one decision per window this cannot spam the log or flap within a second. - uint32_t target = - std::min(s_interpolationSampleTarget.load(std::memory_order_acquire), maximumSamples); - if (misses * 100u >= frames * kPacingReducePercent) { - if (target > 0) { - --target; - s_diagSlotReductions.fetch_add(1, std::memory_order_relaxed); - Log.info("interpolation slots reduced to {}: {}/{} frames overran their retrace budget", - target, misses, frames); - } - } else if (misses * 100u <= frames * kPacingRestorePercent) { - if (target < maximumSamples) { - ++target; - Log.info("interpolation slots restored to {}: {}/{} frames overran their retrace budget", - target, misses, frames); - } - } - s_interpolationSampleTarget.store(target, std::memory_order_release); - s_pacingWindowFrames.store(0, std::memory_order_release); - s_pacingWindowMisses.store(0, std::memory_order_release); -} - -void begin_frame_interpolation() noexcept { - const uint32_t targetFps = frame_interpolation_fps(); - if (targetFps != s_previousInterpolationFps) { - recycle_transform_entries(s_previousFrameTransforms); - s_previousInterpolationFps = targetFps; - } - // Latch the slot count for the frame starting here; see s_activeInterpolationSamples - // for why it cannot move again until the seal. - s_activeInterpolationSamples.store( - std::min(s_interpolationSampleTarget.load(std::memory_order_acquire), - maximum_interpolation_samples()), - std::memory_order_release); - // Normally empty (finalize swapped and recycled); an aborted frame can leave - // entries behind, whose matrix blocks go back to the pool here. - recycle_transform_entries(s_currentFrameTransforms); - // Keep buckets, nodes and capacities across frames so a stable race scene does not - // pay thousands of small allocations every frame. - clear_index_map_keep_nodes(s_previousTransformIndices, s_previousFrameTransforms.size()); - clear_index_map_keep_nodes(s_previousStableTransformIndices, s_previousFrameTransforms.size()); - for (size_t i = 0; i < s_previousFrameTransforms.size(); ++i) { - const auto& identity = s_previousFrameTransforms[i].identity; - s_previousTransformIndices[identity.combined].push_back(i); - s_previousStableTransformIndices[stable_identity(identity)].push_back(i); - } - clear_index_map_keep_nodes(s_currentTransformIndices, s_previousFrameTransforms.size()); - clear_index_map_keep_nodes(s_currentStableTransformIndices, s_previousFrameTransforms.size()); - s_pendingUniformInterpolations.clear(); - s_perspectiveCandidates = 0; - s_perspectiveMatchable = 0; - s_perspectiveMatches = 0; - s_hasInterpolatedFrame.store(false, std::memory_order_release); - s_frameInterpolationReplaySafe.store(true, std::memory_order_release); -} - -void finalize_frame_interpolation() noexcept { - // A frame reported late seals without inserted slots, so the encode phase renders - // the native frame only. Its transforms still seed the next frame's matching. - if (s_dropInterpolationAtSeal.exchange(false, std::memory_order_acq_rel)) { - s_diagLateSealDrops.fetch_add(1, std::memory_order_relaxed); - s_hasInterpolatedFrame.store(false, std::memory_order_release); - s_pendingUniformInterpolations.clear(); - retire_frame_transforms(); - return; - } - // Below this bound a direct all-pairs build is cheaper than setting up the - // spatial grid; the produced edge set is identical either way. - constexpr size_t kAllPairsEdgeLimit = 1024; - // Bounds the all-pairs cost for indexed groups, which have no single translation to - // bucket on. Non-indexed groups of any size use the grid instead. - constexpr size_t kMaximumAssignmentEdges = 16384; - // Hard bound for the grid path; only a swarm co-located within one cell reaches it, - // which is the CPU-deformed shape the ordered fallback exists for. - constexpr size_t kMaximumGridEdges = 65536; - - struct MatchEdge { - float distance = std::numeric_limits::infinity(); - size_t previous = SIZE_MAX; - size_t current = SIZE_MAX; - }; - - // Frame-persistent matching scratch: sized to the frame's draw count, so a - // stable scene performs no matching allocations at all after warm-up. - static std::vector currentToPrevious; - static std::vector previousMatched; - static std::vector currentMatched; - static std::vector groupCurrentIndices; - static std::vector groupPreviousIndices; - static std::vector edges; - static std::unordered_map> gridCells; - currentToPrevious.assign(s_currentFrameTransforms.size(), SIZE_MAX); - previousMatched.assign(s_previousFrameTransforms.size(), 0); - currentMatched.assign(s_currentFrameTransforms.size(), 0); - - // Quantizes a translation onto the matching grid. Cell size equals the gate distance, - // so every acceptable pair lies within one cell along every axis. - constexpr uint64_t kInvalidCell = std::numeric_limits::max(); - const auto translation_cell = [](const Mat3x4& m) noexcept -> uint64_t { - const float x = m.m0.w(); - const float y = m.m1.w(); - const float z = m.m2.w(); - if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(z)) { - return kInvalidCell; - } - constexpr float kInverseCell = 1.0f / kMaximumTranslationPerFrame; - constexpr int64_t kBias = int64_t{1} << 20; - const int64_t cx = static_cast(std::floor(x * kInverseCell)) + kBias; - const int64_t cy = static_cast(std::floor(y * kInverseCell)) + kBias; - const int64_t cz = static_cast(std::floor(z * kInverseCell)) + kBias; - // One cell of margin at each field edge so the +-1 neighbor arithmetic cannot borrow - // into the next packed coordinate. - if (cx < 1 || cy < 1 || cz < 1 || cx >= (kBias << 1) - 1 || cy >= (kBias << 1) - 1 || - cz >= (kBias << 1) - 1) { - return kInvalidCell; - } - return (static_cast(cx) << 42) | (static_cast(cy) << 21) | - static_cast(cz); - }; - - const auto matchGroups = - [&](const auto& currentGroups, const auto& previousGroups, - bool allowOrderedFallback) { - for (const auto& [signature, allCurrentIndices] : currentGroups) { - if (allCurrentIndices.empty()) { - continue; - } - const auto previousIt = previousGroups.find(signature); - if (previousIt == previousGroups.end() || previousIt->second.empty()) { - continue; - } - groupCurrentIndices.clear(); - groupPreviousIndices.clear(); - for (const size_t index : allCurrentIndices) { - if (!currentMatched[index]) { - groupCurrentIndices.push_back(index); - } - } - for (const size_t index : previousIt->second) { - if (!previousMatched[index]) { - groupPreviousIndices.push_back(index); - } - } - if (groupCurrentIndices.empty() || groupPreviousIndices.empty()) { - continue; - } - - // A unique draw has no identity ambiguity. Keep the conservative - // interpolation fallback for malformed/non-finite matrices. - if (groupPreviousIndices.size() == 1 && groupCurrentIndices.size() == 1) { - currentToPrevious[groupCurrentIndices.front()] = groupPreviousIndices.front(); - previousMatched[groupPreviousIndices.front()] = 1; - currentMatched[groupCurrentIndices.front()] = 1; - continue; - } - - // Drop pairs past the translation gate (`<=` also drops a NaN delta): they can only - // render as a snap, and matching them steals a neighbor's true partner. - const auto appendEdge = [&](size_t previousIndex, size_t currentIndex) { - const auto& previousEntry = s_previousFrameTransforms[previousIndex]; - const auto& currentSnapshot = s_currentFrameTransforms[currentIndex].transform; - if (!previousEntry.transform.indexedMatrices && !currentSnapshot.indexedMatrices && - !(translation_delta_squared(previousEntry.transform.position, - currentSnapshot.position) <= - kMaximumTranslationPerFrame * kMaximumTranslationPerFrame)) { - return; - } - const float distance = snapshot_match_distance_squared(previousEntry, currentSnapshot); - if (std::isfinite(distance)) { - edges.push_back({ - .distance = distance, - .previous = previousIndex, - .current = currentIndex, - }); - } - }; - - const auto orderedFallback = [&] { - // GX preserves submission order for these draws, so pair the leftovers in order - // once exact identities have claimed their instances. - if (!allowOrderedFallback) { - return; - } - const size_t pairCount = std::min(groupPreviousIndices.size(), groupCurrentIndices.size()); - for (size_t i = 0; i < pairCount; ++i) { - // Submission order shifts when the transparent sort reorders or culling drops an - // instance; leave over-gate pairs unmatched so they snap instead of sweeping. - const auto& previousEntry = s_previousFrameTransforms[groupPreviousIndices[i]]; - const auto& currentEntry = s_currentFrameTransforms[groupCurrentIndices[i]]; - if (!previousEntry.transform.indexedMatrices && - !currentEntry.transform.indexedMatrices && - !(translation_delta_squared(previousEntry.transform.position, - currentEntry.transform.position) <= - kMaximumTranslationPerFrame * kMaximumTranslationPerFrame)) { - continue; - } - currentToPrevious[groupCurrentIndices[i]] = groupPreviousIndices[i]; - previousMatched[groupPreviousIndices[i]] = 1; - currentMatched[groupCurrentIndices[i]] = 1; - } - }; - - edges.clear(); - const size_t allPairsEdges = groupPreviousIndices.size() * groupCurrentIndices.size(); - if (allPairsEdges <= kAllPairsEdgeLimit) { - for (const size_t currentIndex : groupCurrentIndices) { - for (const size_t previousIndex : groupPreviousIndices) { - appendEdge(previousIndex, currentIndex); - } - } - } else { - // Grid buckets need one translation per entry, which mixed or skinned groups lack, - // so those stay on the bounded all-pairs path. - bool gridable = true; - for (const size_t index : groupCurrentIndices) { - if (s_currentFrameTransforms[index].transform.indexedMatrices) { - gridable = false; - break; - } - } - if (gridable) { - for (const size_t index : groupPreviousIndices) { - if (s_previousFrameTransforms[index].transform.indexedMatrices) { - gridable = false; - break; - } - } - } - if (!gridable) { - if (groupPreviousIndices.size() > kMaximumAssignmentEdges / groupCurrentIndices.size()) { - orderedFallback(); - continue; - } - for (const size_t currentIndex : groupCurrentIndices) { - for (const size_t previousIndex : groupPreviousIndices) { - appendEdge(previousIndex, currentIndex); - } - } - } else { - // Previous entries are matched against their predicted position, so bucket them by - // that same reference (see snapshot_match_distance_squared). - gridCells.clear(); - for (const size_t previousIndex : groupPreviousIndices) { - const auto& previousEntry = s_previousFrameTransforms[previousIndex]; - const Mat3x4& reference = previousEntry.hasPrediction - ? previousEntry.predictedPosition - : previousEntry.transform.position; - const uint64_t cell = translation_cell(reference); - if (cell == kInvalidCell) { - continue; - } - gridCells[cell].push_back(static_cast(previousIndex)); - } - bool overflowed = false; - for (const size_t currentIndex : groupCurrentIndices) { - const auto& position = s_currentFrameTransforms[currentIndex].transform.position; - const uint64_t cell = translation_cell(position); - if (cell == kInvalidCell) { - continue; - } - for (int64_t dx = -1; dx <= 1 && !overflowed; ++dx) { - for (int64_t dy = -1; dy <= 1 && !overflowed; ++dy) { - for (int64_t dz = -1; dz <= 1 && !overflowed; ++dz) { - const uint64_t neighbor = cell + (static_cast(dx) << 42) + - (static_cast(dy) << 21) + - static_cast(dz); - const auto cellIt = gridCells.find(neighbor); - if (cellIt == gridCells.end()) { - continue; - } - for (const uint32_t previousIndex : cellIt->second) { - appendEdge(previousIndex, currentIndex); - if (edges.size() > kMaximumGridEdges) { - overflowed = true; - break; - } - } - } - } - } - if (overflowed) { - break; - } - } - if (overflowed) { - orderedFallback(); - continue; - } - } - } - - std::sort(edges.begin(), edges.end(), [](const MatchEdge& lhs, const MatchEdge& rhs) { - return lhs.distance < rhs.distance; - }); - for (const auto& edge : edges) { - if (previousMatched[edge.previous] || currentMatched[edge.current]) { - continue; - } - currentToPrevious[edge.current] = edge.previous; - previousMatched[edge.previous] = 1; - currentMatched[edge.current] = 1; - } - } - }; - matchGroups(s_currentTransformIndices, s_previousTransformIndices, false); - matchGroups(s_currentStableTransformIndices, s_previousStableTransformIndices, true); - - s_perspectiveMatches = static_cast(std::count_if( - currentToPrevious.begin(), currentToPrevious.end(), - [](size_t previousIndex) { return previousIndex != SIZE_MAX; })); - // Interpolation never pauses on match quality: an unmatched draw just renders its - // end-frame state, while a ratio gate flapped the whole output cadence instead. - const bool eligible = frame_interpolation_fps() != 0; - - // Overlay observability: the live match ratio, and how often the scene sits in - // low-match territory where inserted slots mostly duplicate draws. - { - constexpr uint32_t kLowMatchPercent = 55; - const bool replaySafe = frame_interpolation_replay_safe(); - s_diagCandidates.store(s_perspectiveCandidates, std::memory_order_relaxed); - s_diagMatchable.store(s_perspectiveMatchable, std::memory_order_relaxed); - s_diagMatches.store(s_perspectiveMatches, std::memory_order_relaxed); - s_diagEligible.store(eligible, std::memory_order_relaxed); - s_diagReplaySafe.store(replaySafe, std::memory_order_relaxed); - if (eligible) { - s_diagFramesSealed.fetch_add(1, std::memory_order_relaxed); - if (s_perspectiveMatchable != 0 && - s_perspectiveMatches * 100 < s_perspectiveMatchable * kLowMatchPercent) { - s_diagFramesLowMatch.fetch_add(1, std::memory_order_relaxed); - } - if (!replaySafe) { - s_diagFramesReplayUnsafe.fetch_add(1, std::memory_order_relaxed); - } - } - } - - // Only ordinary one-matrix draws use motion prediction. Indexed draws keep the slot - // identity encoded by PNMTXIDX and are prepared as one coherent draw below. - constexpr float kMaximumPredictionSeedDeltaSquared = - kMaximumTranslationPerFrame * kMaximumTranslationPerFrame; - for (size_t currentIndex = 0; currentIndex < currentToPrevious.size(); ++currentIndex) { - const size_t previousIndex = currentToPrevious[currentIndex]; - if (previousIndex == SIZE_MAX) { - continue; - } - auto& currentEntry = s_currentFrameTransforms[currentIndex]; - const auto& previousEntry = s_previousFrameTransforms[previousIndex]; - if (currentEntry.transform.indexedMatrices || previousEntry.transform.indexedMatrices) { - continue; - } - // Seed the next frame's matching with a constant-velocity reference, but never from - // a pair the interpolator would reject as a teleport (`<=` so NaN fails too). - if (translation_delta_squared(previousEntry.transform.position, - currentEntry.transform.position) <= - kMaximumPredictionSeedDeltaSquared) { - currentEntry.predictedPosition = extrapolate_transform(previousEntry.transform.position, - currentEntry.transform.position); - currentEntry.hasPrediction = true; - } - } - - if (eligible) { - // Prepare each matched pair once: every sample of a draw shares the same - // previous/current matrices. A flat vector keeps the sample tasks parallel. - std::vector preparedTransforms(s_currentFrameTransforms.size()); - std::vector preparedTransformState(s_currentFrameTransforms.size(), 0); - std::vector preparedPairs; - preparedPairs.reserve(s_pendingUniformInterpolations.size() * 2); - - const auto appendPreparedPair = [&](const Mat3x4& previousPosition, - const Mat3x4& currentPosition, - const Mat3x4& previousNormal, - const Mat3x4& currentNormal, - bool indexed) { - const size_t pairOffset = preparedPairs.size(); - preparedPairs.push_back(indexed ? prepare_indexed_pair(previousPosition, currentPosition) - : prepare_affine_pair(previousPosition, currentPosition)); - preparedPairs.push_back(indexed ? prepare_indexed_pair(previousNormal, currentNormal) - : prepare_affine_pair(previousNormal, currentNormal)); - return pairOffset; - }; - - // Content-keyed palette pairing: a mesh split across draws repeats bone matrices byte - // for byte, so a chunk with no partner of its own can borrow a sibling's. - static std::vector paletteDrawIndex; // draw -> compact palette index - static std::vector paletteDraws; // compact palette index -> draw - paletteDrawIndex.assign(s_currentFrameTransforms.size(), -1); - paletteDraws.clear(); - for (size_t drawIndex = 0; drawIndex < s_currentFrameTransforms.size(); ++drawIndex) { - const auto& transform = s_currentFrameTransforms[drawIndex].transform; - if (!transform.indexedMatrices || transform.usedMatrixMask == 0) { - continue; - } - paletteDrawIndex[drawIndex] = static_cast(paletteDraws.size()); - paletteDraws.push_back(static_cast(drawIndex)); - } - - struct PaletteSlotKey { - HashType hash = 0; - uint32_t palette = 0; - uint32_t slot = 0; - }; - struct ResolvedSlot { - const Mat3x4* position = nullptr; - const Mat3x4* normal = nullptr; - }; - static std::vector paletteSlotKeys; - static std::vector resolvedSlots; - static std::vector resolvedProjectionEntry; - paletteSlotKeys.clear(); - resolvedSlots.assign(paletteDraws.size() * MaxPnMtx, ResolvedSlot{}); - resolvedProjectionEntry.assign(paletteDraws.size(), kNoPreparedPair); - - for (uint32_t palette = 0; palette < paletteDraws.size(); ++palette) { - const auto& transform = s_currentFrameTransforms[paletteDraws[palette]].transform; - for (uint32_t slot = 0; slot < MaxPnMtx; ++slot) { - if ((transform.usedMatrixMask & (1u << slot)) == 0) { - continue; - } - paletteSlotKeys.push_back({combine_identity(transform.indexedMatrices->slotHash[slot], - transform.viewportIdentity), palette, slot}); - } - } - std::sort(paletteSlotKeys.begin(), paletteSlotKeys.end(), - [](const PaletteSlotKey& lhs, const PaletteSlotKey& rhs) { - if (lhs.hash != rhs.hash) { - return lhs.hash < rhs.hash; - } - if (lhs.palette != rhs.palette) { - return lhs.palette < rhs.palette; - } - return lhs.slot < rhs.slot; - }); - - for (size_t runStart = 0; runStart < paletteSlotKeys.size();) { - size_t runEnd = runStart + 1; - while (runEnd < paletteSlotKeys.size() && - paletteSlotKeys[runEnd].hash == paletteSlotKeys[runStart].hash) { - ++runEnd; - } - // Where this matrix was last frame, per the draws that did match. Partners that - // disagree mean no single previous pose, so the coupled unit duplicates. - const Mat3x4* sourcePosition = nullptr; - const Mat3x4* sourceNormal = nullptr; - size_t sourceEntry = kNoPreparedPair; - HashType sourceHash = 0; - bool ambiguous = false; - for (size_t keyIndex = runStart; keyIndex < runEnd && !ambiguous; ++keyIndex) { - const uint32_t drawIndex = paletteDraws[paletteSlotKeys[keyIndex].palette]; - const size_t previousIndex = currentToPrevious[drawIndex]; - if (previousIndex >= s_previousFrameTransforms.size()) { - continue; - } - const auto& current = s_currentFrameTransforms[drawIndex].transform; - const auto& previous = s_previousFrameTransforms[previousIndex].transform; - // A slot index is an absolute palette address, which is why it pairs matched draws - // and why a changed layout invalidates every slot as a source. - if (!previous.indexedMatrices || previous.usedMatrixMask != current.usedMatrixMask) { - continue; - } - const uint32_t slot = paletteSlotKeys[keyIndex].slot; - const HashType candidateHash = previous.indexedMatrices->slotHash[slot]; - if (sourcePosition == nullptr) { - sourcePosition = &previous.indexedMatrices->position[slot]; - sourceNormal = &previous.indexedMatrices->normal[slot]; - sourceHash = candidateHash; - sourceEntry = previousIndex; - } else if (candidateHash != sourceHash) { - ambiguous = true; - } - } - if (ambiguous || sourcePosition == nullptr) { - runStart = runEnd; - continue; - } - for (size_t keyIndex = runStart; keyIndex < runEnd; ++keyIndex) { - const auto& key = paletteSlotKeys[keyIndex]; - resolvedSlots[static_cast(key.palette) * MaxPnMtx + key.slot] = {sourcePosition, - sourceNormal}; - if (resolvedProjectionEntry[key.palette] == kNoPreparedPair) { - resolvedProjectionEntry[key.palette] = sourceEntry; - } - } - runStart = runEnd; - } - - for (const auto& task : s_pendingUniformInterpolations) { - if (task.currentTransformIndex >= preparedTransformState.size() || - preparedTransformState[task.currentTransformIndex] != 0) { - continue; - } - preparedTransformState[task.currentTransformIndex] = 1; - - const auto& current = s_currentFrameTransforms[task.currentTransformIndex].transform; - auto& prepared = preparedTransforms[task.currentTransformIndex]; - if (task.indexedMatrices) { - const int32_t palette = paletteDrawIndex[task.currentTransformIndex]; - if (palette < 0) { - continue; - } - prepared.previousProjectionEntry = resolvedProjectionEntry[palette]; - // A palette is one deformation unit: interpolating only the resolved slots cracks - // the mesh, so any unresolved slot duplicates the whole current draw. - bool allSlotsValid = true; - for (size_t slot = 0; slot < MaxPnMtx; ++slot) { - if ((current.usedMatrixMask & (1u << slot)) == 0) { - continue; - } - const auto& resolved = resolvedSlots[static_cast(palette) * MaxPnMtx + slot]; - if (resolved.position == nullptr) { - allSlotsValid = false; - break; - } - const size_t pairOffset = - appendPreparedPair(*resolved.position, current.indexedMatrices->position[slot], - *resolved.normal, current.indexedMatrices->normal[slot], true); - prepared.indexedPairOffsets[slot] = pairOffset; - if (!preparedPairs[pairOffset].valid || !preparedPairs[pairOffset + 1].valid) { - allSlotsValid = false; - break; - } - } - prepared.indexedValid = allSlotsValid; - } else { - const size_t previousTransformIndex = currentToPrevious[task.currentTransformIndex]; - if (previousTransformIndex >= s_previousFrameTransforms.size()) { - continue; - } - const auto& previous = s_previousFrameTransforms[previousTransformIndex].transform; - prepared.previousProjectionEntry = previousTransformIndex; - prepared.nonIndexedPairOffset = appendPreparedPair( - previous.position, current.position, previous.normal, current.normal, false); - } - } - - const auto interpolatePendingUniform = [&](const auto& task) { - if (task.currentTransformIndex >= s_currentFrameTransforms.size()) { - return; - } - - const auto& current = s_currentFrameTransforms[task.currentTransformIndex].transform; - std::memcpy(task.uniformData, task.sourceUniformData, task.uniformSize); - const auto& prepared = preparedTransforms[task.currentTransformIndex]; - if (task.indexedMatrices && !prepared.indexedValid) { - return; - } - // The projection comes from whichever previous entry supplied the transforms, which - // for a borrowed palette is a sibling's partner. - const size_t previousTransformIndex = prepared.previousProjectionEntry; - if (previousTransformIndex >= s_previousFrameTransforms.size()) { - return; - } - const auto& previous = s_previousFrameTransforms[previousTransformIndex].transform; - const float weight = - static_cast(task.numerator) / static_cast(task.denominator); - const auto interpolatedProjection = - interpolate_projection(previous.projection, current.projection, weight); - std::memcpy(task.uniformData + task.projectionOffset, &interpolatedProjection, - sizeof(interpolatedProjection)); - - const auto interpolateMatrixSlot = [&](size_t currentIndex, size_t pairOffset) { - if (pairOffset == kNoPreparedPair) { - return; - } - Mat3x4 interpolatedPosition{}; - Mat3x4 interpolatedNormal{}; - evaluate_affine_pair(preparedPairs[pairOffset], weight, interpolatedPosition); - evaluate_affine_pair(preparedPairs[pairOffset + 1], weight, interpolatedNormal); - std::memcpy(task.uniformData + task.positionOffset + currentIndex * sizeof(Mat3x4), - &interpolatedPosition, sizeof(interpolatedPosition)); - std::memcpy(task.uniformData + task.normalOffset + currentIndex * sizeof(Mat3x4), - &interpolatedNormal, sizeof(interpolatedNormal)); - }; - if (task.indexedMatrices) { - if (!current.indexedMatrices) { - return; - } - for (size_t currentIndex = 0; currentIndex < MaxPnMtx; ++currentIndex) { - if ((current.usedMatrixMask & (1u << currentIndex)) == 0) { - continue; - } - interpolateMatrixSlot(currentIndex, prepared.indexedPairOffsets[currentIndex]); - } - } else { - interpolateMatrixSlot(task.currentMatrix, prepared.nonIndexedPairOffset); - } - }; - // A handful of tasks costs more to schedule than to run. The pool stands in for - // std::execution::par, which libc++ does not provide at all. - constexpr size_t kMinimumParallelInterpolationTasks = 64; - if (s_pendingUniformInterpolations.size() < kMinimumParallelInterpolationTasks) { - std::for_each(s_pendingUniformInterpolations.begin(), s_pendingUniformInterpolations.end(), - interpolatePendingUniform); - } else { - InterpolationWorkerPool::instance().run( - s_pendingUniformInterpolations.size(), - [&](size_t index) { interpolatePendingUniform(s_pendingUniformInterpolations[index]); }); - } - } - s_hasInterpolatedFrame.store(eligible, std::memory_order_release); - s_pendingUniformInterpolations.clear(); - // The index maps are emptied node-preservingly by the next - // begin_frame_interpolation. - retire_frame_transforms(); -} - -void get_frame_interpolation_diagnostics(AuroraFrameInterpolationDiagnostics& diagnostics) noexcept { - diagnostics.targetFps = frame_interpolation_fps(); - diagnostics.targetSamples = std::min(s_interpolationSampleTarget.load(std::memory_order_acquire), - maximum_interpolation_samples()); - diagnostics.activeSamples = s_activeInterpolationSamples.load(std::memory_order_acquire); - diagnostics.candidates = s_diagCandidates.load(std::memory_order_relaxed); - diagnostics.matchable = s_diagMatchable.load(std::memory_order_relaxed); - diagnostics.matches = s_diagMatches.load(std::memory_order_relaxed); - diagnostics.eligible = s_diagEligible.load(std::memory_order_relaxed) ? 1 : 0; - diagnostics.replaySafe = s_diagReplaySafe.load(std::memory_order_relaxed) ? 1 : 0; - diagnostics.framesSealed = s_diagFramesSealed.load(std::memory_order_relaxed); - diagnostics.framesLowMatch = s_diagFramesLowMatch.load(std::memory_order_relaxed); - diagnostics.framesReplayUnsafe = s_diagFramesReplayUnsafe.load(std::memory_order_relaxed); - diagnostics.slotReductions = s_diagSlotReductions.load(std::memory_order_relaxed); - diagnostics.lateSealDrops = s_diagLateSealDrops.load(std::memory_order_relaxed); -} - -bool has_interpolated_frame() noexcept { - return s_hasInterpolatedFrame.load(std::memory_order_acquire); -} - -uint32_t interpolated_frame_count() noexcept { - if (!has_interpolated_frame()) { - return 0; - } - // The count latched when this frame began recording, not the configured maximum: - // build_uniform staged exactly this many ranges for every draw. - return s_activeInterpolationSamples.load(std::memory_order_acquire); -} - -void drop_pending_frame_interpolation_uniforms() noexcept { - // Pending tasks hold raw pointers into the mapped uniform staging range, so anything - // that unmaps or rotates that buffer first has to drop the tasks. - s_pendingUniformInterpolations.clear(); -} - -void mark_frame_interpolation_replay_unsafe() noexcept { - s_frameInterpolationReplaySafe.store(false, std::memory_order_release); - // Marking the frame unsafe rotates the staging buffer mid-frame, and the seal then - // duplicates slots instead of replaying, so drop the copies staged so far. - drop_pending_frame_interpolation_uniforms(); -} - -bool frame_interpolation_replay_safe() noexcept { - return s_frameInterpolationReplaySafe.load(std::memory_order_acquire); -} - -void extend_interpolation_draw(uint16_t usedPnMtxMask) noexcept { - if (s_currentFrameTransforms.empty()) { - return; - } - auto& snapshot = s_currentFrameTransforms.back().transform; - if (!snapshot.indexedMatrices) { - // One-matrix draws all read the current matrix index, which a merge cannot - // have changed either. - return; - } - const uint16_t addedSlots = static_cast(usedPnMtxMask & ~snapshot.usedMatrixMask); - if (addedSlots == 0) { - return; - } - for (size_t slot = 0; slot < MaxPnMtx; ++slot) { - if ((addedSlots & (1u << slot)) == 0) { - continue; - } - snapshot.indexedMatrices->position[slot] = g_gxState.pnMtx[slot].pos; - snapshot.indexedMatrices->normal[slot] = g_gxState.pnMtx[slot].nrm; - snapshot.indexedMatrices->slotHash[slot] = - xxh3_hash_s(&g_gxState.pnMtx[slot].pos, sizeof(Mat3x4), - xxh3_hash_s(&g_gxState.pnMtx[slot].nrm, sizeof(Mat3x4))); - } - snapshot.usedMatrixMask |= addedSlots; -} - -std::array record_interpolation_draw( - const FrameInterpolationDrawIdentity& drawIdentity, const Mat4x4& projection, - uint16_t usedPnMtxMask, const InterpolatedUniformLayout& uniformLayout) noexcept { - // Split-screen cameras can draw identical meshes in unrelated view spaces. - // Scope exact, material-only and sibling-palette history to the guest viewport. - // Logical coordinates keep render-scale changes out of the camera identity. - const auto& viewport = g_gxState.logicalViewport; - const std::array viewportValues{viewport.left, viewport.top, viewport.width, - viewport.height, viewport.znear, viewport.zfar}; - const HashType viewportIdentity = xxh3_hash_s(viewportValues.data(), sizeof(viewportValues)); - auto identity = drawIdentity; - identity.combined = combine_identity(identity.combined, viewportIdentity); - identity.pipeline = combine_identity(identity.pipeline, viewportIdentity); - FrameTransformSnapshot snapshot{ - .projection = projection, - .viewportIdentity = viewportIdentity, - .usedMatrixMask = usedPnMtxMask, - }; - if (uniformLayout.indexedMatrices) { - snapshot.indexedMatrices = acquire_indexed_matrices(); - // Only the used slots are copied; consumers mask with usedMatrixMask, so the stale - // pool contents of unused slots are never read. - for (size_t i = 0; i < MaxPnMtx; ++i) { - if ((usedPnMtxMask & (1u << i)) == 0) { - continue; - } - snapshot.indexedMatrices->position[i] = g_gxState.pnMtx[i].pos; - snapshot.indexedMatrices->normal[i] = g_gxState.pnMtx[i].nrm; - snapshot.indexedMatrices->slotHash[i] = - xxh3_hash_s(&g_gxState.pnMtx[i].pos, sizeof(Mat3x4), - xxh3_hash_s(&g_gxState.pnMtx[i].nrm, sizeof(Mat3x4))); - } - } else { - const size_t currentMatrix = std::min(g_gxState.currentPnMtx, MaxPnMtx - 1); - snapshot.position = g_gxState.pnMtx[currentMatrix].pos; - snapshot.normal = g_gxState.pnMtx[currentMatrix].nrm; - } - - const size_t currentTransformIndex = s_currentFrameTransforms.size(); - s_currentFrameTransforms.emplace_back(FrameTransformEntry{ - .identity = identity, - .transform = std::move(snapshot), - }); - s_currentTransformIndices[identity.combined].push_back(currentTransformIndex); - const HashType stableIdentity = stable_identity(identity); - s_currentStableTransformIndices[stableIdentity].push_back(currentTransformIndex); - - std::array interpolatedRanges{}; - ++s_perspectiveCandidates; - const auto exactPrevious = s_previousTransformIndices.find(identity.combined); - const auto stablePrevious = s_previousStableTransformIndices.find(stableIdentity); - const bool hasPreviousPartner = - (exactPrevious != s_previousTransformIndices.end() && !exactPrevious->second.empty()) || - (stablePrevious != s_previousStableTransformIndices.end() && !stablePrevious->second.empty()); - if (hasPreviousPartner) { - ++s_perspectiveMatchable; - } - // A skinned draw with no identity partner can still borrow sibling transforms at - // seal time, so stage copies whenever the previous frame held any palette. - const bool stageInterpolation = - hasPreviousPartner || - (uniformLayout.indexedMatrices && s_previousFrameHasIndexedMatrices); - // A frame already split by a submitted prefix duplicates its slots instead of - // replaying, so staging copies for the resumed suffix would only waste space. - if (frame_interpolation_replay_safe() && stageInterpolation) { - const uint32_t sampleCount = s_activeInterpolationSamples.load(std::memory_order_acquire); - for (uint32_t sample = 0; sample < sampleCount; ++sample) { - auto [interpolatedBuffer, interpolatedRange] = gfx::map_uniform(uniformLayout.uniformSize); - s_pendingUniformInterpolations.push_back({ - .currentTransformIndex = currentTransformIndex, - .sourceUniformData = uniformLayout.sourceUniformData, - .uniformData = interpolatedBuffer.data(), - .uniformSize = uniformLayout.uniformSize, - .projectionOffset = uniformLayout.projectionOffset, - .positionOffset = uniformLayout.positionOffset, - .normalOffset = uniformLayout.normalOffset, - .currentMatrix = uniformLayout.currentMatrix, - .numerator = sample + 1, - .denominator = sampleCount + 1, - .indexedMatrices = uniformLayout.indexedMatrices, - }); - interpolatedRanges[sample] = interpolatedRange; - } - } - return interpolatedRanges; -} -} // namespace aurora::gx diff --git a/aurora-main/lib/gx/frame_interpolation.hpp b/aurora-main/lib/gx/frame_interpolation.hpp deleted file mode 100644 index b38ffed..0000000 --- a/aurora-main/lib/gx/frame_interpolation.hpp +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once - -#include "gx.hpp" - -#include "aurora/gfx.h" - -#include - -// Frame interpolation: generates intermediate presentation frames between two consecutive 60 Hz -// guest frames by re-staging each perspective draw's uniform block with interpolated transforms. -namespace aurora::gx { -constexpr uint32_t MaxInterpolatedFrames = 3; - -// Identifies a draw across frames. `combined` includes the geometry signature and is exact, while -// `pipeline`/`texture` is the material-only fallback for meshes whose vertex data changes. -struct FrameInterpolationDrawIdentity { - HashType combined = 0; - HashType pipeline = 0; - HashType texture = 0; - // Hash of the per-vertex PNMTXIDX stream. Matrix values animate, but this topology decides which - // absolute palette slot each vertex reads, so it must match across a pair. - HashType matrixTopology = 0; -}; - -// Where the transforms live inside a draw's staged uniform block. Offsets are -// relative to the start of the mapped range. -struct InterpolatedUniformLayout { - const uint8_t* sourceUniformData = nullptr; - size_t uniformSize = 0; - size_t projectionOffset = 0; - size_t positionOffset = 0; - size_t normalOffset = 0; - // Slot the live matrix occupies; a compacted position region holds it at 0. - size_t currentMatrix = 0; - bool indexedMatrices = false; -}; - -namespace detail { -// Defined in frame_interpolation.cpp, exposed so the early-outs below stay inline: the shipped -// build compiles shards without LTO, so a cross-TU call would land on every draw in the frame. -extern std::atomic_uint32_t g_frameInterpolationFps; -} // namespace detail - -// 0 when interpolation is disabled; otherwise the configured target (120/180/240). -inline uint32_t frame_interpolation_fps() noexcept { - return detail::g_frameInterpolationFps.load(std::memory_order_acquire); -} -inline bool frame_interpolation_active() noexcept { return frame_interpolation_fps() != 0; } - -void set_frame_interpolation_fps(uint32_t targetFps) noexcept; - -// Feedback for the adaptive slot controller: whether the producer met its -// retrace boundary for the frame that just presented. -void report_producer_paced(bool paced) noexcept; - -void begin_frame_interpolation() noexcept; -void finalize_frame_interpolation() noexcept; -// Fills the observability snapshot behind aurora_get_frame_interpolation_diagnostics. -void get_frame_interpolation_diagnostics(AuroraFrameInterpolationDiagnostics& diagnostics) noexcept; -bool has_interpolated_frame() noexcept; -uint32_t interpolated_frame_count() noexcept; -void mark_frame_interpolation_replay_unsafe() noexcept; -// Drops the interpolation tasks staged into the currently mapped uniform range. Required of -// anything that unmaps or rotates that range before the frame is finalized. -void drop_pending_frame_interpolation_uniforms() noexcept; -bool frame_interpolation_replay_safe() noexcept; - -// Records one perspective draw and maps its intermediate uniform copies, returning the mapped -// range per slot (empty when the draw has no counterpart). Called by build_uniform. -std::array record_interpolation_draw( - const FrameInterpolationDrawIdentity& identity, const Mat4x4& projection, - uint16_t usedPnMtxMask, const InterpolatedUniformLayout& uniformLayout) noexcept; - -// Folds a merged draw back into the snapshot of the draw it joined. aurora renders merged -// primitives through the first one's uniform block, so without this the merged-in bones tear. -void extend_interpolation_draw(uint16_t usedPnMtxMask) noexcept; - -bool interpolate_transform(const Mat3x4& previous, const Mat3x4& current, - float weight, Mat3x4& output) noexcept; -bool interpolate_transform_midpoint(const Mat3x4& previous, const Mat3x4& current, - Mat3x4& output) noexcept; -// Matrix palettes are already-composed skinning transforms, so interpolating their coefficients -// keeps shared boundaries intact. Ordinary one-matrix draws keep the rigid TRS path above. -bool interpolate_indexed_transform(const Mat3x4& previous, - const Mat3x4& current, float weight, - Mat3x4& output) noexcept; -float transform_match_distance_squared(const Mat3x4& previous, - const Mat3x4& current) noexcept; -} // namespace aurora::gx diff --git a/aurora-main/lib/gx/gx.cpp b/aurora-main/lib/gx/gx.cpp deleted file mode 100644 index 15952a6..0000000 --- a/aurora-main/lib/gx/gx.cpp +++ /dev/null @@ -1,2158 +0,0 @@ -#include "gx.hpp" - -#include "pipeline.hpp" -#include "texture_bind_group_cache_key.hpp" -#include "../dolphin/vi/vi_internal.hpp" -#include "../webgpu/gpu.hpp" -#include "../internal.hpp" -#include "../gfx/common.hpp" -#include "../gfx/tex_palette_conv.hpp" -#include "../gfx/texture.hpp" -#include "../gfx/texture_convert.hpp" -#include "../gfx/texture_replacement.hpp" -#include "gx_fmt.hpp" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static aurora::Module Log("aurora::gx"); - -namespace aurora::gx { -using webgpu::g_device; -using webgpu::g_graphicsConfig; - -namespace { - - - - - - -} // namespace - -static GXState make_default_gx_state() { - GXState state{}; - for (size_t i = 0; i < state.tcgs.size(); ++i) { - state.tcgs[i].src = static_cast(GX_TG_TEX0 + i); - } - return state; -} - -GXState g_gxState = make_default_gx_state(); - -static wgpu::Sampler sEmptySampler; -static wgpu::Texture sEmptyTexture; -static wgpu::TextureView sEmptyTextureView; -static std::mutex sBindGroupLayoutMutex; -static absl::flat_hash_map sUniformBindGroupLayouts; -static absl::flat_hash_map> sTextureBindGroupLayouts; -static wgpu::BindGroupLayout sTextureBindGroupLayout; -static wgpu::BindGroupLayout sSamplerBindGroupLayout; -static wgpu::PipelineLayout sPipelineLayout; -wgpu::BindGroup g_emptyTextureBindGroup; -static u64 s_copyTextureStateRevision = 1; -static u64 s_staticTextureCacheValidationRevision = 1; - -// GXInvalidateTexAll means "the guest may have rewritten texture memory, so re-check anything cached from it before trusting it again". -static u64 s_textureCacheStamps = 0; - -// Marks a cache artifact as reusable at the current validation revision. -static inline void note_texture_cache_stamp() noexcept { ++s_textureCacheStamps; } - -static std::array s_lastNoCopyResolveRevision{}; -static void mark_copy_texture_cache_changed() noexcept; -static size_t static_texture_source_cache_size() noexcept; -static size_t static_palette_texture_source_cache_size() noexcept; -static size_t texture_object_cache_size() noexcept; - -struct TextureResolveIdentity { - const void* data = nullptr; - u32 mode0 = 0; - u32 mode1 = 0; - u32 image0 = 0; - u32 image3 = 0; - u32 width = 0; - u32 height = 0; - u32 format = 0; - GXTlut tlut = GX_TLUT0; - u32 texObjId = 0; - u32 texDataVersion = 0; - u8 flags = 0; - - bool operator==(const TextureResolveIdentity& rhs) const = default; - template - friend H AbslHashValue(H h, const TextureResolveIdentity& identity) { - return H::combine(std::move(h), identity.data, identity.mode0, identity.mode1, identity.image0, - identity.image3, identity.width, identity.height, identity.format, identity.tlut, - identity.texObjId, identity.texDataVersion, identity.flags); - } -}; -static std::array s_lastTextureResolveIdentity{}; -static std::array s_lastTextureResolveIdentityValid{}; - -struct TextureResolveIdentityCacheEntry { - bool valid = false; - size_t hash = 0; - u64 copyTextureRevision = 0; - // Revision this binding was last proved good at. - u64 validationRevision = 0; - TextureResolveIdentity identity{}; - gfx::TextureBind binding{}; -}; - -// ponytail: A fixed direct-mapped cache avoids allocator/hash-table overhead. -static std::array s_textureResolveIdentityCache{}; - -static TextureResolveIdentity make_texture_resolve_identity(const GXTexObj_& obj) noexcept { - return { - .data = obj.data, - .mode0 = obj.mode0, - .mode1 = obj.mode1, - .image0 = obj.image0, - .image3 = obj.image3, - .width = obj.width(), - .height = obj.height(), - .format = obj.format(), - .tlut = obj.tlut, - .texObjId = obj.texObjId, - .texDataVersion = obj.texDataVersion, - .flags = obj.flags, - }; -} - -namespace { -struct DynamicPaletteKey { - const void* sourceIdentity = nullptr; - u32 width = 0; - u32 height = 0; - u32 format = 0; - - bool operator==(const DynamicPaletteKey& rhs) const = default; - template - friend H AbslHashValue(H h, const DynamicPaletteKey& key) { - return H::combine(std::move(h), key.sourceIdentity, key.width, key.height, key.format); - } -}; - -struct DynamicPaletteEntry { - gfx::TextureHandle handle; - u32 sourceRevision = 0; - u32 tlutDataVersion = 0; -}; - -struct CachedTextureEntry { - gfx::TextureHandle handle; - u32 texDataVersion = 0; - u32 tlutObjId = 0; - u32 tlutDataVersion = 0; - // Revision the underlying source bytes were last proved good at. - u64 validationRevision = 0; -}; - -struct StaticTextureKey { - const void* data = nullptr; - u32 width = 0; - u32 height = 0; - u32 mips = 0; - u32 format = 0; - u32 texDataVersion = 0; - - bool operator==(const StaticTextureKey& rhs) const = default; - template - friend H AbslHashValue(H h, const StaticTextureKey& key) { - return H::combine(std::move(h), key.data, key.width, key.height, key.mips, key.format, key.texDataVersion); - } -}; - -static std::array s_lastStaticSourceResolveKey{}; -static std::array s_lastStaticSourceResolveKeyValid{}; -static std::array s_lastStaticSourceNoCopyRevision{}; - -struct StaticPaletteTextureKey { - StaticTextureKey texture; - const void* tlutData = nullptr; - u32 tlutFormat = 0; - u32 tlutEntries = 0; - u32 tlutDataVersion = 0; - - bool operator==(const StaticPaletteTextureKey& rhs) const = default; - template - friend H AbslHashValue(H h, const StaticPaletteTextureKey& key) { - return H::combine(std::move(h), key.texture, key.tlutData, key.tlutFormat, key.tlutEntries, key.tlutDataVersion); - } -}; - -// Revalidation used to keep a full byte-for-byte copy of every cached source and memcmp against it. -struct StaticTextureSourceEntry { - gfx::TextureHandle handle; - u64 digest = 0; - u32 sourceSize = 0; - u64 validationRevision = 0; - u64 sourceGeneration = kGuestWriteUntracked; -}; - -struct StaticPaletteTextureSourceEntry { - gfx::TextureHandle handle; - u64 textureDigest = 0; - u64 tlutDigest = 0; - u32 textureSize = 0; - u32 tlutSize = 0; - u64 validationRevision = 0; - u64 textureGeneration = kGuestWriteUntracked; - u64 tlutGeneration = kGuestWriteUntracked; -}; - -struct CachedTlutTextureEntry { - gfx::TextureHandle handle; - u32 tlutDataVersion = 0; - u64 digest = 0; - u64 validationRevision = 0; - u64 generation = kGuestWriteUntracked; -}; - -struct TlutObjectCache { - CachedTlutTextureEntry tlutTexture; - absl::flat_hash_map dynamicPaletteTextures; - absl::flat_hash_set staticTextureUsers; -}; - -absl::flat_hash_map s_textureObjectCaches; -absl::flat_hash_map s_tlutObjectCaches; -absl::flat_hash_map s_staticTextureSourceCache; -absl::flat_hash_map s_staticPaletteTextureSourceCache; -absl::flat_hash_map s_texObjSourceKeys; -absl::flat_hash_map s_texObjPaletteSourceKeys; - -// A repeated bind of the same texture object re-derives the same source key and re-stores it into the map above on every resolve. -template -struct TexObjSourceKeyMemo { - struct Slot { - u32 texObjId = 0; - Key key{}; - }; - std::array slots{}; - - [[nodiscard]] bool matches(u32 texObjId, const Key& key) const { - const auto& slot = slots[texObjId & (slots.size() - 1)]; - return slot.texObjId == texObjId && slot.key == key; - } - void store(u32 texObjId, const Key& key) { - auto& slot = slots[texObjId & (slots.size() - 1)]; - slot.texObjId = texObjId; - slot.key = key; - } - void forget(u32 texObjId) { - auto& slot = slots[texObjId & (slots.size() - 1)]; - if (slot.texObjId == texObjId) { - slot.texObjId = 0; - } - } - void reset() { - for (auto& slot : slots) { - slot.texObjId = 0; - } - } -}; - -TexObjSourceKeyMemo s_texObjSourceKeyMemo; -TexObjSourceKeyMemo s_texObjPaletteSourceKeyMemo; - -void record_tex_obj_source_key(u32 texObjId, const StaticTextureKey& key) noexcept { - if (s_texObjSourceKeyMemo.matches(texObjId, key)) { - return; - } - s_texObjSourceKeys[texObjId] = key; - s_texObjSourceKeyMemo.store(texObjId, key); -} - -void record_tex_obj_palette_source_key(u32 texObjId, const StaticPaletteTextureKey& key) noexcept { - if (s_texObjPaletteSourceKeyMemo.matches(texObjId, key)) { - return; - } - s_texObjPaletteSourceKeys[texObjId] = key; - s_texObjPaletteSourceKeyMemo.store(texObjId, key); -} - -} // namespace - -static size_t static_texture_source_cache_size() noexcept { return s_staticTextureSourceCache.size(); } -static size_t static_palette_texture_source_cache_size() noexcept { return s_staticPaletteTextureSourceCache.size(); } -static size_t texture_object_cache_size() noexcept { return s_textureObjectCaches.size(); } - -namespace { - -struct StaticSourceFrontCacheEntry { - bool valid = false; - size_t hash = 0; - u64 validationRevision = 0; - StaticTextureKey key{}; - gfx::TextureHandle handle; -}; - -static std::array s_staticSourceFrontCache; - -static gfx::TextureHandle lookup_static_source_front_cache(const StaticTextureKey& key, size_t hash) noexcept { - const auto& entry = s_staticSourceFrontCache[hash & (s_staticSourceFrontCache.size() - 1)]; - if (entry.valid && entry.validationRevision == s_staticTextureCacheValidationRevision && entry.hash == hash && - entry.key == key) { - return entry.handle; - } - return {}; -} - -static void store_static_source_front_cache(const StaticTextureKey& key, size_t hash, - const gfx::TextureHandle& handle) noexcept { - auto& entry = s_staticSourceFrontCache[hash & (s_staticSourceFrontCache.size() - 1)]; - entry.valid = true; - entry.hash = hash; - entry.validationRevision = s_staticTextureCacheValidationRevision; - entry.key = key; - entry.handle = handle; - note_texture_cache_stamp(); -} - -static void clear_static_source_front_cache() noexcept { - for (auto& entry : s_staticSourceFrontCache) { - entry.valid = false; - entry.handle.reset(); - } -} - -static u32 static_texture_data_size(const StaticTextureKey& key) noexcept { - if (key.data == nullptr || key.width == 0 || key.height == 0 || key.mips == 0) { - return 0; - } - return GXGetTexBufferSize(static_cast(key.width), static_cast(key.height), key.format, - key.mips > 1 ? GX_TRUE : GX_FALSE, static_cast(key.mips - 1)); -} - -static u64 digest_source_bytes(const void* data, size_t size) noexcept { - if (data == nullptr || size == 0) { - return 0; - } - return static_cast(xxh3_hash_s(data, size)); -} - -static bool source_matches_digest(const void* data, size_t size, u64 digest, u32 expectedSize) noexcept { - if (data == nullptr || size != expectedSize) { - return false; - } - return digest_source_bytes(data, size) == digest; -} - -// A source whose generation still matches the one recorded beside its digest cannot have been written since, so the digest is skipped. -static bool validate_static_texture_source_entry(const StaticTextureKey& key, - StaticTextureSourceEntry& entry) noexcept { - if (entry.validationRevision == s_staticTextureCacheValidationRevision) { - return true; - } - const u32 dataSize = static_texture_data_size(key); - const u64 generation = guest_write_generation(key.data, dataSize); - if (dataSize == entry.sourceSize && guest_write_generation_matches(entry.sourceGeneration, generation)) { - entry.validationRevision = s_staticTextureCacheValidationRevision; - note_texture_cache_stamp(); - return true; - } - if (!source_matches_digest(key.data, dataSize, entry.digest, entry.sourceSize)) { - return false; - } - entry.sourceGeneration = generation; - entry.validationRevision = s_staticTextureCacheValidationRevision; - note_texture_cache_stamp(); - return true; -} - -static bool validate_static_palette_texture_source_entry(const StaticPaletteTextureKey& key, - StaticPaletteTextureSourceEntry& entry) noexcept { - if (entry.validationRevision == s_staticTextureCacheValidationRevision) { - return true; - } - const u32 textureDataSize = static_texture_data_size(key.texture); - const size_t tlutDataSize = static_cast(key.tlutEntries) * sizeof(u16); - const u64 textureGeneration = guest_write_generation(key.texture.data, textureDataSize); - const u64 tlutGeneration = guest_write_generation(key.tlutData, tlutDataSize); - const bool skippable = textureDataSize == entry.textureSize && tlutDataSize == entry.tlutSize && - guest_write_generation_matches(entry.textureGeneration, textureGeneration) && - guest_write_generation_matches(entry.tlutGeneration, tlutGeneration); - if (!skippable) { - const bool textureOk = - source_matches_digest(key.texture.data, textureDataSize, entry.textureDigest, entry.textureSize); - const bool tlutOk = source_matches_digest(key.tlutData, tlutDataSize, entry.tlutDigest, entry.tlutSize); - if (!textureOk || !tlutOk) { - return false; - } - entry.textureGeneration = textureGeneration; - entry.tlutGeneration = tlutGeneration; - } - entry.validationRevision = s_staticTextureCacheValidationRevision; - note_texture_cache_stamp(); - return true; -} - -static StaticTextureSourceEntry make_static_texture_source_entry(const StaticTextureKey& key, - const gfx::TextureHandle& handle) { - const u32 dataSize = static_texture_data_size(key); - const u64 generation = guest_write_generation(key.data, dataSize); - note_texture_cache_stamp(); - return { - .handle = handle, - .digest = digest_source_bytes(key.data, dataSize), - .sourceSize = dataSize, - .validationRevision = s_staticTextureCacheValidationRevision, - .sourceGeneration = generation, - }; -} - -static StaticPaletteTextureSourceEntry make_static_palette_texture_source_entry( - const StaticPaletteTextureKey& key, const gfx::TextureHandle& handle) { - const u32 textureDataSize = static_texture_data_size(key.texture); - const size_t tlutDataSize = static_cast(key.tlutEntries) * sizeof(u16); - const u64 textureGeneration = guest_write_generation(key.texture.data, textureDataSize); - const u64 tlutGeneration = guest_write_generation(key.tlutData, tlutDataSize); - note_texture_cache_stamp(); - return { - .handle = handle, - .textureDigest = digest_source_bytes(key.texture.data, textureDataSize), - .tlutDigest = digest_source_bytes(key.tlutData, tlutDataSize), - .textureSize = textureDataSize, - .tlutSize = static_cast(tlutDataSize), - .validationRevision = s_staticTextureCacheValidationRevision, - .textureGeneration = textureGeneration, - .tlutGeneration = tlutGeneration, - }; -} - -DynamicPaletteKey make_dynamic_palette_key(const GXTexObj_& obj, const GXState::CopyTextureRef& source) { - return { - .sourceIdentity = source.handle.get(), - .width = obj.width(), - .height = obj.height(), - .format = obj.format(), - }; -} - -StaticTextureKey make_static_texture_key(const GXTexObj_& obj) { - return { - .data = obj.data, - .width = obj.width(), - .height = obj.height(), - .mips = obj.mip_count(), - .format = obj.format(), - .texDataVersion = obj.texDataVersion, - }; -} - -StaticPaletteTextureKey make_static_palette_texture_key(const GXTexObj_& obj, const GXTlutObj_& tlut) { - return { - .texture = make_static_texture_key(obj), - .tlutData = tlut.data, - .tlutFormat = static_cast(tlut.format), - .tlutEntries = tlut.numEntries, - .tlutDataVersion = tlut.tlutDataVersion, - }; -} - -bool can_cache_static_texture_upload(const GXTexObj_& obj) noexcept { - // THP movie frames are decoded into reused guest buffers and uploaded as YUVA. - return obj.format() != GX_CTF_YUVA8; -} - -void clear_texture_dependency(u32 texObjId, u32 tlutObjId) { - if (texObjId == 0 || tlutObjId == 0) { - return; - } - if (auto it = s_tlutObjectCaches.find(tlutObjId); it != s_tlutObjectCaches.end()) { - it->second.staticTextureUsers.erase(texObjId); - if (!it->second.tlutTexture.handle && it->second.dynamicPaletteTextures.empty() && - it->second.staticTextureUsers.empty()) { - s_tlutObjectCaches.erase(it); - } - } -} - -void store_cached_texture(const GXTexObj_& obj, gfx::TextureHandle handle, u32 tlutObjId = 0, u32 tlutDataVersion = 0) { - if (obj.texObjId == 0) { - return; - } - - auto& entry = s_textureObjectCaches[obj.texObjId]; - if (entry.tlutObjId != tlutObjId) { - clear_texture_dependency(obj.texObjId, entry.tlutObjId); - } - - entry.handle = std::move(handle); - entry.texDataVersion = obj.texDataVersion; - entry.tlutObjId = tlutObjId; - entry.tlutDataVersion = tlutDataVersion; - entry.validationRevision = s_staticTextureCacheValidationRevision; - note_texture_cache_stamp(); - - if (tlutObjId != 0) { - s_tlutObjectCaches[tlutObjId].staticTextureUsers.insert(obj.texObjId); - } -} - -gfx::TextureHandle get_tlut_texture(const GXTlutObj_& tlut) { - const size_t tlutSize = static_cast(tlut.numEntries) * sizeof(u16); - if (tlut.tlutObjId != 0) { - auto& cache = s_tlutObjectCaches[tlut.tlutObjId]; - auto& cached = cache.tlutTexture; - if (cached.handle && cached.tlutDataVersion == tlut.tlutDataVersion) { - if (cached.validationRevision == s_staticTextureCacheValidationRevision) { - return cached.handle; - } - // GXInvalidateTexAll: the guest may have rewritten this palette in place without re-running GXInitTlutObj, which is the only thing that moves tlutDataVersion. - bool stillValid = true; - if (tlut.data != nullptr) { - const u64 generation = guest_write_generation(tlut.data, tlutSize); - if (!guest_write_generation_matches(cached.generation, generation)) { - stillValid = digest_source_bytes(tlut.data, tlutSize) == cached.digest; - cached.generation = generation; - } - } - if (stillValid) { - cached.validationRevision = s_staticTextureCacheValidationRevision; - note_texture_cache_stamp(); - return cached.handle; - } - } - cache.dynamicPaletteTextures.clear(); - for (const u32 texObjId : cache.staticTextureUsers) { - s_textureObjectCaches.erase(texObjId); - } - cache.staticTextureUsers.clear(); - } - - const auto handle = - gfx::new_static_texture_2d(tlut.numEntries, 1, 1, gfx::tlut_texture_format(tlut.format), - {static_cast(tlut.data), tlutSize}, true, "Loaded TLUT"); - if (tlut.tlutObjId != 0) { - auto& cache = s_tlutObjectCaches[tlut.tlutObjId]; - const u64 generation = guest_write_generation(tlut.data, tlutSize); - cache.tlutTexture.handle = handle; - cache.tlutTexture.tlutDataVersion = tlut.tlutDataVersion; - cache.tlutTexture.digest = digest_source_bytes(tlut.data, tlutSize); - cache.tlutTexture.generation = generation; - cache.tlutTexture.validationRevision = s_staticTextureCacheValidationRevision; - note_texture_cache_stamp(); - } - return handle; -} - -gfx::TextureHandle resolve_static_texture(const GXTexObj_& obj) { - ZoneScoped; - const bool canCacheUpload = !obj.no_cache() && can_cache_static_texture_upload(obj); - - if (canCacheUpload && obj.texObjId != 0) { - if (const auto it = s_textureObjectCaches.find(obj.texObjId); it != s_textureObjectCaches.end()) { - const auto& entry = it->second; - if (entry.handle && entry.texDataVersion == obj.texDataVersion && entry.tlutObjId == 0 && - entry.validationRevision == s_staticTextureCacheValidationRevision) { - return entry.handle; - } - } - } - - const bool canUseSourceCache = canCacheUpload && obj.data != nullptr; - const StaticTextureKey sourceKey = canUseSourceCache ? make_static_texture_key(obj) : StaticTextureKey{}; - const size_t sourceHash = canUseSourceCache ? absl::Hash{}(sourceKey) : 0; - if (canUseSourceCache) { - if (auto handle = lookup_static_source_front_cache(sourceKey, sourceHash)) { - if (obj.texObjId != 0) { - record_tex_obj_source_key(obj.texObjId, sourceKey); - } - return handle; - } - if (auto it = s_staticTextureSourceCache.find(sourceKey); it != s_staticTextureSourceCache.end()) { - if (!validate_static_texture_source_entry(sourceKey, it->second)) { - s_staticTextureSourceCache.erase(it); - clear_static_source_front_cache(); - } else { - const auto& handle = it->second.handle; - if (obj.texObjId != 0) { - record_tex_obj_source_key(obj.texObjId, sourceKey); - } - store_static_source_front_cache(sourceKey, sourceHash, handle); - return handle; - } - } - } - - gfx::TextureHandle handle; - if (const auto replacement = gfx::texture_replacement::find_replacement(obj); replacement.has_value()) { - handle = *replacement; - } else { -#if DEBUG - const auto name = gfx::texture_replacement::build_texture_replacement_name(obj); - const auto nameStr = name.c_str(); -#else - const auto nameStr = "GX Static Texture"; -#endif - const u32 dataSize = GXGetTexBufferSize(static_cast(obj.width()), static_cast(obj.height()), - obj.format(), obj.has_mips(), - obj.has_mips() ? static_cast(obj.mip_count() - 1) : 0); - handle = gfx::new_static_texture_2d(obj.width(), obj.height(), obj.mip_count(), obj.format(), - {static_cast(obj.data), dataSize}, false, nameStr); - } - if (canCacheUpload) { - store_cached_texture(obj, handle); - if (canUseSourceCache) { - if (s_staticTextureSourceCache.size() >= 512) { - absl::erase_if(s_staticTextureSourceCache, [](const auto& item) { return item.second.handle.use_count() <= 1; }); - clear_static_source_front_cache(); - } - s_staticTextureSourceCache[sourceKey] = make_static_texture_source_entry(sourceKey, handle); - store_static_source_front_cache(sourceKey, sourceHash, handle); - if (obj.texObjId != 0) { - record_tex_obj_source_key(obj.texObjId, sourceKey); - } - } - } - return handle; -} - -gfx::TextureHandle resolve_static_palette_texture(const GXTexObj_& obj, const GXTlutObj_& tlut) { - ZoneScoped; - - if (obj.texObjId != 0) { - if (const auto it = s_textureObjectCaches.find(obj.texObjId); it != s_textureObjectCaches.end()) { - const auto& entry = it->second; - if (entry.handle && entry.texDataVersion == obj.texDataVersion && entry.tlutObjId == tlut.tlutObjId && - entry.tlutDataVersion == tlut.tlutDataVersion && - entry.validationRevision == s_staticTextureCacheValidationRevision) { - return entry.handle; - } - } - } - - const bool canUseSourceCache = !obj.no_cache() && !tlut.no_cache() && obj.data != nullptr && tlut.data != nullptr; - const StaticPaletteTextureKey sourceKey = - canUseSourceCache ? make_static_palette_texture_key(obj, tlut) : StaticPaletteTextureKey{}; - if (canUseSourceCache) { - if (auto it = s_staticPaletteTextureSourceCache.find(sourceKey); - it != s_staticPaletteTextureSourceCache.end()) { - if (!validate_static_palette_texture_source_entry(sourceKey, it->second)) { - s_staticPaletteTextureSourceCache.erase(it); - } else { - const auto& handle = it->second.handle; - if (obj.texObjId != 0) { - store_cached_texture(obj, handle, tlut.tlutObjId, tlut.tlutDataVersion); - record_tex_obj_palette_source_key(obj.texObjId, sourceKey); - } - return handle; - } - } - } - - gfx::TextureHandle handle; - if (const auto replacement = gfx::texture_replacement::find_replacement(obj); replacement.has_value()) { - handle = *replacement; - } else { - const u32 dataSize = GXGetTexBufferSize(static_cast(obj.width()), static_cast(obj.height()), - obj.format(), obj.has_mips(), - obj.has_mips() ? static_cast(obj.mip_count() - 1) : 0); - auto converted = gfx::convert_texture_palette( - obj.format(), obj.width(), obj.height(), obj.mip_count(), {static_cast(obj.data), dataSize}, - tlut.format, tlut.numEntries, {static_cast(tlut.data), static_cast(tlut.numEntries) * 2}); - if (converted.data.empty()) { - return {}; - } - handle = - gfx::new_static_texture_2d(obj.width(), obj.height(), obj.mip_count(), GX_TF_RGBA8_PC, - {converted.data.data(), converted.data.size()}, false, "GX Static Palette Texture"); - handle->hasArbitraryMips = converted.hasArbitraryMips; - } - if (!obj.no_cache() && !tlut.no_cache()) { - store_cached_texture(obj, handle, tlut.tlutObjId, tlut.tlutDataVersion); - if (canUseSourceCache) { - if (s_staticPaletteTextureSourceCache.size() >= 256) { - absl::erase_if(s_staticPaletteTextureSourceCache, [](const auto& item) { return item.second.handle.use_count() <= 1; }); - } - s_staticPaletteTextureSourceCache[sourceKey] = make_static_palette_texture_source_entry(sourceKey, handle); - if (obj.texObjId != 0) { - record_tex_obj_palette_source_key(obj.texObjId, sourceKey); - } - } - } - return handle; -} - -gfx::TextureHandle resolve_dynamic_palette_texture(const GXTexObj_& obj, const GXState::CopyTextureRef& source, - const GXTlutObj_& tlut) { - ZoneScoped; - - const auto tlutHandle = get_tlut_texture(tlut); - auto& tlutCache = s_tlutObjectCaches[tlut.tlutObjId]; - if (tlutCache.dynamicPaletteTextures.size() >= 32) { - absl::erase_if(tlutCache.dynamicPaletteTextures, [](const auto& item) { return item.second.handle.use_count() <= 1; }); - } - auto& entry = tlutCache.dynamicPaletteTextures[make_dynamic_palette_key(obj, source)]; - if (!entry.handle) { - // Use source size instead of target (logical) size - entry.handle = gfx::new_conv_texture(source.handle->size.width, source.handle->size.height, GX_TF_RGBA8, - "GX Dynamic Palette Texture"); - } - if (entry.sourceRevision != source.revision || entry.tlutDataVersion != tlut.tlutDataVersion) { - gfx::queue_palette_conv({ - .variant = obj.format() == GX_TF_C4 ? gfx::tex_palette_conv::Variant::FromFloat4 - : gfx::tex_palette_conv::Variant::FromFloat8, - .src = source.handle, - .dst = entry.handle, - .tlut = tlutHandle, - }); - entry.sourceRevision = source.revision; - entry.tlutDataVersion = tlut.tlutDataVersion; - } - return entry.handle; -} - -u32 resolved_format_for_handle(const gfx::TextureHandle& handle) { - if (!handle) { - return GX_TF_RGBA8; - } - if (handle->gxFormat != gfx::InvalidTextureFormat) { - return handle->gxFormat; - } - return GX_TF_RGBA8_PC; -} -} // namespace - -Vec2 logical_fb_size() noexcept { - return gfx::is_offscreen() ? gfx::get_render_target_size() : vi::configured_fb_size(); -} - -namespace { -struct ScissorRange { - s32 offset = 0; - s32 start = 0; - s32 end = 0; -}; - -struct ScissorRect { - gfx::ClipRect rect{}; - s32 xOff = 0; - s32 yOff = 0; -}; - -std::array compute_scissor_ranges(s32 start, s32 end, s32 offset, s32 efbDim, u32& count) noexcept { - std::array ranges{}; - count = 0; - for (s32 extraOff = -4096; extraOff <= 4096; extraOff += 1024) { - const s32 newOff = offset + extraOff; - const s32 newStart = std::clamp(start - newOff, 0, efbDim); - const s32 newEnd = std::clamp(end - newOff + 1, 0, efbDim); - if (newStart < newEnd && count < ranges.size()) { - ranges[count++] = { - .offset = newOff, - .start = newStart, - .end = newEnd, - }; - } - } - return ranges; -} - -int scissor_viewport_area(const ScissorRect& rect, const gfx::Viewport& viewport) noexcept { - const float viewportLeft = std::min(viewport.left, viewport.left + viewport.width); - const float viewportRight = std::max(viewport.left, viewport.left + viewport.width); - const float viewportTop = std::min(viewport.top, viewport.top + viewport.height); - const float viewportBottom = std::max(viewport.top, viewport.top + viewport.height); - - const float left = std::clamp(static_cast(rect.rect.x + rect.xOff), viewportLeft, viewportRight); - const float right = - std::clamp(static_cast(rect.rect.x + rect.rect.width + rect.xOff), viewportLeft, viewportRight); - const float top = std::clamp(static_cast(rect.rect.y + rect.yOff), viewportTop, viewportBottom); - const float bottom = - std::clamp(static_cast(rect.rect.y + rect.rect.height + rect.yOff), viewportTop, viewportBottom); - - return static_cast(std::max(right - left, 0.0f) * std::max(bottom - top, 0.0f)); -} - -int scissor_area(const ScissorRect& rect) noexcept { - return rect.rect.width * rect.rect.height; -} - -ScissorRect best_scissor_rect(const gfx::ClipRect& logicalScissor, const gfx::Viewport& logicalViewport) noexcept { - if (logicalScissor.width <= 0 || logicalScissor.height <= 0) { - return { - .rect = {1000, 1000, 1, 1}, - .xOff = 0, - .yOff = 0, - }; - } - - const auto [logicalFbWidth, logicalFbHeight] = logical_fb_size(); - const s32 efbWidth = static_cast(logicalFbWidth); - const s32 efbHeight = static_cast(logicalFbHeight); - const s32 left = logicalScissor.x; - const s32 right = logicalScissor.x + logicalScissor.width - 1; - const s32 top = logicalScissor.y; - const s32 bottom = logicalScissor.y + logicalScissor.height - 1; - - u32 xCount = 0; - u32 yCount = 0; - const auto xRanges = compute_scissor_ranges(left, right, g_gxState.scissorOffsetX, efbWidth, xCount); - const auto yRanges = compute_scissor_ranges(top, bottom, g_gxState.scissorOffsetY, efbHeight, yCount); - if (xCount == 0 || yCount == 0) { - return { - .rect = {1000, 1000, 1, 1}, - .xOff = 0, - .yOff = 0, - }; - } - - std::optional best; - for (u32 x = 0; x < xCount; ++x) { - for (u32 y = 0; y < yCount; ++y) { - const ScissorRect candidate{ - .rect = - { - .x = xRanges[x].start, - .y = yRanges[y].start, - .width = xRanges[x].end - xRanges[x].start, - .height = yRanges[y].end - yRanges[y].start, - }, - .xOff = xRanges[x].offset, - .yOff = yRanges[y].offset, - }; - if (!best) { - best = candidate; - continue; - } - - const int candidateViewportArea = scissor_viewport_area(candidate, logicalViewport); - const int bestViewportArea = scissor_viewport_area(*best, logicalViewport); - if (candidateViewportArea > bestViewportArea || - (candidateViewportArea == bestViewportArea && scissor_area(candidate) > scissor_area(*best))) { - best = candidate; - } - } - } - - return *best; -} - -float logical_to_target_x(float value) noexcept { - const auto [logicalFbWidth, logicalFbHeight] = logical_fb_size(); - const auto [targetWidth, targetHeight] = gfx::get_render_target_size(); - if (logicalFbWidth == 0 || logicalFbHeight == 0 || targetWidth == 0 || targetHeight == 0) { - return value; - } - return value * static_cast(targetWidth) / static_cast(logicalFbWidth); -} - -float logical_to_target_y(float value) noexcept { - const auto [logicalFbWidth, logicalFbHeight] = logical_fb_size(); - const auto [targetWidth, targetHeight] = gfx::get_render_target_size(); - if (logicalFbWidth == 0 || logicalFbHeight == 0 || targetWidth == 0 || targetHeight == 0) { - return value; - } - return value * static_cast(targetHeight) / static_cast(logicalFbHeight); -} - -gfx::ClipRect scale_logical_scissor_rect(const gfx::ClipRect& logicalScissor) noexcept { - if (g_gxState.viewportPolicy == AURORA_VIEWPORT_NATIVE) { - return logicalScissor; - } - - const auto [targetWidth, targetHeight] = gfx::get_render_target_size(); - const float left = logical_to_target_x(static_cast(logicalScissor.x)); - const float top = logical_to_target_y(static_cast(logicalScissor.y)); - const float right = logical_to_target_x(static_cast(logicalScissor.x + logicalScissor.width)); - const float bottom = logical_to_target_y(static_cast(logicalScissor.y + logicalScissor.height)); - - const auto mappedLeft = std::clamp(static_cast(std::floor(left)), 0, static_cast(targetWidth)); - const auto mappedTop = std::clamp(static_cast(std::floor(top)), 0, static_cast(targetHeight)); - const auto mappedRight = - std::clamp(static_cast(std::ceil(right)), mappedLeft, static_cast(targetWidth)); - const auto mappedBottom = - std::clamp(static_cast(std::ceil(bottom)), mappedTop, static_cast(targetHeight)); - - return { - .x = mappedLeft, - .y = mappedTop, - .width = mappedRight - mappedLeft, - .height = mappedBottom - mappedTop, - }; -} - -} // namespace - -MappedRenderState map_logical_render_state() noexcept { - if (g_gxState.viewportPolicy == AURORA_VIEWPORT_NATIVE) { - return { - .viewport = g_gxState.logicalViewport, - .scissor = g_gxState.logicalScissor, - }; - } - - const auto bestScissor = best_scissor_rect(g_gxState.logicalScissor, g_gxState.logicalViewport); - const gfx::Viewport shiftedViewport{ - .left = g_gxState.logicalViewport.left - static_cast(bestScissor.xOff), - .top = g_gxState.logicalViewport.top - static_cast(bestScissor.yOff), - .width = g_gxState.logicalViewport.width, - .height = g_gxState.logicalViewport.height, - .znear = g_gxState.logicalViewport.znear, - .zfar = g_gxState.logicalViewport.zfar, - }; - - return { - .viewport = map_logical_viewport(shiftedViewport), - .scissor = scale_logical_scissor_rect(bestScissor.rect), - }; -} - -namespace { -void apply_logical_render_state() noexcept { - const auto mapped = map_logical_render_state(); - set_render_viewport(mapped.viewport); - set_render_scissor(mapped.scissor); -} -} // namespace - -gfx::Viewport map_logical_viewport(const gfx::Viewport& logicalViewport) noexcept { - if (g_gxState.viewportPolicy == AURORA_VIEWPORT_NATIVE) { - return logicalViewport; - } - - const auto [logicalFbWidth, logicalFbHeight] = logical_fb_size(); - const auto [targetWidth, targetHeight] = gfx::get_render_target_size(); - if (logicalFbWidth == 0 || logicalFbHeight == 0 || targetWidth == 0 || targetHeight == 0) { - return logicalViewport; - } - - const float scaleX = static_cast(targetWidth) / static_cast(logicalFbWidth); - const float scaleY = static_cast(targetHeight) / static_cast(logicalFbHeight); - return { - .left = logicalViewport.left * scaleX, - .top = logicalViewport.top * scaleY, - .width = logicalViewport.width * scaleX, - .height = logicalViewport.height * scaleY, - .znear = logicalViewport.znear, - .zfar = logicalViewport.zfar, - }; -} - -gfx::ClipRect map_logical_scissor(const gfx::ClipRect& logicalScissor) noexcept { - if (g_gxState.viewportPolicy == AURORA_VIEWPORT_NATIVE) { - return logicalScissor; - } - - const auto [logicalFbWidth, logicalFbHeight] = logical_fb_size(); - const auto [targetWidth, targetHeight] = gfx::get_render_target_size(); - if (logicalFbWidth == 0 || logicalFbHeight == 0 || targetWidth == 0 || targetHeight == 0) { - return logicalScissor; - } - - return scale_logical_scissor_rect(logicalScissor); -} - -void set_logical_viewport(const gfx::Viewport& viewport) noexcept { - const bool changed = viewport != g_gxState.logicalViewport; - g_gxState.logicalViewport = viewport; - g_gxState.stateDirty = g_gxState.stateDirty || changed; - apply_logical_render_state(); -} - -void set_render_viewport(const gfx::Viewport& viewport) noexcept { - if (viewport == g_gxState.renderViewport) { - return; - } - g_gxState.renderViewport = viewport; - g_gxState.stateDirty = true; - gfx::set_viewport(viewport); -} - -void set_logical_scissor(const gfx::ClipRect& scissor) noexcept { - g_gxState.logicalScissor = scissor; - apply_logical_render_state(); -} - -void set_render_scissor(const gfx::ClipRect& scissor) noexcept { - g_gxState.renderScissor = scissor; - gfx::set_scissor(scissor); -} - -const gfx::TextureBind& get_texture(GXTexMapID id) noexcept { return g_gxState.textures[static_cast(id)]; } - -void evict_texture_object(u32 texObjId) noexcept { - if (const auto it = s_textureObjectCaches.find(texObjId); it != s_textureObjectCaches.end()) { - clear_texture_dependency(texObjId, it->second.tlutObjId); - s_textureObjectCaches.erase(it); - } - if (const auto it = s_texObjSourceKeys.find(texObjId); it != s_texObjSourceKeys.end()) { - s_staticTextureSourceCache.erase(it->second); - s_texObjSourceKeys.erase(it); - s_texObjSourceKeyMemo.forget(texObjId); - clear_static_source_front_cache(); - } - if (const auto it = s_texObjPaletteSourceKeys.find(texObjId); it != s_texObjPaletteSourceKeys.end()) { - s_staticPaletteTextureSourceCache.erase(it->second); - s_texObjPaletteSourceKeys.erase(it); - s_texObjPaletteSourceKeyMemo.forget(texObjId); - } - // If there is a loaded slot with this ID, mark it as no_cache to avoid inserting it when it's resolved. - // This also handles the case where the texture was created, loaded, and immediately destroyed before we resolved it. - for (auto& obj : g_gxState.loadedTextures) { - if (obj.texObjId == texObjId) { - obj.set_no_cache(true); - } - } -} - -void evict_tlut_object(u32 tlutObjId) noexcept { - // Only the conversions that actually depend on this palette are dropped. - if (const auto it = s_tlutObjectCaches.find(tlutObjId); it != s_tlutObjectCaches.end()) { - for (const u32 texObjId : it->second.staticTextureUsers) { - s_textureObjectCaches.erase(texObjId); - if (const auto keyIt = s_texObjPaletteSourceKeys.find(texObjId); keyIt != s_texObjPaletteSourceKeys.end()) { - s_staticPaletteTextureSourceCache.erase(keyIt->second); - s_texObjPaletteSourceKeys.erase(keyIt); - s_texObjPaletteSourceKeyMemo.forget(texObjId); - } - } - s_tlutObjectCaches.erase(it); - } - // If there is a loaded slot with this ID, mark it as no_cache to avoid inserting it when it's resolved. - // This also handles the case where the texture was created, loaded, and immediately destroyed before we resolved it. - for (auto& obj : g_gxState.loadedTluts) { - if (obj.tlutObjId == tlutObjId) { - obj.set_no_cache(true); - } - } -} - -// GXInitTexObj mints a fresh object id per call and nothing ever emits DESTROY_TEXOBJ, so the texture object memo used to be bounded only by the fact that GXInvalidateTexAll dropped it six times a frame. -constexpr u64 kTextureCacheIdleRevisions = 128; -constexpr size_t kTextureObjectCacheSoftLimit = 1024; -constexpr size_t kTlutObjectCacheSoftLimit = 512; -constexpr size_t kTexObjSourceKeySoftLimit = 2048; - -static void prune_idle_texture_caches() noexcept { - const u64 revision = s_staticTextureCacheValidationRevision; - // An idle entry stays idle, so there is nothing to gain from sweeping on every bump (six a frame). - if (revision % (kTextureCacheIdleRevisions / 2) != 0) { - return; - } - if (s_textureObjectCaches.size() >= kTextureObjectCacheSoftLimit) { - std::vector> retired; - for (const auto& [texObjId, entry] : s_textureObjectCaches) { - if (revision - entry.validationRevision > kTextureCacheIdleRevisions) { - retired.emplace_back(texObjId, entry.tlutObjId); - } - } - for (const auto& [texObjId, tlutObjId] : retired) { - clear_texture_dependency(texObjId, tlutObjId); - s_textureObjectCaches.erase(texObjId); - } - } - - if (s_tlutObjectCaches.size() >= kTlutObjectCacheSoftLimit) { - // Only drop palettes nothing depends on: an entry with users still records which cached conversions have to be thrown away when its bytes change. - absl::erase_if(s_tlutObjectCaches, [revision](const auto& item) { - const auto& cache = item.second; - return cache.staticTextureUsers.empty() && cache.dynamicPaletteTextures.empty() && - (!cache.tlutTexture.handle || cache.tlutTexture.handle.use_count() <= 1) && - revision - cache.tlutTexture.validationRevision > kTextureCacheIdleRevisions; - }); - } - - // The source-key maps exist only so evict_texture_object can find the static source entry a texObjId last resolved to, and nothing else ever retires them -- with GXInitTexObj minting a fresh id per call they otherwise grow for the lifetime of the process. - if (s_texObjSourceKeys.size() >= kTexObjSourceKeySoftLimit) { - absl::erase_if(s_texObjSourceKeys, [](const auto& item) { return !s_textureObjectCaches.contains(item.first); }); - s_texObjSourceKeyMemo.reset(); - } - if (s_texObjPaletteSourceKeys.size() >= kTexObjSourceKeySoftLimit) { - absl::erase_if(s_texObjPaletteSourceKeys, - [](const auto& item) { return !s_textureObjectCaches.contains(item.first); }); - s_texObjPaletteSourceKeyMemo.reset(); - } -} - -void invalidate_static_texture_cache() noexcept { - // Nothing has been marked reusable since the last bump, so every entry in every tier is already stale at the current revision. - if (s_textureCacheStamps == 0) { - return; - } - - ++s_staticTextureCacheValidationRevision; - s_textureCacheStamps = 0; - if (s_staticTextureCacheValidationRevision == 0) { - // Unreachable with a 64-bit counter, but if it ever wraps, no stamped revision may survive into the reused revision. - s_staticTextureCacheValidationRevision = 1; - s_textureObjectCaches.clear(); - s_tlutObjectCaches.clear(); - s_staticTextureSourceCache.clear(); - s_staticPaletteTextureSourceCache.clear(); - s_texObjSourceKeys.clear(); - s_texObjPaletteSourceKeys.clear(); - s_texObjSourceKeyMemo.reset(); - s_texObjPaletteSourceKeyMemo.reset(); - clear_static_source_front_cache(); - for (auto& entry : s_textureResolveIdentityCache) { - entry.valid = false; - entry.binding.reset(); - } - } - - // Everything else is revision-gated: the texture object memo, the TLUT textures (re-proved by palette digest), the static source front cache and the resolve identity cache all miss on the new revision without being torn down, so the bump costs one increment instead of dropping GPU textures and rebuilding hash tables. - s_lastTextureResolveIdentityValid.fill(false); - s_lastNoCopyResolveRevision.fill(0); - s_lastStaticSourceResolveKeyValid.fill(false); - s_lastStaticSourceNoCopyRevision.fill(0); - prune_idle_texture_caches(); - g_gxState.stateDirty = true; -} - -void clear_copy_texture_cache() noexcept { - g_gxState.copyTextures.clear(); - g_gxState.copyTextureCache.clear(); - prune_copy_texture_pool(nullptr); - mark_copy_texture_cache_changed(); - clear_display_copy_cache(); - for (auto& [_, cache] : s_tlutObjectCaches) { - cache.dynamicPaletteTextures.clear(); - } -} - -void clear_display_copy_cache() noexcept { - g_gxState.displayCopyTexture.reset(); - g_gxState.displayCopyBindGroup = {}; - g_gxState.displayCopyWidth = 0; - g_gxState.displayCopyHeight = 0; -} - -void set_display_copy_present_source() noexcept { - if (!g_gxState.displayCopyTexture) { - return; - } - - g_gxState.displayCopyBindGroup = webgpu::create_copy_bind_group(g_gxState.displayCopyTexture->sampleTextureView, - webgpu::present_source().sampler); - webgpu::set_present_source_override(g_gxState.displayCopyBindGroup, g_gxState.displayCopyTexture->texture, - g_gxState.displayCopyTexture->size, g_gxState.displayCopyTexture->format); -} - -void evict_copy_texture(const void* dest) noexcept { - // Dynamic palette textures are keyed on the copy texture's raw TextureRef pointer; evicting the copy without them leaves entries that can match a recycled allocation at the same address and serve a stale conversion. - absl::flat_hash_set sourceIdentities; - bool changed = false; - if (const auto it = g_gxState.copyTextures.find(dest); it != g_gxState.copyTextures.end()) { - if (it->second.handle) { - sourceIdentities.insert(it->second.handle.get()); - } - g_gxState.copyTextures.erase(it); - changed = true; - } - for (auto it = g_gxState.copyTextureCache.begin(); it != g_gxState.copyTextureCache.end();) { - if (it->first.dest == dest) { - if (it->second.handle) { - sourceIdentities.insert(it->second.handle.get()); - } - g_gxState.copyTextureCache.erase(it++); - changed = true; - } else { - ++it; - } - } - if (!sourceIdentities.empty()) { - for (auto& [_, cache] : s_tlutObjectCaches) { - for (auto it = cache.dynamicPaletteTextures.begin(); it != cache.dynamicPaletteTextures.end();) { - if (sourceIdentities.contains(it->first.sourceIdentity)) { - cache.dynamicPaletteTextures.erase(it++); - } else { - ++it; - } - } - } - } - prune_copy_texture_pool(dest); - if (changed) { - mark_copy_texture_cache_changed(); - } -} - -static void mark_copy_texture_cache_changed() noexcept { - ++s_copyTextureStateRevision; - if (s_copyTextureStateRevision == 0) { - s_copyTextureStateRevision = 1; - s_lastNoCopyResolveRevision.fill(0); - } -} - -void mark_copy_texture_sampled(const void* copyDest, GXState::CopyTextureRef& copyRef) noexcept { - const auto frame = gfx::current_frame(); - copyRef.lastSampledFrame = frame; - copyRef.sampledThisFrame = true; - - if (auto it = g_gxState.copyTextures.find(copyDest); - it != g_gxState.copyTextures.end() && it->second.handle == copyRef.handle) { - it->second.lastSampledFrame = frame; - it->second.sampledThisFrame = true; - } - - const GXState::CopyTextureKey key{ - .dest = copyDest, - .width = copyRef.width, - .height = copyRef.height, - .format = copyRef.format, - }; - if (auto it = g_gxState.copyTextureCache.find(key); it != g_gxState.copyTextureCache.end() && - it->second.handle == copyRef.handle) { - it->second.lastSampledFrame = frame; - it->second.sampledThisFrame = true; - } - -} - -bool copy_ref_matches_texobj(const GXState::CopyTextureRef& copyRef, const GXTexObj_& obj) noexcept { - return copyRef && copyRef.width == obj.width() && copyRef.height == obj.height() && - copy_texture_format_compatible(copyRef.format, obj.format()); -} - -void notify_copy_texture_created() noexcept { - mark_copy_texture_cache_changed(); -} - - -GXState::CopyTextureRef* find_cached_copy_texture(const void* copyDest, const GXTexObj_& obj) noexcept { - const GXState::CopyTextureKey key{ - .dest = copyDest, - .width = obj.width(), - .height = obj.height(), - .format = static_cast(obj.format()), - }; - auto cached = g_gxState.copyTextureCache.find(key); - if (cached == g_gxState.copyTextureCache.end() || !cached->second) { - return nullptr; - } - mark_copy_texture_sampled(copyDest, cached->second); - return &cached->second; -} - -GXState::CopyTextureRef* find_copy_texture_for_texobj(const GXTexObj_& obj) noexcept { - if (obj.data == nullptr) { - return nullptr; - } - - if (auto* cached = find_cached_copy_texture(obj.data, obj)) { - return cached; - } - - const auto exact = g_gxState.copyTextures.find(obj.data); - if (exact != g_gxState.copyTextures.end() && copy_ref_matches_texobj(exact->second, obj)) { - mark_copy_texture_sampled(obj.data, exact->second); - return &exact->second; - } - // A guest allocation can be recycled while an old GPU-only EFB copy still exists. - return nullptr; -} - -void resolve_sampled_textures(const ShaderInfo& info) noexcept { - ZoneScoped; - - for (u32 i = 0; i < MaxTextures; ++i) { - if (!info.sampledTextures.test(i)) { - continue; - } - - GXTexObj_ obj = g_gxState.loadedTextures[i]; - auto& textureBind = g_gxState.textures[i]; - const TextureResolveIdentity identity = make_texture_resolve_identity(obj); - // obj is unchanged between here and the memo checks below, so the two former can_cache_static_texture_upload(obj) calls are one value. - const bool canCacheUpload = can_cache_static_texture_upload(obj); - const bool sameResolvedTexture = canCacheUpload && s_lastTextureResolveIdentityValid[i] && - s_lastTextureResolveIdentity[i] == identity; - // The primary per-texmap memo below consumes neither the source key nor its hash, so building them ahead of it wasted make_static_texture_key on the hottest path (same texture bound across consecutive draws). - if (sameResolvedTexture && s_lastNoCopyResolveRevision[i] == s_copyTextureStateRevision) { - continue; - } - const bool canUseStaticSourceKey = - !is_palette_format(obj.format()) && canCacheUpload && !obj.no_cache() && - obj.data != nullptr; - const StaticTextureKey staticSourceKey = - canUseStaticSourceKey ? make_static_texture_key(obj) : StaticTextureKey{}; - const size_t identityHash = canUseStaticSourceKey ? absl::Hash{}(identity) : 0; - if (canUseStaticSourceKey) { - const auto& entry = s_textureResolveIdentityCache[identityHash & (s_textureResolveIdentityCache.size() - 1)]; - if (entry.valid && entry.hash == identityHash && entry.copyTextureRevision == s_copyTextureStateRevision && - entry.validationRevision == s_staticTextureCacheValidationRevision && entry.identity == identity && - entry.binding) { - textureBind = entry.binding; - note_texture_cache_stamp(); - s_lastTextureResolveIdentity[i] = identity; - s_lastTextureResolveIdentityValid[i] = true; - s_lastNoCopyResolveRevision[i] = s_copyTextureStateRevision; - s_lastStaticSourceResolveKey[i] = staticSourceKey; - s_lastStaticSourceResolveKeyValid[i] = true; - s_lastStaticSourceNoCopyRevision[i] = s_copyTextureStateRevision; - continue; - } - } - if (canUseStaticSourceKey && textureBind.ref && s_lastStaticSourceResolveKeyValid[i] && - s_lastStaticSourceResolveKey[i] == staticSourceKey && - s_lastStaticSourceNoCopyRevision[i] == s_copyTextureStateRevision) { - obj.mFormat = resolved_format_for_handle(textureBind.ref); - textureBind.texObj = obj; - s_lastTextureResolveIdentity[i] = identity; - s_lastTextureResolveIdentityValid[i] = true; - s_lastNoCopyResolveRevision[i] = s_copyTextureStateRevision; - note_texture_cache_stamp(); - continue; - } - - GXState::CopyTextureRef* copyRef = find_copy_texture_for_texobj(obj); - if (sameResolvedTexture) { - if (copyRef == nullptr) { - s_lastNoCopyResolveRevision[i] = s_copyTextureStateRevision; - continue; - } - if (!is_palette_format(obj.format()) && textureBind.ref == copyRef->handle) { - s_lastNoCopyResolveRevision[i] = 0; - continue; - } - } - - gfx::TextureHandle handle; - if (is_palette_format(obj.format())) { - const auto tlutIdx = static_cast(obj.tlut); - if (tlutIdx < g_gxState.loadedTluts.size()) { - const auto& tlut = g_gxState.loadedTluts[tlutIdx]; - if (tlut.data != nullptr) { - if (copyRef != nullptr) { - handle = resolve_dynamic_palette_texture(obj, *copyRef, tlut); - } else if (obj.data != nullptr) { - handle = resolve_static_palette_texture(obj, tlut); - } - } - } - } else if (copyRef != nullptr) { - handle = copyRef->handle; - } else if (obj.data != nullptr) { - handle = resolve_static_texture(obj); - } - - obj.mFormat = resolved_format_for_handle(handle); - textureBind = gfx::TextureBind{obj, std::move(handle)}; - // The per-texmap memo below lets a later draw reuse this binding without touching guest memory again, including for no_cache textures that never reach any of the stamped caches above, so it has to count as a stamp. - note_texture_cache_stamp(); - s_lastTextureResolveIdentity[i] = identity; - s_lastTextureResolveIdentityValid[i] = true; - s_lastNoCopyResolveRevision[i] = (copyRef == nullptr) ? s_copyTextureStateRevision : 0; - s_lastStaticSourceResolveKeyValid[i] = canUseStaticSourceKey && copyRef == nullptr; - if (s_lastStaticSourceResolveKeyValid[i]) { - s_lastStaticSourceResolveKey[i] = staticSourceKey; - s_lastStaticSourceNoCopyRevision[i] = s_copyTextureStateRevision; - auto& entry = s_textureResolveIdentityCache[identityHash & (s_textureResolveIdentityCache.size() - 1)]; - entry.valid = true; - entry.hash = identityHash; - entry.copyTextureRevision = s_copyTextureStateRevision; - entry.validationRevision = s_staticTextureCacheValidationRevision; - entry.identity = identity; - entry.binding = textureBind; - note_texture_cache_stamp(); - } else { - s_lastStaticSourceNoCopyRevision[i] = 0; - } - } -} - -static inline wgpu::BlendFactor to_blend_factor(GXBlendFactor fac, bool isDst, bool alphaComponent) { - switch (fac) { - DEFAULT_FATAL("invalid blend factor {}", underlying(fac)); - case GX_BL_ZERO: - return wgpu::BlendFactor::Zero; - case GX_BL_ONE: - return wgpu::BlendFactor::One; - case GX_BL_SRCCLR: // + GX_BL_DSTCLR - if (alphaComponent) { - return isDst ? wgpu::BlendFactor::SrcAlpha : wgpu::BlendFactor::DstAlpha; - } - if (isDst) { - return wgpu::BlendFactor::Src; - } else { - return wgpu::BlendFactor::Dst; - } - case GX_BL_INVSRCCLR: // + GX_BL_INVDSTCLR - if (alphaComponent) { - return isDst ? wgpu::BlendFactor::OneMinusSrcAlpha : wgpu::BlendFactor::OneMinusDstAlpha; - } - if (isDst) { - return wgpu::BlendFactor::OneMinusSrc; - } else { - return wgpu::BlendFactor::OneMinusDst; - } - case GX_BL_SRCALPHA: - return wgpu::BlendFactor::SrcAlpha; - case GX_BL_INVSRCALPHA: - return wgpu::BlendFactor::OneMinusSrcAlpha; - case GX_BL_DSTALPHA: - return wgpu::BlendFactor::DstAlpha; - case GX_BL_INVDSTALPHA: - return wgpu::BlendFactor::OneMinusDstAlpha; - } -} - -static inline GXBlendFactor remove_dst_alpha_usage(GXBlendFactor fac) { - switch (fac) { - case GX_BL_DSTALPHA: - return GX_BL_ONE; - case GX_BL_INVDSTALPHA: - return GX_BL_ZERO; - default: - return fac; - } -} - -// GX_LEQUAL etc. describe "pass if this pixel is closer than/equal to what's stored" in GX's own -// distance terms, independent of how that distance is encoded as a host depth value. Under -// UseReversedZ the encoding is flipped (near=1, far=0), so "closer" now corresponds to a *larger* -// stored value, not a smaller one - the ordered compare functions (LESS/LEQUAL/GREATER/GEQUAL) -// must invert to match, or the depth test silently runs backwards (verified directly: this was -// the actual cause of a bug report after the projection/shader half of the reverse-Z fix -// eliminated the double-negation that used to accidentally keep the unreversed comparisons -// correct - LEQUAL now needs GreaterEqual, not LessEqual, once the encoding it's testing against -// is genuinely reversed). Matches upstream aurora's to_compare_function exactly. -static inline wgpu::CompareFunction to_compare_function(GXCompare func) { - switch (func) { - DEFAULT_FATAL("invalid depth fn {}", underlying(func)); - case GX_NEVER: - return wgpu::CompareFunction::Never; - case GX_LESS: - return UseReversedZ ? wgpu::CompareFunction::Greater : wgpu::CompareFunction::Less; - case GX_EQUAL: - return wgpu::CompareFunction::Equal; - case GX_LEQUAL: - return UseReversedZ ? wgpu::CompareFunction::GreaterEqual : wgpu::CompareFunction::LessEqual; - case GX_GREATER: - return UseReversedZ ? wgpu::CompareFunction::Less : wgpu::CompareFunction::Greater; - case GX_NEQUAL: - return wgpu::CompareFunction::NotEqual; - case GX_GEQUAL: - return UseReversedZ ? wgpu::CompareFunction::LessEqual : wgpu::CompareFunction::GreaterEqual; - case GX_ALWAYS: - return wgpu::CompareFunction::Always; - } -} - -static inline wgpu::BlendState to_blend_state(GXBlendMode mode, GXBlendFactor srcFac, GXBlendFactor dstFac, - GXLogicOp op, GXPixelFmt pixelFmt, u32 dstAlpha) { - wgpu::BlendComponent colorBlendComponent; - switch (mode) { - DEFAULT_FATAL("unsupported blend mode {}", underlying(mode)); - case GX_BM_NONE: - colorBlendComponent = { - .operation = wgpu::BlendOperation::Add, - .srcFactor = wgpu::BlendFactor::One, - .dstFactor = wgpu::BlendFactor::Zero, - }; - break; - case GX_BM_BLEND: - if (!render_target_has_alpha(pixelFmt)) { - srcFac = remove_dst_alpha_usage(srcFac); - dstFac = remove_dst_alpha_usage(dstFac); - } - colorBlendComponent = { - .operation = wgpu::BlendOperation::Add, - .srcFactor = to_blend_factor(srcFac, false, false), - .dstFactor = to_blend_factor(dstFac, true, false), - }; - break; - case GX_BM_SUBTRACT: - colorBlendComponent = { - .operation = wgpu::BlendOperation::ReverseSubtract, - .srcFactor = wgpu::BlendFactor::One, - .dstFactor = wgpu::BlendFactor::One, - }; - break; - case GX_BM_LOGIC: - switch (op) { - default: - // WebGPU exposes blend factors, but not fixed-function integer logic ops. - colorBlendComponent = { - .operation = wgpu::BlendOperation::Add, - .srcFactor = wgpu::BlendFactor::One, - .dstFactor = wgpu::BlendFactor::Zero, - }; - break; - case GX_LO_CLEAR: - colorBlendComponent = { - .operation = wgpu::BlendOperation::Add, - .srcFactor = wgpu::BlendFactor::Zero, - .dstFactor = wgpu::BlendFactor::Zero, - }; - break; - case GX_LO_AND: - case GX_LO_REVAND: - case GX_LO_XOR: - case GX_LO_NOR: - case GX_LO_EQUIV: - case GX_LO_INV: - case GX_LO_REVOR: - case GX_LO_INVCOPY: - case GX_LO_INVOR: - case GX_LO_NAND: - case GX_LO_COPY: - case GX_LO_SET: - colorBlendComponent = { - .operation = wgpu::BlendOperation::Add, - .srcFactor = wgpu::BlendFactor::One, - .dstFactor = wgpu::BlendFactor::Zero, - }; - break; - case GX_LO_INVAND: - colorBlendComponent = { - .operation = wgpu::BlendOperation::Add, - .srcFactor = wgpu::BlendFactor::Zero, - .dstFactor = wgpu::BlendFactor::OneMinusSrc, - }; - break; - case GX_LO_NOOP: - colorBlendComponent = { - .operation = wgpu::BlendOperation::Add, - .srcFactor = wgpu::BlendFactor::Zero, - .dstFactor = wgpu::BlendFactor::One, - }; - break; - case GX_LO_OR: - // WebGPU has no fixed-function integer logic op. - colorBlendComponent = { - .operation = wgpu::BlendOperation::Max, - .srcFactor = wgpu::BlendFactor::One, - .dstFactor = wgpu::BlendFactor::One, - }; - break; - } - break; - } - wgpu::BlendComponent alphaBlendComponent; - if (dstAlpha != UINT32_MAX) { - alphaBlendComponent = wgpu::BlendComponent{ - .operation = wgpu::BlendOperation::Add, - .srcFactor = wgpu::BlendFactor::Constant, - .dstFactor = wgpu::BlendFactor::Zero, - }; - } else if (mode == GX_BM_BLEND) { - alphaBlendComponent = wgpu::BlendComponent{ - .operation = wgpu::BlendOperation::Add, - .srcFactor = to_blend_factor(srcFac, false, true), - .dstFactor = to_blend_factor(dstFac, true, true), - }; - } else { - alphaBlendComponent = colorBlendComponent; - } - return { - .color = colorBlendComponent, - .alpha = alphaBlendComponent, - }; -} - -static inline bool effective_alpha_update(GXPixelFmt pixelFmt, bool alphaUpdate) { - return alphaUpdate && render_target_has_alpha(pixelFmt); -} - -static inline u32 effective_dst_alpha(GXPixelFmt pixelFmt, bool alphaUpdate, u32 dstAlpha) { - return effective_alpha_update(pixelFmt, alphaUpdate) ? dstAlpha : UINT32_MAX; -} - -static inline wgpu::ColorWriteMask to_write_mask(bool colorUpdate, bool alphaUpdate) { - wgpu::ColorWriteMask writeMask = wgpu::ColorWriteMask::None; - if (colorUpdate) { - writeMask |= wgpu::ColorWriteMask::Red | wgpu::ColorWriteMask::Green | wgpu::ColorWriteMask::Blue; - } - if (alphaUpdate) { - writeMask |= wgpu::ColorWriteMask::Alpha; - } - return writeMask; -} - -static inline wgpu::PrimitiveState to_primitive_state(GXCullMode gx_cullMode) { - auto cullMode = wgpu::CullMode::None; - switch (gx_cullMode) { - DEFAULT_FATAL("unsupported cull mode {}", underlying(gx_cullMode)); - case GX_CULL_FRONT: - cullMode = wgpu::CullMode::Front; - break; - case GX_CULL_BACK: - cullMode = wgpu::CullMode::Back; - break; - case GX_CULL_ALL: - // todo: remove? since all calls get dropped anyways - cullMode = wgpu::CullMode::Front; - break; - case GX_CULL_NONE: - break; - } - return { - .topology = wgpu::PrimitiveTopology::TriangleList, - .stripIndexFormat = wgpu::IndexFormat::Undefined, - .frontFace = wgpu::FrontFace::CW, - .cullMode = cullMode, - }; -} - -wgpu::RenderPipeline build_pipeline(const PipelineConfig& config, ArrayRef vtxBuffers, - wgpu::ShaderModule shader, const char* label) noexcept { - ZoneScoped; - const wgpu::DepthStencilState depthStencil{ - .format = g_graphicsConfig.depthFormat, - .depthWriteEnabled = config.depthUpdate, - .depthCompare = config.depthCompare ? to_compare_function(config.depthFunc) : wgpu::CompareFunction::Always, - }; - const auto blendState = to_blend_state(config.blendMode, config.blendFacSrc, config.blendFacDst, config.blendOp, - config.pixelFmt, config.dstAlpha); - const std::array colorTargets{wgpu::ColorTargetState{ - .format = g_graphicsConfig.surfaceConfiguration.format, - .blend = &blendState, - .writeMask = to_write_mask(config.colorUpdate, config.alphaUpdate), - }}; - const wgpu::FragmentState fragmentState{ - .module = shader, - .entryPoint = "fs_main", - .targetCount = colorTargets.size(), - .targets = colorTargets.data(), - }; - const wgpu::RenderPipelineDescriptor descriptor{ - .label = label, - .layout = sPipelineLayout, - .vertex = - { - .module = shader, - .entryPoint = "vs_main", - .bufferCount = static_cast(vtxBuffers.size()), - .buffers = vtxBuffers.data(), - }, - .primitive = to_primitive_state(config.cullMode), - .depthStencil = &depthStencil, - .multisample = - wgpu::MultisampleState{ - .count = config.msaaSamples, - }, - .fragment = &fragmentState, - }; - return g_device.CreateRenderPipeline(&descriptor); -} - -u8 comp_type_size(GXAttr attr, GXCompType type) noexcept { - switch (attr) { - case GX_VA_PNMTXIDX: - case GX_VA_TEX0MTXIDX: - case GX_VA_TEX1MTXIDX: - case GX_VA_TEX2MTXIDX: - case GX_VA_TEX3MTXIDX: - case GX_VA_TEX4MTXIDX: - case GX_VA_TEX5MTXIDX: - case GX_VA_TEX6MTXIDX: - case GX_VA_TEX7MTXIDX: - return 1; - case GX_VA_CLR0: - case GX_VA_CLR1: - switch (type) { - case GX_RGB565: - case GX_RGBA4: - return 2; - case GX_RGB8: - case GX_RGBA6: - return 3; - case GX_RGBX8: - case GX_RGBA8: - return 4; - } - default: - switch (type) { - case GX_U8: - case GX_S8: - return 1; - case GX_U16: - case GX_S16: - return 2; - case GX_F32: - return 4; - default: - Log.fatal("comp_type_size: Unsupported component type {}", type); - } - } -} - -u8 comp_cnt_count(GXAttr attr, GXCompCnt cnt) noexcept { - switch (attr) { - case GX_VA_PNMTXIDX: - case GX_VA_TEX0MTXIDX: - case GX_VA_TEX1MTXIDX: - case GX_VA_TEX2MTXIDX: - case GX_VA_TEX3MTXIDX: - case GX_VA_TEX4MTXIDX: - case GX_VA_TEX5MTXIDX: - case GX_VA_TEX6MTXIDX: - case GX_VA_TEX7MTXIDX: - return 1; - case GX_VA_POS: - switch (cnt) { - case GX_POS_XY: - return 2; - case GX_POS_XYZ: - return 3; - default: - break; - } - break; - case GX_VA_NRM: - switch (cnt) { - case GX_NRM_XYZ: - return 3; - case GX_NRM_NBT: - case GX_NRM_NBT3: - return 9; - default: - break; - } - break; - case GX_VA_CLR0: - case GX_VA_CLR1: - return 1; - case GX_VA_TEX0: - case GX_VA_TEX1: - case GX_VA_TEX2: - case GX_VA_TEX3: - case GX_VA_TEX4: - case GX_VA_TEX5: - case GX_VA_TEX6: - case GX_VA_TEX7: - switch (cnt) { - case GX_TEX_S: - return 1; - case GX_TEX_ST: - return 2; - default: - break; - } - break; - default: - break; - } - Log.fatal("comp_cnt_count: Unsupported attr/cnt {} {}", attr, cnt); -} - -static u8 index_attr_size(GXAttr attr, GXCompCnt cnt, GXAttrType type) noexcept { - const u8 indexSize = type == GX_INDEX16 ? 2 : 1; - if (attr == GX_VA_NRM && cnt == GX_NRM_NBT3) { - return indexSize * 3; - } - return indexSize; -} - -void populate_pipeline_config(PipelineConfig& config, GXPrimitive primitive, GXVtxFmt fmt) noexcept { - ZoneScoped; - - const auto& vtxFmt = g_gxState.vtxFmts[fmt]; - // GX applies integer logic ops in the PE after fog. - config.shaderConfig.fogType = effective_pipeline_fog_type( - g_gxState.fog.type, g_gxState.zTextureOp, g_gxState.zCompLocBeforeTex, - g_gxState.blendMode, g_gxState.blendOp); - config.shaderConfig.fogRangeAdjust = - config.shaderConfig.fogType != GX_FOG_NONE && (g_gxState.fogRange[0] & (1u << 10)) != 0; - u8 vtxOffset = 0; - for (int i = GX_VA_PNMTXIDX; i <= GX_VA_TEX7; ++i) { - const auto attr = static_cast(i); - const auto type = g_gxState.vtxDesc[i]; - auto& mapping = config.shaderConfig.attrs[i]; - if (type == GX_NONE) { - mapping = {}; - continue; - } - const auto& attrFmt = vtxFmt.attrs[i]; - const auto cnt = comp_cnt_count(attr, attrFmt.cnt); - mapping = AttrConfig{ - .attrType = static_cast(type), - .cnt = cnt, - .compType = static_cast(attrFmt.type), - .offset = vtxOffset, - .stride = 0, - .frac = attrFmt.frac, - .le = false, - .nrmIndexCount = static_cast(attr == GX_VA_NRM && attrFmt.cnt == GX_NRM_NBT3 ? 3 : 1), - }; - switch (type) { - case GX_DIRECT: { - vtxOffset += comp_type_size(attr, attrFmt.type) * cnt; - break; - } - case GX_INDEX8: - mapping.stride = g_gxState.arrays[i].stride; - mapping.le = g_gxState.arrays[i].le; - vtxOffset += index_attr_size(attr, attrFmt.cnt, type); - break; - case GX_INDEX16: - mapping.stride = g_gxState.arrays[i].stride; - mapping.le = g_gxState.arrays[i].le; - vtxOffset += index_attr_size(attr, attrFmt.cnt, type); - break; - default: - Log.fatal("populate_pipeline_config: Invalid vertex type {}", type); - } - } - config.shaderConfig.vtxStride = vtxOffset; - if (primitive == GX_LINES) { - config.shaderConfig.lineMode = 1; - } else if (primitive == GX_LINESTRIP) { - config.shaderConfig.lineMode = 2; - } else if (primitive == GX_POINTS) { - config.shaderConfig.lineMode = 3; - } else { - config.shaderConfig.lineMode = 0; - } - config.shaderConfig.dualTexEnabled = (g_gxState.dualTex & 1u) != 0; - config.shaderConfig.tevSwapTable = g_gxState.tevSwapTable; - for (u8 i = 0; i < g_gxState.numTevStages; ++i) { - config.shaderConfig.tevStages[i] = g_gxState.tevStages[i]; - } - config.shaderConfig.tevStageCount = g_gxState.numTevStages; - config.shaderConfig.numTexGens = g_gxState.numTexGens; - if (g_gxState.zTextureOp != GX_ZT_DISABLE && !g_gxState.zCompLocBeforeTex) { - config.shaderConfig.zTexture = (g_gxState.zTextureBias & 0x00FFFFFFu) | - ((static_cast(g_gxState.zTextureFmt) & 0x3u) << 24) | - ((static_cast(g_gxState.zTextureOp) & 0x3u) << 26); - } - for (u8 i = 0; i < g_gxState.numIndStages; ++i) { - config.shaderConfig.indStages[i] = g_gxState.indStages[i]; - } - config.shaderConfig.numIndStages = g_gxState.numIndStages; - for (u8 i = 0; i < MaxColorChannels; ++i) { - const auto& cc = g_gxState.colorChannelConfig[i]; - if (cc.lightingEnabled) { - config.shaderConfig.colorChannels[i] = cc; - } else { - // Only matSrc matters when lighting disabled - config.shaderConfig.colorChannels[i] = { - .matSrc = cc.matSrc, - }; - } - } - for (u8 i = 0; i < MaxTexCoord; ++i) { - config.shaderConfig.tcgs[i].src = static_cast(GX_TG_TEX0 + i); - } - for (u8 i = 0; i < g_gxState.numTexGens; ++i) { - config.shaderConfig.tcgs[i] = g_gxState.tcgs[i]; - } - config.shaderConfig.alphaCompare = {}; - if (g_gxState.alphaCompare) { - config.shaderConfig.alphaCompare = g_gxState.alphaCompare; - } - // The remaining fields are assigned in place. - config.version = GXPipelineConfigVersion; - config.msaaSamples = gfx::get_sample_count(); - config.depthFunc = g_gxState.depthFunc; - config.cullMode = config.shaderConfig.lineMode == 0 ? g_gxState.cullMode : GX_CULL_NONE; - config.blendMode = g_gxState.blendMode; - config.blendFacSrc = g_gxState.blendFacSrc; - config.blendFacDst = g_gxState.blendFacDst; - config.blendOp = g_gxState.blendOp; - config.pixelFmt = g_gxState.pixelFmt; - config.dstAlpha = effective_dst_alpha(g_gxState.pixelFmt, g_gxState.alphaUpdate, g_gxState.dstAlpha); - config.depthCompare = g_gxState.depthCompare; - config.depthUpdate = g_gxState.depthUpdate; - config.alphaUpdate = effective_alpha_update(g_gxState.pixelFmt, g_gxState.alphaUpdate); - config.colorUpdate = g_gxState.colorUpdate; -} - -static TextureBindGroupCacheKey make_texture_bind_group_cache_key(const ShaderInfo& info) noexcept { - TextureBindGroupCacheKey key{ - .sampledTextures = info.sampledTextures.to_ullong(), - .sampledIndTextures = info.sampledIndTextures.to_ullong(), - }; - for (u32 i = 0; i < MaxTextures; ++i) { - if (!info.sampledTextures[i] && !info.sampledIndTextures[i]) { - continue; - } - const auto& tex = g_gxState.textures[i]; - if (!tex) { - continue; - } - const u32 refState = (tex.ref->isReplacement ? 1u : 0u) | (tex.ref->hasArbitraryMips ? 2u : 0u) | - (tex.ref->mipCount << 8); - set_texture_bind_group_cache_slot(key, i, tex.ref->sampleTextureView.Get(), tex.texObj.mode0, - tex.texObj.mode1, refState); - } - return key; -} - -static HashType hash_texture_bind_group_cache_key(const TextureBindGroupCacheKey& key) noexcept { - // The key is a 176-byte POD with no padding, so one hash over the whole thing replaces the six chained XXH3 calls this used to make per draw. - static_assert(std::has_unique_object_representations_v); - return xxh3_hash(key); -} - -static GXBindGroups build_bind_groups_uncached(const ShaderInfo& info) noexcept { - ZoneScoped; - - if (!info.sampledTextures.any() && !info.sampledIndTextures.any()) { - // Don't bother re-binding anything - return {}; - } - - // Using C WGPU types instead of C++ wrappers to avoid destructor overhead - std::array textureEntries{}; - for (u32 i = 0; i < MaxTextures; ++i) { - const auto& tex = g_gxState.textures[i]; - WGPUBindGroupEntry& textureEntry = textureEntries[i * 2]; - WGPUBindGroupEntry& samplerEntry = textureEntries[i * 2 + 1]; - textureEntry.binding = i * 2; - samplerEntry.binding = i * 2 + 1; - if (tex && (info.sampledTextures[i] || info.sampledIndTextures[i])) { - textureEntry.textureView = tex.ref->sampleTextureView.Get(); - samplerEntry.sampler = gfx::sampler_ref(tex.get_descriptor()).Get(); - } else { - textureEntry.textureView = sEmptyTextureView.Get(); - samplerEntry.sampler = sEmptySampler.Get(); - } - } - const WGPUBindGroupDescriptor textureBindGroupDescriptor{ - .label = {"GX Texture Bind Group", WGPU_STRLEN}, - .layout = sTextureBindGroupLayout.Get(), - .entryCount = textureEntries.size(), - .entries = textureEntries.data(), - }; - const auto ref = gfx::bind_group_ref(textureBindGroupDescriptor); - return { - .textureBindGroup = ref, - .resolvedTextureBindGroup = gfx::find_bind_group(ref).Get(), - }; -} - -GXBindGroups build_bind_groups(const ShaderInfo& info) noexcept { - ZoneScoped; - - if (!info.sampledTextures.any() && !info.sampledIndTextures.any()) { - return {}; - } - - constexpr size_t CacheSize = 1024; - struct Entry { - bool valid = false; - u32 frame = 0; - HashType hash = 0; - TextureBindGroupCacheKey key{}; - GXBindGroups bindGroups{}; - }; - static std::array cache{}; - - const auto key = make_texture_bind_group_cache_key(info); - const HashType hash = hash_texture_bind_group_cache_key(key); - const u32 frame = gfx::current_frame(); - auto& entry = cache[hash & (CacheSize - 1)]; - if (entry.valid && entry.frame == frame && entry.hash == hash && entry.key == key) { - return entry.bindGroups; - } - - const auto bindGroups = build_bind_groups_uncached(info); - entry.valid = true; - entry.frame = frame; - entry.hash = hash; - entry.key = key; - entry.bindGroups = bindGroups; - return bindGroups; -} - -void initialize() noexcept { - { - std::array textureEntries; - for (u32 i = 0; i < MaxTextures; ++i) { - textureEntries[i * 2] = { - .binding = i * 2, - .visibility = wgpu::ShaderStage::Fragment, - .texture = - { - .sampleType = wgpu::TextureSampleType::Float, - .viewDimension = wgpu::TextureViewDimension::e2D, - }, - }; - textureEntries[i * 2 + 1] = { - .binding = i * 2 + 1, - .visibility = wgpu::ShaderStage::Fragment, - .sampler = {.type = wgpu::SamplerBindingType::Filtering}, - }; - } - const wgpu::BindGroupLayoutDescriptor descriptor{ - .label = "GX Texture Bind Group Layout", - .entryCount = textureEntries.size(), - .entries = textureEntries.data(), - }; - sTextureBindGroupLayout = g_device.CreateBindGroupLayout(&descriptor); - } - { - constexpr wgpu::SamplerDescriptor descriptor{.label = "Empty sampler"}; - sEmptySampler = gfx::sampler_ref(descriptor); - } - { - constexpr wgpu::TextureDescriptor descriptor{ - .label = "Empty texture", - .usage = wgpu::TextureUsage::TextureBinding, - .size = {1, 1}, - .format = wgpu::TextureFormat::RGBA8Unorm, - }; - sEmptyTexture = g_device.CreateTexture(&descriptor); - sEmptyTextureView = sEmptyTexture.CreateView(); - } - { - std::array entries; - for (u32 i = 0; i < MaxTextures; ++i) { - entries[i * 2] = { - .binding = i * 2, - .textureView = sEmptyTextureView, - }; - entries[i * 2 + 1] = { - .binding = i * 2 + 1, - .sampler = sEmptySampler, - }; - } - const wgpu::BindGroupDescriptor desc{ - .label = "GX Empty Texture Bind Group", - .layout = sTextureBindGroupLayout, - .entryCount = entries.size(), - .entries = entries.data(), - }; - g_emptyTextureBindGroup = g_device.CreateBindGroup(&desc); - } - { - const std::array layouts{ - gfx::g_staticBindGroupLayout, - gfx::g_uniformBindGroupLayout, - sTextureBindGroupLayout, - }; - const wgpu::PipelineLayoutDescriptor desc{ - .label = "GX Pipeline Layout", - .bindGroupLayoutCount = layouts.size(), - .bindGroupLayouts = layouts.data(), - }; - sPipelineLayout = g_device.CreatePipelineLayout(&desc); - } -} - -void shutdown() noexcept { - // TODO we should probably store this all in g_state.gx instead - sSamplerBindGroupLayout = {}; - sTextureBindGroupLayout = {}; - { - std::lock_guard lock{sBindGroupLayoutMutex}; - sUniformBindGroupLayouts.clear(); - sTextureBindGroupLayouts.clear(); - } - for (auto& item : g_gxState.textures) { - item.ref.reset(); - } - s_textureObjectCaches.clear(); - s_tlutObjectCaches.clear(); - s_staticTextureSourceCache.clear(); - s_staticPaletteTextureSourceCache.clear(); - s_texObjSourceKeys.clear(); - s_texObjPaletteSourceKeys.clear(); - s_texObjSourceKeyMemo.reset(); - s_texObjPaletteSourceKeyMemo.reset(); - clear_static_source_front_cache(); - // The resolve identity cache holds texture references too; it is revision gated rather than cleared during normal operation, so it has to be dropped explicitly here. - for (auto& entry : s_textureResolveIdentityCache) { - entry.valid = false; - entry.binding.reset(); - } - s_lastTextureResolveIdentityValid.fill(false); - s_lastStaticSourceResolveKeyValid.fill(false); - g_gxState.loadedTextures.fill({}); - g_gxState.loadedTluts.fill({}); - clear_copy_texture_cache(); -} -} // namespace aurora::gx - -static wgpu::AddressMode wgpu_address_mode(GXTexWrapMode mode) { - switch (mode) { - DEFAULT_FATAL("invalid wrap mode {}", underlying(mode)); - case GX_CLAMP: - return wgpu::AddressMode::ClampToEdge; - case GX_REPEAT: - return wgpu::AddressMode::Repeat; - case GX_MIRROR: - return wgpu::AddressMode::MirrorRepeat; - } -} - -static std::pair wgpu_filter_mode(GXTexFilter filter) { - switch (filter) { - DEFAULT_FATAL("invalid filter mode {}", static_cast(filter)); - case GX_NEAR: - return {wgpu::FilterMode::Nearest, wgpu::MipmapFilterMode::Undefined}; - case GX_LINEAR: - return {wgpu::FilterMode::Linear, wgpu::MipmapFilterMode::Undefined}; - case GX_NEAR_MIP_NEAR: - return {wgpu::FilterMode::Nearest, wgpu::MipmapFilterMode::Nearest}; - case GX_LIN_MIP_NEAR: - return {wgpu::FilterMode::Linear, wgpu::MipmapFilterMode::Nearest}; - case GX_NEAR_MIP_LIN: - return {wgpu::FilterMode::Nearest, wgpu::MipmapFilterMode::Linear}; - case GX_LIN_MIP_LIN: - return {wgpu::FilterMode::Linear, wgpu::MipmapFilterMode::Linear}; - } -} - -static u16 wgpu_aniso(GXAnisotropy aniso) { - switch (aniso) { - DEFAULT_FATAL("invalid aniso {}", static_cast(aniso)); - case GX_ANISO_1: - case GX_MAX_ANISOTROPY: - return 1; - case GX_ANISO_2: - return std::max(aurora::webgpu::g_graphicsConfig.textureAnisotropy / 2, 1); - case GX_ANISO_4: - return std::max(aurora::webgpu::g_graphicsConfig.textureAnisotropy, 1); - } -} - -static bool supports_wgpu_aniso(wgpu::FilterMode magFilter, wgpu::FilterMode minFilter, - wgpu::MipmapFilterMode mipFilter) { - return magFilter == wgpu::FilterMode::Linear && minFilter == wgpu::FilterMode::Linear && - mipFilter == wgpu::MipmapFilterMode::Linear; -} - -wgpu::SamplerDescriptor aurora::gfx::TextureBind::get_descriptor() const noexcept { - auto [minFilter, mipFilter] = wgpu_filter_mode(texObj.min_filter()); - const auto [magFilter, _] = wgpu_filter_mode(texObj.mag_filter()); - float minLod = texObj.min_lod(); - float maxLod = texObj.max_lod(); - if (ref && ref->isReplacement) { - minFilter = wgpu::FilterMode::Linear; - mipFilter = wgpu::MipmapFilterMode::Linear; - minLod = 0.f; - maxLod = static_cast(std::max(ref->mipCount, 1u) - 1u); - } else if (ref && ref->hasArbitraryMips && mipFilter != wgpu::MipmapFilterMode::Undefined) { - mipFilter = wgpu::MipmapFilterMode::Linear; - } else if (mipFilter == wgpu::MipmapFilterMode::Undefined) { - minLod = 0.f; - maxLod = 0.f; - } - u16 maxAnisotropy = wgpu_aniso(texObj.max_aniso()); - if (maxAnisotropy > 1 && !supports_wgpu_aniso(magFilter, minFilter, mipFilter)) { - maxAnisotropy = 1; - } - return { - .label = "Generated Filtering Sampler", - .addressModeU = wgpu_address_mode(texObj.wrap_s()), - .addressModeV = wgpu_address_mode(texObj.wrap_t()), - .addressModeW = wgpu::AddressMode::Repeat, - .magFilter = magFilter, - .minFilter = minFilter, - .mipmapFilter = mipFilter, - .lodMinClamp = minLod, - .lodMaxClamp = maxLod, - .maxAnisotropy = maxAnisotropy, - }; -} // namespace aurora::gx diff --git a/aurora-main/lib/gx/gx.hpp b/aurora-main/lib/gx/gx.hpp deleted file mode 100644 index 49ceddb..0000000 --- a/aurora-main/lib/gx/gx.hpp +++ /dev/null @@ -1,776 +0,0 @@ -#pragma once -#include -#include - -#include "../internal.hpp" -#include "../gfx/common.hpp" -#include "../gfx/texture.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define M_PIF 3.14159265358979323846f - -namespace GX { -constexpr u8 MaxLights = 8; -using LightMask = std::bitset; -} // namespace GX - -struct GXLightObj_ { - GXColor color; - float a0 = 1.f; - float a1 = 0.f; - float a2 = 0.f; - float k0 = 1.f; - float k1 = 0.f; - float k2 = 0.f; - float px = 0.f; - float py = 0.f; - float pz = 0.f; - float nx = 0.f; - float ny = 0.f; - float nz = 0.f; -}; -static_assert(sizeof(GXLightObj_) <= sizeof(GXLightObj), "GXLightObj too small!"); - -#if GX_IS_WII -constexpr float GX_LARGE_NUMBER = -1.0e+18f; -#else -constexpr float GX_LARGE_NUMBER = -1048576.0f; -#endif - -namespace aurora::gx { -constexpr bool UsePerPixelLighting = false; -constexpr bool UseReversedZ = true; - -constexpr u32 MaxTextures = GX_MAX_TEXMAP; -constexpr u32 MaxTluts = 20; -constexpr u32 MaxTevStages = GX_MAX_TEVSTAGE; -constexpr u32 MaxColorChannels = 4; -constexpr u32 MaxTevRegs = 4; // TEVPREV, TEVREG0-2 -constexpr u32 MaxKColors = GX_MAX_KCOLOR; -constexpr u32 MaxTexMtx = 10; -constexpr u32 MaxPTTexMtx = 20; -constexpr u32 MaxTexCoord = GX_MAX_TEXCOORD; -constexpr u32 MaxVtxAttr = GX_VA_MAX_ATTR; -constexpr u32 MaxTevSwap = GX_MAX_TEVSWAP; -constexpr u32 MaxIndStages = GX_MAX_INDTEXSTAGE; -constexpr u32 MaxIndTexMtxs = 3; -constexpr u32 MaxVtxFmt = GX_MAX_VTXFMT; -constexpr u32 MaxPnMtx = (GX_PNMTX9 / 3) + 1; -// Position and texture matrices share one shader array (`ubuf.postex_mtx`), mirroring XF matrix memory: rows 0..29 (slots 0..9) are position matrices and rows 30..59 (slots 10..19) are texture matrices. -constexpr u32 MaxPostexMtx = MaxPnMtx + MaxTexMtx; -constexpr u32 MaxIndexAttr = 12; // VA_POS -> VA_TEX7 -constexpr u32 MaxUniformSize = 3840; - -extern wgpu::BindGroup g_emptyTextureBindGroup; - -template -struct TevPass { - Arg a = Default; - Arg b = Default; - Arg c = Default; - Arg d = Default; - - bool operator==(const TevPass& rhs) const { return memcmp(this, &rhs, sizeof(*this)) == 0; } - bool operator!=(const TevPass& rhs) const { return !(*this == rhs); } -}; -static_assert(std::has_unique_object_representations_v>); -static_assert(std::has_unique_object_representations_v>); -struct TevOp { - GXTevOp op = GX_TEV_ADD; - GXTevBias bias = GX_TB_ZERO; - GXTevScale scale = GX_CS_SCALE_1; - GXTevRegID outReg = GX_TEVPREV; - bool clamp = true; - u8 _p1 = 0; - u8 _p2 = 0; - u8 _p3 = 0; - - bool operator==(const TevOp& rhs) const { return memcmp(this, &rhs, sizeof(*this)) == 0; } - bool operator!=(const TevOp& rhs) const { return !(*this == rhs); } -}; -static_assert(std::has_unique_object_representations_v); -struct TevStage { - TevPass colorPass; - TevPass alphaPass; - TevOp colorOp; - TevOp alphaOp; - GXTevKColorSel kcSel = GX_TEV_KCSEL_1; - GXTevKAlphaSel kaSel = GX_TEV_KASEL_1; - GXTexCoordID texCoordId = GX_TEXCOORD_NULL; - GXTexMapID texMapId = GX_TEXMAP_NULL; - GXChannelID channelId = GX_COLOR_NULL; - GXTevSwapSel tevSwapRas = GX_TEV_SWAP0; - GXTevSwapSel tevSwapTex = GX_TEV_SWAP0; - GXIndTexStageID indTexStage = GX_INDTEXSTAGE0; - GXIndTexFormat indTexFormat = GX_ITF_8; - GXIndTexBiasSel indTexBiasSel = GX_ITB_NONE; - GXIndTexAlphaSel indTexAlphaSel = GX_ITBA_OFF; - GXIndTexMtxID indTexMtxId = GX_ITM_OFF; - GXIndTexWrap indTexWrapS = GX_ITW_OFF; - GXIndTexWrap indTexWrapT = GX_ITW_OFF; - bool indTexUseOrigLOD = false; - bool indTexAddPrev = false; - u8 _p1 = 0; - u8 _p2 = 0; - - bool operator==(const TevStage& rhs) const { return memcmp(this, &rhs, sizeof(*this)) == 0; } - bool operator!=(const TevStage& rhs) const { return !(*this == rhs); } -}; -static_assert(std::has_unique_object_representations_v); -struct IndStage { - GXTexCoordID texCoordId; - GXTexMapID texMapId; - GXIndTexScale scaleS; - GXIndTexScale scaleT; -}; -static_assert(std::has_unique_object_representations_v); -// For shader generation -struct ColorChannelConfig { - GXColorSrc matSrc = GX_SRC_REG; - GXColorSrc ambSrc = GX_SRC_REG; - GXDiffuseFn diffFn = GX_DF_NONE; - GXAttnFn attnFn = GX_AF_NONE; - bool lightingEnabled = false; - u8 _p1 = 0; - u8 _p2 = 0; - u8 _p3 = 0; - - bool operator==(const ColorChannelConfig& rhs) const { return memcmp(this, &rhs, sizeof(*this)) == 0; } - bool operator!=(const ColorChannelConfig& rhs) const { return !(*this == rhs); } -}; -static_assert(std::has_unique_object_representations_v); -// For uniform generation -struct ColorChannelState { - Vec4 matColor; - Vec4 ambColor; - GX::LightMask lightMask; -}; -struct TcgConfig { - GXTexGenType type = GX_TG_MTX2x4; - GXTexGenSrc src = GX_MAX_TEXGENSRC; - GXTexMtx mtx = GX_IDENTITY; - GXPTTexMtx postMtx = GX_PTIDENTITY; - bool normalize = false; - bool inputFormAB11 = false; - u8 _p2 = 0; - u8 _p3 = 0; - - bool operator==(const TcgConfig& rhs) const { return memcmp(this, &rhs, sizeof(*this)) == 0; } - bool operator!=(const TcgConfig& rhs) const { return !(*this == rhs); } -}; -static_assert(std::has_unique_object_representations_v); -struct FogState { - GXFogType type = GX_FOG_NONE; - float a = 0.f; - float b = 0.5f; - float c = 0.f; - float aRaw = 0.f; - Vec4 color; - // Raw encoded register values for A/B reconstruction across separate BP writes - u32 fog0Raw = 0; // 0xEE: encoded A parameter - u32 fog1Raw = 0; // 0xEF: B mantissa - u32 fog2Raw = 0; // 0xF0: B shift - u32 bMagnitude = 1; - u32 bShift = 1; - - bool operator==(const FogState& rhs) const { - return type == rhs.type && a == rhs.a && b == rhs.b && c == rhs.c && aRaw == rhs.aRaw && color == rhs.color && - bMagnitude == rhs.bMagnitude && bShift == rhs.bShift; - } - bool operator!=(const FogState& rhs) const { return !(*this == rhs); } -}; -struct TevSwap { - GXTevColorChan red = GX_CH_RED; - GXTevColorChan green = GX_CH_GREEN; - GXTevColorChan blue = GX_CH_BLUE; - GXTevColorChan alpha = GX_CH_ALPHA; - - bool operator==(const TevSwap& rhs) const { return memcmp(this, &rhs, sizeof(*this)) == 0; } - bool operator!=(const TevSwap& rhs) const { return !(*this == rhs); } - explicit operator bool() const { return !(*this == TevSwap{}); } -}; -static_assert(std::has_unique_object_representations_v); -struct AlphaCompare { - GXCompare comp0 = GX_ALWAYS; - u32 ref0 = 0; // would be u8 but extended to avoid padding bytes - GXAlphaOp op = GX_AOP_AND; - GXCompare comp1 = GX_ALWAYS; - u32 ref1 = 0; - - bool operator==(const AlphaCompare& rhs) const { return memcmp(this, &rhs, sizeof(*this)) == 0; } - bool operator!=(const AlphaCompare& rhs) const { return !(*this == rhs); } - explicit operator bool() const { return comp0 != GX_ALWAYS || comp1 != GX_ALWAYS; } -}; -static_assert(std::has_unique_object_representations_v); -struct IndTexMtxInfo { - Mat3x2 mtx; - s8 scaleExp = 0; - // Accumulated adjScale bits from BP registers (2 bits per row, 3 rows) - u8 adjScaleRaw = 0; - - bool operator==(const IndTexMtxInfo& rhs) const { return mtx == rhs.mtx && scaleExp == rhs.scaleExp; } - bool operator!=(const IndTexMtxInfo& rhs) const { return !(*this == rhs); } -}; -struct TexCoordScale { - u16 scaleS = 0; // texture width - 1 - u16 scaleT = 0; // texture height - 1 - bool biasS = false; - bool biasT = false; - bool cylWrapS = false; - bool cylWrapT = false; - bool lineOffset = false; - bool pointOffset = false; - - bool operator==(const TexCoordScale& rhs) const { - return scaleS == rhs.scaleS && scaleT == rhs.scaleT && biasS == rhs.biasS && biasT == rhs.biasT && - cylWrapS == rhs.cylWrapS && cylWrapT == rhs.cylWrapT && lineOffset == rhs.lineOffset && - pointOffset == rhs.pointOffset; - } - bool operator!=(const TexCoordScale& rhs) const { return !(*this == rhs); } -}; -struct VtxAttrFmt { - GXCompCnt cnt; - GXCompType type; - u8 frac; - u8 _p1 = 0; - u8 _p2 = 0; - u8 _p3 = 0; -}; -static_assert(std::has_unique_object_representations_v); -struct VtxFmt { - std::array attrs; -}; -static_assert(std::has_unique_object_representations_v); -struct PnMtx { - Mat3x4 pos; - Mat3x4 nrm; -}; -static_assert(sizeof(PnMtx) == sizeof(Mat3x4) * 2); -struct Light { - Vec4 pos{0.f, 0.f, 0.f}; - Vec4 dir{0.f, 0.f, 0.f}; - Vec4 color{0.f, 0.f, 0.f, 0.f}; - Vec4 cosAtt{0.f, 0.f, 0.f}; - Vec4 distAtt{0.f, 0.f, 0.f}; - - bool operator==(const Light& rhs) const { - return pos == rhs.pos && dir == rhs.dir && color == rhs.color && cosAtt == rhs.cosAtt && distAtt == rhs.distAtt; - } - bool operator!=(const Light& rhs) const { return !(*this == rhs); } -}; -static_assert(sizeof(Light) == 80); -struct Fog { - Vec4 color; - float a = 0.f; - float b = 0.5f; - float c = 0.f; - float pad = FLT_MAX; - Vec4 rangeBase; - std::array, 3> rangeK; -}; -static_assert(sizeof(Fog) == 96); -struct AttrArray { - const void* data; - u32 size; - u8 stride; - bool le = true; - gfx::Range cachedRange; -}; -inline bool operator==(const AttrArray& lhs, const AttrArray& rhs) { - return lhs.data == rhs.data && lhs.size == rhs.size && lhs.stride == rhs.stride && lhs.le == rhs.le; -} -inline bool operator!=(const AttrArray& lhs, const AttrArray& rhs) { return !(lhs == rhs); } - -// Stamps GXState::pipelineStateGeneration, both when a GXState is constructed and on every pipeline-state write. -inline u32 next_gx_state_epoch() noexcept { - static u32 epoch = 0; - return ++epoch; -} - -struct GXState { - struct CopyTextureRef { - gfx::TextureHandle handle; - u32 revision = 0; - u32 lastProducedFrame = 0; - u32 lastSampledFrame = 0; - u32 width = 0; - u32 height = 0; - u32 dataSize = 0; - GXTexFmt format = GX_TF_I4; - bool sampledThisFrame = false; - - operator bool() const noexcept { return handle.operator bool(); } - }; - std::array pnMtx; - u32 currentPnMtx; - Mat4x4 proj; - GXProjectionType projType; // for GXGetProjectionv - FogState fog; - GXCullMode cullMode = GX_CULL_BACK; - u8 lineWidth = 0; - u8 pointSize = 0; - GXTexOffset lineTexOffset = GX_TO_ZERO; - GXTexOffset pointTexOffset = GX_TO_ZERO; - bool lineHalfAspect = false; - GXBlendMode blendMode = GX_BM_NONE; - GXBlendFactor blendFacSrc = GX_BL_SRCALPHA; - GXBlendFactor blendFacDst = GX_BL_INVSRCALPHA; - GXLogicOp blendOp = GX_LO_CLEAR; - GXCompare depthFunc = GX_LEQUAL; - Vec4 clearColor{0.f, 0.f, 0.f, 1.f}; - u32 clearDepth = 0xFFFFFF; - GXPixelFmt pixelFmt = GX_PF_RGB8_Z24; - GXZFmt16 zFmt = GX_ZC_LINEAR; - bool zCompLocBeforeTex = false; - GXZTexOp zTextureOp = GX_ZT_DISABLE; - u8 zTextureFmt = 0; - u32 zTextureBias = 0; - u32 dstAlpha; // u8; UINT32_MAX = disabled - AlphaCompare alphaCompare; - std::array, MaxTevRegs> colorRegs; - std::array, GX_MAX_KCOLOR> kcolors; - std::array colorChannelConfig; - std::array colorChannelState; - std::array lights; - // Light direction sanitization/normalization is independent of the draw. - std::array preparedLights; - bool preparedLightsDirty = true; - std::array tevStages; - std::array textures; - std::array loadedTextures; - std::array loadedTluts; - AuroraViewportPolicy viewportPolicy = AURORA_VIEWPORT_FIT; - gfx::Viewport logicalViewport{0.f, 0.f, 640.f, 480.f, 0.f, 1.f}; - gfx::Viewport renderViewport{0.f, 0.f, 640.f, 480.f, 0.f, 1.f}; - gfx::ClipRect logicalScissor{0, 0, 640, 480}; - gfx::ClipRect renderScissor{0, 0, 640, 480}; - std::array xfViewport{320.f, -240.f, 16777215.f, 660.f, 580.f, 16777215.f}; - std::array xfProjection{}; - std::array, MaxTexMtx> texMtxs; - std::array, MaxPTTexMtx> ptTexMtxs; - std::array tcgs; - std::array texCoordScales; - u16 lastVtxSize = 0; - GXVtxFmt lastVtxFmt = GX_MAX_VTXFMT; - std::array vtxDesc; - std::array sourceVtxDesc; - std::array vtxFmts; - std::array tevSwapTable{ - TevSwap{}, - TevSwap{GX_CH_RED, GX_CH_RED, GX_CH_RED, GX_CH_ALPHA}, - TevSwap{GX_CH_GREEN, GX_CH_GREEN, GX_CH_GREEN, GX_CH_ALPHA}, - TevSwap{GX_CH_BLUE, GX_CH_BLUE, GX_CH_BLUE, GX_CH_ALPHA}, - }; - std::array indStages; - std::array indTexMtxs; - u8 indTexMask = 0; - std::array boundingBox{1023, 0, 1023, 0}; - std::array arrays; - gfx::ClipRect texCopySrc; - gfx::ClipRect dispCopySrc; - bool texCopySrcRenderSpace = false; - GXTexFmt texCopyFmt; - u16 texCopyDstWidth = 0; - u16 texCopyDstHeight = 0; - bool texCopyHalfScale = false; - u16 dispCopyDstWidth = 640; - u16 dispCopyDstHeight = 480; - f32 dispCopyYScale = 1.f; - GXGamma dispCopyGamma = GX_GM_1_0; - GXBool copyFilterAa = GX_FALSE; - GXBool copyFilterVf = GX_FALSE; - std::array, 12> copyFilterSamplePattern{}; - std::array copyFilterVFilter{}; - GXFBClamp copyClamp = GX_CLAMP_NONE; - u32 dispCopyFrame2Field = 0; - u32 fieldMask = 0; - u32 fieldMode = 0; - u32 revBits = 0; - std::array fogRange{}; - u32 xfError = 0; - u32 dualTex = 0; - float zScale = 1.f; - float zOffset = 0.f; - s32 scissorOffsetX = 0; - s32 scissorOffsetY = 0; - struct CopyTextureKey { - const void* dest = nullptr; - u32 width = 0; - u32 height = 0; - GXTexFmt format = GX_TF_I4; - - bool operator==(const CopyTextureKey& rhs) const { - return dest == rhs.dest && width == rhs.width && height == rhs.height && format == rhs.format; - } - - template - friend H AbslHashValue(H h, const CopyTextureKey& key) { - return H::combine(std::move(h), key.dest, key.width, key.height, key.format); - } - }; - absl::flat_hash_map copyTextures; - absl::flat_hash_map copyTextureCache; - gfx::TextureHandle displayCopyTexture; - wgpu::BindGroup displayCopyBindGroup; - u32 displayCopyWidth = 0; - u32 displayCopyHeight = 0; - bool depthCompare = true; - bool depthUpdate = true; - bool colorUpdate = true; - bool alphaUpdate = true; - u8 numChans = 0; - u8 numIndStages = 0; - u8 numTevStages = 0; - u8 numTexGens = 0; - bool stateDirty = true; - // Bumped by the decoded register writes that feed populate_pipeline_config, and by nothing else. - u32 pipelineStateGeneration = next_gx_state_epoch(); - std::array bpRegCache = [] { - std::array regs{}; - // Force the first GEN_MODE decode without changing its masked reset value. - regs[0x00] = 0xFF000000; - regs[0xFE] = 0x00FFFFFF; - return regs; - }(); - // Covers XF 0x00-0x5F: the scalar bank, viewport/projection, and the TexGen and post-transform registers that every material's display list re-emits. - std::array xfRegCache{}; - std::array xfRegCacheValid{}; - - [[nodiscard]] bool xfRegMatches(u32 reg, u32 val) const { - return (xfRegCacheValid[reg >> 6] >> (reg & 63) & 1) != 0 && xfRegCache[reg] == val; - } - void storeXfReg(u32 reg, u32 val) { - xfRegCache[reg] = val; - xfRegCacheValid[reg >> 6] |= u64{1} << (reg & 63); - } - // For state that another register bank writes behind the XF cache's back. - void invalidateXfReg(u32 reg) { xfRegCacheValid[reg >> 6] &= ~(u64{1} << (reg & 63)); } - - void clearVtxSizeCache() { lastVtxFmt = GX_MAX_VTXFMT; } -}; -extern GXState g_gxState; -struct ShaderInfo; -struct MappedRenderState { - gfx::Viewport viewport{}; - gfx::ClipRect scissor{}; -}; - -void initialize() noexcept; -void shutdown() noexcept; -void clear_copy_texture_cache() noexcept; -void clear_display_copy_cache() noexcept; -void set_display_copy_present_source() noexcept; -void evict_copy_texture(const void* dest) noexcept; -// Drops retired GX copy targets so they cannot outlive the destination they were recycled for. -void prune_copy_texture_pool(const void* dest) noexcept; -void evict_texture_object(u32 texObjId) noexcept; -void evict_tlut_object(u32 tlutObjId) noexcept; -void invalidate_static_texture_cache() noexcept; -Vec2 logical_fb_size() noexcept; -MappedRenderState map_logical_render_state() noexcept; -gfx::Viewport map_logical_viewport(const gfx::Viewport& logicalViewport) noexcept; -gfx::ClipRect map_logical_scissor(const gfx::ClipRect& logicalScissor) noexcept; -void set_logical_viewport(const gfx::Viewport& viewport) noexcept; -void set_render_viewport(const gfx::Viewport& viewport) noexcept; -void set_logical_scissor(const gfx::ClipRect& scissor) noexcept; -void set_render_scissor(const gfx::ClipRect& scissor) noexcept; -const gfx::TextureBind& get_texture(GXTexMapID id) noexcept; -void resolve_sampled_textures(const ShaderInfo& info) noexcept; - -inline float clear_depth_value() { - // g_gxState.clearDepth is in GX's own distance terms (0 = near, larger = farther), independent of - // how UseReversedZ encodes that as a host depth value - it must be re-mapped the same way the - // projection matrix and depth compare function are, or the buffer clears to the wrong extreme - // (verified directly: matches upstream aurora's clear_depth_value, which does this same inversion - // and was the second missing piece alongside to_compare_function's compare-op inversion). - const float normalizedDepth = - std::min(static_cast(g_gxState.clearDepth) / 16777216.f, 16777215.f / 16777216.f); - return UseReversedZ ? (1.f - normalizedDepth) : normalizedDepth; -} - -inline bool render_target_has_alpha(GXPixelFmt pixelFmt) noexcept { return pixelFmt == GX_PF_RGBA6_Z24; } - -inline float indirect_matrix_scale_multiplier(s8 scaleExp) { - return std::exp2f(static_cast(scaleExp)); -} - -inline s32 indirect_matrix_mantissa(float value) noexcept { - return static_cast(std::lround(value * 1024.0f)); -} - -inline s32 indirect_matrix_shift(s8 scaleExp) noexcept { return -static_cast(scaleExp); } - -static inline bool is_palette_format(u32 fmt) { return fmt == GX_TF_C4 || fmt == GX_TF_C8 || fmt == GX_TF_C14X2; } -static inline bool is_depth_format(u32 fmt) { - return fmt == GX_TF_Z8 || fmt == GX_TF_Z16 || fmt == GX_TF_Z24X8 || fmt == GX_CTF_Z4 || fmt == GX_CTF_Z8M || - fmt == GX_CTF_Z8L || fmt == GX_CTF_Z16L; -} -static inline bool copy_texture_format_compatible(GXTexFmt copyFmt, u32 sampleFmt) noexcept { - if (static_cast(copyFmt) == sampleFmt) { - return true; - } - - switch (copyFmt) { - case GX_CTF_R4: - return sampleFmt == GX_TF_I4; - case GX_CTF_R8: - case GX_CTF_G8: - case GX_CTF_B8: - case GX_CTF_A8: - return sampleFmt == GX_TF_I8 || sampleFmt == GX_TF_A8; - case GX_CTF_RA4: - return sampleFmt == GX_TF_IA4; - case GX_CTF_RA8: - case GX_CTF_RG8: - case GX_CTF_GB8: - case GX_TF_Z16: - return sampleFmt == GX_TF_IA8; - case GX_CTF_YUVA8: - return sampleFmt == GX_TF_RGBA8; - case GX_TF_Z24X8: - return sampleFmt == GX_TF_RGBA8; - default: - return false; - } -} - -struct AttrConfig { - u8 attrType = GX_NONE; // GXAttrType - u8 cnt = 0xFF; // Actual count; not GXCompCnt - u8 compType = 0xFF; // GXCompType - u8 offset = 0; // Offset within vertex - u8 stride = 0; // Array stride - u8 frac = 0; - bool le = true; - u8 nrmIndexCount = 0; // GX_NRM_NBT3 stores three separate normal/tangent/binormal indices. -}; -struct ShaderConfig { - u8 fogType = GX_FOG_NONE; - u8 vtxStride = 0; - u8 lineMode : 2 = 0; // 1 = GX_LINES, 2 = GX_LINESTRIP, 3 = GX_POINTS - u8 dualTexEnabled : 1 = 0; - u8 fogRangeAdjust : 1 = 0; - u8 pad1 : 4 = 0; - u8 numTexGens = 0; - u32 zTexture = 0; // bias[0:23], format[24:25], op[26:27]; 0 disables shader depth output. - std::array attrs; - std::array tevSwapTable; - std::array tevStages; - u32 tevStageCount = 0; - std::array colorChannels; - std::array tcgs; - AlphaCompare alphaCompare; - std::array indStages{}; - u32 numIndStages = 0; - - bool operator==(const ShaderConfig& rhs) const { return memcmp(this, &rhs, sizeof(*this)) == 0; } -}; -static_assert(std::has_unique_object_representations_v); - -// GX supplies an opaque white color when a draw omits vertex colors. -inline int shader_vertex_color_attr(const ShaderConfig& config, u32 channel) noexcept { - const bool hasColor0 = config.attrs[GX_VA_CLR0].attrType != GX_NONE; - const bool hasColor1 = config.attrs[GX_VA_CLR1].attrType != GX_NONE; - if (channel == 0) { - if (hasColor0) { - return GX_VA_CLR0; - } - if (hasColor1) { - return GX_VA_CLR1; - } - } else if (channel == 1 && hasColor0 && hasColor1) { - return GX_VA_CLR1; - } - return -1; -} - -// The indirect TEV coordinate is persistent across stages. -inline bool tev_stage_needs_fixed_texcoord_state(const ShaderConfig& config, u32 stageIdx) noexcept { - if (stageIdx >= config.tevStageCount) { - return false; - } - - const auto& stage = config.tevStages[stageIdx]; - const bool hasCoordOperation = stage.indTexMtxId != GX_ITM_OFF || stage.indTexWrapS != GX_ITW_OFF || - stage.indTexWrapT != GX_ITW_OFF || stage.indTexAddPrev; - const bool feedsNextAddPrev = - stageIdx + 1 < config.tevStageCount && config.tevStages[stageIdx + 1].indTexAddPrev; - return hasCoordOperation || feedsNextAddPrev; -} - -inline bool tev_stage_has_texture_map(const TevStage& stage) noexcept { - return stage.texMapId != GX_TEXMAP_NULL && stage.texMapId < MaxTextures; -} - -// Returns -1 for GX_ITW_OFF, an integer fixed-point mask for the wrapping modes, and 0 for GX_ITW_0. -inline int tev_indirect_wrap_mask(GXIndTexWrap wrap) noexcept { - switch (wrap) { - case GX_ITW_OFF: - return -1; - case GX_ITW_256: - return (256 << 7) - 1; - case GX_ITW_128: - return (128 << 7) - 1; - case GX_ITW_64: - return (64 << 7) - 1; - case GX_ITW_32: - return (32 << 7) - 1; - case GX_ITW_16: - return (16 << 7) - 1; - case GX_ITW_0: - return 0; - default: - return underlying(wrap) >= underlying(GX_ITW_0) ? 0 : -2; - } -} - -inline constexpr s32 tev_s24_wrap(s32 value) noexcept { - const u32 wrapped = static_cast(value) & 0x00ffffffu; - return (wrapped & 0x00800000u) != 0 ? static_cast(wrapped) - 0x01000000 - : static_cast(wrapped); -} - -// GX falls back to texcoord 0 when a TEV order names GX_TEXCOORD_NULL or a coordinate beyond the configured texgen count. -inline int tev_effective_texcoord(const ShaderConfig& config, GXTexCoordID texCoordId) noexcept { - if (config.numTexGens == 0) { - return -1; - } - - const u32 rawTexCoord = underlying(texCoordId); - return rawTexCoord < config.numTexGens && rawTexCoord < MaxTexCoord ? static_cast(rawTexCoord) : 0; -} - -inline bool tev_stage_combiner_uses_texture(const TevStage& stage) noexcept { - const auto& color = stage.colorPass; - const auto& alpha = stage.alphaPass; - return color.a == GX_CC_TEXC || color.a == GX_CC_TEXA || color.b == GX_CC_TEXC || - color.b == GX_CC_TEXA || color.c == GX_CC_TEXC || color.c == GX_CC_TEXA || - color.d == GX_CC_TEXC || color.d == GX_CC_TEXA || alpha.a == GX_CA_TEXA || - alpha.b == GX_CA_TEXA || alpha.c == GX_CA_TEXA || alpha.d == GX_CA_TEXA; -} - -struct TevStageTextureDependency { - int texCoordId = -1; - int texMapId = -1; - bool needsFixedTexcoordState = false; - bool combinerUsesTexture = false; - bool canSampleTexture = false; -}; - -inline bool tev_texture_sample_enabled(const TevStageTextureDependency& dependency, - bool sampleRequested) noexcept { - return sampleRequested && dependency.canSampleTexture; -} - -// Pure TEV order/dependency analysis used by both ShaderInfo and WGSL generation. -inline TevStageTextureDependency tev_stage_texture_dependency(const ShaderConfig& config, - u32 stageIdx) noexcept { - if (stageIdx >= config.tevStageCount) { - return {}; - } - - const auto& stage = config.tevStages[stageIdx]; - TevStageTextureDependency dependency{ - .texCoordId = tev_effective_texcoord(config, stage.texCoordId), - .texMapId = tev_stage_has_texture_map(stage) ? static_cast(underlying(stage.texMapId)) : -1, - .needsFixedTexcoordState = tev_stage_needs_fixed_texcoord_state(config, stageIdx), - .combinerUsesTexture = tev_stage_combiner_uses_texture(stage), - }; - dependency.canSampleTexture = dependency.texCoordId >= 0 && dependency.texMapId >= 0; - return dependency; -} - -inline bool shader_uses_fixed_texcoord_state(const ShaderConfig& config) noexcept { - for (u32 i = 0; i < config.tevStageCount; ++i) { - if (tev_stage_texture_dependency(config, i).needsFixedTexcoordState) { - return true; - } - } - return false; -} - -inline bool tev_z_texture_enabled(const ShaderConfig& config) noexcept { - return ((config.zTexture >> 26) & 0x3u) != GX_ZT_DISABLE; -} - -inline int tev_z_texture_stage(const ShaderConfig& config) noexcept { - if (!tev_z_texture_enabled(config)) { - return -1; - } - for (int i = static_cast(config.tevStageCount) - 1; i >= 0; --i) { - if (tev_stage_texture_dependency(config, static_cast(i)).canSampleTexture) { - return i; - } - } - return -1; -} - -struct PipelineConfig; - -struct GXBindGroups { - gfx::BindGroupRef textureBindGroup; - // Bind group resolved at draw-build time so that gx::render does not have to hash-map the ref again for every draw. - WGPUBindGroup resolvedTextureBindGroup = nullptr; -}; -// Which matrix-memory slots a generated shader can actually read, and where each one lives in the compacted uniform arrays. -struct UniformMatrixLayout { - // `postexSlots`/`nrmSlots` entry meaning "the matrix selected by the current matrix index", which is only known per draw. - static constexpr u8 kCurrentPnMtx = 0xFE; - // `postexRemap` entry for a slot that this shader never reads. - static constexpr u8 kAbsent = 0xFF; - - // Compact index -> absolute postex slot (or kCurrentPnMtx). - std::array postexSlots{}; - // Absolute postex slot -> compact index (or kAbsent). - std::array postexRemap{}; - // Compact index -> absolute position slot (or kCurrentPnMtx). - std::array nrmSlots{}; - u8 postexCount = 0; - u8 nrmCount = 0; - // Position slots 0..MaxPnMtx-1 are uploaded 1:1 at compact indices 0..9, so `current_pnmtx` and any per-vertex index need no remapping. - bool absolutePosRegion = false; -}; -// Output info from shader generation -struct ShaderInfo { - std::bitset sampledTexCoords; - std::bitset sampledTextures; - std::bitset sampledKColors; - std::bitset sampledColorChannels; - // TEV color and alpha outputs are independently addressable. - std::bitset loadsTevRegRgb; - std::bitset loadsTevRegAlpha; - std::bitset writesTevRegRgb; - std::bitset writesTevRegAlpha; - std::bitset usesPTTexMtx; - std::bitset indexAttr; - std::bitset usedIndStages; - std::bitset sampledIndTextures; - std::bitset usedIndTexMtxs; - UniformMatrixLayout matrixLayout; - u32 uniformSize = 0; - bool usesFog : 1 = false; - bool lightingEnabled : 1 = false; - u8 lineMode : 2 = 0; -}; -struct BindGroupRanges { - std::array vaRanges{}; -}; -void populate_pipeline_config(PipelineConfig& config, GXPrimitive primitive, GXVtxFmt fmt) noexcept; -wgpu::RenderPipeline build_pipeline(const PipelineConfig& config, ArrayRef vtxBuffers, - wgpu::ShaderModule shader, const char* label) noexcept; -wgpu::ShaderModule build_shader(const ShaderConfig& config) noexcept; -GXBindGroups build_bind_groups(const ShaderInfo& info) noexcept; -void notify_copy_texture_created() noexcept; - -u8 comp_type_size(GXAttr attr, GXCompType type) noexcept; -u8 comp_cnt_count(GXAttr attr, GXCompCnt cnt) noexcept; -} // namespace aurora::gx diff --git a/aurora-main/lib/gx/gx_fmt.hpp b/aurora-main/lib/gx/gx_fmt.hpp deleted file mode 100644 index ca1fb33..0000000 --- a/aurora-main/lib/gx/gx_fmt.hpp +++ /dev/null @@ -1,952 +0,0 @@ -#pragma once - -#include "../internal.hpp" - -#include -#include -#include - -inline std::string format_as(const GXTevOp& op) { - switch (op) { - case GX_TEV_ADD: - return "GX_TEV_ADD"; - case GX_TEV_SUB: - return "GX_TEV_SUB"; - case GX_TEV_COMP_R8_GT: - return "GX_TEV_COMP_R8_GT"; - case GX_TEV_COMP_R8_EQ: - return "GX_TEV_COMP_R8_EQ"; - case GX_TEV_COMP_GR16_GT: - return "GX_TEV_COMP_GR16_GT"; - case GX_TEV_COMP_GR16_EQ: - return "GX_TEV_COMP_GR16_EQ"; - case GX_TEV_COMP_BGR24_GT: - return "GX_TEV_COMP_BGR24_GT"; - case GX_TEV_COMP_BGR24_EQ: - return "GX_TEV_COMP_BGR24_EQ"; - case GX_TEV_COMP_RGB8_GT: - return "GX_TEV_COMP_RGB8_GT"; - case GX_TEV_COMP_RGB8_EQ: - return "GX_TEV_COMP_RGB8_EQ"; - default: - return fmt::format("GXTevOp({})", underlying(op)); - } -} - -inline std::string format_as(const GXTevColorArg& arg) { - switch (arg) { - case GX_CC_CPREV: - return "GX_CC_CPREV"; - case GX_CC_APREV: - return "GX_CC_APREV"; - case GX_CC_C0: - return "GX_CC_C0"; - case GX_CC_A0: - return "GX_CC_A0"; - case GX_CC_C1: - return "GX_CC_C1"; - case GX_CC_A1: - return "GX_CC_A1"; - case GX_CC_C2: - return "GX_CC_C2"; - case GX_CC_A2: - return "GX_CC_A2"; - case GX_CC_TEXC: - return "GX_CC_TEXC"; - case GX_CC_TEXA: - return "GX_CC_TEXA"; - case GX_CC_RASC: - return "GX_CC_RASC"; - case GX_CC_RASA: - return "GX_CC_RASA"; - case GX_CC_ONE: - return "GX_CC_ONE"; - case GX_CC_HALF: - return "GX_CC_HALF"; - case GX_CC_KONST: - return "GX_CC_KONST"; - case GX_CC_ZERO: - return "GX_CC_ZERO"; - default: - return fmt::format("GXTevColorArg({})", underlying(arg)); - } -} - -inline std::string format_as(const GXTevAlphaArg& arg) { - switch (arg) { - case GX_CA_APREV: - return "GX_CA_APREV"; - case GX_CA_A0: - return "GX_CA_A0"; - case GX_CA_A1: - return "GX_CA_A1"; - case GX_CA_A2: - return "GX_CA_A2"; - case GX_CA_TEXA: - return "GX_CA_TEXA"; - case GX_CA_RASA: - return "GX_CA_RASA"; - case GX_CA_KONST: - return "GX_CA_KONST"; - case GX_CA_ZERO: - return "GX_CA_ZERO"; - default: - return fmt::format("GXTevAlphaArg({})", underlying(arg)); - } -} - -inline std::string format_as(const GXTexGenSrc& src) { - switch (src) { - case GX_TG_POS: - return "GX_TG_POS"; - case GX_TG_NRM: - return "GX_TG_NRM"; - case GX_TG_BINRM: - return "GX_TG_BINRM"; - case GX_TG_TANGENT: - return "GX_TG_TANGENT"; - case GX_TG_TEX0: - return "GX_TG_TEX0"; - case GX_TG_TEX1: - return "GX_TG_TEX1"; - case GX_TG_TEX2: - return "GX_TG_TEX2"; - case GX_TG_TEX3: - return "GX_TG_TEX3"; - case GX_TG_TEX4: - return "GX_TG_TEX4"; - case GX_TG_TEX5: - return "GX_TG_TEX5"; - case GX_TG_TEX6: - return "GX_TG_TEX6"; - case GX_TG_TEX7: - return "GX_TG_TEX7"; - case GX_TG_TEXCOORD0: - return "GX_TG_TEXCOORD0"; - case GX_TG_TEXCOORD1: - return "GX_TG_TEXCOORD1"; - case GX_TG_TEXCOORD2: - return "GX_TG_TEXCOORD2"; - case GX_TG_TEXCOORD3: - return "GX_TG_TEXCOORD3"; - case GX_TG_TEXCOORD4: - return "GX_TG_TEXCOORD4"; - case GX_TG_TEXCOORD5: - return "GX_TG_TEXCOORD5"; - case GX_TG_TEXCOORD6: - return "GX_TG_TEXCOORD6"; - case GX_TG_COLOR0: - return "GX_TG_COLOR0"; - case GX_TG_COLOR1: - return "GX_TG_COLOR1"; - default: - return fmt::format("GXTexGenSrc({})", underlying(src)); - } -} - -inline std::string format_as(const GXTexGenType& type) { - switch (type) { - case GX_TG_MTX2x4: - return "GX_TG_MTX2x4"; - case GX_TG_MTX3x4: - return "GX_TG_MTX3x4"; - case GX_TG_BUMP0: - return "GX_TG_BUMP0"; - case GX_TG_BUMP1: - return "GX_TG_BUMP1"; - case GX_TG_BUMP2: - return "GX_TG_BUMP2"; - case GX_TG_BUMP3: - return "GX_TG_BUMP3"; - case GX_TG_BUMP4: - return "GX_TG_BUMP4"; - case GX_TG_BUMP5: - return "GX_TG_BUMP5"; - case GX_TG_BUMP6: - return "GX_TG_BUMP6"; - case GX_TG_BUMP7: - return "GX_TG_BUMP7"; - case GX_TG_SRTG: - return "GX_TG_SRTG"; - default: - return fmt::format("GXTexGenType({})", underlying(type)); - } -} - -inline std::string format_as(const GXTevBias& bias) { - switch (bias) { - case GX_TB_ZERO: - return "GX_TB_ZERO"; - case GX_TB_ADDHALF: - return "GX_TB_ADDHALF"; - case GX_TB_SUBHALF: - return "GX_TB_SUBHALF"; - default: - return fmt::format("GXTevBias({})", underlying(bias)); - } -} - -inline std::string format_as(const GXTevScale& scale) { - switch (scale) { - case GX_CS_SCALE_1: - return "GX_CS_SCALE_1"; - case GX_CS_SCALE_2: - return "GX_CS_SCALE_2"; - case GX_CS_SCALE_4: - return "GX_CS_SCALE_4"; - case GX_CS_DIVIDE_2: - return "GX_CS_DIVIDE_2"; - default: - return fmt::format("GXTevScale({})", underlying(scale)); - } -} - -inline std::string format_as(const GXTevRegID& reg) { - switch (reg) { - case GX_TEVPREV: - return "GX_TEVPREV"; - case GX_TEVREG0: - return "GX_TEVREG0"; - case GX_TEVREG1: - return "GX_TEVREG1"; - case GX_TEVREG2: - return "GX_TEVREG2"; - default: - return fmt::format("GXTevRegID({})", underlying(reg)); - } -} - -inline std::string format_as(const GXTevKColorSel& sel) { - switch (sel) { - case GX_TEV_KCSEL_8_8: - return "GX_TEV_KCSEL_8_8"; - case GX_TEV_KCSEL_7_8: - return "GX_TEV_KCSEL_7_8"; - case GX_TEV_KCSEL_6_8: - return "GX_TEV_KCSEL_6_8"; - case GX_TEV_KCSEL_5_8: - return "GX_TEV_KCSEL_5_8"; - case GX_TEV_KCSEL_4_8: - return "GX_TEV_KCSEL_4_8"; - case GX_TEV_KCSEL_3_8: - return "GX_TEV_KCSEL_3_8"; - case GX_TEV_KCSEL_2_8: - return "GX_TEV_KCSEL_2_8"; - case GX_TEV_KCSEL_1_8: - return "GX_TEV_KCSEL_1_8"; - case GX_TEV_KCSEL_K0: - return "GX_TEV_KCSEL_K0"; - case GX_TEV_KCSEL_K1: - return "GX_TEV_KCSEL_K1"; - case GX_TEV_KCSEL_K2: - return "GX_TEV_KCSEL_K2"; - case GX_TEV_KCSEL_K3: - return "GX_TEV_KCSEL_K3"; - case GX_TEV_KCSEL_K0_R: - return "GX_TEV_KCSEL_K0_R"; - case GX_TEV_KCSEL_K1_R: - return "GX_TEV_KCSEL_K1_R"; - case GX_TEV_KCSEL_K2_R: - return "GX_TEV_KCSEL_K2_R"; - case GX_TEV_KCSEL_K3_R: - return "GX_TEV_KCSEL_K3_R"; - case GX_TEV_KCSEL_K0_G: - return "GX_TEV_KCSEL_K0_G"; - case GX_TEV_KCSEL_K1_G: - return "GX_TEV_KCSEL_K1_G"; - case GX_TEV_KCSEL_K2_G: - return "GX_TEV_KCSEL_K2_G"; - case GX_TEV_KCSEL_K3_G: - return "GX_TEV_KCSEL_K3_G"; - case GX_TEV_KCSEL_K0_B: - return "GX_TEV_KCSEL_K0_B"; - case GX_TEV_KCSEL_K1_B: - return "GX_TEV_KCSEL_K1_B"; - case GX_TEV_KCSEL_K2_B: - return "GX_TEV_KCSEL_K2_B"; - case GX_TEV_KCSEL_K3_B: - return "GX_TEV_KCSEL_K3_B"; - case GX_TEV_KCSEL_K0_A: - return "GX_TEV_KCSEL_K0_A"; - case GX_TEV_KCSEL_K1_A: - return "GX_TEV_KCSEL_K1_A"; - case GX_TEV_KCSEL_K2_A: - return "GX_TEV_KCSEL_K2_A"; - case GX_TEV_KCSEL_K3_A: - return "GX_TEV_KCSEL_K3_A"; - default: - return fmt::format("GXTevKColorSel({})", underlying(sel)); - } -} - -inline std::string format_as(const GXTevKAlphaSel& sel) { - switch (sel) { - case GX_TEV_KASEL_8_8: - return "GX_TEV_KASEL_8_8"; - case GX_TEV_KASEL_7_8: - return "GX_TEV_KASEL_7_8"; - case GX_TEV_KASEL_6_8: - return "GX_TEV_KASEL_6_8"; - case GX_TEV_KASEL_5_8: - return "GX_TEV_KASEL_5_8"; - case GX_TEV_KASEL_4_8: - return "GX_TEV_KASEL_4_8"; - case GX_TEV_KASEL_3_8: - return "GX_TEV_KASEL_3_8"; - case GX_TEV_KASEL_2_8: - return "GX_TEV_KASEL_2_8"; - case GX_TEV_KASEL_1_8: - return "GX_TEV_KASEL_1_8"; - case GX_TEV_KASEL_K0_R: - return "GX_TEV_KASEL_K0_R"; - case GX_TEV_KASEL_K1_R: - return "GX_TEV_KASEL_K1_R"; - case GX_TEV_KASEL_K2_R: - return "GX_TEV_KASEL_K2_R"; - case GX_TEV_KASEL_K3_R: - return "GX_TEV_KASEL_K3_R"; - case GX_TEV_KASEL_K0_G: - return "GX_TEV_KASEL_K0_G"; - case GX_TEV_KASEL_K1_G: - return "GX_TEV_KASEL_K1_G"; - case GX_TEV_KASEL_K2_G: - return "GX_TEV_KASEL_K2_G"; - case GX_TEV_KASEL_K3_G: - return "GX_TEV_KASEL_K3_G"; - case GX_TEV_KASEL_K0_B: - return "GX_TEV_KASEL_K0_B"; - case GX_TEV_KASEL_K1_B: - return "GX_TEV_KASEL_K1_B"; - case GX_TEV_KASEL_K2_B: - return "GX_TEV_KASEL_K2_B"; - case GX_TEV_KASEL_K3_B: - return "GX_TEV_KASEL_K3_B"; - case GX_TEV_KASEL_K0_A: - return "GX_TEV_KASEL_K0_A"; - case GX_TEV_KASEL_K1_A: - return "GX_TEV_KASEL_K1_A"; - case GX_TEV_KASEL_K2_A: - return "GX_TEV_KASEL_K2_A"; - case GX_TEV_KASEL_K3_A: - return "GX_TEV_KASEL_K3_A"; - default: - return fmt::format("GXTevKAlphaSel({})", underlying(sel)); - } -} - -inline std::string format_as(const GXTevSwapSel& sel) { - switch (sel) { - case GX_TEV_SWAP0: - return "GX_TEV_SWAP0"; - case GX_TEV_SWAP1: - return "GX_TEV_SWAP1"; - case GX_TEV_SWAP2: - return "GX_TEV_SWAP2"; - case GX_TEV_SWAP3: - return "GX_TEV_SWAP3"; - default: - return fmt::format("GXTevSwapSel({})", underlying(sel)); - } -} - -inline std::string format_as(const GXTexMapID& id) { - switch (id) { - case GX_TEXMAP0: - return "GX_TEXMAP0"; - case GX_TEXMAP1: - return "GX_TEXMAP1"; - case GX_TEXMAP2: - return "GX_TEXMAP2"; - case GX_TEXMAP3: - return "GX_TEXMAP3"; - case GX_TEXMAP4: - return "GX_TEXMAP4"; - case GX_TEXMAP5: - return "GX_TEXMAP5"; - case GX_TEXMAP6: - return "GX_TEXMAP6"; - case GX_TEXMAP7: - return "GX_TEXMAP7"; - case GX_TEXMAP_NULL: - return "GX_TEXMAP_NULL"; - case GX_TEX_DISABLE: - return "GX_TEX_DISABLE"; - default: - return fmt::format("GXTexMapID({})", underlying(id)); - } -} - -inline std::string format_as(const GXChannelID& id) { - switch (id) { - case GX_COLOR0: - return "GX_COLOR0"; - case GX_COLOR1: - return "GX_COLOR1"; - case GX_ALPHA0: - return "GX_ALPHA0"; - case GX_ALPHA1: - return "GX_ALPHA1"; - case GX_COLOR0A0: - return "GX_COLOR0A0"; - case GX_COLOR1A1: - return "GX_COLOR1A1"; - case GX_COLOR_ZERO: - return "GX_COLOR_ZERO"; - case GX_ALPHA_BUMP: - return "GX_ALPHA_BUMP"; - case GX_ALPHA_BUMPN: - return "GX_ALPHA_BUMPN"; - case GX_COLOR_NULL: - return "GX_COLOR_NULL"; - default: - return fmt::format("GXChannelID({})", underlying(id)); - } -} - -inline std::string format_as(const GXColorSrc& src) { - switch (src) { - case GX_SRC_REG: - return "GX_SRC_REG"; - case GX_SRC_VTX: - return "GX_SRC_VTX"; - default: - return fmt::format("GXColorSrc({})", underlying(src)); - } -} - -inline std::string format_as(const GXTexMtx& mtx) { - switch (mtx) { - case GX_TEXMTX0: - return "GX_TEXMTX0"; - case GX_TEXMTX1: - return "GX_TEXMTX1"; - case GX_TEXMTX2: - return "GX_TEXMTX2"; - case GX_TEXMTX3: - return "GX_TEXMTX3"; - case GX_TEXMTX4: - return "GX_TEXMTX4"; - case GX_TEXMTX5: - return "GX_TEXMTX5"; - case GX_TEXMTX6: - return "GX_TEXMTX6"; - case GX_TEXMTX7: - return "GX_TEXMTX7"; - case GX_TEXMTX8: - return "GX_TEXMTX8"; - case GX_TEXMTX9: - return "GX_TEXMTX9"; - case GX_IDENTITY: - return "GX_IDENTITY"; - default: - return fmt::format("GXTexMtx({})", underlying(mtx)); - } -} - -inline std::string format_as(const GXPTTexMtx& mtx) { - switch (mtx) { - case GX_PTTEXMTX0: - return "GX_PTTEXMTX0"; - case GX_PTTEXMTX1: - return "GX_PTTEXMTX1"; - case GX_PTTEXMTX2: - return "GX_PTTEXMTX2"; - case GX_PTTEXMTX3: - return "GX_PTTEXMTX3"; - case GX_PTTEXMTX4: - return "GX_PTTEXMTX4"; - case GX_PTTEXMTX5: - return "GX_PTTEXMTX5"; - case GX_PTTEXMTX6: - return "GX_PTTEXMTX6"; - case GX_PTTEXMTX7: - return "GX_PTTEXMTX7"; - case GX_PTTEXMTX8: - return "GX_PTTEXMTX8"; - case GX_PTTEXMTX9: - return "GX_PTTEXMTX9"; - case GX_PTTEXMTX10: - return "GX_PTTEXMTX10"; - case GX_PTTEXMTX11: - return "GX_PTTEXMTX11"; - case GX_PTTEXMTX12: - return "GX_PTTEXMTX12"; - case GX_PTTEXMTX13: - return "GX_PTTEXMTX13"; - case GX_PTTEXMTX14: - return "GX_PTTEXMTX14"; - case GX_PTTEXMTX15: - return "GX_PTTEXMTX15"; - case GX_PTTEXMTX16: - return "GX_PTTEXMTX16"; - case GX_PTTEXMTX17: - return "GX_PTTEXMTX17"; - case GX_PTTEXMTX18: - return "GX_PTTEXMTX18"; - case GX_PTTEXMTX19: - return "GX_PTTEXMTX19"; - case GX_PTIDENTITY: - return "GX_PTIDENTITY"; - default: - return fmt::format("GXPTTexMtx({})", underlying(mtx)); - } -} - -inline std::string format_as(const GXCompare& comp) { - switch (comp) { - case GX_NEVER: - return "GX_NEVER"; - case GX_LESS: - return "GX_LESS"; - case GX_EQUAL: - return "GX_EQUAL"; - case GX_LEQUAL: - return "GX_LEQUAL"; - case GX_GREATER: - return "GX_GREATER"; - case GX_NEQUAL: - return "GX_NEQUAL"; - case GX_GEQUAL: - return "GX_GEQUAL"; - case GX_ALWAYS: - return "GX_ALWAYS"; - default: - return fmt::format("GXCompare({})", underlying(comp)); - } -} - -inline std::string format_as(const GXAlphaOp& op) { - switch (op) { - case GX_AOP_AND: - return "GX_AOP_AND"; - case GX_AOP_OR: - return "GX_AOP_OR"; - case GX_AOP_XOR: - return "GX_AOP_XOR"; - case GX_AOP_XNOR: - return "GX_AOP_XNOR"; - default: - return fmt::format("GXAlphaOp({})", underlying(op)); - } -} - -inline std::string format_as(const GXFogType& type) { - switch (type) { - case GX_FOG_NONE: - return "GX_FOG_NONE"; - case GX_FOG_PERSP_LIN: - return "GX_FOG_PERSP_LIN"; - case GX_FOG_PERSP_EXP: - return "GX_FOG_PERSP_EXP"; - case GX_FOG_PERSP_EXP2: - return "GX_FOG_PERSP_EXP2"; - case GX_FOG_PERSP_REVEXP: - return "GX_FOG_PERSP_REVEXP"; - case GX_FOG_PERSP_REVEXP2: - return "GX_FOG_PERSP_REVEXP2"; - case GX_FOG_ORTHO_LIN: - return "GX_FOG_ORTHO_LIN"; - case GX_FOG_ORTHO_EXP: - return "GX_FOG_ORTHO_EXP"; - case GX_FOG_ORTHO_EXP2: - return "GX_FOG_ORTHO_EXP2"; - case GX_FOG_ORTHO_REVEXP: - return "GX_FOG_ORTHO_REVEXP"; - case GX_FOG_ORTHO_REVEXP2: - return "GX_FOG_ORTHO_REVEXP2"; - default: - return fmt::format("GXFogType({})", underlying(type)); - } -} - -inline std::string format_as(const GXTexCoordID& id) { - switch (id) { - case GX_TEXCOORD0: - return "GX_TEXCOORD0"; - case GX_TEXCOORD1: - return "GX_TEXCOORD1"; - case GX_TEXCOORD2: - return "GX_TEXCOORD2"; - case GX_TEXCOORD3: - return "GX_TEXCOORD3"; - case GX_TEXCOORD4: - return "GX_TEXCOORD4"; - case GX_TEXCOORD5: - return "GX_TEXCOORD5"; - case GX_TEXCOORD6: - return "GX_TEXCOORD6"; - case GX_TEXCOORD7: - return "GX_TEXCOORD7"; - case GX_TEXCOORD_NULL: - return "GX_TEXCOORD_NULL"; - default: - return fmt::format("GXTexCoordID({})", underlying(id)); - } -} - -inline std::string format_as(const GXIndTexStageID& id) { - switch (id) { - case GX_INDTEXSTAGE0: - return "GX_INDTEXSTAGE0"; - case GX_INDTEXSTAGE1: - return "GX_INDTEXSTAGE1"; - case GX_INDTEXSTAGE2: - return "GX_INDTEXSTAGE2"; - case GX_INDTEXSTAGE3: - return "GX_INDTEXSTAGE3"; - default: - return fmt::format("GXIndTexStageID({})", underlying(id)); - } -} - -inline std::string format_as(const GXIndTexFormat& fmt_) { - switch (fmt_) { - case GX_ITF_8: - return "GX_ITF_8"; - case GX_ITF_5: - return "GX_ITF_5"; - case GX_ITF_4: - return "GX_ITF_4"; - case GX_ITF_3: - return "GX_ITF_3"; - default: - return fmt::format("GXIndTexFormat({})", underlying(fmt_)); - } -} - -inline std::string format_as(const GXIndTexBiasSel& sel) { - switch (sel) { - case GX_ITB_NONE: - return "GX_ITB_NONE"; - case GX_ITB_S: - return "GX_ITB_S"; - case GX_ITB_T: - return "GX_ITB_T"; - case GX_ITB_ST: - return "GX_ITB_ST"; - case GX_ITB_U: - return "GX_ITB_U"; - case GX_ITB_SU: - return "GX_ITB_SU"; - case GX_ITB_TU: - return "GX_ITB_TU"; - case GX_ITB_STU: - return "GX_ITB_STU"; - default: - return fmt::format("GXIndTexBiasSel({})", underlying(sel)); - } -} - -inline std::string format_as(const GXIndTexAlphaSel& sel) { - switch (sel) { - case GX_ITBA_OFF: - return "GX_ITBA_OFF"; - case GX_ITBA_S: - return "GX_ITBA_S"; - case GX_ITBA_T: - return "GX_ITBA_T"; - case GX_ITBA_U: - return "GX_ITBA_U"; - default: - return fmt::format("GXIndTexAlphaSel({})", underlying(sel)); - } -} - -inline std::string format_as(const GXIndTexMtxID& id) { - switch (id) { - case GX_ITM_OFF: - return "GX_ITM_OFF"; - case GX_ITM_0: - return "GX_ITM_0"; - case GX_ITM_1: - return "GX_ITM_1"; - case GX_ITM_2: - return "GX_ITM_2"; - case GX_ITM_S0: - return "GX_ITM_S0"; - case GX_ITM_S1: - return "GX_ITM_S1"; - case GX_ITM_S2: - return "GX_ITM_S2"; - case GX_ITM_T0: - return "GX_ITM_T0"; - case GX_ITM_T1: - return "GX_ITM_T1"; - case GX_ITM_T2: - return "GX_ITM_T2"; - default: - return fmt::format("GXIndTexMtxID({})", underlying(id)); - } -} - -inline std::string format_as(const GXIndTexWrap& wrap) { - switch (wrap) { - case GX_ITW_OFF: - return "GX_ITW_OFF"; - case GX_ITW_256: - return "GX_ITW_256"; - case GX_ITW_128: - return "GX_ITW_128"; - case GX_ITW_64: - return "GX_ITW_64"; - case GX_ITW_32: - return "GX_ITW_32"; - case GX_ITW_16: - return "GX_ITW_16"; - case GX_ITW_0: - return "GX_ITW_0"; - default: - return fmt::format("GXIndTexWrap({})", underlying(wrap)); - } -} - -inline std::string format_as(const GXIndTexScale& scale) { - switch (scale) { - case GX_ITS_1: - return "GX_ITS_1"; - case GX_ITS_2: - return "GX_ITS_2"; - case GX_ITS_4: - return "GX_ITS_4"; - case GX_ITS_8: - return "GX_ITS_8"; - case GX_ITS_16: - return "GX_ITS_16"; - case GX_ITS_32: - return "GX_ITS_32"; - case GX_ITS_64: - return "GX_ITS_64"; - case GX_ITS_128: - return "GX_ITS_128"; - case GX_ITS_256: - return "GX_ITS_256"; - default: - return fmt::format("GXIndTexScale({})", underlying(scale)); - } -} - -inline std::string format_as(const GXPrimitive& prim) { - switch (prim) { - case GX_QUADS: - return "GX_QUADS"; - case GX_TRIANGLES: - return "GX_TRIANGLES"; - case GX_TRIANGLESTRIP: - return "GX_TRIANGLESTRIP"; - case GX_TRIANGLEFAN: - return "GX_TRIANGLEFAN"; - case GX_LINES: - return "GX_LINES"; - case GX_LINESTRIP: - return "GX_LINESTRIP"; - case GX_POINTS: - return "GX_POINTS"; - default: - return fmt::format("GXPrimitive({})", underlying(prim)); - } -} - -inline std::string format_as(const GXAttr& attr) { - switch (attr) { - case GX_VA_PNMTXIDX: - return "GX_VA_PNMTXIDX"; - case GX_VA_TEX0MTXIDX: - return "GX_VA_TEX0MTXIDX"; - case GX_VA_TEX1MTXIDX: - return "GX_VA_TEX1MTXIDX"; - case GX_VA_TEX2MTXIDX: - return "GX_VA_TEX2MTXIDX"; - case GX_VA_TEX3MTXIDX: - return "GX_VA_TEX3MTXIDX"; - case GX_VA_TEX4MTXIDX: - return "GX_VA_TEX4MTXIDX"; - case GX_VA_TEX5MTXIDX: - return "GX_VA_TEX5MTXIDX"; - case GX_VA_TEX6MTXIDX: - return "GX_VA_TEX6MTXIDX"; - case GX_VA_TEX7MTXIDX: - return "GX_VA_TEX7MTXIDX"; - case GX_VA_POS: - return "GX_VA_POS"; - case GX_VA_NRM: - return "GX_VA_NRM"; - case GX_VA_CLR0: - return "GX_VA_CLR0"; - case GX_VA_CLR1: - return "GX_VA_CLR1"; - case GX_VA_TEX0: - return "GX_VA_TEX0"; - case GX_VA_TEX1: - return "GX_VA_TEX1"; - case GX_VA_TEX2: - return "GX_VA_TEX2"; - case GX_VA_TEX3: - return "GX_VA_TEX3"; - case GX_VA_TEX4: - return "GX_VA_TEX4"; - case GX_VA_TEX5: - return "GX_VA_TEX5"; - case GX_VA_TEX6: - return "GX_VA_TEX6"; - case GX_VA_TEX7: - return "GX_VA_TEX7"; - case GX_POS_MTX_ARRAY: - return "GX_POS_MTX_ARRAY"; - case GX_NRM_MTX_ARRAY: - return "GX_NRM_MTX_ARRAY"; - case GX_TEX_MTX_ARRAY: - return "GX_TEX_MTX_ARRAY"; - case GX_LIGHT_ARRAY: - return "GX_LIGHT_ARRAY"; - case GX_VA_NBT: - return "GX_VA_NBT"; - case GX_VA_NULL: - return "GX_VA_NULL"; - default: - return fmt::format("GXAttr({})", underlying(attr)); - } -} - -inline std::string format_as(const GXCompCnt& cnt) { - switch (cnt) { - case GX_POS_XY: - return "GX_POS_XY|GX_NRM_XYZ|GX_CLR_RGB|GX_TEX_S"; - case GX_POS_XYZ: - return "GX_POS_XYZ|GX_NRM_NBT|GX_CLR_RGBA|GX_TEX_ST"; - case GX_NRM_NBT3: - return "GX_NRM_NBT3"; - default: - return fmt::format("GXCompCnt({})", underlying(cnt)); - } -} - -inline std::string format_as(const GXCompType& type) { - switch (type) { - case GX_U8: - return "GX_U8|GX_RGB565"; - case GX_S8: - return "GX_S8|GX_RGB8"; - case GX_U16: - return "GX_U16|GX_RGBX8"; - case GX_S16: - return "GX_S16|GX_RGBA4"; - case GX_F32: - return "GX_F32|GX_RGBA6"; - case GX_RGBA8: - return "GX_RGBA8"; - default: - return fmt::format("GXCompType({})", underlying(type)); - } -} - -inline std::string format_as(const GXAttrType& type) { - switch (type) { - case GX_NONE: - return "GX_NONE"; - case GX_DIRECT: - return "GX_DIRECT"; - case GX_INDEX8: - return "GX_INDEX8"; - case GX_INDEX16: - return "GX_INDEX16"; - default: - return fmt::format("GXAttrType({})", underlying(type)); - } -} - -inline std::string format_as(const GXVtxFmt& fmt) { - switch (fmt) { - case GX_VTXFMT0: - return "GX_VTXFMT0"; - case GX_VTXFMT1: - return "GX_VTXFMT1"; - case GX_VTXFMT2: - return "GX_VTXFMT2"; - case GX_VTXFMT3: - return "GX_VTXFMT3"; - case GX_VTXFMT4: - return "GX_VTXFMT4"; - case GX_VTXFMT5: - return "GX_VTXFMT5"; - case GX_VTXFMT6: - return "GX_VTXFMT6"; - case GX_VTXFMT7: - return "GX_VTXFMT7"; - default: - return fmt::format("GXVtxFmt({})", underlying(fmt)); - } -} - -inline std::string format_as(const GXTexFmt& fmt) { - switch (fmt) { - case GX_TF_I4: - return "GX_TF_I4"; - case GX_TF_I8: - return "GX_TF_I8"; - case GX_TF_IA4: - return "GX_TF_IA4"; - case GX_TF_IA8: - return "GX_TF_IA8"; - case GX_TF_RGB565: - return "GX_TF_RGB565"; - case GX_TF_RGB5A3: - return "GX_TF_RGB5A3"; - case GX_TF_RGBA8: - return "GX_TF_RGBA8"; - case GX_TF_CMPR: - return "GX_TF_CMPR"; - case GX_CTF_R4: - return "GX_CTF_R4"; - case GX_CTF_RA4: - return "GX_CTF_RA4"; - case GX_CTF_RA8: - return "GX_CTF_RA8"; - case GX_CTF_YUVA8: - return "GX_CTF_YUVA8"; - case GX_CTF_A8: - return "GX_CTF_A8"; - case GX_CTF_R8: - return "GX_CTF_R8"; - case GX_CTF_G8: - return "GX_CTF_G8"; - case GX_CTF_B8: - return "GX_CTF_B8"; - case GX_CTF_RG8: - return "GX_CTF_RG8"; - case GX_CTF_GB8: - return "GX_CTF_GB8"; - case GX_TF_Z8: - return "GX_TF_Z8"; - case GX_TF_Z16: - return "GX_TF_Z16"; - case GX_TF_Z24X8: - return "GX_TF_Z24X8"; - case GX_CTF_Z4: - return "GX_CTF_Z4"; - case GX_CTF_Z8M: - return "GX_CTF_Z8M"; - case GX_CTF_Z8L: - return "GX_CTF_Z8L"; - case GX_CTF_Z16L: - return "GX_CTF_Z16L"; - case GX_TF_R8_PC: - return "GX_TF_R8_PC"; - case GX_TF_RGBA8_PC: - return "GX_TF_RGBA8_PC"; - default: - return fmt::format("GXTexFmt({})", underlying(fmt)); - } -} - -inline std::string format_as(const GXTlutFmt& fmt) { - switch (fmt) { - case GX_TL_IA8: - return "GX_TL_IA8"; - case GX_TL_RGB565: - return "GX_TL_RGB565"; - case GX_TL_RGB5A3: - return "GX_TL_RGB5A3"; - default: - return fmt::format("GXTlutFmt({})", underlying(fmt)); - } -} diff --git a/aurora-main/lib/gx/pipeline.cpp b/aurora-main/lib/gx/pipeline.cpp deleted file mode 100644 index 9b1571e..0000000 --- a/aurora-main/lib/gx/pipeline.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "pipeline.hpp" - -#include "../webgpu/gpu.hpp" -#include "gx_fmt.hpp" -#include "shader_info.hpp" -#include "tracy/Tracy.hpp" - -#include -#include -#include - -#include - -namespace aurora::gx { -static Module Log("aurora::gx"); - -namespace { -struct ShaderConfigHash { - size_t operator()(const ShaderConfig& config) const noexcept { return static_cast(xxh3_hash(config)); } -}; - -struct CachedShaderModule { - std::condition_variable ready; - wgpu::ShaderModule module; - bool compiling = true; -}; - -std::mutex sShaderModuleCacheMutex; -absl::flat_hash_map, ShaderConfigHash> sShaderModuleCache; - -wgpu::ShaderModule cached_shader_module(const ShaderConfig& config) { - std::shared_ptr entry; - { - std::unique_lock lock{sShaderModuleCacheMutex}; - const auto it = sShaderModuleCache.find(config); - if (it == sShaderModuleCache.end()) { - entry = std::make_shared(); - sShaderModuleCache.emplace(config, entry); - } else { - entry = it->second; - entry->ready.wait(lock, [&] { return !entry->compiling; }); - return entry->module; - } - } - - auto module = build_shader(config); - { - std::lock_guard lock{sShaderModuleCacheMutex}; - entry->module = module; - entry->compiling = false; - } - entry->ready.notify_all(); - return module; -} -} // namespace - -wgpu::RenderPipeline create_pipeline(const PipelineConfig& config) { - ZoneScoped; - const auto shader = cached_shader_module(config.shaderConfig); - return build_pipeline(config, {}, shader, "GX Pipeline"); -} - -void clear_shader_module_cache() { - std::lock_guard lock{sShaderModuleCacheMutex}; - sShaderModuleCache.clear(); -} - -void render(const DrawData& data, const wgpu::RenderPassEncoder& pass, DrawEncodeState& state, - bool requireReadyPipeline, const gfx::Range* uniformRangeOverride) { - if (!gfx::bind_pipeline(data.pipeline, pass, state.currentPipeline, requireReadyPipeline)) { - return; - } - - // An interpolated presentation slot re-encodes the identical draw with only this range replaced; overriding here avoids copying the whole DrawData per draw per slot. - const gfx::Range& uniformRange = uniformRangeOverride != nullptr ? *uniformRangeOverride : data.uniformRange; - const std::array offsets{uniformRange.offset}; - pass.SetBindGroup(1, gfx::g_uniformBindGroup, offsets.size(), offsets.data()); - // Resolved when the draw was recorded; see GXBindGroups. - if (data.bindGroups.resolvedTextureBindGroup != nullptr && - data.bindGroups.resolvedTextureBindGroup != state.boundTextureBindGroup) { - wgpuRenderPassEncoderSetBindGroup(pass.Get(), 2, data.bindGroups.resolvedTextureBindGroup, 0, nullptr); - state.boundTextureBindGroup = data.bindGroups.resolvedTextureBindGroup; - } - if (data.dstAlpha != UINT32_MAX) { - const wgpu::Color color{0.f, 0.f, 0.f, data.dstAlpha / 255.f}; - pass.SetBlendConstant(&color); - } - if (!state.indexBufferBound) { - // Bound once for the pass; draws select their range with firstIndex below. - pass.SetIndexBuffer(gfx::g_indexBuffer, wgpu::IndexFormat::Uint16, 0, wgpu::kWholeSize); - state.indexBufferBound = true; - } - pass.DrawIndexed(data.indexCount, data.instanceCount, - static_cast(data.idxRange.offset / sizeof(uint16_t))); -} -} // namespace aurora::gx diff --git a/aurora-main/lib/gx/pipeline.hpp b/aurora-main/lib/gx/pipeline.hpp deleted file mode 100644 index a6752b8..0000000 --- a/aurora-main/lib/gx/pipeline.hpp +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once - -#include "../gfx/common.hpp" -#include "shader_info.hpp" - -namespace aurora::gx { -struct DrawData { - gfx::PipelineRef pipeline; - gfx::Range vertRange; - gfx::Range idxRange; - gfx::Range uniformRange; - std::array interpolatedUniformRanges; - uint32_t vtxCount; - uint32_t indexCount; - uint32_t instanceCount; - bool expandedPrimitive; - GXBindGroups bindGroups; - uint32_t dstAlpha; -}; - -constexpr uint32_t GXPipelineConfigVersion = 19; - -constexpr GXFogType effective_pipeline_fog_type(GXFogType fogType, GXZTexOp zTextureOp, - bool zCompLocBeforeTex, GXBlendMode blendMode, - GXLogicOp logicOp) noexcept { - const bool usesLateZTexture = zTextureOp != GX_ZT_DISABLE && !zCompLocBeforeTex; - const bool usesUnsupportedLogicFog = - blendMode == GX_BM_LOGIC && logicOp != GX_LO_OR; - return usesLateZTexture && usesUnsupportedLogicFog ? GX_FOG_NONE : fogType; -} - -struct PipelineConfig { - uint32_t version = GXPipelineConfigVersion; - uint32_t msaaSamples = 1; - ShaderConfig shaderConfig; - GXCompare depthFunc; - GXCullMode cullMode; - GXBlendMode blendMode; - GXBlendFactor blendFacSrc, blendFacDst; - GXLogicOp blendOp; - GXPixelFmt pixelFmt; - uint32_t dstAlpha; - bool depthCompare, depthUpdate, alphaUpdate, colorUpdate; -}; -static_assert(std::has_unique_object_representations_v); - -inline bool valid_pipeline_config(const PipelineConfig& config) noexcept { - const auto in_range = [](auto value, auto maximum) { - using Value = decltype(value); - return static_cast>(value) >= 0 && - static_cast>(value) <= - static_cast>(maximum); - }; - const bool validSamples = config.msaaSamples == 1 || config.msaaSamples == 2 || - config.msaaSamples == 4 || config.msaaSamples == 8; - return config.version == GXPipelineConfigVersion && validSamples && - in_range(config.depthFunc, GX_ALWAYS) && in_range(config.cullMode, GX_CULL_ALL) && - in_range(config.blendMode, GX_BM_SUBTRACT) && - in_range(config.blendFacSrc, GX_BL_INVDSTALPHA) && - in_range(config.blendFacDst, GX_BL_INVDSTALPHA) && - in_range(config.blendOp, GX_LO_SET) && in_range(config.pixelFmt, GX_PF_YUV420); -} - -wgpu::RenderPipeline create_pipeline([[maybe_unused]] const PipelineConfig& config); -void clear_shader_module_cache(); - -// Per-pass encoder state carried across the draws of one render pass, so the replay loop can elide Dawn calls that would re-bind what is already bound. -struct DrawEncodeState { - gfx::PipelineRef currentPipeline = UINTPTR_MAX; - // The bind group currently occupying slot 2. - WGPUBindGroup boundTextureBindGroup = nullptr; - // The pass-wide index buffer binding is established lazily by the first indexed draw; every draw then addresses it with firstIndex instead of a per-draw SetIndexBuffer. - bool indexBufferBound = false; -}; - -void render(const DrawData& data, const wgpu::RenderPassEncoder& pass, DrawEncodeState& state, - bool requireReadyPipeline, const gfx::Range* uniformRangeOverride = nullptr); - -void queue_surface(const u8* dlStart, uint32_t dlSize, bool bigEndian) noexcept; -} // namespace aurora::gx diff --git a/aurora-main/lib/gx/shader.cpp b/aurora-main/lib/gx/shader.cpp deleted file mode 100644 index 15025fe..0000000 --- a/aurora-main/lib/gx/shader.cpp +++ /dev/null @@ -1,2109 +0,0 @@ -#include "../gfx/common.hpp" - -#include "../internal.hpp" -#include "../webgpu/gpu.hpp" -#include "gx.hpp" -#include "gx_fmt.hpp" -#include "shader_info.hpp" - -#include - -#include -#include -#include -#include - -#include "tracy/Tracy.hpp" - -namespace aurora::gx { -using namespace fmt::literals; -using namespace std::string_literals; -using namespace std::string_view_literals; - -static Module Log("aurora::gfx::gx"); - - -static inline std::string_view chan_comp(GXTevColorChan chan) noexcept { - switch (chan) { - case GX_CH_RED: - return "r"; - case GX_CH_GREEN: - return "g"; - case GX_CH_BLUE: - return "b"; - case GX_CH_ALPHA: - return "a"; - default: - return "?"; - } -} - -static bool is_alpha_bump_channel(GXChannelID id) noexcept { return id == GX_ALPHA_BUMP || id == GX_ALPHA_BUMPN; } - -static std::string_view disabled_texture_color(const ShaderConfig& config) noexcept { - return config.numTexGens == 0 ? "vec3f(0.0)"sv : "vec3f(1.0)"sv; -} - -static std::string_view disabled_texture_alpha(const ShaderConfig& config) noexcept { - return config.numTexGens == 0 ? "0.0"sv : "1.0"sv; -} - -static std::string tev_mask_expr(const std::string& value, u32 mask) { - // t_IndTexCoord is already expanded into the 0..255 indirect sample domain. - return fmt::format("(f32(u32({}) & 0x{:X}u) / 255.0)", value, mask); -} - -static std::string alpha_bump_sel(size_t stageIdx, const ShaderConfig& config, const TevStage& stage) { - if (stage.indTexStage >= config.numIndStages || stage.indTexAlphaSel == GX_ITBA_OFF) { - return "0.0"; - } - - std::string baseCoord; - switch (stage.indTexAlphaSel) { - DEFAULT_FATAL("invalid indTexAlphaSel {} for stage {}", underlying(stage.indTexAlphaSel), stageIdx); - case GX_ITBA_S: - baseCoord = fmt::format("t_IndTexCoord{}.x", underlying(stage.indTexStage)); - break; - case GX_ITBA_T: - baseCoord = fmt::format("t_IndTexCoord{}.y", underlying(stage.indTexStage)); - break; - case GX_ITBA_U: - baseCoord = fmt::format("t_IndTexCoord{}.z", underlying(stage.indTexStage)); - break; - case GX_ITBA_OFF: - return "0.0"; - } - - switch (stage.indTexFormat) { - DEFAULT_FATAL("invalid indirect format {} for stage {}", underlying(stage.indTexFormat), stageIdx); - case GX_ITF_8: - return tev_mask_expr(baseCoord, 0xF8u); - case GX_ITF_5: - return tev_mask_expr(baseCoord, 0xE0u); - case GX_ITF_4: - return tev_mask_expr(baseCoord, 0xF0u); - case GX_ITF_3: - return tev_mask_expr(baseCoord, 0xF8u); - } -} - -u8 color_channel(GXChannelID id) noexcept { - switch (id) { - DEFAULT_FATAL("unimplemented color channel {}", id); - case GX_COLOR0: - case GX_ALPHA0: - case GX_COLOR0A0: - return 0; - case GX_COLOR1: - case GX_ALPHA1: - case GX_COLOR1A1: - return 1; - } -} - -static std::string color_arg_reg(GXTevColorArg arg, size_t stageIdx, const ShaderConfig& config, - const TevStage& stage) { - switch (arg) { - DEFAULT_FATAL("invalid color arg {}", underlying(arg)); - case GX_CC_CPREV: - return "prev.rgb"; - case GX_CC_APREV: - return "vec3f(prev.a)"; - case GX_CC_C0: - return "tevreg0.rgb"; - case GX_CC_A0: - return "vec3f(tevreg0.a)"; - case GX_CC_C1: - return "tevreg1.rgb"; - case GX_CC_A1: - return "vec3f(tevreg1.a)"; - case GX_CC_C2: - return "tevreg2.rgb"; - case GX_CC_A2: - return "vec3f(tevreg2.a)"; - case GX_CC_TEXC: { - if (!tev_stage_texture_dependency(config, static_cast(stageIdx)).canSampleTexture) { - return std::string(disabled_texture_color(config)); - } - const auto& swap = config.tevSwapTable[stage.tevSwapTex]; - return fmt::format("sampled{}.{}{}{}", stageIdx, chan_comp(swap.red), chan_comp(swap.green), chan_comp(swap.blue)); - } - case GX_CC_TEXA: { - if (!tev_stage_texture_dependency(config, static_cast(stageIdx)).canSampleTexture) { - return fmt::format("vec3f({})", disabled_texture_alpha(config)); - } - const auto& swap = config.tevSwapTable[stage.tevSwapTex]; - return fmt::format("vec3f(sampled{}.{})", stageIdx, chan_comp(swap.alpha)); - } - case GX_CC_RASC: { - // CHECK(stage.channelId != GX_COLOR_NULL, "unmapped color channel for stage {}", stageIdx); - if (stage.channelId == GX_COLOR_ZERO || stage.channelId == GX_COLOR_NULL) { - return "vec3f(0.0)"; - } - if (is_alpha_bump_channel(stage.channelId)) { - std::string alpha = alpha_bump_sel(stageIdx, config, stage); - if (stage.channelId == GX_ALPHA_BUMPN) { - alpha = fmt::format("({} * (255.0 / 248.0))", alpha); - } - return fmt::format("vec3f({})", alpha); - } - u32 idx = color_channel(stage.channelId); - const auto& swap = config.tevSwapTable[stage.tevSwapRas]; - return fmt::format("rast{}.{}{}{}", idx, chan_comp(swap.red), chan_comp(swap.green), chan_comp(swap.blue)); - } - case GX_CC_RASA: { - // CHECK(stage.channelId != GX_COLOR_NULL, "unmapped color channel for stage {}", stageIdx); - if (stage.channelId == GX_COLOR_ZERO || stage.channelId == GX_COLOR_NULL) { - return "vec3f(0.0)"; - } - if (is_alpha_bump_channel(stage.channelId)) { - std::string alpha = alpha_bump_sel(stageIdx, config, stage); - if (stage.channelId == GX_ALPHA_BUMPN) { - alpha = fmt::format("({} * (255.0 / 248.0))", alpha); - } - return fmt::format("vec3f({})", alpha); - } - u32 idx = color_channel(stage.channelId); - const auto& swap = config.tevSwapTable[stage.tevSwapRas]; - return fmt::format("vec3f(rast{}.{})", idx, chan_comp(swap.alpha)); - } - case GX_CC_ONE: - return "vec3f(1.0)"; - case GX_CC_HALF: - return "vec3f(0.5)"; - case GX_CC_KONST: { - switch (stage.kcSel) { - DEFAULT_FATAL("invalid kcSel {}", underlying(stage.kcSel)); - // Unsourced encodings evaluate to zero in hardware. - case static_cast(0x08): - case static_cast(0x09): - case static_cast(0x0A): - case static_cast(0x0B): - return "vec3f(0.0)"; - case GX_TEV_KCSEL_8_8: - return "vec3f(1.0)"; - case GX_TEV_KCSEL_7_8: - return "vec3f(7.0/8.0)"; - case GX_TEV_KCSEL_6_8: - return "vec3f(6.0/8.0)"; - case GX_TEV_KCSEL_5_8: - return "vec3f(5.0/8.0)"; - case GX_TEV_KCSEL_4_8: - return "vec3f(4.0/8.0)"; - case GX_TEV_KCSEL_3_8: - return "vec3f(3.0/8.0)"; - case GX_TEV_KCSEL_2_8: - return "vec3f(2.0/8.0)"; - case GX_TEV_KCSEL_1_8: - return "vec3f(1.0/8.0)"; - case GX_TEV_KCSEL_K0: - return "ubuf.kcolor0.rgb"; - case GX_TEV_KCSEL_K1: - return "ubuf.kcolor1.rgb"; - case GX_TEV_KCSEL_K2: - return "ubuf.kcolor2.rgb"; - case GX_TEV_KCSEL_K3: - return "ubuf.kcolor3.rgb"; - case GX_TEV_KCSEL_K0_R: - return "vec3f(ubuf.kcolor0.r)"; - case GX_TEV_KCSEL_K1_R: - return "vec3f(ubuf.kcolor1.r)"; - case GX_TEV_KCSEL_K2_R: - return "vec3f(ubuf.kcolor2.r)"; - case GX_TEV_KCSEL_K3_R: - return "vec3f(ubuf.kcolor3.r)"; - case GX_TEV_KCSEL_K0_G: - return "vec3f(ubuf.kcolor0.g)"; - case GX_TEV_KCSEL_K1_G: - return "vec3f(ubuf.kcolor1.g)"; - case GX_TEV_KCSEL_K2_G: - return "vec3f(ubuf.kcolor2.g)"; - case GX_TEV_KCSEL_K3_G: - return "vec3f(ubuf.kcolor3.g)"; - case GX_TEV_KCSEL_K0_B: - return "vec3f(ubuf.kcolor0.b)"; - case GX_TEV_KCSEL_K1_B: - return "vec3f(ubuf.kcolor1.b)"; - case GX_TEV_KCSEL_K2_B: - return "vec3f(ubuf.kcolor2.b)"; - case GX_TEV_KCSEL_K3_B: - return "vec3f(ubuf.kcolor3.b)"; - case GX_TEV_KCSEL_K0_A: - return "vec3f(ubuf.kcolor0.a)"; - case GX_TEV_KCSEL_K1_A: - return "vec3f(ubuf.kcolor1.a)"; - case GX_TEV_KCSEL_K2_A: - return "vec3f(ubuf.kcolor2.a)"; - case GX_TEV_KCSEL_K3_A: - return "vec3f(ubuf.kcolor3.a)"; - } - } - case GX_CC_ZERO: - return "vec3f(0.0)"; - } -} - -static std::string alpha_arg_reg(GXTevAlphaArg arg, size_t stageIdx, const ShaderConfig& config, - const TevStage& stage) { - switch (arg) { - DEFAULT_FATAL("invalid alpha arg {}", underlying(arg)); - case GX_CA_APREV: - return "prev.a"; - case GX_CA_A0: - return "tevreg0.a"; - case GX_CA_A1: - return "tevreg1.a"; - case GX_CA_A2: - return "tevreg2.a"; - case GX_CA_TEXA: { - if (!tev_stage_texture_dependency(config, static_cast(stageIdx)).canSampleTexture) { - return std::string(disabled_texture_alpha(config)); - } - const auto& swap = config.tevSwapTable[stage.tevSwapTex]; - return fmt::format("sampled{}.{}", stageIdx, chan_comp(swap.alpha)); - } - case GX_CA_RASA: { - // CHECK(stage.channelId != GX_COLOR_NULL, "unmapped color channel for stage {}", stageIdx); - if (stage.channelId == GX_COLOR_ZERO || stage.channelId == GX_COLOR_NULL) { - return "0.0"; - } - if (is_alpha_bump_channel(stage.channelId)) { - std::string alpha = alpha_bump_sel(stageIdx, config, stage); - if (stage.channelId == GX_ALPHA_BUMPN) { - alpha = fmt::format("({} * (255.0 / 248.0))", alpha); - } - return alpha; - } - u32 idx = color_channel(stage.channelId); - const auto& swap = config.tevSwapTable[stage.tevSwapRas]; - return fmt::format("rast{}.{}", idx, chan_comp(swap.alpha)); - } - case GX_CA_KONST: { - switch (stage.kaSel) { - DEFAULT_FATAL("invalid kaSel {}", underlying(stage.kaSel)); - // Unsourced encodings evaluate to zero in hardware. - case static_cast(0x08): - case static_cast(0x09): - case static_cast(0x0A): - case static_cast(0x0B): - case static_cast(0x0C): - case static_cast(0x0D): - case static_cast(0x0E): - case static_cast(0x0F): - return "0.0"; - case GX_TEV_KASEL_8_8: - return "1.0"; - case GX_TEV_KASEL_7_8: - return "(7.0/8.0)"; - case GX_TEV_KASEL_6_8: - return "(6.0/8.0)"; - case GX_TEV_KASEL_5_8: - return "(5.0/8.0)"; - case GX_TEV_KASEL_4_8: - return "(4.0/8.0)"; - case GX_TEV_KASEL_3_8: - return "(3.0/8.0)"; - case GX_TEV_KASEL_2_8: - return "(2.0/8.0)"; - case GX_TEV_KASEL_1_8: - return "(1.0/8.0)"; - case GX_TEV_KASEL_K0_R: - return "ubuf.kcolor0.r"; - case GX_TEV_KASEL_K1_R: - return "ubuf.kcolor1.r"; - case GX_TEV_KASEL_K2_R: - return "ubuf.kcolor2.r"; - case GX_TEV_KASEL_K3_R: - return "ubuf.kcolor3.r"; - case GX_TEV_KASEL_K0_G: - return "ubuf.kcolor0.g"; - case GX_TEV_KASEL_K1_G: - return "ubuf.kcolor1.g"; - case GX_TEV_KASEL_K2_G: - return "ubuf.kcolor2.g"; - case GX_TEV_KASEL_K3_G: - return "ubuf.kcolor3.g"; - case GX_TEV_KASEL_K0_B: - return "ubuf.kcolor0.b"; - case GX_TEV_KASEL_K1_B: - return "ubuf.kcolor1.b"; - case GX_TEV_KASEL_K2_B: - return "ubuf.kcolor2.b"; - case GX_TEV_KASEL_K3_B: - return "ubuf.kcolor3.b"; - case GX_TEV_KASEL_K0_A: - return "ubuf.kcolor0.a"; - case GX_TEV_KASEL_K1_A: - return "ubuf.kcolor1.a"; - case GX_TEV_KASEL_K2_A: - return "ubuf.kcolor2.a"; - case GX_TEV_KASEL_K3_A: - return "ubuf.kcolor3.a"; - } - } - case GX_CA_ZERO: - return "0.0"; - } -} - -static std::string tev_bias_i32(GXTevBias bias) { - switch (bias) { - DEFAULT_FATAL("invalid tev bias {}", underlying(bias)); - case GX_TB_ZERO: - return "0"; - case GX_TB_ADDHALF: - return "128"; - case GX_TB_SUBHALF: - return "-128"; - } -} - -static std::string tev_scale_index(GXTevScale scale) { - switch (scale) { - DEFAULT_FATAL("invalid tev scale {}", underlying(scale)); - case GX_CS_SCALE_1: - return "0u"; - case GX_CS_SCALE_2: - return "1u"; - case GX_CS_SCALE_4: - return "2u"; - case GX_CS_DIVIDE_2: - return "3u"; - } -} - -static std::string tev_regular_op(GXTevOp op, GXTevBias bias, GXTevScale scale, std::string_view a, - std::string_view b, std::string_view c, std::string_view d, - std::string_view suffix) { - CHECK(op == GX_TEV_ADD || op == GX_TEV_SUB, "invalid regular tev op {}", underlying(op)); - return fmt::format("tev_regular_{4}({0}, {1}, {2}, {3}, {5}, {6}, {7})", a, b, c, d, suffix, - tev_bias_i32(bias), tev_scale_index(scale), op == GX_TEV_SUB ? "true" : "false"); -} - -static std::string tev_op(GXTevOp op, GXTevBias bias, GXTevScale scale, std::string_view a, std::string_view b, - std::string_view c, std::string_view d, std::string_view zero, - std::string_view suffix) { - switch (op) { - DEFAULT_FATAL("unimplemented tev op {}", underlying(op)); - case GX_TEV_ADD: - case GX_TEV_SUB: - return tev_regular_op(op, bias, scale, a, b, c, d, suffix); - case GX_TEV_COMP_R8_GT: - return fmt::format("select({3}, {2}, round({0}.r * 255.0) > round({1}.r * 255.0)) + {4}", a, b, c, zero, d); - case GX_TEV_COMP_R8_EQ: - return fmt::format("select({3}, {2}, round({0}.r * 255.0) == round({1}.r * 255.0)) + {4}", a, b, c, zero, d); - case GX_TEV_COMP_GR16_GT: - return fmt::format( - "select({3}, {2}, round(dot({0}.rg * 255.0, vec2(1.0, 256.0))) > round(dot({1}.rg * 255.0, vec2(1.0, 256.0))))" - " + {4}", - a, b, c, zero, d); - case GX_TEV_COMP_GR16_EQ: - return fmt::format( - "select({3}, {2}, round(dot({0}.rg * 255.0, vec2(1.0, 256.0))) == round(dot({1}.rg * 255.0, vec2(1.0, 256.0))))" - " + {4}", - a, b, c, zero, d); - case GX_TEV_COMP_BGR24_GT: - return fmt::format( - "select({3}, {2}, round(dot({0}.rgb * 255.0, vec3(1.0, 256.0, 65536.0))) > round(dot({1}.rgb * 255.0, " - "vec3(1.0, 256.0, 65536.0)))) + {4}", - a, b, c, zero, d); - case GX_TEV_COMP_BGR24_EQ: - return fmt::format( - "select({3}, {2}, round(dot({0}.rgb * 255.0, vec3(1.0, 256.0, 65536.0))) == round(dot({1}.rgb * 255.0, " - "vec3(1.0, 256.0, 65536.0)))) + {4}", - a, b, c, zero, d); - case GX_TEV_COMP_RGB8_GT: - return fmt::format("select({3}, {2}, round({0} * 255.0) > round({1} * 255.0)) + {4}", a, b, c, zero, d); - case GX_TEV_COMP_RGB8_EQ: - return fmt::format("select({3}, {2}, round({0} * 255.0) == round({1} * 255.0)) + {4}", a, b, c, zero, d); - } -} - -static std::string tev_color_op(GXTevOp op, GXTevBias bias, GXTevScale scale, bool clamp, - std::string_view a, std::string_view b, std::string_view c, std::string_view d) { - const auto overflow = [](std::string_view reg) { return fmt::format("tev_overflow_vec3f({})", reg); }; - std::string expr = tev_op(op, bias, scale, overflow(a), overflow(b), overflow(c), d, "vec3(0)"sv, "vec3f"sv); - return clamp ? fmt::format("clamp({}, vec3f(0.0), vec3f(1.0))", expr) - : fmt::format("clamp({}, vec3f(-1024.0 / 255.0), vec3f(1023.0 / 255.0))", expr); -} - -static bool alpha_compare_uses_color_inputs(GXTevOp op) noexcept { - switch (op) { - case GX_TEV_COMP_R8_GT: - case GX_TEV_COMP_R8_EQ: - case GX_TEV_COMP_GR16_GT: - case GX_TEV_COMP_GR16_EQ: - case GX_TEV_COMP_BGR24_GT: - case GX_TEV_COMP_BGR24_EQ: - return true; - default: - return false; - } -} - -static std::string tev_alpha_op(GXTevOp op, GXTevBias bias, GXTevScale scale, bool clamp, - std::string_view a, std::string_view b, std::string_view c, std::string_view d, - std::string_view colorA, std::string_view colorB) { - const auto scalarOverflow = [](std::string_view reg) { return fmt::format("tev_overflow_f32({})", reg); }; - std::string expr; - if (alpha_compare_uses_color_inputs(op)) { - const auto colorOverflow = [](std::string_view reg) { return fmt::format("tev_overflow_vec3f({})", reg); }; - // GX alpha compares R8/GR16/BGR24 using the color combiner's A/B inputs, while C and D remain the scalar alpha-combiner inputs. - expr = tev_op(op, bias, scale, colorOverflow(colorA), colorOverflow(colorB), scalarOverflow(c), d, "0.0"sv, - "f32"sv); - } else { - // The numeric RGB8 op aliases are the alpha combiner's A8 compares and therefore continue to compare scalar alpha A/B inputs here. - expr = tev_op(op, bias, scale, scalarOverflow(a), scalarOverflow(b), scalarOverflow(c), d, "0.0"sv, "f32"sv); - } - return clamp ? fmt::format("clamp({}, 0.0, 1.0)", expr) : fmt::format("clamp({}, -1024.0 / 255.0, 1023.0 / 255.0)", expr); -} - -struct AlphaCompareExpr { - std::string expr; - int constant = -1; -}; - -static AlphaCompareExpr alpha_compare_const(bool value) { return {value ? "true"s : "false"s, value ? 1 : 0}; } - -static AlphaCompareExpr alpha_compare_not(const AlphaCompareExpr& expr) { - if (expr.constant != -1) { - return alpha_compare_const(expr.constant == 0); - } - return {fmt::format("!{}", expr.expr), -1}; -} - -static AlphaCompareExpr alpha_compare_and(const AlphaCompareExpr& lhs, const AlphaCompareExpr& rhs) { - if (lhs.constant == 0 || rhs.constant == 0) { - return alpha_compare_const(false); - } - if (lhs.constant == 1) { - return rhs; - } - if (rhs.constant == 1) { - return lhs; - } - return {fmt::format("({} && {})", lhs.expr, rhs.expr), -1}; -} - -static AlphaCompareExpr alpha_compare_or(const AlphaCompareExpr& lhs, const AlphaCompareExpr& rhs) { - if (lhs.constant == 1 || rhs.constant == 1) { - return alpha_compare_const(true); - } - if (lhs.constant == 0) { - return rhs; - } - if (rhs.constant == 0) { - return lhs; - } - return {fmt::format("({} || {})", lhs.expr, rhs.expr), -1}; -} - -static AlphaCompareExpr alpha_compare_xor(const AlphaCompareExpr& lhs, const AlphaCompareExpr& rhs) { - if (lhs.constant != -1 && rhs.constant != -1) { - return alpha_compare_const(lhs.constant != rhs.constant); - } - if (lhs.constant == 0) { - return rhs; - } - if (rhs.constant == 0) { - return lhs; - } - if (lhs.constant == 1) { - return alpha_compare_not(rhs); - } - if (rhs.constant == 1) { - return alpha_compare_not(lhs); - } - return {fmt::format("({} != {})", lhs.expr, rhs.expr), -1}; -} - -static AlphaCompareExpr alpha_compare_xnor(const AlphaCompareExpr& lhs, const AlphaCompareExpr& rhs) { - if (lhs.constant != -1 && rhs.constant != -1) { - return alpha_compare_const(lhs.constant == rhs.constant); - } - if (lhs.constant == 0) { - return alpha_compare_not(rhs); - } - if (rhs.constant == 0) { - return alpha_compare_not(lhs); - } - if (lhs.constant == 1) { - return rhs; - } - if (rhs.constant == 1) { - return lhs; - } - return {fmt::format("({} == {})", lhs.expr, rhs.expr), -1}; -} - -static AlphaCompareExpr alpha_compare(GXCompare comp, u8 ref) { - const auto iref = static_cast(ref); - switch (comp) { - default: - return alpha_compare_const(true); - case GX_NEVER: - return alpha_compare_const(false); - case GX_LESS: - if (ref == 0) { - return alpha_compare_const(false); - } - return {fmt::format("(alphaCompare < {}u)", iref), -1}; - case GX_LEQUAL: - if (ref == 255) { - return alpha_compare_const(true); - } - return {fmt::format("(alphaCompare <= {}u)", iref), -1}; - case GX_EQUAL: - return {fmt::format("(alphaCompare == {}u)", iref), -1}; - case GX_NEQUAL: - return {fmt::format("(alphaCompare != {}u)", iref), -1}; - case GX_GEQUAL: - if (ref == 0) { - return alpha_compare_const(true); - } - return {fmt::format("(alphaCompare >= {}u)", iref), -1}; - case GX_GREATER: - if (ref == 255) { - return alpha_compare_const(false); - } - return {fmt::format("(alphaCompare > {}u)", iref), -1}; - case GX_ALWAYS: - return alpha_compare_const(true); - } -} - -static inline std::string vtx_attr(const ShaderConfig& config, GXAttr attr) { - const auto type = config.attrs[attr].attrType; - if (type == GX_NONE) { - if (attr == GX_VA_PNMTXIDX) { - return "ubuf.current_pnmtx"; - } - if (attr == GX_VA_NRM) { - // Default normal - return "vec3f(1.0, 0.0, 0.0)"s; - } - if (attr == GX_VA_CLR0 || attr == GX_VA_CLR1) { - return "vec4f(1.0)"s; - } - if (attr >= GX_VA_TEX0 && attr <= GX_VA_TEX7) { - return "vec2f(0.0, 0.0)"s; - } - UNLIKELY FATAL("unmapped vtx attr {}", underlying(attr)); - } - if (attr == GX_VA_POS) { - return "in_pos"s; - } - if (attr == GX_VA_NRM) { - return "in_nrm"s; - } - if (attr == GX_VA_CLR0 || attr == GX_VA_CLR1) { - const auto idx = attr - GX_VA_CLR0; - return fmt::format("in_clr{}", idx); - } - if (attr >= GX_VA_TEX0 && attr <= GX_VA_TEX7) { - const auto idx = attr - GX_VA_TEX0; - return fmt::format("in_tex{}_uv", idx); - } - if (attr == GX_VA_PNMTXIDX) { - return "in_pnmtxidx"s; - } - if (attr >= GX_VA_TEX0MTXIDX && attr <= GX_VA_TEX7MTXIDX) { - const auto idx = attr - GX_VA_TEX0MTXIDX; - return fmt::format("in_texmtxidx{}", idx); - } - UNLIKELY FATAL("unhandled vtx attr {}", underlying(attr)); -} - -static std::string vertex_color_attr(const ShaderConfig& config, u32 channel) { - const int attr = shader_vertex_color_attr(config, channel); - return attr >= 0 ? vtx_attr(config, static_cast(attr)) : "vec4f(1.0)"s; -} - -constexpr std::array TevColorArgNames{ - "CPREV"sv, "APREV"sv, "C0"sv, "A0"sv, "C1"sv, "A1"sv, "C2"sv, "A2"sv, - "TEXC"sv, "TEXA"sv, "RASC"sv, "RASA"sv, "ONE"sv, "HALF"sv, "KONST"sv, "ZERO"sv, -}; -constexpr std::array TevAlphaArgNames{ - "APREV"sv, "A0"sv, "A1"sv, "A2"sv, "TEXA"sv, "RASA"sv, "KONST"sv, "ZERO"sv, -}; - -auto fetch_attr(const AttrConfig& mapping, std::string_view buf, std::string_view offs, bool le, u8 cntOverride = 0) -> std::string { - const u8 cnt = cntOverride != 0 ? cntOverride : mapping.cnt; - switch (mapping.compType) { - case GX_U8: - return fmt::format("fetch_u8_{}(&{}, {}, {}, {})", cnt, buf, offs, mapping.frac, le); - case GX_S8: - return fmt::format("fetch_s8_{}(&{}, {}, {}, {})", cnt, buf, offs, mapping.frac, le); - case GX_U16: - return fmt::format("fetch_u16_{}(&{}, {}, {}, {})", cnt, buf, offs, mapping.frac, le); - case GX_S16: - return fmt::format("fetch_s16_{}(&{}, {}, {}, {})", cnt, buf, offs, mapping.frac, le); - case GX_F32: - return fmt::format("fetch_f32_{}(&{}, {}, {})", cnt, buf, offs, le); - case GX_RGBA8: - return fmt::format("unpack4x8unorm(load_u32_raw(&{}, {}))", buf, offs); - default: - Log.fatal("fetch_attr: Unimplemented {}", static_cast(mapping.compType)); - } -} - -auto fetch_color_attr(const AttrConfig& mapping, std::string_view buf, std::string_view offs, bool le) -> std::string { - switch (mapping.compType) { - case GX_RGB565: - return fmt::format("fetch_rgb565(&{}, {}, {})", buf, offs, le); - case GX_RGB8: - return fmt::format("fetch_rgb8(&{}, {}, {})", buf, offs, le); - case GX_RGBX8: - return fmt::format("fetch_rgbx8(&{}, {}, {})", buf, offs, le); - case GX_RGBA4: - return fmt::format("fetch_rgba4(&{}, {}, {})", buf, offs, le); - case GX_RGBA6: - return fmt::format("fetch_rgba6(&{}, {}, {})", buf, offs, le); - case GX_RGBA8: - return fmt::format("fetch_rgba8(&{}, {}, {})", buf, offs, le); - default: - Log.fatal("fetch_color_attr: Unimplemented {}", static_cast(mapping.compType)); - } -} - -auto attr_load(const ShaderConfig& config, GXAttr attr, std::string_view vidx) -> std::string; - -static u32 attr_comp_type_size(u8 compType) noexcept { - switch (static_cast(compType)) { - case GX_U8: - case GX_S8: - return 1; - case GX_U16: - case GX_S16: - return 2; - case GX_F32: - return 4; - default: - Log.fatal("attr_comp_type_size: Unimplemented {}", static_cast(compType)); - } -} - -static std::string offset_plus(std::string_view offs, u32 add) { - if (add == 0) { - return std::string(offs); - } - return fmt::format("({} + {}u)", offs, add); -} - -auto normal_group_load(const ShaderConfig& config, u8 group, std::string_view vidx) -> std::string { - const auto& mapping = config.attrs[GX_VA_NRM]; - if (mapping.attrType == GX_NONE || mapping.cnt != 9) { - return attr_load(config, GX_VA_NRM, vidx); - } - - auto buf = "vbuf"sv; - auto offs = fmt::format("ubuf.vtx_start + {} * {}u + {}u", vidx, config.vtxStride, mapping.offset); - auto le = false; // Vertex buffer is always big endian (for now) - const bool indexedNbt3 = - mapping.nrmIndexCount == 3 && (mapping.attrType == GX_INDEX8 || mapping.attrType == GX_INDEX16); - const u32 groupOffset = indexedNbt3 ? 0 : group * 3u * attr_comp_type_size(mapping.compType); - - if (mapping.attrType == GX_INDEX8) { - const std::string indexOffs = offset_plus(offs, mapping.nrmIndexCount == 3 ? group : 0); - offs = fmt::format("ubuf.array_start[{}] + raw_fetch_u8_1(&{}, {}) * {}u + {}u", GX_VA_NRM - GX_VA_POS, buf, - indexOffs, mapping.stride, groupOffset); - buf = "abuf"sv; - le = mapping.le; - } else if (mapping.attrType == GX_INDEX16) { - const std::string indexOffs = offset_plus(offs, mapping.nrmIndexCount == 3 ? group * 2u : 0); - offs = fmt::format("ubuf.array_start[{}] + raw_fetch_u16_1(&{}, {}, {}) * {}u + {}u", GX_VA_NRM - GX_VA_POS, - buf, indexOffs, le, mapping.stride, groupOffset); - buf = "abuf"sv; - le = mapping.le; - } else { - offs = offset_plus(offs, groupOffset); - } - - return fetch_attr(mapping, buf, offs, le, 3); -} - -auto attr_load(const ShaderConfig& config, GXAttr attr, std::string_view vidx) -> std::string { - const auto& mapping = config.attrs[attr]; - if (mapping.attrType == GX_NONE) { - return vtx_attr(config, attr); - } - auto buf = "vbuf"sv; - auto offs = fmt::format("ubuf.vtx_start + {} * {}u + {}u", vidx, config.vtxStride, mapping.offset); - auto le = false; // Vertex buffer is always big endian (for now) - if (mapping.attrType == GX_INDEX8) { - offs = fmt::format("ubuf.array_start[{}] + raw_fetch_u8_1(&{}, {}) * {}u", attr - GX_VA_POS, buf, offs, - mapping.stride); - buf = "abuf"sv; - le = mapping.le; - } else if (mapping.attrType == GX_INDEX16) { - offs = fmt::format("ubuf.array_start[{}] + raw_fetch_u16_1(&{}, {}, {}) * {}u", attr - GX_VA_POS, buf, offs, le, - mapping.stride); - buf = "abuf"sv; - le = mapping.le; - } - switch (attr) { - case GX_VA_PNMTXIDX: - return fmt::format("(raw_fetch_u8_1(&{}, {}) / 3u)", buf, offs); - case GX_VA_TEX0MTXIDX: - case GX_VA_TEX1MTXIDX: - case GX_VA_TEX2MTXIDX: - case GX_VA_TEX3MTXIDX: - case GX_VA_TEX4MTXIDX: - case GX_VA_TEX5MTXIDX: - case GX_VA_TEX6MTXIDX: - case GX_VA_TEX7MTXIDX: - return fmt::format("raw_fetch_u8_1(&{}, {})", buf, offs); - case GX_VA_POS: { - const auto posLoad = fetch_attr(mapping, buf, offs, le); - if (mapping.cnt == 2) { - return fmt::format("vec3f({}, 0.0)", posLoad); - } - return posLoad; - } - case GX_VA_NRM: - return fetch_attr(mapping, buf, offs, le, mapping.cnt == 9 ? 3 : 0); - case GX_VA_CLR0: - case GX_VA_CLR1: - return fetch_color_attr(mapping, buf, offs, le); - case GX_VA_TEX0: - case GX_VA_TEX1: - case GX_VA_TEX2: - case GX_VA_TEX3: - case GX_VA_TEX4: - case GX_VA_TEX5: - case GX_VA_TEX6: - case GX_VA_TEX7: { - const auto texLoad = fetch_attr(mapping, buf, offs, le); - if (mapping.cnt == 1) { - return fmt::format("vec2f({}, 0.0)", texLoad); - } - return texLoad; - } - default: - Log.fatal("attr_load: Unimplemented {}", attr); - } -} - -auto lighting_func(const ShaderConfig& config, const ColorChannelConfig& cc, u8 i, bool alpha) -> std::string { - std::string_view swizzle = alpha ? ".a"sv : ".rgb"sv; - std::string_view intType = alpha ? "i32"sv : "vec3i"sv; - std::string_view floatType = alpha ? "f32"sv : "vec3f"sv; - std::string_view intZero = alpha ? "0"sv : "vec3i(0)"sv; - std::string_view intMax = alpha ? "255"sv : "vec3i(255)"sv; - std::string_view shift7 = alpha ? "7u"sv : "vec3u(7u)"sv; - std::string_view shift8 = alpha ? "8u"sv : "vec3u(8u)"sv; - std::string outVar; - std::string_view posVar; - if (UsePerPixelLighting) { - outVar = fmt::format("rast{}", i); - posVar = "in.mv_pos"sv; - } else { - outVar = fmt::format("out.cc{}", i); - posVar = "mv_pos"sv; - } - std::string ambSrc, matSrc; - if (cc.ambSrc == GX_SRC_VTX) { - if (UsePerPixelLighting) { - ambSrc = fmt::format("in.clr{}", i); - } else { - ambSrc = vertex_color_attr(config, i); - } - } else if (cc.ambSrc == GX_SRC_REG) { - ambSrc = fmt::format("ubuf.cc{0}{1}_amb", i, alpha ? "a"sv : ""sv); - } - if (cc.matSrc == GX_SRC_VTX) { - if (UsePerPixelLighting) { - matSrc = fmt::format("in.clr{}", i); - } else { - matSrc = vertex_color_attr(config, i); - } - } else if (cc.matSrc == GX_SRC_REG) { - matSrc = fmt::format("ubuf.cc{0}{1}_mat", i, alpha ? "a"sv : ""sv); - } - if (!cc.lightingEnabled) { - // The XF lighting block consumes and produces 8-bit channel values even when lighting is disabled. - if (alpha) { - return fmt::format("\n {0}.a = f32(i32(round({1}.a * 255.0))) / 255.0;", outVar, matSrc); - } - return fmt::format("\n {0} = vec4f(vec3f(vec3i(round({1}.rgb * 255.0))) / 255.0, 1.0);", outVar, - matSrc); - } - GXDiffuseFn diffFn = cc.diffFn; - std::string lightAttnFn; - if (cc.attnFn == GX_AF_NONE) { - lightAttnFn = "attn = 1.0;"s; - } else if (cc.attnFn == GX_AF_SPOT) { - lightAttnFn = fmt::format(R"""( - var cosine = max(0.0, dot(ldir, light.dir)); - var cos_attn = dot(light.cos_att, vec3f(1.0, cosine, cosine * cosine)); - var dist_attn = dot(light.dist_att, vec3f(1.0, dist, dist2)); - attn = max(0.0, cos_attn / dist_attn);)"""); - } else if (cc.attnFn == GX_AF_SPEC) { - std::string_view normal = UsePerPixelLighting ? "in.mv_nrm"sv : "mv_nrm"sv; - std::string dist_attn = diffFn != GX_DF_NONE - ? "dot(normalize(light.dist_att), vec3f(1.0, attn, attn * attn))" - : "dot(light.dist_att, vec3f(1.0, attn, attn * attn))"; - lightAttnFn = fmt::format(R"""( - attn = select(0.0, max(0.0, dot({0}, light.dir)), dot({0}, ldir) >= 0.0); - var cos_attn = dot(light.cos_att, vec3f(1.0, attn, attn * attn)); - var dist_attn = {1}; - attn = select(select(0.0, 1.0, cos_attn > 0.0), max(0.0, cos_attn / dist_attn), dist_attn != 0.0);)""", - normal, dist_attn); - } - std::string_view normal = UsePerPixelLighting ? "in.mv_nrm"sv : "mv_nrm"sv; - std::string lightDirSetup; - if (cc.attnFn == GX_AF_NONE) { - lightDirSetup = fmt::format(R"""( - var ldir = light.pos - {0}; - var dist2 = dot(ldir, ldir); - var dist = sqrt(dist2); - ldir = select({1}, ldir / max(dist, 1e-20), dist > 0.0);)""", - posVar, normal); - } else { - lightDirSetup = fmt::format(R"""( - var ldir = light.pos - {0}; - var dist2 = dot(ldir, ldir); - var dist = sqrt(dist2); - ldir = ldir / dist;)""", - posVar); - } - std::string_view lightDiffFn; - if (diffFn == GX_DF_NONE) { - lightDiffFn = "1.0"sv; - } else if (diffFn == GX_DF_SIGN) { - if (UsePerPixelLighting) { - lightDiffFn = "dot(ldir, in.mv_nrm)"sv; - } else { - lightDiffFn = "dot(ldir, mv_nrm)"sv; - } - } else if (diffFn == GX_DF_CLAMP) { - if (UsePerPixelLighting) { - lightDiffFn = "max(0.0, dot(ldir, in.mv_nrm))"sv; - } else { - lightDiffFn = "max(0.0, dot(ldir, mv_nrm))"sv; - } - } - const auto outputTarget = alpha ? fmt::format("{}.a", outVar) : outVar; - const auto outputValue = - alpha - ? fmt::format("f32((material * (lacc + (lacc >> {}))) >> {}) / 255.0", shift7, shift8) - : fmt::format("vec4f(vec3f((material * (lacc + (lacc >> {}))) >> {}) / 255.0, 1.0)", shift7, - shift8); - return fmt::format(R"""( - {{ - var lighting = {11}(round({5}{8} * 255.0)); - for (var i = 0u; i < {1}u; i++) {{ - if ((ubuf.lightState{0}{9} & (1u << i)) == 0u) {{ continue; }} - var light = ubuf.lights[i];{10} - var attn: f32;{2} - var diff = {3}; - lighting = lighting + {11}(round(attn * diff * light.color{8} * 255.0)); - }} - let lacc = clamp(lighting, {13}, {14}); - let material = {11}(round({4}{8} * 255.0)); - {15} = {16}; - }})""", - i, GX::MaxLights, lightAttnFn, lightDiffFn, matSrc, ambSrc, posVar, outVar, swizzle, - alpha ? "a"sv : ""sv, lightDirSetup, intType, floatType, intZero, intMax, outputTarget, - outputValue); -} - -wgpu::ShaderModule build_shader(const ShaderConfig& config) noexcept { - ZoneScoped; - const auto hash = xxh3_hash(config); - const auto info = build_shader_info(config); - - std::string uniformPre; - std::string uniBufAttrs; - std::string texBindings; - std::string vtxOutAttrs; - std::string vtxInAttrs; - std::string vtxXfrAttrsPre; - std::string vtxXfrAttrs; - size_t vtxOutIdx = 0; - - // Load points for line/point expansion - std::string_view vidxAttr = "vidx"sv; - if (config.lineMode != 0) { - vtxInAttrs += ",\n @builtin(instance_index) iidx: u32"; - uniBufAttrs += - "\n line_width: f32," - "\n line_aspect_y: f32," - "\n line_tex_offset: f32," - "\n line_texcoord_mask: u32,"; - if (config.lineMode == 3) { - // GX_POINTS: each instance = one vertex, expand to quad - vtxXfrAttrsPre += fmt::format( - "\n let in_vidx = iidx;" - "\n let in_pos = {};" - "\n let in_pnmtxidx = {};" - "\n let mv_pos = vec4f(in_pos, 1.0) * ubuf.postex_mtx[in_pnmtxidx];", - attr_load(config, GX_VA_POS, "in_vidx"sv), attr_load(config, GX_VA_PNMTXIDX, "in_vidx"sv)); - } else { - // GX_LINES / GX_LINESTRIP: each instance = two vertices, expand to quad - vtxXfrAttrsPre += fmt::format( - "\n let use_b = vidx >= 2u;" - "\n let vidx_a = iidx * {}u;" - "\n let vidx_b = vidx_a + 1u;" - "\n let in_vidx = select(vidx_a, vidx_b, use_b);" - "\n let pos_a = {};" - "\n let pos_b = {};" - "\n let in_pos = select(pos_a, pos_b, use_b);" - "\n let pnmtxidx_a = {};" - "\n let pnmtxidx_b = {};" - "\n let in_pnmtxidx = select(pnmtxidx_a, pnmtxidx_b, use_b);" - "\n let mv_pos_a = vec4f(pos_a, 1.0) * ubuf.postex_mtx[pnmtxidx_a];" - "\n let mv_pos_b = vec4f(pos_b, 1.0) * ubuf.postex_mtx[pnmtxidx_b];" - "\n let mv_pos = select(mv_pos_a, mv_pos_b, use_b);", - config.lineMode == 1 ? 2 : 1, attr_load(config, GX_VA_POS, "vidx_a"sv), - attr_load(config, GX_VA_POS, "vidx_b"sv), attr_load(config, GX_VA_PNMTXIDX, "vidx_a"sv), - attr_load(config, GX_VA_PNMTXIDX, "vidx_b"sv)); - } - vidxAttr = "in_vidx"sv; - } else if (config.attrs[GX_VA_PNMTXIDX].attrType == GX_NONE) { - vtxXfrAttrsPre += "\n let in_pnmtxidx = ubuf.current_pnmtx;"; - } - - // Load vertex attributes - for (GXAttr attr = GX_VA_PNMTXIDX; attr <= GX_VA_TEX7; attr = static_cast(attr + 1)) { - const auto attrType = config.attrs[attr].attrType; - if (attrType == GX_NONE) { - continue; - } - // in_pnmtxidx and in_pos written above for line mode - if ((attr != GX_VA_PNMTXIDX && attr != GX_VA_POS) || config.lineMode == 0) { - vtxXfrAttrsPre += fmt::format("\n let {} = {};", vtx_attr(config, attr), attr_load(config, attr, vidxAttr)); - } - } - - if (config.lineMode == 0) { - vtxXfrAttrsPre += fmt::format( - "\n let mv_pos = vec4f({}, 1.0) * ubuf.postex_mtx[in_pnmtxidx];" - "\n out.pos = vec4f(mv_pos, 1.0) * ubuf.proj;", - vtx_attr(config, GX_VA_POS)); - } else if (config.lineMode == 3) { - // GX_POINTS: expand single vertex to axis-aligned screen-space square - vtxXfrAttrsPre += - "\n let clip = vec4f(mv_pos, 1.0) * ubuf.proj;" - "\n let viewport_scale = ubuf.render_viewport_size / max(ubuf.logical_viewport_size, vec2f(1.0));" - "\n let point_size = ubuf.line_width * min(viewport_scale.x, viewport_scale.y);" - "\n let x_sign = select(-1.0, 1.0, (vidx & 1u) != 0u);" - "\n let y_sign = select(-1.0, 1.0, vidx >= 2u);" - "\n let offset_px = vec2f(x_sign, y_sign) * (point_size / 2.0);" - "\n let offset_ndc = (offset_px * 2.0) / ubuf.render_viewport_size;" - "\n out.pos = vec4f(clip.xy + offset_ndc * clip.w, clip.zw);"; - } else { - // GX_LINES / GX_LINESTRIP: expand line segment perpendicular to direction - vtxXfrAttrsPre += - "\n let clip_a = vec4f(mv_pos_a, 1.0) * ubuf.proj;" - "\n let clip_b = vec4f(mv_pos_b, 1.0) * ubuf.proj;" - "\n let ndc_a = clip_a.xy / clip_a.w;" - "\n let ndc_b = clip_b.xy / clip_b.w;" - "\n let viewport_scale = ubuf.render_viewport_size / max(ubuf.logical_viewport_size, vec2f(1.0));" - "\n let delta_px = (ndc_b - ndc_a) / 2.0 * ubuf.render_viewport_size;" - "\n let dir_px = select(vec2f(1.0, 0.0), normalize(delta_px), dot(delta_px, delta_px) > 1e-10);" - "\n let perp_px = vec2f(-dir_px.y, dir_px.x);" - "\n let line_width = ubuf.line_width * min(viewport_scale.x, viewport_scale.y);" - "\n let offset_px = perp_px * (line_width / 2.0) * select(-1.0, 1.0, (vidx & 1u) != 0u);" - "\n let offset_ndc = (offset_px * 2.0) / ubuf.render_viewport_size;" - "\n let clip_base = select(clip_a, clip_b, use_b);" - "\n out.pos = vec4f(clip_base.xy + offset_ndc * clip_base.w, clip_base.zw);"; - } - // The near/far depth correction used to be applied here per-vertex (out.pos.z = -out.pos.z for - // reversed, or += out.pos.w for forward), redundantly on top of the same correction already - // folded into ubuf.proj by effective_projection() (shader_info.cpp) - applying it twice canceled - // out for the common case (any draw where effective_projection() decides to flip), silently - // making "reversed" Z behave identically to forward Z. It is now applied exactly once, in the - // projection matrix alone (matching upstream aurora commit 1dde08fa: "Move depth correction to - // projection matrix"), so nothing needs to happen to out.pos.z here. - // GX rasterizes at a 7/12 pixel center when antialiasing is disabled, while WebGPU rasterizes at 1/2. - vtxXfrAttrsPre += - "\n let gx_pixel_center_correction = " - "vec2f(-1.0, 1.0) / (6.0 * max(abs(ubuf.render_viewport_size), vec2f(1.0)));" - "\n out.pos = vec4f(out.pos.xy + out.pos.w * gx_pixel_center_correction, out.pos.zw);"; - vtxXfrAttrsPre += fmt::format( - "\n let nrm_tmp = vec4f({}, 0.0) * ubuf.nrm_mtx[in_pnmtxidx];" - "\n let mv_nrm = select(nrm_tmp, normalize(nrm_tmp), dot(nrm_tmp, nrm_tmp) > 1e-10);", - vtx_attr(config, GX_VA_NRM)); - - uniBufAttrs += "\n proj: mat4x4f,"; - // Only the matrix slots this shader can read are uploaded, in compacted order; see UniformMatrixLayout. - uniBufAttrs += fmt::format("\n postex_mtx: array,", info.matrixLayout.postexCount); - uniBufAttrs += fmt::format("\n nrm_mtx: array,", info.matrixLayout.nrmCount); - std::string fragmentFnPre; - std::string fragmentFn; - const int zTexStage = tev_z_texture_stage(config); - const bool usesZTextureDepth = tev_z_texture_enabled(config); - std::array emittedFixedTexCoord{}; - const auto fixed_texcoord_name = [&](u32 texCoordId) { - if (!emittedFixedTexCoord[texCoordId]) { - fragmentFnPre += fmt::format( - "\n let tex{0}_fixed_uv = vec2i(tex{0}_uv * ubuf.texcoord{0}_scale.xy * 128.0);", texCoordId); - emittedFixedTexCoord[texCoordId] = true; - } - return fmt::format("tex{}_fixed_uv", texCoordId); - }; - - static std::array regName{"prev"sv, "tevreg0"sv, "tevreg1"sv, "tevreg2"sv}; - for (u32 idx = 0; idx < config.tevStageCount; ++idx) { - const auto& stage = config.tevStages[idx]; - std::string colorA = color_arg_reg(stage.colorPass.a, idx, config, stage); - std::string colorB = color_arg_reg(stage.colorPass.b, idx, config, stage); - fragmentFn += fmt::format("\n // TEV stage {}", idx); - if (alpha_compare_uses_color_inputs(stage.alphaOp.op)) { - const std::string colorAName = fmt::format("tev_stage{}_color_a", idx); - const std::string colorBName = fmt::format("tev_stage{}_color_b", idx); - // The color result is emitted before the alpha result below. - fragmentFn += fmt::format("\n let {0} = {1};\n let {2} = {3};", colorAName, colorA, colorBName, colorB); - colorA = colorAName; - colorB = colorBName; - } - { - std::string_view outReg = regName[stage.colorOp.outReg]; - std::string op = tev_color_op( - stage.colorOp.op, stage.colorOp.bias, stage.colorOp.scale, stage.colorOp.clamp, colorA, colorB, - color_arg_reg(stage.colorPass.c, idx, config, stage), color_arg_reg(stage.colorPass.d, idx, config, stage)); - fragmentFn += fmt::format("\n {0} = vec4f({1}, {0}.a);", outReg, op); - } - { - std::string_view outReg = regName[stage.alphaOp.outReg]; - std::string op = tev_alpha_op( - stage.alphaOp.op, stage.alphaOp.bias, stage.alphaOp.scale, stage.alphaOp.clamp, - alpha_arg_reg(stage.alphaPass.a, idx, config, stage), alpha_arg_reg(stage.alphaPass.b, idx, config, stage), - alpha_arg_reg(stage.alphaPass.c, idx, config, stage), alpha_arg_reg(stage.alphaPass.d, idx, config, stage), - colorA, colorB); - fragmentFn += fmt::format("\n {0}.a = {1};", outReg, op); - } - } - - { - const auto& lastStage = config.tevStages[config.tevStageCount - 1]; - if (lastStage.colorOp.outReg != 0) { - fragmentFn += fmt::format("\n prev = vec4f({0}.rgb, prev.a);", regName[lastStage.colorOp.outReg]); - } - if (lastStage.alphaOp.outReg != 0) { - fragmentFn += fmt::format("\n prev.a = {0}.a;", regName[lastStage.alphaOp.outReg]); - } - } - - const auto loadsTevRegs = info.loadsTevRegRgb | info.loadsTevRegAlpha; - const auto writesTevRegs = info.writesTevRegRgb | info.writesTevRegAlpha; - if (loadsTevRegs.test(0)) { - uniBufAttrs += "\n tevprev: vec4f,"; - fragmentFnPre += "\n var prev = ubuf.tevprev;"; - } else { - fragmentFnPre += "\n var prev: vec4f;"; - } - for (int i = 1 /* Skip TEVPREV */; i < loadsTevRegs.size(); ++i) { - if (loadsTevRegs.test(i)) { - uniBufAttrs += fmt::format("\n tevreg{}: vec4f,", i - 1); - fragmentFnPre += fmt::format("\n var tevreg{0} = ubuf.tevreg{0};", i - 1); - } else if (writesTevRegs.test(i)) { - fragmentFnPre += fmt::format("\n var tevreg{0}: vec4f;", i - 1); - } - } - - if (info.lightingEnabled) { - uniBufAttrs += fmt::format(FMT_STRING(R"""( - lights: array, - lightState0: u32, - lightState1: u32, - lightState0a: u32, - lightState1a: u32,)"""), - GX::MaxLights); - uniformPre += - "\n" - "struct Light {\n" - " pos: vec3f,\n" - " dir: vec3f,\n" - " color: vec4f,\n" - " cos_att: vec3f,\n" - " dist_att: vec3f,\n" - "};"; - if (UsePerPixelLighting) { - vtxOutAttrs += fmt::format("\n @location({}) mv_pos: vec3f,", vtxOutIdx++); - vtxOutAttrs += fmt::format("\n @location({}) mv_nrm: vec3f,", vtxOutIdx++); - vtxXfrAttrs += fmt::format(FMT_STRING(R"""( - out.mv_pos = mv_pos; - out.mv_nrm = mv_nrm;)""")); - } - } - - for (int i = 0; i < info.sampledColorChannels.size(); ++i) { - if (!info.sampledColorChannels.test(i)) { - continue; - } - - const auto& cc = config.colorChannels[i]; - const auto& cca = config.colorChannels[i + GX_ALPHA0]; - if (cc.lightingEnabled && cc.ambSrc == GX_SRC_REG) { - uniBufAttrs += fmt::format("\n cc{0}_amb: vec4f,", i); - } - if (cc.matSrc == GX_SRC_REG) { - uniBufAttrs += fmt::format("\n cc{0}_mat: vec4f,", i); - } - if (cca.lightingEnabled && cca.ambSrc == GX_SRC_REG) { - uniBufAttrs += fmt::format("\n cc{0}a_amb: vec4f,", i); - } - if (cca.matSrc == GX_SRC_REG) { - uniBufAttrs += fmt::format("\n cc{0}a_mat: vec4f,", i); - } - - // Output vertex color if necessary - if (UsePerPixelLighting) { - if ((cc.lightingEnabled && cc.ambSrc == GX_SRC_VTX) || cc.matSrc == GX_SRC_VTX || - (cca.lightingEnabled && cca.ambSrc == GX_SRC_VTX) || cca.matSrc == GX_SRC_VTX) { - vtxOutAttrs += fmt::format("\n @location({}) clr{}: vec4f,", vtxOutIdx++, i); - vtxXfrAttrs += fmt::format("\n out.clr{} = {};", i, vertex_color_attr(config, i)); - } - } - - if (UsePerPixelLighting) { - fragmentFnPre += fmt::format("\n var rast{}: vec4f;", i); - fragmentFnPre += lighting_func(config, cc, i, false); - fragmentFnPre += lighting_func(config, cca, i, true); - } else { - vtxOutAttrs += fmt::format("\n @location({}) cc{}: vec4f,", vtxOutIdx++, i); - vtxXfrAttrs += lighting_func(config, cc, i, false); - vtxXfrAttrs += lighting_func(config, cca, i, true); - fragmentFnPre += fmt::format("\n var rast{0} = in.cc{0};", i); - } - } - for (int i = 0; i < info.sampledKColors.size(); ++i) { - if (info.sampledKColors.test(i)) { - uniBufAttrs += fmt::format("\n kcolor{}: vec4f,", i); - } - } - for (int i = 0; i < info.sampledTexCoords.size(); ++i) { - if (!info.sampledTexCoords.test(i)) { - continue; - } - const auto& tcg = config.tcgs[i]; - if (tcg.type == GX_TG_MTX3x4) { - vtxOutAttrs += fmt::format("\n @location({}) tex{}_uvw: vec3f,", vtxOutIdx++, i); - } else { - vtxOutAttrs += fmt::format("\n @location({}) tex{}_uv: vec2f,", vtxOutIdx++, i); - } - if (tcg.src >= GX_TG_TEX0 && tcg.src <= GX_TG_TEX7) { - vtxXfrAttrs += fmt::format("\n var tc{} = vec4f({}, 1.0, 1.0);", i, - vtx_attr(config, GXAttr(GX_VA_TEX0 + (tcg.src - GX_TG_TEX0)))); - } else if (tcg.src == GX_MAX_TEXGENSRC) { - vtxXfrAttrs += fmt::format("\n var tc{} = vec4f({}, 1.0, 1.0);", i, - vtx_attr(config, GXAttr(GX_VA_TEX0 + i))); - } else if (tcg.src == GX_TG_POS) { - vtxXfrAttrs += fmt::format("\n var tc{} = vec4f({}, 1.0);", i, vtx_attr(config, GX_VA_POS)); - } else if (tcg.src == GX_TG_NRM) { - vtxXfrAttrs += fmt::format("\n var tc{} = vec4f({}, 1.0);", i, vtx_attr(config, GX_VA_NRM)); - } else if (tcg.src == GX_TG_BINRM) { - // GX source row 3 is Dolphin's tangent group in NBT normal arrays. - vtxXfrAttrs += fmt::format("\n var tc{} = vec4f({}, 1.0);", i, normal_group_load(config, 1, vidxAttr)); - } else if (tcg.src == GX_TG_TANGENT) { - // GX source row 4 is Dolphin's binormal group in NBT normal arrays. - vtxXfrAttrs += fmt::format("\n var tc{} = vec4f({}, 1.0);", i, normal_group_load(config, 2, vidxAttr)); - } else if (tcg.src == GX_TG_COLOR0) { - vtxXfrAttrs += fmt::format("\n var tc{} = vec4f({}.rgb, 1.0);", i, vtx_attr(config, GX_VA_CLR0)); - } else if (tcg.src == GX_TG_COLOR1) { - vtxXfrAttrs += fmt::format("\n var tc{} = vec4f({}.rgb, 1.0);", i, vtx_attr(config, GX_VA_CLR1)); - } else - UNLIKELY FATAL("unhandled tcg src {}", underlying(tcg.src)); - if (tcg.inputFormAB11) { - vtxXfrAttrs += fmt::format("\n tc{}.z = 1.0;", i); - } - if (tcg.type == GX_TG_MTX2x4 || tcg.type == GX_TG_MTX3x4) { - if (info.indexAttr.test(GX_VA_TEX0MTXIDX + i)) { - vtxXfrAttrs += fmt::format("\n var tc{0}_tmp = tc{0} * ubuf.postex_mtx[in_texmtxidx{0} / 3u];", i); - } else if (tcg.mtx == GX_IDENTITY) { - vtxXfrAttrs += fmt::format("\n var tc{0}_tmp = tc{0}.xyz;", i); - } else { - const u32 texMtxSlot = (tcg.mtx) / 3; - const u32 texMtxIdx = texMtxSlot < MaxPostexMtx ? info.matrixLayout.postexRemap[texMtxSlot] - : texMtxSlot; - CHECK(texMtxIdx != UniformMatrixLayout::kAbsent, - "texgen {} matrix slot {} missing from the uniform layout", i, texMtxSlot); - vtxXfrAttrs += fmt::format("\n var tc{0}_tmp = tc{0} * ubuf.postex_mtx[{1}];", i, texMtxIdx); - } - if (tcg.type == GX_TG_MTX2x4) { - vtxXfrAttrs += fmt::format("\n tc{0}_tmp.z = 1.0f;", i); - } - } else if (tcg.type == GX_TG_SRTG) { - vtxXfrAttrs += fmt::format("\n var tc{0}_tmp = vec3f(tc{0}.xy, 1.0f);", i); - } - if (config.dualTexEnabled && tcg.normalize) { - vtxXfrAttrs += fmt::format("\n tc{0}_tmp = normalize(tc{0}_tmp);", i); - } - if (!config.dualTexEnabled || tcg.postMtx == GX_PTIDENTITY) { - vtxXfrAttrs += fmt::format("\n var tc{0}_proj = tc{0}_tmp;", i); - } else { - u32 postMtxIdx = (tcg.postMtx - GX_PTTEXMTX0) / 3; - vtxXfrAttrs += - fmt::format("\n var tc{0}_proj = vec4f(tc{0}_tmp.xyz, 1.0) * ubuf.postmtx[{1}];", i, postMtxIdx); - } - if (tcg.type == GX_TG_MTX2x4 || tcg.type == GX_TG_MTX3x4) { - vtxXfrAttrs += fmt::format( - "\n if (tc{0}_proj.z == 0.0) {{" - "\n tc{0}_proj.x = clamp(tc{0}_proj.x / 2.0, -1.0, 1.0);" - "\n tc{0}_proj.y = clamp(tc{0}_proj.y / 2.0, -1.0, 1.0);" - "\n }}", - i); - } - // Apply line/point tex offset - if (config.lineMode == 3) { - // GX_POINTS: offset S for right columns, T for bottom rows - vtxXfrAttrs += fmt::format( - "\n if ((ubuf.line_texcoord_mask & (1u << {0})) != 0u) {{" - "\n if ((vidx & 1u) != 0u) {{ tc{0}_proj.x += ubuf.line_tex_offset; }}" - "\n if (vidx >= 2u) {{ tc{0}_proj.y += ubuf.line_tex_offset; }}" - "\n }}", - i); - } else if (config.lineMode != 0) { - // GX_LINES / GX_LINESTRIP: offset one axis for perpendicular side - vtxXfrAttrs += fmt::format( - "\n if ((ubuf.line_texcoord_mask & (1u << {0})) != 0u && (vidx & 1u) != 0u) {{" - "\n tc{0}_proj.y += ubuf.line_tex_offset;" - "\n }}", - i); - } - if (tcg.type == GX_TG_MTX3x4) { - vtxXfrAttrs += fmt::format("\n out.tex{0}_uvw = tc{0}_proj.xyz;", i); - fragmentFnPre += fmt::format( - "\n var tex{0}_uv = in.tex{0}_uvw.xy;" - "\n if (in.tex{0}_uvw.z != 0.0) {{" - "\n tex{0}_uv = in.tex{0}_uvw.xy / in.tex{0}_uvw.z;" - "\n }}", - i); - } else { - vtxXfrAttrs += fmt::format("\n out.tex{0}_uv = tc{0}_proj.xy;", i); - fragmentFnPre += fmt::format("\n var tex{0}_uv = in.tex{0}_uv.xy;", i); - } - } - // Multiple TEV stages may reference the same indirect stage, - // so we sample each indirect texture only once. - const auto ind_scale_shift = [](const GXIndTexScale s) -> u32 { - switch (s) { - case GX_ITS_1: - return 0; - case GX_ITS_2: - return 1; - case GX_ITS_4: - return 2; - case GX_ITS_8: - return 3; - case GX_ITS_16: - return 4; - case GX_ITS_32: - return 5; - case GX_ITS_64: - return 6; - case GX_ITS_128: - return 7; - case GX_ITS_256: - return 8; - default: - FATAL("unhandled indirect scale {}", underlying(s)); - } - }; - for (int i = 0; i < info.usedIndStages.size(); ++i) { - if (!info.usedIndStages.test(i)) { - continue; - } - const auto& indStage = config.indStages[i]; - const int effectiveIndTexCoord = tev_effective_texcoord(config, indStage.texCoordId); - const std::string indFixedUv = - effectiveIndTexCoord >= 0 ? fixed_texcoord_name(static_cast(effectiveIndTexCoord)) : "vec2i(0)"; - fragmentFnPre += fmt::format( - "\n // Indirect stage {0}" - "\n let ind{0}_sample_fixed = {5} >> vec2u({3}u, {4}u);" - "\n let t_IndTexCoord{0} = tev_byte_vec3f(textureSampleBias(tex{2}, tex{2}_samp, " - "vec2f(ind{0}_sample_fixed) / (ubuf.tex{2}_size_bias.xy * 128.0), ubuf.tex{2}_size_bias.z).abg);", - i, effectiveIndTexCoord, underlying(indStage.texMapId), ind_scale_shift(indStage.scaleS), - ind_scale_shift(indStage.scaleT), indFixedUv); - } - const bool usesFixedTexcoordState = shader_uses_fixed_texcoord_state(config); - if (usesFixedTexcoordState) { - fragmentFnPre += "\n var t_TexCoord = vec2i(0);"; - } - for (int i = 0; i < config.tevStageCount; ++i) { - const auto& stage = config.tevStages[i]; - const auto textureDependency = tev_stage_texture_dependency(config, static_cast(i)); - const bool needsIndirectCoord = stage.indTexMtxId != GX_ITM_OFF; - const bool hasIndirectStage = stage.indTexStage < config.numIndStages; - const bool needsTevTexCoord = textureDependency.needsFixedTexcoordState; - const bool needsTextureSample = textureDependency.combinerUsesTexture || static_cast(i) == zTexStage; - const bool willSampleTexture = tev_texture_sample_enabled(textureDependency, needsTextureSample); - if (!needsTevTexCoord && !needsTextureSample) { - continue; - } - const bool hasBaseCoord = textureDependency.texCoordId >= 0; - std::string uvIn; - if (needsTevTexCoord) { - fragmentFnPre += fmt::format("\n // TEV stage {} indirect", i); - - // Apply indirect texture matrix (produces an S17.7 fixed-point offset). - std::string indirectOffsetFixed; - if (needsIndirectCoord && hasIndirectStage) { - u32 fmtShift = 0; - switch (stage.indTexFormat) { - case GX_ITF_8: - break; - case GX_ITF_5: - fmtShift = 3; - break; - case GX_ITF_4: - fmtShift = 4; - break; - case GX_ITF_3: - fmtShift = 5; - break; - default: - FATAL("unhandled indirect format {}", underlying(stage.indTexFormat)); - } - if (fmtShift == 0) { - fragmentFnPre += fmt::format("\n var ind{0}_coord = t_IndTexCoord{1};", i, underlying(stage.indTexStage)); - } else { - fragmentFnPre += fmt::format("\n var ind{0}_coord = t_IndTexCoord{1} >> vec3u({2}u);", i, - underlying(stage.indTexStage), fmtShift); - } - - if (stage.indTexBiasSel != GX_ITB_NONE) { - auto bias = stage.indTexFormat == GX_ITF_8 ? "-128"sv : "1"sv; - auto biasS = "0"sv, biasT = "0"sv, biasU = "0"sv; - if (stage.indTexBiasSel == GX_ITB_S || stage.indTexBiasSel == GX_ITB_ST || stage.indTexBiasSel == GX_ITB_SU || - stage.indTexBiasSel == GX_ITB_STU) { - biasS = "1"sv; - } - if (stage.indTexBiasSel == GX_ITB_T || stage.indTexBiasSel == GX_ITB_ST || stage.indTexBiasSel == GX_ITB_TU || - stage.indTexBiasSel == GX_ITB_STU) { - biasT = "1"sv; - } - if (stage.indTexBiasSel == GX_ITB_U || stage.indTexBiasSel == GX_ITB_SU || stage.indTexBiasSel == GX_ITB_TU || - stage.indTexBiasSel == GX_ITB_STU) { - biasU = "1"sv; - } - fragmentFnPre += fmt::format("\n ind{0}_coord = ind{0}_coord + vec3i({1}, {2}, {3}) * {4};", i, biasS, - biasT, biasU, bias); - } - - const auto appendScaleShift = [&](u32 mtxIdx) { - fragmentFnPre += fmt::format( - "\n let ind{0}_shift = ubuf.ind_mtx[{1}].z;" - "\n if (ind{0}_shift >= 0) {{" - "\n ind{0}_offset_fixed = ind{0}_offset_fixed >> vec2u(u32(ind{0}_shift));" - "\n }} else {{" - "\n ind{0}_offset_fixed = ind{0}_offset_fixed << vec2u(u32(-ind{0}_shift));" - "\n }}", - i, mtxIdx * 2 + 1); - indirectOffsetFixed = fmt::format("ind{}_offset_fixed", i); - }; - - if (stage.indTexMtxId >= GX_ITM_0 && stage.indTexMtxId <= GX_ITM_2) { - // Static 2x3 matrix: integer dot products, then the hardware's fixed >>3 and exponent shift sequence. - u32 mtxIdx = stage.indTexMtxId - GX_ITM_0; - fragmentFnPre += fmt::format( - "\n let ind{0}_c0 = ubuf.ind_mtx[{1}];" - "\n let ind{0}_c1 = ubuf.ind_mtx[{2}];" - "\n var ind{0}_offset_fixed = vec2i(" - "\n (ind{0}_c0.x * ind{0}_coord.x + ind{0}_c0.z * ind{0}_coord.y + " - "ind{0}_c1.x * ind{0}_coord.z) >> 3u," - "\n (ind{0}_c0.y * ind{0}_coord.x + ind{0}_c0.w * ind{0}_coord.y + " - "ind{0}_c1.y * ind{0}_coord.z) >> 3u);", - i, mtxIdx * 2, mtxIdx * 2 + 1); - appendScaleShift(mtxIdx); - } else if (stage.indTexMtxId >= GX_ITM_S0 && stage.indTexMtxId <= GX_ITM_S2 && hasBaseCoord) { - // Dynamic S: (fixed UV * indirect S) >> 8, then exponent shift. - u32 mtxIdx = stage.indTexMtxId - GX_ITM_S0; - u32 regTexCoord = static_cast(textureDependency.texCoordId); - const auto fixedUv = fixed_texcoord_name(regTexCoord); - fragmentFnPre += fmt::format( - "\n var ind{0}_offset_fixed = ({1} * vec2i(ind{0}_coord.x)) >> vec2u(8u);", i, fixedUv); - appendScaleShift(mtxIdx); - } else if (stage.indTexMtxId >= GX_ITM_T0 && stage.indTexMtxId <= GX_ITM_T2 && hasBaseCoord) { - // Dynamic T: (fixed UV * indirect T) >> 8, then exponent shift. - u32 mtxIdx = stage.indTexMtxId - GX_ITM_T0; - u32 regTexCoord = static_cast(textureDependency.texCoordId); - const auto fixedUv = fixed_texcoord_name(regTexCoord); - fragmentFnPre += fmt::format( - "\n var ind{0}_offset_fixed = ({1} * vec2i(ind{0}_coord.y)) >> vec2u(8u);", i, fixedUv); - appendScaleShift(mtxIdx); - } - } - - // Wrap base coord and combine with the indirect translation. - auto wrap_comp = [](GXIndTexWrap wrap, std::string&& coord) -> std::string { - const int mask = tev_indirect_wrap_mask(wrap); - if (mask == -1) { - return std::move(coord); - } - if (mask == 0) { - return "0"; - } - CHECK(mask > 0, "invalid indirect wrap {}", underlying(wrap)); - return fmt::format("({} & {})", coord, mask); - }; - std::string baseCoordExpr = "vec2i(0)"; - if (hasBaseCoord) { - u32 texCoordId = static_cast(textureDependency.texCoordId); - baseCoordExpr = fixed_texcoord_name(texCoordId); - } - const std::string wrappedExpr = - fmt::format("vec2i({}, {})", wrap_comp(stage.indTexWrapS, fmt::format("{}.x", baseCoordExpr)), - wrap_comp(stage.indTexWrapT, fmt::format("{}.y", baseCoordExpr))); - std::string finalCoord = wrappedExpr; - if (!indirectOffsetFixed.empty()) { - finalCoord = fmt::format("{} + ({})", wrappedExpr, indirectOffsetFixed); - } - - if (usesFixedTexcoordState) { - if (stage.indTexAddPrev) { - fragmentFnPre += fmt::format("\n t_TexCoord += {};", finalCoord); - } else { - fragmentFnPre += fmt::format("\n t_TexCoord = {};", finalCoord); - } - fragmentFnPre += "\n t_TexCoord = tev_s24_fixed_vec2i(t_TexCoord);"; - - // ShaderInfo only emits texN_size_bias and texture bindings for a texture that can actually be sampled. - if (willSampleTexture) { - u32 texMapId = static_cast(textureDependency.texMapId); - fragmentFnPre += fmt::format( - "\n var ind{0}_uv = vec2f(t_TexCoord) / (ubuf.tex{1}_size_bias.xy * 128.0);", i, texMapId); - uvIn = fmt::format("ind{0}_uv", i); - } - } - } - if (!willSampleTexture) { - continue; - } - if (uvIn.empty()) { - // No indirect texturing - const auto fixedUv = fixed_texcoord_name(static_cast(textureDependency.texCoordId)); - uvIn = fmt::format("vec2f(tev_s24_fixed_vec2i({0})) / (ubuf.tex{1}_size_bias.xy * 128.0)", fixedUv, - textureDependency.texMapId); - } - fragmentFnPre += - fmt::format("\n var sampled{0} = textureSampleBias(tex{1}, tex{1}_samp, {2}, ubuf.tex{1}_size_bias.z);", i, - textureDependency.texMapId, uvIn); - } - - // in.pos.z is the host NDC z (forward: 0=near/1=far; reversed: 1=near/0=far post-fix), but this - // expression needs to produce GX's own native distance term (always 0=near/1=far, matching how - // g_gxState.clearDepth/clear_depth_value() are interpreted before their own UseReversedZ - // inversion) - forward already matches directly; reversed needs the same 1-x flip everything - // else reversed-Z-aware uses. This was backwards (verified directly against upstream aurora's - // identical expression in build_shader_source), which fed both fog density and the GX_ZT_ADD - // z-texture path the wrong distance value. - std::string fogDepthExpr = UseReversedZ ? "(1.0 - in.pos.z)" : "in.pos.z"; - std::string fogZCoordExpr = - fmt::format("u32(round(clamp({}, 0.0, 1.0) * 16777216.0))", fogDepthExpr); - if (usesZTextureDepth) { - const u32 zTexBias = config.zTexture & 0x00FFFFFFu; - const u32 zTexFmt = (config.zTexture >> 24) & 0x3u; - const u32 zTexOp = (config.zTexture >> 26) & 0x3u; - const std::string zTexSample = zTexStage >= 0 ? fmt::format("sampled{}", zTexStage) : "vec4f(0.0)"; - - fragmentFn += fmt::format( - "\n // Z texture" - "\n let ztexSample = clamp({0}, vec4f(0.0), vec4f(1.0)) * 255.0;" - "\n let ztexRaw = vec4u(round(ztexSample));", - zTexSample); - switch (zTexFmt) { - case 0: - fragmentFn += fmt::format("\n var ztexCoord = ({0}u + ztexRaw.a) & 0x00ffffffu;", zTexBias); - break; - case 1: - fragmentFn += - fmt::format("\n var ztexCoord = ({0}u + ((ztexRaw.a << 8u) | ztexRaw.r)) & 0x00ffffffu;", zTexBias); - break; - case 2: - default: - fragmentFn += fmt::format( - "\n var ztexCoord = ({0}u + ((ztexRaw.r << 16u) | (ztexRaw.g << 8u) | ztexRaw.b)) & 0x00ffffffu;", - zTexBias); - break; - } - if (zTexOp == GX_ZT_ADD) { - fragmentFn += fmt::format( - "\n let oldZ = u32(round(clamp({0}, 0.0, 1.0) * 16777216.0));" - "\n ztexCoord = (ztexCoord + oldZ) & 0x00ffffffu;", - UseReversedZ ? "(1.0 - in.pos.z)" : "in.pos.z"); - } - fragmentFn += "\n let ztexDepth = f32(ztexCoord) / 16777216.0;"; - fogZCoordExpr = "ztexCoord"; - } - - if (info.usesPTTexMtx.any()) - uniBufAttrs += fmt::format("\n postmtx: array,", MaxPTTexMtx); - if (info.usesFog) { - uniformPre += - "\n" - "struct Fog {\n" - " color: vec4f,\n" - " a: f32,\n" - " b: f32,\n" - " c: f32,\n" - " pad: f32,\n" - " range_base: vec4f,\n" - " range_k: array,\n" - "}"; - uniBufAttrs += "\n fog: Fog,"; - - if ((config.fogType & 0x8u) == 0) { - fragmentFn += fmt::format( - "\n // Fog" - "\n let fogZCoord = {};" - "\n let fogShiftedZ = fogZCoord >> u32(ubuf.fog.pad);" - "\n var fogZe = (ubuf.fog.a * 16777216.0) / (ubuf.fog.b - f32(fogShiftedZ));", - fogZCoordExpr); - } else { - fragmentFn += fmt::format( - "\n // Fog" - "\n let fogZCoord = {};" - "\n var fogZe = ubuf.fog.a * f32(fogZCoord) / 16777216.0;", - fogZCoordExpr); - } - if (config.fogRangeAdjust) { - fragmentFn += - "\n let fogRangeOffset = (2.0 * (in.pos.x / ubuf.fog.range_base.y)) - 1.0 - ubuf.fog.range_base.x;" - "\n let fogRangeFloatIndex = clamp(9.0 - abs(fogRangeOffset) * 9.0, 0.0, 9.0);" - "\n let fogRangeIndexLower = u32(fogRangeFloatIndex);" - "\n let fogRangeIndexUpper = fogRangeIndexLower + 1u;" - "\n let fogRangeKLower = ubuf.fog.range_k[fogRangeIndexLower >> 2u][fogRangeIndexLower & 3u];" - "\n let fogRangeKUpper = ubuf.fog.range_k[fogRangeIndexUpper >> 2u][fogRangeIndexUpper & 3u];" - "\n let fogRangeK = mix(fogRangeKLower, fogRangeKUpper, fract(fogRangeFloatIndex));" - "\n fogZe *= sqrt(fogRangeOffset * fogRangeOffset + fogRangeK * fogRangeK) / fogRangeK;"; - } - fragmentFn += "\n var fogF = clamp(fogZe - ubuf.fog.c, 0.0, 1.0);"; - switch (config.fogType) { - DEFAULT_FATAL("invalid fog type {}", config.fogType); - case static_cast(1): - case static_cast(3): - case GX_FOG_PERSP_LIN: - case static_cast(9): - case static_cast(11): - case GX_FOG_ORTHO_LIN: - fragmentFn += "\n var fogZ = fogF;"; - break; - case GX_FOG_PERSP_EXP: - case GX_FOG_ORTHO_EXP: - fragmentFn += "\n var fogZ = 1.0 - exp2(-8.0 * fogF);"; - break; - case GX_FOG_PERSP_EXP2: - case GX_FOG_ORTHO_EXP2: - fragmentFn += "\n var fogZ = 1.0 - exp2(-8.0 * fogF * fogF);"; - break; - case GX_FOG_PERSP_REVEXP: - case GX_FOG_ORTHO_REVEXP: - fragmentFn += "\n var fogZ = exp2(-8.0 * (1.0 - fogF));"; - break; - case GX_FOG_PERSP_REVEXP2: - case GX_FOG_ORTHO_REVEXP2: - fragmentFn += - "\n fogF = 1.0 - fogF;" - "\n var fogZ = exp2(-8.0 * fogF * fogF);"; - break; - } - fragmentFn += "\n prev = vec4f(mix(prev.rgb, ubuf.fog.color.rgb, clamp(fogZ, 0.0, 1.0)), prev.a);"; - } - if (info.usedIndTexMtxs.any()) { - uniBufAttrs += "\n ind_mtx: array,"; - } - for (int i = 0; i < info.sampledTexCoords.size(); ++i) { - if (info.sampledTexCoords.test(i)) { - uniBufAttrs += fmt::format("\n texcoord{}_scale: vec4f,", i); - } - } - for (int i = 0; i < info.sampledTextures.size(); ++i) { - if (!info.sampledTextures.test(i)) { - continue; - } - uniBufAttrs += fmt::format("\n tex{}_size_bias: vec4f,", i); - texBindings += fmt::format( - "\n@group(2) @binding({1})\n" - "var tex{0}: texture_2d;\n" - "@group(2) @binding({2})\n" - "var tex{0}_samp: sampler;", - i, i * 2, i * 2 + 1); - } - fragmentFn += "\n prev = tev_overflow_vec4f(prev);"; - if (config.alphaCompare) { - const auto comp0 = alpha_compare(config.alphaCompare.comp0, config.alphaCompare.ref0); - const auto comp1 = alpha_compare(config.alphaCompare.comp1, config.alphaCompare.ref1); - AlphaCompareExpr pass; - switch (config.alphaCompare.op) { - default: - pass = alpha_compare_and(comp0, comp1); - break; - case GX_AOP_AND: - pass = alpha_compare_and(comp0, comp1); - break; - case GX_AOP_OR: - pass = alpha_compare_or(comp0, comp1); - break; - case GX_AOP_XOR: - pass = alpha_compare_xor(comp0, comp1); - break; - case GX_AOP_XNOR: - pass = alpha_compare_xnor(comp0, comp1); - break; - } - const auto discard = alpha_compare_not(pass); - if (discard.constant == 1) { - fragmentFn += "\n // Alpha compare\n discard;"; - } else if (discard.constant != 0) { - fragmentFn += "\n // Alpha compare" - "\n let alphaCompare = u32(round(clamp(prev.a, 0.0, 1.0) * 255.0));"; - fragmentFn += fmt::format("\n if ({}) {{ discard; }}", discard.expr); - } - } - - std::string fragmentReturnType = "@location(0) vec4f"; - std::string fragmentReturn = " return prev;"; - if (usesZTextureDepth) { - uniformPre += - "\n" - "struct FragmentOutput {\n" - " @location(0) color: vec4f,\n" - " @builtin(frag_depth) depth: f32,\n" - "};"; - - // ztexDepth is in GX's native distance terms (0=near/1=far, see fogDepthExpr's comment above), - // but frag_depth must be written in the same host NDC-z convention in.pos.z itself uses - - // forward matches directly (no change), reversed needs the same 1-x flip. This was backwards - // the same way fogDepthExpr was (verified by the same derivation, since aurora upstream has no - // directly equivalent line here to cross-check against - this z-texture-depth-output path - // appears to be specific to this fork). - fragmentFn += fmt::format("\n let fragDepth = {}ztexDepth;", UseReversedZ ? "1.0 - " : ""); - fragmentReturnType = "FragmentOutput"; - fragmentReturn = - " var out: FragmentOutput;\n" - " out.color = prev;\n" - " out.depth = fragDepth;\n" - " return out;"; - } - - const auto shaderSource = fmt::format(R"""( -fn bswap32(v: u32, le: bool) -> u32 {{ - if (le) {{ - return v; - }} - return ((v & 0x000000FFu) << 24u) | - ((v & 0x0000FF00u) << 8u) | - ((v & 0x00FF0000u) >> 8u) | - ((v & 0xFF000000u) >> 24u); -}} - -fn bswap16(v: u32, le: bool) -> u32 {{ - return select(((v & 0xFFu) << 8u) | (v >> 8u), v, le); -}} - -fn load_u8(p: ptr>, byte_off: u32) -> u32 {{ - let word = p[byte_off / 4u]; - let shift = (byte_off & 3u) * 8u; - return (word >> shift) & 0xFFu; -}} - -fn load_u32_raw(p: ptr>, byte_off: u32) -> u32 {{ - let word_idx = byte_off >> 2u; - let sub = byte_off & 3u; - let lo = p[word_idx]; - if (sub == 0u) {{ - return lo; - }} - let hi = p[word_idx + 1u]; - let shift = sub * 8u; - return (lo >> shift) | (hi << (32u - shift)); -}} - -fn load_u16(p: ptr>, byte_off: u32, le: bool) -> u32 {{ - let word_idx = byte_off >> 2u; - let sub = byte_off & 3u; - let word = p[word_idx]; - if (sub <= 2u) {{ - return bswap16(extractBits(word, sub * 8u, 16u), le); - }} - let next = p[word_idx + 1u]; - let raw = extractBits(word, 24u, 8u) | (extractBits(next, 0u, 8u) << 8u); - return bswap16(raw, le); -}} - -fn load_u24_raw(p: ptr>, byte_off: u32) -> u32 {{ - let word_idx = byte_off >> 2u; - let sub = byte_off & 3u; - let word = p[word_idx]; - // Three bytes at offsets zero or one fit entirely in this word. Do not - // access the next word: this attribute may end at the binding boundary. - if (sub <= 1u) {{ - return (word >> (sub * 8u)) & 0x00FFFFFFu; - }} - let next = p[word_idx + 1u]; - let shift = sub * 8u; - return ((word >> shift) | (next << (32u - shift))) & 0x00FFFFFFu; -}} - -fn load_u24(p: ptr>, byte_off: u32, le: bool) -> u32 {{ - let raw = load_u24_raw(p, byte_off); - if (le) {{ - return raw; - }} - return ((raw & 0x0000FFu) << 16u) | - (raw & 0x00FF00u) | - ((raw & 0xFF0000u) >> 16u); -}} - -fn load_u32(p: ptr>, byte_off: u32, le: bool) -> u32 {{ - return bswap32(load_u32_raw(p, byte_off), le); -}} - -fn load_f32(p: ptr>, byte_off: u32, le: bool) -> f32 {{ - return bitcast(load_u32(p, byte_off, le)); -}} - -fn raw_fetch_u8_1(p: ptr>, byte_off: u32) -> u32 {{ - return load_u8(p, byte_off); -}} - -fn raw_fetch_u8_2(p: ptr>, byte_off: u32) -> vec2u {{ - let word_idx = byte_off >> 2u; - let sub = byte_off & 3u; - let word = p[word_idx]; - if (sub <= 2u) {{ - let shift = sub * 8u; - return vec2u( - extractBits(word, shift + 0u, 8u), - extractBits(word, shift + 8u, 8u), - ); - }} - let next = p[word_idx + 1u]; - return vec2u( - extractBits(word, 24u, 8u), - extractBits(next, 0u, 8u), - ); -}} - -fn raw_fetch_u8_3(p: ptr>, byte_off: u32) -> vec3u {{ - let raw = load_u24_raw(p, byte_off); - return vec3u( - extractBits(raw, 0u, 8u), - extractBits(raw, 8u, 8u), - extractBits(raw, 16u, 8u), - ); -}} - -fn raw_fetch_u8_4(p: ptr>, byte_off: u32) -> vec4u {{ - let raw = load_u32_raw(p, byte_off); - return vec4u( - extractBits(raw, 0u, 8u), - extractBits(raw, 8u, 8u), - extractBits(raw, 16u, 8u), - extractBits(raw, 24u, 8u), - ); -}} - -fn raw_fetch_u16_1(p: ptr>, byte_off: u32, le: bool) -> u32 {{ - return load_u16(p, byte_off, le); -}} - -fn raw_fetch_u16_2(p: ptr>, byte_off: u32, le: bool) -> vec2u {{ - return vec2u( - load_u16(p, byte_off + 0u, le), - load_u16(p, byte_off + 2u, le), - ); -}} - -fn raw_fetch_u16_3(p: ptr>, byte_off: u32, le: bool) -> vec3u {{ - return vec3u( - load_u16(p, byte_off + 0u, le), - load_u16(p, byte_off + 2u, le), - load_u16(p, byte_off + 4u, le), - ); -}} - -fn raw_fetch_u16_4(p: ptr>, byte_off: u32, le: bool) -> vec4u {{ - return vec4u( - load_u16(p, byte_off + 0u, le), - load_u16(p, byte_off + 2u, le), - load_u16(p, byte_off + 4u, le), - load_u16(p, byte_off + 6u, le), - ); -}} - -fn raw_fetch_f32_1(p: ptr>, byte_off: u32, le: bool) -> f32 {{ - return load_f32(p, byte_off, le); -}} - -fn raw_fetch_f32_2(p: ptr>, byte_off: u32, le: bool) -> vec2f {{ - return vec2f( - load_f32(p, byte_off + 0u, le), - load_f32(p, byte_off + 4u, le), - ); -}} - -fn raw_fetch_f32_3(p: ptr>, byte_off: u32, le: bool) -> vec3f {{ - return vec3f( - load_f32(p, byte_off + 0u, le), - load_f32(p, byte_off + 4u, le), - load_f32(p, byte_off + 8u, le), - ); -}} - -fn raw_fetch_f32_4(p: ptr>, byte_off: u32, le: bool) -> vec4f {{ - return vec4f( - load_f32(p, byte_off + 0u, le), - load_f32(p, byte_off + 4u, le), - load_f32(p, byte_off + 8u, le), - load_f32(p, byte_off + 12u, le), - ); -}} - -fn fetch_u8_1(p: ptr>, byte_off: u32, frac: u32, le: bool) -> f32 {{ - let v = raw_fetch_u8_1(p, byte_off); - return f32(v) / f32(1u << frac); -}} - -fn fetch_s8_1(p: ptr>, byte_off: u32, frac: u32, le: bool) -> f32 {{ - let v = (bitcast(raw_fetch_u8_1(p, byte_off)) << 24) >> 24; - return f32(v) / f32(1u << frac); -}} - -fn fetch_u8_2(p: ptr>, byte_off: u32, frac: u32, le: bool) -> vec2f {{ - let v = raw_fetch_u8_2(p, byte_off); - return vec2f(v) / f32(1u << frac); -}} - -fn fetch_s8_2(p: ptr>, byte_off: u32, frac: u32, le: bool) -> vec2f {{ - let v = (bitcast(raw_fetch_u8_2(p, byte_off)) << vec2u(24u)) >> vec2u(24u); - return vec2f(v) / f32(1u << frac); -}} - -fn fetch_u8_3(p: ptr>, byte_off: u32, frac: u32, le: bool) -> vec3f {{ - let v = raw_fetch_u8_3(p, byte_off); - return vec3f(v) / f32(1u << frac); -}} - -fn fetch_s8_3(p: ptr>, byte_off: u32, frac: u32, le: bool) -> vec3f {{ - let v = (bitcast(raw_fetch_u8_3(p, byte_off)) << vec3u(24u)) >> vec3u(24u); - return vec3f(v) / f32(1u << frac); -}} - -fn fetch_u8_4(p: ptr>, byte_off: u32, frac: u32, le: bool) -> vec4f {{ - let v = raw_fetch_u8_4(p, byte_off); - return vec4f(v) / f32(1u << frac); -}} - -fn fetch_s8_4(p: ptr>, byte_off: u32, frac: u32, le: bool) -> vec4f {{ - let v = (bitcast(raw_fetch_u8_4(p, byte_off)) << vec4u(24u)) >> vec4u(24u); - return vec4f(v) / f32(1u << frac); -}} - -fn fetch_u16_1(p: ptr>, byte_off: u32, frac: u32, le: bool) -> f32 {{ - let v = raw_fetch_u16_1(p, byte_off, le); - return f32(v) / f32(1u << frac); -}} - -fn fetch_s16_1(p: ptr>, byte_off: u32, frac: u32, le: bool) -> f32 {{ - let v = bitcast(raw_fetch_u16_1(p, byte_off, le) << 16u) >> 16; - return f32(v) / f32(1u << frac); -}} - -fn fetch_u16_2(p: ptr>, byte_off: u32, frac: u32, le: bool) -> vec2f {{ - let v = raw_fetch_u16_2(p, byte_off, le); - return vec2f(v) / f32(1u << frac); -}} - -fn fetch_s16_2(p: ptr>, byte_off: u32, frac: u32, le: bool) -> vec2f {{ - let v = (bitcast(raw_fetch_u16_2(p, byte_off, le)) << vec2u(16u)) >> vec2u(16u); - return vec2f(v) / f32(1u << frac); -}} - -fn fetch_u16_3(p: ptr>, byte_off: u32, frac: u32, le: bool) -> vec3f {{ - let v = raw_fetch_u16_3(p, byte_off, le); - return vec3f(v) / f32(1u << frac); -}} - -fn fetch_s16_3(p: ptr>, byte_off: u32, frac: u32, le: bool) -> vec3f {{ - let v = (bitcast(raw_fetch_u16_3(p, byte_off, le)) << vec3u(16u)) >> vec3u(16u); - return vec3f(v) / f32(1u << frac); -}} - -fn fetch_u16_4(p: ptr>, byte_off: u32, frac: u32, le: bool) -> vec4f {{ - let v = raw_fetch_u16_4(p, byte_off, le); - return vec4f(v) / f32(1u << frac); -}} - -fn fetch_s16_4(p: ptr>, byte_off: u32, frac: u32, le: bool) -> vec4f {{ - let v = (bitcast(raw_fetch_u16_4(p, byte_off, le)) << vec4u(16u)) >> vec4u(16u); - return vec4f(v) / f32(1u << frac); -}} - -fn fetch_f32_1(p: ptr>, byte_off: u32, le: bool) -> f32 {{ - return raw_fetch_f32_1(p, byte_off, le); -}} - -fn fetch_f32_2(p: ptr>, byte_off: u32, le: bool) -> vec2f {{ - return raw_fetch_f32_2(p, byte_off, le); -}} - -fn fetch_f32_3(p: ptr>, byte_off: u32, le: bool) -> vec3f {{ - return raw_fetch_f32_3(p, byte_off, le); -}} - -fn fetch_f32_4(p: ptr>, byte_off: u32, le: bool) -> vec4f {{ - return raw_fetch_f32_4(p, byte_off, le); -}} - -fn fetch_rgb565(p: ptr>, byte_off: u32, le: bool) -> vec4f {{ - let v = load_u16(p, byte_off, le); - return vec4f( - f32((v >> 11u) & 0x1Fu) / f32(0x1Fu), - f32((v >> 5u) & 0x3Fu) / f32(0x3Fu), - f32((v >> 0u) & 0x1Fu) / f32(0x1Fu), - 1.0, - ); -}} - -fn fetch_rgb8(p: ptr>, byte_off: u32, le: bool) -> vec4f {{ - let v = raw_fetch_u8_3(p, byte_off); - return vec4f(f32(v.x), f32(v.y), f32(v.z), 255.0) / 255.0; -}} - -fn fetch_rgbx8(p: ptr>, byte_off: u32, le: bool) -> vec4f {{ - let v = raw_fetch_u8_4(p, byte_off); - return vec4f(f32(v.x), f32(v.y), f32(v.z), 255.0) / 255.0; -}} - -fn fetch_rgba4(p: ptr>, byte_off: u32, le: bool) -> vec4f {{ - let v = load_u16(p, byte_off, le); - return vec4f( - f32((v >> 12u) & 0x0Fu) / f32(0x0Fu), - f32((v >> 8u) & 0x0Fu) / f32(0x0Fu), - f32((v >> 4u) & 0x0Fu) / f32(0x0Fu), - f32((v >> 0u) & 0x0Fu) / f32(0x0Fu), - ); -}} - -fn fetch_rgba6(p: ptr>, byte_off: u32, le: bool) -> vec4f {{ - let v = load_u24(p, byte_off, le); - return vec4f( - f32((v >> 18u) & 0x3Fu) / f32(0x3Fu), - f32((v >> 12u) & 0x3Fu) / f32(0x3Fu), - f32((v >> 6u) & 0x3Fu) / f32(0x3Fu), - f32((v >> 0u) & 0x3Fu) / f32(0x3Fu), - ); -}} - -fn fetch_rgba8(p: ptr>, byte_off: u32, le: bool) -> vec4f {{ - let v = raw_fetch_u8_4(p, byte_off); - return vec4f(v) / 255.0; -}} - -fn tev_overflow_f32(in: f32) -> f32 {{ - let byte_space = in * 255.0; - return (byte_space - floor(byte_space / 256.0) * 256.0) / 255.0; -}} - -fn tev_overflow_vec3f(in: vec3f) -> vec3f {{ - let byte_space = in * 255.0; - return (byte_space - floor(byte_space / 256.0) * 256.0) / 255.0; -}} - -fn tev_overflow_vec4f(in: vec4f) -> vec4f {{ - let byte_space = in * 255.0; - return (byte_space - floor(byte_space / 256.0) * 256.0) / 255.0; -}} - -fn tev_s24_fixed_vec2i(in: vec2i) -> vec2i {{ - return (in << vec2u(8u)) >> vec2u(8u); -}} - -fn tev_byte_f32(in: f32) -> i32 {{ - return i32(round(in * 255.0)); -}} - -fn tev_byte_vec3f(in: vec3f) -> vec3i {{ - return vec3i(round(in * 255.0)); -}} - -fn tev_regular_i32(a: i32, b: i32, c: i32, d: i32, bias: i32, scale: u32, is_sub: bool) -> i32 {{ - var d_part = d + bias; - var lerp_part = (a << 8u) + (b - a) * (c + (c >> 7u)); - if (scale == 1u) {{ - d_part = d_part << 1u; - lerp_part = lerp_part << 1u; - }} - if (scale == 2u) {{ - d_part = d_part << 2u; - lerp_part = lerp_part << 2u; - }} - if (scale != 3u) {{ - lerp_part += select(128, 127, is_sub); - }} - let lerp = lerp_part >> 8u; - var result = select(d_part + lerp, d_part - lerp, is_sub); - if (scale == 3u) {{ - result = result >> 1u; - }} - return result; -}} - -fn tev_regular_f32(a: f32, b: f32, c: f32, d: f32, bias: i32, scale: u32, is_sub: bool) -> f32 {{ - return f32(tev_regular_i32(tev_byte_f32(a), tev_byte_f32(b), tev_byte_f32(c), tev_byte_f32(d), bias, scale, is_sub)) / - 255.0; -}} - -fn tev_regular_vec3f(a: vec3f, b: vec3f, c: vec3f, d: vec3f, bias: i32, scale: u32, is_sub: bool) -> vec3f {{ - let ai = tev_byte_vec3f(a); - let bi = tev_byte_vec3f(b); - let ci = tev_byte_vec3f(c); - let di = tev_byte_vec3f(d); - return vec3f( - f32(tev_regular_i32(ai.x, bi.x, ci.x, di.x, bias, scale, is_sub)) / 255.0, - f32(tev_regular_i32(ai.y, bi.y, ci.y, di.y, bias, scale, is_sub)) / 255.0, - f32(tev_regular_i32(ai.z, bi.z, ci.z, di.z, bias, scale, is_sub)) / 255.0, - ); -}} - -{8} - -struct Uniform {{ - vtx_start: u32, - current_pnmtx: u32, - render_viewport_size: vec2f, - logical_viewport_size: vec2f, - pad: vec2u, - array_start: array,{0} -}}; -@group(0) @binding(0) -var vbuf: array; -@group(0) @binding(1) -var abuf: array; -@group(1) @binding(0) -var ubuf: Uniform;{1} - -struct VertexOutput {{ - @builtin(position) pos: vec4f,{2} -}}; - -@vertex -fn vs_main( - @builtin(vertex_index) vidx: u32{3} -) -> VertexOutput {{ - var out: VertexOutput;{7}{4} - return out; -}} - -@fragment -fn fs_main(in: VertexOutput) -> {9} {{{6}{5} -{10} -}} -)""", - uniBufAttrs, texBindings, vtxOutAttrs, vtxInAttrs, vtxXfrAttrs, fragmentFn, - fragmentFnPre, vtxXfrAttrsPre, uniformPre, fragmentReturnType, - fragmentReturn); - wgpu::ShaderSourceWGSL wgslDescriptor{}; - wgslDescriptor.code = shaderSource.c_str(); - const auto label = fmt::format("GX Shader {:x}", hash); - const auto shaderDescriptor = wgpu::ShaderModuleDescriptor{ - .nextInChain = &wgslDescriptor, - .label = label.c_str(), - }; - return webgpu::g_device.CreateShaderModule(&shaderDescriptor); -} -} // namespace aurora::gx diff --git a/aurora-main/lib/gx/shader_info.cpp b/aurora-main/lib/gx/shader_info.cpp deleted file mode 100644 index 92ae1de..0000000 --- a/aurora-main/lib/gx/shader_info.cpp +++ /dev/null @@ -1,746 +0,0 @@ -#include "shader_info.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#if !defined(_LIBCPP_VERSION) -#include -#endif -#include -#include -#include -#include - -#include - -namespace aurora::gx { -// TODO: remove, just for testing -bool enableLodBias = true; - -namespace { -Module Log("aurora::gx"); - -bool is_alpha_bump_channel(GXChannelID id) { return id == GX_ALPHA_BUMP || id == GX_ALPHA_BUMPN; } - -bool sampled_color_channel(GXChannelID id, size_t& out) { - switch (id) { - case GX_COLOR0: - case GX_ALPHA0: - case GX_COLOR0A0: - out = 0; - return true; - case GX_COLOR1: - case GX_ALPHA1: - case GX_COLOR1A1: - out = 1; - return true; - default: - return false; - } -} - -Fog fog_uniform() { - const auto& state = g_gxState.fog; - Fog fog{ - .color = state.color, - .a = state.aRaw, - .b = static_cast(state.bMagnitude), - .c = state.c, - .pad = static_cast(state.bShift), - }; - - const u32 rangeBase = g_gxState.fogRange[0]; - const bool rangeEnabled = (rangeBase & (1u << 10)) != 0; - float rangeWidth = std::abs(g_gxState.xfViewport[0]) * 2.0f; - if (rangeWidth <= 0.0f) { - rangeWidth = 1.0f; - } - const int rangeCenter = static_cast(rangeBase & 0x3ffu) - 342; - const float screenSpaceCenter = rangeEnabled ? ((static_cast(rangeCenter) / rangeWidth) * 2.0f) - 1.0f - : 0.0f; - fog.rangeBase = {screenSpaceCenter, rangeEnabled ? rangeWidth : 1.0f, 0.0f, 0.0f}; - - std::array rangeK{}; - size_t kIndex = 0; - for (size_t i = 1; i < g_gxState.fogRange.size(); ++i) { - const u32 packed = g_gxState.fogRange[i]; - rangeK[kIndex++] = static_cast((packed >> 12) & 0xfffu) / 64.0f; - rangeK[kIndex++] = static_cast(packed & 0xfffu) / 64.0f; - } - rangeK[10] = rangeK[9]; - rangeK[11] = rangeK[9]; - for (size_t i = 0; i < fog.rangeK.size(); ++i) { - fog.rangeK[i] = {rangeK[i * 4 + 0], rangeK[i * 4 + 1], rangeK[i * 4 + 2], rangeK[i * 4 + 3]}; - } - return fog; -} - -float sanitize_light_dir_component(float value) noexcept { - u32 bits = 0; - std::memcpy(&bits, &value, sizeof(bits)); - if ((bits & 0x7f800000u) != 0x7f800000u) { - return value; - } - if ((bits & 0x007fffffu) != 0) { - return 0.0f; - } - return (bits & 0x80000000u) != 0 ? -1.0f : 1.0f; -} -} // namespace - -Light prepare_shader_light(Light light) noexcept { - if (std::fabs(light.distAtt[0]) < 0.00001f && std::fabs(light.distAtt[1]) < 0.00001f && - std::fabs(light.distAtt[2]) < 0.00001f) { - light.distAtt[0] = 0.00001f; - } - - const double normSq = static_cast(light.dir[0]) * static_cast(light.dir[0]) + - static_cast(light.dir[1]) * static_cast(light.dir[1]) + - static_cast(light.dir[2]) * static_cast(light.dir[2]); - if (normSq == 0.0) { - light.dir[0] = 0.0f; - light.dir[1] = 0.0f; - light.dir[2] = 0.0f; - return light; - } - const double invNorm = 1.0 / std::sqrt(normSq); - // Aurora is built with fast-math, under which std::isnan/std::isinf may be optimized away. - light.dir[0] = sanitize_light_dir_component(static_cast(light.dir[0] * invNorm)); - light.dir[1] = sanitize_light_dir_component(static_cast(light.dir[1] * invNorm)); - light.dir[2] = sanitize_light_dir_component(static_cast(light.dir[2] * invNorm)); - return light; -} - -namespace { -Vec4 texture_size_bias(const gfx::TextureBind& tex) { - auto width = static_cast(tex.texObj.width()); - auto height = static_cast(tex.texObj.height()); - const auto vpBias = - enableLodBias && tex.ref && tex.ref->hasArbitraryMips - ? log2(std::min(g_gxState.renderViewport.width / std::max(g_gxState.logicalViewport.width, 1.f), - g_gxState.renderViewport.height / std::max(g_gxState.logicalViewport.height, 1.f))) - : 0.f; - return {width, height, tex.texObj.lod_bias() + vpBias, 0.0f}; -} - -Vec4 texcoord_scale(const TexCoordScale& scale) { - return {static_cast(scale.scaleS) + 1.0f, static_cast(scale.scaleT) + 1.0f, - scale.biasS ? 1.0f : 0.0f, scale.biasT ? 1.0f : 0.0f}; -} - -void mark_texture_sample(const TevStageTextureDependency& dependency, ShaderInfo& info) { - if (!dependency.canSampleTexture) { - return; - } - info.sampledTexCoords.set(static_cast(dependency.texCoordId)); - info.sampledTextures.set(static_cast(dependency.texMapId)); -} - -void mark_tev_reg_read(GXTevRegID reg, bool alpha, ShaderInfo& info) { - auto& writes = alpha ? info.writesTevRegAlpha : info.writesTevRegRgb; - auto& loads = alpha ? info.loadsTevRegAlpha : info.loadsTevRegRgb; - if (!writes.test(reg)) { - loads.set(reg); - } -} - -void color_arg_reg_info(GXTevColorArg arg, const TevStage& stage, - const TevStageTextureDependency& textureDependency, ShaderInfo& info) { - switch (arg) { - case GX_CC_CPREV: - mark_tev_reg_read(GX_TEVPREV, false, info); - break; - case GX_CC_APREV: - mark_tev_reg_read(GX_TEVPREV, true, info); - break; - case GX_CC_C0: - mark_tev_reg_read(GX_TEVREG0, false, info); - break; - case GX_CC_A0: - mark_tev_reg_read(GX_TEVREG0, true, info); - break; - case GX_CC_C1: - mark_tev_reg_read(GX_TEVREG1, false, info); - break; - case GX_CC_A1: - mark_tev_reg_read(GX_TEVREG1, true, info); - break; - case GX_CC_C2: - mark_tev_reg_read(GX_TEVREG2, false, info); - break; - case GX_CC_A2: - mark_tev_reg_read(GX_TEVREG2, true, info); - break; - case GX_CC_TEXC: - case GX_CC_TEXA: - mark_texture_sample(textureDependency, info); - break; - case GX_CC_RASC: - case GX_CC_RASA: - if (stage.channelId != GX_COLOR_NULL && stage.channelId != GX_COLOR_ZERO && - !is_alpha_bump_channel(stage.channelId)) { - size_t channel = 0; - if (sampled_color_channel(stage.channelId, channel)) { - info.sampledColorChannels.set(channel); - } - } - break; - case GX_CC_KONST: - switch (stage.kcSel) { - case GX_TEV_KCSEL_K0: - case GX_TEV_KCSEL_K0_R: - case GX_TEV_KCSEL_K0_G: - case GX_TEV_KCSEL_K0_B: - case GX_TEV_KCSEL_K0_A: - info.sampledKColors.set(0); - break; - case GX_TEV_KCSEL_K1: - case GX_TEV_KCSEL_K1_R: - case GX_TEV_KCSEL_K1_G: - case GX_TEV_KCSEL_K1_B: - case GX_TEV_KCSEL_K1_A: - info.sampledKColors.set(1); - break; - case GX_TEV_KCSEL_K2: - case GX_TEV_KCSEL_K2_R: - case GX_TEV_KCSEL_K2_G: - case GX_TEV_KCSEL_K2_B: - case GX_TEV_KCSEL_K2_A: - info.sampledKColors.set(2); - break; - case GX_TEV_KCSEL_K3: - case GX_TEV_KCSEL_K3_R: - case GX_TEV_KCSEL_K3_G: - case GX_TEV_KCSEL_K3_B: - case GX_TEV_KCSEL_K3_A: - info.sampledKColors.set(3); - break; - default: - break; - } - break; - default: - break; - } -} - -void alpha_arg_reg_info(GXTevAlphaArg arg, const TevStage& stage, - const TevStageTextureDependency& textureDependency, ShaderInfo& info) { - switch (arg) { - case GX_CA_APREV: - mark_tev_reg_read(GX_TEVPREV, true, info); - break; - case GX_CA_A0: - mark_tev_reg_read(GX_TEVREG0, true, info); - break; - case GX_CA_A1: - mark_tev_reg_read(GX_TEVREG1, true, info); - break; - case GX_CA_A2: - mark_tev_reg_read(GX_TEVREG2, true, info); - break; - case GX_CA_TEXA: - mark_texture_sample(textureDependency, info); - break; - case GX_CA_RASA: - if (stage.channelId != GX_COLOR_NULL && stage.channelId != GX_COLOR_ZERO && - !is_alpha_bump_channel(stage.channelId)) { - size_t channel = 0; - if (sampled_color_channel(stage.channelId, channel)) { - info.sampledColorChannels.set(channel); - } - } - break; - case GX_CA_KONST: - switch (stage.kaSel) { - case GX_TEV_KASEL_K0_R: - case GX_TEV_KASEL_K0_G: - case GX_TEV_KASEL_K0_B: - case GX_TEV_KASEL_K0_A: - info.sampledKColors.set(0); - break; - case GX_TEV_KASEL_K1_R: - case GX_TEV_KASEL_K1_G: - case GX_TEV_KASEL_K1_B: - case GX_TEV_KASEL_K1_A: - info.sampledKColors.set(1); - break; - case GX_TEV_KASEL_K2_R: - case GX_TEV_KASEL_K2_G: - case GX_TEV_KASEL_K2_B: - case GX_TEV_KASEL_K2_A: - info.sampledKColors.set(2); - break; - case GX_TEV_KASEL_K3_R: - case GX_TEV_KASEL_K3_G: - case GX_TEV_KASEL_K3_B: - case GX_TEV_KASEL_K3_A: - info.sampledKColors.set(3); - break; - default: - break; - } - break; - default: - break; - } -} -} // namespace - -ShaderInfo build_shader_info(const ShaderConfig& config) noexcept { - ZoneScoped; - - ShaderInfo info{ - // vtx_start, current_pnmtx, render/logical viewport size, array_start, pad, proj - .uniformSize = 4 + 4 + 8 + 8 + 8 + 48 + 64, - }; - - if (config.lineMode != 0) { - info.uniformSize += 4 + 4 + 4 + 4; // line_width, line_aspect_y, line_tex_offset, line_texcoord_mask - info.lineMode = config.lineMode; - } - - for (int attr = 0; attr < config.attrs.size(); attr++) { - const auto attrType = config.attrs[attr].attrType; - if ((attr == GX_VA_PNMTXIDX || (attr >= GX_VA_TEX0MTXIDX && attr <= GX_VA_TEX7MTXIDX)) && attrType == GX_DIRECT) { - info.indexAttr.set(attr); - } else if (attrType == GX_INDEX8 || attrType == GX_INDEX16) { - info.indexAttr.set(attr); - } - } - - for (int i = 0; i < config.tevStageCount; ++i) { - const auto& stage = config.tevStages[i]; - const auto textureDependency = tev_stage_texture_dependency(config, static_cast(i)); - // Color pass - color_arg_reg_info(stage.colorPass.a, stage, textureDependency, info); - color_arg_reg_info(stage.colorPass.b, stage, textureDependency, info); - color_arg_reg_info(stage.colorPass.c, stage, textureDependency, info); - color_arg_reg_info(stage.colorPass.d, stage, textureDependency, info); - info.writesTevRegRgb.set(stage.colorOp.outReg); - - // Alpha pass - alpha_arg_reg_info(stage.alphaPass.a, stage, textureDependency, info); - alpha_arg_reg_info(stage.alphaPass.b, stage, textureDependency, info); - alpha_arg_reg_info(stage.alphaPass.c, stage, textureDependency, info); - alpha_arg_reg_info(stage.alphaPass.d, stage, textureDependency, info); - info.writesTevRegAlpha.set(stage.alphaOp.outReg); - } - if (const int zTexStage = tev_z_texture_stage(config); zTexStage >= 0) { - mark_texture_sample(tev_stage_texture_dependency(config, static_cast(zTexStage)), info); - } - for (int i = 0; i < config.tevStageCount; ++i) { - const auto& stage = config.tevStages[i]; - const auto textureDependency = tev_stage_texture_dependency(config, static_cast(i)); - - // Coordinate state is independent of whether this stage has an enabled texture map. - if (textureDependency.needsFixedTexcoordState && textureDependency.texCoordId >= 0) { - info.sampledTexCoords.set(static_cast(textureDependency.texCoordId)); - } - - // Skip if not enabled - if (stage.indTexStage >= config.numIndStages) { - continue; - } - const bool usesIndStage = stage.indTexMtxId != GX_ITM_OFF || is_alpha_bump_channel(stage.channelId); - if (!usesIndStage) { - continue; - } - info.usedIndStages.set(stage.indTexStage); - const auto& indStage = config.indStages[stage.indTexStage]; - if (indStage.texMapId < MaxTextures) { - info.sampledTextures.set(indStage.texMapId); - info.sampledIndTextures.set(indStage.texMapId); - } - const int effectiveIndTexCoord = tev_effective_texcoord(config, indStage.texCoordId); - if (effectiveIndTexCoord >= 0) { - info.sampledTexCoords.set(static_cast(effectiveIndTexCoord)); - } - // Track which indirect matrix is used - if (stage.indTexMtxId >= GX_ITM_0 && stage.indTexMtxId <= GX_ITM_2) { - info.usedIndTexMtxs.set(stage.indTexMtxId - GX_ITM_0); - } else if (stage.indTexMtxId >= GX_ITM_S0 && stage.indTexMtxId <= GX_ITM_S2) { - info.usedIndTexMtxs.set(stage.indTexMtxId - GX_ITM_S0); - } else if (stage.indTexMtxId >= GX_ITM_T0 && stage.indTexMtxId <= GX_ITM_T2) { - info.usedIndTexMtxs.set(stage.indTexMtxId - GX_ITM_T0); - } - } - - const auto loadsTevRegs = info.loadsTevRegRgb | info.loadsTevRegAlpha; - info.uniformSize += loadsTevRegs.count() * sizeof(Vec4); - for (int i = 0; i < info.sampledColorChannels.size(); ++i) { - if (info.sampledColorChannels.test(i)) { - const auto& cc = config.colorChannels[i]; - const auto& cca = config.colorChannels[i + GX_ALPHA0]; - if (cc.lightingEnabled || cca.lightingEnabled) { - info.lightingEnabled = true; - } - } - } - if (info.lightingEnabled) { - // Lights + light state for all channels - info.uniformSize += 16 + sizeof(Light) * GX::MaxLights; - } - for (int i = 0; i < info.sampledColorChannels.size(); ++i) { - if (info.sampledColorChannels.test(i)) { - const auto& cc = config.colorChannels[i]; - if (cc.lightingEnabled && cc.ambSrc == GX_SRC_REG) { - info.uniformSize += sizeof(Vec4); - } - if (cc.matSrc == GX_SRC_REG) { - info.uniformSize += sizeof(Vec4); - } - const auto& cca = config.colorChannels[i + GX_ALPHA0]; - if (cca.lightingEnabled && cca.ambSrc == GX_SRC_REG) { - info.uniformSize += sizeof(Vec4); - } - if (cca.matSrc == GX_SRC_REG) { - info.uniformSize += sizeof(Vec4); - } - } - } - info.uniformSize += info.sampledKColors.count() * sizeof(Vec4); - for (int i = 0; i < info.sampledTexCoords.size(); ++i) { - if (!info.sampledTexCoords.test(i)) { - continue; - } - const auto& tcg = config.tcgs[i]; - if (config.dualTexEnabled && tcg.postMtx != GX_PTIDENTITY) { - u32 postMtxIdx = (tcg.postMtx - GX_PTTEXMTX0) / 3; - info.usesPTTexMtx.set(postMtxIdx); - } - } - if (info.usesPTTexMtx.any()) - info.uniformSize += sizeof(Mat3x4) * MaxPTTexMtx; - - // Resolve the matrix slots this shader can read. - { - auto& layout = info.matrixLayout; - layout.postexRemap.fill(UniformMatrixLayout::kAbsent); - - const bool dynamicPnMtx = config.attrs[GX_VA_PNMTXIDX].attrType != GX_NONE; - bool dynamicTexMtx = false; - std::bitset literalSlots; - for (size_t i = 0; i < info.sampledTexCoords.size(); ++i) { - if (!info.sampledTexCoords.test(i)) { - continue; - } - const auto& tcg = config.tcgs[i]; - if (tcg.type != GX_TG_MTX2x4 && tcg.type != GX_TG_MTX3x4) { - continue; - } - if (info.indexAttr.test(GX_VA_TEX0MTXIDX + i)) { - // A per-vertex texture matrix index addresses raw matrix memory and can name any row, including the position rows. - dynamicTexMtx = true; - continue; - } - if (tcg.mtx == GX_IDENTITY) { - continue; - } - const u32 slot = static_cast(tcg.mtx) / 3; - if (slot >= MaxPostexMtx) { - // Out of range for the shader array; preserve the uncompacted layout rather than inventing a different (still invalid) index. - dynamicTexMtx = true; - continue; - } - literalSlots.set(slot); - } - - // At most MaxPostexMtx entries can ever be pushed: the absolute layout pushes the ten position slots plus at most ten texture slots, and the compacted layout pushes the current matrix plus at most one literal slot per texgen. - const auto pushPostex = [&](u8 slot) { - CHECK(layout.postexCount < layout.postexSlots.size(), "postex matrix layout overflow"); - layout.postexSlots[layout.postexCount++] = slot; - }; - const auto pushNrm = [&](u8 slot) { - CHECK(layout.nrmCount < layout.nrmSlots.size(), "normal matrix layout overflow"); - layout.nrmSlots[layout.nrmCount++] = slot; - }; - - layout.absolutePosRegion = dynamicPnMtx || dynamicTexMtx; - if (!layout.absolutePosRegion) { - // Compact slot 0 always holds the matrix selected by the current matrix index; build_uniform writes 0 into `current_pnmtx` to match. - pushPostex(UniformMatrixLayout::kCurrentPnMtx); - pushNrm(UniformMatrixLayout::kCurrentPnMtx); - } - for (u32 slot = 0; slot < MaxPnMtx; ++slot) { - if (!layout.absolutePosRegion && !literalSlots.test(slot)) { - continue; - } - layout.postexRemap[slot] = layout.postexCount; - pushPostex(static_cast(slot)); - if (layout.absolutePosRegion) { - // The normal array is indexed by the same expression as the position array, so its compact indices have to line up with the position slots. - pushNrm(static_cast(slot)); - } - } - for (u32 slot = MaxPnMtx; slot < MaxPostexMtx; ++slot) { - if (!dynamicTexMtx && !literalSlots.test(slot)) { - continue; - } - layout.postexRemap[slot] = layout.postexCount; - pushPostex(static_cast(slot)); - } - // `postex_mtx[in_pnmtxidx]` and `nrm_mtx[in_pnmtxidx]` are emitted unconditionally, so neither array can ever be empty. - info.uniformSize += sizeof(Mat3x4) * (layout.postexCount + layout.nrmCount); - } - if (config.fogType != GX_FOG_NONE) { - info.usesFog = true; - info.uniformSize += sizeof(Fog); - } - if (info.usedIndTexMtxs.any()) { - info.uniformSize += MaxIndTexMtxs * 2 * sizeof(Vec4); - } - info.uniformSize += info.sampledTexCoords.count() * sizeof(Vec4); - info.uniformSize += info.sampledTextures.count() * sizeof(Vec4); - info.uniformSize = gfx::align_uniform(info.uniformSize); - if (info.uniformSize > MaxUniformSize) { - Log.fatal("Uniform size exceeds maximum: {} > {}", info.uniformSize, MaxUniformSize); - } - return info; -} - -static f32 tex_offset(GXTexOffset offs) noexcept { - switch (offs) { - DEFAULT_FATAL("invalid tex offset {}", underlying(offs)); - case GX_TO_ZERO: - return 0.f; - case GX_TO_SIXTEENTH: - return 1.f / 16.f; - case GX_TO_EIGHTH: - return 1.f / 8.f; - case GX_TO_FOURTH: - return 1.f / 4.f; - case GX_TO_HALF: - return 1.f / 2.f; - case GX_TO_ONE: - return 1.f; - } -} - -static u32 point_texcoord_mask() noexcept { - u32 mask = 0; - for (int i = 0; i < MaxTexCoord; ++i) { - if (g_gxState.texCoordScales[i].pointOffset) { - mask |= 1 << i; - } - } - return mask; -} - -static u32 line_texcoord_mask() noexcept { - u32 mask = 0; - for (int i = 0; i < MaxTexCoord; ++i) { - if (g_gxState.texCoordScales[i].lineOffset) { - mask |= 1 << i; - } - } - return mask; -} - -namespace { -// Largest possible staged prefix: scalar head (80) + line/point block (16) + projection matrix + every matrix the uncompacted layout can hold. -constexpr size_t kStagedUniformBytes = - 96 + sizeof(Mat4x4) + sizeof(Mat3x4) * (MaxPostexMtx + MaxPnMtx); - -// The host viewport always receives the normalized GX depth window (render_pass_impl clamps to minDepth <= maxDepth). -// -// Folds the near/far depth correction the vertex shader used to apply per-vertex directly into the -// projection matrix instead (matching upstream aurora commit 1dde08fa, "Move depth correction to -// projection matrix") - valid because the correction is a linear combination of the z/w rows, so -// applying it once here to the row is equivalent to applying it once per-vertex to the dot product, -// and it must be applied exactly once: doing it here AND in the shader (the previous bug) canceled -// the negation out for `flip`, silently making "reversed" Z behave identically to forward Z. -// `flip` decides which of the two single-application forms this draw needs: true bakes in the -// reversed-Z inversion (z' = -z), false bakes in the forward-Z near/far combination (z' = z + w) - -// exactly one always applies, never both, and never neither. -static Mat4x4 effective_projection() noexcept { - const auto& vp = g_gxState.renderViewport; - const bool flip = (vp.znear <= vp.zfar) == UseReversedZ; - Mat4x4 proj = g_gxState.proj; - for (size_t i = 0; i < 4; ++i) { - proj.m2.m[i] = flip ? -proj.m2.m[i] : (proj.m2.m[i] + proj.m3.m[i]); - } - return proj; -} -} // namespace - -UniformRanges build_uniform(const ShaderInfo& info, u32 vtxStart, const BindGroupRanges& ranges, - const FrameInterpolationDrawIdentity& drawIdentity, bool perspective, - uint16_t usedPnMtxMask) noexcept { - ZoneScoped; - - auto [buf, range] = gfx::map_uniform(info.uniformSize); - - const auto& layout = info.matrixLayout; - // `postex_mtx[current_pnmtx]` indexes raw matrix memory, so a current-matrix index of 10 or more selects a texture matrix; the normal array only covers the position rows and clamps. - const u32 currentPostexSlot = std::min(g_gxState.currentPnMtx, MaxPostexMtx - 1); - const u32 currentNrmSlot = std::min(g_gxState.currentPnMtx, MaxPnMtx - 1); - - // The mapped uniform range lives in write-combine memory, which wants long sequential stores. - alignas(16) std::array staged; - size_t stagedSize = 0; - const auto stage = [&](const void* data, size_t size) noexcept { - std::memcpy(staged.data() + stagedSize, data, size); - stagedSize += size; - }; - const auto stage_u32 = [&](u32 value) noexcept { stage(&value, sizeof(value)); }; - const auto stage_f32 = [&](f32 value) noexcept { stage(&value, sizeof(value)); }; - - stage_u32(vtxStart); - // With a compacted position region the live matrix is uploaded to slot 0, so every `postex_mtx[in_pnmtxidx]` / `nrm_mtx[in_pnmtxidx]` read has to resolve to 0 as well. - stage_u32(layout.absolutePosRegion ? g_gxState.currentPnMtx : 0u); - stage_f32(g_gxState.renderViewport.width); - stage_f32(g_gxState.renderViewport.height); - stage_f32(g_gxState.logicalViewport.width); - stage_f32(g_gxState.logicalViewport.height); - std::memset(staged.data() + stagedSize, 0, 8); // pad - stagedSize += 8; - for (const auto& vaRange : ranges.vaRanges) { - stage_u32(vaRange.offset); - } - if (info.lineMode != 0) { - if (info.lineMode == 3) { // GX_POINTS - stage_f32(static_cast(g_gxState.pointSize) / 6.f); - stage_f32(1.0f); - stage_f32(tex_offset(g_gxState.pointTexOffset)); - stage_u32(point_texcoord_mask()); - } else { // GX_LINES / GX_LINESTRIP - stage_f32(static_cast(g_gxState.lineWidth) / 6.f); - stage_f32(g_gxState.lineHalfAspect ? 0.5f : 1.f); - stage_f32(tex_offset(g_gxState.lineTexOffset)); - stage_u32(line_texcoord_mask()); - } - } - const size_t projectionOffset = stagedSize; - const Mat4x4 effectiveProj = effective_projection(); - stage(&effectiveProj, sizeof(effectiveProj)); - - const size_t positionOffset = stagedSize; - for (u32 i = 0; i < layout.postexCount; ++i) { - const u32 slot = - layout.postexSlots[i] == UniformMatrixLayout::kCurrentPnMtx ? currentPostexSlot - : layout.postexSlots[i]; - stage(slot < MaxPnMtx ? &g_gxState.pnMtx[slot].pos : &g_gxState.texMtxs[slot - MaxPnMtx], - sizeof(Mat3x4)); - } - - const size_t normalOffset = stagedSize; - for (u32 i = 0; i < layout.nrmCount; ++i) { - const u32 slot = layout.nrmSlots[i] == UniformMatrixLayout::kCurrentPnMtx ? currentNrmSlot - : layout.nrmSlots[i]; - stage(&g_gxState.pnMtx[slot].nrm, sizeof(Mat3x4)); - } - buf.append(staged.data(), stagedSize); - - const auto loadsTevRegs = info.loadsTevRegRgb | info.loadsTevRegAlpha; - for (int i = 0; i < loadsTevRegs.size(); ++i) { - if (loadsTevRegs.test(i)) { - buf.append(g_gxState.colorRegs[i]); - } - } - if (info.lightingEnabled) { - // Sanitizing and normalizing light directions is substantially more expensive than copying the uniform data, while lights normally remain unchanged across many draws. - static_assert(sizeof(g_gxState.lights) == 80 * GX::MaxLights); - if (g_gxState.preparedLightsDirty) { - for (size_t i = 0; i < g_gxState.preparedLights.size(); ++i) { - g_gxState.preparedLights[i] = prepare_shader_light(g_gxState.lights[i]); - } - g_gxState.preparedLightsDirty = false; - } - buf.append(g_gxState.preparedLights); - // Light state for all channels - for (int i = 0; i < 4; ++i) { - buf.append(g_gxState.colorChannelState[i].lightMask.to_ulong()); - } - } - for (int i = 0; i < info.sampledColorChannels.size(); ++i) { - if (!info.sampledColorChannels.test(i)) { - continue; - } - const auto& ccc = g_gxState.colorChannelConfig[i]; - const auto& ccs = g_gxState.colorChannelState[i]; - if (ccc.lightingEnabled && ccc.ambSrc == GX_SRC_REG) { - buf.append(ccs.ambColor); - } - if (ccc.matSrc == GX_SRC_REG) { - buf.append(ccs.matColor); - } - const auto& ccca = g_gxState.colorChannelConfig[i + GX_ALPHA0]; - const auto& ccsa = g_gxState.colorChannelState[i + GX_ALPHA0]; - if (ccca.lightingEnabled && ccca.ambSrc == GX_SRC_REG) { - buf.append(ccsa.ambColor); - } - if (ccca.matSrc == GX_SRC_REG) { - buf.append(ccsa.matColor); - } - } - for (int i = 0; i < info.sampledKColors.size(); ++i) { - if (info.sampledKColors.test(i)) { - buf.append(g_gxState.kcolors[i]); - } - } - if (info.usesPTTexMtx.any()) { - for (int i = 0; i < info.usesPTTexMtx.size(); ++i) { - buf.append(g_gxState.ptTexMtxs[i]); - } - } - if (info.usesFog) { - buf.append(fog_uniform()); - } - if (info.usedIndTexMtxs.any()) { - for (int i = 0; i < MaxIndTexMtxs; ++i) { - const auto& mtx = g_gxState.indTexMtxs[i]; - buf.append(Vec4{indirect_matrix_mantissa(mtx.mtx.m0.x), indirect_matrix_mantissa(mtx.mtx.m0.y), - indirect_matrix_mantissa(mtx.mtx.m1.x), indirect_matrix_mantissa(mtx.mtx.m1.y)}); - buf.append(Vec4{indirect_matrix_mantissa(mtx.mtx.m2.x), indirect_matrix_mantissa(mtx.mtx.m2.y), - indirect_matrix_shift(mtx.scaleExp), 0}); - } - } - for (int i = 0; i < info.sampledTexCoords.size(); ++i) { - if (info.sampledTexCoords.test(i)) { - buf.append(texcoord_scale(g_gxState.texCoordScales[i])); - } - } - for (int i = 0; i < info.sampledTextures.size(); ++i) { - if (!info.sampledTextures.test(i)) { - continue; - } - const auto& tex = get_texture(static_cast(i)); - // CHECK(tex, "unbound texture {}", i); - buf.append(texture_size_bias(tex)); - } - - if (!perspective || frame_interpolation_fps() == 0) { - g_gxState.stateDirty = false; - return { - .current = range, - .interpolated = {}, - }; - } - - const auto interpolatedRanges = record_interpolation_draw( - drawIdentity, effectiveProj, usedPnMtxMask, - InterpolatedUniformLayout{ - .sourceUniformData = buf.data(), - .uniformSize = range.size, - .projectionOffset = projectionOffset, - .positionOffset = positionOffset, - .normalOffset = normalOffset, - // A compacted position region holds the current matrix at slot 0. - .currentMatrix = layout.absolutePosRegion - ? std::min(g_gxState.currentPnMtx, MaxPnMtx - 1) - : 0, - .indexedMatrices = info.indexAttr.test(GX_VA_PNMTXIDX), - }); - g_gxState.stateDirty = false; - return { - .current = range, - .interpolated = interpolatedRanges, - }; -} -} // namespace aurora::gx diff --git a/aurora-main/lib/gx/shader_info.hpp b/aurora-main/lib/gx/shader_info.hpp deleted file mode 100644 index 6b8e329..0000000 --- a/aurora-main/lib/gx/shader_info.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "gx.hpp" -// MaxInterpolatedFrames / FrameInterpolationDrawIdentity, and the interpolation API that build_uniform feeds. -#include "frame_interpolation.hpp" - -namespace aurora::gx { -struct UniformRanges { - gfx::Range current; - std::array interpolated; -}; - -ShaderInfo build_shader_info(const ShaderConfig& config) noexcept; -Light prepare_shader_light(Light light) noexcept; -UniformRanges build_uniform(const ShaderInfo& info, uint32_t vtxStart, const BindGroupRanges& ranges, - const FrameInterpolationDrawIdentity& drawIdentity, bool perspective, - uint16_t usedPnMtxMask = 1) noexcept; -u8 color_channel(GXChannelID id) noexcept; -}; // namespace aurora::gx diff --git a/aurora-main/lib/gx/texture_bind_group_cache_key.hpp b/aurora-main/lib/gx/texture_bind_group_cache_key.hpp deleted file mode 100644 index 5cb78a0..0000000 --- a/aurora-main/lib/gx/texture_bind_group_cache_key.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -namespace aurora::gx { - -struct TextureBindGroupCacheKey { - std::uint64_t sampledTextures = 0; - std::uint64_t sampledIndTextures = 0; - std::array textureViews{}; - std::array mode0{}; - std::array mode1{}; - std::array refState{}; - - bool operator==(const TextureBindGroupCacheKey&) const = default; -}; - -inline void set_texture_bind_group_cache_slot(TextureBindGroupCacheKey& key, std::size_t slot, - const void* textureView, std::uint32_t mode0, - std::uint32_t mode1, std::uint32_t refState) noexcept { - key.textureViews[slot] = textureView; - key.mode0[slot] = mode0; - key.mode1[slot] = mode1; - key.refState[slot] = refState; -} - -} // namespace aurora::gx diff --git a/aurora-main/lib/imgui.cpp b/aurora-main/lib/imgui.cpp deleted file mode 100644 index 57d426f..0000000 --- a/aurora-main/lib/imgui.cpp +++ /dev/null @@ -1,266 +0,0 @@ -#include "imgui.hpp" - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "fs_helper.hpp" -#include "internal.hpp" -#include "webgpu/gpu.hpp" -#include "window.hpp" - -#define IMGUI_IMPL_WEBGPU_BACKEND_DAWN -#include "backends/imgui_impl_sdl3.h" -#include "backends/imgui_impl_sdlrenderer3.h" -#include "backends/imgui_impl_wgpu.h" -#include "tracy/Tracy.hpp" - -namespace aurora::imgui { -static float g_scale; -static std::string g_imguiLog{}; -static bool g_useSdlRenderer = false; -// Set once ImGui::Render() has produced this frame's draw data. Interpolation encodes up to four -// ImGui passes per frame, and every one of them used to rebuild the draw lists from scratch. -static bool g_frameDataBuilt = false; - -static std::vector g_sdlTextures; -static std::vector g_wgpuTextures; - -void remove_legacy_ini_file(const char* basePath) noexcept { - if (basePath == nullptr || *basePath == '\0') { - return; - } - - std::error_code ec; - std::filesystem::remove(fs_path_from_string(basePath) / "imgui.ini", ec); -} - -void create_context() noexcept { - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); - io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; - remove_legacy_ini_file(g_config.userPath); - remove_legacy_ini_file(g_config.cachePath); - g_imguiLog = std::string{g_config.cachePath} + "/imgui.log"; - io.IniFilename = nullptr; - io.LogFilename = g_imguiLog.c_str(); - ImGui::LoadIniSettingsFromMemory("", 0); - io.WantSaveIniSettings = false; -} - -void initialize() noexcept { - ZoneScoped; - SDL_Renderer* renderer = window::get_sdl_renderer(); - ImGui_ImplSDL3_InitForSDLRenderer(window::get_sdl_window(), renderer); - g_useSdlRenderer = renderer != nullptr; - if (g_useSdlRenderer) { - ImGui_ImplSDLRenderer3_Init(renderer); - } else { - ImGui_ImplWGPU_InitInfo info; - info.Device = webgpu::g_device.Get(); - info.RenderTargetFormat = static_cast(webgpu::g_graphicsConfig.surfaceConfiguration.format); - // Interpolation records up to four ImGui passes in one command buffer, so keep three logical - // frames of renderer resources to stop them overwriting each other's vertex/index buffers. - info.NumFramesInFlight = 12; - ImGui_ImplWGPU_Init(&info); - } -} - -void shutdown() noexcept { - ZoneScoped; - // Startup can fail before either backend initializes. A context alone does - // not mean its renderer/platform backend owns resources to release. - if (ImGui::GetCurrentContext() != nullptr) { - ImGuiIO& io = ImGui::GetIO(); - if (io.BackendRendererUserData != nullptr) { - if (g_useSdlRenderer) { - ImGui_ImplSDLRenderer3_Shutdown(); - } else { - ImGui_ImplWGPU_Shutdown(); - } - } - if (io.BackendPlatformUserData != nullptr) { - ImGui_ImplSDL3_Shutdown(); - } - ImGui::DestroyContext(); - } - for (const auto& texture : g_sdlTextures) { - SDL_DestroyTexture(texture); - } - g_sdlTextures.clear(); - g_wgpuTextures.clear(); - g_useSdlRenderer = false; - g_scale = 0.f; - g_frameDataBuilt = false; -} - -void process_event(const SDL_Event& event) noexcept { - auto renderEvent = event; - if (g_useSdlRenderer) { - if (SDL_Renderer* renderer = window::get_sdl_renderer()) { - SDL_ConvertEventToRenderCoordinates(renderer, &renderEvent); - } - } - ImGui_ImplSDL3_ProcessEvent(&renderEvent); -} - -bool wants_capture_event(const SDL_Event& event) noexcept { - if (ImGui::GetCurrentContext() == nullptr) { - return false; - } - - const ImGuiIO& io = ImGui::GetIO(); - switch (event.type) { - case SDL_EVENT_MOUSE_MOTION: - case SDL_EVENT_MOUSE_BUTTON_DOWN: - case SDL_EVENT_MOUSE_BUTTON_UP: - case SDL_EVENT_MOUSE_WHEEL: - case SDL_EVENT_FINGER_DOWN: - case SDL_EVENT_FINGER_MOTION: - case SDL_EVENT_FINGER_UP: - case SDL_EVENT_FINGER_CANCELED: - return io.WantCaptureMouse; - case SDL_EVENT_KEY_DOWN: - case SDL_EVENT_KEY_UP: - case SDL_EVENT_TEXT_INPUT: - return io.WantCaptureKeyboard || io.WantTextInput; - default: - return false; - } -} - -void new_frame(const AuroraWindowSize& size) noexcept { - ZoneScoped; - ImVec2 framebufferScale{ - size.width > 0 ? static_cast(size.native_fb_width) / static_cast(size.width) : 1.0f, - size.height > 0 ? static_cast(size.native_fb_height) / static_cast(size.height) : 1.0f, - }; - ImVec2 displaySize{static_cast(size.width), static_cast(size.height)}; - - if (g_useSdlRenderer) { - if (SDL_Renderer* renderer = window::get_sdl_renderer()) { - float renderScaleX = 1.0f; - float renderScaleY = 1.0f; - SDL_GetRenderScale(renderer, &renderScaleX, &renderScaleY); - if (renderScaleX > 0.0f && renderScaleY > 0.0f && - (std::fabs(renderScaleX - 1.0f) > 0.0001f || std::fabs(renderScaleY - 1.0f) > 0.0001f)) { - int outputWidth = static_cast(size.native_fb_width); - int outputHeight = static_cast(size.native_fb_height); - SDL_GetRenderOutputSize(renderer, &outputWidth, &outputHeight); - displaySize = { - static_cast(outputWidth) / renderScaleX, - static_cast(outputHeight) / renderScaleY, - }; - framebufferScale = {renderScaleX, renderScaleY}; - } - } - ImGui_ImplSDLRenderer3_NewFrame(); - g_scale = size.scale; - } else { - if (g_scale != size.scale) { - if (g_scale > 0.f) { - ImGui_ImplWGPU_CreateDeviceObjects(); - } - g_scale = size.scale; - } - if (!ImGui::GetIO().Fonts->IsBuilt()) { - ImGui_ImplWGPU_CreateDeviceObjects(); - } - ImGui_ImplWGPU_NewFrame(); - } - ImGui_ImplSDL3_NewFrame(); - - ImGuiIO& io = ImGui::GetIO(); - io.DisplayFramebufferScale = framebufferScale; - ImGui::GetIO().DisplaySize = displaySize; - ImGui::NewFrame(); - g_frameDataBuilt = false; -} - -void render_frame_data() noexcept { - ZoneScoped; - if (g_frameDataBuilt) { - return; - } - ImGui::Render(); - auto* data = ImGui::GetDrawData(); - data->FramebufferScale = ImGui::GetIO().DisplayFramebufferScale; - g_frameDataBuilt = true; -} - -void render(const wgpu::RenderPassEncoder& pass) noexcept { - ZoneScoped; - render_frame_data(); - - auto* data = ImGui::GetDrawData(); - if (g_useSdlRenderer) { - SDL_Renderer* renderer = window::get_sdl_renderer(); - SDL_RenderClear(renderer); - ImGui_ImplSDLRenderer3_RenderDrawData(data, renderer); - SDL_RenderPresent(renderer); - } else { - pass.PushDebugGroup("Aurora: Dear Imgui"); - ImGui_ImplWGPU_RenderDrawData(data, pass.Get()); - pass.PopDebugGroup(); - } -} - -ImTextureID add_texture(uint32_t width, uint32_t height, const uint8_t* data) noexcept { - if (SDL_Renderer* renderer = window::get_sdl_renderer()) { - SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, width, height); - SDL_UpdateTexture(texture, nullptr, data, width * 4); - SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_LINEAR); - g_sdlTextures.push_back(texture); - return reinterpret_cast(texture); - } - const wgpu::Extent3D size{ - .width = width, - .height = height, - .depthOrArrayLayers = 1, - }; - const wgpu::TextureDescriptor textureDescriptor{ - .label = "imgui texture", - .usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopyDst, - .dimension = wgpu::TextureDimension::e2D, - .size = size, - .format = wgpu::TextureFormat::RGBA8Unorm, - .mipLevelCount = 1, - .sampleCount = 1, - }; - const wgpu::TextureViewDescriptor textureViewDescriptor{ - .label = "imgui texture view", - .format = wgpu::TextureFormat::RGBA8Unorm, - .dimension = wgpu::TextureViewDimension::e2D, - .mipLevelCount = WGPU_MIP_LEVEL_COUNT_UNDEFINED, - .arrayLayerCount = WGPU_ARRAY_LAYER_COUNT_UNDEFINED, - }; - auto texture = webgpu::g_device.CreateTexture(&textureDescriptor); - auto textureView = texture.CreateView(&textureViewDescriptor); - { - const wgpu::TexelCopyTextureInfo dstView{ - .texture = texture, - }; - const wgpu::TexelCopyBufferLayout dataLayout{ - .bytesPerRow = 4 * width, - .rowsPerImage = height, - }; - webgpu::g_queue.WriteTexture(&dstView, data, width * height * 4, &dataLayout, &size); - } - g_wgpuTextures.push_back(texture); - return reinterpret_cast(textureView.MoveToCHandle()); -} -} // namespace aurora::imgui - -// C bindings -extern "C" { -ImTextureID aurora_imgui_add_texture(uint32_t width, uint32_t height, const void* rgba8) { - return aurora::imgui::add_texture(width, height, static_cast(rgba8)); -} -} diff --git a/aurora-main/lib/imgui.hpp b/aurora-main/lib/imgui.hpp deleted file mode 100644 index 908a122..0000000 --- a/aurora-main/lib/imgui.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include - -union SDL_Event; - -namespace wgpu { -class RenderPassEncoder; -} // namespace wgpu - -namespace aurora::imgui { -void create_context() noexcept; -void initialize() noexcept; -void shutdown() noexcept; - -void process_event(const SDL_Event& event) noexcept; -bool wants_capture_event(const SDL_Event& event) noexcept; -void new_frame(const AuroraWindowSize& size) noexcept; -// Build this frame's ImGui draw data. Idempotent for the rest of the frame: the lists are built -// once and every presentation slot replays them. Reset by new_frame. -void render_frame_data() noexcept; -void render(const wgpu::RenderPassEncoder& pass) noexcept; -} // namespace aurora::imgui diff --git a/aurora-main/lib/imgui_config.cpp b/aurora-main/lib/imgui_config.cpp deleted file mode 100644 index e06eecb..0000000 --- a/aurora-main/lib/imgui_config.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include - -#include - -#include - -ImFileHandle ImFileOpen(const char* filename, const char* mode) { - if (filename == nullptr || mode == nullptr) { - return nullptr; - } - return SDL_IOFromFile(filename, mode); -} - -bool ImFileClose(ImFileHandle file) { return file == nullptr || SDL_CloseIO(file); } - -ImU64 ImFileGetSize(ImFileHandle file) { - if (file == nullptr) { - return static_cast(-1); - } - const Sint64 size = SDL_GetIOSize(file); - if (size < 0) { - return static_cast(-1); - } - return static_cast(size); -} - -ImU64 ImFileRead(void* data, ImU64 size, ImU64 count, ImFileHandle file) { - ImU64 byteCount = size * count; - if (file == nullptr || data == nullptr || byteCount == 0) { - return 0; - } - - ImU64 totalRead = 0; - auto* dst = static_cast(data); - while (totalRead < byteCount) { - const size_t read = SDL_ReadIO(file, dst + totalRead, byteCount - totalRead); - if (read == 0) { - return totalRead / size; - } - totalRead += read; - } - return count; -} - -ImU64 ImFileWrite(const void* data, ImU64 size, ImU64 count, ImFileHandle file) { - ImU64 byteCount = size * count; - if (file == nullptr || data == nullptr || byteCount == 0) { - return 0; - } - - ImU64 totalWritten = 0; - auto* src = static_cast(data); - while (totalWritten < byteCount) { - const size_t written = SDL_WriteIO(file, src + totalWritten, byteCount - totalWritten); - if (written == 0) { - return totalWritten / size; - } - totalWritten += written; - } - return count; -} diff --git a/aurora-main/lib/input.cpp b/aurora-main/lib/input.cpp deleted file mode 100644 index ccd1e0a..0000000 --- a/aurora-main/lib/input.cpp +++ /dev/null @@ -1,622 +0,0 @@ -#include "input.hpp" -#include "internal.hpp" - -#include "magic_enum.hpp" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -using namespace std::string_view_literals; - -namespace aurora::input { -Module Log("aurora::input"); -absl::flat_hash_map g_GameControllers; - -namespace { -constexpr uint32_t kPortPreferencesMagic = SBIG('CPRT'); -constexpr uint32_t kPortPreferencesVersion = 3; -constexpr uint32_t kMaxPersistedStringLength = 256; - -enum class PortPreferenceState : uint8_t { - Unset = 0, - None = 1, - Controller = 2, -}; - -struct ControllerIdentity { - std::string guid; - std::string serial; - std::string path; - int32_t slot = -1; -}; - -struct PortPreference { - PortPreferenceState state = PortPreferenceState::Unset; - ControllerIdentity identity; -}; - -std::array g_portPreferences; -bool g_portPreferencesLoaded = false; -// Startup controllers are added one by one via events; capture their SDL player index at init, -// before earlier port reassignments can move it. -absl::flat_hash_map g_connectSlots; - -std::string port_preferences_path() { - if (g_config.userPath == nullptr) { - return {}; - } - - std::string path{g_config.userPath}; - if (!path.empty() && path.back() != '/' && path.back() != '\\') { - path += '/'; - } - path += "controller_ports.dat"; - return path; -} - -std::string normalize_serial(const char* serial) { - std::string normalized; - if (serial == nullptr) { - return normalized; - } - - for (const char* c = serial; *c != '\0'; ++c) { - if (*c == ':' || *c == '-') { - continue; - } - normalized += *c >= 'A' && *c <= 'Z' ? static_cast(*c - 'A' + 'a') : *c; - } - return normalized; -} - -bool serial_matches(const std::string& saved, const std::string& current) { - return !saved.empty() && !current.empty() && normalize_serial(saved.c_str()) == normalize_serial(current.c_str()); -} - -ControllerIdentity controller_identity(const GameController& controller) { - ControllerIdentity identity; - char guid[33] = {}; - SDL_GUIDToString(SDL_GetGamepadGUIDForID(SDL_GetGamepadID(controller.m_controller)), guid, sizeof(guid)); - identity.guid = guid; - identity.serial = normalize_serial(SDL_GetGamepadSerial(controller.m_controller)); - identity.path = controller.m_path; - identity.slot = controller.m_slot; - return identity; -} - -bool read_exact(SDL_IOStream* file, void* dst, size_t size) { - auto* bytes = static_cast(dst); - size_t total = 0; - while (total < size) { - const size_t read = SDL_ReadIO(file, bytes + total, size - total); - if (read == 0) { - return false; - } - total += read; - } - return true; -} - -bool write_exact(SDL_IOStream* file, const void* src, size_t size) { - auto* bytes = static_cast(src); - size_t total = 0; - while (total < size) { - const size_t written = SDL_WriteIO(file, bytes + total, size - total); - if (written == 0) { - return false; - } - total += written; - } - return true; -} - -template -bool read_value(SDL_IOStream* file, T& value) { - return read_exact(file, &value, sizeof(value)); -} - -template -bool write_value(SDL_IOStream* file, const T& value) { - return write_exact(file, &value, sizeof(value)); -} - -bool read_string(SDL_IOStream* file, std::string& value) { - uint32_t size = 0; - if (!read_value(file, size) || size > kMaxPersistedStringLength) { - return false; - } - - value.resize(size); - return size == 0 || read_exact(file, value.data(), size); -} - -bool write_string(SDL_IOStream* file, const std::string& value) { - const uint32_t size = static_cast(std::min(value.size(), kMaxPersistedStringLength)); - return write_value(file, size) && (size == 0 || write_exact(file, value.data(), size)); -} - -bool read_identity(SDL_IOStream* file, uint32_t version, ControllerIdentity& identity) { - if (!read_string(file, identity.guid) || !read_string(file, identity.serial)) { - return false; - } - return version < 3 || (read_string(file, identity.path) && read_value(file, identity.slot)); -} - -bool write_identity(SDL_IOStream* file, const ControllerIdentity& identity) { - return write_string(file, identity.guid) && write_string(file, identity.serial) && - write_string(file, identity.path) && write_value(file, identity.slot); -} - -bool read_port_preferences_file(std::array& preferences) { - const auto path = port_preferences_path(); - if (path.empty()) { - return true; - } - - SDL_IOStream* file = SDL_IOFromFile(path.c_str(), "rb"); - if (file == nullptr) { - return true; - } - - uint32_t magic = 0; - uint32_t version = 0; - bool ok = read_value(file, magic) && read_value(file, version) && magic == kPortPreferencesMagic && - version >= 2 && version <= kPortPreferencesVersion; - - for (auto& preference : preferences) { - uint8_t state = 0; - ControllerIdentity identity; - ok = ok && read_value(file, state) && state <= static_cast(PortPreferenceState::Controller) && - read_identity(file, version, identity); - if (ok) { - preference.state = static_cast(state); - preference.identity = std::move(identity); - } - } - - SDL_CloseIO(file); - if (!ok) { - Log.warn("Ignoring invalid controller port preference file '{}'", path); - } - return ok; -} - -void ensure_port_preferences_loaded() { - if (g_portPreferencesLoaded) { - return; - } - - std::array preferences; - if (read_port_preferences_file(preferences)) { - g_portPreferences = std::move(preferences); - } - g_portPreferencesLoaded = true; -} - -void save_port_preferences() { - const auto path = port_preferences_path(); - if (path.empty()) { - return; - } - - if (!SDL_CreateDirectory(g_config.userPath)) { - Log.warn("Failed to create controller port preference directory '{}': {}", g_config.userPath, SDL_GetError()); - return; - } - - SDL_IOStream* file = SDL_IOFromFile(path.c_str(), "wb"); - if (file == nullptr) { - Log.warn("Failed to open controller port preference file '{}': {}", path, SDL_GetError()); - return; - } - - bool ok = write_value(file, kPortPreferencesMagic) && write_value(file, kPortPreferencesVersion); - for (const auto& preference : g_portPreferences) { - const auto state = static_cast(preference.state); - ok = ok && write_value(file, state) && write_identity(file, preference.identity); - } - - if (!SDL_FlushIO(file)) { - ok = false; - } - if (!SDL_CloseIO(file)) { - ok = false; - } - if (!ok) { - Log.warn("Failed to write controller port preference file '{}': {}", path, SDL_GetError()); - } -} - -// Zero means no match. Higher scores claim ports first: path+slot > GUID > VID/PID. -constexpr int kScoreVidPid = 1; -constexpr int kScoreGuid = 2; -constexpr int kScoreSlot = 1; -constexpr int kScorePath = 2; - -int identity_score(const ControllerIdentity& saved, const ControllerIdentity& current) { - if (saved.guid.empty()) { - return 0; - } - if (saved.guid == current.guid) { - if (!saved.serial.empty() && !serial_matches(saved.serial, current.serial)) { - return 0; - } - int score = kScoreGuid; - if (!saved.path.empty() && saved.path == current.path) { - score += kScorePath; - } - if (saved.slot >= 0 && saved.slot == current.slot) { - score += kScoreSlot; - } - return score; - } - if (!serial_matches(saved.serial, current.serial)) { - return 0; - } - - // Attempt to match against VID/PID as a fallback if the GUID changes - uint16_t savedVendor = 0; - uint16_t savedProduct = 0; - uint16_t currentVendor = 0; - uint16_t currentProduct = 0; - SDL_GetJoystickGUIDInfo(SDL_StringToGUID(saved.guid.c_str()), &savedVendor, &savedProduct, nullptr, nullptr); - SDL_GetJoystickGUIDInfo(SDL_StringToGUID(current.guid.c_str()), ¤tVendor, ¤tProduct, nullptr, nullptr); - const bool sameDevice = - savedVendor != 0 && savedVendor == currentVendor && savedProduct != 0 && savedProduct == currentProduct; - return sameDevice ? kScoreVidPid : 0; -} - -void assign_player_index(GameController& controller, int32_t port) { - SDL_SetGamepadPlayerIndex(controller.m_controller, port); - controller.m_playerIndex = port; -} - -// SDL forgets the index for devices mapped after connect, so player_index() falls -// back to the cached copy; both have to move together or a port looks doubly taken. -int32_t effective_player_index(const GameController& controller) { - const int32_t player = SDL_GetGamepadPlayerIndex(controller.m_controller); - return player >= 0 ? player : controller.m_playerIndex; -} - -void apply_port_preferences() noexcept { - ensure_port_preferences_loaded(); - if (!std::any_of(g_portPreferences.begin(), g_portPreferences.end(), - [](const auto& preference) { return preference.state != PortPreferenceState::Unset; })) { - return; - } - - for (auto& [instance, controller] : g_GameControllers) { - const int32_t player = effective_player_index(controller); - if (player >= 0 && player < PAD_MAX_CONTROLLERS && g_portPreferences[player].state != PortPreferenceState::Unset) { - // Keep SDL's default player assignment from taking explicitly configured ports - assign_player_index(controller, -1); - } - } - - struct Candidate { - int score; - uint32_t port; - Uint32 instance; - }; - std::vector candidates; - for (const auto& [instance, controller] : g_GameControllers) { - const auto identity = controller_identity(controller); - for (uint32_t port = 0; port < g_portPreferences.size(); ++port) { - if (g_portPreferences[port].state != PortPreferenceState::Controller) { - continue; - } - if (const int score = identity_score(g_portPreferences[port].identity, identity); score > 0) { - candidates.push_back({score, port, instance}); - } - } - } - // Best matches claim first so identical controllers each end up on their own port - std::sort(candidates.begin(), candidates.end(), [](const Candidate& a, const Candidate& b) { - if (a.score != b.score) { - return a.score > b.score; - } - return a.port != b.port ? a.port < b.port : a.instance < b.instance; - }); - - std::array portClaimed{}; - std::array claimedInstances{}; - size_t claimedCount = 0; - bool upgraded = false; - for (const auto& candidate : candidates) { - if (portClaimed[candidate.port] || - std::find(claimedInstances.begin(), claimedInstances.begin() + claimedCount, candidate.instance) != - claimedInstances.begin() + claimedCount) { - continue; - } - portClaimed[candidate.port] = true; - claimedInstances[claimedCount++] = candidate.instance; - auto& controller = g_GameControllers[candidate.instance]; - assign_player_index(controller, static_cast(candidate.port)); - - // Preferences saved before path and slot existed gain them on their first GUID match - auto& saved = g_portPreferences[candidate.port].identity; - if (candidate.score >= kScoreGuid && (saved.path.empty() || saved.slot < 0)) { - const auto current = controller_identity(controller); - if (saved.path.empty() && !current.path.empty()) { - saved.path = current.path; - upgraded = true; - } - if (saved.slot < 0 && current.slot >= 0) { - saved.slot = current.slot; - upgraded = true; - } - } - } - if (upgraded) { - save_port_preferences(); - } -} - -// SDL only hands out a player index when the device already had a gamepad mapping -// at connect time, so anything mapped later (the setup wizard) stays at -1. -void ensure_player_index(GameController& controller) noexcept { - const int32_t player = SDL_GetGamepadPlayerIndex(controller.m_controller); - if (player >= 0) { - controller.m_playerIndex = player; - return; - } - if (controller.m_playerIndex >= 0) { - return; - } - ensure_port_preferences_loaded(); - const auto claim = [&](bool skipConfiguredPorts) { - for (int32_t port = 0; port < PAD_MAX_CONTROLLERS; ++port) { - if (skipConfiguredPorts && g_portPreferences[port].state != PortPreferenceState::Unset) { - continue; - } - const bool taken = std::any_of(g_GameControllers.begin(), g_GameControllers.end(), [&](const auto& entry) { - return entry.second.m_controller != controller.m_controller && effective_player_index(entry.second) == port; - }); - if (!taken) { - assign_player_index(controller, port); - return true; - } - } - return false; - }; - // Explicitly configured ports are only used as a last resort so a hot-plugged - // controller cannot steal the port its preferred device will claim. - if (!claim(true)) { - claim(false); - } -} -} // namespace - -GameController* get_controller_for_player(uint32_t player) noexcept { - for (auto& [which, controller] : g_GameControllers) { - if (player_index(which) == player) { - return &controller; - } - } - - return nullptr; -} - -Sint32 get_instance_for_player(uint32_t player) noexcept { - for (const auto& [which, controller] : g_GameControllers) { - if (player_index(which) == player) { - return which; - } - } - - return {}; -} - -SDL_JoystickID add_controller(SDL_JoystickID which) noexcept { - if (g_GameControllers.contains(which)) { - return which; - } - auto* ctrl = SDL_OpenGamepad(which); - if (ctrl != nullptr) { - GameController controller; - controller.m_controller = ctrl; - controller.m_index = which; - controller.m_vid = SDL_GetGamepadVendor(ctrl); - controller.m_pid = SDL_GetGamepadProduct(ctrl); - if (controller.m_vid == 0x05ac /* USB_VENDOR_APPLE */ && controller.m_pid == 3) { - // Ignore Apple TV remote - SDL_CloseGamepad(ctrl); - return -1; - } - controller.m_isGameCube = controller.m_vid == 0x057E && controller.m_pid == 0x0337; - if (const char* path = SDL_GetGamepadPath(ctrl); path != nullptr) { - controller.m_path = path; - } - if (const auto slot = g_connectSlots.find(which); slot != g_connectSlots.end()) { - controller.m_slot = slot->second; - g_connectSlots.erase(slot); - } else { - controller.m_slot = SDL_GetGamepadPlayerIndex(ctrl); - } - const char* serial = SDL_GetGamepadSerial(ctrl); - controller.m_gameCubeUseOrdinaryStop = controller.m_isGameCube && serial && "GCP+"sv == serial; - if (controller.m_isGameCube || - (SDL_GetGamepadType(ctrl) == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO && controller.m_pid == 0x2073)) { - controller.m_deadZones.emulateTriggers = false; - } - const auto props = SDL_GetGamepadProperties(ctrl); - controller.m_hasRumble = SDL_GetBooleanProperty(props, SDL_PROP_GAMEPAD_CAP_RUMBLE_BOOLEAN, true); - controller.m_hasRgbLed = SDL_GetBooleanProperty(props, SDL_PROP_GAMEPAD_CAP_RGB_LED_BOOLEAN, false); - SDL_JoystickID instance = SDL_GetJoystickID(SDL_GetGamepadJoystick(ctrl)); - g_GameControllers[instance] = controller; - ensure_player_index(g_GameControllers[instance]); - apply_port_preferences(); -#if defined(SDL_PLATFORM_MACOS) - // First-use convenience only: never override a saved assignment or None. - if (g_portPreferences[0].state == PortPreferenceState::Unset) { - bool hasOtherPortPreference = false; - for (size_t port = 1; port < g_portPreferences.size(); ++port) { - if (g_portPreferences[port].state == PortPreferenceState::Controller && - identity_score(g_portPreferences[port].identity, controller_identity(g_GameControllers[instance])) > 0) { - hasOtherPortPreference = true; - break; - } - } - if (!hasOtherPortPreference) { - const auto* p0 = get_controller_for_player(0); - if (p0 == nullptr) { - assign_player_index(g_GameControllers[instance], 0); - persist_controller_for_player(0, &g_GameControllers[instance]); - } else if (p0 == &g_GameControllers[instance]) { - persist_controller_for_player(0, &g_GameControllers[instance]); - } - } - } -#endif - return instance; - } - - return -1; -} - -bool refresh_controller(SDL_JoystickID instance) noexcept { - const auto it = g_GameControllers.find(instance); - if (it == g_GameControllers.end()) { - return false; - } - // The SDL mapping changed underneath us; drop the cached PAD bindings so they - // are rebuilt from the new one. - it->second.m_mappingLoaded = false; - ensure_player_index(it->second); - apply_port_preferences(); - return true; -} - -void remove_controller(Uint32 instance) noexcept { - g_connectSlots.erase(instance); - if (auto it = g_GameControllers.find(instance); it != g_GameControllers.end()) { - SDL_CloseGamepad(it->second.m_controller); - g_GameControllers.erase(it); - apply_port_preferences(); - } -} - -bool is_gamecube(Uint32 instance) noexcept { - if (auto it = g_GameControllers.find(instance); it != g_GameControllers.end()) { - return it->second.m_isGameCube; - } - return false; -} - -int32_t player_index(Uint32 instance) noexcept { - if (auto it = g_GameControllers.find(instance); it != g_GameControllers.end()) { - const int player = SDL_GetGamepadPlayerIndex(it->second.m_controller); - return player >= 0 ? player : it->second.m_playerIndex; - } - return -1; -} - -void set_player_index(Uint32 instance, Sint32 index) noexcept { - if (auto it = g_GameControllers.find(instance); it != g_GameControllers.end()) { - SDL_SetGamepadPlayerIndex(it->second.m_controller, index); - it->second.m_playerIndex = index; - } -} - -std::string controller_name(Uint32 instance) noexcept { - if (auto it = g_GameControllers.find(instance); it != g_GameControllers.end()) { - const auto* name = SDL_GetGamepadName(it->second.m_controller); - if (name != nullptr) { - return {name}; - } - } - return {}; -} - -bool controller_has_rumble(Uint32 instance) noexcept { - if (auto it = g_GameControllers.find(instance); it != g_GameControllers.end()) { - return it->second.m_hasRumble; - } - return false; -} - -void controller_rumble(uint32_t instance, uint16_t low_freq_intensity, uint16_t high_freq_intensity, - uint16_t duration_ms) noexcept { - if (auto it = g_GameControllers.find(instance); it != g_GameControllers.end()) { - // GC Pocket+ has been observed continuing to vibrate after a hard stop; - // an ordinary stop cleared it. With GAMECUBE_RUMBLE_BRAKE enabled, SDL - // encodes (0, 1) as adapter command 0, whereas (0, 0) sends command 2. - // Apply the workaround here so shutdown uses the same stop as PAD calls. - if (it->second.m_gameCubeUseOrdinaryStop && low_freq_intensity == 0 && high_freq_intensity == 0) { - high_freq_intensity = 1; - } - SDL_RumbleGamepad(it->second.m_controller, low_freq_intensity, high_freq_intensity, duration_ms); - } -} - -uint32_t controller_count() noexcept { return g_GameControllers.size(); } - -void persist_controller_for_player(uint32_t player, const GameController* controller) noexcept { - if (player >= PAD_MAX_CONTROLLERS) { - return; - } - - ensure_port_preferences_loaded(); - if (controller != nullptr) { - g_portPreferences[player].state = PortPreferenceState::Controller; - g_portPreferences[player].identity = controller_identity(*controller); - } else { - g_portPreferences[player].state = PortPreferenceState::None; - g_portPreferences[player].identity = {}; - } - save_port_preferences(); -} - -void initialize() noexcept { - /* Make sure we initialize everything input related now, this will automatically add all of the connected controllers - * as expected */ - ASSERT(SDL_Init(SDL_INIT_HAPTIC | SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD), "Failed to initialize SDL subsystems: {}", - SDL_GetError()); - - int count = 0; - if (SDL_JoystickID* ids = SDL_GetGamepads(&count)) { - for (int i = 0; i < count; ++i) { - g_connectSlots[ids[i]] = SDL_GetGamepadPlayerIndexForID(ids[i]); - } - SDL_free(ids); - } -} - -struct MouseScrollStatus { - float scrollX; - float scrollY; -}; - -static MouseScrollStatus g_MouseStatus; - -void set_mouse_scroll(const float scrollX, const float scrollY) noexcept { - g_MouseStatus.scrollX = scrollX; - g_MouseStatus.scrollY = scrollY; -} - -void get_mouse_scroll(float* scrollX, float* scrollY) noexcept { - *scrollX = g_MouseStatus.scrollX; - *scrollY = g_MouseStatus.scrollY; -} - -void shutdown() noexcept { - // Upon shutdown we want to ensure all controllers are in a default state, so force all rumble supporting controllers - // to shut off their rumble motors. - for (const auto& controller : g_GameControllers) { - if (!controller.second.m_hasRumble) { - continue; - } - controller_rumble(controller.first, 0, 0, 0); - } -} -} // namespace aurora::input diff --git a/aurora-main/lib/input.hpp b/aurora-main/lib/input.hpp deleted file mode 100644 index 2740ad6..0000000 --- a/aurora-main/lib/input.hpp +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once - -#include -#include -#include "dolphin/pad.h" // For PADDeaZones and PADButtonMapping -#include "SDL3/SDL_gamepad.h" -#include "SDL3/SDL_keyboard.h" -#include "SDL3/SDL_keycode.h" -#include "SDL3/SDL_mouse.h" -#include "logging.hpp" - -#include - -namespace aurora::input { -extern Module Log; - -struct GameController { - SDL_Gamepad* m_controller = nullptr; - bool m_isGameCube = false; - bool m_gameCubeUseOrdinaryStop = false; - Sint32 m_index = -1; - Sint32 m_playerIndex = -1; - // Device path and the SDL player index at connect (the adapter port for GameCube adapters). - std::string m_path; - Sint32 m_slot = -1; - bool m_hasRumble = false; - PADDeadZones m_deadZones{ - .emulateTriggers = true, - .useDeadzones = true, - .stickDeadZone = 8000, - .substickDeadZone = 8000, - .leftTriggerActivationZone = 31150, - .rightTriggerActivationZone = 31150, - }; - uint16_t m_vid = 0; - uint16_t m_pid = 0; - std::array m_buttonMapping{}; - // Secondary binding per GC button; not persisted in .controller files, the - // runtime re-applies it from its own config whenever a controller attaches. - std::array m_altButtonMapping{}; - std::array m_axisMapping{}; - uint16_t m_rumbleIntensityLow = 32767; - uint16_t m_rumbleIntensityHigh = 32767; - bool m_mappingLoaded = false; - constexpr bool operator==(const GameController& other) const { - return m_controller == other.m_controller && m_index == other.m_index; - } - uint8_t m_ledRed = 0xFF; - uint8_t m_ledGreen = 0xFF; - uint8_t m_ledBlue = 0xFF; - bool m_isColorDirty = true; - bool m_hasRgbLed = false; -}; - -GameController* get_controller_for_player(uint32_t player) noexcept; -Sint32 get_instance_for_player(uint32_t player) noexcept; -SDL_JoystickID add_controller(SDL_JoystickID which) noexcept; -bool refresh_controller(SDL_JoystickID instance) noexcept; -void remove_controller(Uint32 instance) noexcept; -Sint32 player_index(Uint32 instance) noexcept; -void set_player_index(Uint32 instance, Sint32 index) noexcept; -std::string controller_name(Uint32 instance) noexcept; -bool is_gamecube(Uint32 instance) noexcept; -bool controller_has_rumble(Uint32 instance) noexcept; -void controller_rumble(uint32_t instance, uint16_t low_freq_intensity, uint16_t high_freq_intensity, - uint16_t duration_ms) noexcept; -uint32_t controller_count() noexcept; -void initialize() noexcept; -void persist_controller_for_player(uint32_t player, const GameController* controller) noexcept; -extern absl::flat_hash_map g_GameControllers; - -void set_mouse_scroll(float scrollX, float scrollY) noexcept; -void get_mouse_scroll(float* scrollX, float* scrollY) noexcept; - -void shutdown() noexcept; -} // namespace aurora::input diff --git a/aurora-main/lib/internal.hpp b/aurora-main/lib/internal.hpp deleted file mode 100644 index 81699ae..0000000 --- a/aurora-main/lib/internal.hpp +++ /dev/null @@ -1,200 +0,0 @@ -#pragma once - -#include "logging.hpp" // IWYU pragma: keep - -#include - -#include -#include -#include -#include -#include -#include -#include - -using namespace std::string_view_literals; - -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#ifndef SBIG -#define SBIG(q) \ - (((q) & 0x000000FF) << 24 | ((q) & 0x0000FF00) << 8 | ((q) & 0x00FF0000) >> 8 | ((q) & 0xFF000000) >> 24) -#endif -#else -#ifndef SBIG -#define SBIG(q) (q) -#endif -#endif - -template - requires(sizeof(T) == sizeof(uint16_t) && std::is_arithmetic_v) -constexpr T bswap(T val) noexcept { - union { - uint16_t u; - T t; - } v{.t = val}; -#if __GNUC__ - v.u = __builtin_bswap16(v.u); -#elif _WIN32 - v.u = _byteswap_ushort(v.u); -#else - v.u = (v.u << 8) | ((v.u >> 8) & 0xFF); -#endif - return v.t; -} - -template - requires(sizeof(T) == sizeof(uint32_t) && std::is_arithmetic_v) -constexpr T bswap(T val) noexcept { - union { - uint32_t u; - T t; - } v{.t = val}; -#if __GNUC__ - v.u = __builtin_bswap32(v.u); -#elif _WIN32 - v.u = _byteswap_ulong(v.u); -#else - v.u = ((v.u & 0x0000FFFF) << 16) | ((v.u & 0xFFFF0000) >> 16) | ((v.u & 0x00FF00FF) << 8) | ((v.u & 0xFF00FF00) >> 8); -#endif - return v.t; -} - -template - requires(sizeof(T) == sizeof(uint64_t) && std::is_arithmetic_v) -constexpr T bswap(T val) noexcept { - union { - uint64_t u; - T t; - } v{.t = val}; -#if __GNUC__ - v.u = __builtin_bswap64(v.u); -#elif _WIN32 - v.u = _byteswap_uint64(v.u); -#else - static_assert(false, "bswap 64bit not implemented on this target"); -#endif - return v.t; -} - -template - requires(std::is_enum_v) -auto underlying(T value) -> std::underlying_type_t { - return static_cast>(value); -} - -#define AURORA_ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) - -#define POINTER_ADD_TYPE(type_, ptr_, offset_) ((type_)((uintptr_t)(ptr_) + (uintptr_t)(offset_))) -#define POINTER_ADD(ptr_, offset_) POINTER_ADD_TYPE(decltype(ptr_), ptr_, offset_) - -#if !defined(__has_cpp_attribute) -#define __has_cpp_attribute(name) 0 -#endif -#if __has_cpp_attribute(unlikely) -#define UNLIKELY [[unlikely]] -#else -#define UNLIKELY -#endif -#if __has_cpp_attribute(likely) -#define LIKELY [[likely]] -#else -#define LIKELY -#endif -#define FATAL(msg, ...) Log.fatal(msg, ##__VA_ARGS__); -#define ASSERT(cond, msg, ...) \ - if (!(cond)) \ - UNLIKELY FATAL(msg, ##__VA_ARGS__) -#ifdef NDEBUG -#define CHECK(cond, msg, ...) -#else -#define CHECK(cond, msg, ...) ASSERT(cond, msg, ##__VA_ARGS__) -#endif -#define DEFAULT_FATAL(msg, ...) UNLIKELY default : FATAL(msg, ##__VA_ARGS__) -#define TRY(cond, msg, ...) \ - if (!(cond)) \ - UNLIKELY { \ - Log.error(msg, ##__VA_ARGS__); \ - return false; \ - } -#define TRY_WARN(cond, msg, ...) \ - if (!(cond)) \ - UNLIKELY { Log.warn(msg, ##__VA_ARGS__); } - -#define UNIMPLEMENTED() FATAL("UNIMPLEMENTED: {}", __FUNCTION__) - -namespace wgpu { class CommandBuffer; } - -namespace aurora { -void submit_staging_commands(const wgpu::CommandBuffer& commands); -extern AuroraConfig g_config; -extern uint32_t g_sdlCustomEventsStart; -extern char g_gameName[4]; - -// wait_for_frame_worker() joins the DONE phase (ImGui, surface, sealing another frame need this). -// wait_for_frame_worker_sealed() joins only SEALED, which is what the FIFO drain uses. -void wait_for_frame_worker() noexcept; -std::chrono::nanoseconds wait_for_frame_worker_sealed() noexcept; -bool wait_for_frame_worker_for(std::chrono::microseconds timeout) noexcept; -std::recursive_mutex& renderer_gpu_mutex() noexcept; - -template -class ArrayRef { -public: - using value_type = std::remove_cvref_t; - using pointer = value_type*; - using const_pointer = const value_type*; - using reference = value_type&; - using const_reference = const value_type&; - using iterator = const_pointer; - using const_iterator = const_pointer; - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - - ArrayRef() = default; - explicit ArrayRef(const T& one) : ptr(&one), length(1) {} - ArrayRef(const T* data, size_t length) : ptr(data), length(length) {} - ArrayRef(const T* begin, const T* end) : ptr(begin), length(end - begin) {} - template - constexpr ArrayRef(const T (&arr)[N]) : ptr(arr), length(N) {} - template - constexpr ArrayRef(const std::array& arr) : ptr(arr.data()), length(arr.size()) {} - ArrayRef(const std::vector& vec) : ptr(vec.data()), length(vec.size()) {} - - const T* data() const { return ptr; } - size_t size() const { return length; } - bool empty() const { return length == 0; } - - const T& front() const { - assert(!empty()); - return ptr[0]; - } - const T& back() const { - assert(!empty()); - return ptr[length - 1]; - } - const T& operator[](size_t i) const { - assert(i < length && "Invalid index!"); - return ptr[i]; - } - - iterator begin() const { return ptr; } - iterator end() const { return ptr + length; } - - reverse_iterator rbegin() const { return reverse_iterator(end()); } - reverse_iterator rend() const { return reverse_iterator(begin()); } - - /// Disallow accidental assignment from a temporary. - template - std::enable_if_t::value, ArrayRef>& operator=(U&& Temporary) = delete; - - /// Disallow accidental assignment from a temporary. - template - std::enable_if_t::value, ArrayRef>& operator=(std::initializer_list) = delete; - -private: - const T* ptr = nullptr; - size_t length = 0; -}; -} // namespace aurora diff --git a/aurora-main/lib/logging.cpp b/aurora-main/lib/logging.cpp deleted file mode 100644 index 609d5d2..0000000 --- a/aurora-main/lib/logging.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "logging.hpp" - -#include -#include -#include - -#include -#include -#include - -#if defined(_WIN32) -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#endif - -namespace aurora { -extern AuroraConfig g_config; - -void Module::show_fatal_dialog(const char* module, std::string_view message) noexcept { - try { - std::string body = "Aurora stopped because of a fatal renderer error"; - if (module != nullptr && module[0] != '\0') { - body += " in "; - body += module; - } - body += ":\n\n"; - body.append(message.data(), message.size()); - body += "\n\nSee the console and log files for more details."; -#if defined(_WIN32) - ::MessageBoxA(nullptr, body.c_str(), "Aurora fatal error", - MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TASKMODAL); -#else - std::fprintf(stderr, "[aurora] fatal dialog: %s\n", body.c_str()); -#endif - } catch (...) { - // Fatal reporting must never hide the original abort. - } -} - -void log_internal(const AuroraLogLevel level, const char* module, const char* message, - const unsigned int len) noexcept { - if (module == nullptr) { - module = ""; - } - if (g_config.logCallback == nullptr) { - fmt::println(stderr, "[{}] [{}] {}", level, module, std::string_view(message, len)); - } else { - g_config.logCallback(level, module, message, len); - } -} -} // namespace aurora - -auto fmt::formatter::format(const AuroraLogLevel level, format_context& ctx) const - -> format_context::iterator { - std::string_view name = "unknown"; - switch (level) { - case LOG_DEBUG: - name = "debug"; - break; - case LOG_INFO: - name = "info"; - break; - case LOG_WARNING: - name = "warning"; - break; - case LOG_ERROR: - name = "error"; - break; - case LOG_FATAL: - name = "fatal"; - break; - default: - break; - } - return formatter::format(name, ctx); -} diff --git a/aurora-main/lib/logging.hpp b/aurora-main/lib/logging.hpp deleted file mode 100644 index 13f9314..0000000 --- a/aurora-main/lib/logging.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include - -#include -#include - -#include -#include - -namespace aurora { -void log_internal(AuroraLogLevel level, const char* module, const char* message, unsigned int len) noexcept; - -extern AuroraConfig g_config; - -struct Module { - const char* name; - explicit Module(const char* name) noexcept : name(name) {} - - template - void report(const AuroraLogLevel level, fmt::format_string fmt, T&&... args) noexcept { - if (g_config.logLevel > level) return; - - auto message = fmt::format(fmt, std::forward(args)...); - log_internal(level, name, message.c_str(), static_cast(message.size())); - } - - template - void debug(fmt::format_string fmt, T&&... args) noexcept { - report(LOG_DEBUG, fmt, std::forward(args)...); - } - - template - void info(fmt::format_string fmt, T&&... args) noexcept { - report(LOG_INFO, fmt, std::forward(args)...); - } - - template - void warn(fmt::format_string fmt, T&&... args) noexcept { - report(LOG_WARNING, fmt, std::forward(args)...); - } - - template - void error(fmt::format_string fmt, T&&... args) noexcept { - report(LOG_ERROR, fmt, std::forward(args)...); - } - - template - [[noreturn]] void fatal(fmt::format_string fmt, T&&... args) noexcept { - auto message = fmt::format(fmt, std::forward(args)...); - log_internal(LOG_FATAL, name, message.c_str(), static_cast(message.size())); - // Embedders can provide a fatal log callback, which the runtime uses for its own crash dialog. - // Standalone Aurora builds fall back to logging.cpp's native one. - if (g_config.logCallback == nullptr) { - show_fatal_dialog(name, message); - } - std::abort(); - } - -private: - static void show_fatal_dialog(const char* module, std::string_view message) noexcept; -}; -} // namespace aurora - -template <> -struct fmt::formatter : formatter { - auto format(AuroraLogLevel level, format_context& ctx) const -> format_context::iterator; -}; diff --git a/aurora-main/lib/main.cpp b/aurora-main/lib/main.cpp deleted file mode 100644 index 8a7fbee..0000000 --- a/aurora-main/lib/main.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include -#undef main - -#include - -int main(int argc, char** argv) { return aurora_main(argc, argv); } diff --git a/aurora-main/lib/sqlite_utils.hpp b/aurora-main/lib/sqlite_utils.hpp deleted file mode 100644 index 38db46b..0000000 --- a/aurora-main/lib/sqlite_utils.hpp +++ /dev/null @@ -1,77 +0,0 @@ -#pragma once - -#include "internal.hpp" - -#include - -namespace aurora::sqlite { - -inline int exec(sqlite3* db, const char* sql) { return sqlite3_exec(db, sql, nullptr, nullptr, nullptr); } - -template -int exec(sqlite3* db, const char* sql, T callback, char** errmsg = nullptr) { - return sqlite3_exec( - db, sql, - [](void* cb, int argc, char** argv, char** columns) -> int { - auto& fp = *static_cast(cb); - if constexpr (std::is_same_v) { - fp(argc, argv, columns); - return 0; - } else { - return fp(argc, argv, columns); - } - }, - &callback, errmsg); -} - -class Transaction { -public: - Transaction(sqlite3* db, Module& log, bool immediate = false) : m_db(db), m_log(log) { - const auto type = immediate ? "BEGIN IMMEDIATE" : "BEGIN"; - const auto ret = sqlite3_exec(m_db, type, nullptr, nullptr, nullptr); - if (ret != SQLITE_OK) { - m_log.error("Failed to start transaction: {}", sqlite3_errmsg(m_db)); - return; - } - m_active = true; - } - - Transaction(const Transaction&) = delete; - Transaction& operator=(const Transaction&) = delete; - Transaction(Transaction&&) = delete; - Transaction& operator=(Transaction&&) = delete; - - ~Transaction() { - if (!m_active) { - return; - } - - const auto ret = sqlite3_exec(m_db, "ROLLBACK", nullptr, nullptr, nullptr); - if (ret != SQLITE_OK) { - m_log.error("Failed to roll back transaction (uh oh?): {}", sqlite3_errmsg(m_db)); - } - } - - void commit() { - if (!m_active) { - return; - } - - const auto ret = sqlite3_exec(m_db, "COMMIT", nullptr, nullptr, nullptr); - if (ret != SQLITE_OK) { - m_log.error("Failed to commit transaction: {}", sqlite3_errmsg(m_db)); - return; - } - - m_active = false; - } - - explicit operator bool() const { return m_active; } - -private: - sqlite3* m_db = nullptr; - Module& m_log; - bool m_active = false; -}; - -} // namespace aurora::sqlite diff --git a/aurora-main/lib/system_info.cpp b/aurora-main/lib/system_info.cpp deleted file mode 100644 index 9197cd0..0000000 --- a/aurora-main/lib/system_info.cpp +++ /dev/null @@ -1,368 +0,0 @@ -#include "system_info.hpp" -#include "internal.hpp" - -#if _WIN32 -#define WIN32_LEAN_AND_MEAN 1 -#include -#include - -template -class ComPtr { -public: - ComPtr() = default; - ComPtr(const ComPtr&) = delete; - ComPtr& operator=(const ComPtr&) = delete; - ~ComPtr() { reset(); } - - T* Get() const { return value; } - T* operator->() const { return value; } - T** Put() { - reset(); - return &value; - } - -private: - void reset() { - if (value != nullptr) { - value->Release(); - value = nullptr; - } - } - - T* value = nullptr; -}; -typedef LONG NTSTATUS, *PNTSTATUS; -extern "C" NTSYSAPI NTSTATUS NTAPI RtlGetVersion(PRTL_OSVERSIONINFOEXW lpVersionInformation); -#elif __APPLE__ -#include "sys/sysctl.h" -#elif linux -#include -#include -#include -#include -#endif - - -using namespace std::string_literals; - -namespace aurora { - -static constexpr auto Unknown = "Unknown"; - -static Module Log("aurora::system_info"); - -static std::string GetOSVersion(); -static std::string GetCpuModel(); -static uint64_t GetMemoryAmount(); -static void LogMisc(); - -void log_system_information() { - Log.info("CPU model: {}", GetCpuModel()); - const auto memSize = GetMemoryAmount() / 1024 / 1024; - Log.info("Memory: {} MiB", memSize); - -#if defined(__x86_64__) || defined(_M_X64) || defined(_M_X64) - Log.info("Architecture: x86_64"); -#elif defined(__aarch64__) || defined(_M_ARM64) - Log.info("Architecture: aarch64"); -#else - Log.info("Architecture: Unknown"); -#endif - - Log.info("OS: {}", GetOSVersion()); - LogMisc(); -} - -#if _WIN32 -static std::string wideStringToUtf8(std::wstring_view str) { - const auto size = WideCharToMultiByte( - CP_UTF8, - 0, - str.data(), - static_cast(str.size()), - nullptr, - 0, - nullptr, - nullptr - ); - - std::string result{}; - result.resize(size); - - WideCharToMultiByte( - CP_UTF8, - 0, - str.data(), - static_cast(str.size()), - result.data(), - static_cast(result.size()), - nullptr, - nullptr - ); - - return result; -} - -std::string GetCpuModel() { - HKEY key = nullptr; - const auto opened = RegOpenKeyExW( - HKEY_LOCAL_MACHINE, - L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", - 0, - KEY_QUERY_VALUE, - &key); - if (opened != ERROR_SUCCESS) { - Log.error("Unable to open the processor registry key"); - return Unknown; - } - - wchar_t value[256]{}; - DWORD type = 0; - DWORD size = sizeof(value); - const auto queried = RegQueryValueExW( - key, - L"ProcessorNameString", - nullptr, - &type, - reinterpret_cast(value), - &size); - RegCloseKey(key); - if (queried != ERROR_SUCCESS || (type != REG_SZ && type != REG_EXPAND_SZ)) { - Log.error("Unable to read the processor name"); - return Unknown; - } - - const auto length = wcsnlen(value, sizeof(value) / sizeof(value[0])); - return wideStringToUtf8(std::wstring_view(value, length)); -} - -uint64_t GetMemoryAmount() { - MEMORYSTATUSEX status; - status.dwLength = sizeof(status); - GlobalMemoryStatusEx(&status); - - return status.ullTotalPhys; -} - -std::string GetOSVersion() { - RTL_OSVERSIONINFOEXW info = {}; - info.dwOSVersionInfoSize = sizeof(info); - auto result = RtlGetVersion(&info); - if (result != 0) { - Log.error("RtlGetVersion failed"); - return Unknown; - } - - return fmt::format( - "Microsoft Windows {}.{} build {}", - info.dwMajorVersion, - info.dwMinorVersion, - info.dwBuildNumber); -} - -static void LogGpus() { - ComPtr factory; - auto result = CreateDXGIFactory1( - __uuidof(IDXGIFactory1), - reinterpret_cast(factory.Put())); - if (FAILED(result)) { - Log.error("Unable to create IDXGIFactory1"); - return; - } - - for (UINT i = 0;;i++) { - ComPtr adapter; - result = factory->EnumAdapters1(i, adapter.Put()); - if (result == DXGI_ERROR_NOT_FOUND) - break; - - DXGI_ADAPTER_DESC1 desc{}; - adapter->GetDesc1(&desc); - - std::wstring descName(desc.Description, wcsnlen(desc.Description, 128)); - Log.info("Detected GPU: {}", wideStringToUtf8(descName)); - } -} - -void LogMisc() { - LogGpus(); -} - -#elif __APPLE__ - -static std::string sysCtlToString(const char* name) { - size_t length; - auto err = sysctlbyname(name, nullptr, &length, nullptr, 0); - if (err) { - Log.error("sysctlbyname failed: %d", err); - return Unknown; - } - - std::string value; - value.resize(length); - err = sysctlbyname(name, value.data(), &length, nullptr, 0); - if (err) { - Log.error("second sysctlbyname failed: %d", err); - return Unknown; - } - - if (value[length - 1] == '\0') - value.pop_back(); - - return value; -} - -std::string GetCpuModel() { - return sysCtlToString("machdep.cpu.brand_string"); -} - -uint64_t GetMemoryAmount() { - uint64_t result; - size_t size = sizeof(result); - const auto err = sysctlbyname("hw.memsize", &result, &size, nullptr, 0); - if (err) { - Log.error("sysctlbyname failed: %d", err); - return 0; - } - - return result; -} - -std::string GetOSVersion() { -#if TARGET_OS_MAC - constexpr auto name = "macOS"; -#elif TARGET_OS_IOS - constexpr auto name = "iOS"; -#elif TARGET_OS_TV - constexpr auto name = "tvOS"; -#else - constexpr auto name = Unknown; -#endif - - return fmt::format("{} {}", name, system_info::getSystemVersionString()); -} - -void LogMisc() { - // Nada. -} -#elif linux - -// https://stackoverflow.com/questions/216823/how-can-i-trim-a-stdstring -static void ltrim(std::string &s) { - s.erase(s.begin(), std::ranges::find_if(s.begin(), s.end(), [](unsigned char ch) { - return !std::isspace(ch); - })); -} -static void rtrim(std::string &s) { - s.erase(std::ranges::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { - return !std::isspace(ch); - }).base(), s.end()); -} -inline std::string trim(std::string str) { - ltrim(str); - rtrim(str); - return std::move(str); -} - -std::string GetCpuModel() { - std::ifstream cpuInfo("/proc/cpuinfo"); - if (!cpuInfo) - { - Log.error("Failed to open /proc/cpuinfo"); - return Unknown; - } - - while (!cpuInfo.bad() && !cpuInfo.eof()) { - std::string line; - std::getline(cpuInfo, line); - - const auto colon = line.find(':'); - if (colon == std::string::npos) { - continue; - } - - auto left = trim(line.substr(0, colon)); - auto right = trim(line.substr(colon + 1)); - - if (left == "model name") { - return right; - } - } - - return Unknown; -} - -uint64_t GetMemoryAmount() { - struct sysinfo info{}; - sysinfo(&info); - - return info.totalram; -} - -std::string GetOSVersion() { - auto path = "/etc/os-release"; - if (!std::filesystem::exists(path)) { - path = "/usr/lib/os-release"; - } - - std::ifstream releaseInfo(path); - if (!releaseInfo) - { - Log.error("Failed to open /etc/os-release or /usr/lib/os-release"); - return Unknown; - } - - std::string name, version; - - while (!releaseInfo.bad() && !releaseInfo.eof()) { - std::string line; - std::getline(releaseInfo, line); - - const auto split = line.find('='); - if (split == std::string::npos) { - continue; - } - - auto left = trim(line.substr(0, split)); - auto right = trim(line.substr(split + 1)); - - if (right[0] == '"' && right[right.size()-1] == '"') { - right = right.substr(1, right.size()-2); - } - - if (left == "NAME") { - name = right; - } else if (left == "VERSION") { - version = right; - } - } - - if (name.empty()) { - return Unknown; - } - - return fmt::format("{} {}", name, version); -} - -void LogMisc() { - -} -#else -std::string GetCpuModel() { - return Unknown; -} - -uint64_t GetMemoryAmount() { - return 0; -} - -std::string GetOSVersion() { - return Unknown; -} - -void LogMisc() { - -} -#endif - -} // namespace aurora diff --git a/aurora-main/lib/system_info.hpp b/aurora-main/lib/system_info.hpp deleted file mode 100644 index 6dda15e..0000000 --- a/aurora-main/lib/system_info.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -namespace aurora { - void log_system_information(); - - namespace system_info { -#if __APPLE__ - std::string getSystemVersionString(); -#endif - } -} \ No newline at end of file diff --git a/aurora-main/lib/system_info_mac.mm b/aurora-main/lib/system_info_mac.mm deleted file mode 100644 index 113ac47..0000000 --- a/aurora-main/lib/system_info_mac.mm +++ /dev/null @@ -1,10 +0,0 @@ -#include "system_info.hpp" -#include -#include - -namespace aurora::system_info { - std::string getSystemVersionString() { - NSString * str = [[NSProcessInfo processInfo] operatingSystemVersionString]; - return [str UTF8String]; - } -} \ No newline at end of file diff --git a/aurora-main/lib/webgpu/gpu.cpp b/aurora-main/lib/webgpu/gpu.cpp deleted file mode 100644 index 2e01e39..0000000 --- a/aurora-main/lib/webgpu/gpu.cpp +++ /dev/null @@ -1,987 +0,0 @@ -#include "gpu.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "../gfx/common.hpp" -#include "../internal.hpp" -#include "../window.hpp" -#include "../dolphin/vi/vi_internal.hpp" - -#if defined(WEBGPU_DAWN) && !defined(__MINGW32__) -#include "../dawn/BackendBinding.hpp" -#include -#elif defined(WEBGPU_DAWN) -#include "../dawn/BackendBinding.hpp" -#endif - -#if defined(WEBGPU_DAWN) && defined(_WIN32) -#include -#endif - -namespace aurora::gx { -void clear_display_copy_cache() noexcept; -} // namespace aurora::gx -namespace aurora::gfx { -void clear_offscreen_cache(); -} // namespace aurora::gfx - -namespace aurora::webgpu { -static Module Log("aurora::gpu"); - -wgpu::Device g_device; -wgpu::Queue g_queue; -wgpu::Surface g_surface; -wgpu::BackendType g_backendType; -GraphicsConfig g_graphicsConfig; -TextureWithSampler g_frameBuffer; -TextureWithSampler g_frameBufferResolved; -TextureWithSampler g_depthBuffer; - -// EFB -> XFB copy pipeline -static wgpu::BindGroupLayout g_CopyBindGroupLayout; -wgpu::RenderPipeline g_CopyPipeline; -wgpu::BindGroup g_CopyBindGroup; -static bool g_presentSourceOverrideActive = false; -static wgpu::BindGroup g_presentSourceOverrideBindGroup; -static wgpu::Texture g_presentSourceOverrideTexture; -static wgpu::Extent3D g_presentSourceOverrideSize{}; -static wgpu::TextureFormat g_presentSourceOverrideFormat = wgpu::TextureFormat::Undefined; - -static wgpu::Adapter g_adapter; -wgpu::Instance g_instance; -static wgpu::AdapterInfo g_adapterInfo; -static wgpu::SurfaceCapabilities g_surfaceCapabilities; -bool g_bcTexturesSupported; -// Written by Dawn's device-loss callback and consumed at ordered frame boundaries. Keep the -// callback free of logging, allocation, teardown and renderer state mutation. -static std::atomic_bool g_deviceLost{false}; -static std::atomic g_deviceLostReason{wgpu::DeviceLostReason::Unknown}; -// The reason enum is almost always `Unknown`, while Dawn's message carries the real cause, so -// keep a truncated copy. Written with a plain memcpy, published by the g_deviceLost store. -static std::array g_deviceLostMessage{}; -// Errors raised before initialize() completes must not be fatal: the backend fallback loop retries -// the next backend, and a broken ICD can raise uncaptured errors mid-probe. -static std::atomic_bool g_initialized{false}; - -namespace { - -struct RenderTargetSize { - uint32_t width; - uint32_t height; -}; - -RenderTargetSize clamp_render_target_size(uint32_t width, uint32_t height) noexcept { - const uint32_t maxDimension = g_graphicsConfig.maxTextureDimension2D; - if (width == 0 || height == 0 || maxDimension == 0 || maxDimension == WGPU_LIMIT_U32_UNDEFINED || - (width <= maxDimension && height <= maxDimension)) { - return {width, height}; - } - - // Keep the requested aspect while fitting both axes inside the adapter's maximum 2D texture size. - // 64-bit arithmetic so a large window cannot wrap during the scale. - if (width > maxDimension) { - height = std::max(1u, static_cast((static_cast(height) * maxDimension) / width)); - width = maxDimension; - } - if (height > maxDimension) { - width = std::max(1u, static_cast((static_cast(width) * maxDimension) / height)); - height = maxDimension; - } - return {width, height}; -} - -RenderTargetSize clamp_frame_buffer_size(uint32_t width, uint32_t height) noexcept { - const auto adapterClamped = clamp_render_target_size(width, height); - const auto budgeted = - render_size_limits::fit_framebuffer_to_budget(adapterClamped.width, adapterClamped.height, - g_graphicsConfig.maxTextureDimension2D); - return {budgeted.width, budgeted.height}; -} - -// V-Sync is never enabled: the guest drives its own pacing, and blocking in Present() couples the -// whole machine to the monitor (a 120 FPS target on a 75 Hz display runs in slow motion). -wgpu::PresentMode best_present_mode() { - const auto supports = [](const wgpu::PresentMode candidate) { - for (size_t i = 0; i < g_surfaceCapabilities.presentModeCount; ++i) { - if (g_surfaceCapabilities.presentModes[i] == candidate) { - return true; - } - } - return false; - }; - // Vulkan prefers Mailbox, every other backend Immediate. Under window capture the Vulkan driver - // cannot flip and Immediate leaks about a megabyte per present until the device is lost. - const bool preferMailbox = g_backendType == wgpu::BackendType::Vulkan; - if (preferMailbox && supports(wgpu::PresentMode::Mailbox)) { - return wgpu::PresentMode::Mailbox; - } - if (supports(wgpu::PresentMode::Immediate)) { - return wgpu::PresentMode::Immediate; - } - if (g_backendType != wgpu::BackendType::Metal && supports(wgpu::PresentMode::Mailbox)) { - return wgpu::PresentMode::Mailbox; - } - // Mailbox is preferred over Fifo because Fifo caps presentation at the refresh rate and every slot - // deadline after the first is missed. Reaching this means neither is offered, so say so loudly. - Log.warn("Surface supports neither Immediate nor Mailbox; falling back to Fifo. Presentation " - "is capped at the display refresh rate, so the game may run slower than its own " - "pace and frame interpolation cannot exceed the refresh rate."); - return wgpu::PresentMode::Fifo; -} - -wgpu::TextureFormat to_linear(wgpu::TextureFormat format) { - if (format == wgpu::TextureFormat::RGBA8UnormSrgb) { - return wgpu::TextureFormat::RGBA8Unorm; - } - if (format == wgpu::TextureFormat::BGRA8UnormSrgb) { - return wgpu::TextureFormat::BGRA8Unorm; - } - return format; -} - -wgpu::TextureFormat best_surface_format() { - if (g_surfaceCapabilities.formatCount == 0) { - return wgpu::TextureFormat::Undefined; - } - for (size_t i = 0; i < g_surfaceCapabilities.formatCount; ++i) { - const auto format = to_linear(g_surfaceCapabilities.formats[i]); - if (format == wgpu::TextureFormat::RGBA8Unorm || format == wgpu::TextureFormat::BGRA8Unorm) { - return format; - } - } - return g_surfaceCapabilities.formats[0]; -} - -} // namespace - -TextureWithSampler create_render_texture(uint32_t width, uint32_t height, bool multisampled) { - const auto renderTargetSize = clamp_render_target_size(width, height); - const wgpu::Extent3D size{ - .width = renderTargetSize.width, - .height = renderTargetSize.height, - .depthOrArrayLayers = 1, - }; - const auto format = g_graphicsConfig.surfaceConfiguration.format; - uint32_t sampleCount = 1; - if (multisampled) { - sampleCount = g_graphicsConfig.msaaSamples; - } - if (width == 0 || height == 0) { - Log.fatal("Invalid render texture size! {}x{}, multisampled {}, format {}", width, height, static_cast(format), multisampled); - } - const wgpu::TextureDescriptor textureDescriptor{ - .label = "Render texture", - .usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc | - wgpu::TextureUsage::CopyDst, - .dimension = wgpu::TextureDimension::e2D, - .size = size, - .format = format, - .mipLevelCount = 1, - .sampleCount = sampleCount, - }; - auto texture = g_device.CreateTexture(&textureDescriptor); - - constexpr wgpu::TextureViewDescriptor viewDescriptor{ - .label = "Render texture view", - .dimension = wgpu::TextureViewDimension::e2D, - }; - auto view = texture.CreateView(&viewDescriptor); - - constexpr wgpu::SamplerDescriptor samplerDescriptor{ - .label = "Render sampler", - .addressModeU = wgpu::AddressMode::ClampToEdge, - .addressModeV = wgpu::AddressMode::ClampToEdge, - .addressModeW = wgpu::AddressMode::ClampToEdge, - .magFilter = wgpu::FilterMode::Linear, - .minFilter = wgpu::FilterMode::Linear, - .mipmapFilter = wgpu::MipmapFilterMode::Linear, - .lodMinClamp = 0.f, - .lodMaxClamp = 1000.f, - .maxAnisotropy = 1, - }; - auto sampler = g_device.CreateSampler(&samplerDescriptor); - - return { - .texture = std::move(texture), - .view = std::move(view), - .size = size, - .format = format, - .sampler = std::move(sampler), - }; -} - -const TextureWithSampler& present_source() noexcept { - return g_graphicsConfig.msaaSamples > 1 ? g_frameBufferResolved : g_frameBuffer; -} - -PresentSource current_present_source() noexcept { - if (g_presentSourceOverrideActive && g_presentSourceOverrideBindGroup != nullptr) { - return { - .bindGroup = g_presentSourceOverrideBindGroup, - .texture = g_presentSourceOverrideTexture, - .size = g_presentSourceOverrideSize, - .format = g_presentSourceOverrideFormat, - }; - } - - return { - .bindGroup = g_CopyBindGroup, - .texture = present_source().texture, - .size = present_source().size, - .format = present_source().format, - }; -} - -void set_present_source_override(wgpu::BindGroup bindGroup, wgpu::Texture texture, wgpu::Extent3D size, - wgpu::TextureFormat format) noexcept { - g_presentSourceOverrideBindGroup = std::move(bindGroup); - g_presentSourceOverrideTexture = std::move(texture); - g_presentSourceOverrideSize = size; - g_presentSourceOverrideFormat = format; - g_presentSourceOverrideActive = true; -} - -void clear_present_source_override() noexcept { - g_presentSourceOverrideActive = false; - g_presentSourceOverrideBindGroup = {}; - g_presentSourceOverrideTexture = {}; - g_presentSourceOverrideSize = {}; - g_presentSourceOverrideFormat = wgpu::TextureFormat::Undefined; -} - -Viewport calculate_present_viewport_for_aspect(uint32_t surface_width, uint32_t surface_height, - float content_aspect) noexcept { - if (surface_width == 0 || surface_height == 0 || !(content_aspect > 0.f)) { - return {}; - } - - uint32_t viewport_width = surface_width; - uint32_t viewport_height = std::min( - surface_height, std::max(1u, static_cast(std::lround(static_cast(viewport_width) * - static_cast(1.f / content_aspect))))); - if (viewport_height == surface_height) { - viewport_width = std::min( - surface_width, std::max(1u, static_cast(std::lround(static_cast(viewport_height) * - static_cast(content_aspect))))); - } - - return { - .left = static_cast((surface_width - viewport_width) / 2), - .top = static_cast((surface_height - viewport_height) / 2), - .width = static_cast(viewport_width), - .height = static_cast(viewport_height), - .znear = 0.f, - .zfar = 1.f, - }; -} - -Viewport calculate_present_viewport(uint32_t surface_width, uint32_t surface_height, uint32_t content_width, - uint32_t content_height) noexcept { - if (content_width == 0 || content_height == 0) { - return {}; - } - return calculate_present_viewport_for_aspect( - surface_width, surface_height, static_cast(content_width) / static_cast(content_height)); -} - -static TextureWithSampler create_depth_texture(uint32_t width, uint32_t height) { - const auto renderTargetSize = clamp_render_target_size(width, height); - const wgpu::Extent3D size{ - .width = renderTargetSize.width, - .height = renderTargetSize.height, - .depthOrArrayLayers = 1, - }; - const auto format = g_graphicsConfig.depthFormat; - const wgpu::TextureDescriptor textureDescriptor{ - .label = "Depth texture", - .usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding, - .dimension = wgpu::TextureDimension::e2D, - .size = size, - .format = format, - .mipLevelCount = 1, - .sampleCount = g_graphicsConfig.msaaSamples, - }; - auto texture = g_device.CreateTexture(&textureDescriptor); - - const wgpu::TextureViewDescriptor viewDescriptor{ - .label = "Depth texture view", - .dimension = wgpu::TextureViewDimension::e2D, - }; - auto view = texture.CreateView(&viewDescriptor); - - const wgpu::SamplerDescriptor samplerDescriptor{ - .label = "Depth sampler", - .addressModeU = wgpu::AddressMode::ClampToEdge, - .addressModeV = wgpu::AddressMode::ClampToEdge, - .addressModeW = wgpu::AddressMode::ClampToEdge, - .magFilter = wgpu::FilterMode::Linear, - .minFilter = wgpu::FilterMode::Linear, - .mipmapFilter = wgpu::MipmapFilterMode::Linear, - .lodMinClamp = 0.f, - .lodMaxClamp = 1000.f, - .maxAnisotropy = 1, - }; - auto sampler = g_device.CreateSampler(&samplerDescriptor); - - return { - .texture = std::move(texture), - .view = std::move(view), - .size = size, - .format = format, - .sampler = std::move(sampler), - }; -} - -void create_copy_pipeline() { - wgpu::ShaderSourceWGSL sourceDescriptor{}; - sourceDescriptor.code = R"""( -@group(0) @binding(0) -var efb_sampler: sampler; -@group(0) @binding(1) -var efb_texture: texture_2d; - -struct VertexOutput { - @builtin(position) pos: vec4, - @location(0) uv: vec2, -}; - -var pos: array, 3> = array, 3>( - vec2(-1.0, 1.0), - vec2(-1.0, -3.0), - vec2(3.0, 1.0), -); -var uvs: array, 3> = array, 3>( - vec2(0.0, 0.0), - vec2(0.0, 2.0), - vec2(2.0, 0.0), -); - -@vertex -fn vs_main(@builtin(vertex_index) vtxIdx: u32) -> VertexOutput { - var out: VertexOutput; - out.pos = vec4(pos[vtxIdx], 0.0, 1.0); - out.uv = uvs[vtxIdx]; - return out; -} - -@fragment -fn fs_main(in: VertexOutput) -> @location(0) vec4 { - let color = textureSample(efb_texture, efb_sampler, in.uv); - return vec4(color.rgb, 1.0); -} -)"""; - const wgpu::ShaderModuleDescriptor moduleDescriptor{ - .nextInChain = &sourceDescriptor, - .label = "XFB Copy Module", - }; - auto module = g_device.CreateShaderModule(&moduleDescriptor); - const std::array colorTargets{wgpu::ColorTargetState{ - .format = g_graphicsConfig.surfaceConfiguration.format, - .writeMask = wgpu::ColorWriteMask::All, - }}; - const wgpu::FragmentState fragmentState{ - .module = module, - .entryPoint = "fs_main", - .targetCount = colorTargets.size(), - .targets = colorTargets.data(), - }; - const std::array bindGroupLayoutEntries{ - wgpu::BindGroupLayoutEntry{ - .binding = 0, - .visibility = wgpu::ShaderStage::Fragment, - .sampler = - wgpu::SamplerBindingLayout{ - .type = wgpu::SamplerBindingType::Filtering, - }, - }, - wgpu::BindGroupLayoutEntry{ - .binding = 1, - .visibility = wgpu::ShaderStage::Fragment, - .texture = - wgpu::TextureBindingLayout{ - .sampleType = wgpu::TextureSampleType::Float, - .viewDimension = wgpu::TextureViewDimension::e2D, - }, - }, - }; - const wgpu::BindGroupLayoutDescriptor bindGroupLayoutDescriptor{ - .entryCount = bindGroupLayoutEntries.size(), - .entries = bindGroupLayoutEntries.data(), - }; - g_CopyBindGroupLayout = g_device.CreateBindGroupLayout(&bindGroupLayoutDescriptor); - const wgpu::PipelineLayoutDescriptor layoutDescriptor{ - .bindGroupLayoutCount = 1, - .bindGroupLayouts = &g_CopyBindGroupLayout, - }; - auto pipelineLayout = g_device.CreatePipelineLayout(&layoutDescriptor); - const wgpu::RenderPipelineDescriptor pipelineDescriptor{ - .layout = pipelineLayout, - .vertex = - wgpu::VertexState{ - .module = module, - .entryPoint = "vs_main", - }, - .primitive = - wgpu::PrimitiveState{ - .topology = wgpu::PrimitiveTopology::TriangleList, - }, - .multisample = - wgpu::MultisampleState{ - .count = 1, - .mask = UINT32_MAX, - }, - .fragment = &fragmentState, - }; - g_CopyPipeline = g_device.CreateRenderPipeline(&pipelineDescriptor); -} - -wgpu::BindGroup create_copy_bind_group(wgpu::TextureView sourceView, wgpu::Sampler sampler) { - const std::array bindGroupEntries{ - wgpu::BindGroupEntry{ - .binding = 0, - .sampler = sampler, - }, - wgpu::BindGroupEntry{ - .binding = 1, - .textureView = sourceView, - }, - }; - const wgpu::BindGroupDescriptor bindGroupDescriptor{ - .layout = g_CopyBindGroupLayout, - .entryCount = bindGroupEntries.size(), - .entries = bindGroupEntries.data(), - }; - return g_device.CreateBindGroup(&bindGroupDescriptor); -} - -wgpu::BindGroup create_copy_bind_group(const TextureWithSampler& source) { - return create_copy_bind_group(source.view, source.sampler); -} - -static wgpu::BackendType to_wgpu_backend(AuroraBackend backend) { - switch (backend) { - case BACKEND_WEBGPU: - return wgpu::BackendType::WebGPU; - case BACKEND_D3D11: - return wgpu::BackendType::D3D11; - case BACKEND_D3D12: - return wgpu::BackendType::D3D12; - case BACKEND_METAL: - return wgpu::BackendType::Metal; - case BACKEND_VULKAN: - return wgpu::BackendType::Vulkan; - case BACKEND_OPENGL: - return wgpu::BackendType::OpenGL; - case BACKEND_OPENGLES: - return wgpu::BackendType::OpenGLES; - default: - return wgpu::BackendType::Null; - } -} - -static bool create_surface() { - SDL_Window* window = window::get_sdl_window(); - if (window == nullptr) { - Log.error("Failed to create surface: no window"); - return false; - } - const auto chainedDescriptor = utils::SetupWindowAndGetSurfaceDescriptor(window); - if (!chainedDescriptor) { - Log.error("Failed to create surface descriptor for current window"); - return false; - } - const wgpu::SurfaceDescriptor surfaceDescriptor{ - .nextInChain = chainedDescriptor.get(), - .label = "Surface", - }; - release_surface(); - g_surface = g_instance.CreateSurface(&surfaceDescriptor); - if (!g_surface) { - Log.error("Failed to create surface"); - return false; - } - return true; -} - -bool initialize(AuroraBackend auroraBackend) { - if (!g_instance) { - Log.info("Creating WebGPU instance"); - const std::array requiredInstanceFeatures{ - wgpu::InstanceFeatureName::TimedWaitAny, - }; - wgpu::InstanceDescriptor instanceDescriptor{ - .requiredFeatureCount = requiredInstanceFeatures.size(), - .requiredFeatures = requiredInstanceFeatures.data(), - }; -#if defined(WEBGPU_DAWN) && !defined(__MINGW32__) - // DawnNative.h's C++ constructor has an MSVC ABI that cannot cross into llvm-mingw, and the - // descriptor only restates Dawn's defaults, so use the public WebGPU descriptor here. - dawn::native::DawnInstanceDescriptor dawnInstanceDescriptor; - dawnInstanceDescriptor.backendValidationLevel = dawn::native::BackendValidationLevel::Disabled; - instanceDescriptor.nextInChain = &dawnInstanceDescriptor; -#endif - g_instance = wgpu::CreateInstance(&instanceDescriptor); - if (!g_instance) { - Log.error("Failed to create WebGPU instance"); - return false; - } - } - const wgpu::BackendType backend = to_wgpu_backend(auroraBackend); - Log.info("Attempting to initialize {}", magic_enum::enum_name(backend)); - // One call is one backend attempt. aurora::initialize() retries without calling shutdown(), so a - // leftover adapter would pass the `if (!g_adapter)` guard and mismatch adapter with device. - g_queue = {}; - g_device = {}; - g_deviceLostReason.store(wgpu::DeviceLostReason::Unknown, std::memory_order_relaxed); - g_deviceLost.store(false, std::memory_order_release); - g_adapter = {}; - g_backendType = wgpu::BackendType::Undefined; - { - window::SurfaceLock surfaceLock; - if (!create_surface()) { - return false; - } - } - { - const wgpu::RequestAdapterOptions options{ - .powerPreference = wgpu::PowerPreference::HighPerformance, - .backendType = backend, - .compatibleSurface = g_surface, - }; - const auto future = g_instance.RequestAdapter( - &options, wgpu::CallbackMode::WaitAnyOnly, - [](wgpu::RequestAdapterStatus status, wgpu::Adapter adapter, wgpu::StringView message) { - if (status == wgpu::RequestAdapterStatus::Success) { - g_adapter = std::move(adapter); - } else { - Log.warn("Adapter request failed: {}", message); - const std::string_view reason{message}; - SDL_SetError("Graphics adapter unavailable: %.*s", - static_cast(std::min(reason.size(), 512)), reason.data()); - } - }); - const auto status = g_instance.WaitAny(future, 5000000000); - if (status != wgpu::WaitStatus::Success) { - Log.error("Failed to create {} adapter: {}", magic_enum::enum_name(backend), - magic_enum::enum_name(status)); - SDL_SetError("Graphics adapter request did not complete within its startup deadline"); - return false; - } - if (!g_adapter) { - Log.error("No {} adapter is available on this system", magic_enum::enum_name(backend)); - return false; - } - } - g_adapter.GetInfo(&g_adapterInfo); - g_backendType = g_adapterInfo.backendType; - const auto backendName = magic_enum::enum_name(g_backendType); - auto adapterName = g_adapterInfo.device; - if (adapterName.IsUndefined()) { - adapterName = wgpu::StringView("Unknown"); - } - auto description = g_adapterInfo.description; - if (description.IsUndefined()) { - description = wgpu::StringView("Unknown"); - } - Log.info("Graphics adapter information\n API: {}\n Device: {} ({})\n Driver: {}", backendName, adapterName, - magic_enum::enum_name(g_adapterInfo.adapterType), description); - - uint32_t maxTextureDimension2D = 0; - { - wgpu::Limits supportedLimits{}; - g_adapter.GetLimits(&supportedLimits); - maxTextureDimension2D = supportedLimits.maxTextureDimension2D; - const wgpu::Limits requiredLimits{ - // Use "best" supported limits - .maxTextureDimension1D = supportedLimits.maxTextureDimension1D == 0 ? WGPU_LIMIT_U32_UNDEFINED - : supportedLimits.maxTextureDimension1D, - .maxTextureDimension2D = supportedLimits.maxTextureDimension2D == 0 ? WGPU_LIMIT_U32_UNDEFINED - : supportedLimits.maxTextureDimension2D, - .maxTextureDimension3D = supportedLimits.maxTextureDimension3D == 0 ? WGPU_LIMIT_U32_UNDEFINED - : supportedLimits.maxTextureDimension3D, - .maxTextureArrayLayers = supportedLimits.maxTextureArrayLayers == 0 ? WGPU_LIMIT_U32_UNDEFINED - : supportedLimits.maxTextureArrayLayers, - .maxDynamicStorageBuffersPerPipelineLayout = supportedLimits.maxDynamicStorageBuffersPerPipelineLayout == 0 - ? WGPU_LIMIT_U32_UNDEFINED - : supportedLimits.maxDynamicStorageBuffersPerPipelineLayout, - .maxStorageBuffersPerShaderStage = supportedLimits.maxStorageBuffersPerShaderStage == 0 - ? WGPU_LIMIT_U32_UNDEFINED - : supportedLimits.maxStorageBuffersPerShaderStage, - .minUniformBufferOffsetAlignment = - supportedLimits.minUniformBufferOffsetAlignment < 64 ? 64 : supportedLimits.minUniformBufferOffsetAlignment, - .minStorageBufferOffsetAlignment = - supportedLimits.minStorageBufferOffsetAlignment < 16 ? 16 : supportedLimits.minStorageBufferOffsetAlignment, - }; - Log.info( - "Using limits:" - "\n maxTextureDimension1D: {}" - "\n maxTextureDimension2D: {}" - "\n maxTextureDimension3D: {}" - "\n maxTextureArrayLayers: {}" - "\n maxDynamicStorageBuffersPerPipelineLayout: {}" - "\n maxStorageBuffersPerShaderStage: {}" - "\n minUniformBufferOffsetAlignment: {}" - "\n minStorageBufferOffsetAlignment: {}", - requiredLimits.maxTextureDimension1D, requiredLimits.maxTextureDimension2D, - requiredLimits.maxTextureDimension3D, requiredLimits.maxTextureArrayLayers, - requiredLimits.maxDynamicStorageBuffersPerPipelineLayout, requiredLimits.maxStorageBuffersPerShaderStage, - requiredLimits.minUniformBufferOffsetAlignment, requiredLimits.minStorageBufferOffsetAlignment); - std::vector requiredFeatures; - // Optional native sharing for MetalFX. Devices without either feature keep - // the normal renderer; the upscaler checks the enabled pair at runtime. - if (backend == wgpu::BackendType::Metal && - g_adapter.HasFeature(wgpu::FeatureName::SharedTextureMemoryIOSurface) && - g_adapter.HasFeature(wgpu::FeatureName::SharedFenceMTLSharedEvent)) { - requiredFeatures.push_back(wgpu::FeatureName::SharedTextureMemoryIOSurface); - requiredFeatures.push_back(wgpu::FeatureName::SharedFenceMTLSharedEvent); - } - bool implicitDeviceSynchronizationSupported = false; - wgpu::SupportedFeatures supportedFeatures; - g_adapter.GetFeatures(&supportedFeatures); - for (size_t i = 0; i < supportedFeatures.featureCount; ++i) { - const auto feature = supportedFeatures.features[i]; - if (feature == wgpu::FeatureName::TextureCompressionBC) { - g_bcTexturesSupported = true; - requiredFeatures.push_back(feature); - } - // The presenter calls device and queue methods while the frame worker encodes, which Dawn only - // supports with this feature; without it the two race inside the device's dynamic uploader. - if (feature == wgpu::FeatureName::ImplicitDeviceSynchronization) { - implicitDeviceSynchronizationSupported = true; - requiredFeatures.push_back(feature); - } - } - if (!implicitDeviceSynchronizationSupported) { - Log.warn( - "Adapter does not support ImplicitDeviceSynchronization; multi-threaded presentation is " - "not safe on this device."); - } -#ifdef WEBGPU_DAWN - wgpu::DawnCacheDeviceDescriptor cacheDescriptor({ - .isolationKey = nullptr, - .loadDataFunction = load_from_cache, - .storeDataFunction = store_to_cache, - .functionUserdata = nullptr, - }); - - std::vector enableToggles{ - /* clang-format off */ -#if _WIN32 - "use_dxc", -#ifndef NDEBUG - "emit_hlsl_debug_symbols", -#endif -#endif -#ifndef ANDROID - "use_user_defined_labels_in_backend", -#endif - "disable_symbol_renaming", - "enable_immediate_error_handling", - /* clang-format on */ - }; -#ifdef NDEBUG - enableToggles.push_back("skip_validation"); - enableToggles.push_back("disable_robustness"); -#endif - if (g_backendType == wgpu::BackendType::Vulkan) { - enableToggles.push_back("vulkan_monolithic_pipeline_cache"); - } - const wgpu::DawnTogglesDescriptor togglesDescriptor({ - .nextInChain = &cacheDescriptor, - .enabledToggleCount = enableToggles.size(), - .enabledToggles = enableToggles.data(), - }); -#endif - wgpu::DeviceDescriptor deviceDescriptor; -#ifdef WEBGPU_DAWN - deviceDescriptor.nextInChain = &togglesDescriptor; -#endif - deviceDescriptor.requiredFeatureCount = requiredFeatures.size(); - deviceDescriptor.requiredFeatures = requiredFeatures.data(); - deviceDescriptor.requiredLimits = &requiredLimits; - deviceDescriptor.SetUncapturedErrorCallback( - [](const wgpu::Device& device, wgpu::ErrorType type, wgpu::StringView message) { - if (g_initialized.load(std::memory_order_acquire)) { - FATAL("WebGPU error {}: {}", underlying(type), message); - } else { - Log.warn("WebGPU error {}: {}", underlying(type), message); - } - }); - deviceDescriptor.SetDeviceLostCallback(wgpu::CallbackMode::AllowSpontaneous, - [](const wgpu::Device& device, wgpu::DeviceLostReason reason, - wgpu::StringView message) { - (void)device; - // Shutdown and backend retry release the final - // device reference here too, not a real failure. - if (reason == wgpu::DeviceLostReason::Destroyed) { - return; - } - // Via string_view, so Dawn resolves a - // WGPU_STRLEN length instead of SIZE_MAX. - const std::string_view text{message}; - const size_t copied = - std::min(text.size(), g_deviceLostMessage.size() - 1); - if (copied > 0) { - std::memcpy(g_deviceLostMessage.data(), text.data(), copied); - } - g_deviceLostMessage[copied] = '\0'; - g_deviceLostReason.store(reason, std::memory_order_relaxed); - g_deviceLost.store(true, std::memory_order_release); - }); - const auto future = - g_adapter.RequestDevice(&deviceDescriptor, wgpu::CallbackMode::WaitAnyOnly, - [](wgpu::RequestDeviceStatus status, wgpu::Device device, wgpu::StringView message) { - if (status == wgpu::RequestDeviceStatus::Success) { - g_device = std::move(device); - } else { - Log.warn("Device request failed: {}", message); - const std::string_view reason{message}; - SDL_SetError("Graphics device unavailable: %.*s", - static_cast(std::min(reason.size(), 512)), reason.data()); - } - }); - const auto status = g_instance.WaitAny(future, 5000000000); - if (status != wgpu::WaitStatus::Success) { - Log.error("Failed to create device: {}", magic_enum::enum_name(status)); - SDL_SetError("Graphics device request did not complete within its startup deadline"); - return false; - } - if (!g_device) { - return false; - } - g_device.SetLoggingCallback([](wgpu::LoggingType type, wgpu::StringView message) { - AuroraLogLevel level = LOG_FATAL; - switch (type) { - case wgpu::LoggingType::Verbose: - level = LOG_DEBUG; - break; - case wgpu::LoggingType::Info: - level = LOG_INFO; - break; - case wgpu::LoggingType::Warning: - level = LOG_WARNING; - break; - case wgpu::LoggingType::Error: - level = LOG_ERROR; - break; - default: - break; - } - Log.report(level, "WebGPU message: {}", message); - }); - } - g_queue = g_device.GetQueue(); - - const wgpu::Status status = g_surface.GetCapabilities(g_adapter, &g_surfaceCapabilities); - if (status != wgpu::Status::Success) { - Log.error("Failed to get surface capabilities: {}", magic_enum::enum_name(status)); - return false; - } - if (g_surfaceCapabilities.formatCount == 0) { - Log.error("Surface has no formats"); - return false; - } - if (g_surfaceCapabilities.presentModeCount == 0) { - Log.error("Surface has no present modes"); - return false; - } - auto surfaceFormat = best_surface_format(); - auto presentMode = best_present_mode(); - Log.info("Using surface format {}, present mode {}", magic_enum::enum_name(surfaceFormat), - magic_enum::enum_name(presentMode)); - const auto size = window::get_window_size(); - g_graphicsConfig = GraphicsConfig{ - .surfaceConfiguration = - wgpu::SurfaceConfiguration{ - .format = surfaceFormat, - .usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc, - .width = size.native_fb_width, - .height = size.native_fb_height, - .presentMode = presentMode, - }, - .depthFormat = wgpu::TextureFormat::Depth32Float, - .msaaSamples = g_config.msaa, - .textureAnisotropy = g_config.maxTextureAnisotropy, - .maxTextureDimension2D = maxTextureDimension2D, - }; - create_copy_pipeline(); - { - window::SurfaceLock surfaceLock; - resize_swapchain(size.fb_width, size.fb_height, size.native_fb_width, size.native_fb_height, true); - } - g_initialized.store(true, std::memory_order_release); - return true; -} - -void fail_if_device_lost() noexcept { - if (!g_deviceLost.load(std::memory_order_acquire)) { - return; - } - - // Several frame-owning threads can observe loss, so serialize escalation: one thread logs and the - // rest wait for termination instead of submitting more work to a lost device. - static std::mutex fatalMutex; - const std::lock_guard lock(fatalMutex); - const auto reason = g_deviceLostReason.load(std::memory_order_relaxed); - const char* const detail = g_deviceLostMessage.data(); - if (detail[0] != '\0') { - Log.fatal("WebGPU device was lost ({}: {}). Rendering cannot continue safely; restart the application.", - magic_enum::enum_name(reason), detail); - } else { - Log.fatal("WebGPU device was lost ({}). Rendering cannot continue safely; restart the application.", - magic_enum::enum_name(reason)); - } -} - -void serialize_pipeline_caches() noexcept { -#if defined(WEBGPU_DAWN) && defined(_WIN32) - if (!g_device || g_backendType != wgpu::BackendType::Vulkan) { - return; - } - using PerformIdleTasksFn = void(*)(const wgpu::Device*); - static const auto performIdleTasks = []() -> PerformIdleTasksFn { - const HMODULE dawnModule = GetModuleHandleW(L"webgpu_dawn.dll"); - if (dawnModule == nullptr) { - return nullptr; - } - return reinterpret_cast(reinterpret_cast( - GetProcAddress(dawnModule, "?PerformIdleTasks@native@dawn@@YAXAEBVDevice@wgpu@@@Z"))); - }(); - if (performIdleTasks != nullptr) { - performIdleTasks(&g_device); - } -#endif -} - -void shutdown() { - serialize_pipeline_caches(); - g_initialized.store(false, std::memory_order_release); - g_CopyBindGroupLayout = {}; - g_CopyPipeline = {}; - g_CopyBindGroup = {}; - g_frameBuffer = {}; - g_frameBufferResolved = {}; - g_depthBuffer = {}; - g_queue = {}; - g_surface = {}; - g_device = {}; - g_adapter = {}; - g_instance = {}; - - cache_shutdown(); -} - -void release_surface() noexcept { - const bool hadSurface = static_cast(g_surface); - if (g_surface) { - g_surface.Unconfigure(); - } - g_surface = {}; - if (hadSurface && g_instance && g_device && g_queue) { - // Retired swapchain is freed after a later submission completes and the device ticks. - submit_staging_commands(g_device.CreateCommandEncoder().Finish()); - const auto future = g_queue.OnSubmittedWorkDone( - wgpu::CallbackMode::WaitAnyOnly, [](wgpu::QueueWorkDoneStatus, wgpu::StringView) {}); - if (const auto status = g_instance.WaitAny(future, 1000000000); status != wgpu::WaitStatus::Success) { - Log.warn("Timed out waiting for queue idle on surface release: {}", magic_enum::enum_name(status)); - } - g_device.Tick(); - } -} - -bool refresh_surface(bool recreate) { - if (!g_instance || !g_device) { - return false; - } - if (!window::is_presentable()) { - release_surface(); - return false; - } - if ((!g_surface || recreate) && !create_surface()) { - return false; - } - uint32_t width = g_graphicsConfig.surfaceConfiguration.width; - uint32_t height = g_graphicsConfig.surfaceConfiguration.height; - uint32_t native_width = width; - uint32_t native_height = height; - if (window::get_sdl_window() != nullptr) { - const auto size = window::get_window_size(); - width = size.fb_width; - height = size.fb_height; - native_width = size.native_fb_width; - native_height = size.native_fb_height; - } - if (width != 0 && height != 0) { - resize_swapchain(width, height, native_width, native_height, true); - } - return true; -} - -void resize_swapchain(uint32_t width, uint32_t height, uint32_t native_width, uint32_t native_height, bool force) { - if (!g_surface || !g_device || width == 0 || height == 0 || native_height == 0 || native_width == 0) { - return; - } - - uint32_t render_width = width; - uint32_t render_height = height; - const auto [efbWidth, efbHeight] = vi::configured_fb_size(); - if (efbWidth != 0 && efbHeight != 0) { - render_width = std::max(render_width, efbWidth); - render_height = std::max(render_height, efbHeight); - } - - const auto requestedRenderSize = RenderTargetSize{render_width, render_height}; - const auto clampedRenderSize = clamp_frame_buffer_size(render_width, render_height); - render_width = clampedRenderSize.width; - render_height = clampedRenderSize.height; - if (requestedRenderSize.width != render_width || requestedRenderSize.height != render_height) { - Log.warn( - "Render target {}x{} exceeds the safe framebuffer budget (adapter max {}, practical max {} / {} " - "pixels); clamping to {}x{}", - requestedRenderSize.width, requestedRenderSize.height, g_graphicsConfig.maxTextureDimension2D, - render_size_limits::kMaxFramebufferDimension, render_size_limits::kMaxFramebufferPixels, render_width, - render_height); - } - - const bool sizeChanged = g_graphicsConfig.surfaceConfiguration.width != native_width || - g_graphicsConfig.surfaceConfiguration.height != native_height || - g_frameBuffer.size.width != render_width || g_frameBuffer.size.height != render_height; - if (!force && !sizeChanged) { - return; - } - if (sizeChanged) { - gx::clear_display_copy_cache(); - gfx::clear_caches(); - clear_present_source_override(); - } - g_graphicsConfig.surfaceConfiguration.width = native_width; - g_graphicsConfig.surfaceConfiguration.height = native_height; - auto surfaceConfiguration = g_graphicsConfig.surfaceConfiguration; - surfaceConfiguration.device = g_device; - g_surface.Configure(&surfaceConfiguration); - if (!sizeChanged) { - // Forced reconfigure at an unchanged size (present-mode change or recreated surface). The - // offscreen targets are not swapchain images, so reallocating them would only stall the frame. - return; - } - g_frameBuffer = create_render_texture(render_width, render_height, true); - g_frameBufferResolved = create_render_texture(render_width, render_height, false); - g_depthBuffer = create_depth_texture(render_width, render_height); - g_CopyBindGroup = create_copy_bind_group(present_source()); -} -} // namespace aurora::webgpu diff --git a/aurora-main/lib/webgpu/gpu.hpp b/aurora-main/lib/webgpu/gpu.hpp deleted file mode 100644 index 7b96e95..0000000 --- a/aurora-main/lib/webgpu/gpu.hpp +++ /dev/null @@ -1,100 +0,0 @@ -#pragma once - -#include -#include - -#include "wgpu.hpp" - -#include -#include - -struct SDL_Window; - -namespace aurora::webgpu { -struct GraphicsConfig { - wgpu::SurfaceConfiguration surfaceConfiguration; - wgpu::TextureFormat depthFormat; - uint32_t msaaSamples; - uint16_t textureAnisotropy; - uint32_t maxTextureDimension2D; -}; -struct TextureWithSampler { - wgpu::Texture texture; - wgpu::TextureView view; - wgpu::Extent3D size; - wgpu::TextureFormat format; - wgpu::Sampler sampler; -}; -struct PresentSource { - wgpu::BindGroup bindGroup; - wgpu::Texture texture; - wgpu::Extent3D size; - wgpu::TextureFormat format; -}; -struct Viewport { - float left; - float top; - float width; - float height; - float znear; - float zfar; - - bool operator==(const Viewport& rhs) const { - return left == rhs.left && top == rhs.top && width == rhs.width && height == rhs.height && znear == rhs.znear && - zfar == rhs.zfar; - } - bool operator!=(const Viewport& rhs) const { return !(*this == rhs); } -}; - -extern wgpu::Device g_device; -extern wgpu::Queue g_queue; -extern wgpu::Surface g_surface; -extern wgpu::BackendType g_backendType; -extern GraphicsConfig g_graphicsConfig; -extern TextureWithSampler g_frameBuffer; -extern TextureWithSampler g_frameBufferResolved; -extern TextureWithSampler g_depthBuffer; -extern wgpu::RenderPipeline g_CopyPipeline; -extern wgpu::BindGroup g_CopyBindGroup; -extern wgpu::Instance g_instance; -extern bool g_bcTexturesSupported; - -bool initialize(AuroraBackend backend); -void shutdown(); -// Device-loss callbacks may run on a Dawn-managed thread and only publish loss state; frame -// threads call this at ordered boundaries to turn it into the one user-visible fatal error. -void fail_if_device_lost() noexcept; -void release_surface() noexcept; -bool refresh_surface(bool recreate = true); -void resize_swapchain(uint32_t width, uint32_t height, uint32_t native_width, uint32_t native_height, - bool force = false); -TextureWithSampler create_render_texture(uint32_t width, uint32_t height, bool multisampled); -const TextureWithSampler& present_source() noexcept; -PresentSource current_present_source() noexcept; -void set_present_source_override(wgpu::BindGroup bindGroup, wgpu::Texture texture, wgpu::Extent3D size, - wgpu::TextureFormat format) noexcept; -void clear_present_source_override() noexcept; -wgpu::BindGroup create_copy_bind_group(const TextureWithSampler& source); -wgpu::BindGroup create_copy_bind_group(wgpu::TextureView sourceView, wgpu::Sampler sampler); -Viewport calculate_present_viewport(uint32_t surface_width, uint32_t surface_height, uint32_t content_width, - uint32_t content_height) noexcept; -Viewport calculate_present_viewport_for_aspect(uint32_t surface_width, uint32_t surface_height, - float content_aspect) noexcept; -void draw_clear(const wgpu::RenderPassEncoder& pass, bool clearColor, bool clearAlpha, bool clearDepth, - const Vec4& clearColorValue, float clearDepthValue); - -size_t load_from_cache(void const* key, size_t keySize, void* value, size_t valueSize, void* userdata); -void store_to_cache(void const* key, size_t keySize, void const* value, size_t valueSize, void* userdata); -void cache_shutdown(); - -struct BlobCacheStats { - uint64_t lookups; - uint64_t hits; - uint64_t stores; - uint64_t hitBytes; -}; -BlobCacheStats blob_cache_stats() noexcept; -// Persists the monolithic Vulkan pipeline cache into the blob cache (no-op elsewhere). -void serialize_pipeline_caches() noexcept; - -} // namespace aurora::webgpu diff --git a/aurora-main/lib/webgpu/gpu_cache.cpp b/aurora-main/lib/webgpu/gpu_cache.cpp deleted file mode 100644 index 7b0fa1f..0000000 --- a/aurora-main/lib/webgpu/gpu_cache.cpp +++ /dev/null @@ -1,452 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../fs_helper.hpp" -#include "../internal.hpp" -#include "../sqlite_utils.hpp" -#include "gpu.hpp" - -#include -#include -#if defined(AURORA_CACHE_USE_ZSTD) -#include -#endif -#define XXH_STATIC_LINKING_ONLY -#include - -namespace aurora::webgpu { -static Module Log("aurora::gpu::cache"); - -static sqlite3* db; -static sqlite3_stmt* load_stmt; -static sqlite3_stmt* store_stmt; -static sqlite3_stmt* touch_stmt; -static bool cache_broken; -static std::mutex cache_mutex; -#if defined(AURORA_CACHE_USE_ZSTD) -static std::vector compress_buffer; -#endif - -// Schema 3 added last_used (whole days since the Unix epoch) so stale blobs can be -// pruned: config-version bumps and driver updates change every Dawn cache key, and -// without an age column the orphaned rows accumulate forever (observed 1.6 GB). -// Schema 4 is a content reset for the vulkan_monolithic_pipeline_cache switch, which -// obsoletes every per-pipeline blob at once. -constexpr int CACHE_SCHEMA = 4; -constexpr int64_t PruneAfterDays = 30; -// Rows whose last_used lags today are collected in memory and written in one batch at -// shutdown: the load path sits inside a read transaction that is always rolled back, -// and day granularity makes anything more eager pointless. - -static std::atomic g_lookups{0}; -static std::atomic g_hits{0}; -static std::atomic g_stores{0}; -static std::atomic g_hitBytes{0}; -static std::vector g_pendingTouches; - -static int64_t days_now() { return static_cast(std::time(nullptr) / 86400); } - -static void init_abort() { - cache_broken = true; - sqlite3_close(db); - db = nullptr; -} - -static int check(int ret) { - if (ret != SQLITE_OK) { - Log.error("SQLite operation failed: {}", sqlite3_errmsg(db)); - } - - return ret; -} - -enum class SchemaState { Match, Mismatch, Error }; - -static SchemaState check_schema() { - auto ret = sqlite::exec(db, "CREATE TABLE IF NOT EXISTS aurora_schema(value INTEGER);"); - if (ret != SQLITE_OK) { - Log.error("Failed to create schema table: {}", sqlite3_errmsg(db)); - return SchemaState::Error; - } - - bool match = false; - const auto cmd = fmt::format("SELECT * FROM aurora_schema WHERE value = {}", CACHE_SCHEMA); - ret = sqlite::exec(db, cmd.c_str(), [&match](int, char**, char**) { match = true; }, nullptr); - if (ret != SQLITE_OK) { - Log.error("Failed to check schema table: {}", sqlite3_errmsg(db)); - return SchemaState::Error; - } - return match ? SchemaState::Match : SchemaState::Mismatch; -} - -static bool create_schema() { - sqlite::Transaction tx(db, Log, true); - if (!tx) { - Log.error("Failed to open schema transaction: {}", sqlite3_errmsg(db)); - return false; - } - const auto cmd = fmt::format( - R"(CREATE TABLE IF NOT EXISTS aurora_schema(value INTEGER); -DROP TABLE IF EXISTS cache; -CREATE TABLE cache ( - key BLOB PRIMARY KEY NOT NULL, - value BLOB NOT NULL, - size INTEGER NOT NULL, - compressed INTEGER NOT NULL, - last_used INTEGER NOT NULL DEFAULT 0 -); -DELETE FROM aurora_schema; -INSERT INTO aurora_schema VALUES ({});)", - CACHE_SCHEMA); - const auto ret = sqlite::exec(db, cmd.c_str()); - if (ret != SQLITE_OK) { - Log.error("Failed to create schema: {}", sqlite3_errmsg(db)); - return false; - } - tx.commit(); - return true; -} - -static void prune_stale_rows() { - const auto cmd = fmt::format("DELETE FROM cache WHERE last_used < {}", days_now() - PruneAfterDays); - auto ret = sqlite::exec(db, cmd.c_str()); - if (ret != SQLITE_OK) { - Log.error("Failed to prune stale cache rows: {}", sqlite3_errmsg(db)); - return; - } - const auto pruned = sqlite3_changes(db); - if (pruned > 0) { - Log.info("Pruned {} stale Dawn cache blobs (unused for {}+ days)", pruned, PruneAfterDays); - } - // Freed pages are only reused, never returned to the filesystem, so compact when a - // meaningful amount was dropped. Blobs run hundreds of KB each, making even a few - // hundred rows a noticeable slice of the file. - if (pruned > 256) { - ret = sqlite::exec(db, "VACUUM;"); - if (ret != SQLITE_OK) { - Log.warn("Failed to vacuum Dawn cache after pruning: {}", sqlite3_errmsg(db)); - } - } -} - -static bool cache_init_core() { - Log.debug("SQLite version {}", sqlite3_libversion()); - - const auto path = fs_path_from_string(g_config.cachePath) / "dawn_cache.db"; - std::string file = fs_path_to_string(path); - Log.debug("Using dawn cache at {}", file); - auto ret = sqlite3_open(file.c_str(), &db); - if (ret != SQLITE_OK) { - Log.error("Failed to open database: {}", sqlite3_errmsg(db)); - return false; - } - - // WAL mode + NORMAL = no need for disk syncs, consistent but not durable is fine. - ret = sqlite::exec(db, "PRAGMA journal_mode=WAL; PRAGMA synchronous=NORMAL;"); - if (ret != SQLITE_OK) { - Log.error("Failed to set pragmas: {}", sqlite3_errmsg(db)); - return false; - } - - switch (check_schema()) { - case SchemaState::Match: - prune_stale_rows(); - break; - case SchemaState::Mismatch: { - // Dropping the table would leave the freed pages inside the file, so a schema - // change deletes the database outright; pre-schema-3 files had grown unbounded. - Log.info("Dawn cache schema changed; recreating '{}'", file); - sqlite3_close(db); - db = nullptr; - std::error_code ec; - std::filesystem::remove(path, ec); - auto wal = path; - wal += "-wal"; - std::filesystem::remove(wal, ec); - auto shm = path; - shm += "-shm"; - std::filesystem::remove(shm, ec); - ret = sqlite3_open(file.c_str(), &db); - if (ret != SQLITE_OK) { - Log.error("Failed to recreate database: {}", sqlite3_errmsg(db)); - return false; - } - ret = sqlite::exec(db, "PRAGMA journal_mode=WAL; PRAGMA synchronous=NORMAL;"); - if (ret != SQLITE_OK) { - Log.error("Failed to set pragmas: {}", sqlite3_errmsg(db)); - return false; - } - if (!create_schema()) { - return false; - } - break; - } - case SchemaState::Error: - return false; - } - - ret = sqlite3_prepare_v3(db, "SELECT value, size, compressed, last_used FROM cache WHERE key = ?", -1, - SQLITE_PREPARE_PERSISTENT, &load_stmt, nullptr); - if (ret != SQLITE_OK) { - Log.error("Failed to prepare statement: {}", sqlite3_errmsg(db)); - return false; - } - - ret = sqlite3_prepare_v3(db, "REPLACE INTO cache (key, value, size, compressed, last_used) VALUES (?, ?, ?, ?, ?)", - -1, SQLITE_PREPARE_PERSISTENT, &store_stmt, nullptr); - if (ret != SQLITE_OK) { - Log.error("Failed to prepare statement: {}", sqlite3_errmsg(db)); - return false; - } - - ret = sqlite3_prepare_v3(db, "UPDATE cache SET last_used = ? WHERE key = ?", -1, SQLITE_PREPARE_PERSISTENT, - &touch_stmt, nullptr); - if (ret != SQLITE_OK) { - Log.error("Failed to prepare statement: {}", sqlite3_errmsg(db)); - return false; - } - - return true; -} - -// Caller holds cache_mutex. Writes the queued last_used refreshes in one transaction. -static void flush_touches() { - if (g_pendingTouches.empty() || db == nullptr || touch_stmt == nullptr) { - return; - } - - sqlite::Transaction tx(db, Log, true); - if (!tx) { - Log.error("Failed to open touch transaction"); - g_pendingTouches.clear(); - return; - } - const auto today = days_now(); - for (const auto& keyHash : g_pendingTouches) { - check(sqlite3_bind_int64(touch_stmt, 1, today)); - check(sqlite3_bind_blob(touch_stmt, 2, &keyHash, sizeof(keyHash), SQLITE_TRANSIENT)); - if (sqlite3_step(touch_stmt) != SQLITE_DONE) { - Log.error("Failed to refresh cache row age: {}", sqlite3_errmsg(db)); - } - check(sqlite3_reset(touch_stmt)); - } - g_pendingTouches.clear(); - tx.commit(); -} - -static bool cache_init() { - if (cache_broken) { - return false; - } - - if (db) { - return true; - } - - if (!cache_init_core()) { - Log.error("SQLite DB init failed"); - init_abort(); - return false; - } - - Log.debug("SQLite cache init succeeded"); - - return true; -} - -size_t load_from_cache(void const* key, size_t keySize, void* value, size_t valueSize, void*) { - std::lock_guard lock(cache_mutex); - - if (!cache_init()) { - return 0; - } - - sqlite::Transaction tx(db, Log); - if (!tx) { - Log.error("Failed to open load transaction"); - return 0; - } - - // Dawn probes with value == nullptr for the size first, then fetches; count each - // probe as one logical lookup so the hit rate reads per-entry. - if (value == nullptr) { - g_lookups.fetch_add(1, std::memory_order_relaxed); - } - - const auto keyHash = XXH128(key, keySize, 0); - check(sqlite3_bind_blob(load_stmt, 1, &keyHash, sizeof(keyHash), SQLITE_TRANSIENT)); - - const auto ret = sqlite3_step(load_stmt); - size_t foundSize; - if (ret == SQLITE_ROW) { - // Hit - const auto foundPtr = sqlite3_column_blob(load_stmt, 0); - const auto declaredSize = sqlite3_column_int64(load_stmt, 1); - const auto storedSize = sqlite3_column_bytes(load_stmt, 0); - const auto compression = sqlite3_column_int(load_stmt, 2); - const bool compressed = compression == 1; - // Dawn asks for the size before allocating its destination. Validate here, - // not only during the copy: corrupt metadata must become a cache miss. - bool valid = declaredSize > 0 && - static_cast(declaredSize) <= std::numeric_limits::max() && - foundPtr != nullptr && storedSize > 0 && (compression == 0 || compression == 1); - if (valid && compressed) { -#if defined(AURORA_CACHE_USE_ZSTD) - // Our writer uses ZSTD_compress, which records the original content size. - const auto frameSize = ZSTD_getFrameContentSize(foundPtr, static_cast(storedSize)); - valid = frameSize != ZSTD_CONTENTSIZE_ERROR && frameSize != ZSTD_CONTENTSIZE_UNKNOWN && - frameSize == static_cast(declaredSize); -#else - valid = false; -#endif - } else if (valid) { - valid = declaredSize == storedSize; - } - if (!valid) { - Log.error("Ignoring cache entry with inconsistent size or compression metadata"); - check(sqlite3_reset(load_stmt)); - return 0; - } - foundSize = static_cast(declaredSize); - if (value == nullptr) { - g_hits.fetch_add(1, std::memory_order_relaxed); - } else { - g_hitBytes.fetch_add(static_cast(foundSize), std::memory_order_relaxed); - } - if (sqlite3_column_int64(load_stmt, 3) != days_now()) { - g_pendingTouches.push_back(keyHash); - } - - if (value && valueSize == foundSize) { - if (compressed) { -#if defined(AURORA_CACHE_USE_ZSTD) - const auto compSize = sqlite3_column_bytes(load_stmt, 0); - const auto zstdRet = ZSTD_decompress(value, valueSize, foundPtr, compSize); - if (ZSTD_isError(zstdRet)) { - Log.error("zstd decompression error: {}", ZSTD_getErrorName(zstdRet)); - foundSize = 0; - } else if (zstdRet != foundSize) { - Log.error("zstd decompression size mismatch: expected {}, got {}", foundSize, zstdRet); - foundSize = 0; - } -#else - Log.error("Cache entry is zstd-compressed but zstd support is disabled"); - foundSize = 0; -#endif - } else { - if (foundSize != 0 && !foundPtr) { - Log.error("Cache entry is missing raw value data"); - foundSize = 0; - } else if (foundSize != 0) { - std::memcpy(value, foundPtr, foundSize); - } - } - } - } else if (ret == SQLITE_DONE) { - // Miss - foundSize = 0; - } else { - Log.error("Looking up cache key failed: {}", sqlite3_errmsg(db)); - return 0; - } - - check(sqlite3_reset(load_stmt)); - - return foundSize; -} - -void store_to_cache(void const* key, size_t keySize, void const* value, size_t valueSize, void*) { - std::lock_guard lock(cache_mutex); - - if (!cache_init()) { - return; - } - - sqlite::Transaction tx(db, Log, true); - if (!tx) { - Log.error("Failed to open store transaction"); - return; - } - - const void* storedValue = value; - sqlite3_uint64 storedValueSize = valueSize; - int compressed = 0; -#if defined(AURORA_CACHE_USE_ZSTD) - const auto bound = ZSTD_compressBound(valueSize); - if (ZSTD_isError(bound)) { - Log.error("Failed to calculate ZSTD_compressBound: {}", ZSTD_getErrorName(bound)); - return; - } - - if (compress_buffer.size() < bound) { - compress_buffer.resize(bound); - } - - const auto compressRet = ZSTD_compress(compress_buffer.data(), compress_buffer.size(), value, valueSize, 0); - if (ZSTD_isError(compressRet)) { - Log.error("ZSTD compression error: {}", ZSTD_getErrorName(compressRet)); - return; - } - - if (compressRet < valueSize) { - storedValue = compress_buffer.data(); - storedValueSize = compressRet; - compressed = 1; - } -#endif - - const auto keyHash = XXH128(key, keySize, 0); - check(sqlite3_bind_blob64(store_stmt, 1, &keyHash, sizeof(keyHash), SQLITE_TRANSIENT)); - check( - sqlite3_bind_blob64(store_stmt, 2, storedValue, storedValueSize, compressed ? SQLITE_STATIC : SQLITE_TRANSIENT)); - check(sqlite3_bind_int64(store_stmt, 3, static_cast(valueSize))); - check(sqlite3_bind_int(store_stmt, 4, compressed)); - check(sqlite3_bind_int64(store_stmt, 5, days_now())); - g_stores.fetch_add(1, std::memory_order_relaxed); - - const auto ret = sqlite3_step(store_stmt); - if (ret != SQLITE_DONE) { - // Error or something - Log.error("Failed to insert row: {}", sqlite3_errmsg(db)); - return; - } - - check(sqlite3_reset(store_stmt)); - check(sqlite3_bind_null(store_stmt, 2)); - check(sqlite3_bind_null(store_stmt, 4)); - - tx.commit(); -} - -void cache_shutdown() { - std::lock_guard lock(cache_mutex); -#if defined(AURORA_CACHE_USE_ZSTD) - compress_buffer.clear(); -#endif - flush_touches(); - check(sqlite3_finalize(load_stmt)); - check(sqlite3_finalize(store_stmt)); - check(sqlite3_finalize(touch_stmt)); - load_stmt = nullptr; - store_stmt = nullptr; - touch_stmt = nullptr; - check(sqlite3_close(db)); - db = nullptr; -} - -BlobCacheStats blob_cache_stats() noexcept { - return BlobCacheStats{ - .lookups = g_lookups.load(std::memory_order_relaxed), - .hits = g_hits.load(std::memory_order_relaxed), - .stores = g_stores.load(std::memory_order_relaxed), - .hitBytes = g_hitBytes.load(std::memory_order_relaxed), - }; -} - -} // namespace aurora::webgpu diff --git a/aurora-main/lib/webgpu/metalfx.hpp b/aurora-main/lib/webgpu/metalfx.hpp deleted file mode 100644 index 6a9d485..0000000 --- a/aurora-main/lib/webgpu/metalfx.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include - -#include -#include - -namespace aurora::webgpu::metalfx { -struct Size { - uint32_t inputWidth; - uint32_t inputHeight; - uint32_t outputWidth; - uint32_t outputHeight; - wgpu::TextureFormat format; - - bool operator==(const Size&) const = default; -}; - -// All methods except supported() belong to the serialized frame encoder. -// GPU ownership is explicit: begin_input -> submit input -> upscale -> -// submit output consumption -> end_output. Neither texture may be used by -// Dawn outside its access interval. Destruction retires in-flight resources. -class SpatialScaler { -public: - virtual ~SpatialScaler() = default; - virtual const wgpu::TextureView& input_view() const = 0; - virtual const wgpu::TextureView& output_view() const = 0; - virtual const wgpu::Texture& output_texture() const = 0; - virtual bool begin_input() = 0; - virtual bool upscale() = 0; - virtual bool end_output() = 0; - virtual const std::string& error() const = 0; -}; - -bool supported(const wgpu::Device& device, wgpu::BackendType backend); -// A null result with no error means the bounded retirement pool is busy; -// skip upscaling for this frame and retry at a later frame boundary. -std::unique_ptr create(const wgpu::Instance& instance, - const wgpu::Device& device, const Size& size, - std::string& error); -} // namespace aurora::webgpu::metalfx diff --git a/aurora-main/lib/webgpu/metalfx.mm b/aurora-main/lib/webgpu/metalfx.mm deleted file mode 100644 index f66a5fe..0000000 --- a/aurora-main/lib/webgpu/metalfx.mm +++ /dev/null @@ -1,326 +0,0 @@ -#include "metalfx.hpp" - -#import -#import -#import -#import - -#include - -#include -#include - -namespace aurora::webgpu::metalfx { -namespace { -constexpr uint64_t kScheduleTimeoutNs = 1'000'000'000; -// Four current slots plus at most four retiring slots during resize. A busy -// GPU must not allow resize events to allocate unbounded full-resolution images. -constexpr unsigned kMaxLiveResources = 8; -std::atomic g_liveResources{0}; - -struct SharedImage { - IOSurfaceRef surface = nullptr; - id metal; - wgpu::SharedTextureMemory memory; - wgpu::Texture texture; - wgpu::TextureView view; - - ~SharedImage() { if (surface) CFRelease(surface); } - - bool create(const wgpu::Device& device, id native, uint32_t width, - uint32_t height, wgpu::TextureFormat format, MTLTextureUsage nativeUsage, - wgpu::TextureUsage usage) { - const bool bgra = format == wgpu::TextureFormat::BGRA8Unorm; - const size_t rowBytes = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, size_t(width) * 4); - NSDictionary* properties = @{ - (id)kIOSurfaceWidth: @(width), (id)kIOSurfaceHeight: @(height), - (id)kIOSurfaceBytesPerElement: @4, (id)kIOSurfaceBytesPerRow: @(rowBytes), - (id)kIOSurfaceAllocSize: @(rowBytes * height), - (id)kIOSurfacePixelFormat: @(bgra ? 0x42475241u : 0x52474241u) - }; - surface = IOSurfaceCreate((__bridge CFDictionaryRef)properties); - if (!surface) return false; - auto descriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: - bgra ? MTLPixelFormatBGRA8Unorm : MTLPixelFormatRGBA8Unorm - width:width height:height mipmapped:NO]; - descriptor.storageMode = MTLStorageModeShared; - descriptor.usage = nativeUsage; - metal = [native newTextureWithDescriptor:descriptor iosurface:surface plane:0]; - if (!metal) return false; - - wgpu::SharedTextureMemoryIOSurfaceDescriptor io{}; - io.ioSurface = surface; - io.allowStorageBinding = false; - wgpu::SharedTextureMemoryDescriptor importDescriptor{}; - importDescriptor.nextInChain = &io; - memory = device.ImportSharedTextureMemory(&importDescriptor); - wgpu::SharedTextureMemoryProperties actual{}; - if (!memory || memory.GetProperties(&actual) != wgpu::Status::Success || - actual.format != format || actual.size.width != width || actual.size.height != height || - (actual.usage & usage) != usage) return false; - wgpu::TextureDescriptor textureDescriptor{}; - textureDescriptor.label = "MetalFX shared texture"; - textureDescriptor.size = {width, height, 1}; - textureDescriptor.format = format; - textureDescriptor.usage = usage; - texture = memory.CreateTexture(&textureDescriptor); - if (!texture) return false; - view = texture.CreateView(); - return view != nullptr; - } -}; - -struct API_AVAILABLE(macos(13.0)) Resources { - SharedImage input, output; - id scaler; - id privateOutput; - id nativeQueue; - id event; - wgpu::SharedFence fence; - std::atomic failed{false}; - - Resources() { ++g_liveResources; } - ~Resources() { --g_liveResources; } -}; - -class API_AVAILABLE(macos(13.0)) MetalSpatialScaler final : public SpatialScaler { - wgpu::Instance m_instance; - wgpu::Queue m_queue; - std::shared_ptr m_resources; - wgpu::SharedTextureMemoryEndAccessState m_outputReleased{}; - wgpu::Future m_outputScheduled{}; - uint64_t m_value = 0; - std::string m_error; - - bool fail(const char* reason) { - m_error = reason; - m_resources->failed = true; - return false; - } - - bool wait_scheduled(wgpu::Future future) { - return m_instance.WaitAny(future, kScheduleTimeoutNs) == wgpu::WaitStatus::Success || - fail("Timed out scheduling MetalFX GPU work"); - } - - bool end_access(SharedImage& image, wgpu::SharedTextureMemoryEndAccessState& state, - wgpu::Future& scheduled) { - wgpu::SharedTextureMemoryMetalEndAccessState metal{}; - state.nextInChain = &metal; - const auto status = image.memory.EndAccess(image.texture, &state); - state.nextInChain = nullptr; - scheduled = metal.commandsScheduledFuture; - return status == wgpu::Status::Success || fail("MetalFX Dawn EndAccess failed"); - } - - bool begin_access(SharedImage& image, bool initialized, uint64_t value) { - wgpu::SharedTextureMemoryBeginAccessDescriptor access{}; - access.initialized = initialized; - if (value) { - access.fenceCount = 1; - access.fences = &m_resources->fence; - access.signaledValueCount = 1; - access.signaledValues = &value; - } - return image.memory.BeginAccess(image.texture, &access) == wgpu::Status::Success || - fail("MetalFX Dawn BeginAccess failed"); - } - - bool encode_waits(id commands, - const wgpu::SharedTextureMemoryEndAccessState& state) { - for (size_t i = 0; i < state.fenceCount; ++i) { - wgpu::SharedFenceMTLSharedEventExportInfo metal{}; - wgpu::SharedFenceExportInfo info{}; - info.nextInChain = &metal; - state.fences[i].ExportInfo(&info); - if (info.type != wgpu::SharedFenceType::MTLSharedEvent || !metal.sharedEvent) - return fail("Dawn did not export a MetalFX shared-event dependency"); - [commands encodeWaitForEvent:(__bridge id)metal.sharedEvent - value:state.signaledValues[i]]; - } - return true; - } - - void retain_until_dawn_done() { - // A resize/toggle can destroy this wrapper immediately. The last submitted - // Dawn consumer keeps the IOSurfaces/scaler alive independently of the cache. - m_queue.OnSubmittedWorkDone(wgpu::CallbackMode::AllowSpontaneous, - [resources = m_resources](wgpu::QueueWorkDoneStatus status, wgpu::StringView) { - if (status != wgpu::QueueWorkDoneStatus::Success) resources->failed = true; - }); - } - -public: - MetalSpatialScaler(const wgpu::Instance& instance, const wgpu::Device& device, - std::shared_ptr resources) - : m_instance(instance), m_queue(device.GetQueue()), m_resources(std::move(resources)) {} - - const wgpu::TextureView& input_view() const override { return m_resources->input.view; } - const wgpu::TextureView& output_view() const override { return m_resources->output.view; } - const wgpu::Texture& output_texture() const override { return m_resources->output.texture; } - const std::string& error() const override { return m_error; } - - bool begin_input() override { - if (m_resources->failed) return fail("Previous MetalFX GPU work failed"); - return begin_access(m_resources->input, m_value != 0, m_value); - } - - bool upscale() override { - @autoreleasepool { - // Input has already been submitted. Retain it even if an export or native - // allocation fails and the caller immediately falls back to normal copy. - retain_until_dawn_done(); - wgpu::SharedTextureMemoryEndAccessState inputReleased{}; - wgpu::Future inputScheduled{}; - if (!end_access(m_resources->input, inputReleased, inputScheduled) || - !wait_scheduled(inputScheduled)) return false; - if (m_value && !wait_scheduled(m_outputScheduled)) return false; - id commands = [m_resources->nativeQueue commandBuffer]; - if (!commands) return fail("Could not allocate a MetalFX command buffer"); - commands.label = @"MetalFX spatial upscale and return to Dawn"; - if (!encode_waits(commands, inputReleased) || !encode_waits(commands, m_outputReleased)) - return false; - [m_resources->scaler encodeToCommandBuffer:commands]; - id blit = [commands blitCommandEncoder]; - if (!blit) return fail("Could not allocate the MetalFX output blit"); - [blit copyFromTexture:m_resources->privateOutput sourceSlice:0 sourceLevel:0 - sourceOrigin:MTLOriginMake(0, 0, 0) - sourceSize:MTLSizeMake(m_resources->privateOutput.width, m_resources->privateOutput.height, 1) - toTexture:m_resources->output.metal destinationSlice:0 destinationLevel:0 - destinationOrigin:MTLOriginMake(0, 0, 0)]; - [blit endEncoding]; - ++m_value; - [commands encodeSignalEvent:m_resources->event value:m_value]; - const auto resources = m_resources; - [commands addCompletedHandler:^(id completed) { - if (completed.status == MTLCommandBufferStatusError) resources->failed = true; - }]; - [commands commit]; - // Scheduling is required to order independent Metal queues. Completion - // remains asynchronous; resource reuse is guarded by shared GPU events. - [commands waitUntilScheduled]; - if (commands.status == MTLCommandBufferStatusError) - return fail("MetalFX command buffer failed"); - return begin_access(m_resources->output, true, m_value); - } - } - - bool end_output() override { - retain_until_dawn_done(); - m_outputReleased = {}; - return end_access(m_resources->output, m_outputReleased, m_outputScheduled); - } -}; - -// Allocation failures must be caught here rather than reaching Aurora's fatal -// uncaptured-error callback. Scope callbacks own their strings even on timeout. -bool pop_scope(const wgpu::Instance& instance, const wgpu::Device& device, std::string& error) { - auto message = std::make_shared(); - auto future = device.PopErrorScope(wgpu::CallbackMode::WaitAnyOnly, - [message](wgpu::PopErrorScopeStatus status, wgpu::ErrorType type, wgpu::StringView text) { - if (status != wgpu::PopErrorScopeStatus::Success || type != wgpu::ErrorType::NoError) { - const std::string_view detail{text}; - *message = detail.empty() ? "MetalFX texture allocation failed" : std::string(detail); - } - }); - if (instance.WaitAny(future, kScheduleTimeoutNs) != wgpu::WaitStatus::Success) { - error = "Timed out checking MetalFX texture allocation"; - return false; - } - if (!message->empty()) { error = *message; return false; } - return true; -} -} // namespace - -bool supported(const wgpu::Device& device, wgpu::BackendType backend) { - if (@available(macOS 13.0, *)) { - if (!device || backend != wgpu::BackendType::Metal || - !device.HasFeature(wgpu::FeatureName::SharedTextureMemoryIOSurface) || - !device.HasFeature(wgpu::FeatureName::SharedFenceMTLSharedEvent)) return false; - auto native = dawn::native::metal::GetMTLDevice(device.Get()); - return native && [MTLFXSpatialScalerDescriptor supportsDevice:native]; - } - return false; -} - -std::unique_ptr create(const wgpu::Instance& instance, - const wgpu::Device& device, const Size& size, - std::string& error) { - error.clear(); - if (@available(macOS 13.0, *)) { - @autoreleasepool { - if (!supported(device, wgpu::BackendType::Metal)) { - error = "MetalFX spatial scaling is unsupported"; - return {}; - } - wgpu::Limits limits{}; - device.GetLimits(&limits); - if (!size.inputWidth || !size.inputHeight || size.inputWidth >= size.outputWidth || - size.inputHeight >= size.outputHeight || size.outputWidth > limits.maxTextureDimension2D || - size.outputHeight > limits.maxTextureDimension2D || - (size.format != wgpu::TextureFormat::RGBA8Unorm && size.format != wgpu::TextureFormat::BGRA8Unorm)) { - error = "MetalFX requires smaller input dimensions and an RGBA8/BGRA8 unorm target"; - return {}; - } - if (g_liveResources.load() >= kMaxLiveResources) { - return {}; - } - auto native = dawn::native::metal::GetMTLDevice(device.Get()); - auto resources = std::make_shared(); - auto descriptor = [MTLFXSpatialScalerDescriptor new]; - descriptor.inputWidth = size.inputWidth; - descriptor.inputHeight = size.inputHeight; - descriptor.outputWidth = size.outputWidth; - descriptor.outputHeight = size.outputHeight; - descriptor.colorTextureFormat = size.format == wgpu::TextureFormat::BGRA8Unorm - ? MTLPixelFormatBGRA8Unorm : MTLPixelFormatRGBA8Unorm; - descriptor.outputTextureFormat = descriptor.colorTextureFormat; - descriptor.colorProcessingMode = MTLFXSpatialScalerColorProcessingModePerceptual; - resources->scaler = [descriptor newSpatialScalerWithDevice:native]; - resources->nativeQueue = [native newCommandQueue]; - resources->event = [native newSharedEvent]; - if (!resources->scaler || !resources->nativeQueue || !resources->event) { - error = "Could not create MetalFX spatial resources"; - return {}; - } - auto outputDescriptor = [MTLTextureDescriptor - texture2DDescriptorWithPixelFormat:descriptor.outputTextureFormat - width:size.outputWidth height:size.outputHeight mipmapped:NO]; - outputDescriptor.storageMode = MTLStorageModePrivate; - outputDescriptor.usage = resources->scaler.outputTextureUsage; - resources->privateOutput = [native newTextureWithDescriptor:outputDescriptor]; - if (!resources->privateOutput) { error = "Could not allocate MetalFX private output"; return {}; } - - device.PushErrorScope(wgpu::ErrorFilter::Validation); - device.PushErrorScope(wgpu::ErrorFilter::OutOfMemory); - device.PushErrorScope(wgpu::ErrorFilter::Internal); - bool allocated = resources->input.create(device, native, size.inputWidth, size.inputHeight, - size.format, resources->scaler.colorTextureUsage, wgpu::TextureUsage::RenderAttachment); - allocated = allocated && resources->output.create(device, native, size.outputWidth, size.outputHeight, - size.format, MTLTextureUsageShaderRead, wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc); - if (allocated) { - wgpu::SharedFenceMTLSharedEventDescriptor event{}; - event.sharedEvent = (__bridge void*)resources->event; - wgpu::SharedFenceDescriptor fence{}; - fence.nextInChain = &event; - resources->fence = device.ImportSharedFence(&fence); - allocated = resources->fence != nullptr; - } - for (int i = 0; i < 3; ++i) { - if (!pop_scope(instance, device, error)) allocated = false; - } - if (!allocated) { - if (error.empty()) error = "Could not import MetalFX IOSurface textures into Dawn"; - return {}; - } - resources->scaler.colorTexture = resources->input.metal; - resources->scaler.outputTexture = resources->privateOutput; - resources->scaler.inputContentWidth = size.inputWidth; - resources->scaler.inputContentHeight = size.inputHeight; - return std::make_unique(instance, device, std::move(resources)); - } - } - error = "MetalFX requires macOS 13 or newer"; - return {}; -} -} // namespace aurora::webgpu::metalfx diff --git a/aurora-main/lib/webgpu/metalfx_stub.cpp b/aurora-main/lib/webgpu/metalfx_stub.cpp deleted file mode 100644 index 7279443..0000000 --- a/aurora-main/lib/webgpu/metalfx_stub.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "metalfx.hpp" - -namespace aurora::webgpu::metalfx { -bool supported(const wgpu::Device&, wgpu::BackendType) { return false; } - -std::unique_ptr create(const wgpu::Instance&, const wgpu::Device&, - const Size&, std::string& error) { - error = "MetalFX is not available in this build"; - return {}; -} -} // namespace aurora::webgpu::metalfx diff --git a/aurora-main/lib/webgpu/wgpu.hpp b/aurora-main/lib/webgpu/wgpu.hpp deleted file mode 100644 index ba7ebea..0000000 --- a/aurora-main/lib/webgpu/wgpu.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include - -#include - -static inline bool operator==(const wgpu::Extent3D& lhs, const wgpu::Extent3D& rhs) { - return lhs.width == rhs.width && lhs.height == rhs.height && lhs.depthOrArrayLayers == rhs.depthOrArrayLayers; -} -static inline bool operator!=(const wgpu::Extent3D& lhs, const wgpu::Extent3D& rhs) { return !(lhs == rhs); } - -namespace wgpu { -inline std::string_view format_as(wgpu::StringView str) { return str; } -} // namespace wgpu diff --git a/aurora-main/lib/window.cpp b/aurora-main/lib/window.cpp deleted file mode 100644 index 2a24edb..0000000 --- a/aurora-main/lib/window.cpp +++ /dev/null @@ -1,844 +0,0 @@ -#include "window.hpp" - -#ifdef AURORA_ENABLE_GX -#include "imgui.hpp" -#include "webgpu/gpu.hpp" -#endif -#include "input.hpp" -#include "internal.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(_WIN32) -#include -#endif - -#if defined(SDL_PLATFORM_ANDROID) -#include -extern "C" void Android_LockActivityMutex(void); -extern "C" void Android_UnlockActivityMutex(void); -#endif - -#include -#include -#include - -#include "dolphin/vi/vi_internal.hpp" - -namespace aurora::window { -namespace { -Module Log("aurora::window"); - -SDL_Window* g_window; -SDL_Renderer* g_renderer; -float g_frameBufferScale = 0.f; -bool g_frameBufferAspectFit = true; -std::atomic_bool g_forceAspect169{false}; -bool g_presentSurfaceFill = false; -int g_presentAspectWidth = 0; -int g_presentAspectHeight = 0; -AuroraWindowSize g_windowSize; -std::vector g_events; -std::atomic_bool g_backgrounded = false; -std::atomic_bool g_nativeResizePending = false; -std::atomic g_displayMode{AURORA_DISPLAY_MODE_WINDOWED}; -#if defined(SDL_PLATFORM_ANDROID) -std::atomic_bool g_surfaceReady = false; -#else -std::atomic_bool g_surfaceReady = true; -#endif -bool g_lastPaused = false; -bool g_gotFocus = false; -#if defined(_WIN32) -WNDPROC g_prevWindowProc = nullptr; -// Native window handle captured once when the hook is installed. The presenter checks the native -// size several times per slot, which used to be an SDL lookup for a handle that never changes. -HWND g_nativeWindowHandle = nullptr; -// Packed native client size ((width << 32) | height) kept by the window procedure; zero means -// unknown. Atomic because that procedure runs on the SDL thread while the presenter reads it. -std::atomic g_nativeClientSize{0}; - -constexpr uint64_t pack_native_size(uint32_t width, uint32_t height) noexcept { - return (static_cast(width) << 32) | static_cast(height); -} - -LRESULT CALLBACK aurora_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - bool sizeChanged = msg == WM_SIZE; - if (msg == WM_WINDOWPOSCHANGED) { - const auto* pos = reinterpret_cast(lparam); - sizeChanged = pos != nullptr && (pos->flags & SWP_NOSIZE) == 0; - } - if (sizeChanged) { - g_nativeResizePending.store(true, std::memory_order_release); - if (msg == WM_SIZE) { - // WM_SIZE carries the new client size directly. - g_nativeClientSize.store(pack_native_size(static_cast(LOWORD(lparam)), - static_cast(HIWORD(lparam))), - std::memory_order_release); - } else { - // WM_WINDOWPOSCHANGED carries no client size. Invalidate before forwarding: DefWindowProc turns - // it into a nested WM_SIZE through this procedure, which refills the cache authoritatively. - g_nativeClientSize.store(0, std::memory_order_release); - } - } - if (g_prevWindowProc == nullptr) { - return DefWindowProc(hwnd, msg, wparam, lparam); - } - return CallWindowProc(g_prevWindowProc, hwnd, msg, wparam, lparam); -} - -void install_window_proc_hook() noexcept { - const auto props = SDL_GetWindowProperties(g_window); - auto* hwnd = static_cast(SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr)); - if (hwnd == nullptr) { - return; - } - g_nativeWindowHandle = hwnd; - g_nativeClientSize.store(0, std::memory_order_release); - g_prevWindowProc = reinterpret_cast(SetWindowLongPtr(hwnd, GWLP_WNDPROC, - reinterpret_cast(aurora_window_proc))); -} - -void uninstall_window_proc_hook() noexcept { - if (g_window == nullptr || g_prevWindowProc == nullptr) { - g_nativeWindowHandle = nullptr; - g_nativeClientSize.store(0, std::memory_order_release); - return; - } - const auto props = SDL_GetWindowProperties(g_window); - auto* hwnd = static_cast(SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr)); - if (hwnd != nullptr) { - SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast(g_prevWindowProc)); - } - g_prevWindowProc = nullptr; - g_nativeWindowHandle = nullptr; - g_nativeClientSize.store(0, std::memory_order_release); -} -#endif - -// Native client size of the window without going through SDL. Returns false when the platform has -// no cheap native query, in which case callers fall back to get_window_size(). -bool query_native_client_size(uint32_t& width, uint32_t& height) noexcept { -#if defined(_WIN32) - const uint64_t cached = g_nativeClientSize.load(std::memory_order_acquire); - if (cached != 0) { - width = static_cast(cached >> 32); - height = static_cast(cached & 0xffffffffull); - return true; - } - if (g_nativeWindowHandle != nullptr) { - RECT client{}; - if (GetClientRect(g_nativeWindowHandle, &client) != 0) { - width = static_cast(std::max(client.right - client.left, 0)); - height = static_cast(std::max(client.bottom - client.top, 0)); - if (width != 0 && height != 0) { - g_nativeClientSize.store(pack_native_size(width, height), std::memory_order_release); - } - return true; - } - } -#else - (void)width; - (void)height; -#endif - return false; -} - -bool operator==(const AuroraWindowSize& lhs, const AuroraWindowSize& rhs) { - return lhs.width == rhs.width && lhs.height == rhs.height && lhs.fb_width == rhs.fb_width && - lhs.fb_height == rhs.fb_height && lhs.native_fb_height == rhs.native_fb_height && - lhs.native_fb_width == rhs.native_fb_width && lhs.scale == rhs.scale; -} - -Vec2 scale_frame_buffer_to_aspect(int w, int h, float scale, float aspect) { - if (w <= 0 || h <= 0) { - return {std::max(w, 1), std::max(h, 1)}; - } - const auto size = render_size_limits::scale_framebuffer_to_aspect( - static_cast(w), static_cast(h), scale, aspect); - return {static_cast(size.width), static_cast(size.height)}; -} - -void resize_swapchain() noexcept { -#if defined(SDL_PLATFORM_ANDROID) - SurfaceLock surfaceLock; -#endif - // Consume only requests that preceded this synchronization; a native resize arriving mid-rebuild - // stays flagged for the next ordered frame boundary. - g_nativeResizePending.exchange(false, std::memory_order_acq_rel); - const auto size = get_window_size(); - if (size == g_windowSize) { - return; - } - if (size.scale != g_windowSize.scale) { - if (g_windowSize.scale > 0.f) { - Log.info("Display scale changed to {}", size.scale); - } - } - g_windowSize = size; - if (g_renderer != nullptr) { - SDL_SetRenderLogicalPresentation(g_renderer, static_cast(size.native_fb_width), - static_cast(size.native_fb_height), SDL_LOGICAL_PRESENTATION_DISABLED); - SDL_SetRenderScale(g_renderer, size.scale, size.scale); - } -#ifdef AURORA_ENABLE_GX - webgpu::resize_swapchain(size.fb_width, size.fb_height, size.native_fb_width, size.native_fb_height); -#endif -} - -void set_window_icon() noexcept { - if (g_config.iconRGBA8 == nullptr) { - return; - } - auto* iconSurface = - SDL_CreateSurfaceFrom(static_cast(g_config.iconWidth), static_cast(g_config.iconHeight), - SDL_GetPixelFormatForMasks(32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000), - g_config.iconRGBA8, static_cast(4 * g_config.iconWidth)); - ASSERT(iconSurface != nullptr, "Failed to create icon surface: {}", SDL_GetError()); - TRY_WARN(SDL_SetWindowIcon(g_window, iconSurface), "Failed to set window icon: {}", SDL_GetError()); - SDL_DestroySurface(iconSurface); -} - -bool SDLCALL lifecycle_event_watch(void*, SDL_Event* event) { - switch (event->type) { - case SDL_EVENT_WINDOW_RESIZED: - case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: - case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED: - g_nativeResizePending.store(true, std::memory_order_release); - break; -#if defined(SDL_PLATFORM_ANDROID) || defined(SDL_PLATFORM_APPLE) - case SDL_EVENT_WINDOW_MINIMIZED: - g_backgrounded.store(true, std::memory_order_relaxed); - break; - case SDL_EVENT_WINDOW_RESTORED: - g_backgrounded.store(false, std::memory_order_relaxed); - break; -#endif - default: - break; - } - return true; -} - -void sync_paused() { - const bool paused = is_paused(); - if (g_lastPaused == paused) { - return; - } - g_lastPaused = paused; - g_events.push_back(AuroraEvent{ - .type = paused ? AURORA_PAUSED : AURORA_UNPAUSED, - }); -} - -bool is_alt_enter_event(const SDL_Event& event) noexcept { - if (event.type != SDL_EVENT_KEY_DOWN || event.key.repeat) { - return false; - } - - const SDL_Keymod altMask = static_cast(SDL_KMOD_LALT | SDL_KMOD_RALT | SDL_KMOD_ALT); - return event.key.key == SDLK_RETURN && (event.key.mod & altMask) != 0; -} - -void process_event(SDL_Event& event) { -#ifdef AURORA_ENABLE_GX - imgui::process_event(event); -#endif - - switch (event.type) { - case SDL_EVENT_KEY_DOWN: - if (is_alt_enter_event(event)) { - set_display_mode(get_fullscreen() ? AURORA_DISPLAY_MODE_WINDOWED : AURORA_DISPLAY_MODE_BORDERLESS); - g_nativeResizePending.store(true, std::memory_order_release); - } - break; - case SDL_EVENT_WINDOW_MOVED: { - g_events.push_back(AuroraEvent{ - .type = AURORA_WINDOW_MOVED, - .windowPos = {.x = event.window.data1, .y = event.window.data2}, - }); - break; - } - case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED: { - g_events.push_back(AuroraEvent{ - .type = AURORA_DISPLAY_SCALE_CHANGED, - .windowSize = get_window_size(), - }); - break; - } - case SDL_EVENT_WINDOW_RESIZED: - case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: { - g_events.push_back(AuroraEvent{ - .type = AURORA_WINDOW_RESIZED, - .windowSize = get_window_size(), - }); - break; - } - case SDL_EVENT_GAMEPAD_ADDED: { - auto instance = input::add_controller(event.gdevice.which); - g_events.push_back(AuroraEvent{ - .type = AURORA_CONTROLLER_ADDED, - .controller = instance, - }); - break; - } - case SDL_EVENT_GAMEPAD_REMAPPED: { - if (input::refresh_controller(event.gdevice.which)) { - g_events.push_back(AuroraEvent{ - .type = AURORA_CONTROLLER_ADDED, - .controller = event.gdevice.which, - }); - } - break; - } - case SDL_EVENT_GAMEPAD_REMOVED: { - input::remove_controller(event.gdevice.which); - g_events.push_back(AuroraEvent{ - .type = AURORA_CONTROLLER_REMOVED, - .controller = event.gdevice.which, - }); - break; - } - case SDL_EVENT_MOUSE_WHEEL: - input::set_mouse_scroll(event.wheel.x, event.wheel.y); - break; - case SDL_EVENT_QUIT: - g_events.push_back(AuroraEvent{ - .type = AURORA_EXIT, - }); - break; - default: - if (event.type == g_sdlCustomEventsStart + CustomEvent::FutureResize) { - // The request flag is set before this wakeup is queued. Renderer resource mutation belongs to - // begin/end_frame_impl, which may be running on the frame worker. - g_events.push_back(AuroraEvent{ - .type = AURORA_WINDOW_RESIZED, - .windowSize = get_window_size(), - }); - } else if (event.type == g_sdlCustomEventsStart + CustomEvent::RefreshSurface) { - // This event only wakes the window loop; the frame worker applies the pending surface - // configuration at its next ordered frame boundary. - } - break; - } - - sync_paused(); - g_events.push_back(AuroraEvent{ - .type = AURORA_SDL_EVENT, - .sdl = event, - }); -} -} // namespace - -const AuroraEvent* poll_events() { - g_events.clear(); - SDL_Event event; - // Clear out the previous scroll values to prevent ghost input - input::set_mouse_scroll(0, 0); - if (is_paused()) { - if (SDL_WaitEvent(&event)) { - process_event(event); - } else { - Log.warn("SDL_WaitEvent failed: {}", SDL_GetError()); - } - } - while (SDL_PollEvent(&event)) { - process_event(event); - } - g_events.push_back(AuroraEvent{ - .type = AURORA_NONE, - }); - return g_events.data(); -} - -bool create_window(AuroraBackend backend) { - SDL_WindowFlags flags = SDL_WINDOW_HIGH_PIXEL_DENSITY; -#if TARGET_OS_IOS || TARGET_OS_TV - flags |= SDL_WINDOW_FULLSCREEN; -#else - flags |= SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE; - if (g_config.startFullscreen) { - flags |= SDL_WINDOW_FULLSCREEN; - } -#endif - switch (backend) { -#ifdef AURORA_ENABLE_GX -#ifdef DAWN_ENABLE_BACKEND_VULKAN - case BACKEND_VULKAN: - flags |= SDL_WINDOW_VULKAN; - break; -#endif -#ifdef DAWN_ENABLE_BACKEND_METAL - case BACKEND_METAL: - flags |= SDL_WINDOW_METAL; - break; -#endif -#ifdef DAWN_ENABLE_BACKEND_OPENGL - case BACKEND_OPENGL: - case BACKEND_OPENGLES: - flags |= SDL_WINDOW_OPENGL; - break; -#endif -#endif - default: - break; - } - auto width = static_cast(g_config.windowWidth); - auto height = static_cast(g_config.windowHeight); - if (width == 0 || height == 0) { - width = 1280; - height = 960; - } - if (width < 640) { - width = 640; - } - if (height < 480) { - height = 480; - } - - const Sint32 posX = g_config.hasWindowPosition ? g_config.windowPosX : SDL_WINDOWPOS_CENTERED; - const Sint32 posY = g_config.hasWindowPosition ? g_config.windowPosY : SDL_WINDOWPOS_CENTERED; - - const auto props = SDL_CreateProperties(); - TRY(SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, g_config.appName), "Failed to set {}: {}", - SDL_PROP_WINDOW_CREATE_TITLE_STRING, SDL_GetError()); - TRY(SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, posX), "Failed to set {}: {}", - SDL_PROP_WINDOW_CREATE_X_NUMBER, SDL_GetError()); - TRY(SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, posY), "Failed to set {}: {}", - SDL_PROP_WINDOW_CREATE_Y_NUMBER, SDL_GetError()); - TRY(SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, width), "Failed to set {}: {}", - SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, SDL_GetError()); - TRY(SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, height), "Failed to set {}: {}", - SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, SDL_GetError()); - TRY(SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER, flags), "Failed to set {}: {}", - SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER, SDL_GetError()); - g_window = SDL_CreateWindowWithProperties(props); - if (g_window == nullptr) { - Log.error("Failed to create window: {}", SDL_GetError()); - return false; - } - SDL_SetWindowMinimumSize(g_window, 640, 480); - g_displayMode.store(g_config.startFullscreen ? AURORA_DISPLAY_MODE_BORDERLESS : AURORA_DISPLAY_MODE_WINDOWED, - std::memory_order_release); -#if defined(_WIN32) - install_window_proc_hook(); -#endif - set_window_icon(); - return true; -} - -bool create_renderer() { - if (g_window == nullptr) { - return false; - } - const auto props = SDL_CreateProperties(); - TRY(SDL_SetPointerProperty(props, SDL_PROP_RENDERER_CREATE_WINDOW_POINTER, g_window), "Failed to set {}: {}", - SDL_PROP_RENDERER_CREATE_WINDOW_POINTER, SDL_GetError()); - // Never vsync: presentation must not throttle the guest's own pacing. - TRY(SDL_SetNumberProperty(props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, SDL_RENDERER_VSYNC_DISABLED), - "Failed to set {}: {}", SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, SDL_GetError()); - g_renderer = SDL_CreateRendererWithProperties(props); - if (g_renderer == nullptr) { - Log.error("Failed to create renderer: {}", SDL_GetError()); - return false; - } - return true; -} - -void destroy_window() { -#if defined(_WIN32) - uninstall_window_proc_hook(); -#endif - if (g_renderer != nullptr) { - SDL_DestroyRenderer(g_renderer); - g_renderer = nullptr; - } - if (g_window != nullptr) { - SDL_DestroyWindow(g_window); - g_window = nullptr; - } -} - -void show_window() { - if (g_window != nullptr) { - TRY_WARN(SDL_ShowWindow(g_window), "Failed to show window: {}", SDL_GetError()); - } -} - -bool initialize() { - /* We don't want to initialize anything input related here, otherwise the add events will get lost to the void */ - TRY(SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeLeft LandscapeRight"), "Error setting {}: {}", SDL_HINT_ORIENTATIONS, - SDL_GetError()); - TRY(SDL_InitSubSystem(SDL_INIT_EVENTS | SDL_INIT_VIDEO), "Error initializing SDL: {}", SDL_GetError()); - -#if !defined(_WIN32) && !defined(__APPLE__) - TRY(SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0"), "Error setting {}: {}", - SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, SDL_GetError()); -#endif - TRY(SDL_SetHint(SDL_HINT_SCREENSAVER_INHIBIT_ACTIVITY_NAME, g_config.appName), "Error setting {}: {}", - SDL_HINT_SCREENSAVER_INHIBIT_ACTIVITY_NAME, SDL_GetError()); - TRY(SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE_RUMBLE_BRAKE, "1"), "Error setting {}: {}", - SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE_RUMBLE_BRAKE, SDL_GetError()); - - TRY(SDL_DisableScreenSaver(), "Error disabling screensaver: {}", SDL_GetError()); - if (g_config.allowJoystickBackgroundEvents) { - TRY(SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"), "Error setting {}: {}", - SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, SDL_GetError()); - } - - return true; -} - -bool initialize_event_watch() { - TRY(SDL_AddEventWatch(lifecycle_event_watch, nullptr), "Error adding SDL event watch: {}", SDL_GetError()); - return true; -} - -void shutdown() { - SDL_RemoveEventWatch(lifecycle_event_watch, nullptr); - destroy_window(); - TRY_WARN(SDL_EnableScreenSaver(), "Error enabling screensaver: {}", SDL_GetError()); - SDL_Quit(); -} - -AuroraWindowSize get_window_size() { - int width = 0; - int height = 0; - int native_fb_w = 0; - int native_fb_h = 0; - ASSERT(SDL_GetWindowSize(g_window, &width, &height), "Failed to get window size: {}", SDL_GetError()); - ASSERT(SDL_GetWindowSizeInPixels(g_window, &native_fb_w, &native_fb_h), "Failed to get window size in pixels: {}", - SDL_GetError()); - - int fb_w = native_fb_w; - int fb_h = native_fb_h; - const auto [baseW, baseH] = vi::configured_fb_size(); - if (g_forceAspect169.load(std::memory_order_acquire) && native_fb_w > 0 && native_fb_h > 0) { - if (g_frameBufferScale > 0.f && baseW > 0 && baseH > 0) { - const auto [scaledW, scaledH] = - scale_frame_buffer_to_aspect(static_cast(baseW), static_cast(baseH), - g_frameBufferScale, 16.f / 9.f); - fb_w = scaledW; - fb_h = scaledH; - } else { - fb_w = std::min(native_fb_w, - std::max(1, static_cast(std::lround(native_fb_h * (16.f / 9.f))))); - fb_h = std::min(native_fb_h, - std::max(1, static_cast(std::lround(native_fb_w * (9.f / 16.f))))); - } - } else if (g_frameBufferAspectFit && baseW > 0 && baseH > 0) { - float renderScale = g_frameBufferScale > 0.f ? g_frameBufferScale : 1.f; - if (g_frameBufferScale <= 0.f) { - renderScale = std::min(static_cast(native_fb_w) / static_cast(baseW), - static_cast(native_fb_h) / static_cast(baseH)); - if (renderScale < 1.f) { - renderScale = 1.f; - } - } - fb_w = std::max(1, static_cast(std::lround(static_cast(baseW) * renderScale))); - fb_h = std::max(1, static_cast(std::lround(static_cast(baseH) * renderScale))); - } else if (g_frameBufferScale > 0.f && baseW > 0 && baseH > 0) { - const auto [scaledW, scaledH] = - scale_frame_buffer_to_aspect(static_cast(baseW), static_cast(baseH), g_frameBufferScale, - static_cast(fb_w) / static_cast(fb_h)); - fb_w = scaledW; - fb_h = scaledH; - } - - const float scale = SDL_GetWindowDisplayScale(g_window); - return { - .width = static_cast(width), - .height = static_cast(height), - .fb_width = static_cast(fb_w), - .fb_height = static_cast(fb_h), - .native_fb_width = static_cast(native_fb_w), - .native_fb_height = static_cast(native_fb_h), - .scale = scale, - }; -} - -SDL_Window* get_sdl_window() { return g_window; } - -SDL_Renderer* get_sdl_renderer() { return g_renderer; } - -bool is_paused() noexcept { - if (!is_presentable()) { - return true; - } - const auto flags = SDL_GetWindowFlags(g_window); - if ((flags & SDL_WINDOW_HIDDEN) != 0u) { - return true; - } - // Wait until the window has received focus before respecting pauseOnFocusLost - if (!g_gotFocus) { - g_gotFocus = (flags & SDL_WINDOW_INPUT_FOCUS) != 0u; - return false; - } - return g_config.pauseOnFocusLost && ((flags & SDL_WINDOW_INPUT_FOCUS) == 0u || (flags & SDL_WINDOW_MINIMIZED) != 0u); -} - -bool is_presentable() noexcept { - return g_window != nullptr && !g_backgrounded.load(std::memory_order_acquire) && - g_surfaceReady.load(std::memory_order_acquire); -} - -void pump_events() noexcept { - if (g_window != nullptr) { - SDL_SyncWindow(g_window); - } - SDL_PumpEvents(); -} - -bool native_resize_pending() noexcept { return g_nativeResizePending.load(std::memory_order_acquire); } - -bool native_window_size_matches(uint32_t width, uint32_t height) noexcept { - if (g_window == nullptr || width == 0 || height == 0) { - return true; - } - uint32_t nativeWidth = 0; - uint32_t nativeHeight = 0; - if (query_native_client_size(nativeWidth, nativeHeight)) { - return nativeWidth == width && nativeHeight == height; - } - const auto size = get_window_size(); - return size.native_fb_width == width && size.native_fb_height == height; -} - -void set_surface_ready(bool ready) noexcept { g_surfaceReady.store(ready, std::memory_order_release); } - -SurfaceLock::SurfaceLock() noexcept { -#if defined(SDL_PLATFORM_ANDROID) - Android_LockActivityMutex(); -#endif -} - -SurfaceLock::~SurfaceLock() { -#if defined(SDL_PLATFORM_ANDROID) - Android_UnlockActivityMutex(); -#endif -} - -bool push_custom_event(CustomEvent eventType) { - SDL_Event event{.type = g_sdlCustomEventsStart + eventType}; - return SDL_PushEvent(&event); -} - -void set_title(const char* title) { - TRY_WARN(SDL_SetWindowTitle(g_window, title), "Failed to set window title: {}", SDL_GetError()); -} - -void set_fullscreen(bool fullscreen) { - set_display_mode(fullscreen ? AURORA_DISPLAY_MODE_BORDERLESS : AURORA_DISPLAY_MODE_WINDOWED); -} - -bool get_fullscreen() { return (SDL_GetWindowFlags(g_window) & SDL_WINDOW_FULLSCREEN) != 0u; } - -void set_display_mode(AuroraDisplayMode mode) { - if (g_window == nullptr) { - return; - } - if (mode < AURORA_DISPLAY_MODE_WINDOWED || mode > AURORA_DISPLAY_MODE_EXCLUSIVE) { - Log.warn("Ignoring invalid display mode {}", static_cast(mode)); - return; - } - const AuroraDisplayMode currentMode = g_displayMode.load(std::memory_order_acquire); - // Exclusive mode is re-applied even when already active: the desired refresh - // rate tracks the frame interpolation target, which can change at runtime. - if (mode == currentMode && mode != AURORA_DISPLAY_MODE_EXCLUSIVE) { - return; - } - - bool success = true; - if (mode == AURORA_DISPLAY_MODE_WINDOWED) { - success = SDL_SetWindowFullscreen(g_window, false); - if (success) { - success = SDL_SetWindowFullscreenMode(g_window, nullptr); - } - } else if (mode == AURORA_DISPLAY_MODE_BORDERLESS) { - if (SDL_GetWindowFullscreenMode(g_window) != nullptr) { - success = SDL_SetWindowFullscreen(g_window, false); - } - if (success) { - success = SDL_SetWindowFullscreenMode(g_window, nullptr); - } - if (success) { - success = SDL_SetWindowFullscreen(g_window, true); - } - } else { - const SDL_DisplayID display = SDL_GetDisplayForWindow(g_window); - const SDL_DisplayMode* desktop = display != 0 ? SDL_GetDesktopDisplayMode(display) : nullptr; - const uint32_t interpolationFps = aurora_get_frame_interpolation_fps(); - const float targetHz = interpolationFps > 60 ? static_cast(interpolationFps) : 60.0f; - SDL_DisplayMode closest{}; - if (desktop == nullptr || - !SDL_GetClosestFullscreenDisplayMode(display, desktop->w, desktop->h, targetHz, true, &closest)) { - Log.warn("No exclusive fullscreen mode near {:.0f} Hz is available: {}", targetHz, SDL_GetError()); - return; - } - const SDL_DisplayMode* active = SDL_GetWindowFullscreenMode(g_window); - if (mode == currentMode && active != nullptr && active->w == closest.w && active->h == closest.h && - active->refresh_rate == closest.refresh_rate) { - return; - } - if (get_fullscreen() && mode != currentMode) { - success = SDL_SetWindowFullscreen(g_window, false); - } - if (success) { - success = SDL_SetWindowFullscreenMode(g_window, &closest); - } - if (success) { - success = SDL_SetWindowFullscreen(g_window, true); - } - if (success) { - Log.info("Exclusive fullscreen requested at {}x{} {:.3f} Hz", closest.w, closest.h, closest.refresh_rate); - } - } - - if (!success) { - Log.warn("Failed to change display mode: {}", SDL_GetError()); - return; - } - g_displayMode.store(mode, std::memory_order_release); - g_nativeResizePending.store(true, std::memory_order_release); - TRY_WARN(push_custom_event(CustomEvent::FutureResize), "Failed to queue fullscreen resize event: {}", - SDL_GetError()); -} - -AuroraDisplayMode get_display_mode() { return g_displayMode.load(std::memory_order_acquire); } - -void set_window_size(uint32_t width, uint32_t height) { - TRY_WARN(SDL_RestoreWindow(g_window), "Failed to un-maximize window: {}", SDL_GetError()); - TRY_WARN(SDL_SetWindowSize(g_window, width, height), "Failed to set window size: {}", SDL_GetError()); -} - -void set_window_position(uint32_t x, uint32_t y) { - TRY_WARN(SDL_SetWindowPosition(g_window, x, y), "Failed to set window position: {}", SDL_GetError()); -} - -void center_window() { - TRY_WARN(SDL_SetWindowPosition(g_window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED), - "Failed to center window: {}", SDL_GetError()); -} - -void sync_frame_buffer_size() noexcept { - if (g_window != nullptr) { - resize_swapchain(); - } -} - -static void push_future_resize_event() { - TRY_WARN(push_custom_event(CustomEvent::FutureResize), "Failed to push SDL event for future resize: {}", - SDL_GetError()); -} - -void request_frame_buffer_resize() { - if (g_window != nullptr) { - // Publish the request before waking the SDL loop: the render worker consumes it at an ordered - // frame boundary, and the main thread must never recreate WebGPU targets mid-frame. - g_nativeResizePending.store(true, std::memory_order_release); - push_future_resize_event(); - } -} - -void set_frame_buffer_scale(float scale) { - if (scale < 0.f) { - scale = 0.f; - } - if (g_frameBufferScale == scale) { - return; - } - g_frameBufferScale = scale; - request_frame_buffer_resize(); -} - -void set_frame_buffer_aspect_fit(bool fit) { - if (g_frameBufferAspectFit == fit) { - return; - } - - g_frameBufferAspectFit = fit; - request_frame_buffer_resize(); -} - -void set_force_aspect_16_9(bool force) { - if (g_forceAspect169.load(std::memory_order_relaxed) == force) { - return; - } - g_forceAspect169.store(force, std::memory_order_release); - request_frame_buffer_resize(); -} - -void set_present_surface_fill(bool fill) { - g_presentSurfaceFill = fill; -} - -void lock_present_aspect_ratio(int width, int height) { - if (width <= 0 || height <= 0) { - unlock_present_aspect_ratio(); - return; - } - if (g_presentAspectWidth == width && g_presentAspectHeight == height) { - return; - } - g_presentAspectWidth = width; - g_presentAspectHeight = height; -} - -void unlock_present_aspect_ratio() { - g_presentAspectWidth = 0; - g_presentAspectHeight = 0; -} - -bool get_present_aspect_ratio(float& aspect) noexcept { - if (g_forceAspect169.load(std::memory_order_acquire)) { - aspect = 16.f / 9.f; - return true; - } - if (g_presentSurfaceFill && g_window != nullptr) { - // Queried once per presentation snapshot; use the cached native client size - // instead of re-entering SDL for a value the window procedure already knows. - uint32_t nativeWidth = 0; - uint32_t nativeHeight = 0; - if (query_native_client_size(nativeWidth, nativeHeight) && nativeWidth > 0 && nativeHeight > 0) { - aspect = static_cast(nativeWidth) / static_cast(nativeHeight); - return true; - } - int width = 0; - int height = 0; - if (SDL_GetWindowSizeInPixels(g_window, &width, &height) && width > 0 && height > 0) { - aspect = static_cast(width) / static_cast(height); - return true; - } - } - if (g_presentAspectWidth <= 0 || g_presentAspectHeight <= 0) { - aspect = 0.f; - return false; - } - aspect = (static_cast(g_presentAspectWidth) / static_cast(g_presentAspectHeight)) * - vi::present_aspect_correction(); - return aspect > 0.f; -} - -void set_background_input(bool value) { SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, value ? "1" : "0"); } - -} // namespace aurora::window - -#if defined(SDL_PLATFORM_ANDROID) -extern "C" JNIEXPORT void JNICALL Java_org_libsdl_app_SDLSurface_auroraNativeSetSurfaceReady(JNIEnv*, jclass, - jboolean ready) { - aurora::window::set_surface_ready(ready == JNI_TRUE); -} -#endif diff --git a/aurora-main/lib/window.hpp b/aurora-main/lib/window.hpp deleted file mode 100644 index 94032f7..0000000 --- a/aurora-main/lib/window.hpp +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include -#include - -struct SDL_Window; -struct SDL_Renderer; - -namespace aurora::window { - -enum class CustomEvent { - FutureResize, - RefreshSurface, - End, -}; -static Uint32 operator+(Uint32 lhs, CustomEvent rhs) { return lhs + static_cast(rhs); } - -// On Android in particular, we need to hold a mutex around critical areas like surface creation -// and presentation, so that the SDLActivity doesn't destroy the surface out from underneath us. -class SurfaceLock { -public: - SurfaceLock() noexcept; - ~SurfaceLock(); - - SurfaceLock(const SurfaceLock&) = delete; - SurfaceLock& operator=(const SurfaceLock&) = delete; -}; - -bool initialize(); -bool initialize_event_watch(); -bool push_custom_event(CustomEvent eventType); -void shutdown(); -bool create_window(AuroraBackend backend); -bool create_renderer(); -void destroy_window(); -void show_window(); -AuroraWindowSize get_window_size(); -const AuroraEvent* poll_events(); -SDL_Window* get_sdl_window(); -SDL_Renderer* get_sdl_renderer(); -bool is_paused() noexcept; -bool is_presentable() noexcept; -void pump_events() noexcept; -bool native_resize_pending() noexcept; -bool native_window_size_matches(uint32_t width, uint32_t height) noexcept; -void set_surface_ready(bool ready) noexcept; -void set_title(const char* title); -void set_fullscreen(bool fullscreen); -bool get_fullscreen(); -void set_display_mode(AuroraDisplayMode mode); -AuroraDisplayMode get_display_mode(); -void set_window_size(uint32_t width, uint32_t height); -void set_window_position(uint32_t x, uint32_t y); -void center_window(); -void sync_frame_buffer_size() noexcept; -void request_frame_buffer_resize(); -void set_frame_buffer_scale(float scale); -void set_frame_buffer_aspect_fit(bool fit); -void set_force_aspect_16_9(bool force); -void set_present_surface_fill(bool fill); -void lock_present_aspect_ratio(int width, int height); -void unlock_present_aspect_ratio(); -bool get_present_aspect_ratio(float& aspect) noexcept; -void set_background_input(bool value); -}; // namespace aurora::window diff --git a/aurora-main/tests/CMakeLists.txt b/aurora-main/tests/CMakeLists.txt deleted file mode 100644 index d20dedd..0000000 --- a/aurora-main/tests/CMakeLists.txt +++ /dev/null @@ -1,108 +0,0 @@ -include(FetchContent) -include(GoogleTest) - -if (NOT TARGET gtest) - FetchContent_Declare(googletest - URL https://github.com/google/googletest/archive/refs/tags/v1.17.0.tar.gz - URL_HASH SHA256=65fab701d9829d38cb77c14acdc431d2108bfdbf8979e40eb8ae567edf10b27c - DOWNLOAD_EXTRACT_TIMESTAMP FALSE - EXCLUDE_FROM_ALL - ) - FetchContent_MakeAvailable(googletest) -endif () - -if (AURORA_ENABLE_GX) - # GX FIFO round-trip tests - # Compile GX sources directly to avoid pulling in the full renderer/WebGPU runtime - add_executable(gx_fifo_tests - gx_fifo_test.cpp - gx_test_stubs.cpp - texture_bind_group_cache_key_test.cpp - renderer_regression_test.cpp - ../lib/gfx/efb_ram_encoder.cpp - # GX API implementations (encoders) - ../lib/dolphin/gx/GXBump.cpp - ../lib/dolphin/gx/GXCull.cpp - ../lib/dolphin/gx/GXCpu2Efb.cpp - ../lib/dolphin/gx/GXDispList.cpp - ../lib/dolphin/gx/GXDraw.cpp - ../lib/dolphin/gx/GXExtra.cpp - ../lib/dolphin/gx/GXFifo.cpp - ../lib/dolphin/gx/GXFrameBuffer.cpp - ../lib/dolphin/gx/GXGeometry.cpp - ../lib/dolphin/gx/GXGet.cpp - ../lib/dolphin/gx/GXLighting.cpp - ../lib/dolphin/gx/GXManage.cpp - ../lib/dolphin/gx/GXAurora.cpp - ../lib/dolphin/gx/GXPixel.cpp - ../lib/dolphin/gx/GXTev.cpp - ../lib/dolphin/gx/GXTexture.cpp - ../lib/dolphin/gx/GXTransform.cpp - ../lib/dolphin/gx/GXVert.cpp - # FIFO/command processor (encoder + decoder) - ../lib/gx/fifo.cpp - ../lib/gx/command_processor.cpp - ../lib/gx/shader_info.cpp - ../lib/gx/frame_interpolation.cpp - ) - - target_include_directories(gx_fifo_tests PRIVATE - ../include - ../lib - ../lib/dolphin/gx - ) - - target_compile_definitions(gx_fifo_tests PRIVATE AURORA TARGET_PC) - - target_link_libraries(gx_fifo_tests PRIVATE - gtest - gtest_main - fmt::fmt - xxhash - absl::flat_hash_map - absl::btree - dawn::dawncpp_headers - TracyClient - ${AURORA_SDL3_TARGET} - ) - - gtest_discover_tests(gx_fifo_tests) - - option(AURORA_BUILD_GPU_TESTS "Build renderer pixel tests requiring a graphics device" OFF) - if (AURORA_BUILD_GPU_TESTS) - add_executable(gx_readback_tests gpu_readback_test.cpp) - target_compile_features(gx_readback_tests PRIVATE cxx_std_20) - target_include_directories(gx_readback_tests PRIVATE ../lib) - target_link_libraries(gx_readback_tests PRIVATE - aurora::core aurora::gx aurora::pad aurora::vi aurora::mtx aurora::si - dawn::dawncpp_headers absl::flat_hash_map absl::btree TracyClient) - add_test(NAME gx_readback_tests COMMAND gx_readback_tests "${CMAKE_CURRENT_BINARY_DIR}/readback-cache") - set_tests_properties(gx_readback_tests PROPERTIES TIMEOUT 90) - endif () -endif () # AURORA_ENABLE_GX - -# DVD API tests -if (TARGET aurora::dvd) - add_executable(dvd_tests test_dvd.cpp) - target_link_libraries(dvd_tests PRIVATE aurora::dvd gtest gtest_main) - - # Pass disc image path as a compile definition if provided - if (DEFINED DVD_TEST_IMAGE AND EXISTS "${DVD_TEST_IMAGE}") - target_compile_definitions(dvd_tests PRIVATE DVD_TEST_IMAGE="${DVD_TEST_IMAGE}") - endif () - - gtest_discover_tests(dvd_tests) -endif () - -add_executable(os_alloc_tests - os_alloc_test.cpp - os_test_globals.cpp - ../lib/dolphin/os/OSAlloc.cpp - ../lib/logging.cpp -) -target_include_directories(os_alloc_tests PRIVATE - ../include -) -target_compile_definitions(os_alloc_tests PRIVATE AURORA TARGET_PC) -target_link_libraries(os_alloc_tests PRIVATE gtest gtest_main fmt::fmt) -gtest_discover_tests(os_alloc_tests) diff --git a/aurora-main/tests/gpu_readback_test.cpp b/aurora-main/tests/gpu_readback_test.cpp deleted file mode 100644 index 8ce3dc9..0000000 --- a/aurora-main/tests/gpu_readback_test.cpp +++ /dev/null @@ -1,363 +0,0 @@ -// ROM-free integration probe. Links the actual maintained Aurora renderer. -#include "gfx/common.hpp" -#include "gfx/clear.hpp" -#include "gfx/efb_ram_copy.hpp" -#include "gfx/pipeline_cache.hpp" -#include "gfx/texture.hpp" -#include "gx/gx.hpp" -#include "gx/fifo.hpp" -#include "gx/command_processor.hpp" -#include "gx/frame_interpolation.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { -using namespace aurora; -std::atomic errors{}; -std::atomic guestWrites{}; -// Keep destinations alive through shutdown, including any failing wait. -std::array guarded; -std::array guardedBake; -void require(bool value, const char* message) { - if (!value) throw std::runtime_error(message); -} -void submit(bool final, bool download = false, bool async = false) { - auto encoder = webgpu::g_device.CreateCommandEncoder(); - if (final) gfx::end_frame(encoder); else gfx::end_batch(encoder); - gfx::render(encoder); - if (download) gfx::efb_ram::encode_downloads(encoder); - if (async) gfx::efb_ram::encode_async_downloads(encoder); - auto commands = encoder.Finish(); - webgpu::g_queue.Submit(1, &commands); - if (download) require(gfx::efb_ram::complete_downloads(), "EFB readback failed"); - gfx::after_submit(); - if (!final) require(gfx::resume_frame(), "Batch resume failed"); -} - -constexpr std::array, 4> colors{{ - {255, 0, 0, 255}, {0, 255, 0, 255}, {0, 0, 255, 255}, {255, 255, 0, 255}}}; -using Pixels = std::vector; -Pixels expected(unsigned extent) { - Pixels bytes(extent * extent * 4); - // GX RGBA8: 4x4 tiles, sixteen A/R pairs followed by sixteen G/B pairs. - for (unsigned y = 0; y < extent; ++y) for (unsigned x = 0; x < extent; ++x) { - const auto color = colors[y * 4 / extent]; - const auto tile = ((y / 4) * (extent / 4) + x / 4) * 64; - const auto pair = ((y % 4) * 4 + x % 4) * 2; - bytes[tile + pair] = color[3]; bytes[tile + pair + 1] = color[0]; - bytes[tile + 32 + pair] = color[1]; bytes[tile + 33 + pair] = color[2]; - } - return bytes; -} - -Pixels run(unsigned splitEvery, bool async = false, bool offscreen = false, unsigned geometry = 0, bool capacityStress = false, bool interpolate = false, bool frameWorker = false, unsigned copyCase = 0) { - require(!async || !offscreen, "Combined probe mode is not supported"); - guardedBake.fill(0xa5); - gx::g_gxState.clearColor = {0.f, 0.f, 0.f, 1.f}; - require(frameWorker ? aurora_begin_frame() : gfx::begin_frame(), "Frame begin failed"); - std::array, 4> positions{}; - if (geometry) { - alignas(32) static std::array fifo; - GXInit(fifo.data(), fifo.size()); - gx::g_gxState.viewportPolicy = AURORA_VIEWPORT_NATIVE; - GXSetViewport(0.f, 0.f, 64.f, 64.f, 0.f, 1.f); - GXSetScissor(0, 0, 64, 64); - GXSetCullMode(GX_CULL_NONE); - GXSetZMode(false, GX_ALWAYS, false); - GXSetBlendMode(GX_BM_NONE, GX_BL_ONE, GX_BL_ZERO, GX_LO_COPY); - GXSetColorUpdate(true); GXSetAlphaUpdate(true); - GXSetNumTexGens(0); GXSetNumChans(1); GXSetNumTevStages(copyCase ? copyCase : 1); - for (unsigned stage = 1; stage < copyCase; ++stage) { - GXSetTevOrder(static_cast(stage), GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); - GXSetTevOp(static_cast(stage), GX_PASSCLR); - } - GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); - GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR); - GXSetChanCtrl(GX_COLOR0A0, false, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE); - const float projection[]{interpolate ? 0.f : 1.f, 1.f, 0.f, 1.f, 0.f, 0.f, -0.5f}; - GXSetProjectionv(projection); - GXClearVtxDesc(); - GXSetVtxDesc(GX_VA_POS, geometry == 2 ? GX_INDEX8 : GX_DIRECT); - GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT); - if (geometry == 2) GXSetArray(GX_VA_POS, positions.data(), sizeof(positions), sizeof(positions[0]), true); - GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); - GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); - gx::fifo::drain(); - } - const auto pipeline = gfx::pipeline_ref(gfx::clear::PipelineConfig{}); - for (unsigned band = 0; band < 4; ++band) { - const auto c = colors[band]; - if (geometry) { - const float top = 1.f - band * 0.5f; - const float bottom = top - 0.5f; - const float z = interpolate ? -1.f : 0.f; - positions = {{{-1.f, top, z}, {1.f, top, z}, {1.f, bottom, z}, {-1.f, bottom, z}}}; - // Keep the same array address/format and change only its bytes between draws. - if (geometry == 2) GXInvalidateVtxCache(); - if (geometry == 3) { - std::array raw{}; - for (unsigned index = 0; index < positions.size(); ++index) { - for (unsigned axis = 0; axis < 3; ++axis) { - const auto bits = std::bit_cast(positions[index][axis]); - for (unsigned byte = 0; byte < 4; ++byte) - raw[index * 16 + axis * 4 + byte] = bits >> (24 - byte * 8); - } - std::copy(c.begin(), c.end(), raw.begin() + index * 16 + 12); - } - require(gx::fifo::submit_raw_draw(GX_QUADS, GX_VTXFMT0, raw.data(), 4, raw.size()), - "Raw bridge rejected valid quad"); - } else { - GXBegin(GX_QUADS, GX_VTXFMT0, 4); - for (unsigned index = 0; index < positions.size(); ++index) { - if (geometry == 2) GXPosition1x8(index); - else GXPosition3f32(positions[index][0], positions[index][1], positions[index][2]); - GXColor4u8(c[0], c[1], c[2], 255); - } - GXEnd(); - } - } else { - gfx::push_draw_command(gfx::clear::DrawData{ - .pipeline = pipeline, - .color = {c[0] / 255., c[1] / 255., c[2] / 255., 1.}, - .depth = 0.5f, - .useScissor = true, - .scissor = {0, static_cast(band * 16), 64, 16}}); - } - if (offscreen && band == 0) { - // Suspend a partially recorded EFB, bake an independently observable copy, - // then resume it before a possible capacity-boundary submission. - gfx::begin_offscreen(64, 64); - gfx::push_draw_command(gfx::clear::DrawData{ - .pipeline = pipeline, .color = {1., 0., 1., 1.}, .depth = 0.25f}); - if (capacityStress) for (unsigned draw = 0; draw < 24; ++draw) { - gfx::push_draw_command(gfx::clear::DrawData{ - .pipeline = pipeline, .color = {1., 0., 1., 1.}, .depth = 0.25f, - .useScissor = true, .scissor = {0, 0, 4, 4}}); - } - auto baked = gfx::new_render_texture(64, 64, GX_TF_RGBA8, "Aurora probe offscreen bake"); - gfx::resolve_pass(baked, {0, 0, 64, 64}, false, false, false, - {0.f, 0.f, 0.f, 1.f}, 1.f, GX_TF_RGBA8, nullptr, false, - nullptr, false, 1.f, false, false, true); - gfx::efb_ram::schedule(guardedBake.data() + 16, 16, 16, GX_TF_RGBA8, baked); - gfx::end_offscreen(); - if (capacityStress) { - require(gfx::efb_ram::prepare_downloads(), "Early bake readback preparation failed"); - for (unsigned draw = 0; draw < 24; ++draw) { - gfx::push_draw_command(gfx::clear::DrawData{ - .pipeline = pipeline, .color = {1., 0., 0., 1.}, .depth = 0.5f, - .useScissor = true, .scissor = {0, 0, 4, 4}}); - } - } - } - if (splitEvery && band < 3 && (band + 1) % splitEvery == 0) submit(false); - } - auto texture = gfx::new_render_texture(64, 64, GX_TF_RGBA8, "Aurora probe persistent copy"); - static std::array copyDestination; - if (copyCase) { - gx::fifo::drain(); - GXSetTexCopySrc(0, 0, 64, 64); - GXSetTexCopyDst(64, 64, GX_TF_RGBA8, GX_FALSE); - GXCopyTex(copyDestination.data(), GX_FALSE); - texture = gx::g_gxState.copyTextures.at(copyDestination.data()).handle; - } else { - // A partial clear forces the real snapshot and clear-uniform paths after the copy. - gfx::resolve_pass(texture, {0, 0, 64, 64}, true, true, true, {0.f, 0.f, 0.f, 1.f}, - 1.f, GX_TF_RGBA8, nullptr, false, nullptr, false, 1.f, false, false, true); - } - guarded.fill(0xa5); - const unsigned extent = async ? 4 : 16; - const unsigned bytes = extent * extent * 4; - gfx::efb_ram::schedule(guarded.data() + 16, extent, extent, GX_TF_RGBA8, texture); - const auto before = guestWrites.load(std::memory_order_acquire); - if (async) gfx::efb_ram::seal_async_downloads(); - else require(gfx::efb_ram::prepare_downloads(), "Readback preparation failed"); - if (frameWorker) { - require(!async && aurora_flush_efb_copies_to_ram(), "Worker-mode EFB readback failed"); - aurora_end_frame(); - } else submit(true, !async, async); - if (async) { - const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(5); - while (guestWrites.load(std::memory_order_acquire) == before) { - webgpu::g_instance.ProcessEvents(); - require(std::chrono::steady_clock::now() < deadline, "Async readback did not complete"); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - } - require(std::all_of(guarded.begin(), guarded.begin() + 16, [](auto b) { return b == 0xa5; }) && - std::all_of(guarded.begin() + 16 + bytes, guarded.end(), [](auto b) { return b == 0xa5; }), - "Readback wrote outside its destination"); - if (offscreen) { - require(std::all_of(guardedBake.begin(), guardedBake.begin() + 16, [](auto b) { return b == 0xa5; }) && - std::all_of(guardedBake.end() - 16, guardedBake.end(), [](auto b) { return b == 0xa5; }), - "Offscreen readback wrote outside its destination"); - for (unsigned tile = 0; tile < 16; ++tile) for (unsigned pair = 0; pair < 16; ++pair) { - const auto offset = 16 + tile * 64 + pair * 2; - require(guardedBake[offset] == 255 && guardedBake[offset + 1] == 255 && - guardedBake[offset + 32] == 0 && guardedBake[offset + 33] == 255, - "Offscreen bake did not preserve expected magenta pixels"); - } - } - Pixels pixels(guarded.begin() + 16, guarded.begin() + 16 + bytes); - return pixels; -} -} // namespace - -int main(int argc, char** argv) { - if (argc != 2) return 2; - std::filesystem::create_directories(argv[1]); - AuroraConfig config{}; - config.appName = "Aurora readback regression tests"; - config.userPath = argv[1]; - config.cachePath = argv[1]; - config.resourcesPath = argv[1]; - config.desiredBackend = BACKEND_AUTO; - config.windowWidth = 64; - config.windowHeight = 64; - config.msaa = 1; - config.maxTextureAnisotropy = 1; - config.logLevel = LOG_INFO; - config.logCallback = [](AuroraLogLevel level, const char* module, const char* message, unsigned size) { - if (level >= LOG_ERROR) ++errors; - std::fprintf(stderr, "[%s] %.*s\n", module, static_cast(size), message); - }; - const auto initialized = aurora_initialize(1, argv, &config); - if (initialized.initializationStatus != AURORA_INITIALIZATION_SUCCESS) return 3; - aurora_set_skip_unready_pipelines(true); - aurora_set_guest_write_hooks(nullptr, [](const void*, size_t) { - guestWrites.fetch_add(1, std::memory_order_release); - }); - try { - const auto prewarmQueued = gfx::queued_pipeline_count(); - const auto prewarmDeadline = std::chrono::steady_clock::now() + std::chrono::seconds(60); - while (gfx::queued_pipeline_count() != 0) { - require(std::chrono::steady_clock::now() < prewarmDeadline, "Seeded pipeline prewarm did not finish"); - webgpu::g_instance.ProcessEvents(); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - std::printf("Actual Aurora completed seeded startup queue (%u observed pending)\n", prewarmQueued); - const auto control = run(0); - for (unsigned band = 0; band < 4; ++band) { - const auto tile = band * 4 * 64; - std::fprintf(stderr, "band=%u ARGB=%u,%u,%u,%u\n", band, control[tile], - control[tile + 1], control[tile + 32], control[tile + 33]); - } - require(control == expected(16), "Unsplit pixels differ from independently expected GX data"); - for (unsigned iteration = 0; iteration < 9; ++iteration) { - const auto splitEvery = iteration % 3 + 1; - require(run(splitEvery) == control, "Split pixels differ from unsplit control"); - std::printf("Actual Aurora split=%u iteration=%u matched native tiled readback\n", splitEvery, iteration); - } - for (unsigned iteration = 0; iteration < 9; ++iteration) { - require(run(iteration % 3 + 1, true) == expected(4), "Async pixels differ from expected GX data"); - std::printf("Actual Aurora async iteration=%u matched native tiled readback\n", iteration); - } - for (unsigned splitEvery = 0; splitEvery < 4; ++splitEvery) { - require(run(splitEvery, false, true) == expected(16), "Offscreen interlude changed the suspended EFB"); - std::printf("Actual Aurora offscreen split=%u preserved bake and suspended EFB\n", splitEvery); - } - for (unsigned splitEvery = 0; splitEvery < 4; ++splitEvery) { - require(run(splitEvery, false, false, true) == expected(16), "GX FIFO quad pixels differ from expected output"); - std::printf("Actual Aurora GX FIFO split=%u preserved direct vertices, indices and uniforms\n", splitEvery); - } - for (unsigned splitEvery = 0; splitEvery < 4; ++splitEvery) { - require(run(splitEvery, false, false, 2) == expected(16), "Invalidated GX array pixels differ from expected output"); - std::printf("Actual Aurora GX invalidation split=%u refreshed the same array address\n", splitEvery); - } - const gfx::StagingSizes physical{gfx::VertexBufferSize, gfx::UniformBufferSize, - gfx::IndexBufferSize, gfx::StorageBufferSize}; - const auto uniformTail = gx::MaxUniformSize + 32 * gfx::staging_uniform_bytes(48); - for (unsigned buffer = 0; buffer < 4; ++buffer) { - auto limits = physical; - limits[buffer] = buffer == 0 ? 128 : buffer == 1 ? uniformTail + 512 : - buffer == 2 ? 24 : 2 * gfx::staging_storage_bytes(48); - gfx::set_staging_capacity_limits_for_testing(limits); - const auto before = gfx::staging_split_count(); - require(run(0, false, false, buffer == 1 ? 0 : buffer == 3 ? 2 : 1) == expected(16), - "Automatic capacity split changed pixels"); - require(gfx::staging_split_count() > before, "Forced capacity did not split"); - const auto highWater = gfx::staging_high_water(); - for (unsigned i = 0; i < limits.size(); ++i) - require(highWater[i] <= limits[i], "Actual staging usage exceeded admission budget"); - std::printf("Actual staging high-water V/U/I/S=%llu/%llu/%llu/%llu bytes\n", - static_cast(highWater[0]), static_cast(highWater[1]), - static_cast(highWater[2]), static_cast(highWater[3])); - std::printf("Actual Aurora automatic capacity buffer=%u splits=%llu matched pixels\n", buffer, - static_cast(gfx::staging_split_count() - before)); - } - auto limits = physical; - limits[0] = 128; - gfx::set_staging_capacity_limits_for_testing(limits); - require(run(0, false, false, 3) == expected(16), "Raw bridge capacity split changed pixels"); - std::puts("Actual Aurora raw bridge capacity split preserved direct quad pixels"); - limits = physical; - limits[1] = uniformTail + 768; - gfx::set_staging_capacity_limits_for_testing(limits); - const auto beforeBake = gfx::staging_split_count(); - require(run(0, false, true, 0, true) == expected(16), - "Automatic offscreen split changed bake or suspended EFB"); - require(gfx::staging_split_count() - beforeBake >= 9, "Offscreen test did not reuse all staging slots"); - std::printf("Actual Aurora automatic offscreen/readback splits=%llu preserved all pixels\n", - static_cast(gfx::staging_split_count() - beforeBake)); - gfx::set_staging_capacity_limits_for_testing(physical); - aurora_set_frame_interpolation_fps(120); - for (unsigned frame = 0; frame < 3; ++frame) - require(run(0, false, false, 2, false, true) == expected(16), "Perspective warmup changed pixels"); - AuroraFrameInterpolationDiagnostics interpolation{}; - gx::get_frame_interpolation_diagnostics(interpolation); - require(interpolation.matchable > 0 && interpolation.activeSamples > 0, - "Interpolation probe did not establish matching perspective draws"); - limits = physical; - limits[3] = 2 * gfx::staging_storage_bytes(48); - gfx::set_staging_capacity_limits_for_testing(limits); - require(run(0, false, false, 2, false, true) == expected(16), "Interpolated split changed native pixels"); - gx::get_frame_interpolation_diagnostics(interpolation); - require(!interpolation.replaySafe, "Split frame incorrectly retained interpolation replay"); - aurora_set_frame_interpolation_fps(0); - std::puts("Actual Aurora matched perspective interpolation survived capacity split and disabled replay"); - limits = physical; - limits[0] = 32; // One quad needs 64 bytes: typed rejection before any draw allocation. - gfx::set_staging_capacity_limits_for_testing(limits); - bool oversized = false; - try { run(0, false, false, 1); } - catch (const gfx::StagingCapacityError&) { oversized = true; } - require(oversized, "Oversized primitive was not rejected"); - require(gfx::staging_usage() == gfx::StagingSizes{}, "Oversized primitive partially allocated"); - gx::fifo::clear_buffer(); - gfx::abort_frame(); - gfx::set_staging_capacity_limits_for_testing(physical); - std::puts("Actual Aurora oversized primitive rejected before staging mutation"); - require(run(0, false, false, 1) == expected(16), "Renderer failed after rejected primitive cleanup"); - limits = physical; - limits[3] = 2 * gfx::staging_storage_bytes(48); - gfx::set_staging_capacity_limits_for_testing(limits); - aurora_set_frame_interpolation_fps(120); - for (unsigned frame = 0; frame < 16; ++frame) - require(run(0, false, false, 2, false, true, true) == expected(16), - "Frame-worker capacity split changed pixels"); - // Grant preparation of the next frame before joining DONE, exactly as the - // real producer does; leave no worker waiting for a future begin_frame. - require(aurora_begin_frame(), "Final worker frame preparation failed"); - aurora::wait_for_frame_worker(); - gfx::abort_frame(); - aurora_set_frame_interpolation_fps(0); - gfx::set_staging_capacity_limits_for_testing(physical); - std::puts("Actual Aurora frame worker completed 16 capacity-split perspective frames"); - require(errors == 0, "Renderer reported an error"); - } catch (const std::exception& error) { - std::fprintf(stderr, "FAIL: %s\n", error.what()); - aurora_shutdown(); - return 4; - } - aurora_shutdown(); - if (errors != 0) return 4; - std::puts("Actual Aurora clear/resolve/snapshot/downsample/readback batches passed"); -} diff --git a/aurora-main/tests/gx_fifo_test.cpp b/aurora-main/tests/gx_fifo_test.cpp deleted file mode 100644 index d72ce43..0000000 --- a/aurora-main/tests/gx_fifo_test.cpp +++ /dev/null @@ -1,5029 +0,0 @@ -// GX FIFO encode/decode round-trip tests: call a GX function, capture the FIFO bytes, reset -// g_gxState, feed them to command_processor::process(), then check the decoded state. - -#include "gx_test_common.hpp" -#include "gfx/efb_ram_encoder.hpp" -#include "gfx/tex_copy_format_contract.hpp" -#include "gx/shader_info.hpp" -#include "gx/pipeline.hpp" -#include "__gx.h" - -#include -#include -#include -#include - -using aurora::gx::g_gxState; - -TEST(GXPipelineConfig, RejectsInvalidDeserializedEnums) { - aurora::gx::PipelineConfig config{}; - EXPECT_TRUE(aurora::gx::valid_pipeline_config(config)); - - config.depthFunc = static_cast(0x009F01F2); - EXPECT_FALSE(aurora::gx::valid_pipeline_config(config)); -} - -TEST(GXPipelineConfig, FoggedLateZLogicOrPreservesEggDofMask) { - EXPECT_EQ(aurora::gx::effective_pipeline_fog_type(GX_FOG_PERSP_LIN, GX_ZT_REPLACE, - false, GX_BM_LOGIC, GX_LO_OR), - GX_FOG_PERSP_LIN); - - // Keep the existing defensive suppression for late-Z mask passes whose - // integer logic operation still has only an inexact WebGPU fallback. - EXPECT_EQ(aurora::gx::effective_pipeline_fog_type(GX_FOG_PERSP_LIN, GX_ZT_REPLACE, - false, GX_BM_LOGIC, GX_LO_COPY), - GX_FOG_NONE); - - // Logic fallbacks do not require this workaround when Z-texturing is early. - EXPECT_EQ(aurora::gx::effective_pipeline_fog_type(GX_FOG_PERSP_LIN, GX_ZT_REPLACE, - true, GX_BM_LOGIC, GX_LO_COPY), - GX_FOG_PERSP_LIN); -} - -TEST(GXShaderInfo, ShaderLightSanitizesNonFiniteDirectionForUniforms) { - aurora::gx::Light light{}; - light.dir = { - std::numeric_limits::quiet_NaN(), - std::numeric_limits::infinity(), - -std::numeric_limits::infinity(), - }; - - const auto sanitized = aurora::gx::prepare_shader_light(light); - EXPECT_FLOAT_EQ(sanitized.dir[0], 0.0f); - EXPECT_FLOAT_EQ(sanitized.dir[1], 0.0f); - EXPECT_FLOAT_EQ(sanitized.dir[2], 0.0f); - - light.dir = {3.0f, 4.0f, 0.0f}; - const auto normalized = aurora::gx::prepare_shader_light(light); - EXPECT_FLOAT_EQ(normalized.dir[0], 0.6f); - EXPECT_FLOAT_EQ(normalized.dir[1], 0.8f); - EXPECT_FLOAT_EQ(normalized.dir[2], 0.0f); - - light.dir = {0.0f, 0.0f, 0.0f}; - const auto zero = aurora::gx::prepare_shader_light(light); - EXPECT_FLOAT_EQ(zero.dir[0], 0.0f); - EXPECT_FLOAT_EQ(zero.dir[1], 0.0f); - EXPECT_FLOAT_EQ(zero.dir[2], 0.0f); -} - -TEST(GXLighting, SpotCoefficientsAndPositionGetterMatchRevolutionSdk) { - GXLightObj light{}; - GXInitLightSpot(&light, 60.0f, GX_SP_SHARP); - - float a0 = 0.0f; - float a1 = 0.0f; - float a2 = 0.0f; - GXGetLightAttnA(&light, &a0, &a1, &a2); - EXPECT_NEAR(a0, -3.0f, 0.00001f); - EXPECT_NEAR(a1, 8.0f, 0.00001f); - EXPECT_NEAR(a2, -4.0f, 0.00001f); - - GXInitLightSpot(&light, 60.0f, GX_SP_RING1); - GXGetLightAttnA(&light, &a0, &a1, &a2); - EXPECT_NEAR(a0, -8.0f, 0.00001f); - EXPECT_NEAR(a1, 24.0f, 0.00001f); - EXPECT_NEAR(a2, -16.0f, 0.00001f); - - GXInitLightPos(&light, 10.0f, 20.0f, 30.0f); - float x = 0.0f; - float y = 0.0f; - float z = 0.0f; - GXGetLightPos(&light, &x, &y, &z); - EXPECT_FLOAT_EQ(x, 10.0f); - EXPECT_FLOAT_EQ(y, 20.0f); - EXPECT_FLOAT_EQ(z, 30.0f); -} - -TEST(EfbRamEncoderContract, Z24X8WritesNativeFourByFourArGbPlanes) { - std::array rgba{}; - for (u32 i = 0; i < 16; ++i) { - rgba[i * 4 + 0] = static_cast(0x10 + i); // high Z - rgba[i * 4 + 1] = static_cast(0x40 + i); // middle Z - rgba[i * 4 + 2] = static_cast(0x80 + i); // low Z - rgba[i * 4 + 3] = 0xff; - } - - std::array encoded{}; - ASSERT_TRUE(aurora::gfx::efb_ram::encode( - encoded.data(), encoded.size(), GX_TF_Z24X8, 4, 4, rgba.data(), 4, 4, 16, - aurora::gfx::efb_ram::HostPixelOrder::RGBA)); - EXPECT_EQ(aurora::gfx::efb_ram::encoded_size(GX_TF_Z24X8, 4, 4), encoded.size()); - - for (u32 i = 0; i < 16; ++i) { - EXPECT_EQ(encoded[i * 2 + 0], 0xff) << "AR plane texel " << i; - EXPECT_EQ(encoded[i * 2 + 1], 0x10 + i) << "AR plane texel " << i; - EXPECT_EQ(encoded[32 + i * 2 + 0], 0x40 + i) << "GB plane texel " << i; - EXPECT_EQ(encoded[32 + i * 2 + 1], 0x80 + i) << "GB plane texel " << i; - - const u32 depth = (static_cast(encoded[i * 2 + 1]) << 16) | - (static_cast(encoded[32 + i * 2 + 0]) << 8) | - encoded[32 + i * 2 + 1]; - EXPECT_EQ(depth, ((0x10u + i) << 16) | ((0x40u + i) << 8) | (0x80u + i)); - } -} - -static bool has_bp_write(const std::vector& bytes, u8 reg) { - const std::array pattern{0x61, reg}; - return std::search(bytes.begin(), bytes.end(), pattern.begin(), pattern.end()) != bytes.end(); -} - -static void expect_fog_raw_fields_match_decoded_state() { - const float expectedA = std::ldexp(g_gxState.fog.aRaw, static_cast(g_gxState.fog.bShift)); - const float bMant = static_cast(g_gxState.fog.bMagnitude) / 8388638.0f; - const float expectedB = std::ldexp(bMant, static_cast(g_gxState.fog.bShift) - 1); - EXPECT_NEAR(g_gxState.fog.a, expectedA, std::max(std::abs(g_gxState.fog.a) * 1e-3f, 1e-6f)); - EXPECT_NEAR(g_gxState.fog.b, expectedB, std::max(std::abs(g_gxState.fog.b) * 1e-3f, 1e-6f)); -} - -static bool has_aurora_cmd(const std::vector& bytes, u16 cmd) { - const std::array pattern{GX_LOAD_AURORA, static_cast(cmd >> 8), static_cast(cmd & 0xFF)}; - return std::search(bytes.begin(), bytes.end(), pattern.begin(), pattern.end()) != bytes.end(); -} - -static std::vector bp_cmd(u8 reg, u32 value) { - return {0x61, reg, static_cast((value >> 16) & 0xFF), static_cast((value >> 8) & 0xFF), - static_cast(value & 0xFF)}; -} - -static std::vector cp_cmd(u8 reg, u32 value) { - return {0x08, reg, static_cast((value >> 24) & 0xFF), static_cast((value >> 16) & 0xFF), - static_cast((value >> 8) & 0xFF), static_cast(value & 0xFF)}; -} - -static std::vector xf_cmd(u16 addr, std::initializer_list values) { - std::vector bytes; - bytes.reserve(5 + values.size() * 4); - bytes.push_back(0x10); - - const u32 header = ((static_cast(values.size() - 1) & 0xFFFFu) << 16) | addr; - bytes.push_back(static_cast((header >> 24) & 0xFF)); - bytes.push_back(static_cast((header >> 16) & 0xFF)); - bytes.push_back(static_cast((header >> 8) & 0xFF)); - bytes.push_back(static_cast(header & 0xFF)); - - for (const u32 value : values) { - bytes.push_back(static_cast((value >> 24) & 0xFF)); - bytes.push_back(static_cast((value >> 16) & 0xFF)); - bytes.push_back(static_cast((value >> 8) & 0xFF)); - bytes.push_back(static_cast(value & 0xFF)); - } - return bytes; -} - -static u32 read_be32_at(const std::vector& bytes, size_t offset) { - return (static_cast(bytes[offset]) << 24) | (static_cast(bytes[offset + 1]) << 16) | - (static_cast(bytes[offset + 2]) << 8) | static_cast(bytes[offset + 3]); -} - -TEST(FrameInterpolationContract, RequiresStablePerspectiveDrawSequence) { - const auto resetInterpolation = [] { - aurora::gx::set_frame_interpolation_fps(0); - aurora::gx::begin_frame_interpolation(); - }; - const auto buildFrame = [](const aurora::gx::ShaderInfo& info, aurora::HashType signatureBase, - bool perspective, bool reverse = false) { - aurora::gx::begin_frame_interpolation(); - aurora::gx::BindGroupRanges ranges{}; - uint32_t interpolatedUniforms = 0; - for (uint32_t i = 0; i < 8; ++i) { - const uint32_t signatureOffset = reverse ? 7 - i : i; - const aurora::gx::FrameInterpolationDrawIdentity identity{ - .combined = signatureBase + signatureOffset, - .pipeline = signatureBase, - .texture = 1, - }; - const auto uniforms = aurora::gx::build_uniform(info, 0, ranges, identity, perspective); - interpolatedUniforms += static_cast(std::count_if( - uniforms.interpolated.begin(), uniforms.interpolated.end(), - [](const aurora::gfx::Range& range) { return range.size != 0; })); - } - aurora::gx::finalize_frame_interpolation(); - return interpolatedUniforms; - }; - - resetInterpolation(); - aurora::gx::set_frame_interpolation_fps(120); - const auto info = aurora::gx::build_shader_info({}); - - // Slots are inserted whenever interpolation is configured, so a frame with no matches just fills - // them with duplicates. The staged uniform counts below are what verify the matching. - EXPECT_EQ(buildFrame(info, 100, true), 0u); - EXPECT_TRUE(aurora::gx::has_interpolated_frame()); - - EXPECT_EQ(buildFrame(info, 100, true), 8u); - EXPECT_TRUE(aurora::gx::has_interpolated_frame()); - EXPECT_EQ(aurora::gx::interpolated_frame_count(), 1u); - EXPECT_TRUE(aurora::gx::frame_interpolation_replay_safe()); - - EXPECT_EQ(buildFrame(info, 100, true, true), 8u); - EXPECT_TRUE(aurora::gx::has_interpolated_frame()); - - aurora::gx::mark_frame_interpolation_replay_unsafe(); - EXPECT_FALSE(aurora::gx::frame_interpolation_replay_safe()); - EXPECT_EQ(aurora::gx::interpolated_frame_count(), 1u); - - aurora::gx::set_frame_interpolation_fps(180); - EXPECT_EQ(buildFrame(info, 250, true), 0u); - EXPECT_TRUE(aurora::gx::frame_interpolation_replay_safe()); - EXPECT_TRUE(aurora::gx::has_interpolated_frame()); - EXPECT_EQ(buildFrame(info, 250, true), 16u); - EXPECT_TRUE(aurora::gx::has_interpolated_frame()); - EXPECT_EQ(aurora::gx::interpolated_frame_count(), 2u); - - aurora::gx::set_frame_interpolation_fps(120); - EXPECT_EQ(buildFrame(info, 200, true), 0u); - EXPECT_TRUE(aurora::gx::has_interpolated_frame()); - - EXPECT_EQ(buildFrame(info, 200, false), 0u); - EXPECT_TRUE(aurora::gx::has_interpolated_frame()); - - aurora::gx::set_frame_interpolation_fps(240); - EXPECT_EQ(buildFrame(info, 300, true), 0u); - EXPECT_TRUE(aurora::gx::has_interpolated_frame()); - EXPECT_EQ(buildFrame(info, 300, true), 24u); - EXPECT_TRUE(aurora::gx::has_interpolated_frame()); - EXPECT_EQ(aurora::gx::interpolated_frame_count(), 3u); - - // CPU-deformed draws change their vertex bytes every frame, so their stable pipeline and texture - // identity still has to retain transform history for the camera and model matrices. - aurora::gx::set_frame_interpolation_fps(120); - const auto buildDeformedFrame = [&](aurora::HashType geometryEpoch) { - aurora::gx::begin_frame_interpolation(); - aurora::gx::BindGroupRanges ranges{}; - uint32_t interpolatedUniforms = 0; - for (uint32_t i = 0; i < 8; ++i) { - const aurora::gx::FrameInterpolationDrawIdentity identity{ - .combined = geometryEpoch + i, - .pipeline = 42, - .texture = 7, - }; - const auto uniforms = aurora::gx::build_uniform(info, 0, ranges, identity, true); - interpolatedUniforms += static_cast(std::count_if( - uniforms.interpolated.begin(), uniforms.interpolated.end(), - [](const aurora::gfx::Range& range) { return range.size != 0; })); - } - aurora::gx::finalize_frame_interpolation(); - return interpolatedUniforms; - }; - EXPECT_EQ(buildDeformedFrame(400), 0u); - EXPECT_EQ(buildDeformedFrame(500), 8u); - EXPECT_TRUE(aurora::gx::has_interpolated_frame()); - - resetInterpolation(); -} - -TEST(FrameInterpolationContract, DecomposesRotationScaleAndTranslation) { - const aurora::Mat3x4 previous{ - {1.0f, 0.0f, 0.0f, 0.0f}, - {0.0f, 1.0f, 0.0f, 0.0f}, - {0.0f, 0.0f, 1.0f, 0.0f}, - }; - const aurora::Mat3x4 current{ - {0.0f, -2.0f, 0.0f, 10.0f}, - {2.0f, 0.0f, 0.0f, 20.0f}, - {0.0f, 0.0f, 2.0f, 30.0f}, - }; - aurora::Mat3x4 midpoint{}; - ASSERT_TRUE(aurora::gx::interpolate_transform_midpoint(previous, current, midpoint)); - - const float expectedAxis = std::sqrt(0.5f) * 1.5f; - EXPECT_NEAR(midpoint.m0.x(), expectedAxis, 1.0e-5f); - EXPECT_NEAR(midpoint.m0.y(), -expectedAxis, 1.0e-5f); - EXPECT_NEAR(midpoint.m1.x(), expectedAxis, 1.0e-5f); - EXPECT_NEAR(midpoint.m1.y(), expectedAxis, 1.0e-5f); - EXPECT_NEAR(midpoint.m2.z(), 1.5f, 1.0e-5f); - EXPECT_FLOAT_EQ(midpoint.m0.w(), 5.0f); - EXPECT_FLOAT_EQ(midpoint.m1.w(), 10.0f); - EXPECT_FLOAT_EQ(midpoint.m2.w(), 15.0f); - - aurora::Mat3x4 quarter{}; - aurora::Mat3x4 threeQuarter{}; - ASSERT_TRUE(aurora::gx::interpolate_transform(previous, current, 0.25f, quarter)); - ASSERT_TRUE(aurora::gx::interpolate_transform(previous, current, 0.75f, threeQuarter)); - EXPECT_FLOAT_EQ(quarter.m0.w(), 2.5f); - EXPECT_FLOAT_EQ(quarter.m1.w(), 5.0f); - EXPECT_FLOAT_EQ(quarter.m2.w(), 7.5f); - EXPECT_FLOAT_EQ(threeQuarter.m0.w(), 7.5f); - EXPECT_FLOAT_EQ(threeQuarter.m1.w(), 15.0f); - EXPECT_FLOAT_EQ(threeQuarter.m2.w(), 22.5f); -} - -TEST(FrameInterpolationContract, IndexedPaletteInterpolationPreservesSharedSeams) { - const aurora::Mat3x4 identity{ - {1.0f, 0.0f, 0.0f, 0.0f}, - {0.0f, 1.0f, 0.0f, 0.0f}, - {0.0f, 0.0f, 1.0f, 0.0f}, - }; - const aurora::Mat3x4 quarterTurn{ - {0.0f, -1.0f, 0.0f, 0.0f}, - {1.0f, 0.0f, 0.0f, 0.0f}, - {0.0f, 0.0f, 1.0f, 0.0f}, - }; - const aurora::Mat3x4 translatedPrevious{ - {1.0f, 0.0f, 0.0f, 1.0f}, - {0.0f, 1.0f, 0.0f, 0.0f}, - {0.0f, 0.0f, 1.0f, 0.0f}, - }; - const aurora::Mat3x4 translatedCurrent{ - {1.0f, 0.0f, 0.0f, 0.0f}, - {0.0f, 1.0f, 0.0f, 1.0f}, - {0.0f, 0.0f, 1.0f, 0.0f}, - }; - - aurora::Mat3x4 rotatedMidpoint{}; - aurora::Mat3x4 translatedMidpoint{}; - ASSERT_TRUE(aurora::gx::interpolate_indexed_transform( - identity, quarterTurn, 0.5f, rotatedMidpoint)); - ASSERT_TRUE(aurora::gx::interpolate_indexed_transform( - translatedPrevious, translatedCurrent, 0.5f, translatedMidpoint)); - - const auto transformPoint = [](const aurora::Mat3x4& matrix, - const std::array& point) { - return std::array{ - matrix.m0.x() * point[0] + matrix.m0.y() * point[1] + - matrix.m0.z() * point[2] + matrix.m0.w(), - matrix.m1.x() * point[0] + matrix.m1.y() * point[1] + - matrix.m1.z() * point[2] + matrix.m1.w(), - matrix.m2.x() * point[0] + matrix.m2.y() * point[1] + - matrix.m2.z() * point[2] + matrix.m2.w(), - }; - }; - - // Two representations of the same seam point that agree at both real frames, so coefficient - // interpolation has to keep them coincident; a rigid decompose would pull them apart. - const auto rotatedSeam = transformPoint(rotatedMidpoint, {1.0f, 0.0f, 0.0f}); - const auto translatedSeam = transformPoint(translatedMidpoint, {0.0f, 0.0f, 0.0f}); - for (size_t component = 0; component < rotatedSeam.size(); ++component) { - EXPECT_FLOAT_EQ(rotatedSeam[component], translatedSeam[component]); - } - EXPECT_FLOAT_EQ(rotatedSeam[0], 0.5f); - EXPECT_FLOAT_EQ(rotatedSeam[1], 0.5f); - - // Composed palette matrices may legitimately contain shear, so the indexed path interpolates it - // instead of rejecting the matrix and snapping those vertices to the new frame. - const aurora::Mat3x4 sheared{ - {1.0f, 0.5f, 0.0f, 4.0f}, - {0.0f, 1.0f, 0.0f, 0.0f}, - {0.0f, 0.0f, 1.0f, 0.0f}, - }; - aurora::Mat3x4 shearedMidpoint{}; - ASSERT_TRUE(aurora::gx::interpolate_indexed_transform( - identity, sheared, 0.5f, shearedMidpoint)); - EXPECT_FLOAT_EQ(shearedMidpoint.m0.y(), 0.25f); - EXPECT_FLOAT_EQ(shearedMidpoint.m0.w(), 2.0f); -} - -TEST(FrameInterpolationContract, IndexedPaletteHistoryKeepsAbsoluteVertexSlots) { - constexpr uint16_t usedMask = (1u << 0) | (1u << 1); - constexpr size_t projectionOffset = 0; - constexpr size_t positionOffset = sizeof(aurora::Mat4x4); - constexpr size_t normalOffset = - positionOffset + aurora::gx::MaxPnMtx * sizeof(aurora::Mat3x4); - constexpr size_t uniformSize = - normalOffset + aurora::gx::MaxPnMtx * sizeof(aurora::Mat3x4); - const aurora::gx::FrameInterpolationDrawIdentity identity{ - .combined = 0x1234, - .pipeline = 0x5678, - .texture = 0x9abc, - .matrixTopology = 0xdef0, - }; - const aurora::Mat4x4 projection{}; - const auto matrixAt = [](float x) { - return aurora::Mat3x4{ - {1.0f, 0.0f, 0.0f, x}, - {0.0f, 1.0f, 0.0f, 0.0f}, - {0.0f, 0.0f, 1.0f, 0.0f}, - }; - }; - const auto recordFrame = [&](const aurora::gx::FrameInterpolationDrawIdentity& drawIdentity, - float slot0X, float slot1X, - std::array& source) { - g_gxState.pnMtx[0].pos = matrixAt(slot0X); - g_gxState.pnMtx[1].pos = matrixAt(slot1X); - g_gxState.pnMtx[0].nrm = matrixAt(0.0f); - g_gxState.pnMtx[1].nrm = matrixAt(0.0f); - std::memcpy(source.data() + positionOffset, &g_gxState.pnMtx[0].pos, - sizeof(aurora::Mat3x4)); - std::memcpy(source.data() + positionOffset + sizeof(aurora::Mat3x4), - &g_gxState.pnMtx[1].pos, sizeof(aurora::Mat3x4)); - std::memcpy(source.data() + normalOffset, &g_gxState.pnMtx[0].nrm, - sizeof(aurora::Mat3x4)); - std::memcpy(source.data() + normalOffset + sizeof(aurora::Mat3x4), - &g_gxState.pnMtx[1].nrm, sizeof(aurora::Mat3x4)); - return aurora::gx::record_interpolation_draw( - drawIdentity, projection, usedMask, - aurora::gx::InterpolatedUniformLayout{ - .sourceUniformData = source.data(), - .uniformSize = source.size(), - .projectionOffset = projectionOffset, - .positionOffset = positionOffset, - .normalOffset = normalOffset, - .currentMatrix = 0, - .indexedMatrices = true, - }); - }; - - aurora::gx::set_frame_interpolation_fps(0); - aurora::gx::begin_frame_interpolation(); - aurora::gx::set_frame_interpolation_fps(120); - - std::array previousSource{}; - aurora::gx::begin_frame_interpolation(); - recordFrame(identity, 0.0f, 100.0f, previousSource); - aurora::gx::finalize_frame_interpolation(); - - // Current slot 0 is spatially nearest previous slot 1 and vice versa. The old nearest-unused - // heuristic crossed them even though vertex PNMTXIDX bytes address absolute slots 0 and 1. - aurora::gfx::testing::reset_uniform_allocations(); - std::array currentSource{}; - aurora::gx::begin_frame_interpolation(); - const auto ranges = recordFrame(identity, 90.0f, 10.0f, currentSource); - ASSERT_NE(ranges[0].size, 0u); - aurora::gx::finalize_frame_interpolation(); - - const auto& interpolated = aurora::gfx::testing::uniform_allocation(0); - ASSERT_EQ(interpolated.size(), uniformSize); - aurora::Mat3x4 slot0Midpoint{}; - aurora::Mat3x4 slot1Midpoint{}; - std::memcpy(static_cast(&slot0Midpoint), interpolated.data() + positionOffset, - sizeof(slot0Midpoint)); - std::memcpy(static_cast(&slot1Midpoint), - interpolated.data() + positionOffset + sizeof(slot0Midpoint), - sizeof(slot1Midpoint)); - EXPECT_FLOAT_EQ(slot0Midpoint.m0.w(), 45.0f); - EXPECT_FLOAT_EQ(slot1Midpoint.m0.w(), 55.0f); - - // A changed vertex-to-slot topology is not recoverable from matrix values, so it must not fall - // into the coarse material-only bucket even when the used mask is unchanged. - auto changedTopology = identity; - ++changedTopology.combined; - ++changedTopology.matrixTopology; - aurora::gfx::testing::reset_uniform_allocations(); - std::array changedSource{}; - aurora::gx::begin_frame_interpolation(); - const auto changedRanges = recordFrame(changedTopology, 91.0f, 9.0f, changedSource); - // Staging may reserve a copy for sibling matching; the correctness contract - // is that an unmatched topology receives the current pose unchanged. - const auto expectedCurrent = changedSource; - aurora::gx::finalize_frame_interpolation(); - EXPECT_EQ(changedSource, expectedCurrent); - if (changedRanges[0].size != 0) { - // No replacement range also correctly selects the original current uniform. - ASSERT_EQ(changedRanges[0].size, uniformSize); - const auto& duplicated = aurora::gfx::testing::uniform_allocation(changedRanges[0].offset); - ASSERT_EQ(duplicated.size(), expectedCurrent.size()); - EXPECT_EQ(std::memcmp(duplicated.data(), expectedCurrent.data(), expectedCurrent.size()), 0); - } - - aurora::gx::set_frame_interpolation_fps(0); - aurora::gx::begin_frame_interpolation(); - aurora::gfx::testing::reset_uniform_allocations(); -} - -TEST(FrameInterpolationContract, RepeatedDrawsMatchByTransformInsteadOfDrawOrder) { - const aurora::Mat3x4 left{ - {1.0f, 0.0f, 0.0f, -500.0f}, - {0.0f, 1.0f, 0.0f, 0.0f}, - {0.0f, 0.0f, 1.0f, 1000.0f}, - }; - const aurora::Mat3x4 right{ - {1.0f, 0.0f, 0.0f, 500.0f}, - {0.0f, 1.0f, 0.0f, 0.0f}, - {0.0f, 0.0f, 1.0f, 1000.0f}, - }; - const aurora::Mat3x4 currentRight{ - {0.9998f, 0.0f, 0.02f, 496.0f}, - {0.0f, 1.0f, 0.0f, 1.0f}, - {-0.02f, 0.0f, 0.9998f, 997.0f}, - }; - - // A transparent sorter may submit right then left this frame after left then right last frame. - // The signatures are identical, so spatial continuity has to pick the historical transform. - EXPECT_LT(aurora::gx::transform_match_distance_squared(right, currentRight), - aurora::gx::transform_match_distance_squared(left, currentRight)); -} - -TEST(VertexColorContract, MissingAndSparseColorsFollowGxRasterDefaults) { - aurora::gx::ShaderConfig config{}; - - EXPECT_EQ(aurora::gx::shader_vertex_color_attr(config, 0), -1); - EXPECT_EQ(aurora::gx::shader_vertex_color_attr(config, 1), -1); - - config.attrs[GX_VA_CLR1].attrType = GX_DIRECT; - EXPECT_EQ(aurora::gx::shader_vertex_color_attr(config, 0), GX_VA_CLR1); - EXPECT_EQ(aurora::gx::shader_vertex_color_attr(config, 1), -1); - - config.attrs[GX_VA_CLR0].attrType = GX_DIRECT; - EXPECT_EQ(aurora::gx::shader_vertex_color_attr(config, 0), GX_VA_CLR0); - EXPECT_EQ(aurora::gx::shader_vertex_color_attr(config, 1), GX_VA_CLR1); - - config.attrs[GX_VA_CLR1].attrType = GX_NONE; - EXPECT_EQ(aurora::gx::shader_vertex_color_attr(config, 0), GX_VA_CLR0); - EXPECT_EQ(aurora::gx::shader_vertex_color_attr(config, 1), -1); -} - -TEST(TevTexcoordStateContract, DirectStageFeedsFollowingAddPrevInFixedPoint) { - aurora::gx::ShaderConfig config{}; - config.numTexGens = 2; - config.numIndStages = 1; - config.tevStageCount = 2; - config.indStages[0].texCoordId = GX_TEXCOORD0; - config.indStages[0].texMapId = GX_TEXMAP0; - config.indStages[0].scaleS = GX_ITS_1; - config.indStages[0].scaleT = GX_ITS_1; - - config.tevStages[0].texCoordId = GX_TEXCOORD1; - config.tevStages[0].texMapId = GX_TEXMAP_NULL; - config.tevStages[0].indTexMtxId = GX_ITM_OFF; - config.tevStages[1].indTexMtxId = GX_ITM_1; - config.tevStages[1].indTexAddPrev = true; - config.tevStages[1].indTexWrapS = GX_ITW_0; - config.tevStages[1].indTexWrapT = GX_ITW_0; - config.tevStages[1].texCoordId = GX_TEXCOORD_NULL; - config.tevStages[1].texMapId = GX_TEXMAP1; - config.tevStages[1].colorPass.d = GX_CC_TEXC; - - // Stage 0 is direct and stage 1 consumes the coordinate it establishes. Disabling stage 1's - // texture map does not stop that update, so its GX_TEXCOORD_NULL resolves to coord 0. - const auto directDependency = aurora::gx::tev_stage_texture_dependency(config, 0); - const auto indirectDependency = aurora::gx::tev_stage_texture_dependency(config, 1); - EXPECT_EQ(directDependency.texCoordId, 1); - EXPECT_EQ(directDependency.texMapId, -1); - EXPECT_TRUE(directDependency.needsFixedTexcoordState); - EXPECT_FALSE(directDependency.canSampleTexture); - EXPECT_EQ(indirectDependency.texCoordId, 0); - EXPECT_EQ(indirectDependency.texMapId, 1); - EXPECT_TRUE(indirectDependency.needsFixedTexcoordState); - EXPECT_TRUE(indirectDependency.combinerUsesTexture); - EXPECT_TRUE(indirectDependency.canSampleTexture); - EXPECT_TRUE(aurora::gx::shader_uses_fixed_texcoord_state(config)); - - // The production ShaderInfo implementation, not the old empty stub: both effective coords, the - // regular texture and the indirect lookup have to appear in the binding contract. - const auto info = aurora::gx::build_shader_info(config); - EXPECT_TRUE(info.sampledTexCoords.test(0)); - EXPECT_TRUE(info.sampledTexCoords.test(1)); - EXPECT_TRUE(info.sampledTextures.test(0)); - EXPECT_TRUE(info.sampledTextures.test(1)); - EXPECT_TRUE(info.usedIndStages.test(0)); - EXPECT_TRUE(info.usedIndTexMtxs.test(GX_ITM_1 - GX_ITM_0)); - EXPECT_EQ(aurora::gx::tev_indirect_wrap_mask(GX_ITW_256), 0x7fff); - EXPECT_EQ(aurora::gx::tev_indirect_wrap_mask(static_cast(GX_MAX_ITWRAP)), 0); - EXPECT_EQ(aurora::gx::indirect_matrix_mantissa(0.5f), 512); - EXPECT_EQ(aurora::gx::indirect_matrix_mantissa(-0.5f), -512); - EXPECT_EQ(aurora::gx::indirect_matrix_shift(3), -3); - EXPECT_EQ(aurora::gx::indirect_matrix_shift(-5), 5); - EXPECT_EQ(aurora::gx::tev_s24_wrap(0x007fffff), 0x007fffff); - EXPECT_EQ(aurora::gx::tev_s24_wrap(0x00800000), -0x00800000); - EXPECT_EQ(aurora::gx::tev_s24_wrap(-0x00800000), -0x00800000); - EXPECT_EQ(aurora::gx::tev_s24_wrap(-0x00800001), 0x007fffff); - - config.tevStages[1].texMapId = GX_TEXMAP_NULL; - EXPECT_FALSE(aurora::gx::tev_stage_texture_dependency(config, 1).canSampleTexture); - config.tevStages[1].texMapId = GX_TEXMAP1; - - // No regular texture lookup occurs with zero texgens, but an enabled - // indirect stage still samples its texture at the literal zero coordinate. - config.numTexGens = 0; - EXPECT_EQ(aurora::gx::tev_stage_texture_dependency(config, 1).texCoordId, -1); - EXPECT_FALSE(aurora::gx::tev_stage_texture_dependency(config, 1).canSampleTexture); - const auto zeroTexgenInfo = aurora::gx::build_shader_info(config); - EXPECT_FALSE(zeroTexgenInfo.sampledTexCoords.any()); - EXPECT_TRUE(zeroTexgenInfo.sampledTextures.test(0)); - EXPECT_FALSE(zeroTexgenInfo.sampledTextures.test(1)); - // WGSL must likewise avoid producing a regular-texture UV expression for - // stage 1: tex1_size_bias is intentionally absent from this uniform layout. - const auto zeroTexgenDependency = aurora::gx::tev_stage_texture_dependency(config, 1); - EXPECT_FALSE(aurora::gx::tev_texture_sample_enabled(zeroTexgenDependency, - zeroTexgenDependency.combinerUsesTexture)); - - // A standalone direct stage still uses the normalized fast path. - config.numTexGens = 2; - config.tevStageCount = 1; - config.tevStages[1] = {}; - config.tevStages[0].texMapId = GX_TEXMAP1; - config.tevStages[0].colorPass.d = GX_CC_TEXC; - const auto directSampleDependency = aurora::gx::tev_stage_texture_dependency(config, 0); - EXPECT_FALSE(directSampleDependency.needsFixedTexcoordState); - EXPECT_TRUE(directSampleDependency.combinerUsesTexture); - EXPECT_TRUE(directSampleDependency.canSampleTexture); - const auto directInfo = aurora::gx::build_shader_info(config); - EXPECT_TRUE(directInfo.sampledTexCoords.test(1)); - EXPECT_TRUE(directInfo.sampledTextures.test(1)); - - // Z-texture remains enabled even without a regular source stage; the shader - // applies its bias/op to a zero raw texture value in that case. - config.tevStages[0].texMapId = GX_TEXMAP_NULL; - config.tevStages[0].colorPass.d = GX_CC_ZERO; - config.zTexture = static_cast(GX_ZT_REPLACE) << 26; - EXPECT_TRUE(aurora::gx::tev_z_texture_enabled(config)); - EXPECT_EQ(aurora::gx::tev_z_texture_stage(config), -1); - -} - -TEST(TevRegisterLivenessContract, RgbWriteDoesNotHideSameStageOldAlphaRead) { - aurora::gx::ShaderConfig config{}; - config.tevStageCount = 1; - config.tevStages[0].colorOp.outReg = GX_TEVREG0; - config.tevStages[0].alphaPass.d = GX_CA_A0; - - const auto info = aurora::gx::build_shader_info(config); - EXPECT_TRUE(info.writesTevRegRgb.test(GX_TEVREG0)); - EXPECT_FALSE(info.writesTevRegAlpha.test(GX_TEVREG0)); - EXPECT_FALSE(info.loadsTevRegRgb.test(GX_TEVREG0)); - EXPECT_TRUE(info.loadsTevRegAlpha.test(GX_TEVREG0)); -} - -TEST(TevRegisterLivenessContract, TracksOppositeHalvesIndependentlyAcrossStages) { - aurora::gx::ShaderConfig config{}; - config.tevStageCount = 2; - config.tevStages[0].colorOp.outReg = GX_TEVREG0; - config.tevStages[0].alphaOp.outReg = GX_TEVREG1; - config.tevStages[1].colorPass.a = GX_CC_C1; - config.tevStages[1].alphaPass.a = GX_CA_A0; - - const auto info = aurora::gx::build_shader_info(config); - EXPECT_TRUE(info.loadsTevRegAlpha.test(GX_TEVREG0)); - EXPECT_FALSE(info.loadsTevRegRgb.test(GX_TEVREG0)); - EXPECT_TRUE(info.loadsTevRegRgb.test(GX_TEVREG1)); - EXPECT_FALSE(info.loadsTevRegAlpha.test(GX_TEVREG1)); -} - -TEST(TevRegisterLivenessContract, PacksOneUniformWhenBothHalvesNeedInitialValue) { - aurora::gx::ShaderConfig baseline{}; - baseline.tevStageCount = 1; - - auto config = baseline; - config.tevStages[0].colorPass.a = GX_CC_C0; - config.tevStages[0].alphaPass.a = GX_CA_A0; - config.tevStages[0].colorPass.b = GX_CC_KONST; - config.tevStages[0].kcSel = GX_TEV_KCSEL_K0; - - const auto info = aurora::gx::build_shader_info(config); - EXPECT_TRUE(info.loadsTevRegRgb.test(GX_TEVREG0)); - EXPECT_TRUE(info.loadsTevRegAlpha.test(GX_TEVREG0)); - // The final allocation is alignment-rounded, so adding one register need - // not increase it. Verify actual packing with a distinct following K color. - const auto savedReg = g_gxState.colorRegs[GX_TEVREG0]; - const auto savedKColor = g_gxState.kcolors[GX_KCOLOR0]; - g_gxState.colorRegs[GX_TEVREG0] = {11.f, 22.f, 33.f, 44.f}; - g_gxState.kcolors[GX_KCOLOR0] = {55.f, 66.f, 77.f, 88.f}; - EXPECT_TRUE(info.sampledKColors.test(GX_KCOLOR0)); - aurora::gfx::testing::reset_uniform_allocations(); - aurora::gx::build_uniform(info, 0, {}, {}, false); - const auto expectedReg = g_gxState.colorRegs[GX_TEVREG0]; - const auto expectedKColor = g_gxState.kcolors[GX_KCOLOR0]; - g_gxState.colorRegs[GX_TEVREG0] = savedReg; - g_gxState.kcolors[GX_KCOLOR0] = savedKColor; - const auto& bytes = aurora::gfx::testing::uniform_allocation(0); - const auto* reg = reinterpret_cast(&expectedReg); - const auto found = std::search(bytes.begin(), bytes.end(), reg, reg + sizeof(aurora::Vec4)); - ASSERT_NE(found, bytes.end()); - const size_t offset = static_cast(found - bytes.begin()); - ASSERT_LE(offset + 2 * sizeof(aurora::Vec4), bytes.size()); - EXPECT_EQ(std::memcmp(bytes.data() + offset + sizeof(aurora::Vec4), - &expectedKColor, sizeof(aurora::Vec4)), 0); - aurora::gfx::testing::reset_uniform_allocations(); -} - -// BP registers (direct FIFO writes, no dirty state flush needed) - -// --- GXSetBlendMode (BP 0x41) --- - -TEST_F(GXFifoTest, BlendMode_Blend_SrcAlpha) { - GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_NOOP); - auto bytes = capture_fifo(); - - // Validate encoding: BP opcode 0x61, register ID 0x41 - ASSERT_GE(bytes.size(), 5u); - EXPECT_EQ(bytes[0], 0x61); - EXPECT_EQ(bytes[1], 0x41); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.blendMode, GX_BM_BLEND); - EXPECT_EQ(g_gxState.blendFacSrc, GX_BL_SRCALPHA); - EXPECT_EQ(g_gxState.blendFacDst, GX_BL_INVSRCALPHA); -} - -TEST_F(GXFifoTest, BlendMode_None) { - GXSetBlendMode(GX_BM_NONE, GX_BL_ZERO, GX_BL_ZERO, GX_LO_CLEAR); - auto bytes = capture_fifo(); - - reset_gx_state(); - // Pre-set to something else to prove the decode works - g_gxState.blendMode = GX_BM_BLEND; - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.blendMode, GX_BM_NONE); -} - -TEST_F(GXFifoTest, BlendMode_Subtract) { - GXSetBlendMode(GX_BM_SUBTRACT, GX_BL_ONE, GX_BL_ONE, GX_LO_NOOP); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.blendMode, GX_BM_SUBTRACT); -} - -TEST_F(GXFifoTest, BlendMode_Logic) { - GXSetBlendMode(GX_BM_LOGIC, GX_BL_ONE, GX_BL_ZERO, GX_LO_XOR); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.blendMode, GX_BM_LOGIC); - EXPECT_EQ(g_gxState.blendOp, GX_LO_XOR); -} - - -TEST_F(GXFifoTest, GenMode_FirstZeroWriteDecodesAndRepeatDeduplicates) { - reset_gx_state(); - const auto before = g_gxState.pipelineStateGeneration; - decode_fifo(bp_cmd(0, 0)); - EXPECT_EQ(g_gxState.numTevStages, 1u); - EXPECT_EQ(g_gxState.cullMode, GX_CULL_NONE); - EXPECT_EQ(g_gxState.numChans, 0u); - EXPECT_EQ(g_gxState.numTexGens, 0u); - EXPECT_EQ(g_gxState.numIndStages, 0u); - EXPECT_EQ(g_gxState.bpRegCache[0], 0u); - EXPECT_NE(g_gxState.pipelineStateGeneration, before); - const auto decoded = g_gxState.pipelineStateGeneration; - decode_fifo(bp_cmd(0, 0)); - EXPECT_EQ(g_gxState.pipelineStateGeneration, decoded); -} - -TEST_F(GXFifoTest, GenMode_FirstMaskedWritePreservesZeroResetBits) { - for (const u32 mask : {0u, 1u << 10}) { - reset_gx_state(); - const auto before = g_gxState.pipelineStateGeneration; - decode_fifo(bp_cmd(0xFE, mask)); - decode_fifo(bp_cmd(0, 0xFFFFFF)); - EXPECT_EQ(g_gxState.bpRegCache[0], mask); - EXPECT_EQ(g_gxState.bpRegCache[0xFE], 0xFFFFFFu); - EXPECT_EQ(g_gxState.numTevStages, mask ? 2u : 1u); - EXPECT_EQ(g_gxState.cullMode, GX_CULL_NONE); - EXPECT_NE(g_gxState.pipelineStateGeneration, before); - decode_fifo(bp_cmd(0, 0)); - EXPECT_EQ(g_gxState.numTevStages, 1u); - EXPECT_EQ(g_gxState.bpRegCache[0], 0u); - } -} - -TEST_F(GXFifoTest, GenMode_ColdSingleStageApiSetupDecodes) { - reset_gx_state(); - GXSetNumTevStages(1); - GXSetNumTexGens(0); - GXSetNumChans(0); - GXSetCullMode(GX_CULL_NONE); - const auto bytes = flush_and_capture(); - decode_fifo(bytes); - EXPECT_EQ(g_gxState.numTevStages, 1u); - EXPECT_EQ(g_gxState.cullMode, GX_CULL_NONE); -} - -TEST_F(GXFifoTest, BpMask_AppliesOnlyToNextWrite) { - std::vector bytes; - auto mask = bp_cmd(0xFE, 1u << 19); - auto genMode = bp_cmd(0x00, 1u << 19); - auto cullAndInd = bp_cmd(0x00, (2u << 14) | (3u << 16)); - bytes.insert(bytes.end(), mask.begin(), mask.end()); - bytes.insert(bytes.end(), genMode.begin(), genMode.end()); - bytes.insert(bytes.end(), cullAndInd.begin(), cullAndInd.end()); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.bpRegCache[0x00] & (1u << 19), 0u); - EXPECT_EQ(g_gxState.cullMode, GX_CULL_FRONT); - EXPECT_EQ(g_gxState.numIndStages, 3u); -} - -TEST_F(GXFifoTest, IndirectTextureMask_DecodesWithoutChangingBpWriteMask) { - auto bytes = bp_cmd(0x0F, 0x5A); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.indTexMask, 0x5Au); - EXPECT_EQ(g_gxState.bpRegCache[0x0F], 0x0F00005Au); - EXPECT_EQ(g_gxState.bpRegCache[0xFE], 0x00FFFFFFu); -} - -// --- GXSetColorUpdate / GXSetAlphaUpdate (BP 0x41 cmode0) --- - -TEST_F(GXFifoTest, ColorUpdate_Disabled) { - GXSetColorUpdate(GX_FALSE); - auto bytes = capture_fifo(); - - reset_gx_state(); - g_gxState.colorUpdate = true; - decode_fifo(bytes); - - EXPECT_FALSE(g_gxState.colorUpdate); -} - -TEST_F(GXFifoTest, AlphaUpdate_Disabled) { - GXSetAlphaUpdate(false); - auto bytes = capture_fifo(); - - reset_gx_state(); - g_gxState.alphaUpdate = true; - decode_fifo(bytes); - - EXPECT_FALSE(g_gxState.alphaUpdate); -} - -// --- GXSetZMode (BP 0x40) --- - -TEST_F(GXFifoTest, ZMode_LessNoUpdate) { - GXSetZMode(true, GX_LESS, false); - auto bytes = capture_fifo(); - - ASSERT_GE(bytes.size(), 5u); - EXPECT_EQ(bytes[0], 0x61); - EXPECT_EQ(bytes[1], 0x40); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_TRUE(g_gxState.depthCompare); - EXPECT_EQ(g_gxState.depthFunc, GX_LESS); - EXPECT_FALSE(g_gxState.depthUpdate); -} - -TEST_F(GXFifoTest, ZMode_AlwaysUpdate) { - GXSetZMode(true, GX_ALWAYS, true); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_TRUE(g_gxState.depthCompare); - EXPECT_EQ(g_gxState.depthFunc, GX_ALWAYS); - EXPECT_TRUE(g_gxState.depthUpdate); -} - -TEST_F(GXFifoTest, ZMode_Disabled) { - GXSetZMode(false, GX_NEVER, false); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_FALSE(g_gxState.depthCompare); - EXPECT_EQ(g_gxState.depthFunc, GX_NEVER); - EXPECT_FALSE(g_gxState.depthUpdate); -} - -TEST_F(GXFifoTest, ZTexture_ReplaceZ24X8) { - GXSetZTexture(GX_ZT_REPLACE, GX_TF_Z24X8, 0x123456); - auto bytes = capture_fifo(); - - EXPECT_TRUE(has_bp_write(bytes, 0xF4)); - EXPECT_TRUE(has_bp_write(bytes, 0xF5)); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.zTextureBias, 0x123456u); - EXPECT_EQ(g_gxState.zTextureFmt, 2u); - EXPECT_EQ(g_gxState.zTextureOp, GX_ZT_REPLACE); -} - -// --- GXSetAlphaCompare (BP 0xF3) --- - -TEST_F(GXFifoTest, AlphaCompare_GreaterThan128) { - GXSetAlphaCompare(GX_GREATER, 128, GX_AOP_AND, GX_ALWAYS, 0); - auto bytes = capture_fifo(); - - ASSERT_GE(bytes.size(), 5u); - EXPECT_EQ(bytes[0], 0x61); - EXPECT_EQ(bytes[1], 0xF3); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.alphaCompare.comp0, GX_GREATER); - EXPECT_EQ(g_gxState.alphaCompare.ref0, 128u); - EXPECT_EQ(g_gxState.alphaCompare.op, GX_AOP_AND); - EXPECT_EQ(g_gxState.alphaCompare.comp1, GX_ALWAYS); - EXPECT_EQ(g_gxState.alphaCompare.ref1, 0u); -} - -TEST_F(GXFifoTest, AlphaCompare_OrGequal) { - GXSetAlphaCompare(GX_GEQUAL, 64, GX_AOP_OR, GX_LEQUAL, 200); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.alphaCompare.comp0, GX_GEQUAL); - EXPECT_EQ(g_gxState.alphaCompare.ref0, 64u); - EXPECT_EQ(g_gxState.alphaCompare.op, GX_AOP_OR); - EXPECT_EQ(g_gxState.alphaCompare.comp1, GX_LEQUAL); - EXPECT_EQ(g_gxState.alphaCompare.ref1, 200u); -} - -// --- GXSetDstAlpha (BP 0x42) --- - -TEST_F(GXFifoTest, DstAlpha_Enabled) { - GXSetDstAlpha(true, 0x80); - auto bytes = capture_fifo(); - - reset_gx_state(); - g_gxState.dstAlpha = UINT32_MAX; - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.dstAlpha, 0x80u); -} - -TEST_F(GXFifoTest, DstAlpha_Disabled) { - GXSetDstAlpha(false, 0); - auto bytes = capture_fifo(); - - reset_gx_state(); - g_gxState.dstAlpha = 0x80; - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.dstAlpha, UINT32_MAX); -} - -// --- GXSetPixelFmt (BP 0x43, 0x42 + genMode flush) --- - -TEST_F(GXFifoTest, PixelFmt_Rgb565Z16_Decode) { - GXSetPixelFmt(GX_PF_RGB565_Z16, GX_ZC_FAR); - auto bytes = flush_and_capture(); - - EXPECT_TRUE(has_bp_write(bytes, 0x43)); - EXPECT_TRUE(has_bp_write(bytes, 0x00)); - - reset_gx_state(); - g_gxState.pixelFmt = GX_PF_RGB8_Z24; - g_gxState.zFmt = GX_ZC_LINEAR; - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.pixelFmt, GX_PF_RGB565_Z16); - EXPECT_EQ(g_gxState.zFmt, GX_ZC_FAR); - EXPECT_TRUE(g_gxState.zCompLocBeforeTex); -} - -TEST_F(GXFifoTest, PixelFmt_U8_Decode) { - GXSetPixelFmt(GX_PF_U8, GX_ZC_MID); - auto bytes = flush_and_capture(); - - EXPECT_TRUE(has_bp_write(bytes, 0x43)); - EXPECT_TRUE(has_bp_write(bytes, 0x42)); - EXPECT_TRUE(has_bp_write(bytes, 0x00)); - - reset_gx_state(); - g_gxState.pixelFmt = GX_PF_RGB8_Z24; - g_gxState.zFmt = GX_ZC_LINEAR; - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.pixelFmt, GX_PF_U8); - EXPECT_EQ(g_gxState.zFmt, GX_ZC_MID); - EXPECT_EQ(g_gxState.dstAlpha, UINT32_MAX); - EXPECT_TRUE(g_gxState.zCompLocBeforeTex); -} - -// TEV registers (direct FIFO writes) - -// --- GXSetTevColorIn / GXSetTevAlphaIn --- - -TEST_F(GXFifoTest, TevColorIn_Stage0) { - GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_TEXC, GX_CC_RASC, GX_CC_ZERO); - auto bytes = capture_fifo(); - - // BP opcode 0x61, register 0xC0 (stage 0 color) - ASSERT_GE(bytes.size(), 5u); - EXPECT_EQ(bytes[0], 0x61); - EXPECT_EQ(bytes[1], 0xC0); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[0]; - EXPECT_EQ(s.colorPass.a, GX_CC_ZERO); - EXPECT_EQ(s.colorPass.b, GX_CC_TEXC); - EXPECT_EQ(s.colorPass.c, GX_CC_RASC); - EXPECT_EQ(s.colorPass.d, GX_CC_ZERO); -} - -TEST_F(GXFifoTest, TevAlphaIn_Stage0) { - GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_TEXA, GX_CA_RASA, GX_CA_ZERO); - auto bytes = capture_fifo(); - - // BP opcode 0x61, register 0xC1 (stage 0 alpha) - ASSERT_GE(bytes.size(), 5u); - EXPECT_EQ(bytes[0], 0x61); - EXPECT_EQ(bytes[1], 0xC1); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[0]; - EXPECT_EQ(s.alphaPass.a, GX_CA_ZERO); - EXPECT_EQ(s.alphaPass.b, GX_CA_TEXA); - EXPECT_EQ(s.alphaPass.c, GX_CA_RASA); - EXPECT_EQ(s.alphaPass.d, GX_CA_ZERO); -} - -TEST_F(GXFifoTest, TevAlphaIn_Stage5) { - GXSetTevAlphaIn(GX_TEVSTAGE5, GX_CA_APREV, GX_CA_A0, GX_CA_KONST, GX_CA_ZERO); - auto bytes = capture_fifo(); - - // Stage 5 alpha register = 0xC1 + 5*2 = 0xCB - ASSERT_GE(bytes.size(), 5u); - EXPECT_EQ(bytes[0], 0x61); - EXPECT_EQ(bytes[1], 0xCB); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[5]; - EXPECT_EQ(s.alphaPass.a, GX_CA_APREV); - EXPECT_EQ(s.alphaPass.b, GX_CA_A0); - EXPECT_EQ(s.alphaPass.c, GX_CA_KONST); - EXPECT_EQ(s.alphaPass.d, GX_CA_ZERO); -} - -TEST_F(GXFifoTest, TevColorIn_Stage7) { - GXSetTevColorIn(GX_TEVSTAGE7, GX_CC_C0, GX_CC_A0, GX_CC_KONST, GX_CC_CPREV); - auto bytes = capture_fifo(); - - // Stage 7 color register = 0xC0 + 7*2 = 0xCE - ASSERT_GE(bytes.size(), 5u); - EXPECT_EQ(bytes[0], 0x61); - EXPECT_EQ(bytes[1], 0xCE); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[7]; - EXPECT_EQ(s.colorPass.a, GX_CC_C0); - EXPECT_EQ(s.colorPass.b, GX_CC_A0); - EXPECT_EQ(s.colorPass.c, GX_CC_KONST); - EXPECT_EQ(s.colorPass.d, GX_CC_CPREV); -} - -// --- GXSetTevOp (convenience wrapper over ColorIn/AlphaIn/ColorOp/AlphaOp) --- -// GXSetTevOp emits 4 BP writes: tevc (colorIn+colorOp) and teva (alphaIn+alphaOp). - -TEST_F(GXFifoTest, TevOp_Modulate_Stage0) { - GXSetTevOp(GX_TEVSTAGE0, GX_MODULATE); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[0]; - // Modulate: color = ZERO, TEXC, RASC, ZERO (stage 0 uses RASC/RASA) - EXPECT_EQ(s.colorPass.a, GX_CC_ZERO); - EXPECT_EQ(s.colorPass.b, GX_CC_TEXC); - EXPECT_EQ(s.colorPass.c, GX_CC_RASC); - EXPECT_EQ(s.colorPass.d, GX_CC_ZERO); - // Modulate: alpha = ZERO, TEXA, RASA, ZERO - EXPECT_EQ(s.alphaPass.a, GX_CA_ZERO); - EXPECT_EQ(s.alphaPass.b, GX_CA_TEXA); - EXPECT_EQ(s.alphaPass.c, GX_CA_RASA); - EXPECT_EQ(s.alphaPass.d, GX_CA_ZERO); - // Op = ADD, bias = ZERO, scale = 1, clamp = true, outReg = TEVPREV - EXPECT_EQ(s.colorOp.op, GX_TEV_ADD); - EXPECT_EQ(s.colorOp.bias, GX_TB_ZERO); - EXPECT_EQ(s.colorOp.scale, GX_CS_SCALE_1); - EXPECT_TRUE(s.colorOp.clamp); - EXPECT_EQ(s.colorOp.outReg, GX_TEVPREV); - EXPECT_EQ(s.alphaOp.op, GX_TEV_ADD); - EXPECT_EQ(s.alphaOp.bias, GX_TB_ZERO); - EXPECT_EQ(s.alphaOp.scale, GX_CS_SCALE_1); - EXPECT_TRUE(s.alphaOp.clamp); - EXPECT_EQ(s.alphaOp.outReg, GX_TEVPREV); -} - -TEST_F(GXFifoTest, TevOp_Modulate_Stage1) { - // Non-stage-0 uses CPREV/APREV instead of RASC/RASA - GXSetTevOp(GX_TEVSTAGE1, GX_MODULATE); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[1]; - EXPECT_EQ(s.colorPass.a, GX_CC_ZERO); - EXPECT_EQ(s.colorPass.b, GX_CC_TEXC); - EXPECT_EQ(s.colorPass.c, GX_CC_CPREV); - EXPECT_EQ(s.colorPass.d, GX_CC_ZERO); - EXPECT_EQ(s.alphaPass.a, GX_CA_ZERO); - EXPECT_EQ(s.alphaPass.b, GX_CA_TEXA); - EXPECT_EQ(s.alphaPass.c, GX_CA_APREV); - EXPECT_EQ(s.alphaPass.d, GX_CA_ZERO); -} - -TEST_F(GXFifoTest, TevOp_Replace) { - GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[0]; - // Replace: color = ZERO, ZERO, ZERO, TEXC - EXPECT_EQ(s.colorPass.a, GX_CC_ZERO); - EXPECT_EQ(s.colorPass.b, GX_CC_ZERO); - EXPECT_EQ(s.colorPass.c, GX_CC_ZERO); - EXPECT_EQ(s.colorPass.d, GX_CC_TEXC); - // Replace: alpha = ZERO, ZERO, ZERO, TEXA - EXPECT_EQ(s.alphaPass.a, GX_CA_ZERO); - EXPECT_EQ(s.alphaPass.b, GX_CA_ZERO); - EXPECT_EQ(s.alphaPass.c, GX_CA_ZERO); - EXPECT_EQ(s.alphaPass.d, GX_CA_TEXA); -} - -TEST_F(GXFifoTest, TevOp_Decal) { - GXSetTevOp(GX_TEVSTAGE0, GX_DECAL); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[0]; - // Decal: color = RASC, TEXC, TEXA, ZERO - EXPECT_EQ(s.colorPass.a, GX_CC_RASC); - EXPECT_EQ(s.colorPass.b, GX_CC_TEXC); - EXPECT_EQ(s.colorPass.c, GX_CC_TEXA); - EXPECT_EQ(s.colorPass.d, GX_CC_ZERO); - // Decal: alpha = ZERO, ZERO, ZERO, RASA - EXPECT_EQ(s.alphaPass.a, GX_CA_ZERO); - EXPECT_EQ(s.alphaPass.b, GX_CA_ZERO); - EXPECT_EQ(s.alphaPass.c, GX_CA_ZERO); - EXPECT_EQ(s.alphaPass.d, GX_CA_RASA); -} - -TEST_F(GXFifoTest, TevOp_Blend) { - GXSetTevOp(GX_TEVSTAGE0, GX_BLEND); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[0]; - // Blend: color = RASC, ONE, TEXC, ZERO - EXPECT_EQ(s.colorPass.a, GX_CC_RASC); - EXPECT_EQ(s.colorPass.b, GX_CC_ONE); - EXPECT_EQ(s.colorPass.c, GX_CC_TEXC); - EXPECT_EQ(s.colorPass.d, GX_CC_ZERO); - // Blend: alpha = ZERO, TEXA, RASA, ZERO - EXPECT_EQ(s.alphaPass.a, GX_CA_ZERO); - EXPECT_EQ(s.alphaPass.b, GX_CA_TEXA); - EXPECT_EQ(s.alphaPass.c, GX_CA_RASA); - EXPECT_EQ(s.alphaPass.d, GX_CA_ZERO); -} - -TEST_F(GXFifoTest, TevOp_PassClr) { - GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[0]; - // PassClr: color = ZERO, ZERO, ZERO, RASC - EXPECT_EQ(s.colorPass.a, GX_CC_ZERO); - EXPECT_EQ(s.colorPass.b, GX_CC_ZERO); - EXPECT_EQ(s.colorPass.c, GX_CC_ZERO); - EXPECT_EQ(s.colorPass.d, GX_CC_RASC); - // PassClr: alpha = ZERO, ZERO, ZERO, RASA - EXPECT_EQ(s.alphaPass.a, GX_CA_ZERO); - EXPECT_EQ(s.alphaPass.b, GX_CA_ZERO); - EXPECT_EQ(s.alphaPass.c, GX_CA_ZERO); - EXPECT_EQ(s.alphaPass.d, GX_CA_RASA); -} - -// --- GXSetTevColorOp / GXSetTevAlphaOp --- - -TEST_F(GXFifoTest, TevColorOp_Sub_Scale2_Reg1) { - GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_SUB, GX_TB_ADDHALF, GX_CS_SCALE_2, GX_TRUE, GX_TEVREG1); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[0]; - EXPECT_EQ(s.colorOp.op, GX_TEV_SUB); - EXPECT_EQ(s.colorOp.bias, GX_TB_ADDHALF); - EXPECT_EQ(s.colorOp.scale, GX_CS_SCALE_2); - EXPECT_TRUE(s.colorOp.clamp); - EXPECT_EQ(s.colorOp.outReg, GX_TEVREG1); -} - -TEST_F(GXFifoTest, TevAlphaOp_Add_NoClamp_Reg2) { - GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_SUBHALF, GX_CS_DIVIDE_2, GX_FALSE, GX_TEVREG2); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[0]; - EXPECT_EQ(s.alphaOp.op, GX_TEV_ADD); - EXPECT_EQ(s.alphaOp.bias, GX_TB_SUBHALF); - EXPECT_EQ(s.alphaOp.scale, GX_CS_DIVIDE_2); - EXPECT_FALSE(s.alphaOp.clamp); - EXPECT_EQ(s.alphaOp.outReg, GX_TEVREG2); -} - -TEST_F(GXFifoTest, TevColorOp_CompareR8GT) { - // Compare ops (op > 1) use a different encoding: bias=3, scale encodes compare mode - GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_COMP_R8_GT, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[0]; - EXPECT_EQ(s.colorOp.op, GX_TEV_COMP_R8_GT); - // Decoder normalizes compare mode: bias=ZERO, scale=SCALE_1 - EXPECT_EQ(s.colorOp.bias, GX_TB_ZERO); - EXPECT_EQ(s.colorOp.scale, GX_CS_SCALE_1); - EXPECT_EQ(s.colorOp.outReg, GX_TEVPREV); -} - -TEST_F(GXFifoTest, TevColorOp_CompareGR16EQ) { - GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_COMP_GR16_EQ, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVREG0); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[0]; - EXPECT_EQ(s.colorOp.op, GX_TEV_COMP_GR16_EQ); - EXPECT_EQ(s.colorOp.outReg, GX_TEVREG0); -} - -TEST_F(GXFifoTest, TevAlphaOp_CompareRGB8GT) { - GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_COMP_RGB8_GT, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[0]; - // GX_TEV_COMP_RGB8_GT is the same enum value for alpha as GX_TEV_COMP_A8_GT - EXPECT_EQ(s.alphaOp.op, GX_TEV_COMP_RGB8_GT); - EXPECT_EQ(s.alphaOp.bias, GX_TB_ZERO); - EXPECT_EQ(s.alphaOp.scale, GX_CS_SCALE_1); -} - -TEST_F(GXFifoTest, TevColorOp_CompareBGR24GT) { - GXSetTevColorOp(GX_TEVSTAGE2, GX_TEV_COMP_BGR24_GT, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVREG1); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[2]; - EXPECT_EQ(s.colorOp.op, GX_TEV_COMP_BGR24_GT); - EXPECT_EQ(s.colorOp.bias, GX_TB_ZERO); - EXPECT_EQ(s.colorOp.scale, GX_CS_SCALE_1); - EXPECT_EQ(s.colorOp.outReg, GX_TEVREG1); -} - -TEST_F(GXFifoTest, TevColorOp_CompareRGB8EQ) { - GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_COMP_RGB8_EQ, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[0]; - EXPECT_EQ(s.colorOp.op, GX_TEV_COMP_RGB8_EQ); - EXPECT_EQ(s.colorOp.outReg, GX_TEVPREV); -} - -TEST_F(GXFifoTest, TevAlphaOp_CompareA8EQ) { - GXSetTevAlphaOp(GX_TEVSTAGE1, GX_TEV_COMP_RGB8_EQ, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVREG2); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[1]; - // For alpha, GX_TEV_COMP_RGB8_EQ maps to A8_EQ - EXPECT_EQ(s.alphaOp.op, GX_TEV_COMP_RGB8_EQ); - EXPECT_EQ(s.alphaOp.outReg, GX_TEVREG2); -} - -// --- GXSetTevColorS10 --- - -TEST_F(GXFifoTest, TevColorS10_Positive) { - GXColorS10 col = {511, 256, 100, 0}; - GXSetTevColorS10(GX_TEVREG0, col); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - // S10 values are encoded as 11-bit signed and decoded to float/255 - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG0][0], 511.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG0][1], 256.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG0][2], 100.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG0][3], 0.f / 255.f, 1.f / 255.f); -} - -TEST_F(GXFifoTest, TevColorS10_Negative) { - GXColorS10 col = {-128, -1, 0, 255}; - GXSetTevColorS10(GX_TEVPREV, col); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVPREV][0], -128.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVPREV][1], -1.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVPREV][2], 0.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVPREV][3], 255.f / 255.f, 1.f / 255.f); -} - -// --- GXSetTevKColorSel / GXSetTevKAlphaSel --- - -TEST_F(GXFifoTest, TevKColorSel_Stage0_K0) { - GXSetTevKColorSel(GX_TEVSTAGE0, GX_TEV_KCSEL_K0); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.tevStages[0].kcSel, GX_TEV_KCSEL_K0); -} - -TEST_F(GXFifoTest, TevKColorSel_Stage1_K2_R) { - GXSetTevKColorSel(GX_TEVSTAGE1, GX_TEV_KCSEL_K2_R); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.tevStages[1].kcSel, GX_TEV_KCSEL_K2_R); -} - -TEST_F(GXFifoTest, TevKAlphaSel_Stage0_K1_A) { - GXSetTevKAlphaSel(GX_TEVSTAGE0, GX_TEV_KASEL_K1_A); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.tevStages[0].kaSel, GX_TEV_KASEL_K1_A); -} - -TEST_F(GXFifoTest, TevKAlphaSel_Stage3_K3_B) { - GXSetTevKAlphaSel(GX_TEVSTAGE3, GX_TEV_KASEL_K3_B); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.tevStages[3].kaSel, GX_TEV_KASEL_K3_B); -} - -TEST_F(GXFifoTest, TevKColorSel_DoesNotCorruptSwapTable) { - // Regression: tevKsel shadow registers share bits with swap table entries. - // Setting K color selection must not zero out the swap table bits. - GXSetTevKColorSel(GX_TEVSTAGE0, GX_TEV_KCSEL_K0); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - // Swap table 0 should remain identity (initialized in GXInit) - EXPECT_EQ(g_gxState.tevSwapTable[0].red, GX_CH_RED); - EXPECT_EQ(g_gxState.tevSwapTable[0].green, GX_CH_GREEN); - EXPECT_EQ(g_gxState.tevSwapTable[0].blue, GX_CH_BLUE); - EXPECT_EQ(g_gxState.tevSwapTable[0].alpha, GX_CH_ALPHA); - // K color selection should still be set - EXPECT_EQ(g_gxState.tevStages[0].kcSel, GX_TEV_KCSEL_K0); -} - -// --- GXSetTevSwapMode --- - -TEST_F(GXFifoTest, TevSwapMode_Stage0) { - GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP1, GX_TEV_SWAP2); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.tevStages[0].tevSwapRas, GX_TEV_SWAP1); - EXPECT_EQ(g_gxState.tevStages[0].tevSwapTex, GX_TEV_SWAP2); -} - -TEST_F(GXFifoTest, TevSwapMode_Stage3) { - GXSetTevSwapMode(GX_TEVSTAGE3, GX_TEV_SWAP3, GX_TEV_SWAP0); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.tevStages[3].tevSwapRas, GX_TEV_SWAP3); - EXPECT_EQ(g_gxState.tevStages[3].tevSwapTex, GX_TEV_SWAP0); -} - -// --- GXSetTevSwapModeTable --- - -TEST_F(GXFifoTest, TevSwapModeTable_Swap1_AllRed) { - GXSetTevSwapModeTable(GX_TEV_SWAP1, GX_CH_RED, GX_CH_RED, GX_CH_RED, GX_CH_ALPHA); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.tevSwapTable[GX_TEV_SWAP1].red, GX_CH_RED); - EXPECT_EQ(g_gxState.tevSwapTable[GX_TEV_SWAP1].green, GX_CH_RED); - EXPECT_EQ(g_gxState.tevSwapTable[GX_TEV_SWAP1].blue, GX_CH_RED); - EXPECT_EQ(g_gxState.tevSwapTable[GX_TEV_SWAP1].alpha, GX_CH_ALPHA); -} - -TEST_F(GXFifoTest, TevSwapModeTable_Swap2_Swizzle) { - GXSetTevSwapModeTable(GX_TEV_SWAP2, GX_CH_BLUE, GX_CH_GREEN, GX_CH_RED, GX_CH_ALPHA); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.tevSwapTable[GX_TEV_SWAP2].red, GX_CH_BLUE); - EXPECT_EQ(g_gxState.tevSwapTable[GX_TEV_SWAP2].green, GX_CH_GREEN); - EXPECT_EQ(g_gxState.tevSwapTable[GX_TEV_SWAP2].blue, GX_CH_RED); - EXPECT_EQ(g_gxState.tevSwapTable[GX_TEV_SWAP2].alpha, GX_CH_ALPHA); -} - -// --- GXSetTevOrder (BP 0x28-0x2F) --- - -TEST_F(GXFifoTest, TevOrder_Stage0) { - GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[0]; - EXPECT_EQ(s.texMapId, GX_TEXMAP0); - EXPECT_EQ(s.texCoordId, GX_TEXCOORD0); - EXPECT_EQ(s.channelId, GX_COLOR0A0); -} - -TEST_F(GXFifoTest, TevOrder_Stage1_OddStage) { - // Odd stages use different bit positions within the tref register - GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD2, GX_TEXMAP3, GX_COLOR1A1); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[1]; - EXPECT_EQ(s.texMapId, GX_TEXMAP3); - EXPECT_EQ(s.texCoordId, GX_TEXCOORD2); - EXPECT_EQ(s.channelId, GX_COLOR1A1); -} - -TEST_F(GXFifoTest, TevOrder_Stage0_TexNull) { - GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& s = g_gxState.tevStages[0]; - EXPECT_EQ(s.texMapId, GX_TEXMAP_NULL); - EXPECT_EQ(s.channelId, GX_COLOR0A0); -} - -// --- GXSetTevKColor (BP 0xE0-0xE7, K color flag) --- - -TEST_F(GXFifoTest, TevKColor_K0) { - GXColor kc = {255, 128, 64, 32}; - GXSetTevKColor(GX_KCOLOR0, kc); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - // K colors are stored as float (0-1 range), 8-bit precision - EXPECT_NEAR(g_gxState.kcolors[0][0], 255.f / 255.f, 1.f / 255.f); // R - EXPECT_NEAR(g_gxState.kcolors[0][1], 128.f / 255.f, 1.f / 255.f); // G - EXPECT_NEAR(g_gxState.kcolors[0][2], 64.f / 255.f, 1.f / 255.f); // B - EXPECT_NEAR(g_gxState.kcolors[0][3], 32.f / 255.f, 1.f / 255.f); // A -} - -TEST_F(GXFifoTest, TevKColor_K1) { - GXColor kc = {0, 255, 0, 128}; - GXSetTevKColor(GX_KCOLOR1, kc); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_NEAR(g_gxState.kcolors[1][0], 0.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.kcolors[1][1], 255.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.kcolors[1][2], 0.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.kcolors[1][3], 128.f / 255.f, 1.f / 255.f); -} - -TEST_F(GXFifoTest, TevKColor_K2) { - GXColor kc = {10, 20, 30, 40}; - GXSetTevKColor(GX_KCOLOR2, kc); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_NEAR(g_gxState.kcolors[2][0], 10.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.kcolors[2][1], 20.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.kcolors[2][2], 30.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.kcolors[2][3], 40.f / 255.f, 1.f / 255.f); -} - -TEST_F(GXFifoTest, TevKColor_K3) { - GXColor kc = {200, 150, 100, 50}; - GXSetTevKColor(GX_KCOLOR3, kc); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_NEAR(g_gxState.kcolors[3][0], 200.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.kcolors[3][1], 150.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.kcolors[3][2], 100.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.kcolors[3][3], 50.f / 255.f, 1.f / 255.f); -} - -// GXSetTevColor (BP 0xE0-0xE7): the side channel stores float while the FIFO encodes 11-bit -// signed, so the decoded value comes back with reduced precision. - -TEST_F(GXFifoTest, TevColor_Reg0) { - GXColor col = {200, 100, 50, 255}; - GXSetTevColor(GX_TEVREG0, col); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - // 11-bit signed encoding, so values should round-trip within 8-bit range - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG0][0], 200.f / 255.f, 1.f / 255.f); // R - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG0][1], 100.f / 255.f, 1.f / 255.f); // G - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG0][2], 50.f / 255.f, 1.f / 255.f); // B - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG0][3], 255.f / 255.f, 1.f / 255.f); // A -} - -TEST_F(GXFifoTest, TevColor_Prev) { - GXColor col = {128, 64, 32, 16}; - GXSetTevColor(GX_TEVPREV, col); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVPREV][0], 128.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVPREV][1], 64.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVPREV][2], 32.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVPREV][3], 16.f / 255.f, 1.f / 255.f); -} - -TEST_F(GXFifoTest, TevColor_Reg1) { - GXColor col = {0, 128, 255, 192}; - GXSetTevColor(GX_TEVREG1, col); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG1][0], 0.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG1][1], 128.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG1][2], 255.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG1][3], 192.f / 255.f, 1.f / 255.f); -} - -TEST_F(GXFifoTest, TevColor_Reg2) { - GXColor col = {1, 2, 3, 4}; - GXSetTevColor(GX_TEVREG2, col); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG2][0], 1.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG2][1], 2.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG2][2], 3.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG2][3], 4.f / 255.f, 1.f / 255.f); -} - -TEST_F(GXFifoTest, TevColorS10_Reg1) { - GXColorS10 col = {300, -50, 0, 255}; - GXSetTevColorS10(GX_TEVREG1, col); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG1][0], 300.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG1][1], -50.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG1][2], 0.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG1][3], 255.f / 255.f, 1.f / 255.f); -} - -TEST_F(GXFifoTest, TevColorS10_Reg2) { - GXColorS10 col = {-1024, 1023, 128, -256}; - GXSetTevColorS10(GX_TEVREG2, col); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG2][0], -1024.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG2][1], 1023.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG2][2], 128.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG2][3], -256.f / 255.f, 1.f / 255.f); -} - -// CP registers (require __GXSetDirtyState() flush) - -// --- GXClearVtxDesc --- - -TEST_F(GXFifoTest, ClearVtxDesc_ClearsAll) { - // Set every attribute to something non-default - GXSetVtxDesc(GX_VA_PNMTXIDX, GX_DIRECT); - GXSetVtxDesc(GX_VA_TEX0MTXIDX, GX_DIRECT); - GXSetVtxDesc(GX_VA_TEX1MTXIDX, GX_DIRECT); - GXSetVtxDesc(GX_VA_TEX2MTXIDX, GX_DIRECT); - GXSetVtxDesc(GX_VA_TEX3MTXIDX, GX_DIRECT); - GXSetVtxDesc(GX_VA_TEX4MTXIDX, GX_DIRECT); - GXSetVtxDesc(GX_VA_TEX5MTXIDX, GX_DIRECT); - GXSetVtxDesc(GX_VA_TEX6MTXIDX, GX_DIRECT); - GXSetVtxDesc(GX_VA_TEX7MTXIDX, GX_DIRECT); - GXSetVtxDesc(GX_VA_POS, GX_INDEX16); - GXSetVtxDesc(GX_VA_NRM, GX_INDEX8); - GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT); - GXSetVtxDesc(GX_VA_CLR1, GX_DIRECT); - GXSetVtxDesc(GX_VA_TEX0, GX_INDEX16); - GXSetVtxDesc(GX_VA_TEX1, GX_INDEX8); - GXSetVtxDesc(GX_VA_TEX2, GX_DIRECT); - GXSetVtxDesc(GX_VA_TEX3, GX_DIRECT); - GXSetVtxDesc(GX_VA_TEX4, GX_INDEX16); - GXSetVtxDesc(GX_VA_TEX5, GX_INDEX8); - GXSetVtxDesc(GX_VA_TEX6, GX_DIRECT); - GXSetVtxDesc(GX_VA_TEX7, GX_DIRECT); - // Discard the dirty state from above - aurora::gx::fifo::clear_buffer(); - - // Now clear and flush - GXClearVtxDesc(); - auto bytes = flush_and_capture(); - - reset_gx_state(); - // Pre-fill g_gxState with non-zero to prove decode clears them - for (int i = 0; i < GX_VA_MAX_ATTR; ++i) { - g_gxState.vtxDesc[i] = GX_INDEX16; - } - decode_fifo(bytes); - - // After GXClearVtxDesc: POS = GX_DIRECT, everything else = GX_NONE - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_PNMTXIDX], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_TEX0MTXIDX], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_TEX1MTXIDX], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_TEX2MTXIDX], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_TEX3MTXIDX], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_TEX4MTXIDX], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_TEX5MTXIDX], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_TEX6MTXIDX], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_TEX7MTXIDX], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_POS], GX_DIRECT); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_NRM], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_CLR0], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_CLR1], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_TEX0], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_TEX1], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_TEX2], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_TEX3], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_TEX4], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_TEX5], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_TEX6], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_TEX7], GX_NONE); -} - -// --- GXSetVtxDesc / GXClearVtxDesc --- - -TEST_F(GXFifoTest, VtxDesc_PosAndNrm_Direct) { - GXClearVtxDesc(); - GXSetVtxDesc(GX_VA_POS, GX_DIRECT); - GXSetVtxDesc(GX_VA_NRM, GX_DIRECT); - auto bytes = flush_and_capture(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_POS], GX_DIRECT); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_NRM], GX_DIRECT); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_CLR0], GX_NONE); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_TEX0], GX_NONE); -} - -TEST_F(GXFifoTest, VtxDesc_Indexed) { - GXClearVtxDesc(); - GXSetVtxDesc(GX_VA_POS, GX_INDEX16); - GXSetVtxDesc(GX_VA_NRM, GX_INDEX16); - GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT); - GXSetVtxDesc(GX_VA_TEX0, GX_INDEX8); - auto bytes = flush_and_capture(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_POS], GX_INDEX16); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_NRM], GX_INDEX16); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_CLR0], GX_DIRECT); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_TEX0], GX_INDEX8); - EXPECT_EQ(g_gxState.sourceVtxDesc[GX_VA_POS], GX_INDEX16); - EXPECT_EQ(g_gxState.sourceVtxDesc[GX_VA_NRM], GX_INDEX16); - EXPECT_EQ(g_gxState.sourceVtxDesc[GX_VA_CLR0], GX_DIRECT); - EXPECT_EQ(g_gxState.sourceVtxDesc[GX_VA_TEX0], GX_INDEX8); -} - -TEST_F(GXFifoTest, SourceVtxDesc_DoesNotChangeEmittedLayout) { - GXClearVtxDesc(); - GXSetVtxDesc(GX_VA_POS, GX_DIRECT); - auto bytes = flush_and_capture(); - - reset_gx_state(); - decode_fifo(bytes); - GXSetSourceVtxDesc(GX_VA_POS, GX_INDEX16); - - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_POS], GX_DIRECT); - EXPECT_EQ(g_gxState.sourceVtxDesc[GX_VA_POS], GX_INDEX16); -} - -TEST_F(GXFifoTest, VtxDesc_MtxIdx) { - GXClearVtxDesc(); - GXSetVtxDesc(GX_VA_PNMTXIDX, GX_DIRECT); - GXSetVtxDesc(GX_VA_TEX0MTXIDX, GX_DIRECT); - GXSetVtxDesc(GX_VA_POS, GX_DIRECT); - auto bytes = flush_and_capture(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_PNMTXIDX], GX_DIRECT); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_TEX0MTXIDX], GX_DIRECT); - EXPECT_EQ(g_gxState.vtxDesc[GX_VA_POS], GX_DIRECT); -} - -TEST_F(GXFifoTest, GetVtxDesc_UsesShadowState) { - GXClearVtxDesc(); - GXSetVtxDesc(GX_VA_POS, GX_INDEX16); - GXSetVtxDesc(GX_VA_NBT, GX_DIRECT); - - GXAttrType posType = GX_NONE; - GXAttrType nbtType = GX_NONE; - GXVtxDescList vcd[24]{}; - GXGetVtxDesc(GX_VA_POS, &posType); - GXGetVtxDesc(GX_VA_NBT, &nbtType); - GXGetVtxDescv(vcd); - - EXPECT_EQ(posType, GX_INDEX16); - EXPECT_EQ(nbtType, GX_DIRECT); - EXPECT_EQ(vcd[GX_VA_POS].attr, GX_VA_POS); - EXPECT_EQ(vcd[GX_VA_POS].type, GX_INDEX16); - EXPECT_EQ(vcd[GX_VA_TEX7 + 1].attr, GX_VA_NBT); - EXPECT_EQ(vcd[GX_VA_TEX7 + 1].type, GX_DIRECT); - EXPECT_EQ(vcd[GX_VA_TEX7 + 2].attr, GX_VA_NULL); -} - -// --- GXSetVtxAttrFmt --- - -TEST_F(GXFifoTest, VtxAttrFmt_PosF32) { - GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); - auto bytes = flush_and_capture(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& vf = g_gxState.vtxFmts[GX_VTXFMT0]; - EXPECT_EQ(vf.attrs[GX_VA_POS].cnt, GX_POS_XYZ); - EXPECT_EQ(vf.attrs[GX_VA_POS].type, GX_F32); - EXPECT_EQ(vf.attrs[GX_VA_POS].frac, 0); -} - -TEST_F(GXFifoTest, VtxAttrFmt_NrmS16) { - GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_S16, 0); - auto bytes = flush_and_capture(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& vf = g_gxState.vtxFmts[GX_VTXFMT0]; - EXPECT_EQ(vf.attrs[GX_VA_NRM].cnt, GX_NRM_XYZ); - EXPECT_EQ(vf.attrs[GX_VA_NRM].type, GX_S16); - EXPECT_EQ(vf.attrs[GX_VA_NRM].frac, 14); -} - -TEST_F(GXFifoTest, VtxAttrFmt_NrmU8UsesUnsignedScale) { - GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_S16, 0); - (void)flush_and_capture(); - GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_U8, 0); - auto bytes = flush_and_capture(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& vf = g_gxState.vtxFmts[GX_VTXFMT0]; - EXPECT_EQ(vf.attrs[GX_VA_NRM].cnt, GX_NRM_XYZ); - EXPECT_EQ(vf.attrs[GX_VA_NRM].type, GX_U8); - EXPECT_EQ(vf.attrs[GX_VA_NRM].frac, 7); -} - -TEST_F(GXFifoTest, NormalU8DirectPreservesUnsignedRawBytes) { - GXClearVtxDesc(); - GXSetVtxDesc(GX_VA_NRM, GX_DIRECT); - GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_U8, 0); - aurora::gx::fifo::clear_buffer(); - - GXNormal3u8(0xFF, 0x80, 0x01); - const auto bytes = capture_fifo(); - - ASSERT_EQ(bytes.size(), 3u); - EXPECT_EQ(bytes[0], 0xFF); - EXPECT_EQ(bytes[1], 0x80); - EXPECT_EQ(bytes[2], 0x01); -} - -TEST_F(GXFifoTest, VtxAttrFmt_NrmNBT3PreservesIndex3Bit) { - GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_NBT3, GX_S16, 0); - auto bytes = flush_and_capture(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& vf = g_gxState.vtxFmts[GX_VTXFMT0]; - EXPECT_EQ(vf.attrs[GX_VA_NRM].cnt, GX_NRM_NBT3); - EXPECT_EQ(vf.attrs[GX_VA_NRM].type, GX_S16); -} - -TEST_F(GXFifoTest, VtxAttrFmt_Tex0_S16_Frac8) { - GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_S16, 8); - auto bytes = flush_and_capture(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& vf = g_gxState.vtxFmts[GX_VTXFMT0]; - EXPECT_EQ(vf.attrs[GX_VA_TEX0].cnt, GX_TEX_ST); - EXPECT_EQ(vf.attrs[GX_VA_TEX0].type, GX_S16); - EXPECT_EQ(vf.attrs[GX_VA_TEX0].frac, 8); -} - -TEST_F(GXFifoTest, VtxAttrFmt_Clr0_RGBA8) { - GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); - auto bytes = flush_and_capture(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& vf = g_gxState.vtxFmts[GX_VTXFMT0]; - EXPECT_EQ(vf.attrs[GX_VA_CLR0].cnt, GX_CLR_RGBA); - EXPECT_EQ(vf.attrs[GX_VA_CLR0].type, GX_RGBA8); -} - -TEST_F(GXFifoTest, VtxAttrFmt_MultipleTexCoords) { - GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); - GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_TEX1, GX_TEX_ST, GX_U16, 15); - GXSetVtxAttrFmt(GX_VTXFMT1, GX_VA_TEX2, GX_TEX_ST, GX_S16, 8); - auto bytes = flush_and_capture(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& vf = g_gxState.vtxFmts[GX_VTXFMT1]; - EXPECT_EQ(vf.attrs[GX_VA_TEX0].type, GX_F32); - EXPECT_EQ(vf.attrs[GX_VA_TEX1].type, GX_U16); - EXPECT_EQ(vf.attrs[GX_VA_TEX1].frac, 15); - EXPECT_EQ(vf.attrs[GX_VA_TEX2].type, GX_S16); - EXPECT_EQ(vf.attrs[GX_VA_TEX2].frac, 8); -} - -TEST_F(GXFifoTest, GetVtxAttrFmt_UsesShadowState) { - GXSetVtxAttrFmt(GX_VTXFMT2, GX_VA_NRM, GX_NRM_NBT3, GX_S16, 0); - GXSetVtxAttrFmt(GX_VTXFMT2, GX_VA_TEX4, GX_TEX_ST, GX_U16, 11); - - GXCompCnt cnt = GX_POS_XY; - GXCompType type = GX_U8; - u8 frac = 0; - GXVtxAttrFmtList vat[13]{}; - - GXGetVtxAttrFmt(GX_VTXFMT2, GX_VA_NRM, &cnt, &type, &frac); - EXPECT_EQ(cnt, GX_NRM_NBT3); - EXPECT_EQ(type, GX_S16); - EXPECT_EQ(frac, 14); - - GXGetVtxAttrFmtv(GX_VTXFMT2, vat); - EXPECT_EQ(vat[GX_VA_NRM - GX_VA_POS].attr, GX_VA_NRM); - EXPECT_EQ(vat[GX_VA_NRM - GX_VA_POS].cnt, GX_NRM_NBT3); - EXPECT_EQ(vat[GX_VA_NRM - GX_VA_POS].type, GX_S16); - EXPECT_EQ(vat[GX_VA_TEX4 - GX_VA_POS].attr, GX_VA_TEX4); - EXPECT_EQ(vat[GX_VA_TEX4 - GX_VA_POS].type, GX_U16); - EXPECT_EQ(vat[GX_VA_TEX4 - GX_VA_POS].frac, 11); - EXPECT_EQ(vat[12].attr, GX_VA_NULL); -} - -// --- GXSetArray (Aurora array-base command + CP stride command) --- - -TEST_F(GXFifoTest, SetArray_Pos_EncodesAuroraArrayBaseAndStride) { - u8 posData[32]{}; - u8 oldData[8]{}; - - GXSetArray(GX_VA_POS, posData, sizeof(posData), 12, false); - auto bytes = capture_fifo(); - - ASSERT_EQ(bytes.size(), 22u); - EXPECT_EQ(bytes[0], GX_LOAD_AURORA); - EXPECT_EQ(bytes[1], 0x00); - EXPECT_EQ(bytes[2], GX_LOAD_AURORA_ARRAYBASE); - - const auto expect_be64 = [&](size_t offset, u64 value) { - for (size_t i = 0; i < 8; ++i) { - EXPECT_EQ(bytes[offset + i], static_cast((value >> (56 - i * 8)) & 0xFF)); - } - }; - const auto expect_be32 = [&](size_t offset, u32 value) { - for (size_t i = 0; i < 4; ++i) { - EXPECT_EQ(bytes[offset + i], static_cast((value >> (24 - i * 8)) & 0xFF)); - } - }; - - expect_be64(3, static_cast(reinterpret_cast(posData))); - expect_be32(11, sizeof(posData)); - EXPECT_EQ(bytes[15], 0); - EXPECT_EQ(bytes[16], GX_LOAD_CP_REG); - EXPECT_EQ(bytes[17], GX_CP_REG_ARRAYSTRIDE); - expect_be32(18, 12); - - reset_gx_state(); - gxState().arrays[GX_VA_POS].data = oldData; - gxState().arrays[GX_VA_POS].size = sizeof(oldData); - gxState().arrays[GX_VA_POS].stride = 2; - gxState().arrays[GX_VA_POS].cachedRange.offset = 4; - gxState().arrays[GX_VA_POS].cachedRange.size = 8; - gxState().stateDirty = false; - decode_fifo(bytes); - - EXPECT_EQ(gxState().arrays[GX_VA_POS].data, posData); - EXPECT_EQ(gxState().arrays[GX_VA_POS].size, sizeof(posData)); - EXPECT_EQ(gxState().arrays[GX_VA_POS].stride, 12); - EXPECT_FALSE(gxState().arrays[GX_VA_POS].le); - EXPECT_EQ(gxState().arrays[GX_VA_POS].cachedRange.offset, 0u); - EXPECT_EQ(gxState().arrays[GX_VA_POS].cachedRange.size, 0u); - EXPECT_TRUE(gxState().stateDirty); -} - -TEST_F(GXFifoTest, SetArray_Nbt_UsesNrmCommandSlotAndState) { - u8 nbtData[96]{}; - u8 untouchedData[24]{}; - - GXSetArray(GX_VA_NBT, nbtData, sizeof(nbtData), 36, false); - auto bytes = capture_fifo(); - - ASSERT_EQ(bytes.size(), 22u); - EXPECT_EQ(bytes[0], GX_LOAD_AURORA); - EXPECT_EQ(bytes[1], 0x00); - EXPECT_EQ(bytes[2], GX_LOAD_AURORA_ARRAYBASE | 0x01); - EXPECT_EQ(bytes[15], 0); - EXPECT_EQ(bytes[16], GX_LOAD_CP_REG); - EXPECT_EQ(bytes[17], GX_CP_REG_ARRAYSTRIDE | 0x01); - - reset_gx_state(); - gxState().arrays[GX_VA_NRM].cachedRange.offset = 12; - gxState().arrays[GX_VA_NRM].cachedRange.size = 48; - gxState().arrays[GX_VA_NBT].data = untouchedData; - gxState().arrays[GX_VA_NBT].size = sizeof(untouchedData); - gxState().arrays[GX_VA_NBT].stride = 24; - gxState().stateDirty = false; - decode_fifo(bytes); - - EXPECT_EQ(gxState().arrays[GX_VA_NRM].data, nbtData); - EXPECT_EQ(gxState().arrays[GX_VA_NRM].size, sizeof(nbtData)); - EXPECT_EQ(gxState().arrays[GX_VA_NRM].stride, 36); - EXPECT_FALSE(gxState().arrays[GX_VA_NRM].le); - EXPECT_EQ(gxState().arrays[GX_VA_NRM].cachedRange.offset, 0u); - EXPECT_EQ(gxState().arrays[GX_VA_NRM].cachedRange.size, 0u); - EXPECT_TRUE(gxState().stateDirty); - - EXPECT_EQ(gxState().arrays[GX_VA_NBT].data, untouchedData); - EXPECT_EQ(gxState().arrays[GX_VA_NBT].size, sizeof(untouchedData)); - EXPECT_EQ(gxState().arrays[GX_VA_NBT].stride, 24); -} - -TEST_F(GXFifoTest, SetArray_LittleEndianFlag_UpdatesStateAndClearsCachedRange) { - u8 clrData[16]{}; - - GXSetArray(GX_VA_CLR0, clrData, sizeof(clrData), 4, true); - auto bytes = capture_fifo(); - - ASSERT_EQ(bytes.size(), 22u); - EXPECT_EQ(bytes[0], GX_LOAD_AURORA); - EXPECT_EQ(bytes[1], 0x00); - EXPECT_EQ(bytes[2], GX_LOAD_AURORA_ARRAYBASE | (GX_VA_CLR0 - GX_VA_POS)); - EXPECT_EQ(bytes[15], 1); - EXPECT_EQ(bytes[16], GX_LOAD_CP_REG); - EXPECT_EQ(bytes[17], GX_CP_REG_ARRAYSTRIDE | (GX_VA_CLR0 - GX_VA_POS)); - - reset_gx_state(); - gxState().arrays[GX_VA_CLR0].data = clrData; - gxState().arrays[GX_VA_CLR0].size = sizeof(clrData); - gxState().arrays[GX_VA_CLR0].stride = 4; - gxState().arrays[GX_VA_CLR0].le = false; - gxState().arrays[GX_VA_CLR0].cachedRange.offset = 3; - gxState().arrays[GX_VA_CLR0].cachedRange.size = 9; - gxState().stateDirty = false; - decode_fifo(bytes); - - EXPECT_EQ(gxState().arrays[GX_VA_CLR0].data, clrData); - EXPECT_EQ(gxState().arrays[GX_VA_CLR0].size, sizeof(clrData)); - EXPECT_EQ(gxState().arrays[GX_VA_CLR0].stride, 4); - EXPECT_TRUE(gxState().arrays[GX_VA_CLR0].le); - EXPECT_EQ(gxState().arrays[GX_VA_CLR0].cachedRange.offset, 0u); - EXPECT_EQ(gxState().arrays[GX_VA_CLR0].cachedRange.size, 0u); - EXPECT_TRUE(gxState().stateDirty); -} - -TEST_F(GXFifoTest, InvalidateVtxCache_DropsAllIndexedArrayUploads) { - for (int i = GX_VA_POS; i <= GX_VA_TEX7; ++i) { - gxState().arrays[i].cachedRange.offset = static_cast(i * 32); - gxState().arrays[i].cachedRange.size = static_cast(i + 1); - } - - const std::vector command{GX_CMD_INVL_VC}; - decode_fifo(command); - - for (int i = GX_VA_POS; i <= GX_VA_TEX7; ++i) { - EXPECT_EQ(gxState().arrays[i].cachedRange.offset, 0u); - EXPECT_EQ(gxState().arrays[i].cachedRange.size, 0u); - } -} - -TEST_F(GXFifoTest, LoadTexObj_EncodesSdkBpBurstAndAuroraMetadata) { - alignas(32) u8 image[64]{}; - GXTexObj obj{}; - GXInitTexObj(&obj, image, 8, 8, GX_TF_RGB5A3, GX_REPEAT, GX_MIRROR, GX_FALSE); - - GXLoadTexObj(&obj, GX_TEXMAP2); - auto bytes = capture_fifo(); - - EXPECT_TRUE(has_bp_write(bytes, 0x82)); - EXPECT_TRUE(has_bp_write(bytes, 0x86)); - EXPECT_TRUE(has_bp_write(bytes, 0x8A)); - EXPECT_TRUE(has_bp_write(bytes, 0x8E)); - EXPECT_TRUE(has_bp_write(bytes, 0x92)); - EXPECT_TRUE(has_bp_write(bytes, 0x96)); - EXPECT_TRUE(has_aurora_cmd(bytes, GX_LOAD_AURORA_TEXOBJ)); - - reset_gx_state(); - decode_fifo(bytes); - - const auto& slot = gxState().loadedTextures[GX_TEXMAP2]; - EXPECT_EQ(slot.data, image); - EXPECT_EQ(slot.width(), 8u); - EXPECT_EQ(slot.height(), 8u); - EXPECT_EQ(slot.format(), GX_TF_RGB5A3); - EXPECT_FALSE(slot.has_mips()); - EXPECT_EQ(slot.mode0 >> 24, 0x82u); - EXPECT_EQ(slot.mode1 >> 24, 0x86u); - EXPECT_EQ(slot.image0 >> 24, 0x8Au); - EXPECT_EQ(slot.image3 >> 24, 0x96u); - EXPECT_NE(slot.texObjId, 0u); - EXPECT_EQ(slot.texDataVersion, 1u); -} - -TEST(GXTextureMipCount, ClampsLodToTheDimensionsFullMipChain) { - alignas(32) u8 image[64]{}; - - GXTexObj small{}; - GXInitTexObj(&small, image, 8, 8, GX_TF_I4, GX_CLAMP, GX_CLAMP, GX_TRUE); - GXInitTexObjMaxLOD(&small, 10.0f); - const auto& smallRef = reinterpret_cast(small); - EXPECT_EQ(smallRef.mip_count(), 4u); - - GXTexObj large{}; - GXInitTexObj(&large, image, 1024, 1024, GX_TF_I4, GX_CLAMP, GX_CLAMP, GX_TRUE); - GXInitTexObjMaxLOD(&large, 10.0f); - const auto& largeRef = reinterpret_cast(large); - EXPECT_EQ(largeRef.mip_count(), 11u); -} - -TEST_F(GXFifoTest, LoadTexObjPcFormat_PreservesFullFormatMetadata) { - alignas(32) u8 image[64]{}; - GXTexObj obj{}; - GXInitTexObj(&obj, image, 8, 8, GX_TF_RGBA8_PC, GX_REPEAT, GX_REPEAT, GX_FALSE); - - EXPECT_EQ(GXGetTexObjFmt(&obj), GX_TF_RGBA8_PC); - - GXLoadTexObj(&obj, GX_TEXMAP3); - auto bytes = capture_fifo(); - - EXPECT_TRUE(has_aurora_cmd(bytes, GX_LOAD_AURORA_TEXOBJ)); - - reset_gx_state(); - decode_fifo(bytes); - - const auto& slot = gxState().loadedTextures[GX_TEXMAP3]; - EXPECT_EQ(slot.width(), 8u); - EXPECT_EQ(slot.height(), 8u); - EXPECT_EQ(slot.format(), GX_TF_RGBA8_PC); - EXPECT_EQ(slot.raw_format(), static_cast(GX_TF_RGBA8)); -} - -TEST_F(GXFifoTest, RawDrawDrainsQueuedMaterialStateWithoutDeferredDirtyBits) { - __GXSetDirtyState(); - aurora::gx::fifo::clear_buffer(); - - constexpr GXColor color = {200, 100, 50, 255}; - GXSetTevColor(GX_TEVREG0, color); - - // TEV register writes are complete FIFO commands, not deferred SDK state. - // They therefore leave dirtyState clear while still preceding the draw. - ASSERT_EQ(__gx->dirtyState, 0u); - ASSERT_GT(aurora::gx::fifo::get_buffer_size(), 0u); - - // The raw bridge receives vertices that are already packed according to the - // active VAT. Seed its size cache so this test can isolate FIFO ordering. - g_gxState.lastVtxFmt = GX_VTXFMT0; - g_gxState.lastVtxSize = 1; - const std::array vertices{}; - - ASSERT_TRUE(aurora::gx::fifo::submit_raw_draw(GX_QUADS, GX_VTXFMT0, vertices.data(), 4, - static_cast(vertices.size()))); - EXPECT_EQ(aurora::gx::fifo::get_buffer_size(), 0u); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG0][0], 200.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG0][1], 100.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG0][2], 50.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.colorRegs[GX_TEVREG0][3], 255.f / 255.f, 1.f / 255.f); -} - -TEST_F(GXFifoTest, DisplayListCallWhileRecordingInlinesNestedCommands) { - std::array outer{}; - const std::array nested{GX_NOP, GX_NOP, GX_NOP}; - - __GXSetDirtyState(); - aurora::gx::fifo::clear_buffer(); - GXBeginDisplayList(outer.data(), static_cast(outer.size())); - GXCallDisplayList(nested.data(), static_cast(nested.size())); - const u32 bytes = GXEndDisplayList(); - - EXPECT_EQ(bytes, 32u); - EXPECT_TRUE(std::equal(nested.begin(), nested.end(), outer.begin())); - EXPECT_EQ(aurora::gx::fifo::get_buffer_size(), 0u); -} - -TEST_F(GXFifoTest, DirectEfbCopiesDrainQueuedCommands) { - aurora::gx::fifo::write_u8(GX_NOP); - ASSERT_GT(aurora::gx::fifo::get_buffer_size(), 0u); - GXCopyDisp(nullptr, GX_FALSE); - EXPECT_EQ(aurora::gx::fifo::get_buffer_size(), 0u); - - std::array copyDest{}; - aurora::gx::fifo::write_u8(GX_NOP); - ASSERT_GT(aurora::gx::fifo::get_buffer_size(), 0u); - GXCopyTex(copyDest.data(), GX_FALSE); - EXPECT_EQ(aurora::gx::fifo::get_buffer_size(), 0u); -} - -TEST_F(GXFifoTest, RawDrawPreservesHorizontalXzQuadVertices) { - __GXSetDirtyState(); - aurora::gx::fifo::clear_buffer(); - aurora::gfx::testing::use_real_vertex_format_helpers(true); - - g_gxState.lastVtxFmt = GX_VTXFMT0; - g_gxState.lastVtxSize = 14; - g_gxState.vtxDesc[GX_VA_POS] = GX_DIRECT; - g_gxState.vtxDesc[GX_VA_TEX0] = GX_DIRECT; - auto& fmt = g_gxState.vtxFmts[GX_VTXFMT0]; - fmt.attrs[GX_VA_POS].cnt = GX_POS_XYZ; - fmt.attrs[GX_VA_POS].type = GX_F32; - fmt.attrs[GX_VA_TEX0].cnt = GX_TEX_ST; - fmt.attrs[GX_VA_TEX0].type = GX_U8; - - std::vector vertices; - const auto append_f32_be = [&](float value) { - u32 bits = 0; - std::memcpy(&bits, &value, sizeof(bits)); - vertices.push_back(static_cast(bits >> 24)); - vertices.push_back(static_cast(bits >> 16)); - vertices.push_back(static_cast(bits >> 8)); - vertices.push_back(static_cast(bits)); - }; - const auto append_vertex = [&](float x, float y, float z, u8 s, u8 t) { - append_f32_be(x); - append_f32_be(y); - append_f32_be(z); - vertices.push_back(s); - vertices.push_back(t); - }; - - append_vertex(-53.659431f, 0.27f, -53.659435f, 0, 1); - append_vertex(-53.659431f, 0.27f, 53.659435f, 0, 0); - append_vertex(53.659431f, 0.27f, 53.659435f, 1, 0); - append_vertex(53.659431f, 0.27f, -53.659435f, 1, 1); - const auto expected = vertices; - - ASSERT_TRUE(aurora::gx::fifo::submit_raw_draw( - GX_QUADS, GX_VTXFMT0, vertices.data(), 4, static_cast(vertices.size()))); - EXPECT_EQ(aurora::gfx::testing::last_pushed_vertices(), expected); -} - -static void append_test_draw(std::vector& fifo, GXPrimitive primitive, u16 count) { - fifo.push_back(static_cast(primitive) | static_cast(GX_VTXFMT0)); - fifo.push_back(static_cast(count >> 8)); - fifo.push_back(static_cast(count)); - for (u16 vertex = 0; vertex < count; ++vertex) { - fifo.push_back(static_cast(vertex)); - } -} - -TEST_F(GXFifoTest, DrawTopologyTemplatesPreserveExactGxIndexOrder) { - g_gxState.lastVtxFmt = GX_VTXFMT0; - g_gxState.lastVtxSize = 1; - g_gxState.stateDirty = true; - - const auto decodeAndReadIndices = [&](GXPrimitive primitive, u16 count) { - std::vector fifo; - append_test_draw(fifo, primitive, count); - aurora::gfx::testing::reset_vertex_push_record(); - decode_fifo(fifo); - return aurora::gfx::testing::last_pushed_indices(); - }; - - EXPECT_EQ(decodeAndReadIndices(GX_QUADS, 8), - (std::vector{0, 1, 2, 2, 3, 0, 4, 5, 6, 6, 7, 4})); - g_gxState.stateDirty = true; - EXPECT_EQ(decodeAndReadIndices(GX_TRIANGLES, 6), - (std::vector{0, 1, 2, 3, 4, 5})); - g_gxState.stateDirty = true; - EXPECT_EQ(decodeAndReadIndices(GX_TRIANGLEFAN, 5), - (std::vector{0, 1, 2, 0, 2, 3, 0, 3, 4})); - g_gxState.stateDirty = true; - EXPECT_EQ(decodeAndReadIndices(GX_TRIANGLEFAN, 2), - (std::vector{})); - g_gxState.stateDirty = true; - EXPECT_EQ(decodeAndReadIndices(GX_TRIANGLESTRIP, 6), - (std::vector{0, 1, 2, 2, 1, 3, 2, 3, 4, 4, 3, 5})); - g_gxState.stateDirty = true; - EXPECT_TRUE(decodeAndReadIndices(GX_TRIANGLESTRIP, 0).empty()); - g_gxState.stateDirty = true; - EXPECT_EQ(decodeAndReadIndices(GX_LINES, 2), - (std::vector{0, 1, 3, 3, 2, 0})); -} - -TEST_F(GXFifoTest, MergedDrawOffsetsCachedTopologyWithoutJoiningPrimitives) { - g_gxState.lastVtxFmt = GX_VTXFMT0; - g_gxState.lastVtxSize = 1; - g_gxState.stateDirty = true; - aurora::gfx::testing::use_draw_command_tracking(true); - - std::vector fifo; - append_test_draw(fifo, GX_TRIANGLES, 3); - append_test_draw(fifo, GX_TRIANGLES, 3); - decode_fifo(fifo); - - EXPECT_EQ(aurora::gfx::g_mergedDrawCallCount, 1u); - EXPECT_EQ(aurora::gfx::testing::last_pushed_indices(), - (std::vector{3, 4, 5})); -} - -TEST_F(GXFifoTest, TexBufferSize_UsesExactLinearPcFormatSizes) { - EXPECT_EQ(GXGetTexBufferSize(8, 4, GX_TF_R8_PC, GX_FALSE, 0), 32u); - EXPECT_EQ(GXGetTexBufferSize(8, 4, GX_TF_RGBA8_PC, GX_FALSE, 0), 128u); - EXPECT_EQ(GXGetTexBufferSize(8, 4, GX_TF_R8_PC, GX_TRUE, 2), 42u); - EXPECT_EQ(GXGetTexBufferSize(8, 4, GX_TF_RGBA8_PC, GX_TRUE, 2), 168u); -} - -TEST_F(GXFifoTest, InvalidateTexAll_EmitsAuroraCacheInvalidationAndDirtiesState) { - GXInvalidateTexAll(); - auto bytes = capture_fifo(); - - EXPECT_TRUE(has_aurora_cmd(bytes, GX_LOAD_AURORA_INVALIDATE_TEX_ALL)); - - reset_gx_state(); - gxState().stateDirty = false; - decode_fifo(bytes); - EXPECT_TRUE(gxState().stateDirty); -} - -TEST_F(GXFifoTest, TexObjRawDimensions_WrapAtTenBitBoundary) { - auto& slot = gxState().loadedTextures[GX_TEXMAP0]; - slot.image0 = (0x3FFu << 0) | (0x3FFu << 10); - slot.mWidth = 0; - slot.mHeight = 0; - - EXPECT_EQ(slot.width(), 0u); - EXPECT_EQ(slot.height(), 0u); -} - -TEST_F(GXFifoTest, TexObjExplicitDimensions_DoNotWrapAtTenBitBoundary) { - auto& slot = gxState().loadedTextures[GX_TEXMAP0]; - slot.image0 = (0x3FFu << 0) | (0x3FFu << 10); - slot.mWidth = 1024; - slot.mHeight = 1024; - - EXPECT_EQ(slot.width(), 1024u); - EXPECT_EQ(slot.height(), 1024u); -} - -TEST_F(GXFifoTest, LoadTexObjCiAndTlut_PopulatesTextureAndTlutSlots) { - alignas(32) u8 image[64]{}; - alignas(32) u16 palette[16]{}; - GXTexObj texObj{}; - GXTlutObj tlutObj{}; - - GXInitTexObjCI(&texObj, image, 8, 8, GX_TF_C4, GX_CLAMP, GX_CLAMP, GX_FALSE, GX_TLUT3); - GXInitTlutObj(&tlutObj, palette, GX_TL_RGB565, 16); - - GXLoadTexObj(&texObj, GX_TEXMAP1); - GXLoadTlut(&tlutObj, GX_TLUT3); - auto bytes = capture_fifo(); - - EXPECT_TRUE(has_bp_write(bytes, 0x81)); - EXPECT_TRUE(has_bp_write(bytes, 0x85)); - EXPECT_TRUE(has_bp_write(bytes, 0x89)); - EXPECT_TRUE(has_bp_write(bytes, 0x8D)); - EXPECT_TRUE(has_bp_write(bytes, 0x91)); - EXPECT_TRUE(has_bp_write(bytes, 0x95)); - EXPECT_TRUE(has_bp_write(bytes, 0x99)); - EXPECT_TRUE(has_aurora_cmd(bytes, GX_LOAD_AURORA_TEXOBJ)); - EXPECT_TRUE(has_aurora_cmd(bytes, GX_LOAD_AURORA_TLUT)); - - reset_gx_state(); - decode_fifo(bytes); - - const auto& texSlot = gxState().loadedTextures[GX_TEXMAP1]; - EXPECT_EQ(texSlot.data, image); - EXPECT_EQ(texSlot.width(), 8u); - EXPECT_EQ(texSlot.height(), 8u); - EXPECT_EQ(texSlot.format(), GX_TF_C4); - EXPECT_EQ(texSlot.tlut, GX_TLUT3); - - const auto& tlutSlot = gxState().loadedTluts[GX_TLUT3]; - EXPECT_EQ(tlutSlot.data, palette); - EXPECT_EQ(tlutSlot.format, GX_TL_RGB565); - EXPECT_EQ(tlutSlot.numEntries, 16u); - EXPECT_NE(tlutSlot.tlutObjId, 0u); - EXPECT_EQ(tlutSlot.tlutDataVersion, 1u); -} - -TEST_F(GXFifoTest, DestroyTexObj_DoesNotEvictTextureDataAndClearsIdentity) { - alignas(32) u8 image[64]{}; - GXTexObj obj{}; - GXInitTexObj(&obj, image, 8, 8, GX_TF_RGB5A3, GX_REPEAT, GX_REPEAT, GX_FALSE); - GXDestroyTexObj(&obj); - auto bytes = capture_fifo(); - - EXPECT_FALSE(has_aurora_cmd(bytes, GX_LOAD_AURORA_DESTROY_TEXOBJ)); - EXPECT_EQ(reinterpret_cast(&obj)->texObjId, 0u); - - reset_gx_state(); - decode_fifo(bytes); -} - -TEST_F(GXFifoTest, DestroyTexObj_DoesNotPoisonLoadedSlotCache) { - alignas(32) u8 imageA[64]{}; - alignas(32) u8 imageB[64]{}; - GXTexObj objA{}; - GXTexObj objB{}; - - GXInitTexObj(&objA, imageA, 8, 8, GX_TF_RGB5A3, GX_REPEAT, GX_REPEAT, GX_FALSE); - GXLoadTexObj(&objA, GX_TEXMAP2); - auto loadABytes = capture_fifo(); - const auto destroyedTexObjId = reinterpret_cast(&objA)->texObjId; - - GXDestroyTexObj(&objA); - auto destroyBytes = capture_fifo(); - - GXInitTexObj(&objB, imageB, 8, 8, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE); - GXLoadTexObj(&objB, GX_TEXMAP2); - auto loadBBytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(loadABytes); - auto& slot = gxState().loadedTextures[GX_TEXMAP2]; - EXPECT_EQ(slot.texObjId, destroyedTexObjId); - EXPECT_FALSE(slot.no_cache()); - - decode_fifo(destroyBytes); - EXPECT_EQ(slot.texObjId, destroyedTexObjId); - EXPECT_FALSE(slot.no_cache()); - - decode_fifo(loadBBytes); - EXPECT_EQ(slot.data, imageB); - EXPECT_EQ(slot.format(), GX_TF_RGB565); - EXPECT_FALSE(slot.no_cache()); -} - -TEST_F(GXFifoTest, DestroyTlutObj_EmitsAuroraDestroyCommandAndClearsIdentity) { - alignas(32) u16 palette[16]{}; - GXTlutObj obj{}; - GXInitTlutObj(&obj, palette, GX_TL_RGB565, 16); - GXDestroyTlutObj(&obj); - auto bytes = capture_fifo(); - - EXPECT_TRUE(has_aurora_cmd(bytes, GX_LOAD_AURORA_DESTROY_TLUT)); - EXPECT_EQ(reinterpret_cast(&obj)->tlutObjId, 0u); - - reset_gx_state(); - decode_fifo(bytes); -} - -TEST_F(GXFifoTest, DestroyTlutObj_MarksLoadedSlotNoCacheUntilReloaded) { - alignas(32) u16 paletteA[16]{}; - alignas(32) u16 paletteB[16]{}; - GXTlutObj objA{}; - GXTlutObj objB{}; - - GXInitTlutObj(&objA, paletteA, GX_TL_RGB565, 16); - GXLoadTlut(&objA, GX_TLUT3); - auto loadABytes = capture_fifo(); - const auto destroyedTlutObjId = reinterpret_cast(&objA)->tlutObjId; - - GXDestroyTlutObj(&objA); - auto destroyBytes = capture_fifo(); - - GXInitTlutObj(&objB, paletteB, GX_TL_IA8, 16); - GXLoadTlut(&objB, GX_TLUT3); - auto loadBBytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(loadABytes); - auto& slot = gxState().loadedTluts[GX_TLUT3]; - EXPECT_EQ(slot.tlutObjId, destroyedTlutObjId); - EXPECT_FALSE(slot.no_cache()); - - decode_fifo(destroyBytes); - EXPECT_EQ(slot.tlutObjId, destroyedTlutObjId); - EXPECT_TRUE(slot.no_cache()); - - decode_fifo(loadBBytes); - EXPECT_EQ(slot.data, paletteB); - EXPECT_EQ(slot.format, GX_TL_IA8); - EXPECT_FALSE(slot.no_cache()); -} - -TEST_F(GXFifoTest, DestroyCopyTex_EmitsAuroraDestroyCommand) { - alignas(32) u8 image[32]{}; - - GXDestroyCopyTex(image); - auto bytes = capture_fifo(); - - EXPECT_TRUE(has_aurora_cmd(bytes, GX_LOAD_AURORA_DESTROY_COPY_TEX)); - - reset_gx_state(); - decode_fifo(bytes); -} - -TEST_F(GXFifoTest, DestroyCopyTex_RemovesActiveCopyTextureAndCacheEntriesForPointer) { - alignas(32) u8 imageA[32]{}; - alignas(32) u8 imageB[32]{}; - - const aurora::gx::GXState::CopyTextureRef ref{.revision = 1}; - gxState().copyTextures[imageA] = ref; - gxState().copyTextures[imageB] = ref; - gxState().copyTextureCache.emplace( - aurora::gx::GXState::CopyTextureKey{.dest = imageA, .width = 32, .height = 32, .format = GX_TF_I4}, ref); - gxState().copyTextureCache.emplace( - aurora::gx::GXState::CopyTextureKey{.dest = imageA, .width = 64, .height = 64, .format = GX_TF_I8}, ref); - gxState().copyTextureCache.emplace( - aurora::gx::GXState::CopyTextureKey{.dest = imageB, .width = 32, .height = 32, .format = GX_TF_I4}, ref); - - GXDestroyCopyTex(imageA); - auto bytes = capture_fifo(); - - decode_fifo(bytes); - - EXPECT_FALSE(gxState().copyTextures.contains(imageA)); - EXPECT_TRUE(gxState().copyTextures.contains(imageB)); - for (const auto& [key, _] : gxState().copyTextureCache) { - EXPECT_NE(key.dest, imageA); - } - EXPECT_EQ(gxState().copyTextureCache.size(), 1u); -} - -// BP genMode (requires __GXSetDirtyState() flush) - -// --- GXSetCullMode --- - -TEST_F(GXFifoTest, CullMode_Back) { - GXSetCullMode(GX_CULL_BACK); - auto bytes = flush_and_capture(); - - reset_gx_state(); - g_gxState.cullMode = GX_CULL_NONE; - decode_fifo(bytes); - - // The encoder swaps front/back for hardware, and decoder swaps back - EXPECT_EQ(g_gxState.cullMode, GX_CULL_BACK); -} - -TEST_F(GXFifoTest, CullMode_Front) { - GXSetCullMode(GX_CULL_FRONT); - auto bytes = flush_and_capture(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.cullMode, GX_CULL_FRONT); -} - -TEST_F(GXFifoTest, CullMode_None) { - GXSetCullMode(GX_CULL_NONE); - auto bytes = flush_and_capture(); - - reset_gx_state(); - g_gxState.cullMode = GX_CULL_BACK; - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.cullMode, GX_CULL_NONE); -} - -TEST_F(GXFifoTest, GetLinePointCullShadowState) { - GXSetLineWidth(12, GX_TO_ZERO); - GXSetPointSize(34, GX_TO_ONE); - GXSetCullMode(GX_CULL_FRONT); - - u8 lineWidth = 0; - u8 pointSize = 0; - GXTexOffset lineOffs = GX_TO_ZERO; - GXTexOffset pointOffs = GX_TO_ZERO; - GXCullMode cullMode = GX_CULL_NONE; - - GXGetLineWidth(&lineWidth, &lineOffs); - GXGetPointSize(&pointSize, &pointOffs); - GXGetCullMode(&cullMode); - - EXPECT_EQ(lineWidth, 12); - EXPECT_EQ(lineOffs, GX_TO_ZERO); - EXPECT_EQ(pointSize, 34); - EXPECT_EQ(pointOffs, GX_TO_ONE); - EXPECT_EQ(cullMode, GX_CULL_FRONT); -} - -TEST_F(GXFifoTest, LinePointSize_Decode) { - GXSetLineWidth(12, GX_TO_ZERO); - GXSetPointSize(34, GX_TO_ONE); - auto bytes = capture_fifo(); - - ASSERT_EQ(bytes.size(), 10u); - EXPECT_EQ(bytes[0], 0x61); - EXPECT_EQ(bytes[1], 0x22); - EXPECT_EQ(bytes[5], 0x61); - EXPECT_EQ(bytes[6], 0x22); - - reset_gx_state(); - g_gxState.lineWidth = 1; - g_gxState.pointSize = 2; - g_gxState.lineTexOffset = GX_TO_ONE; - g_gxState.pointTexOffset = GX_TO_ZERO; - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.lineWidth, 12u); - EXPECT_EQ(g_gxState.lineTexOffset, GX_TO_ZERO); - EXPECT_EQ(g_gxState.pointSize, 34u); - EXPECT_EQ(g_gxState.pointTexOffset, GX_TO_ONE); -} - -// --- GXSetNumTevStages / GXSetNumTexGens / GXSetNumChans --- - -TEST_F(GXFifoTest, NumTevStages) { - GXSetNumTevStages(4); - auto bytes = flush_and_capture(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.numTevStages, 4u); -} - -TEST_F(GXFifoTest, NumTexGens) { - GXSetNumTexGens(3); - auto bytes = flush_and_capture(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.numTexGens, 3u); -} - -TEST_F(GXFifoTest, NumChans) { - GXSetNumChans(2); - auto bytes = flush_and_capture(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.numChans, 2u); -} - -// XF registers (direct FIFO writes) - -// --- GXLoadPosMtxImm (XF 0x000-0x077) --- - -TEST_F(GXFifoTest, LoadPosMtxImm_Identity) { - // 3x4 identity matrix - aurora::Mat3x4 mtx{}; - mtx.m0[0] = 1.0f; - mtx.m1[1] = 1.0f; - mtx.m2[2] = 1.0f; - - GXLoadPosMtxImm(&mtx, GX_PNMTX0); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& decoded = g_gxState.pnMtx[0].pos; - EXPECT_FLOAT_EQ(decoded.m0[0], 1.0f); - EXPECT_FLOAT_EQ(decoded.m0[1], 0.0f); - EXPECT_FLOAT_EQ(decoded.m0[2], 0.0f); - EXPECT_FLOAT_EQ(decoded.m0[3], 0.0f); - EXPECT_FLOAT_EQ(decoded.m1[0], 0.0f); - EXPECT_FLOAT_EQ(decoded.m1[1], 1.0f); - EXPECT_FLOAT_EQ(decoded.m1[2], 0.0f); - EXPECT_FLOAT_EQ(decoded.m1[3], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[0], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[1], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[2], 1.0f); - EXPECT_FLOAT_EQ(decoded.m2[3], 0.0f); -} - -TEST_F(GXFifoTest, LoadPosMtxImm_Translation) { - aurora::Mat3x4 mtx{}; - mtx.m0[0] = 1.0f; - mtx.m1[1] = 1.0f; - mtx.m2[2] = 1.0f; - mtx.m0[3] = 10.0f; - mtx.m1[3] = 20.0f; - mtx.m2[3] = 30.0f; - - GXLoadPosMtxImm(&mtx, GX_PNMTX3); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& decoded = g_gxState.pnMtx[3].pos; - EXPECT_FLOAT_EQ(decoded.m0[0], 1.0f); - EXPECT_FLOAT_EQ(decoded.m0[3], 10.0f); - EXPECT_FLOAT_EQ(decoded.m1[3], 20.0f); - EXPECT_FLOAT_EQ(decoded.m2[3], 30.0f); -} - -// --- GXLoadNrmMtxImm (XF 0x400-0x459) --- - -TEST_F(GXFifoTest, LoadNrmMtxImm_Identity) { - // 3x4 matrix with 3x3 identity (translation column ignored by encoder) - aurora::Mat3x4 mtx{}; - mtx.m0[0] = 1.0f; - mtx.m1[1] = 1.0f; - mtx.m2[2] = 1.0f; - - GXLoadNrmMtxImm(&mtx, GX_PNMTX0); - auto bytes = capture_fifo(); - - // XF opcode 0x10 - ASSERT_GE(bytes.size(), 5u); - EXPECT_EQ(bytes[0], 0x10); - - reset_gx_state(); - decode_fifo(bytes); - - auto& decoded = g_gxState.pnMtx[0].nrm; - EXPECT_FLOAT_EQ(decoded.m0[0], 1.0f); - EXPECT_FLOAT_EQ(decoded.m0[1], 0.0f); - EXPECT_FLOAT_EQ(decoded.m0[2], 0.0f); - EXPECT_FLOAT_EQ(decoded.m1[0], 0.0f); - EXPECT_FLOAT_EQ(decoded.m1[1], 1.0f); - EXPECT_FLOAT_EQ(decoded.m1[2], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[0], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[1], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[2], 1.0f); -} - -TEST_F(GXFifoTest, LoadNrmMtxImm_ArbitraryValues) { - aurora::Mat3x4 mtx{}; - mtx.m0[0] = 0.5f; mtx.m0[1] = -0.5f; mtx.m0[2] = 0.7f; mtx.m0[3] = 999.0f; - mtx.m1[0] = 0.3f; mtx.m1[1] = 0.8f; mtx.m1[2] = -0.1f; mtx.m1[3] = 888.0f; - mtx.m2[0] = -0.6f; mtx.m2[1] = 0.2f; mtx.m2[2] = 0.9f; mtx.m2[3] = 777.0f; - - GXLoadNrmMtxImm(&mtx, GX_PNMTX0); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& decoded = g_gxState.pnMtx[0].nrm; - // 3x3 portion should round-trip - EXPECT_FLOAT_EQ(decoded.m0[0], 0.5f); - EXPECT_FLOAT_EQ(decoded.m0[1], -0.5f); - EXPECT_FLOAT_EQ(decoded.m0[2], 0.7f); - EXPECT_FLOAT_EQ(decoded.m1[0], 0.3f); - EXPECT_FLOAT_EQ(decoded.m1[1], 0.8f); - EXPECT_FLOAT_EQ(decoded.m1[2], -0.1f); - EXPECT_FLOAT_EQ(decoded.m2[0], -0.6f); - EXPECT_FLOAT_EQ(decoded.m2[1], 0.2f); - EXPECT_FLOAT_EQ(decoded.m2[2], 0.9f); - // Translation column is NOT written by the encoder, so it stays zeroed - EXPECT_FLOAT_EQ(decoded.m0[3], 0.0f); - EXPECT_FLOAT_EQ(decoded.m1[3], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[3], 0.0f); -} - -TEST_F(GXFifoTest, LoadNrmMtxImm_DifferentSlot) { - aurora::Mat3x4 mtx{}; - mtx.m0[0] = 2.0f; - mtx.m1[1] = 3.0f; - mtx.m2[2] = 4.0f; - - GXLoadNrmMtxImm(&mtx, GX_PNMTX3); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& decoded = g_gxState.pnMtx[3].nrm; - EXPECT_FLOAT_EQ(decoded.m0[0], 2.0f); - EXPECT_FLOAT_EQ(decoded.m1[1], 3.0f); - EXPECT_FLOAT_EQ(decoded.m2[2], 4.0f); -} - -TEST_F(GXFifoTest, LoadNrmMtxImm_Isolation) { - // Loading nrm into slot 0 should not affect slot 1 or the pos matrix - aurora::Mat3x4 mtx{}; - mtx.m0[0] = 11.0f; - mtx.m1[1] = 22.0f; - mtx.m2[2] = 33.0f; - - GXLoadNrmMtxImm(&mtx, GX_PNMTX0); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - // Slot 0 nrm should have our values - EXPECT_FLOAT_EQ(g_gxState.pnMtx[0].nrm.m0[0], 11.0f); - // Slot 0 pos should remain zeroed (nrm write doesn't touch pos) - EXPECT_FLOAT_EQ(g_gxState.pnMtx[0].pos.m0[0], 0.0f); - // Slot 1 nrm should remain zeroed - EXPECT_FLOAT_EQ(g_gxState.pnMtx[1].nrm.m0[0], 0.0f); -} - -TEST_F(GXFifoTest, LoadNrmMtxImm_WithPosMtx) { - // Load both pos and nrm into the same slot, verify both decode correctly - aurora::Mat3x4 posMtx{}; - posMtx.m0[0] = 1.0f; - posMtx.m1[1] = 1.0f; - posMtx.m2[2] = 1.0f; - posMtx.m0[3] = 5.0f; - posMtx.m1[3] = 10.0f; - posMtx.m2[3] = 15.0f; - - aurora::Mat3x4 nrmMtx{}; - nrmMtx.m0[0] = 0.5f; - nrmMtx.m1[1] = 0.5f; - nrmMtx.m2[2] = 0.5f; - - GXLoadPosMtxImm(&posMtx, GX_PNMTX0); - GXLoadNrmMtxImm(&nrmMtx, GX_PNMTX0); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - // Position matrix - EXPECT_FLOAT_EQ(g_gxState.pnMtx[0].pos.m0[0], 1.0f); - EXPECT_FLOAT_EQ(g_gxState.pnMtx[0].pos.m0[3], 5.0f); - EXPECT_FLOAT_EQ(g_gxState.pnMtx[0].pos.m1[3], 10.0f); - EXPECT_FLOAT_EQ(g_gxState.pnMtx[0].pos.m2[3], 15.0f); - // Normal matrix - EXPECT_FLOAT_EQ(g_gxState.pnMtx[0].nrm.m0[0], 0.5f); - EXPECT_FLOAT_EQ(g_gxState.pnMtx[0].nrm.m1[1], 0.5f); - EXPECT_FLOAT_EQ(g_gxState.pnMtx[0].nrm.m2[2], 0.5f); -} - -// --- GXLoadTexMtxImm 3x4 (XF 0x078-0x0EF) --- - -TEST_F(GXFifoTest, LoadTexMtx3x4_Identity) { - aurora::Mat3x4 mtx{}; - mtx.m0[0] = 1.0f; - mtx.m1[1] = 1.0f; - mtx.m2[2] = 1.0f; - - GXLoadTexMtxImm(&mtx, GX_TEXMTX0, GX_MTX3x4); - auto bytes = capture_fifo(); - - ASSERT_GE(bytes.size(), 5u); - EXPECT_EQ(bytes[0], 0x10); - - reset_gx_state(); - decode_fifo(bytes); - - auto& decoded = g_gxState.texMtxs[0]; - EXPECT_FLOAT_EQ(decoded.m0[0], 1.0f); - EXPECT_FLOAT_EQ(decoded.m0[1], 0.0f); - EXPECT_FLOAT_EQ(decoded.m0[2], 0.0f); - EXPECT_FLOAT_EQ(decoded.m0[3], 0.0f); - EXPECT_FLOAT_EQ(decoded.m1[0], 0.0f); - EXPECT_FLOAT_EQ(decoded.m1[1], 1.0f); - EXPECT_FLOAT_EQ(decoded.m1[2], 0.0f); - EXPECT_FLOAT_EQ(decoded.m1[3], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[0], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[1], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[2], 1.0f); - EXPECT_FLOAT_EQ(decoded.m2[3], 0.0f); -} - -TEST_F(GXFifoTest, LoadTexMtx3x4_ArbitraryValues) { - aurora::Mat3x4 mtx{}; - mtx.m0[0] = 2.0f; mtx.m0[1] = 0.5f; mtx.m0[2] = 0.0f; mtx.m0[3] = 10.0f; - mtx.m1[0] = -0.5f; mtx.m1[1] = 3.0f; mtx.m1[2] = 0.0f; mtx.m1[3] = 20.0f; - mtx.m2[0] = 0.0f; mtx.m2[1] = 0.0f; mtx.m2[2] = 1.5f; mtx.m2[3] = -5.0f; - - GXLoadTexMtxImm(&mtx, GX_TEXMTX0, GX_MTX3x4); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& decoded = g_gxState.texMtxs[0]; - EXPECT_FLOAT_EQ(decoded.m0[0], 2.0f); - EXPECT_FLOAT_EQ(decoded.m0[1], 0.5f); - EXPECT_FLOAT_EQ(decoded.m0[2], 0.0f); - EXPECT_FLOAT_EQ(decoded.m0[3], 10.0f); - EXPECT_FLOAT_EQ(decoded.m1[0], -0.5f); - EXPECT_FLOAT_EQ(decoded.m1[1], 3.0f); - EXPECT_FLOAT_EQ(decoded.m1[2], 0.0f); - EXPECT_FLOAT_EQ(decoded.m1[3], 20.0f); - EXPECT_FLOAT_EQ(decoded.m2[0], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[1], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[2], 1.5f); - EXPECT_FLOAT_EQ(decoded.m2[3], -5.0f); -} - -TEST_F(GXFifoTest, LoadTexMtx3x4_DifferentSlot) { - aurora::Mat3x4 mtx{}; - mtx.m0[0] = 7.0f; - mtx.m1[1] = 8.0f; - mtx.m2[2] = 9.0f; - mtx.m2[3] = 42.0f; - - GXLoadTexMtxImm(&mtx, GX_TEXMTX5, GX_MTX3x4); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - // GX_TEXMTX5 = 45, addr = 45*4 = 180 = 0xB4, index = (0xB4 - 0x78) / 12 = 5 - auto& decoded = g_gxState.texMtxs[5]; - EXPECT_FLOAT_EQ(decoded.m0[0], 7.0f); - EXPECT_FLOAT_EQ(decoded.m1[1], 8.0f); - EXPECT_FLOAT_EQ(decoded.m2[2], 9.0f); - EXPECT_FLOAT_EQ(decoded.m2[3], 42.0f); -} - -TEST_F(GXFifoTest, LoadTexMtx3x4_LastSlot) { - aurora::Mat3x4 mtx{}; - mtx.m0[0] = 11.0f; - mtx.m1[1] = 22.0f; - mtx.m2[2] = 33.0f; - - GXLoadTexMtxImm(&mtx, GX_TEXMTX9, GX_MTX3x4); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& decoded = g_gxState.texMtxs[9]; - EXPECT_FLOAT_EQ(decoded.m0[0], 11.0f); - EXPECT_FLOAT_EQ(decoded.m1[1], 22.0f); - EXPECT_FLOAT_EQ(decoded.m2[2], 33.0f); -} - -TEST_F(GXFifoTest, LoadTexMtx3x4_Isolation) { - aurora::Mat3x4 mtx{}; - mtx.m0[0] = 50.0f; - mtx.m1[1] = 60.0f; - mtx.m2[2] = 70.0f; - - GXLoadTexMtxImm(&mtx, GX_TEXMTX0, GX_MTX3x4); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_FLOAT_EQ(g_gxState.texMtxs[0].m0[0], 50.0f); - // Slot 1 should remain zeroed - EXPECT_FLOAT_EQ(g_gxState.texMtxs[1].m0[0], 0.0f); - EXPECT_FLOAT_EQ(g_gxState.texMtxs[1].m1[1], 0.0f); -} - -// --- GXLoadTexMtxImm 2x4 (XF 0x078-0x0EF) --- - -TEST_F(GXFifoTest, LoadTexMtx2x4_Identity) { - // 2x4 identity: row0 = [1,0,0,0], row1 = [0,1,0,0] - aurora::Mat3x4 mtx{}; - mtx.m0[0] = 1.0f; - mtx.m1[1] = 1.0f; - - GXLoadTexMtxImm(&mtx, GX_TEXMTX0, GX_MTX2x4); - auto bytes = capture_fifo(); - - ASSERT_GE(bytes.size(), 5u); - EXPECT_EQ(bytes[0], 0x10); - - reset_gx_state(); - decode_fifo(bytes); - - auto& decoded = g_gxState.texMtxs[0]; - // First two rows should round-trip - EXPECT_FLOAT_EQ(decoded.m0[0], 1.0f); - EXPECT_FLOAT_EQ(decoded.m0[1], 0.0f); - EXPECT_FLOAT_EQ(decoded.m0[2], 0.0f); - EXPECT_FLOAT_EQ(decoded.m0[3], 0.0f); - EXPECT_FLOAT_EQ(decoded.m1[0], 0.0f); - EXPECT_FLOAT_EQ(decoded.m1[1], 1.0f); - EXPECT_FLOAT_EQ(decoded.m1[2], 0.0f); - EXPECT_FLOAT_EQ(decoded.m1[3], 0.0f); - // Third row not written by 2x4, should be zeroed - EXPECT_FLOAT_EQ(decoded.m2[0], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[1], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[2], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[3], 0.0f); -} - -TEST_F(GXFifoTest, LoadTexMtx2x4_ArbitraryValues) { - aurora::Mat3x4 mtx{}; - mtx.m0[0] = 0.5f; mtx.m0[1] = -1.0f; mtx.m0[2] = 0.25f; mtx.m0[3] = 100.0f; - mtx.m1[0] = 3.0f; mtx.m1[1] = 0.0f; mtx.m1[2] = -2.5f; mtx.m1[3] = -50.0f; - // Row 2 values should be ignored by the encoder - mtx.m2[0] = 999.0f; - - GXLoadTexMtxImm(&mtx, GX_TEXMTX0, GX_MTX2x4); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& decoded = g_gxState.texMtxs[0]; - EXPECT_FLOAT_EQ(decoded.m0[0], 0.5f); - EXPECT_FLOAT_EQ(decoded.m0[1], -1.0f); - EXPECT_FLOAT_EQ(decoded.m0[2], 0.25f); - EXPECT_FLOAT_EQ(decoded.m0[3], 100.0f); - EXPECT_FLOAT_EQ(decoded.m1[0], 3.0f); - EXPECT_FLOAT_EQ(decoded.m1[1], 0.0f); - EXPECT_FLOAT_EQ(decoded.m1[2], -2.5f); - EXPECT_FLOAT_EQ(decoded.m1[3], -50.0f); - // Row 2 should be zeroed (only 8 floats written) - EXPECT_FLOAT_EQ(decoded.m2[0], 0.0f); -} - -TEST_F(GXFifoTest, LoadTexMtx2x4_DifferentSlot) { - aurora::Mat3x4 mtx{}; - mtx.m0[0] = 4.0f; - mtx.m0[3] = 15.0f; - mtx.m1[1] = 5.0f; - mtx.m1[3] = 25.0f; - - GXLoadTexMtxImm(&mtx, GX_TEXMTX3, GX_MTX2x4); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& decoded = g_gxState.texMtxs[3]; - EXPECT_FLOAT_EQ(decoded.m0[0], 4.0f); - EXPECT_FLOAT_EQ(decoded.m0[3], 15.0f); - EXPECT_FLOAT_EQ(decoded.m1[1], 5.0f); - EXPECT_FLOAT_EQ(decoded.m1[3], 25.0f); -} - -TEST_F(GXFifoTest, LoadTexMtx2x4_Isolation) { - aurora::Mat3x4 mtx{}; - mtx.m0[0] = 10.0f; - mtx.m1[1] = 20.0f; - - GXLoadTexMtxImm(&mtx, GX_TEXMTX0, GX_MTX2x4); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_FLOAT_EQ(g_gxState.texMtxs[0].m0[0], 10.0f); - EXPECT_FLOAT_EQ(g_gxState.texMtxs[0].m1[1], 20.0f); - // Slot 1 should remain zeroed - EXPECT_FLOAT_EQ(g_gxState.texMtxs[1].m0[0], 0.0f); - EXPECT_FLOAT_EQ(g_gxState.texMtxs[1].m1[1], 0.0f); -} - -// --- GXSetProjection (XF 0x1020-0x1026) --- - -TEST_F(GXFifoTest, Projection_Perspective) { - aurora::Mat4x4 proj{}; - proj.m0[0] = 1.5f; // near / (right - left) * 2 - proj.m0[2] = 0.1f; - proj.m1[1] = 2.0f; // near / (top - bottom) * 2 - proj.m1[2] = 0.2f; - proj.m2[2] = -1.002f; - proj.m2[3] = -0.2002f; - proj.m3[2] = -1.0f; - - GXSetProjection(&proj, GX_PERSPECTIVE); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.projType, GX_PERSPECTIVE); - EXPECT_FLOAT_EQ(g_gxState.proj.m0[0], 1.5f); - EXPECT_FLOAT_EQ(g_gxState.proj.m0[2], 0.1f); - EXPECT_FLOAT_EQ(g_gxState.proj.m1[1], 2.0f); - EXPECT_FLOAT_EQ(g_gxState.proj.m1[2], 0.2f); - EXPECT_FLOAT_EQ(g_gxState.proj.m2[2], -1.002f); - EXPECT_FLOAT_EQ(g_gxState.proj.m2[3], -0.2002f); - EXPECT_FLOAT_EQ(g_gxState.proj.m3[2], -1.0f); -} - -TEST_F(GXFifoTest, Projection_Orthographic) { - aurora::Mat4x4 proj{}; - proj.m0[0] = 2.0f / 640.0f; - proj.m0[3] = -1.0f; - proj.m1[1] = 2.0f / 480.0f; - proj.m1[3] = -1.0f; - proj.m2[2] = -1.0f / 10000.0f; - proj.m2[3] = 0.0f; - proj.m3[3] = 1.0f; - - GXSetProjection(&proj, GX_ORTHOGRAPHIC); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.projType, GX_ORTHOGRAPHIC); - EXPECT_FLOAT_EQ(g_gxState.proj.m0[0], 2.0f / 640.0f); - EXPECT_FLOAT_EQ(g_gxState.proj.m0[3], -1.0f); - EXPECT_FLOAT_EQ(g_gxState.proj.m1[1], 2.0f / 480.0f); - EXPECT_FLOAT_EQ(g_gxState.proj.m1[3], -1.0f); - EXPECT_FLOAT_EQ(g_gxState.proj.m3[3], 1.0f); -} - -TEST_F(GXFifoTest, GetProjectionAndScissorShadowState) { - const f32 proj[] = {0.0f, 1.5f, 0.1f, 2.0f, 0.2f, -1.002f, -0.2002f}; - f32 outProj[7]{}; - u32 left = 0, top = 0, width = 0, height = 0; - - GXSetProjectionv(proj); - GXSetScissor(16, 24, 320, 240); - GXGetProjectionv(outProj); - GXGetScissor(&left, &top, &width, &height); - - for (size_t i = 0; i < 7; ++i) { - EXPECT_FLOAT_EQ(outProj[i], proj[i]); - } - EXPECT_EQ(left, 16u); - EXPECT_EQ(top, 24u); - EXPECT_EQ(width, 320u); - EXPECT_EQ(height, 240u); -} - -TEST_F(GXFifoTest, Scissor_EncodesBpAndDecodesLogicalState) { - GXSetScissor(16, 24, 320, 240); - auto bytes = capture_fifo(); - - EXPECT_TRUE(has_bp_write(bytes, 0x20)); - EXPECT_TRUE(has_bp_write(bytes, 0x21)); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.logicalScissor.x, 16); - EXPECT_EQ(g_gxState.logicalScissor.y, 24); - EXPECT_EQ(g_gxState.logicalScissor.width, 320); - EXPECT_EQ(g_gxState.logicalScissor.height, 240); -} - -TEST_F(GXFifoTest, ScissorBoxOffset_EncodesBp59AndDecodesState) { - GXSetScissorBoxOffset(1024, 0); - auto bytes = capture_fifo(); - - EXPECT_TRUE(has_bp_write(bytes, 0x59)); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.scissorOffsetX, 1024); - EXPECT_EQ(g_gxState.scissorOffsetY, 0); -} - -TEST_F(GXFifoTest, GetViewportShadowState) { - f32 vp[6]{}; - - GXSetViewport(10.0f, 20.0f, 640.0f, 480.0f, 0.1f, 1.0f); - GXGetViewportv(vp); - EXPECT_FLOAT_EQ(vp[0], 10.0f); - EXPECT_FLOAT_EQ(vp[1], 20.0f); - EXPECT_FLOAT_EQ(vp[2], 640.0f); - EXPECT_FLOAT_EQ(vp[3], 480.0f); - EXPECT_FLOAT_EQ(vp[4], 0.1f); - EXPECT_FLOAT_EQ(vp[5], 1.0f); - - GXSetViewportJitter(30.0f, 40.0f, 320.0f, 240.0f, 0.2f, 0.9f, 0); - GXGetViewportv(vp); - EXPECT_FLOAT_EQ(vp[0], 30.0f); - EXPECT_FLOAT_EQ(vp[1], 39.5f); - EXPECT_FLOAT_EQ(vp[2], 320.0f); - EXPECT_FLOAT_EQ(vp[3], 240.0f); - EXPECT_FLOAT_EQ(vp[4], 0.2f); - EXPECT_FLOAT_EQ(vp[5], 0.9f); -} - -TEST_F(GXFifoTest, Viewport_DecodesLogicalViewportState) { - GXSetViewport(10.0f, 20.0f, 640.0f, 480.0f, 0.1f, 1.0f); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_FLOAT_EQ(g_gxState.logicalViewport.left, 10.0f); - EXPECT_FLOAT_EQ(g_gxState.logicalViewport.top, 20.0f); - EXPECT_FLOAT_EQ(g_gxState.logicalViewport.width, 640.0f); - EXPECT_FLOAT_EQ(g_gxState.logicalViewport.height, 480.0f); - EXPECT_FLOAT_EQ(g_gxState.renderViewport.left, 10.0f); - EXPECT_FLOAT_EQ(g_gxState.renderViewport.top, 20.0f); - EXPECT_FLOAT_EQ(g_gxState.renderViewport.width, 640.0f); - EXPECT_FLOAT_EQ(g_gxState.renderViewport.height, 480.0f); -} - -TEST_F(GXFifoTest, ViewportRender_EncodesAuroraOverride) { - GXSetViewportRender(100.0f, 50.0f, 1280.0f, 720.0f, 0.0f, 1.0f); - auto bytes = capture_fifo(); - - EXPECT_TRUE(has_aurora_cmd(bytes, GX_LOAD_AURORA_VIEWPORT_RENDER)); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_FLOAT_EQ(g_gxState.renderViewport.left, 100.0f); - EXPECT_FLOAT_EQ(g_gxState.renderViewport.top, 50.0f); - EXPECT_FLOAT_EQ(g_gxState.renderViewport.width, 1280.0f); - EXPECT_FLOAT_EQ(g_gxState.renderViewport.height, 720.0f); -} - -TEST_F(GXFifoTest, ScissorRender_EncodesAuroraOverride) { - GXSetScissorRender(100, 40, 800, 600); - auto bytes = capture_fifo(); - - EXPECT_TRUE(has_aurora_cmd(bytes, GX_LOAD_AURORA_SCISSOR_RENDER)); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.renderScissor.x, 100); - EXPECT_EQ(g_gxState.renderScissor.y, 40); - EXPECT_EQ(g_gxState.renderScissor.width, 800); - EXPECT_EQ(g_gxState.renderScissor.height, 600); -} - -// --- GXLoadLightObjImm (XF 0x600-0x67F) --- - -TEST_F(GXFifoTest, LoadLightObjImm_Light0_BasicColor) { - GXLightObj lightObj; - GXInitLightPos(&lightObj, 100.0f, 200.0f, 300.0f); - GXInitLightDir(&lightObj, 0.0f, -1.0f, 0.0f); - GXInitLightColor(&lightObj, {255, 128, 64, 255}); - GXInitLightAttn(&lightObj, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f); - - GXLoadLightObjImm(&lightObj, GX_LIGHT0); - auto bytes = capture_fifo(); - - // XF bulk write: opcode 0x10 - ASSERT_GE(bytes.size(), 5u); - EXPECT_EQ(bytes[0], 0x10); - - reset_gx_state(); - g_gxState.preparedLightsDirty = false; - decode_fifo(bytes); - EXPECT_TRUE(g_gxState.preparedLightsDirty); - - auto& light = g_gxState.lights[0]; - // Color - EXPECT_NEAR(light.color[0], 255.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(light.color[1], 128.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(light.color[2], 64.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(light.color[3], 255.f / 255.f, 1.f / 255.f); - // Position - EXPECT_FLOAT_EQ(light.pos[0], 100.0f); - EXPECT_FLOAT_EQ(light.pos[1], 200.0f); - EXPECT_FLOAT_EQ(light.pos[2], 300.0f); - // Direction (GXInitLightDir negates) - EXPECT_FLOAT_EQ(light.dir[0], 0.0f); - EXPECT_FLOAT_EQ(light.dir[1], 1.0f); - EXPECT_FLOAT_EQ(light.dir[2], 0.0f); - // Cosine attenuation - EXPECT_FLOAT_EQ(light.cosAtt[0], 1.0f); - EXPECT_FLOAT_EQ(light.cosAtt[1], 0.0f); - EXPECT_FLOAT_EQ(light.cosAtt[2], 0.0f); - // Distance attenuation - EXPECT_FLOAT_EQ(light.distAtt[0], 1.0f); - EXPECT_FLOAT_EQ(light.distAtt[1], 0.0f); - EXPECT_FLOAT_EQ(light.distAtt[2], 0.0f); -} - -TEST_F(GXFifoTest, LoadLightObjImm_Light3_Attenuation) { - GXLightObj lightObj; - GXInitLightPos(&lightObj, -50.0f, 0.0f, 75.0f); - GXInitLightDir(&lightObj, 1.0f, 0.0f, 0.0f); - GXInitLightColor(&lightObj, {0, 255, 0, 128}); - GXInitLightAttn(&lightObj, 0.5f, 0.3f, 0.2f, 1.0f, 0.01f, 0.001f); - - GXLoadLightObjImm(&lightObj, GX_LIGHT3); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& light = g_gxState.lights[3]; - EXPECT_NEAR(light.color[0], 0.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(light.color[1], 255.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(light.color[2], 0.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(light.color[3], 128.f / 255.f, 1.f / 255.f); - EXPECT_FLOAT_EQ(light.pos[0], -50.0f); - EXPECT_FLOAT_EQ(light.pos[1], 0.0f); - EXPECT_FLOAT_EQ(light.pos[2], 75.0f); - EXPECT_FLOAT_EQ(light.dir[0], -1.0f); - EXPECT_FLOAT_EQ(light.dir[1], 0.0f); - EXPECT_FLOAT_EQ(light.dir[2], 0.0f); - EXPECT_FLOAT_EQ(light.cosAtt[0], 0.5f); - EXPECT_FLOAT_EQ(light.cosAtt[1], 0.3f); - EXPECT_FLOAT_EQ(light.cosAtt[2], 0.2f); - EXPECT_FLOAT_EQ(light.distAtt[0], 1.0f); - EXPECT_FLOAT_EQ(light.distAtt[1], 0.01f); - EXPECT_FLOAT_EQ(light.distAtt[2], 0.001f); -} - -TEST_F(GXFifoTest, LoadLightObjImm_Light7_LastLight) { - GXLightObj lightObj; - GXInitLightPos(&lightObj, 0.0f, 1000.0f, 0.0f); - GXInitLightDir(&lightObj, 0.0f, 0.0f, -1.0f); - GXInitLightColor(&lightObj, {128, 128, 128, 255}); - GXInitLightAttn(&lightObj, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f); - - GXLoadLightObjImm(&lightObj, GX_LIGHT7); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& light = g_gxState.lights[7]; - EXPECT_NEAR(light.color[0], 128.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(light.color[1], 128.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(light.color[2], 128.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(light.color[3], 255.f / 255.f, 1.f / 255.f); - EXPECT_FLOAT_EQ(light.pos[0], 0.0f); - EXPECT_FLOAT_EQ(light.pos[1], 1000.0f); - EXPECT_FLOAT_EQ(light.pos[2], 0.0f); - EXPECT_FLOAT_EQ(light.dir[0], 0.0f); - EXPECT_FLOAT_EQ(light.dir[1], 0.0f); - EXPECT_FLOAT_EQ(light.dir[2], 1.0f); -} - -TEST_F(GXFifoTest, LoadLightObjImm_SpotLight) { - GXLightObj lightObj; - GXInitLightPos(&lightObj, 10.0f, 20.0f, 30.0f); - GXInitLightDir(&lightObj, 0.0f, -1.0f, 0.0f); - GXInitLightSpot(&lightObj, 45.0f, GX_SP_COS); - GXInitLightDistAttn(&lightObj, 100.0f, 0.5f, GX_DA_MEDIUM); - GXInitLightColor(&lightObj, {255, 255, 255, 255}); - - GXLoadLightObjImm(&lightObj, GX_LIGHT1); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& light = g_gxState.lights[1]; - EXPECT_NEAR(light.color[0], 1.0f, 1.f / 255.f); - EXPECT_NEAR(light.color[1], 1.0f, 1.f / 255.f); - EXPECT_NEAR(light.color[2], 1.0f, 1.f / 255.f); - EXPECT_FLOAT_EQ(light.pos[0], 10.0f); - EXPECT_FLOAT_EQ(light.pos[1], 20.0f); - EXPECT_FLOAT_EQ(light.pos[2], 30.0f); - // GX_SP_COS with cutoff=45: cr = cos(45 * pi / 180) - // a0 = -cr/(1-cr), a1 = 1/(1-cr), a2 = 0 - float cr = std::cos(45.0f * M_PIF / 180.0f); - EXPECT_FLOAT_EQ(light.cosAtt[0], -cr / (1.0f - cr)); - EXPECT_FLOAT_EQ(light.cosAtt[1], 1.0f / (1.0f - cr)); - EXPECT_FLOAT_EQ(light.cosAtt[2], 0.0f); - // GX_DA_MEDIUM with refDist=100, refBright=0.5: - // k0 = 1, k1 = 0.5*(1-b)/(b*d), k2 = 0.5*(1-b)/(b*d*d) - EXPECT_FLOAT_EQ(light.distAtt[0], 1.0f); - EXPECT_FLOAT_EQ(light.distAtt[1], 0.5f * 0.5f / (0.5f * 100.0f)); - EXPECT_FLOAT_EQ(light.distAtt[2], 0.5f * 0.5f / (0.5f * 100.0f * 100.0f)); -} - -// --- GXSetChanCtrl (XF 0x100E-0x1011) --- - -TEST_F(GXFifoTest, ChanCtrl_Color0_LightingEnabled) { - GXSetChanCtrl(GX_COLOR0, true, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT0 | GX_LIGHT1, GX_DF_CLAMP, GX_AF_SPOT); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& cfg = g_gxState.colorChannelConfig[GX_COLOR0]; - EXPECT_TRUE(cfg.lightingEnabled); - EXPECT_EQ(cfg.matSrc, GX_SRC_VTX); - EXPECT_EQ(cfg.ambSrc, GX_SRC_REG); - EXPECT_EQ(cfg.diffFn, GX_DF_CLAMP); - EXPECT_EQ(cfg.attnFn, GX_AF_SPOT); - - // Light mask should be 0x03 (lights 0 and 1) - auto& state = g_gxState.colorChannelState[GX_COLOR0]; - EXPECT_TRUE(state.lightMask[0]); - EXPECT_TRUE(state.lightMask[1]); - EXPECT_FALSE(state.lightMask[2]); -} - -TEST_F(GXFifoTest, ChanCtrl_Alpha0_NoLighting) { - GXSetChanCtrl(GX_ALPHA0, false, GX_SRC_VTX, GX_SRC_REG, 0, GX_DF_NONE, GX_AF_NONE); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& cfg = g_gxState.colorChannelConfig[GX_ALPHA0]; - EXPECT_FALSE(cfg.lightingEnabled); - EXPECT_EQ(cfg.matSrc, GX_SRC_REG); - EXPECT_EQ(cfg.ambSrc, GX_SRC_VTX); - EXPECT_EQ(cfg.attnFn, GX_AF_NONE); -} - -TEST_F(GXFifoTest, ChanCtrl_Color1_SpecularLighting) { - GXSetChanCtrl(GX_COLOR1, true, GX_SRC_REG, GX_SRC_REG, GX_LIGHT2 | GX_LIGHT5, GX_DF_SIGN, GX_AF_SPEC); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& cfg = g_gxState.colorChannelConfig[GX_COLOR1]; - EXPECT_TRUE(cfg.lightingEnabled); - EXPECT_EQ(cfg.matSrc, GX_SRC_REG); - EXPECT_EQ(cfg.ambSrc, GX_SRC_REG); - EXPECT_EQ(cfg.diffFn, GX_DF_NONE); - EXPECT_EQ(cfg.attnFn, GX_AF_SPEC); - - auto& state = g_gxState.colorChannelState[GX_COLOR1]; - EXPECT_FALSE(state.lightMask[0]); - EXPECT_FALSE(state.lightMask[1]); - EXPECT_TRUE(state.lightMask[2]); - EXPECT_FALSE(state.lightMask[3]); - EXPECT_FALSE(state.lightMask[4]); - EXPECT_TRUE(state.lightMask[5]); -} - -TEST_F(GXFifoTest, ChanCtrl_EncodesHardwareAttenuationField) { - GXSetChanCtrl(GX_COLOR0, true, GX_SRC_REG, GX_SRC_REG, GX_LIGHT0, GX_DF_SIGN, GX_AF_SPEC); - auto specBytes = capture_fifo(); - ASSERT_GE(specBytes.size(), 9u); - EXPECT_EQ((read_be32_at(specBytes, 5) >> 7) & 0x3u, static_cast(GX_DF_NONE)); - EXPECT_EQ((read_be32_at(specBytes, 5) >> 9) & 0x3u, 1u); - - GXSetChanCtrl(GX_COLOR0, true, GX_SRC_REG, GX_SRC_REG, GX_LIGHT0, GX_DF_CLAMP, GX_AF_SPOT); - auto spotBytes = capture_fifo(); - ASSERT_GE(spotBytes.size(), 9u); - EXPECT_EQ((read_be32_at(spotBytes, 5) >> 9) & 0x3u, 3u); - - GXSetChanCtrl(GX_COLOR0, true, GX_SRC_REG, GX_SRC_REG, GX_LIGHT0, GX_DF_NONE, GX_AF_NONE); - auto noneBytes = capture_fifo(); - ASSERT_GE(noneBytes.size(), 9u); - EXPECT_EQ((read_be32_at(noneBytes, 5) >> 9) & 0x3u, 2u); -} - -TEST_F(GXFifoTest, ChanCtrl_DecodesRawHardwareAttenuationField) { - reset_gx_state(); - decode_fifo(xf_cmd(0x100E, {1u << 9})); - EXPECT_EQ(g_gxState.colorChannelConfig[GX_COLOR0].attnFn, GX_AF_SPEC); - - reset_gx_state(); - decode_fifo(xf_cmd(0x100E, {2u << 9})); - EXPECT_EQ(g_gxState.colorChannelConfig[GX_COLOR0].attnFn, GX_AF_NONE); - - reset_gx_state(); - decode_fifo(xf_cmd(0x100E, {3u << 9})); - EXPECT_EQ(g_gxState.colorChannelConfig[GX_COLOR0].attnFn, GX_AF_SPOT); - - reset_gx_state(); - decode_fifo(xf_cmd(0x100E, {0u << 9})); - EXPECT_EQ(g_gxState.colorChannelConfig[GX_COLOR0].attnFn, GX_AF_NONE); -} - -TEST_F(GXFifoTest, ChanCtrl_Color0A0_Compound) { - // GX_COLOR0A0 should set both GX_COLOR0 and GX_ALPHA0 - GXSetChanCtrl(GX_COLOR0A0, true, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT0, GX_DF_CLAMP, GX_AF_SPOT); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - // Both COLOR0 and ALPHA0 should be configured identically - auto& cfgC = g_gxState.colorChannelConfig[GX_COLOR0]; - EXPECT_TRUE(cfgC.lightingEnabled); - EXPECT_EQ(cfgC.matSrc, GX_SRC_VTX); - EXPECT_EQ(cfgC.ambSrc, GX_SRC_REG); - EXPECT_EQ(cfgC.diffFn, GX_DF_CLAMP); - EXPECT_EQ(cfgC.attnFn, GX_AF_SPOT); - - auto& cfgA = g_gxState.colorChannelConfig[GX_ALPHA0]; - EXPECT_TRUE(cfgA.lightingEnabled); - EXPECT_EQ(cfgA.matSrc, GX_SRC_VTX); - EXPECT_EQ(cfgA.ambSrc, GX_SRC_REG); - EXPECT_EQ(cfgA.attnFn, GX_AF_SPOT); - - EXPECT_TRUE(g_gxState.colorChannelState[GX_COLOR0].lightMask[0]); - EXPECT_TRUE(g_gxState.colorChannelState[GX_ALPHA0].lightMask[0]); -} - -TEST_F(GXFifoTest, ChanCtrl_Color1A1_Compound) { - GXSetChanCtrl(GX_COLOR1A1, false, GX_SRC_VTX, GX_SRC_VTX, 0, GX_DF_NONE, GX_AF_NONE); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& cfgC = g_gxState.colorChannelConfig[GX_COLOR1]; - EXPECT_FALSE(cfgC.lightingEnabled); - EXPECT_EQ(cfgC.ambSrc, GX_SRC_VTX); - EXPECT_EQ(cfgC.matSrc, GX_SRC_VTX); - - auto& cfgA = g_gxState.colorChannelConfig[GX_ALPHA1]; - EXPECT_FALSE(cfgA.lightingEnabled); - EXPECT_EQ(cfgA.ambSrc, GX_SRC_VTX); - EXPECT_EQ(cfgA.matSrc, GX_SRC_VTX); -} - -// --- GXSetTexCoordGen2 (XF 0x1040-0x105F) --- - -TEST_F(GXFifoTest, TexCoordGen_Mtx2x4_Tex0) { - GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX0, GX_FALSE, GX_PTIDENTITY); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& tcg = g_gxState.tcgs[GX_TEXCOORD0]; - EXPECT_EQ(tcg.type, GX_TG_MTX2x4); - EXPECT_EQ(tcg.src, GX_TG_TEX0); - EXPECT_EQ(tcg.mtx, GX_TEXMTX0); - EXPECT_EQ(tcg.postMtx, GX_PTIDENTITY); -} - -TEST_F(GXFifoTest, TexCoordGen_Mtx3x4_Nrm) { - GXSetTexCoordGen2(GX_TEXCOORD1, GX_TG_MTX3x4, GX_TG_NRM, GX_TEXMTX0, GX_TRUE, GX_PTTEXMTX0); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& tcg = g_gxState.tcgs[GX_TEXCOORD1]; - EXPECT_EQ(tcg.type, GX_TG_MTX3x4); - EXPECT_EQ(tcg.src, GX_TG_NRM); - EXPECT_EQ(tcg.mtx, GX_TEXMTX0); - EXPECT_TRUE(tcg.normalize); - EXPECT_EQ(tcg.postMtx, GX_PTTEXMTX0); -} - -TEST_F(GXFifoTest, TexCoordGen_SRTG_Color0) { - GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_SRTG, GX_TG_COLOR0, GX_TEXMTX0, GX_FALSE, GX_PTIDENTITY); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& tcg = g_gxState.tcgs[GX_TEXCOORD0]; - EXPECT_EQ(tcg.type, GX_TG_SRTG); - EXPECT_EQ(tcg.mtx, GX_TEXMTX0); -} - -TEST_F(GXFifoTest, TexCoordGen_NonZeroMtx) { - GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX3x4, GX_TG_TEX0, GX_TEXMTX3, GX_FALSE, GX_PTTEXMTX5); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& tcg = g_gxState.tcgs[GX_TEXCOORD0]; - EXPECT_EQ(tcg.type, GX_TG_MTX3x4); - EXPECT_EQ(tcg.src, GX_TG_TEX0); - EXPECT_EQ(tcg.mtx, GX_TEXMTX3); - EXPECT_EQ(tcg.postMtx, GX_PTTEXMTX5); -} - -TEST_F(GXFifoTest, TexCoordGen_MultipleCoords) { - GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX3x4, GX_TG_TEX0, GX_TEXMTX0, GX_FALSE, GX_PTTEXMTX0); - GXSetTexCoordGen2(GX_TEXCOORD1, GX_TG_MTX3x4, GX_TG_TEX1, GX_TEXMTX1, GX_FALSE, GX_PTTEXMTX1); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.tcgs[0].mtx, GX_TEXMTX0); - EXPECT_EQ(g_gxState.tcgs[0].postMtx, GX_PTTEXMTX0); - EXPECT_EQ(g_gxState.tcgs[0].src, GX_TG_TEX0); - EXPECT_EQ(g_gxState.tcgs[1].mtx, GX_TEXMTX1); - EXPECT_EQ(g_gxState.tcgs[1].postMtx, GX_PTTEXMTX1); - EXPECT_EQ(g_gxState.tcgs[1].src, GX_TG_TEX1); -} - -TEST_F(GXFifoTest, TexCoordGen_HighCoord_MatIdxB) { - // TexCoord4+ uses matIdxB - GXSetTexCoordGen2(GX_TEXCOORD4, GX_TG_MTX2x4, GX_TG_TEX4, GX_TEXMTX5, GX_FALSE, GX_PTTEXMTX3); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& tcg = g_gxState.tcgs[GX_TEXCOORD4]; - EXPECT_EQ(tcg.type, GX_TG_MTX2x4); - EXPECT_EQ(tcg.src, GX_TG_TEX4); - EXPECT_EQ(tcg.mtx, GX_TEXMTX5); - EXPECT_EQ(tcg.postMtx, GX_PTTEXMTX3); -} - -TEST_F(GXFifoTest, TexCoordGen_Identity) { - GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY, GX_FALSE, GX_PTIDENTITY); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& tcg = g_gxState.tcgs[GX_TEXCOORD0]; - EXPECT_EQ(tcg.mtx, GX_IDENTITY); - EXPECT_EQ(tcg.postMtx, GX_PTIDENTITY); -} - -TEST_F(GXFifoTest, MatrixIndexA_DecodesTexMatricesFromCpPacket) { - const u32 value = (GX_PNMTX3 << 0) | (GX_TEXMTX3 << 6) | (GX_TEXMTX4 << 12) | (GX_IDENTITY << 18) | - (GX_TEXMTX7 << 24); - auto bytes = cp_cmd(0x30, value); - - reset_gx_state(); - g_gxState.tcgs[0].mtx = GX_IDENTITY; - g_gxState.tcgs[1].mtx = GX_IDENTITY; - g_gxState.tcgs[2].mtx = GX_TEXMTX0; - g_gxState.tcgs[3].mtx = GX_IDENTITY; - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.currentPnMtx, 3u); - EXPECT_EQ(g_gxState.tcgs[0].mtx, GX_TEXMTX3); - EXPECT_EQ(g_gxState.tcgs[1].mtx, GX_TEXMTX4); - EXPECT_EQ(g_gxState.tcgs[2].mtx, GX_IDENTITY); - EXPECT_EQ(g_gxState.tcgs[3].mtx, GX_TEXMTX7); -} - -TEST_F(GXFifoTest, MatrixIndexB_DecodesTexMatricesFromCpPacket) { - const u32 value = (GX_TEXMTX4 << 0) | (GX_TEXMTX5 << 6) | (GX_IDENTITY << 12) | (GX_TEXMTX9 << 18); - auto bytes = cp_cmd(0x40, value); - - reset_gx_state(); - g_gxState.tcgs[4].mtx = GX_IDENTITY; - g_gxState.tcgs[5].mtx = GX_IDENTITY; - g_gxState.tcgs[6].mtx = GX_TEXMTX0; - g_gxState.tcgs[7].mtx = GX_IDENTITY; - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.tcgs[4].mtx, GX_TEXMTX4); - EXPECT_EQ(g_gxState.tcgs[5].mtx, GX_TEXMTX5); - EXPECT_EQ(g_gxState.tcgs[6].mtx, GX_IDENTITY); - EXPECT_EQ(g_gxState.tcgs[7].mtx, GX_TEXMTX9); -} - -// --- GXSetChanAmbColor / GXSetChanMatColor (XF 0x100A-0x100D) --- - -TEST_F(GXFifoTest, ChanAmbColor_Color0) { - GXColor amb = {64, 128, 192, 255}; - GXSetChanAmbColor(GX_COLOR0, amb); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& state = g_gxState.colorChannelState[GX_COLOR0]; - EXPECT_NEAR(state.ambColor[0], 64.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(state.ambColor[1], 128.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(state.ambColor[2], 192.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(state.ambColor[3], 255.f / 255.f, 1.f / 255.f); -} - -TEST_F(GXFifoTest, ChanMatColor_Color0) { - GXColor mat = {255, 0, 128, 64}; - GXSetChanMatColor(GX_COLOR0, mat); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& state = g_gxState.colorChannelState[GX_COLOR0]; - EXPECT_NEAR(state.matColor[0], 255.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(state.matColor[1], 0.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(state.matColor[2], 128.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(state.matColor[3], 64.f / 255.f, 1.f / 255.f); -} - -TEST_F(GXFifoTest, ChanAmbColor_Color1) { - GXColor amb = {10, 20, 30, 40}; - GXSetChanAmbColor(GX_COLOR1, amb); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& state = g_gxState.colorChannelState[GX_COLOR1]; - EXPECT_NEAR(state.ambColor[0], 10.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(state.ambColor[1], 20.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(state.ambColor[2], 30.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(state.ambColor[3], 40.f / 255.f, 1.f / 255.f); -} - -TEST_F(GXFifoTest, ChanMatColor_Color1) { - GXColor mat = {100, 150, 200, 250}; - GXSetChanMatColor(GX_COLOR1, mat); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& state = g_gxState.colorChannelState[GX_COLOR1]; - EXPECT_NEAR(state.matColor[0], 100.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(state.matColor[1], 150.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(state.matColor[2], 200.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(state.matColor[3], 250.f / 255.f, 1.f / 255.f); -} - -TEST_F(GXFifoTest, ChanAmbColor_Color0A0_Compound) { - // GX_COLOR0A0 should write to both COLOR0 and ALPHA0 XF registers - GXColor amb = {80, 160, 240, 128}; - GXSetChanAmbColor(GX_COLOR0A0, amb); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& stateC = g_gxState.colorChannelState[GX_COLOR0]; - EXPECT_NEAR(stateC.ambColor[0], 80.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(stateC.ambColor[1], 160.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(stateC.ambColor[2], 240.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(stateC.ambColor[3], 128.f / 255.f, 1.f / 255.f); - // ALPHA0 shares the same XF register as COLOR0, so should match - auto& stateA = g_gxState.colorChannelState[GX_ALPHA0]; - EXPECT_NEAR(stateA.ambColor[0], 80.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(stateA.ambColor[3], 128.f / 255.f, 1.f / 255.f); -} - -TEST_F(GXFifoTest, ChanMatColor_Color1A1_Compound) { - GXColor mat = {32, 64, 96, 128}; - GXSetChanMatColor(GX_COLOR1A1, mat); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& stateC = g_gxState.colorChannelState[GX_COLOR1]; - EXPECT_NEAR(stateC.matColor[0], 32.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(stateC.matColor[1], 64.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(stateC.matColor[2], 96.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(stateC.matColor[3], 128.f / 255.f, 1.f / 255.f); - - auto& stateA = g_gxState.colorChannelState[GX_ALPHA1]; - EXPECT_NEAR(stateA.matColor[0], 32.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(stateA.matColor[3], 128.f / 255.f, 1.f / 255.f); -} - -// GXSetFog (BP 0xEE-0xF2): fog A/B/C parameters, type and color - -// --- Fog with perspective linear fog, typical parameters --- -TEST_F(GXFifoTest, Fog_PerspLin_Typical) { - GXColor fogColor = {128, 200, 255, 255}; - GXSetFog(GX_FOG_PERSP_LIN, 100.f, 900.f, 0.1f, 1000.f, fogColor); - auto bytes = capture_fifo(); - - // Should produce 5 BP writes (0xEE-0xF2): 5 * 5 = 25 bytes - ASSERT_EQ(bytes.size(), 25u); - // Verify BP opcodes and register IDs - EXPECT_EQ(bytes[0], 0x61); - EXPECT_EQ(bytes[1], 0xEE); - EXPECT_EQ(bytes[5], 0x61); - EXPECT_EQ(bytes[6], 0xEF); - EXPECT_EQ(bytes[10], 0x61); - EXPECT_EQ(bytes[11], 0xF0); - EXPECT_EQ(bytes[15], 0x61); - EXPECT_EQ(bytes[16], 0xF1); - EXPECT_EQ(bytes[20], 0x61); - EXPECT_EQ(bytes[21], 0xF2); - - reset_gx_state(); - decode_fifo(bytes); - - // Compute expected A, B, C from the SDK formula - float nearZ = 0.1f, farZ = 1000.f, startZ = 100.f, endZ = 900.f; - float A = (farZ * nearZ) / ((farZ - nearZ) * (endZ - startZ)); - float B = farZ / (farZ - nearZ); - float C = startZ / (endZ - startZ); - - // Allow tolerance for encoding precision loss (11-bit mantissa) - EXPECT_NEAR(g_gxState.fog.a, A, std::abs(A) * 1e-3f); - EXPECT_NEAR(g_gxState.fog.b, B, std::abs(B) * 1e-3f); - EXPECT_NEAR(g_gxState.fog.c, C, std::abs(C) * 1e-3f); - expect_fog_raw_fields_match_decoded_state(); - EXPECT_EQ(g_gxState.fog.type, GX_FOG_PERSP_LIN); - EXPECT_NEAR(g_gxState.fog.color[0], 128.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.fog.color[1], 200.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.fog.color[2], 255.f / 255.f, 1.f / 255.f); -} - -// --- Orthographic fog keeps the projection bit and uses the SDK ortho coefficients --- -TEST_F(GXFifoTest, Fog_OrthoLin_Typical) { - GXColor fogColor = {128, 200, 255, 255}; - GXSetFog(GX_FOG_ORTHO_LIN, 100.f, 900.f, 0.1f, 1000.f, fogColor); - auto bytes = capture_fifo(); - - ASSERT_EQ(bytes.size(), 25u); - const u32 fog3 = (static_cast(bytes[16]) << 24) | (static_cast(bytes[17]) << 16) | - (static_cast(bytes[18]) << 8) | static_cast(bytes[19]); - EXPECT_EQ((fog3 >> 20) & 1u, 1u); - EXPECT_EQ((fog3 >> 21) & 7u, static_cast(GX_FOG_LIN)); - - reset_gx_state(); - decode_fifo(bytes); - - float nearZ = 0.1f, farZ = 1000.f, startZ = 100.f, endZ = 900.f; - float A = (farZ - nearZ) / (endZ - startZ); - float C = (startZ - nearZ) / (endZ - startZ); - - EXPECT_NEAR(g_gxState.fog.a, A, std::abs(A) * 1e-3f); - EXPECT_FLOAT_EQ(g_gxState.fog.b, 0.f); - EXPECT_NEAR(g_gxState.fog.c, C, std::abs(C) * 1e-3f); - expect_fog_raw_fields_match_decoded_state(); - EXPECT_EQ(g_gxState.fog.type, GX_FOG_ORTHO_LIN); -} - -// --- Fog with degenerate parameters (nearZ == farZ) --- -TEST_F(GXFifoTest, Fog_Degenerate_EqualDepths) { - GXColor fogColor = {0, 0, 0, 255}; - GXSetFog(GX_FOG_PERSP_EXP, 0.f, 100.f, 10.f, 10.f, fogColor); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - // When nearZ == farZ, SDK sets A=0, B=0.5, C=0 - EXPECT_FLOAT_EQ(g_gxState.fog.a, 0.f); - EXPECT_NEAR(g_gxState.fog.b, 0.5f, 1e-3f); - EXPECT_FLOAT_EQ(g_gxState.fog.c, 0.f); - expect_fog_raw_fields_match_decoded_state(); - EXPECT_EQ(g_gxState.fog.type, GX_FOG_PERSP_EXP); -} - -// --- Fog type: none --- -TEST_F(GXFifoTest, Fog_None) { - GXColor fogColor = {64, 64, 64, 255}; - GXSetFog(GX_FOG_NONE, 0.f, 0.f, 0.f, 0.f, fogColor); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.fog.type, GX_FOG_NONE); - EXPECT_FLOAT_EQ(g_gxState.fog.a, 0.f); - EXPECT_NEAR(g_gxState.fog.b, 0.5f, 1e-3f); - EXPECT_FLOAT_EQ(g_gxState.fog.c, 0.f); - expect_fog_raw_fields_match_decoded_state(); - EXPECT_NEAR(g_gxState.fog.color[0], 64.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.fog.color[1], 64.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.fog.color[2], 64.f / 255.f, 1.f / 255.f); -} - -// --- Fog with perspective reverse exponential squared type --- -TEST_F(GXFifoTest, Fog_PerspRevExp2) { - GXColor fogColor = {255, 0, 0, 255}; - GXSetFog(GX_FOG_PERSP_REVEXP2, 50.f, 500.f, 1.f, 1000.f, fogColor); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - float nearZ = 1.f, farZ = 1000.f, startZ = 50.f, endZ = 500.f; - float A = (farZ * nearZ) / ((farZ - nearZ) * (endZ - startZ)); - float B = farZ / (farZ - nearZ); - float C = startZ / (endZ - startZ); - - EXPECT_NEAR(g_gxState.fog.a, A, std::abs(A) * 1e-3f); - EXPECT_NEAR(g_gxState.fog.b, B, std::abs(B) * 1e-3f); - EXPECT_NEAR(g_gxState.fog.c, C, std::abs(C) * 1e-3f); - expect_fog_raw_fields_match_decoded_state(); - EXPECT_EQ(g_gxState.fog.type, GX_FOG_PERSP_REVEXP2); - EXPECT_NEAR(g_gxState.fog.color[0], 1.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.fog.color[1], 0.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.fog.color[2], 0.f, 1.f / 255.f); -} - -// GXSetIndTexMtx (BP 0x06-0x0E): indirect texture matrix parameters - -// --- IndTexMtx 0 with half-scale diagonal matrix --- -// Note: 11-bit signed range limits values to [-1.0, 0.999], so 1.0 is not representable. -TEST_F(GXFifoTest, IndTexMtx0_HalfScale) { - f32 mtx[2][3] = { - {0.5f, 0.0f, 0.0f}, - {0.0f, 0.5f, 0.0f}, - }; - GXSetIndTexMtx(GX_ITM_0, mtx, 0); - auto bytes = capture_fifo(); - - // Should produce 3 BP writes: 3 * 5 = 15 bytes - ASSERT_EQ(bytes.size(), 15u); - // Verify BP opcodes and register IDs (0x06, 0x07, 0x08 for matrix 0) - EXPECT_EQ(bytes[0], 0x61); - EXPECT_EQ(bytes[1], 0x06); - EXPECT_EQ(bytes[5], 0x61); - EXPECT_EQ(bytes[6], 0x07); - EXPECT_EQ(bytes[10], 0x61); - EXPECT_EQ(bytes[11], 0x08); - - reset_gx_state(); - decode_fifo(bytes); - - const auto& info = g_gxState.indTexMtxs[0]; - // 11-bit fixed-point (1/1024) precision - float tol = 1.0f / 1024.0f; - EXPECT_NEAR(info.mtx.m0.x, 0.5f, tol); - EXPECT_NEAR(info.mtx.m0.y, 0.0f, tol); - EXPECT_NEAR(info.mtx.m1.x, 0.0f, tol); - EXPECT_NEAR(info.mtx.m1.y, 0.5f, tol); - EXPECT_NEAR(info.mtx.m2.x, 0.0f, tol); - EXPECT_NEAR(info.mtx.m2.y, 0.0f, tol); - EXPECT_EQ(info.scaleExp, 0); -} - -// --- IndTexMtx 1 with fractional values and positive scale --- -TEST_F(GXFifoTest, IndTexMtx1_FractionalWithScale) { - f32 mtx[2][3] = { - {0.5f, 0.25f, -0.125f}, - {-0.5f, 0.75f, 0.0f}, - }; - GXSetIndTexMtx(GX_ITM_1, mtx, 3); - auto bytes = capture_fifo(); - - // Register IDs for matrix 1: 0x09, 0x0A, 0x0B - ASSERT_EQ(bytes.size(), 15u); - EXPECT_EQ(bytes[1], 0x09); - EXPECT_EQ(bytes[6], 0x0A); - EXPECT_EQ(bytes[11], 0x0B); - - reset_gx_state(); - decode_fifo(bytes); - - const auto& info = g_gxState.indTexMtxs[1]; - float tol = 1.0f / 1024.0f; - EXPECT_NEAR(info.mtx.m0.x, 0.5f, tol); - EXPECT_NEAR(info.mtx.m0.y, -0.5f, tol); - EXPECT_NEAR(info.mtx.m1.x, 0.25f, tol); - EXPECT_NEAR(info.mtx.m1.y, 0.75f, tol); - EXPECT_NEAR(info.mtx.m2.x, -0.125f, tol); - EXPECT_NEAR(info.mtx.m2.y, 0.0f, tol); - EXPECT_EQ(info.scaleExp, 3); -} - -// --- IndTexMtx 2 with negative scale exponent --- -TEST_F(GXFifoTest, IndTexMtx2_NegativeScale) { - f32 mtx[2][3] = { - {0.0f, 0.0f, 0.0f}, - {0.0f, 0.0f, 0.0f}, - }; - GXSetIndTexMtx(GX_ITM_2, mtx, -5); - auto bytes = capture_fifo(); - - // Register IDs for matrix 2: 0x0C, 0x0D, 0x0E - ASSERT_EQ(bytes.size(), 15u); - EXPECT_EQ(bytes[1], 0x0C); - EXPECT_EQ(bytes[6], 0x0D); - EXPECT_EQ(bytes[11], 0x0E); - - reset_gx_state(); - decode_fifo(bytes); - - const auto& info = g_gxState.indTexMtxs[2]; - EXPECT_EQ(info.scaleExp, -5); -} - -TEST_F(GXFifoTest, IndTexMtxScaleMultiplier_MatchesHardwareExponent) { - EXPECT_FLOAT_EQ(aurora::gx::indirect_matrix_scale_multiplier(0), 1.0f); - EXPECT_FLOAT_EQ(aurora::gx::indirect_matrix_scale_multiplier(3), 8.0f); - EXPECT_FLOAT_EQ(aurora::gx::indirect_matrix_scale_multiplier(-5), 0.03125f); -} - -TEST_F(GXFifoTest, IndTexMtxDynamicAliases_MapToSameSlotsAsSdk) { - f32 mtxS[2][3] = { - {0.25f, 0.0f, 0.0f}, - {0.0f, 0.25f, 0.0f}, - }; - f32 mtxT[2][3] = { - {0.5f, 0.0f, 0.0f}, - {0.0f, 0.5f, 0.0f}, - }; - - GXSetIndTexMtx(GX_ITM_S1, mtxS, 2); - GXSetIndTexMtx(GX_ITM_T2, mtxT, -3); - auto bytes = capture_fifo(); - - ASSERT_EQ(bytes.size(), 30u); - EXPECT_EQ(bytes[1], 0x09); - EXPECT_EQ(bytes[6], 0x0A); - EXPECT_EQ(bytes[11], 0x0B); - EXPECT_EQ(bytes[16], 0x0C); - EXPECT_EQ(bytes[21], 0x0D); - EXPECT_EQ(bytes[26], 0x0E); - - reset_gx_state(); - decode_fifo(bytes); - - constexpr float tol = 1.0f / 1024.0f; - EXPECT_NEAR(g_gxState.indTexMtxs[1].mtx.m0.x, 0.25f, tol); - EXPECT_NEAR(g_gxState.indTexMtxs[1].mtx.m1.y, 0.25f, tol); - EXPECT_EQ(g_gxState.indTexMtxs[1].scaleExp, 2); - EXPECT_NEAR(g_gxState.indTexMtxs[2].mtx.m0.x, 0.5f, tol); - EXPECT_NEAR(g_gxState.indTexMtxs[2].mtx.m1.y, 0.5f, tol); - EXPECT_EQ(g_gxState.indTexMtxs[2].scaleExp, -3); -} - -// --- IndTexMtx 0 does not affect matrix 1 --- -TEST_F(GXFifoTest, IndTexMtx0_Isolation) { - f32 mtx0[2][3] = { - {0.5f, 0.0f, 0.0f}, - {0.0f, 0.5f, 0.0f}, - }; - f32 mtx1[2][3] = { - {-1.0f, 0.0f, 0.0f}, - {0.0f, -1.0f, 0.0f}, - }; - GXSetIndTexMtx(GX_ITM_0, mtx0, 1); - GXSetIndTexMtx(GX_ITM_1, mtx1, -2); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - float tol = 1.0f / 1024.0f; - // Matrix 0 - EXPECT_NEAR(g_gxState.indTexMtxs[0].mtx.m0.x, 0.5f, tol); - EXPECT_NEAR(g_gxState.indTexMtxs[0].mtx.m1.y, 0.5f, tol); - EXPECT_EQ(g_gxState.indTexMtxs[0].scaleExp, 1); - // Matrix 1 - EXPECT_NEAR(g_gxState.indTexMtxs[1].mtx.m0.x, -1.0f, tol); - EXPECT_NEAR(g_gxState.indTexMtxs[1].mtx.m1.y, -1.0f, tol); - EXPECT_EQ(g_gxState.indTexMtxs[1].scaleExp, -2); -} - -// SU texture coordinate scale (BP 0x30-0x3F) - -// --- GXSetTexCoordScaleManually sets width/height --- -TEST_F(GXFifoTest, TexCoordScale_Manual_Coord0) { - GXSetTexCoordScaleManually(GX_TEXCOORD0, GX_TRUE, 256, 128); - auto bytes = capture_fifo(); - - // Two BP writes (suTs0 + suTs1): 2 * 5 = 10 bytes - ASSERT_EQ(bytes.size(), 10u); - EXPECT_EQ(bytes[0], 0x61); - EXPECT_EQ(bytes[1], 0x30); // suTs0[0] - EXPECT_EQ(bytes[5], 0x61); - EXPECT_EQ(bytes[6], 0x31); // suTs1[0] - - reset_gx_state(); - decode_fifo(bytes); - - const auto& tcs = g_gxState.texCoordScales[0]; - EXPECT_EQ(tcs.scaleS, 255u); // width - 1 - EXPECT_EQ(tcs.scaleT, 127u); // height - 1 -} - -// --- GXSetTexCoordScaleManually for coord 3 --- -TEST_F(GXFifoTest, TexCoordScale_Manual_Coord3) { - GXSetTexCoordScaleManually(GX_TEXCOORD3, GX_TRUE, 512, 512); - auto bytes = capture_fifo(); - - ASSERT_EQ(bytes.size(), 10u); - EXPECT_EQ(bytes[1], 0x36); // suTs0[3] = 0x30 + 3*2 - EXPECT_EQ(bytes[6], 0x37); // suTs1[3] = 0x31 + 3*2 - - reset_gx_state(); - decode_fifo(bytes); - - const auto& tcs = g_gxState.texCoordScales[3]; - EXPECT_EQ(tcs.scaleS, 511u); - EXPECT_EQ(tcs.scaleT, 511u); -} - -// --- GXSetTexCoordScaleManually with bias and cyl wrap --- -TEST_F(GXFifoTest, TexCoordScale_BiasAndCylWrap) { - // Enable manual mode first, then set bias and cyl wrap - GXSetTexCoordScaleManually(GX_TEXCOORD0, GX_TRUE, 64, 64); - capture_fifo(); // discard - - GXSetTexCoordBias(GX_TEXCOORD0, GX_TRUE, GX_FALSE); - auto biasBytes = capture_fifo(); - - GXSetTexCoordCylWrap(GX_TEXCOORD0, GX_FALSE, GX_TRUE); - auto cylBytes = capture_fifo(); - - // Each writes 2 BP regs - ASSERT_EQ(biasBytes.size(), 10u); - ASSERT_EQ(cylBytes.size(), 10u); - - reset_gx_state(); - decode_fifo(biasBytes); - decode_fifo(cylBytes); - - const auto& tcs = g_gxState.texCoordScales[0]; - EXPECT_TRUE(tcs.biasS); - EXPECT_FALSE(tcs.biasT); - EXPECT_FALSE(tcs.cylWrapS); - EXPECT_TRUE(tcs.cylWrapT); -} - -// --- GXEnableTexOffsets --- -TEST_F(GXFifoTest, TexCoordScale_TexOffsets) { - GXEnableTexOffsets(GX_TEXCOORD2, GX_TRUE, GX_TRUE); - auto bytes = capture_fifo(); - - // One BP write (suTs0 only): 5 bytes - ASSERT_EQ(bytes.size(), 5u); - EXPECT_EQ(bytes[1], 0x34); // suTs0[2] = 0x30 + 2*2 - - reset_gx_state(); - decode_fifo(bytes); - - const auto& tcs = g_gxState.texCoordScales[2]; - EXPECT_TRUE(tcs.lineOffset); - EXPECT_TRUE(tcs.pointOffset); -} - -TEST_F(GXFifoTest, TexCoordScale_TexOffsets_Disabled) { - GXEnableTexOffsets(GX_TEXCOORD2, GX_FALSE, GX_FALSE); - auto bytes = capture_fifo(); - - ASSERT_EQ(bytes.size(), 5u); - EXPECT_EQ(bytes[1], 0x34); - - reset_gx_state(); - g_gxState.texCoordScales[2].lineOffset = true; - g_gxState.texCoordScales[2].pointOffset = true; - decode_fifo(bytes); - - const auto& tcs = g_gxState.texCoordScales[2]; - EXPECT_FALSE(tcs.lineOffset); - EXPECT_FALSE(tcs.pointOffset); -} - -// --- Coord isolation: writing coord 0 doesn't affect coord 1 --- -TEST_F(GXFifoTest, TexCoordScale_Isolation) { - GXSetTexCoordScaleManually(GX_TEXCOORD0, GX_TRUE, 100, 200); - GXSetTexCoordScaleManually(GX_TEXCOORD1, GX_TRUE, 300, 400); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.texCoordScales[0].scaleS, 99u); - EXPECT_EQ(g_gxState.texCoordScales[0].scaleT, 199u); - EXPECT_EQ(g_gxState.texCoordScales[1].scaleS, 299u); - EXPECT_EQ(g_gxState.texCoordScales[1].scaleT, 399u); -} - -// GXSetCopyClear (BP 0x4F-0x51): clear color and depth - -TEST_F(GXFifoTest, DispCopyState_EncodesBpAndYScale) { - GXSetDispCopySrc(4, 8, 640, 480); - GXSetDispCopyDst(640, 480); - const u32 lines = GXSetDispCopyYScale(1.0f); - auto bytes = capture_fifo(); - - EXPECT_EQ(lines, 480u); - EXPECT_TRUE(has_bp_write(bytes, 0x49)); - EXPECT_TRUE(has_bp_write(bytes, 0x4A)); - EXPECT_TRUE(has_bp_write(bytes, 0x4D)); - EXPECT_TRUE(has_bp_write(bytes, 0x4E)); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.dispCopySrc.x, 4); - EXPECT_EQ(g_gxState.dispCopySrc.y, 8); - EXPECT_EQ(g_gxState.dispCopySrc.width, 640); - EXPECT_EQ(g_gxState.dispCopySrc.height, 480); - EXPECT_NEAR(g_gxState.dispCopyYScale, 1.0f, 0.001f); -} - -TEST_F(GXFifoTest, DispCopyYScaleHelpers_MatchIdentityScale) { - EXPECT_EQ(GXGetNumXfbLines(480, 1.0f), 480u); - EXPECT_NEAR(GXGetYScaleFactor(480, 480), 1.0f, 0.001f); -} - -TEST_F(GXFifoTest, CopyFilter_EncodesAndDecodesAaAndVerticalFilter) { - u8 samples[12][2] = {}; - for (size_t i = 0; i < 12; ++i) { - samples[i][0] = static_cast((i * 2) & 0x0f); - samples[i][1] = static_cast((i * 2 + 1) & 0x0f); - } - u8 vfilter[7] = {1, 2, 3, 4, 5, 6, 7}; - - GXSetCopyFilter(GX_TRUE, samples, GX_TRUE, vfilter); - auto bytes = capture_fifo(); - - ASSERT_EQ(bytes.size(), 30u); - EXPECT_EQ(bytes[1], 0x01); - EXPECT_EQ(bytes[6], 0x02); - EXPECT_EQ(bytes[11], 0x03); - EXPECT_EQ(bytes[16], 0x04); - EXPECT_EQ(bytes[21], 0x53); - EXPECT_EQ(bytes[26], 0x54); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_TRUE(g_gxState.copyFilterAa); - EXPECT_TRUE(g_gxState.copyFilterVf); - for (size_t i = 0; i < 12; ++i) { - EXPECT_EQ(g_gxState.copyFilterSamplePattern[i][0], samples[i][0]); - EXPECT_EQ(g_gxState.copyFilterSamplePattern[i][1], samples[i][1]); - } - for (size_t i = 0; i < 7; ++i) { - EXPECT_EQ(g_gxState.copyFilterVFilter[i], vfilter[i]); - } -} - -TEST_F(GXFifoTest, CopyFilter_DisabledUsesSdkFallbackCoefficients) { - u8 samples[12][2] = {}; - u8 vfilter[7] = {}; - - GXSetCopyFilter(GX_FALSE, samples, GX_FALSE, vfilter); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_FALSE(g_gxState.copyFilterAa); - EXPECT_FALSE(g_gxState.copyFilterVf); - for (const auto& sample : g_gxState.copyFilterSamplePattern) { - EXPECT_EQ(sample[0], 6u); - EXPECT_EQ(sample[1], 6u); - } - const std::array expectedVFilter{0, 0, 21, 22, 21, 0, 0}; - EXPECT_EQ(g_gxState.copyFilterVFilter, expectedVFilter); -} - -TEST_F(GXFifoTest, DispCopyGamma_UpdatesCopyTriggerShadowBits) { - GXSetDispCopyGamma(GX_GM_2_2); - - EXPECT_EQ(g_gxState.dispCopyGamma, GX_GM_2_2); - EXPECT_EQ((g_gxState.bpRegCache[0x52] >> 7) & 3u, static_cast(GX_GM_2_2)); -} - -TEST_F(GXFifoTest, CopyTrigger_DecodesClampGammaFormatHalfScaleAndFrameMode) { - const u32 value = (static_cast(GX_CLAMP_TOP) << 0) | (static_cast(GX_TF_RGBA8) << 3) | - (static_cast(GX_GM_1_7) << 7) | (1u << 9) | (2u << 12); - auto bytes = bp_cmd(0x52, value); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.copyClamp, GX_CLAMP_TOP); - EXPECT_EQ(g_gxState.texCopyFmt, GX_TF_RGBA8); - EXPECT_EQ(g_gxState.dispCopyGamma, GX_GM_1_7); - EXPECT_TRUE(g_gxState.texCopyHalfScale); - EXPECT_EQ(g_gxState.dispCopyFrame2Field, 2u); -} - -TEST_F(GXFifoTest, CopyTexClearTruePassesScratchRectAndUpdateMasksToResolve) { - std::array image{}; - gxState().pixelFmt = GX_PF_RGBA6_Z24; - gxState().colorUpdate = true; - gxState().alphaUpdate = true; - gxState().depthUpdate = true; - gxState().dstAlpha = UINT32_MAX; - gxState().clearColor = {64.f / 255.f, 128.f / 255.f, 192.f / 255.f, 32.f / 255.f}; - gxState().clearDepth = 0x123456; - - GXSetTexCopySrc(336, 300, 152, 114); - GXSetTexCopyDst(152, 114, GX_TF_RGBA8, GX_FALSE); - GXCopyTex(image.data(), GX_TRUE); - - const auto& records = aurora::gfx::testing::resolve_pass_records(); - ASSERT_EQ(records.size(), 1u); - const auto& resolve = records.front(); - EXPECT_EQ(resolve.rect, (aurora::gfx::ClipRect{336, 300, 152, 114})); - ASSERT_TRUE(resolve.sourceRectPixels.has_value()); - EXPECT_EQ(resolve.sourceRectPixels->x(), 336.f); - EXPECT_EQ(resolve.sourceRectPixels->y(), 300.f); - EXPECT_EQ(resolve.sourceRectPixels->z(), 152.f); - EXPECT_EQ(resolve.sourceRectPixels->w(), 114.f); - EXPECT_TRUE(resolve.clearColor); - EXPECT_TRUE(resolve.clearAlpha); - EXPECT_TRUE(resolve.clearDepth); - EXPECT_NEAR(resolve.clearColorValue.x(), 64.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(resolve.clearColorValue.y(), 128.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(resolve.clearColorValue.z(), 192.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(resolve.clearColorValue.w(), 32.f / 255.f, 1.f / 255.f); - const float gxDepth = 0x123456 / 16777216.f; - EXPECT_NEAR(resolve.clearDepthValue, aurora::gx::UseReversedZ ? 1.f - gxDepth : gxDepth, - 1.f / 16777216.f); - EXPECT_EQ(resolve.resolveFormat, GX_TF_RGBA8); - EXPECT_FALSE(resolve.halfScale); - EXPECT_FALSE(resolve.forceOpaqueAlpha); - EXPECT_EQ(gxState().copyTextures.at(image.data()).revision, 1u); -} - -TEST_F(GXFifoTest, CopyTexColorFormatMarksResolvePersistent) { - std::array image{}; - gxState().pixelFmt = GX_PF_RGBA6_Z24; - - GXSetTexCopySrc(336, 300, 152, 114); - GXSetTexCopyDst(152, 114, GX_TF_RGBA8, GX_FALSE); - GXCopyTex(image.data(), GX_FALSE); - - const auto& records = aurora::gfx::testing::resolve_pass_records(); - ASSERT_EQ(records.size(), 1u); - EXPECT_TRUE(records.front().persistentCopy); -} - -TEST_F(GXFifoTest, RecurringColorCopyKeepsLaterResolveSkippable) { - std::array image{}; - gxState().pixelFmt = GX_PF_RGBA6_Z24; - - GXSetTexCopySrc(336, 300, 152, 114); - GXSetTexCopyDst(152, 114, GX_TF_RGBA8, GX_FALSE); - aurora::gfx::testing::set_current_frame(10); - GXCopyTex(image.data(), GX_FALSE); - aurora::gfx::testing::set_current_frame(11); - GXCopyTex(image.data(), GX_FALSE); - - const auto& records = aurora::gfx::testing::resolve_pass_records(); - ASSERT_EQ(records.size(), 2u); - EXPECT_TRUE(records[0].persistentCopy); - EXPECT_FALSE(records[1].persistentCopy); -} - -TEST_F(GXFifoTest, ColorCopyAfterFrameGapRegainsPersistentProtection) { - std::array image{}; - gxState().pixelFmt = GX_PF_RGBA6_Z24; - - GXSetTexCopySrc(336, 300, 152, 114); - GXSetTexCopyDst(152, 114, GX_TF_RGBA8, GX_FALSE); - aurora::gfx::testing::set_current_frame(10); - GXCopyTex(image.data(), GX_FALSE); - aurora::gfx::testing::set_current_frame(12); - GXCopyTex(image.data(), GX_FALSE); - - const auto& records = aurora::gfx::testing::resolve_pass_records(); - ASSERT_EQ(records.size(), 2u); - EXPECT_TRUE(records[0].persistentCopy); - EXPECT_TRUE(records[1].persistentCopy); -} - -TEST_F(GXFifoTest, CopyTexDepthFormatKeepsResolveSkippable) { - std::array image{}; - gxState().pixelFmt = GX_PF_RGBA6_Z24; - - GXSetTexCopySrc(0, 0, 4, 4); - GXSetTexCopyDst(4, 4, GX_TF_Z24X8, GX_FALSE); - GXCopyTex(image.data(), GX_FALSE); - - const auto& records = aurora::gfx::testing::resolve_pass_records(); - ASSERT_EQ(records.size(), 1u); - EXPECT_FALSE(records.front().persistentCopy); -} - -TEST_F(GXFifoTest, CopyDispResolveIsNotPersistent) { - GXSetDispCopySrc(0, 0, 32, 32); - GXSetDispCopyDst(32, 32); - GXCopyDisp(nullptr, GX_FALSE); - - const auto& records = aurora::gfx::testing::resolve_pass_records(); - ASSERT_EQ(records.size(), 1u); - EXPECT_FALSE(records.front().persistentCopy); -} - -TEST_F(GXFifoTest, CopyTexMipmapDstRequestsHalfScaleResolve) { - std::array image{}; - gxState().pixelFmt = GX_PF_RGBA6_Z24; - - GXSetTexCopySrc(336, 300, 152, 114); - GXSetTexCopyDst(76, 57, GX_TF_RGBA8, GX_TRUE); - GXCopyTex(image.data(), GX_FALSE); - - const auto& records = aurora::gfx::testing::resolve_pass_records(); - ASSERT_EQ(records.size(), 1u); - const auto& resolve = records.front(); - EXPECT_EQ(resolve.rect, (aurora::gfx::ClipRect{336, 300, 152, 114})); - ASSERT_TRUE(resolve.sourceRectPixels.has_value()); - EXPECT_EQ(resolve.sourceRectPixels->x(), 336.f); - EXPECT_EQ(resolve.sourceRectPixels->y(), 300.f); - EXPECT_EQ(resolve.sourceRectPixels->z(), 152.f); - EXPECT_EQ(resolve.sourceRectPixels->w(), 114.f); - EXPECT_TRUE(resolve.halfScale); - EXPECT_TRUE(gxState().texCopyHalfScale); - EXPECT_EQ(gxState().copyTextures.at(image.data()).width, 76u); - EXPECT_EQ(gxState().copyTextures.at(image.data()).height, 57u); -} - -TEST_F(GXFifoTest, CopyTexRetainsInternalResolutionInGpuCopyAndGuestDimensionsInCache) { - std::array image{}; - aurora::gfx::testing::set_framebuffer_sizes(640, 528, 2560, 2112); - gxState().pixelFmt = GX_PF_RGBA6_Z24; - - GXSetTexCopySrc(336, 300, 152, 114); - GXSetTexCopyDst(152, 114, GX_TF_RGBA8, GX_FALSE); - GXCopyTex(image.data(), GX_FALSE); - - const auto& records = aurora::gfx::testing::resolve_pass_records(); - ASSERT_EQ(records.size(), 1u); - const auto& resolve = records.front(); - EXPECT_EQ(resolve.rect, (aurora::gfx::ClipRect{1344, 1200, 608, 456})); - ASSERT_TRUE(resolve.sourceRectPixels.has_value()); - EXPECT_EQ(resolve.sourceRectPixels->x(), 1344.f); - EXPECT_EQ(resolve.sourceRectPixels->y(), 1200.f); - EXPECT_EQ(resolve.sourceRectPixels->z(), 608.f); - EXPECT_EQ(resolve.sourceRectPixels->w(), 456.f); - ASSERT_TRUE(resolve.texture); - EXPECT_EQ(resolve.texture->size.width, 608u); - EXPECT_EQ(resolve.texture->size.height, 456u); - EXPECT_FLOAT_EQ(resolve.copyFilterRowStride, 4.0f); - - const auto& copy = gxState().copyTextures.at(image.data()); - EXPECT_EQ(copy.width, 152u); - EXPECT_EQ(copy.height, 114u); - EXPECT_EQ(copy.dataSize, GXGetTexBufferSize(152, 114, GX_TF_RGBA8, GX_FALSE, 0)); -} - -TEST_F(GXFifoTest, CopyTexUsesExactRationalScaledEdgesBeforeClearing) { - std::array image{}; - // float32 evaluates 7 * (62 / 14) just below 31. Without stabilizing - // the rational copy edges, floor() expands this clear to begin at x/y 30. - aurora::gfx::testing::set_framebuffer_sizes(14, 14, 62, 62); - gxState().pixelFmt = GX_PF_RGBA6_Z24; - - GXSetTexCopySrc(7, 7, 7, 7); - GXSetTexCopyDst(31, 31, GX_TF_RGBA8, GX_FALSE); - GXCopyTex(image.data(), GX_TRUE); - - const auto& records = aurora::gfx::testing::resolve_pass_records(); - ASSERT_EQ(records.size(), 1u); - const auto& resolve = records.front(); - EXPECT_EQ(resolve.rect, (aurora::gfx::ClipRect{31, 31, 31, 31})); - ASSERT_TRUE(resolve.sourceRectPixels.has_value()); - EXPECT_FLOAT_EQ(resolve.sourceRectPixels->x(), 31.0f); - EXPECT_FLOAT_EQ(resolve.sourceRectPixels->y(), 31.0f); - EXPECT_FLOAT_EQ(resolve.sourceRectPixels->z(), 31.0f); - EXPECT_FLOAT_EQ(resolve.sourceRectPixels->w(), 31.0f); -} - -TEST_F(GXFifoTest, CopyTexClearDoesNotOverlapFractionalLeftEdge) { - std::array image{}; - // MKW split-screen scratch-copy geometry from the regression capture: the scaled source edge is - // x=492.975, so flooring clears column 492 while the matching viewport rasterizes from 493. - aurora::gfx::testing::set_framebuffer_sizes(640, 528, 939, 528); - gxState().pixelFmt = GX_PF_RGBA6_Z24; - - GXSetTexCopySrc(336, 300, 152, 114); - GXSetTexCopyDst(152, 114, GX_TF_RGBA8, GX_FALSE); - GXCopyTex(image.data(), GX_TRUE); - - const auto& records = aurora::gfx::testing::resolve_pass_records(); - ASSERT_EQ(records.size(), 1u); - const auto& resolve = records.front(); - EXPECT_EQ(resolve.rect, (aurora::gfx::ClipRect{493, 300, 223, 114})); - ASSERT_TRUE(resolve.sourceRectPixels.has_value()); - EXPECT_FLOAT_EQ(resolve.sourceRectPixels->x(), 492.975f); - EXPECT_FLOAT_EQ(resolve.sourceRectPixels->y(), 300.0f); - EXPECT_FLOAT_EQ(resolve.sourceRectPixels->z(), 223.0125f); - EXPECT_FLOAT_EQ(resolve.sourceRectPixels->w(), 114.0f); -} - -TEST_F(GXFifoTest, CopyTexClearBoundsRemainExactAtSixTimesInternalResolution) { - std::array image{}; - aurora::gfx::testing::set_framebuffer_sizes(640, 528, 3840, 3168); - gxState().pixelFmt = GX_PF_RGBA6_Z24; - - GXSetTexCopySrc(336, 300, 152, 114); - GXSetTexCopyDst(152, 114, GX_TF_RGBA8, GX_FALSE); - GXCopyTex(image.data(), GX_TRUE); - - const auto& records = aurora::gfx::testing::resolve_pass_records(); - ASSERT_EQ(records.size(), 1u); - const auto& resolve = records.front(); - EXPECT_EQ(resolve.rect, (aurora::gfx::ClipRect{2016, 1800, 912, 684})); - ASSERT_TRUE(resolve.sourceRectPixels.has_value()); - EXPECT_FLOAT_EQ(resolve.sourceRectPixels->x(), 2016.0f); - EXPECT_FLOAT_EQ(resolve.sourceRectPixels->y(), 1800.0f); - EXPECT_FLOAT_EQ(resolve.sourceRectPixels->z(), 912.0f); - EXPECT_FLOAT_EQ(resolve.sourceRectPixels->w(), 684.0f); -} - -TEST_F(GXFifoTest, CopyTexRecreatesGpuCopyWhenInternalResolutionChanges) { - std::array image{}; - gxState().pixelFmt = GX_PF_RGBA6_Z24; - GXSetTexCopySrc(0, 0, 64, 64); - GXSetTexCopyDst(64, 64, GX_TF_RGBA8, GX_FALSE); - - GXCopyTex(image.data(), GX_FALSE); - const auto* nativeHandle = gxState().copyTextures.at(image.data()).handle.get(); - ASSERT_NE(nativeHandle, nullptr); - EXPECT_EQ(nativeHandle->size.width, 64u); - - aurora::gfx::testing::set_framebuffer_sizes(640, 480, 1280, 960); - GXCopyTex(image.data(), GX_FALSE); - - const auto& scaledCopy = gxState().copyTextures.at(image.data()); - ASSERT_TRUE(scaledCopy.handle); - EXPECT_NE(scaledCopy.handle.get(), nativeHandle); - EXPECT_EQ(scaledCopy.handle->size.width, 128u); - EXPECT_EQ(scaledCopy.handle->size.height, 128u); - EXPECT_EQ(scaledCopy.width, 64u); - EXPECT_EQ(scaledCopy.height, 64u); - EXPECT_EQ(scaledCopy.revision, 2u); -} - -TEST_F(GXFifoTest, CopyTexPassesVerticalCopyFilterCoefficientsToResolve) { - std::array image{}; - gxState().pixelFmt = GX_PF_RGBA6_Z24; - u8 vfilter[7] = {3, 5, 7, 11, 13, 17, 19}; - - GXSetCopyFilter(GX_FALSE, nullptr, GX_TRUE, vfilter); - GXSetTexCopySrc(0, 0, 32, 32); - GXSetTexCopyDst(32, 32, GX_TF_RGBA8, GX_FALSE); - GXCopyTex(image.data(), GX_FALSE); - - const auto& records = aurora::gfx::testing::resolve_pass_records(); - ASSERT_EQ(records.size(), 1u); - EXPECT_EQ(records.front().copyFilterCoefficients, (std::array{8, 31, 36})); -} - -TEST_F(GXFifoTest, CopyTexPassesVerticalCopyClampToResolve) { - std::array image{}; - gxState().pixelFmt = GX_PF_RGBA6_Z24; - - GXSetCopyClamp(GX_CLAMP_TOP); - GXSetTexCopySrc(8, 12, 32, 32); - GXSetTexCopyDst(32, 32, GX_TF_RGBA8, GX_FALSE); - GXCopyTex(image.data(), GX_FALSE); - - const auto& records = aurora::gfx::testing::resolve_pass_records(); - ASSERT_EQ(records.size(), 1u); - EXPECT_TRUE(records.front().clampTop); - EXPECT_FALSE(records.front().clampBottom); -} - -TEST_F(GXFifoTest, CopyDispCanDisableSpatialCopyFilterWithoutChangingBrightness) { - u8 vfilter[7] = {3, 5, 7, 11, 13, 17, 19}; - aurora::g_config.disableCopyFilter = true; - - GXSetCopyFilter(GX_FALSE, nullptr, GX_TRUE, vfilter); - GXSetDispCopySrc(0, 0, 32, 32); - GXSetDispCopyDst(32, 32); - GXCopyDisp(nullptr, GX_FALSE); - - const auto& records = aurora::gfx::testing::resolve_pass_records(); - ASSERT_EQ(records.size(), 1u); - EXPECT_EQ(records.front().copyFilterCoefficients, (std::array{0, 75, 0})); -} - -TEST_F(GXFifoTest, CopyTexDepthZ16PreservesVerticalCopyFilterForConversion) { - std::array image{}; - gxState().pixelFmt = GX_PF_RGBA6_Z24; - u8 vfilter[7] = {21, 0, 0, 22, 0, 21, 0}; - - GXSetCopyFilter(GX_FALSE, nullptr, GX_TRUE, vfilter); - EXPECT_TRUE(gxState().copyFilterVf); - EXPECT_EQ(gxState().copyFilterVFilter, (std::array{21, 0, 0, 22, 0, 21, 0})); - GXSetTexCopySrc(0, 0, 32, 32); - GXSetTexCopyDst(32, 32, GX_TF_Z16, GX_FALSE); - EXPECT_EQ(gxState().copyFilterVFilter, (std::array{21, 0, 0, 22, 0, 21, 0})); - GXCopyTex(image.data(), GX_FALSE); - EXPECT_EQ(gxState().copyFilterVFilter, (std::array{21, 0, 0, 22, 0, 21, 0})); - - const auto& records = aurora::gfx::testing::resolve_pass_records(); - ASSERT_EQ(records.size(), 1u); - EXPECT_EQ(records.front().resolveFormat, GX_TF_Z16); - EXPECT_EQ(records.front().copyFilterCoefficients, (std::array{21, 22, 21})); - EXPECT_FALSE(records.front().forceOpaqueAlpha); - EXPECT_EQ(gxState().copyTextures.at(image.data()).format, GX_TF_Z16); -} - -TEST_F(GXFifoTest, CopyTexDepthZ16UsesRa8Ia8Semantics) { - constexpr auto rgba = aurora::gfx::tex_copy_conv::detail::z16_ra8_as_ia8_rgba(0x12); - EXPECT_EQ(rgba, (std::array{0x12, 0x12, 0x12, 0xff})); - - constexpr auto shader = aurora::gfx::tex_copy_conv::detail::Z16FragmentShader; - EXPECT_NE(shader.find("let i = f32(depth_bytes.r)"), std::string_view::npos); - EXPECT_NE(shader.find("return vec4f(i, i, i, 1.0)"), std::string_view::npos); -} - -TEST_F(GXFifoTest, CopyTexClearTrueNoOpsWhenAllUpdateMasksAreDisabled) { - std::array image{}; - gxState().pixelFmt = GX_PF_RGBA6_Z24; - gxState().colorUpdate = false; - gxState().alphaUpdate = false; - gxState().depthUpdate = false; - gxState().dstAlpha = UINT32_MAX; - - GXSetTexCopySrc(8, 16, 64, 64); - GXSetTexCopyDst(64, 64, GX_TF_RGBA8, GX_FALSE); - GXCopyTex(image.data(), GX_TRUE); - - const auto& records = aurora::gfx::testing::resolve_pass_records(); - ASSERT_EQ(records.size(), 1u); - EXPECT_FALSE(records.front().clearColor); - EXPECT_FALSE(records.front().clearAlpha); - EXPECT_FALSE(records.front().clearDepth); -} - -TEST_F(GXFifoTest, CopyTexClearTrueRgbTargetKeepsFormatAndForcesOpaqueCopiedAlpha) { - std::array image{}; - gxState().pixelFmt = GX_PF_RGB8_Z24; - gxState().colorUpdate = true; - gxState().alphaUpdate = false; - gxState().depthUpdate = false; - gxState().dstAlpha = UINT32_MAX; - gxState().clearColor = {0.2f, 0.4f, 0.6f, 0.25f}; - - GXSetTexCopySrc(0, 0, 32, 32); - GXSetTexCopyDst(32, 32, GX_TF_RGBA8, GX_FALSE); - GXCopyTex(image.data(), GX_TRUE); - - const auto& records = aurora::gfx::testing::resolve_pass_records(); - ASSERT_EQ(records.size(), 1u); - EXPECT_TRUE(records.front().clearColor); - EXPECT_FALSE(records.front().clearAlpha); - EXPECT_FALSE(records.front().clearDepth); - EXPECT_NEAR(records.front().clearColorValue.x(), 0.2f, 1.f / 255.f); - EXPECT_NEAR(records.front().clearColorValue.y(), 0.4f, 1.f / 255.f); - EXPECT_NEAR(records.front().clearColorValue.z(), 0.6f, 1.f / 255.f); - EXPECT_EQ(records.front().clearColorValue.w(), 0.25f); - EXPECT_EQ(records.front().resolveFormat, GX_TF_RGBA8); - EXPECT_TRUE(records.front().forceOpaqueAlpha); -} - -TEST_F(GXFifoTest, CopyTexSameTargetReusesHostTextureUntilSampledThisFrame) { - std::array image{}; - gxState().pixelFmt = GX_PF_RGBA6_Z24; - - GXSetTexCopySrc(0, 0, 64, 64); - GXSetTexCopyDst(64, 64, GX_TF_RGBA8, GX_FALSE); - GXCopyTex(image.data(), GX_FALSE); - - const auto& first = gxState().copyTextures.at(image.data()); - ASSERT_TRUE(first.handle); - const auto* firstHandle = first.handle.get(); - EXPECT_EQ(first.revision, 1u); - - GXCopyTex(image.data(), GX_FALSE); - - const auto& second = gxState().copyTextures.at(image.data()); - EXPECT_EQ(second.handle.get(), firstHandle); - EXPECT_EQ(second.revision, 2u); -} - -TEST_F(GXFifoTest, CopyTexSameFrameSampledTargetGetsFreshHostTexture) { - std::array image{}; - gxState().pixelFmt = GX_PF_RGBA6_Z24; - - GXSetTexCopySrc(0, 0, 64, 64); - GXSetTexCopyDst(64, 64, GX_TF_RGBA8, GX_FALSE); - GXCopyTex(image.data(), GX_FALSE); - - const aurora::gx::GXState::CopyTextureKey key{ - .dest = image.data(), - .width = 64, - .height = 64, - .format = GX_TF_RGBA8, - }; - const auto& first = gxState().copyTextures.at(image.data()); - ASSERT_TRUE(first.handle); - const auto* firstHandle = first.handle.get(); - - auto& cached = gxState().copyTextureCache.at(key); - cached.lastSampledFrame = aurora::gfx::current_frame(); - cached.sampledThisFrame = true; - - GXCopyTex(image.data(), GX_FALSE); - - const auto& second = gxState().copyTextures.at(image.data()); - ASSERT_TRUE(second.handle); - EXPECT_NE(second.handle.get(), firstHandle); - EXPECT_EQ(second.revision, 2u); -} - -TEST_F(GXFifoTest, CopyTexSameTargetDifferentShapeRetiresHistoricalCacheEntry) { - std::vector image(608 * 456 * 4); - gxState().pixelFmt = GX_PF_RGBA6_Z24; - - GXSetTexCopySrc(0, 0, 608, 456); - GXSetTexCopyDst(608, 456, GX_TF_RGB565, GX_FALSE); - GXCopyTex(image.data(), GX_FALSE); - - const aurora::gx::GXState::CopyTextureKey fullKey{ - .dest = image.data(), - .width = 608, - .height = 456, - .format = GX_TF_RGB565, - }; - const auto& fullCopy = gxState().copyTextureCache.at(fullKey); - ASSERT_TRUE(fullCopy.handle); - const auto* fullHandle = fullCopy.handle.get(); - - GXSetTexCopySrc(0, 0, 304, 228); - GXSetTexCopyDst(304, 228, GX_TF_RGBA8, GX_TRUE); - GXCopyTex(image.data(), GX_FALSE); - - const aurora::gx::GXState::CopyTextureKey halfKey{ - .dest = image.data(), - .width = 304, - .height = 228, - .format = GX_TF_RGBA8, - }; - const auto& halfCopy = gxState().copyTextureCache.at(halfKey); - ASSERT_TRUE(halfCopy.handle); - - EXPECT_FALSE(gxState().copyTextureCache.contains(fullKey)); - EXPECT_EQ(gxState().copyTextureCache.size(), 1u); - EXPECT_NE(halfCopy.handle.get(), fullHandle); - EXPECT_EQ(gxState().copyTextures.at(image.data()).handle.get(), halfCopy.handle.get()); - EXPECT_EQ(gxState().copyTextures.at(image.data()).width, 304u); - EXPECT_EQ(gxState().copyTextures.at(image.data()).height, 228u); - EXPECT_EQ(gxState().copyTextures.at(image.data()).format, GX_TF_RGBA8); -} - -TEST_F(GXFifoTest, CopyTexCtfFormatsCanBackCompatibleTextureFormats) { - EXPECT_TRUE(aurora::gx::copy_texture_format_compatible(GX_CTF_R4, GX_TF_I4)); - EXPECT_TRUE(aurora::gx::copy_texture_format_compatible(GX_CTF_R8, GX_TF_I8)); - EXPECT_TRUE(aurora::gx::copy_texture_format_compatible(GX_CTF_G8, GX_TF_I8)); - EXPECT_TRUE(aurora::gx::copy_texture_format_compatible(GX_CTF_B8, GX_TF_I8)); - EXPECT_TRUE(aurora::gx::copy_texture_format_compatible(GX_CTF_RA4, GX_TF_IA4)); - EXPECT_TRUE(aurora::gx::copy_texture_format_compatible(GX_CTF_RA8, GX_TF_IA8)); - EXPECT_TRUE(aurora::gx::copy_texture_format_compatible(GX_CTF_RG8, GX_TF_IA8)); - EXPECT_TRUE(aurora::gx::copy_texture_format_compatible(GX_CTF_GB8, GX_TF_IA8)); - EXPECT_TRUE(aurora::gx::copy_texture_format_compatible(GX_TF_Z16, GX_TF_IA8)); - EXPECT_TRUE(aurora::gx::copy_texture_format_compatible(GX_CTF_YUVA8, GX_TF_RGBA8)); - EXPECT_TRUE(aurora::gx::copy_texture_format_compatible(GX_TF_Z24X8, GX_TF_RGBA8)); - EXPECT_FALSE(aurora::gx::copy_texture_format_compatible(GX_CTF_R8, GX_TF_RGBA8)); -} - -TEST_F(GXFifoTest, FieldMaskModeRevBitsAndFogRange_DecodeKnownBpState) { - std::vector bytes; - const auto fieldMask = bp_cmd(0x44, 0x03); - const auto revBits = bp_cmd(0x58, 0x0F); - const auto fieldMode = bp_cmd(0x68, 0x01); - const auto fogRangeBase = bp_cmd(0xE8, 0x0156); - const auto fogRangeK0 = bp_cmd(0xE9, 0x123456); - bytes.insert(bytes.end(), fieldMask.begin(), fieldMask.end()); - bytes.insert(bytes.end(), revBits.begin(), revBits.end()); - bytes.insert(bytes.end(), fieldMode.begin(), fieldMode.end()); - bytes.insert(bytes.end(), fogRangeBase.begin(), fogRangeBase.end()); - bytes.insert(bytes.end(), fogRangeK0.begin(), fogRangeK0.end()); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.fieldMask, 0x03u); - EXPECT_EQ(g_gxState.revBits, 0x0Fu); - EXPECT_EQ(g_gxState.fieldMode, 0x01u); - EXPECT_EQ(g_gxState.fogRange[0], 0x0156u); - EXPECT_EQ(g_gxState.fogRange[1], 0x123456u); -} - -TEST_F(GXFifoTest, XfErrorAndDualTex_DecodeKnownRawState) { - std::vector bytes; - const auto xfError = xf_cmd(0x1000, {0x3F}); - const auto dualTex = xf_cmd(0x1012, {0x01}); - bytes.insert(bytes.end(), xfError.begin(), xfError.end()); - bytes.insert(bytes.end(), dualTex.begin(), dualTex.end()); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.xfError, 0x3Fu); - EXPECT_EQ(g_gxState.dualTex, 0x01u); -} - -TEST_F(GXFifoTest, ClearBoundingBox_EncodesBpAndDecodesFallbackExtents) { - GXClearBoundingBox(); - auto bytes = capture_fifo(); - - ASSERT_EQ(bytes.size(), 10u); - EXPECT_EQ(bytes[0], 0x61); - EXPECT_EQ(bytes[1], 0x55); - EXPECT_EQ(bytes[5], 0x61); - EXPECT_EQ(bytes[6], 0x56); - - reset_gx_state(); - g_gxState.boundingBox = {1, 2, 3, 4}; - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.boundingBox[0], 1023u); - EXPECT_EQ(g_gxState.boundingBox[1], 0u); - EXPECT_EQ(g_gxState.boundingBox[2], 1023u); - EXPECT_EQ(g_gxState.boundingBox[3], 0u); -} - -TEST_F(GXFifoTest, ReadBoundingBox_ReturnsTrackedState) { - g_gxState.boundingBox = {10, 20, 30, 40}; - - u16 left = 0; - u16 right = 0; - u16 top = 0; - u16 bottom = 0; - GXReadBoundingBox(&left, &right, &top, &bottom); - - EXPECT_EQ(left, 10u); - EXPECT_EQ(right, 20u); - EXPECT_EQ(top, 30u); - EXPECT_EQ(bottom, 40u); -} - -// --- Clear color and depth round-trip --- -TEST_F(GXFifoTest, CopyClear_ColorAndDepth) { - GXColor color = {64, 128, 192, 255}; - GXSetCopyClear(color, 0x00ABCDEF); - auto bytes = capture_fifo(); - - // 3 BP writes: 3 * 5 = 15 bytes - ASSERT_EQ(bytes.size(), 15u); - EXPECT_EQ(bytes[0], 0x61); - EXPECT_EQ(bytes[1], 0x4F); // R + A - EXPECT_EQ(bytes[5], 0x61); - EXPECT_EQ(bytes[6], 0x50); // B + G - EXPECT_EQ(bytes[10], 0x61); - EXPECT_EQ(bytes[11], 0x51); // Z - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_NEAR(g_gxState.clearColor[0], 64.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.clearColor[1], 128.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.clearColor[2], 192.f / 255.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.clearColor[3], 255.f / 255.f, 1.f / 255.f); - EXPECT_EQ(g_gxState.clearDepth, 0x00ABCDEFu); -} - -// --- Clear with black and zero depth --- -TEST_F(GXFifoTest, CopyClear_BlackZeroDepth) { - GXColor color = {0, 0, 0, 0}; - GXSetCopyClear(color, 0); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_NEAR(g_gxState.clearColor[0], 0.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.clearColor[1], 0.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.clearColor[2], 0.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.clearColor[3], 0.f, 1.f / 255.f); - EXPECT_EQ(g_gxState.clearDepth, 0u); -} - -// --- Clear with max depth --- -TEST_F(GXFifoTest, CopyClear_MaxDepth) { - GXColor color = {255, 255, 255, 128}; - GXSetCopyClear(color, 0xFFFFFF); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_NEAR(g_gxState.clearColor[0], 1.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.clearColor[1], 1.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.clearColor[2], 1.f, 1.f / 255.f); - EXPECT_NEAR(g_gxState.clearColor[3], 128.f / 255.f, 1.f / 255.f); - EXPECT_EQ(g_gxState.clearDepth, 0xFFFFFFu); -} - -TEST_F(GXFifoTest, PeekZ_ReturnsClearDepthFallbackAndRequestsSnapshot) { - g_gxState.clearDepth = 0x123456; - - u32 z = 0; - GXPeekZ(10, 20, &z); - - EXPECT_EQ(z, 0x123456u); - EXPECT_TRUE(aurora::gfx::depth_peek::testing::snapshot_requested()); -} - -TEST_F(GXFifoTest, PeekZ_ReturnsLatestCompletedSnapshot) { - aurora::gfx::depth_peek::testing::set_latest(2, 2, {0x000001, 0x000002, 0x000003, 0x01000004}); - - u32 z = 0; - GXPeekZ(1, 1, &z); - - EXPECT_EQ(z, 0x000004u); - EXPECT_TRUE(aurora::gfx::depth_peek::testing::snapshot_requested()); -} - -TEST_F(GXFifoTest, PeekZ_OutOfRangeReturnsClearDepthFallback) { - g_gxState.clearDepth = 0xabcdef; - aurora::gfx::depth_peek::testing::set_latest(1, 1, {0x000001}); - - u32 z = 0; - GXPeekZ(1, 0, &z); - - EXPECT_EQ(z, 0xabcdefu); - EXPECT_TRUE(aurora::gfx::depth_peek::testing::snapshot_requested()); -} - -// Composite tests (multiple state changes in a single FIFO stream) - -TEST_F(GXFifoTest, Composite_BlendAndZMode) { - GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_NOOP); - GXSetZMode(true, GX_LEQUAL, true); - GXSetAlphaCompare(GX_GREATER, 128, GX_AOP_AND, GX_ALWAYS, 0); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.blendMode, GX_BM_BLEND); - EXPECT_EQ(g_gxState.blendFacSrc, GX_BL_SRCALPHA); - EXPECT_EQ(g_gxState.blendFacDst, GX_BL_INVSRCALPHA); - - EXPECT_TRUE(g_gxState.depthCompare); - EXPECT_EQ(g_gxState.depthFunc, GX_LEQUAL); - EXPECT_TRUE(g_gxState.depthUpdate); - - EXPECT_EQ(g_gxState.alphaCompare.comp0, GX_GREATER); - EXPECT_EQ(g_gxState.alphaCompare.ref0, 128u); -} - -// --- GXLoadTexMtxImm for PTTexMtx (XF 0x500-0x5EF) --- - -TEST_F(GXFifoTest, LoadPTTexMtx_Identity) { - aurora::Mat3x4 mtx{}; - mtx.m0[0] = 1.0f; - mtx.m1[1] = 1.0f; - mtx.m2[2] = 1.0f; - - GXLoadTexMtxImm(&mtx, GX_PTTEXMTX0, GX_MTX3x4); - auto bytes = capture_fifo(); - - // XF opcode 0x10, addr = (64 - 64) * 4 + 0x500 = 0x500, count = 12 - ASSERT_GE(bytes.size(), 5u); - EXPECT_EQ(bytes[0], 0x10); - - reset_gx_state(); - decode_fifo(bytes); - - auto& decoded = g_gxState.ptTexMtxs[0]; - EXPECT_FLOAT_EQ(decoded.m0[0], 1.0f); - EXPECT_FLOAT_EQ(decoded.m0[1], 0.0f); - EXPECT_FLOAT_EQ(decoded.m0[2], 0.0f); - EXPECT_FLOAT_EQ(decoded.m0[3], 0.0f); - EXPECT_FLOAT_EQ(decoded.m1[0], 0.0f); - EXPECT_FLOAT_EQ(decoded.m1[1], 1.0f); - EXPECT_FLOAT_EQ(decoded.m1[2], 0.0f); - EXPECT_FLOAT_EQ(decoded.m1[3], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[0], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[1], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[2], 1.0f); - EXPECT_FLOAT_EQ(decoded.m2[3], 0.0f); -} - -TEST_F(GXFifoTest, LoadPTTexMtx_ArbitraryValues) { - aurora::Mat3x4 mtx{}; - mtx.m0[0] = 2.0f; mtx.m0[1] = 0.5f; mtx.m0[2] = 0.0f; mtx.m0[3] = 10.0f; - mtx.m1[0] = -0.5f; mtx.m1[1] = 3.0f; mtx.m1[2] = 0.0f; mtx.m1[3] = 20.0f; - mtx.m2[0] = 0.0f; mtx.m2[1] = 0.0f; mtx.m2[2] = 1.5f; mtx.m2[3] = -5.0f; - - GXLoadTexMtxImm(&mtx, GX_PTTEXMTX0, GX_MTX3x4); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& decoded = g_gxState.ptTexMtxs[0]; - EXPECT_FLOAT_EQ(decoded.m0[0], 2.0f); - EXPECT_FLOAT_EQ(decoded.m0[1], 0.5f); - EXPECT_FLOAT_EQ(decoded.m0[2], 0.0f); - EXPECT_FLOAT_EQ(decoded.m0[3], 10.0f); - EXPECT_FLOAT_EQ(decoded.m1[0], -0.5f); - EXPECT_FLOAT_EQ(decoded.m1[1], 3.0f); - EXPECT_FLOAT_EQ(decoded.m1[2], 0.0f); - EXPECT_FLOAT_EQ(decoded.m1[3], 20.0f); - EXPECT_FLOAT_EQ(decoded.m2[0], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[1], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[2], 1.5f); - EXPECT_FLOAT_EQ(decoded.m2[3], -5.0f); -} - -TEST_F(GXFifoTest, LoadPTTexMtx_DifferentSlots) { - aurora::Mat3x4 mtx0{}; - mtx0.m0[0] = 1.0f; - mtx0.m1[1] = 1.0f; - mtx0.m2[2] = 1.0f; - - aurora::Mat3x4 mtx5{}; - mtx5.m0[0] = 5.0f; - mtx5.m1[1] = 6.0f; - mtx5.m2[2] = 7.0f; - mtx5.m0[3] = 100.0f; - - GXLoadTexMtxImm(&mtx0, GX_PTTEXMTX0, GX_MTX3x4); - GXLoadTexMtxImm(&mtx5, GX_PTTEXMTX5, GX_MTX3x4); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - // Slot 0 - EXPECT_FLOAT_EQ(g_gxState.ptTexMtxs[0].m0[0], 1.0f); - EXPECT_FLOAT_EQ(g_gxState.ptTexMtxs[0].m1[1], 1.0f); - EXPECT_FLOAT_EQ(g_gxState.ptTexMtxs[0].m2[2], 1.0f); - - // Slot 5: GX_PTTEXMTX5 = 79, index = (79 - 64) / 3 = 5 - EXPECT_FLOAT_EQ(g_gxState.ptTexMtxs[5].m0[0], 5.0f); - EXPECT_FLOAT_EQ(g_gxState.ptTexMtxs[5].m1[1], 6.0f); - EXPECT_FLOAT_EQ(g_gxState.ptTexMtxs[5].m2[2], 7.0f); - EXPECT_FLOAT_EQ(g_gxState.ptTexMtxs[5].m0[3], 100.0f); -} - -TEST_F(GXFifoTest, LoadPTTexMtx_LastSlot) { - aurora::Mat3x4 mtx{}; - mtx.m0[0] = 42.0f; - mtx.m1[1] = 43.0f; - mtx.m2[2] = 44.0f; - - GXLoadTexMtxImm(&mtx, GX_PTTEXMTX19, GX_MTX3x4); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - auto& decoded = g_gxState.ptTexMtxs[19]; - EXPECT_FLOAT_EQ(decoded.m0[0], 42.0f); - EXPECT_FLOAT_EQ(decoded.m1[1], 43.0f); - EXPECT_FLOAT_EQ(decoded.m2[2], 44.0f); - // Other elements should be zero (from reset) - EXPECT_FLOAT_EQ(decoded.m0[1], 0.0f); - EXPECT_FLOAT_EQ(decoded.m2[3], 0.0f); -} - -TEST_F(GXFifoTest, LoadPTTexMtx_Isolation) { - // Loading PTTexMtx0 should not affect PTTexMtx1 - aurora::Mat3x4 mtx{}; - mtx.m0[0] = 99.0f; - mtx.m1[1] = 88.0f; - mtx.m2[2] = 77.0f; - - GXLoadTexMtxImm(&mtx, GX_PTTEXMTX0, GX_MTX3x4); - auto bytes = capture_fifo(); - - reset_gx_state(); - decode_fifo(bytes); - - // Slot 0 should have our values - EXPECT_FLOAT_EQ(g_gxState.ptTexMtxs[0].m0[0], 99.0f); - // Slot 1 should remain zeroed - EXPECT_FLOAT_EQ(g_gxState.ptTexMtxs[1].m0[0], 0.0f); - EXPECT_FLOAT_EQ(g_gxState.ptTexMtxs[1].m1[1], 0.0f); - EXPECT_FLOAT_EQ(g_gxState.ptTexMtxs[1].m2[2], 0.0f); -} - -// Composite / multi-command tests - -TEST_F(GXFifoTest, Composite_TevSetup) { - // Set up a simple 1-stage TEV that passes through texture color - GXSetNumTevStages(1); - GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); - GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_TEXC); - GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA); - - // TEV order writes to dirty state, so flush before capture - auto bytes = flush_and_capture(); - - reset_gx_state(); - decode_fifo(bytes); - - EXPECT_EQ(g_gxState.numTevStages, 1u); - EXPECT_EQ(g_gxState.tevStages[0].texMapId, GX_TEXMAP0); - EXPECT_EQ(g_gxState.tevStages[0].texCoordId, GX_TEXCOORD0); - EXPECT_EQ(g_gxState.tevStages[0].channelId, GX_COLOR0A0); - EXPECT_EQ(g_gxState.tevStages[0].colorPass.d, GX_CC_TEXC); - EXPECT_EQ(g_gxState.tevStages[0].alphaPass.d, GX_CA_TEXA); -} diff --git a/aurora-main/tests/gx_test_common.hpp b/aurora-main/tests/gx_test_common.hpp deleted file mode 100644 index fce6605..0000000 --- a/aurora-main/tests/gx_test_common.hpp +++ /dev/null @@ -1,99 +0,0 @@ -#pragma once - -#include - -#include - -#include "gx/gx.hpp" -#include "gx/fifo.hpp" -#include "gx/command_processor.hpp" -#include "gfx/depth_peek.hpp" -#include "internal.hpp" - -#include -#include -#include -#include - -// Forward declare dirty state flush -extern "C" void __GXSetDirtyState(); - -namespace aurora::gfx::testing { -struct ResolvePassRecord { - TextureHandle texture; - ClipRect rect; - bool clearColor = false; - bool clearAlpha = false; - bool clearDepth = false; - Vec4 clearColorValue{0.f, 0.f, 0.f, 0.f}; - float clearDepthValue = 0.f; - GXTexFmt resolveFormat = GX_TF_RGBA8; - std::optional> sourceRectPixels; - bool halfScale = false; - std::array copyFilterCoefficients{0, 64, 0}; - bool forceOpaqueAlpha = false; - float copyFilterRowStride = 1.0f; - bool clampTop = false; - bool clampBottom = false; - bool persistentCopy = false; -}; - -void reset_resolve_pass_records() noexcept; -const std::vector& resolve_pass_records() noexcept; -void set_current_frame(uint32_t frame) noexcept; -void set_framebuffer_sizes(uint32_t logicalWidth, uint32_t logicalHeight, - uint32_t targetWidth, uint32_t targetHeight) noexcept; -void reset_vertex_push_record() noexcept; -const std::vector& last_pushed_vertices() noexcept; -const std::vector& last_pushed_indices() noexcept; -void reset_uniform_allocations() noexcept; -const std::vector& uniform_allocation(size_t index) noexcept; -void use_draw_command_tracking(bool enabled) noexcept; -void use_real_vertex_format_helpers(bool enabled) noexcept; -// Admit this many draws, then refuse one as if the staging batch were full. -void refuse_staging_admission_after(uint32_t admissions) noexcept; -void reset_staging_capacity() noexcept; -} // namespace aurora::gfx::testing - -class GXFifoTest : public ::testing::Test { -protected: - void SetUp() override { - aurora::gfx::testing::set_current_frame(0); - aurora::gfx::testing::set_framebuffer_sizes(640, 480, 640, 480); - GXInit(nullptr, 0); - aurora::gx::fifo::clear_buffer(); - aurora::gx::g_gxState = aurora::gx::GXState{}; - aurora::g_config.disableCopyFilter = false; - aurora::gfx::depth_peek::testing::reset(); - aurora::gfx::testing::reset_resolve_pass_records(); - aurora::gfx::testing::reset_vertex_push_record(); - aurora::gfx::testing::use_real_vertex_format_helpers(false); - aurora::gfx::testing::reset_staging_capacity(); - } - - // Copy the internal FIFO buffer contents and clear it - std::vector capture_fifo() { - auto size = aurora::gx::fifo::get_buffer_size(); - auto* data = aurora::gx::fifo::get_buffer_data(); - std::vector bytes(data, data + size); - aurora::gx::fifo::clear_buffer(); - return bytes; - } - - // Reset g_gxState to default-constructed state - void reset_gx_state() { aurora::gx::g_gxState = aurora::gx::GXState{}; } - - // Decode a captured FIFO byte stream through the command processor - void decode_fifo(const std::vector& bytes) { - aurora::gx::fifo::process(bytes.data(), static_cast(bytes.size()), true); - } - - // Flush dirty state, then capture the FIFO buffer - std::vector flush_and_capture() { - __GXSetDirtyState(); - return capture_fifo(); - } - - // Convenience reference to g_gxState - aurora::gx::GXState& gxState() { return aurora::gx::g_gxState; } -}; diff --git a/aurora-main/tests/gx_test_stubs.cpp b/aurora-main/tests/gx_test_stubs.cpp deleted file mode 100644 index aaa2144..0000000 --- a/aurora-main/tests/gx_test_stubs.cpp +++ /dev/null @@ -1,585 +0,0 @@ -// Stubs for renderer symbols the GX/FIFO/command_processor code references but that live in the -// full renderer, so the test binary links without the WebGPU runtime. - -#include "gx/gx.hpp" -#include "gfx/clear.hpp" -#include "gfx/common.hpp" -#include "gfx/depth_peek.hpp" -#include "gfx/efb_ram_copy.hpp" -#include "gfx/tex_copy_conv.hpp" -#include "gfx/tex_palette_conv.hpp" -#include "gfx/texture.hpp" -#include "gx/pipeline.hpp" -#include "gx/shader_info.hpp" -#include "internal.hpp" -#include "webgpu/gpu.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { -aurora::Vec2 s_logicalFbSize{640, 480}; -aurora::Vec2 s_renderTargetSize{640, 480}; -uint32_t s_currentFrame = 0; -std::vector s_lastPushedVertices; -std::vector s_lastPushedIndices; -std::optional s_lastGxDraw; -bool s_trackDrawCommands = false; -bool s_useRealVertexFormatHelpers = false; -std::deque> s_uniformAllocations; -std::optional s_stagingAdmissionsBeforeRefusal; -bool s_stagingRefused = false; -uint64_t s_stagingSplitCount = 0; -} // namespace - -// --- aurora::g_config --- -namespace aurora { -AuroraConfig g_config{}; -void wait_for_frame_worker() noexcept {} -std::chrono::nanoseconds wait_for_frame_worker_sealed() noexcept { return {}; } -bool wait_for_frame_worker_for(std::chrono::microseconds) noexcept { return true; } -std::recursive_mutex& renderer_gpu_mutex() noexcept { - static std::recursive_mutex mutex; - return mutex; -} -} // namespace aurora - -extern "C" bool aurora_wait_for_frame_worker_for(uint32_t) { return true; } - -// --- aurora::log_internal --- -namespace aurora { -void log_internal(AuroraLogLevel level, const char* module, const char* message, unsigned int len) noexcept { - fprintf(stderr, "[%d] %s: %.*s\n", static_cast(level), module, len, message); -} -void Module::show_fatal_dialog(const char*, std::string_view) noexcept {} -} // namespace aurora - -namespace aurora::window { -void set_present_surface_fill(bool) {} -} // namespace aurora::window - -// --- fmt::formatter --- -auto fmt::formatter::format(AuroraLogLevel level, format_context& ctx) const - -> format_context::iterator { - return fmt::format_to(ctx.out(), "{}", static_cast(level)); -} - -// --- GPU buffers (default-constructed, not used in tests) --- -namespace aurora::gfx { -AuroraStats g_stats; -wgpu::Buffer g_vertexBuffer; -wgpu::Buffer g_uniformBuffer; -wgpu::Buffer g_indexBuffer; -wgpu::Buffer g_storageBuffer; -uint32_t g_drawCallCount = 0; -uint32_t g_mergedDrawCallCount = 0; -} // namespace aurora::gfx - -namespace aurora::webgpu { -GraphicsConfig g_graphicsConfig{}; -} // namespace aurora::webgpu - -// --- GXState (the real instance -- tests validate this) --- -namespace aurora::gx { -GXState g_gxState{}; -void notify_copy_texture_created() noexcept {} -} // namespace aurora::gx - -namespace aurora::vi { -Vec2 configured_fb_size() noexcept { return s_logicalFbSize; } -void configure(const GXRenderModeObj*) noexcept {} -} // namespace aurora::vi - -// --- Texture uploads --- -namespace aurora::gfx { -std::vector g_textureUploads; -} // namespace aurora::gfx - -namespace aurora::gfx::efb_ram { -void schedule(void*, uint32_t, uint32_t, GXTexFmt, TextureHandle) noexcept {} -} // namespace aurora::gfx::efb_ram - -// --- get_texture --- -namespace aurora::gx { -const gfx::TextureBind& get_texture(GXTexMapID id) noexcept { return g_gxState.textures[id]; } -void evict_texture_object(u32 texObjId) noexcept { - for (auto& obj : g_gxState.loadedTextures) { - if (obj.texObjId == texObjId) { - obj.set_no_cache(true); - } - } -} -void evict_tlut_object(u32 tlutObjId) noexcept { - for (auto& obj : g_gxState.loadedTluts) { - if (obj.tlutObjId == tlutObjId) { - obj.set_no_cache(true); - } - } -} -void invalidate_static_texture_cache() noexcept { - for (auto& texture : g_gxState.textures) { - texture.reset(); - } - g_gxState.stateDirty = true; -} -void evict_copy_texture(const void* dest) noexcept { - g_gxState.copyTextures.erase(dest); - for (auto it = g_gxState.copyTextureCache.begin(); it != g_gxState.copyTextureCache.end();) { - if (it->first.dest == dest) { - g_gxState.copyTextureCache.erase(it++); - } else { - ++it; - } - } -} -void set_display_copy_present_source() noexcept {} -void shutdown() noexcept {} -Vec2 logical_fb_size() noexcept { return s_logicalFbSize; } -gfx::Viewport map_logical_viewport(const gfx::Viewport& logicalViewport) noexcept { - const float scaleX = static_cast(s_renderTargetSize.x) / static_cast(s_logicalFbSize.x); - const float scaleY = static_cast(s_renderTargetSize.y) / static_cast(s_logicalFbSize.y); - return { - .left = logicalViewport.left * scaleX, - .top = logicalViewport.top * scaleY, - .width = logicalViewport.width * scaleX, - .height = logicalViewport.height * scaleY, - .znear = logicalViewport.znear, - .zfar = logicalViewport.zfar, - }; -} -gfx::ClipRect map_logical_scissor(const gfx::ClipRect& logicalScissor) noexcept { - const auto mapped = map_logical_viewport({ - .left = static_cast(logicalScissor.x), - .top = static_cast(logicalScissor.y), - .width = static_cast(logicalScissor.width), - .height = static_cast(logicalScissor.height), - .znear = 0.0f, - .zfar = 1.0f, - }); - const auto left = static_cast(std::floor(mapped.left)); - const auto top = static_cast(std::floor(mapped.top)); - const auto right = static_cast(std::ceil(mapped.left + mapped.width)); - const auto bottom = static_cast(std::ceil(mapped.top + mapped.height)); - return {left, top, right - left, bottom - top}; -} -MappedRenderState map_logical_render_state() noexcept { - return { - .viewport = map_logical_viewport(g_gxState.logicalViewport), - .scissor = map_logical_scissor(g_gxState.logicalScissor), - }; -} -void set_logical_viewport(const gfx::Viewport& viewport) noexcept { - g_gxState.logicalViewport = viewport; - set_render_viewport(map_logical_viewport(viewport)); -} -void set_render_viewport(const gfx::Viewport& viewport) noexcept { g_gxState.renderViewport = viewport; } -void set_logical_scissor(const gfx::ClipRect& scissor) noexcept { - g_gxState.logicalScissor = scissor; - set_render_scissor(map_logical_scissor(scissor)); -} -void set_render_scissor(const gfx::ClipRect& scissor) noexcept { g_gxState.renderScissor = scissor; } -} // namespace aurora::gx - -// --- Shader/pipeline stubs --- -namespace aurora::gx { -void populate_pipeline_config(PipelineConfig& config, GXPrimitive primitive, GXVtxFmt fmt) noexcept { - // No-op for tests -} -GXBindGroups build_bind_groups(const ShaderInfo& info) noexcept { return {}; } -void resolve_sampled_textures(const ShaderInfo& info) noexcept {} -u8 color_channel(GXChannelID id) noexcept { return 0; } -u8 comp_type_size(GXAttr attr, GXCompType type) noexcept { - if (!s_useRealVertexFormatHelpers) { - return 0; - } - switch (attr) { - case GX_VA_PNMTXIDX: - case GX_VA_TEX0MTXIDX: - case GX_VA_TEX1MTXIDX: - case GX_VA_TEX2MTXIDX: - case GX_VA_TEX3MTXIDX: - case GX_VA_TEX4MTXIDX: - case GX_VA_TEX5MTXIDX: - case GX_VA_TEX6MTXIDX: - case GX_VA_TEX7MTXIDX: - return 1; - case GX_VA_CLR0: - case GX_VA_CLR1: - switch (type) { - case GX_RGB565: - case GX_RGBA4: - return 2; - case GX_RGB8: - case GX_RGBA6: - return 3; - case GX_RGBX8: - case GX_RGBA8: - return 4; - default: - return 0; - } - default: - switch (type) { - case GX_U8: - case GX_S8: - return 1; - case GX_U16: - case GX_S16: - return 2; - case GX_F32: - return 4; - default: - return 0; - } - } -} -u8 comp_cnt_count(GXAttr attr, GXCompCnt cnt) noexcept { - if (!s_useRealVertexFormatHelpers) { - return 0; - } - switch (attr) { - case GX_VA_PNMTXIDX: - case GX_VA_TEX0MTXIDX: - case GX_VA_TEX1MTXIDX: - case GX_VA_TEX2MTXIDX: - case GX_VA_TEX3MTXIDX: - case GX_VA_TEX4MTXIDX: - case GX_VA_TEX5MTXIDX: - case GX_VA_TEX6MTXIDX: - case GX_VA_TEX7MTXIDX: - return 1; - case GX_VA_POS: - return cnt == GX_POS_XY ? 2 : cnt == GX_POS_XYZ ? 3 : 0; - case GX_VA_NRM: - return cnt == GX_NRM_XYZ ? 3 : (cnt == GX_NRM_NBT || cnt == GX_NRM_NBT3) ? 9 : 0; - case GX_VA_CLR0: - case GX_VA_CLR1: - return 1; - case GX_VA_TEX0: - case GX_VA_TEX1: - case GX_VA_TEX2: - case GX_VA_TEX3: - case GX_VA_TEX4: - case GX_VA_TEX5: - case GX_VA_TEX6: - case GX_VA_TEX7: - return cnt == GX_TEX_S ? 1 : cnt == GX_TEX_ST ? 2 : 0; - default: - return 0; - } -} -} // namespace aurora::gx - -// --- Buffer push stubs --- -namespace aurora::gfx { -Range push_verts(const uint8_t* data, size_t length) { - s_lastPushedVertices.assign(data, data + length); - return {}; -} -Range push_indices(const uint8_t* data, size_t length) { - CHECK(length % sizeof(uint16_t) == 0, "unaligned test index upload"); - s_lastPushedIndices.resize(length / sizeof(uint16_t)); - std::memcpy(s_lastPushedIndices.data(), data, length); - return {}; -} -Range push_uniform(const uint8_t* data, size_t length) { return {}; } -Range push_storage(const uint8_t* data, size_t length) { return {}; } -std::pair map_uniform(size_t length) { - s_uniformAllocations.emplace_back(length, 0); - auto& uniformBytes = s_uniformAllocations.back(); - return {ByteBuffer{uniformBytes.data(), uniformBytes.size()}, - Range{static_cast(s_uniformAllocations.size() - 1), - static_cast(length)}}; -} -std::pair copy_uniform(Range source) { - return map_uniform(source.size); -} -uint32_t align_uniform(uint32_t value) { return (value + 255u) & ~255u; } -uint64_t staging_uniform_bytes(uint64_t value) { return staging_padded(value, 256); } -uint64_t staging_storage_bytes(uint64_t value) { return staging_padded(value, 256); } -bool staging_has_space(const StagingSizes&) { - if (!s_stagingAdmissionsBeforeRefusal) return true; - if (*s_stagingAdmissionsBeforeRefusal > 0) { - --*s_stagingAdmissionsBeforeRefusal; - return true; - } - // Refuse once, as a full batch would; the split that follows makes room again. - s_stagingAdmissionsBeforeRefusal.reset(); - s_stagingRefused = true; - return false; -} -void split_staging_batch() { - if (!s_stagingRefused) throw StagingCapacityError("Unexpected split in FIFO unit test"); - s_stagingRefused = false; - ++s_stagingSplitCount; -} -uint64_t staging_split_count() noexcept { return s_stagingSplitCount; } - -Vec2 get_render_target_size() noexcept { return s_renderTargetSize; } -Vec2 get_frame_buffer_size() noexcept { return s_renderTargetSize; } -uint32_t current_frame() noexcept { return s_currentFrame; } -// The command processor keys its resolved-pipeline memo on this. The test build never changes -// render targets, so a fixed single-sample target matches what pipeline_ref would produce. -uint32_t get_sample_count() noexcept { return 1; } -void set_viewport(const Viewport& viewport) noexcept {} -void set_scissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) noexcept {} -} // namespace aurora::gfx - -namespace aurora::gfx::testing { -void set_current_frame(uint32_t frame) noexcept { s_currentFrame = frame; } - -void reset_vertex_push_record() noexcept { - s_lastPushedVertices.clear(); - s_lastPushedIndices.clear(); - s_lastGxDraw.reset(); - s_trackDrawCommands = false; - g_mergedDrawCallCount = 0; -} -const std::vector& last_pushed_vertices() noexcept { - return s_lastPushedVertices; -} -const std::vector& last_pushed_indices() noexcept { - return s_lastPushedIndices; -} -void reset_uniform_allocations() noexcept { - s_uniformAllocations.clear(); -} -const std::vector& uniform_allocation(size_t index) noexcept { - CHECK(index < s_uniformAllocations.size(), "uniform test allocation {} out of range {}", index, - s_uniformAllocations.size()); - return s_uniformAllocations[index]; -} -void use_draw_command_tracking(bool enabled) noexcept { - s_trackDrawCommands = enabled; - s_lastGxDraw.reset(); -} -void use_real_vertex_format_helpers(bool enabled) noexcept { - s_useRealVertexFormatHelpers = enabled; -} -void refuse_staging_admission_after(uint32_t admissions) noexcept { - s_stagingAdmissionsBeforeRefusal = admissions; - s_stagingRefused = false; -} -void reset_staging_capacity() noexcept { - s_stagingAdmissionsBeforeRefusal.reset(); - s_stagingRefused = false; - s_stagingSplitCount = 0; -} -} // namespace aurora::gfx::testing - -// --- Pipeline/draw command stubs --- -namespace aurora::gfx { -template <> -PipelineRef pipeline_ref(const clear::PipelineConfig& config) { - return 0; -} -template <> -void push_draw_command(clear::DrawData data) { - // No-op -} -template <> -PipelineRef pipeline_ref(const gx::PipelineConfig& config) { - return 0; -} -template <> -void push_draw_command(gx::DrawData data) { - if (s_trackDrawCommands) { - s_lastGxDraw = std::move(data); - } -} -template <> -gx::DrawData* get_last_draw_command() { - return s_trackDrawCommands && s_lastGxDraw.has_value() ? &*s_lastGxDraw : nullptr; -} -} // namespace aurora::gfx - -// --- TextureBind::get_descriptor --- -namespace aurora::gfx { -wgpu::SamplerDescriptor TextureBind::get_descriptor() const noexcept { return wgpu::SamplerDescriptor{}; } -} // namespace aurora::gfx - -// --- Texture creation/write/replacement stubs --- -namespace aurora::gfx { -namespace testing { -struct ResolvePassRecord { - TextureHandle texture; - ClipRect rect; - bool clearColor = false; - bool clearAlpha = false; - bool clearDepth = false; - Vec4 clearColorValue{0.f, 0.f, 0.f, 0.f}; - float clearDepthValue = 0.f; - GXTexFmt resolveFormat = GX_TF_RGBA8; - std::optional> sourceRectPixels; - bool halfScale = false; - std::array copyFilterCoefficients{0, 64, 0}; - bool forceOpaqueAlpha = false; - float copyFilterRowStride = 1.0f; - bool clampTop = false; - bool clampBottom = false; - bool persistentCopy = false; -}; - -namespace { -std::vector s_resolvePassRecords; -} // namespace - -void reset_resolve_pass_records() noexcept { s_resolvePassRecords.clear(); } - -const std::vector& resolve_pass_records() noexcept { return s_resolvePassRecords; } - -void set_framebuffer_sizes(uint32_t logicalWidth, uint32_t logicalHeight, - uint32_t targetWidth, uint32_t targetHeight) noexcept { - s_logicalFbSize = {logicalWidth, logicalHeight}; - s_renderTargetSize = {targetWidth, targetHeight}; -} -} // namespace testing - -TextureHandle new_static_texture_2d(uint32_t width, uint32_t height, uint32_t mips, u32 gxFormat, - ArrayRef data, bool tlut, const char* label) noexcept { - return {}; -} -TextureHandle new_dynamic_texture_2d(uint32_t width, uint32_t height, uint32_t mips, u32 gxFormat, - const char* label) noexcept { - return {}; -} -TextureHandle new_render_texture(uint32_t width, uint32_t height, u32 gxFormat, const char* label) noexcept { - return std::make_shared(wgpu::Texture{}, wgpu::TextureView{}, wgpu::TextureView{}, - wgpu::Extent3D{width, height, 1}, wgpu::TextureFormat::RGBA8Unorm, 1, gxFormat); -} -TextureHandle new_conv_texture(uint32_t width, uint32_t height, u32 gxFormat, const char* label) noexcept { - return std::make_shared(wgpu::Texture{}, wgpu::TextureView{}, wgpu::TextureView{}, - wgpu::Extent3D{width, height, 1}, wgpu::TextureFormat::RGBA8Unorm, 1, gxFormat); -} -void write_texture(const TextureRef& ref, ArrayRef data) noexcept {} -void resolve_pass(TextureHandle texture, ClipRect rect, bool clearColor, bool clearAlpha, bool clearDepth, - Vec4 clearColorValue, float clearDepthValue, GXTexFmt resolveFormat, - const Vec4* sourceRectPixels, bool halfScale, - const std::array* copyFilterCoefficients, bool forceOpaqueAlpha, - float copyFilterRowStride, bool clampTop, bool clampBottom, bool persistentCopy) { - testing::ResolvePassRecord record; - record.texture = std::move(texture); - record.rect = rect; - record.clearColor = clearColor; - record.clearAlpha = clearAlpha; - record.clearDepth = clearDepth; - record.clearColorValue = clearColorValue; - record.clearDepthValue = clearDepthValue; - record.resolveFormat = resolveFormat; - record.sourceRectPixels = sourceRectPixels != nullptr ? std::make_optional(*sourceRectPixels) : std::nullopt; - record.halfScale = halfScale; - record.copyFilterCoefficients = - copyFilterCoefficients != nullptr ? *copyFilterCoefficients : std::array{0, 64, 0}; - record.forceOpaqueAlpha = forceOpaqueAlpha; - record.copyFilterRowStride = copyFilterRowStride; - record.clampTop = clampTop; - record.clampBottom = clampBottom; - record.persistentCopy = persistentCopy; - testing::s_resolvePassRecords.push_back(std::move(record)); -} -void queue_palette_conv(tex_palette_conv::ConvRequest req) {} -void begin_offscreen(uint32_t width, uint32_t height) {} -void end_offscreen() {} -bool is_offscreen() noexcept { return false; } -} // namespace aurora::gfx - -namespace aurora::gfx::depth_peek { -namespace { -bool s_snapshotRequested = false; -uint32_t s_width = 0; -uint32_t s_height = 0; -std::vector s_data; -} // namespace - -void initialize() {} -void shutdown() {} -void request_snapshot() noexcept { s_snapshotRequested = true; } -void poll() noexcept {} -void encode_frame_snapshot(const wgpu::CommandEncoder& cmd, const wgpu::TextureView& depthView, - wgpu::Extent3D sourceSize, uint32_t msaaSamples) noexcept {} -void after_submit() noexcept {} - -bool read_latest(uint16_t x, uint16_t y, uint32_t& z) noexcept { - if (x >= s_width || y >= s_height || s_data.empty()) { - return false; - } - z = s_data[static_cast(y) * s_width + x] & 0x00ffffffu; - return true; -} - -namespace testing { -void reset() noexcept { - s_snapshotRequested = false; - s_width = 0; - s_height = 0; - s_data.clear(); -} - -bool snapshot_requested() noexcept { return s_snapshotRequested; } - -void set_latest(uint32_t width, uint32_t height, const std::vector& data) { - s_width = width; - s_height = height; - s_data = data; -} -} // namespace testing -} // namespace aurora::gfx::depth_peek - -namespace aurora::gfx::tex_copy_conv { -bool needs_conversion(GXTexFmt fmt) { return false; } -} // namespace aurora::gfx::tex_copy_conv - -namespace aurora::gfx::tex_palette_conv { -void queue(ConvRequest req) {} -} // namespace aurora::gfx::tex_palette_conv - -namespace aurora::gfx::texture_replacement { -u32 compute_texture_upload_size(const GXTexObj_& obj) noexcept { return 0; } -void register_tlut(const GXTlutObj*, const void*, GXTlutFmt, u16) noexcept {} -void load_tlut(const GXTlutObj*, u32) noexcept {} -std::optional find_replacement(const GXTexObj_&) noexcept { return std::nullopt; } -} // namespace aurora::gfx::texture_replacement - -// --- Window stub --- -#include "../lib/window.hpp" -namespace aurora::window { -AuroraWindowSize get_window_size() { return {640, 480, 640, 480, 640, 480, 1.0f}; } -void set_frame_buffer_aspect_fit(bool) {} -void set_force_aspect_16_9(bool) {} -} // namespace aurora::window - -// --- WebGPU C API stubs (prevent linker errors from wgpu:: destructors) --- -extern "C" { -void wgpuDeviceRelease(WGPUDevice) {} -void wgpuQueueRelease(WGPUQueue) {} -void wgpuSurfaceRelease(WGPUSurface) {} -void wgpuBufferRelease(WGPUBuffer) {} -void wgpuTextureRelease(WGPUTexture) {} -void wgpuTextureViewRelease(WGPUTextureView) {} -void wgpuSamplerRelease(WGPUSampler) {} -void wgpuShaderModuleRelease(WGPUShaderModule) {} -void wgpuRenderPipelineRelease(WGPURenderPipeline) {} -void wgpuBindGroupRelease(WGPUBindGroup) {} -void wgpuBindGroupLayoutRelease(WGPUBindGroupLayout) {} -void wgpuPipelineLayoutRelease(WGPUPipelineLayout) {} -void wgpuInstanceRelease(WGPUInstance) {} -void wgpuDeviceAddRef(WGPUDevice) {} -void wgpuQueueAddRef(WGPUQueue) {} -void wgpuSurfaceAddRef(WGPUSurface) {} -void wgpuBufferAddRef(WGPUBuffer) {} -void wgpuTextureAddRef(WGPUTexture) {} -void wgpuTextureViewAddRef(WGPUTextureView) {} -void wgpuInstanceAddRef(WGPUInstance) {} -} - -void aurora::gfx::push_debug_group(std::string) {} -void aurora_push_debug_group(const char*) {} -void aurora_pop_debug_group() {} -void aurora::gfx::insert_debug_marker(std::string) {} diff --git a/aurora-main/tests/metalfx_interop/CMakeLists.txt b/aurora-main/tests/metalfx_interop/CMakeLists.txt deleted file mode 100644 index 4f5330d..0000000 --- a/aurora-main/tests/metalfx_interop/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -cmake_minimum_required(VERSION 3.25) -project(metalfx_interop LANGUAGES CXX) - -if(NOT APPLE) - message(FATAL_ERROR "The MetalFX interoperability probe requires macOS") -endif() -enable_language(OBJCXX) -set(CMAKE_OBJCXX_STANDARD 20) -set(CMAKE_OBJCXX_STANDARD_REQUIRED ON) -set(CMAKE_OSX_DEPLOYMENT_TARGET 13.0) - -# Use the same Dawn package as Aurora; no separate download or renderer build. -find_package(Threads REQUIRED) -find_package(Dawn CONFIG REQUIRED) -add_executable(metalfx_interop main.mm ../../lib/webgpu/metalfx.mm) -target_include_directories(metalfx_interop PRIVATE ../../lib) -target_compile_options(metalfx_interop PRIVATE -fobjc-arc -Wall -Wextra) -target_link_libraries(metalfx_interop PRIVATE dawn::webgpu_dawn - "-framework MetalFX" "-framework Metal" "-framework IOSurface" "-framework Foundation") -enable_testing() -add_test(NAME metalfx_interop COMMAND metalfx_interop) -set_tests_properties(metalfx_interop PROPERTIES SKIP_RETURN_CODE 77 TIMEOUT 60) - -add_executable(metalfx_stub_test stub_test.cpp ../../lib/webgpu/metalfx_stub.cpp) -target_include_directories(metalfx_stub_test PRIVATE ../../lib) -target_compile_features(metalfx_stub_test PRIVATE cxx_std_20) -target_link_libraries(metalfx_stub_test PRIVATE dawn::webgpu_dawn) -add_test(NAME metalfx_stub COMMAND metalfx_stub_test) diff --git a/aurora-main/tests/metalfx_interop/README.md b/aurora-main/tests/metalfx_interop/README.md deleted file mode 100644 index 21a3a95..0000000 --- a/aurora-main/tests/metalfx_interop/README.md +++ /dev/null @@ -1,124 +0,0 @@ -# MetalFX spatial upscaling: renderer integration and tests - -Aurora can now upscale the completed game image with MetalFX before aspect-fit -presentation and ImGui composition. It is opt-in and requires macOS 13+, a -supported Metal device, and Dawn IOSurface/shared-event support. Other backends -and builds without the MetalFX SDK use a stub and the existing presentation path. -The MetalFX framework is weak-linked; the game's deployment target is unchanged. - -## Trying the renderer integration - -Use F10 → Graphics → MetalFX spatial upscaling. Then use the existing -Resolution control to render below the output viewport's size. -Both source dimensions must be smaller than the output dimensions. Equal-size -rendering, supersampling, and unsupported source formats bypass MetalFX. In -particular, Auto (window size) generally offers no upscaling opportunity. - -The F10 toggle is saved in `Config.toml` as -`video.metalfx_spatial_upscaling`. It uses these thread-safe Aurora entry points: - -- `aurora_set_metalfx_spatial(bool)` requests a change at the next sealed frame. -- `aurora_get_metalfx_spatial()` returns the requested setting. -- `aurora_is_metalfx_spatial_supported()` reports device/build support. -- `aurora_get_metalfx_status()` distinguishes Disabled, Unsupported, - Not Upscaling, Active, and Error. A busy resize-retirement pool temporarily - bypasses upscaling and retries on a later frame. Other upscaler errors log a - reason and use normal presentation until a disabled frame resets the error. - -The game's HUD is part of the source image and is upscaled. ImGui/F10/FPS overlays -are composed afterward at output resolution. Existing source-frame captures -still capture the original source image. The interpolation snapshot call sites -all use the same upscaling hook; game-specific interpolation remains untested. - -## GPU path and ownership - -1. Request Dawn's `SharedTextureMemoryIOSurface` and `SharedFenceMTLSharedEvent` - features when the Metal adapter supports both. Use that Dawn device's native - `MTLDevice`, not a separately selected default device. -2. Cache MaxInterpolatedFrames + 1 upscaling slots with IOSurface-backed input and output textures, - a spatial scaler, a private MetalFX output, and shared-event dependencies. - Check texture formats, dimensions, usages, and device size limits on creation. -3. Begin Dawn input access, copy the completed game image at its source size, - and submit the scene plus copy. End input access and wait for Dawn's - `commandsScheduledFuture` before submitting dependent native Metal work. -4. On the native queue, wait for input rendering and any prior Dawn consumption - of the shared output. Encode MetalFX into its required **private** output - texture, then GPU-blit the result into the output IOSurface and signal an event. -5. After native scheduling, begin Dawn output access with that event/value. - Composite the upscaled image into the existing content viewport, retaining - letterboxing, then draw ImGui. Submit and end output access. Reuse observes - both Dawn-to-Metal and Metal-to-Dawn event dependencies. -6. GPU completion callbacks retain resources after a cache entry is replaced, - disabled, or shut down. At most eight resource sets may exist (four current - plus four retiring); rapid resizing cannot allocate an unbounded queue. - -CPU scheduling waits remain, but there are no CPU image transfers or per-frame -GPU-completion waits in the upscaling path. There is one source-size GPU copy -and one full-output GPU blit. Their cost must be measured before promising a -performance gain. The input copy follows the existing perceptual/unorm sampling -path. sRGB texture formats bypass MetalFX to avoid implicit color conversion. - -## Standalone GPU regression test - -The test builds the actual `lib/webgpu/metalfx.mm` implementation. Point -`Dawn_DIR` at the package used by an existing Aurora build: - -```sh -cmake -S aurora-main/tests/metalfx_interop -B build-metalfx-interop \ - -DDawn_DIR="/absolute/path/to/dawn_prebuilt-src/lib/cmake/Dawn" \ - -DCMAKE_BUILD_TYPE=Release -cmake --build build-metalfx-interop -MTL_DEBUG_LAYER=1 MTL_SHADER_VALIDATION=1 \ - ctest --test-dir build-metalfx-interop --output-on-failure -V -``` - -The GPU test returns 77 (CTest **Skipped**) when no Metal adapter, required -sharing features, or spatial scaler is available. A skip is not evidence of -interoperability. Sandboxed processes may need GPU access. CTest imposes a -60-second timeout. The separate stub test needs no GPU. - -Tested on Apple M3, macOS 26.5.1, using Aurora's existing Dawn package -(`v20260603.191052`). Metal API and GPU validation were enabled: - -| Formats | Input | Output | Frames per format | -| --- | --- | --- | --- | -| RGBA8Unorm, BGRA8Unorm | 64 × 48 | 128 × 96 | 24 | -| RGBA8Unorm, BGRA8Unorm | 320 × 180 | 480 × 270 | 24 | -| RGBA8Unorm, BGRA8Unorm | 960 × 540 | 1920 × 1080 | 24 | - -All 144 frames and 2,304 interior pixel samples passed. Red changes per frame; -green and blue distinguish left/right and top/bottom. All channels are checked -within five 8-bit levels, catching stale images, orientation/channel mistakes, -and missing output. Tests cover 1.5× and 2× scaling, padded readback rows, slot -reuse, dropping wrappers before readback completion, invalid dimensions/sRGB -formats, the eight-set allocation bound, and the unavailable-backend stub. - -Readback is only the test oracle and is absent from the game upscaling path. -These samples do not measure reconstruction quality at edges or race performance. - -## Windowed presentation test - -This optional target exercises Aurora's actual frame submission and presentation -with a synthetic source and an ImGui overlay. It requires no Wii game data and -creates an automatically closing test window. Add the option to an existing -from-source runtime build (the normal dependency/provider options still apply): - -```sh -cmake -S runtime -B build-macos -DCMAKE_BUILD_TYPE=Release \ - -DAURORA_BUILD_METALFX_PRESENTATION_TEST=ON -cmake --build build-macos --target metalfx_presentation_test -MTL_DEBUG_LAYER=1 MTL_SHADER_VALIDATION=1 \ - ./build-macos/aurora-build/metalfx_presentation_test -``` - -On the same M3, all 84 frames passed with Metal API/GPU validation: disabled, -enabled, window resize, 4:3/16:9 aspect changes, native-size bypass, disable, and -re-enable. Assertions check renderer status and errors; this is not a pixel-level -verification of the window image. The core build and macOS 12 deployment-target -availability compilation also passed. Full Mario Kart gameplay, race performance, -visual quality, Intel Macs, other Apple GPUs, older macOS runtime versions, and -non-macOS full builds remain untested. - -References: [Apple MetalFX](https://developer.apple.com/documentation/metalfx), -[spatial scaler requirements](https://developer.apple.com/documentation/metalfx/mtlfxspatialscaler), -and the installed Dawn `MetalBackend.h` / `webgpu_cpp.h` APIs. diff --git a/aurora-main/tests/metalfx_interop/main.mm b/aurora-main/tests/metalfx_interop/main.mm deleted file mode 100644 index 5e62e25..0000000 --- a/aurora-main/tests/metalfx_interop/main.mm +++ /dev/null @@ -1,269 +0,0 @@ -#import -#import -#import -#include "webgpu/metalfx.hpp" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { -constexpr uint64_t kTimeoutNs = 10'000'000'000; -constexpr unsigned kFrames = 24; -std::atomic g_errors{0}; - -void require(bool condition, const char* message) { - if (!condition) throw std::runtime_error(message); -} - -void wait(const wgpu::Instance& instance, wgpu::Future future) { - require(instance.WaitAny(future, kTimeoutNs) == wgpu::WaitStatus::Success, - "Dawn operation timed out or failed"); -} - -void runCase(const wgpu::Instance& instance, const wgpu::Device& device, - bool bgra, uint32_t width, uint32_t height, - uint32_t outWidth, uint32_t outHeight) { - const auto format = bgra ? wgpu::TextureFormat::BGRA8Unorm : wgpu::TextureFormat::RGBA8Unorm; - using namespace aurora::webgpu::metalfx; - std::array, 3> slots; - for (auto& slot : slots) { - std::string error; - slot = create(instance, device, {width, height, outWidth, outHeight, format}, error); - if (!slot) { - throw std::runtime_error(error.empty() - ? "MetalFX resource pool was still busy retiring earlier slots" - : error); - } - } - - // Asymmetric quadrants expose channel swaps, vertical flips, and stale frames. - wgpu::ShaderSourceWGSL source{}; - source.code = R"( - @group(0) @binding(0) var params: vec4f; - @vertex fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f { - let p = array(vec2f(-1, -1), vec2f(3, -1), vec2f(-1, 3)); - return vec4f(p[i], 0, 1); - } - @fragment fn fs(@builtin(position) p: vec4f) -> @location(0) vec4f { - return vec4f(params.x, select(0.2, 0.8, p.x >= params.y / 2), - select(0.3, 0.7, p.y >= params.z / 2), 1); - } - )"; - wgpu::ShaderModuleDescriptor shaderDescriptor{}; - shaderDescriptor.nextInChain = &source; - auto shader = device.CreateShaderModule(&shaderDescriptor); - wgpu::ColorTargetState target{}; - target.format = format; - wgpu::FragmentState fragment{}; - fragment.module = shader; - fragment.entryPoint = "fs"; - fragment.targetCount = 1; - fragment.targets = ⌖ - wgpu::RenderPipelineDescriptor pipelineDescriptor{}; - pipelineDescriptor.vertex.module = shader; - pipelineDescriptor.vertex.entryPoint = "vs"; - pipelineDescriptor.fragment = &fragment; - auto pipeline = device.CreateRenderPipeline(&pipelineDescriptor); - auto dawnQueue = device.GetQueue(); - const uint32_t bytesPerRow = (outWidth * 4 + 255) & ~255u; - const uint64_t readbackSize = uint64_t(bytesPerRow) * outHeight; - std::vector readbacks; - - for (unsigned frame = 0; frame < kFrames; ++frame) { - auto& slot = slots[frame % slots.size()]; - require(slot->begin_input(), "Production MetalFX begin_input failed"); - const std::array params{0.2f + float(frame % 5) * 0.1f, - float(width), float(height), 0}; - wgpu::BufferDescriptor uniformDescriptor{}; - uniformDescriptor.size = sizeof(params); - uniformDescriptor.usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst; - auto uniform = device.CreateBuffer(&uniformDescriptor); - dawnQueue.WriteBuffer(uniform, 0, params.data(), sizeof(params)); - wgpu::BindGroupEntry entry{}; - entry.binding = 0; - entry.buffer = uniform; - entry.size = sizeof(params); - wgpu::BindGroupDescriptor bindDescriptor{}; - bindDescriptor.layout = pipeline.GetBindGroupLayout(0); - bindDescriptor.entryCount = 1; - bindDescriptor.entries = &entry; - auto bindGroup = device.CreateBindGroup(&bindDescriptor); - auto encoder = device.CreateCommandEncoder(); - wgpu::RenderPassColorAttachment attachment{}; - attachment.view = slot->input_view(); - attachment.loadOp = wgpu::LoadOp::Clear; - attachment.storeOp = wgpu::StoreOp::Store; - wgpu::RenderPassDescriptor passDescriptor{}; - passDescriptor.colorAttachmentCount = 1; - passDescriptor.colorAttachments = &attachment; - auto pass = encoder.BeginRenderPass(&passDescriptor); - pass.SetPipeline(pipeline); - pass.SetBindGroup(0, bindGroup); - pass.Draw(3); - pass.End(); - auto render = encoder.Finish(); - dawnQueue.Submit(1, &render); - if (!slot->upscale()) throw std::runtime_error(slot->error()); - - wgpu::BufferDescriptor readbackDescriptor{}; - readbackDescriptor.size = readbackSize; - readbackDescriptor.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::MapRead; - auto readback = device.CreateBuffer(&readbackDescriptor); - encoder = device.CreateCommandEncoder(); - wgpu::TexelCopyTextureInfo copySource{}; - copySource.texture = slot->output_texture(); - wgpu::TexelCopyBufferInfo destination{}; - destination.buffer = readback; - destination.layout.bytesPerRow = bytesPerRow; - destination.layout.rowsPerImage = outHeight; - const wgpu::Extent3D extent{outWidth, outHeight, 1}; - encoder.CopyTextureToBuffer(©Source, &destination, &extent); - auto copy = encoder.Finish(); - dawnQueue.Submit(1, ©); - if (!slot->end_output()) throw std::runtime_error(slot->error()); - readbacks.push_back(std::move(readback)); - } - - // Model toggle/resize immediately after submission, while either queue may - // still be consuming these textures. Production completion callbacks must - // keep the resources alive after the cache drops its wrappers. - slots = {}; - - // Readback is only the test oracle. No CPU image transfer or GPU completion - // wait occurs between Dawn rendering, MetalFX, and Dawn consumption above. - for (unsigned frame = 0; frame < kFrames; ++frame) { - bool mapped = false; - auto& readback = readbacks[frame]; - wait(instance, readback.MapAsync(wgpu::MapMode::Read, 0, readbackSize, - wgpu::CallbackMode::WaitAnyOnly, [&mapped](wgpu::MapAsyncStatus status, wgpu::StringView) { - mapped = status == wgpu::MapAsyncStatus::Success; - })); - require(mapped, "Output readback mapping failed"); - const auto* bytes = static_cast(readback.GetConstMappedRange()); - require(bytes != nullptr, "Output readback pointer is null"); - for (unsigned y = 0; y < 4; ++y) { - for (unsigned x = 0; x < 4; ++x) { - const unsigned px = (2 * x + 1) * outWidth / 8; - const unsigned py = (2 * y + 1) * outHeight / 8; - const auto* pixel = bytes + py * bytesPerRow + px * 4; - const std::array expected{ - 0.2f + float(frame % 5) * 0.1f, x >= 2 ? 0.8f : 0.2f, - y >= 2 ? 0.7f : 0.3f, 1}; - for (unsigned c = 0; c < 4; ++c) { - const unsigned channel = bgra && c != 1 && c != 3 ? 2 - c : c; - if (std::abs(int(pixel[channel]) - int(std::lround(expected[c] * 255))) > 5) { - std::cerr << "Pixel mismatch: frame=" << frame << " x=" << px << " y=" << py - << " channel=" << c << " actual=" << int(pixel[channel]) - << " expected=" << std::lround(expected[c] * 255) << '\n'; - throw std::runtime_error("MetalFX output failed image validation"); - } - } - } - } - readback.Unmap(); - } - require(g_errors.load() == 0, "Dawn reported validation errors or device loss"); - std::cout << "PASS " << (bgra ? "BGRA8" : "RGBA8") << ' ' << width << 'x' << height - << " -> " << outWidth << 'x' << outHeight << ": " << kFrames - << " frames, 3 reused slots, 16 pixel samples/frame\n"; -} - -int run() { - const wgpu::InstanceFeatureName timedWait = wgpu::InstanceFeatureName::TimedWaitAny; - wgpu::InstanceDescriptor instanceDescriptor{}; - instanceDescriptor.requiredFeatureCount = 1; - instanceDescriptor.requiredFeatures = &timedWait; - auto instance = wgpu::CreateInstance(&instanceDescriptor); - require(instance != nullptr, "Dawn instance creation failed"); - wgpu::Adapter adapter; - wgpu::RequestAdapterOptions options{}; - options.backendType = wgpu::BackendType::Metal; - wait(instance, instance.RequestAdapter(&options, wgpu::CallbackMode::WaitAnyOnly, - [&adapter](wgpu::RequestAdapterStatus status, wgpu::Adapter result, wgpu::StringView message) { - if (status == wgpu::RequestAdapterStatus::Success) adapter = std::move(result); - else std::cerr << "Adapter: " << std::string_view(message) << '\n'; - })); - if (!adapter) { std::cout << "SKIP: no Dawn Metal adapter\n"; return 77; } - const std::array features{wgpu::FeatureName::SharedTextureMemoryIOSurface, - wgpu::FeatureName::SharedFenceMTLSharedEvent}; - for (auto feature : features) { - if (!adapter.HasFeature(feature)) { - std::cout << "SKIP: Dawn adapter lacks IOSurface/shared-event interoperability\n"; - return 77; - } - } - wgpu::DeviceDescriptor descriptor{}; - descriptor.requiredFeatureCount = features.size(); - descriptor.requiredFeatures = features.data(); - descriptor.SetUncapturedErrorCallback( - [](const wgpu::Device&, wgpu::ErrorType, wgpu::StringView message) { - ++g_errors; - std::cerr << "Dawn error: " << std::string_view(message) << '\n'; - }); - descriptor.SetDeviceLostCallback(wgpu::CallbackMode::AllowSpontaneous, - [](const wgpu::Device&, wgpu::DeviceLostReason reason, wgpu::StringView message) { - if (reason != wgpu::DeviceLostReason::Destroyed) { - ++g_errors; - std::cerr << "Device lost: " << std::string_view(message) << '\n'; - } - }); - wgpu::Device device; - wait(instance, adapter.RequestDevice(&descriptor, wgpu::CallbackMode::WaitAnyOnly, - [&device](wgpu::RequestDeviceStatus status, wgpu::Device result, wgpu::StringView message) { - if (status == wgpu::RequestDeviceStatus::Success) device = std::move(result); - else std::cerr << "Device: " << std::string_view(message) << '\n'; - })); - require(device != nullptr, "Dawn device creation failed"); - id native = dawn::native::metal::GetMTLDevice(device.Get()); - require(native != nil, "Dawn native Metal device is unavailable"); - std::cout << "GPU: " << native.name.UTF8String << '\n'; - if (!aurora::webgpu::metalfx::supported(device, wgpu::BackendType::Metal)) { - std::cout << "SKIP: GPU does not support MetalFX spatial scaling\n"; - return 77; - } - require(!aurora::webgpu::metalfx::supported(device, wgpu::BackendType::Vulkan), - "MetalFX must reject non-Metal backends"); - std::string error; - require(!aurora::webgpu::metalfx::create(instance, device, - {128, 96, 128, 96, wgpu::TextureFormat::RGBA8Unorm}, error) && !error.empty(), - "MetalFX must reject equal-size input/output"); - require(!aurora::webgpu::metalfx::create(instance, device, - {128, 96, 256, 192, wgpu::TextureFormat::RGBA8UnormSrgb}, error), - "MetalFX must reject implicit sRGB conversion"); - { - using namespace aurora::webgpu::metalfx; - std::array, 8> resources; - for (auto& scaler : resources) { - scaler = create(instance, device, {64, 48, 128, 96, wgpu::TextureFormat::RGBA8Unorm}, error); - require(scaler != nullptr, "Could not fill the MetalFX resource pool"); - } - require(!create(instance, device, {64, 48, 128, 96, wgpu::TextureFormat::RGBA8Unorm}, error) - && error.empty(), "A full retirement pool must defer allocation without a fatal error"); - } - for (bool bgra : {false, true}) { - runCase(instance, device, bgra, 64, 48, 128, 96); - runCase(instance, device, bgra, 320, 180, 480, 270); - runCase(instance, device, bgra, 960, 540, 1920, 1080); - } - return 0; -} -} // namespace - -int main() { - @autoreleasepool { - try { return run(); } - catch (const std::exception& error) { - std::cerr << "FAIL: " << error.what() << '\n'; - return 1; - } - } -} diff --git a/aurora-main/tests/metalfx_interop/presentation_test.cpp b/aurora-main/tests/metalfx_interop/presentation_test.cpp deleted file mode 100644 index 244f746..0000000 --- a/aurora-main/tests/metalfx_interop/presentation_test.cpp +++ /dev/null @@ -1,124 +0,0 @@ -// Explicitly opted-in windowed test of Aurora's real frame/presentation path. -// No Wii game data is needed; the source override supplies a synthetic image. -#include -#include -#include - -#include "webgpu/gpu.hpp" -#include "window.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { -std::atomic g_errors{0}; - -void log_message(AuroraLogLevel level, const char* module, const char* message, unsigned len) { - if (level >= LOG_ERROR) ++g_errors; - if (level >= LOG_WARNING || std::string_view(message, len).find("MetalFX") != std::string_view::npos) - std::fprintf(stderr, "[%s] %.*s\n", module, static_cast(len), message); - if (level == LOG_FATAL) std::abort(); -} - -void require(bool value, const char* message) { - if (!value) throw std::runtime_error(message); -} - -void draw_frames(uint32_t width, uint32_t height, AuroraMetalFXStatus expected) { - using namespace aurora::webgpu; - auto source = create_render_texture(width, height, false); - auto bindGroup = create_copy_bind_group(source); - std::vector pixels(size_t(width) * height); - for (uint32_t y = 0; y < height; ++y) { - for (uint32_t x = 0; x < width; ++x) { - pixels[size_t(y) * width + x] = 0xff000000u | ((x / 16 % 2) ? 0x00bb55u : 0xbb5500u); - } - } - wgpu::TexelCopyTextureInfo target{}; - target.texture = source.texture; - wgpu::TexelCopyBufferLayout layout{}; - layout.bytesPerRow = width * 4; - layout.rowsPerImage = height; - g_queue.WriteTexture(&target, pixels.data(), pixels.size() * sizeof(uint32_t), &layout, &source.size); - - unsigned rendered = 0; - unsigned matchingStatus = 0; - for (unsigned attempt = 0; attempt < 300 && rendered < 12; ++attempt) { - aurora_update(); - if (!aurora_begin_frame()) { SDL_Delay(5); continue; } - set_present_source_override(bindGroup, source.texture, source.size, source.format); - ImGui::SetNextWindowPos(ImVec2(12, 12), ImGuiCond_Always); - ImGui::Begin("MetalFX presentation test", nullptr, ImGuiWindowFlags_AlwaysAutoResize); - ImGui::TextUnformatted("Output-resolution overlay after game upscaling"); - ImGui::Text("Source: %u x %u", width, height); - ImGui::End(); - aurora_end_frame(); - aurora_wait_for_frame_worker(); - const auto status = aurora_get_metalfx_status(); - require(status != AURORA_METALFX_ERROR, "MetalFX reported a presentation error"); - if (status == expected) ++matchingStatus; - ++rendered; - } - require(rendered == 12 && matchingStatus >= 9, "Presentation did not reach the expected MetalFX state"); - require(g_errors.load() == 0, "Aurora reported an error"); - std::printf("PASS presentation source=%ux%u status=%d frames=%u\n", width, height, expected, rendered); -} -} // namespace - -int main(int argc, char** argv) { - const auto cache = std::filesystem::temp_directory_path() / - ("aurora-metalfx-presentation-test-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count())); - std::filesystem::create_directories(cache); - const auto path = cache.string(); - AuroraConfig config{}; - config.appName = "MetalFX presentation test"; - config.userPath = path.c_str(); - config.cachePath = path.c_str(); - config.resourcesPath = path.c_str(); - config.desiredBackend = BACKEND_METAL; - config.windowWidth = 640; - config.windowHeight = 480; - config.msaa = 1; - config.maxTextureAnisotropy = 1; - config.logCallback = log_message; - config.logLevel = LOG_INFO; - aurora_initialize(argc, argv, &config); - int result = 0; - try { - if (!aurora_is_metalfx_spatial_supported()) { - std::puts("SKIP: MetalFX spatial scaling is unavailable"); - result = 77; - } else { - aurora::window::lock_present_aspect_ratio(4, 3); - aurora_set_metalfx_spatial(false); - require(!aurora_get_metalfx_spatial(), "Disable request was not retained"); - draw_frames(320, 240, AURORA_METALFX_DISABLED); - aurora_set_metalfx_spatial(true); - require(aurora_get_metalfx_spatial(), "Enable request was not retained"); - draw_frames(320, 240, AURORA_METALFX_ACTIVE); - aurora::window::set_window_size(800, 500); - draw_frames(320, 240, AURORA_METALFX_ACTIVE); - aurora::window::lock_present_aspect_ratio(16, 9); - draw_frames(320, 240, AURORA_METALFX_ACTIVE); - const auto output = aurora::window::get_window_size(); - draw_frames(output.native_fb_width, output.native_fb_height, AURORA_METALFX_NOT_UPSCALING); - aurora_set_metalfx_spatial(false); - draw_frames(320, 240, AURORA_METALFX_DISABLED); - aurora_set_metalfx_spatial(true); - draw_frames(320, 240, AURORA_METALFX_ACTIVE); - } - } catch (const std::exception& error) { - std::fprintf(stderr, "FAIL: %s\n", error.what()); - result = 1; - } - aurora_shutdown(); - std::error_code cleanupError; - std::filesystem::remove_all(cache, cleanupError); - return result; -} diff --git a/aurora-main/tests/metalfx_interop/stub_test.cpp b/aurora-main/tests/metalfx_interop/stub_test.cpp deleted file mode 100644 index fc4bc8d..0000000 --- a/aurora-main/tests/metalfx_interop/stub_test.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "webgpu/metalfx.hpp" - -int main() { - using namespace aurora::webgpu::metalfx; - if (supported({}, wgpu::BackendType::Vulkan) || supported({}, wgpu::BackendType::Metal)) return 1; - std::string error; - if (create({}, {}, {640, 480, 1280, 960, wgpu::TextureFormat::RGBA8Unorm}, error)) return 1; - return error.empty() ? 1 : 0; -} diff --git a/aurora-main/tests/os_alloc_test.cpp b/aurora-main/tests/os_alloc_test.cpp deleted file mode 100644 index 2811210..0000000 --- a/aurora-main/tests/os_alloc_test.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include - -#include - -#include -#include - -namespace { - -constexpr std::size_t kArenaBytes = 64 * 1024; - -std::array gArena{}; - -void resetAllocator(int maxHeaps = 8) { - std::fill(gArena.begin(), gArena.end(), 0); - void* start = gArena.data(); - void* end = gArena.data() + gArena.size(); - ASSERT_NE(OSInitAlloc(start, end, maxHeaps), nullptr); - EXPECT_EQ(OSSetCurrentHeap(-1), -1); -} - -} // namespace - -TEST(OSAlloc, InitCreateAllocFreeCheck) { - resetAllocator(); - - OSHeapHandle heap = OSCreateHeap(gArena.data() + 512, gArena.data() + 4096); - ASSERT_GE(heap, 0); - - EXPECT_EQ(OSSetCurrentHeap(heap), -1); - - void* p = OSAllocFromHeap(heap, 96); - ASSERT_NE(p, nullptr); - EXPECT_EQ(reinterpret_cast(p) & 31u, 0u); - EXPECT_GE(OSReferentSize(p), 96u); - - s32 freeBefore = OSCheckHeap(heap); - EXPECT_GE(freeBefore, 0); - - OSFreeToHeap(heap, p); - s32 freeAfter = OSCheckHeap(heap); - EXPECT_GE(freeAfter, freeBefore); -} - -TEST(OSAlloc, AddToHeapMakesSpaceAvailable) { - resetAllocator(); - - OSHeapHandle heap = OSCreateHeap(gArena.data() + 0x1000, gArena.data() + 0x2000); - ASSERT_GE(heap, 0); - - void* p1 = OSAllocFromHeap(heap, 0xD00); - ASSERT_NE(p1, nullptr); - - void* p2 = OSAllocFromHeap(heap, 0x400); - EXPECT_EQ(p2, nullptr); - - OSAddToHeap(heap, gArena.data() + 0x3000, gArena.data() + 0x3800); - - p2 = OSAllocFromHeap(heap, 0x400); - EXPECT_NE(p2, nullptr); -} - -TEST(OSAlloc, AllocFixedCarvesRangeFromHeap) { - resetAllocator(); - - OSHeapHandle heap = OSCreateHeap(gArena.data() + 0x2000, gArena.data() + 0x5000); - ASSERT_GE(heap, 0); - - s32 freeBefore = OSCheckHeap(heap); - ASSERT_GT(freeBefore, 0); - - void* fixed = OSAllocFixed(gArena.data() + 0x3000, gArena.data() + 0x3400); - ASSERT_NE(fixed, nullptr); - - s32 freeAfter = OSCheckHeap(heap); - EXPECT_GE(freeBefore, freeAfter); -} - -TEST(OSAlloc, SetCurrentHeapReturnsPrevious) { - resetAllocator(); - - OSHeapHandle heapA = OSCreateHeap(gArena.data() + 0x1000, gArena.data() + 0x2000); - OSHeapHandle heapB = OSCreateHeap(gArena.data() + 0x3000, gArena.data() + 0x4000); - ASSERT_GE(heapA, 0); - ASSERT_GE(heapB, 0); - - EXPECT_EQ(OSSetCurrentHeap(heapA), -1); - EXPECT_EQ(OSSetCurrentHeap(heapB), heapA); - - void* p = OSAlloc(128); - ASSERT_NE(p, nullptr); - OSFree(p); - - EXPECT_GE(OSCheckHeap(heapB), 0); -} - -TEST(OSAlloc, DestroyHeapInvalidatesHandle) { - resetAllocator(); - - OSHeapHandle heap = OSCreateHeap(gArena.data() + 0x1000, gArena.data() + 0x2000); - ASSERT_GE(heap, 0); - - OSDestroyHeap(heap); - EXPECT_LT(OSCheckHeap(heap), 0); - EXPECT_EQ(OSAllocFromHeap(heap, 64), nullptr); -} diff --git a/aurora-main/tests/os_test_globals.cpp b/aurora-main/tests/os_test_globals.cpp deleted file mode 100644 index 40e4355..0000000 --- a/aurora-main/tests/os_test_globals.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include - -namespace aurora { -AuroraConfig g_config{}; -} diff --git a/aurora-main/tests/renderer_regression_test.cpp b/aurora-main/tests/renderer_regression_test.cpp deleted file mode 100644 index 632cfdf..0000000 --- a/aurora-main/tests/renderer_regression_test.cpp +++ /dev/null @@ -1,199 +0,0 @@ -#include "gx_test_common.hpp" -#include "gfx/staging_map.hpp" -#include "gx/pipeline.hpp" - -#include - -using aurora::gx::g_gxState; - -namespace { -std::vector draw(GXPrimitive primitive, u16 count, GXVtxFmt format = GX_VTXFMT0) { - std::vector bytes{static_cast(primitive | format), static_cast(count >> 8), - static_cast(count)}; - bytes.resize(3 + count); - return bytes; -} -} - -TEST_F(GXFifoTest, MaximumQuadCountTerminatesWithoutOutOfRangeIndices) { - g_gxState.lastVtxFmt = GX_VTXFMT0; - g_gxState.lastVtxSize = 1; - for (const u16 count : {65532, 65533, 65534, 65535}) { - g_gxState.stateDirty = true; - decode_fifo(draw(GX_QUADS, count)); - const auto& indices = aurora::gfx::testing::last_pushed_indices(); - ASSERT_EQ(indices.size(), (count / 4) * 6 + (count % 4 == 3 ? 3 : 0)); - for (const auto index : indices) ASSERT_LT(index, count); - } -} - -TEST_F(GXFifoTest, IncompletePrimitivesNeverJoinAcrossDraws) { - g_gxState.lastVtxFmt = GX_VTXFMT0; - g_gxState.lastVtxSize = 1; - aurora::gfx::testing::use_draw_command_tracking(true); - decode_fifo(draw(GX_TRIANGLES, 4)); - EXPECT_EQ(aurora::gfx::testing::last_pushed_indices(), (std::vector{0, 1, 2})); - decode_fifo(draw(GX_TRIANGLES, 5)); - EXPECT_EQ(aurora::gfx::testing::last_pushed_indices(), (std::vector{4, 5, 6})); - const auto before = aurora::gfx::testing::last_pushed_indices(); - decode_fifo(draw(GX_TRIANGLEFAN, 2)); - EXPECT_EQ(aurora::gfx::testing::last_pushed_indices(), before); -} - -TEST_F(GXFifoTest, MergeStopsBeforeSixteenBitIndexOverflow) { - g_gxState.lastVtxFmt = GX_VTXFMT0; - g_gxState.lastVtxSize = 1; - aurora::gfx::testing::use_draw_command_tracking(true); - decode_fifo(draw(GX_TRIANGLES, 65535)); - decode_fifo(draw(GX_TRIANGLES, 3)); - EXPECT_EQ(aurora::gfx::g_mergedDrawCallCount, 0u); - EXPECT_EQ(aurora::gfx::testing::last_pushed_indices(), (std::vector{0, 1, 2})); -} - -TEST_F(GXFifoTest, VertexCacheInvalidationBreaksDrawMerging) { - g_gxState.lastVtxFmt = GX_VTXFMT0; - g_gxState.lastVtxSize = 1; - aurora::gfx::testing::use_draw_command_tracking(true); - decode_fifo(draw(GX_TRIANGLES, 3)); - decode_fifo({GX_CMD_INVL_VC}); - EXPECT_TRUE(g_gxState.stateDirty); - decode_fifo(draw(GX_TRIANGLES, 3)); - EXPECT_EQ(aurora::gfx::g_mergedDrawCallCount, 0u); -} - -TEST_F(GXFifoTest, EqualStrideVertexFormatChangeBreaksDrawMerging) { - aurora::gfx::testing::use_real_vertex_format_helpers(true); - g_gxState.vtxDesc[GX_VA_POS] = GX_DIRECT; - for (const auto format : {GX_VTXFMT0, GX_VTXFMT1}) { - g_gxState.vtxFmts[format].attrs[GX_VA_POS].cnt = GX_POS_XY; - g_gxState.vtxFmts[format].attrs[GX_VA_POS].type = GX_U8; - } - g_gxState.vtxFmts[GX_VTXFMT1].attrs[GX_VA_POS].frac = 1; - aurora::gfx::testing::use_draw_command_tracking(true); - for (const auto format : {GX_VTXFMT0, GX_VTXFMT1}) { - auto bytes = draw(GX_TRIANGLES, 3, format); - bytes.resize(9); - decode_fifo(bytes); - } - EXPECT_EQ(aurora::gfx::g_mergedDrawCallCount, 0u); -} - -TEST_F(GXFifoTest, SingleExpandedPrimitiveCannotMergeWithTriangles) { - g_gxState.lastVtxFmt = GX_VTXFMT0; - g_gxState.lastVtxSize = 1; - aurora::gfx::testing::use_draw_command_tracking(true); - decode_fifo(draw(GX_POINTS, 1)); - decode_fifo(draw(GX_TRIANGLES, 3)); - EXPECT_EQ(aurora::gfx::g_mergedDrawCallCount, 0u); - EXPECT_EQ(aurora::gfx::testing::last_pushed_indices(), (std::vector{0, 1, 2})); -} - -TEST_F(GXFifoTest, DisplayListSubmitsStagingWhenADrawDoesNotFit) { - __GXSetDirtyState(); - aurora::gx::fifo::clear_buffer(); - g_gxState.lastVtxFmt = GX_VTXFMT0; - g_gxState.lastVtxSize = 1; - // admitted=1 refuses the middle draw; admitted=2 refuses the last, so only a replay of the refused draw pushes 0x33. - for (const u32 admitted : {1u, 2u}) for (const bool bigEndian : {true, false}) { - std::vector list; - for (const u8 fill : {0x11, 0x22, 0x33}) { - auto bytes = draw(GX_TRIANGLES, 3); - if (!bigEndian) std::swap(bytes[1], bytes[2]); - std::fill(bytes.begin() + 3, bytes.end(), fill); - list.insert(list.end(), bytes.begin(), bytes.end()); - } - const auto splitsBefore = aurora::gfx::staging_split_count(); - aurora::gfx::testing::refuse_staging_admission_after(admitted); - if (bigEndian) GXCallDisplayList(list.data(), static_cast(list.size())); - else GXCallDisplayListLE(list.data(), static_cast(list.size())); - EXPECT_EQ(aurora::gfx::staging_split_count() - splitsBefore, 1u) - << "admitted=" << admitted << " bigEndian=" << bigEndian; - EXPECT_EQ(aurora::gfx::testing::last_pushed_vertices(), (std::vector{0x33, 0x33, 0x33})) - << "admitted=" << admitted << " bigEndian=" << bigEndian; - } -} - -TEST(StagingMapping, RetiredCallbacksCannotPublishAnotherBuffersReadiness) { - using namespace aurora::gfx; - StagingMapState state; - const auto old = state.request(); - EXPECT_EQ(state.request(), 0u); - state.reset(); - const auto current = state.request(); - EXPECT_FALSE(state.complete(old, BufferMapState::Mapped)); - EXPECT_FALSE(state.complete(old, BufferMapState::Unmapped)); - EXPECT_EQ(state.state(), BufferMapState::Mapping); - EXPECT_TRUE(state.complete(current, BufferMapState::Mapped)); - EXPECT_FALSE(state.complete(current, BufferMapState::Unmapped)); - EXPECT_EQ(state.state(), BufferMapState::Mapped); -} - -TEST(StagingMapping, AsyncCompletionWakesWaiters) { - using namespace aurora::gfx; - StagingMapState state; - const auto generation = state.request(); - std::thread callback([&] { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - state.complete(generation, BufferMapState::Mapped); - }); - const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(2); - while (state.state() == BufferMapState::Mapping && std::chrono::steady_clock::now() < deadline) - state.wait_for_progress(); - callback.join(); - EXPECT_EQ(state.state(), BufferMapState::Mapped); -} - -TEST(StagingCapacity, ReservesPaddingAndRejectsOverflow) { - using namespace aurora::gfx; - EXPECT_EQ(staging_padded(257, 256), 512u); - EXPECT_THROW(staging_padded(UINT64_MAX, 256), StagingCapacityError); - const StagingSizes used{0, 256, 0, 0}, demand{0, 256, 0, 0}, tail{0, 3840, 0, 0}; - EXPECT_TRUE(staging_fits(used, demand, tail, {4, 4352, 4, 4})); - EXPECT_FALSE(staging_fits(used, demand, tail, {4, 4351, 4, 4})); - EXPECT_FALSE(staging_fits({UINT64_MAX, 0, 0, 0}, {1, 0, 0, 0}, {}, - {UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX})); -} - -TEST(FrameInterpolationContract, IdenticalMeshesInDifferentViewportsDoNotShareHistory) { - using namespace aurora; - const auto savedViewport = gx::g_gxState.logicalViewport; - constexpr size_t positionOffset = sizeof(Mat4x4); - constexpr size_t normalOffset = positionOffset + gx::MaxPnMtx * sizeof(Mat3x4); - constexpr size_t uniformSize = normalOffset + gx::MaxPnMtx * sizeof(Mat3x4); - const gx::FrameInterpolationDrawIdentity identity{0x1234, 0x5678, 0x9abc, 0xdef0}; - const Mat4x4 projection{}; - const auto record = [&](float x, std::array& source) { - gx::g_gxState.pnMtx[0].pos = {{1.f, 0.f, 0.f, x}, {0.f, 1.f, 0.f, 0.f}, {0.f, 0.f, 1.f, 0.f}}; - gx::g_gxState.pnMtx[0].nrm = {{1.f, 0.f, 0.f, 0.f}, {0.f, 1.f, 0.f, 0.f}, {0.f, 0.f, 1.f, 0.f}}; - std::memcpy(source.data() + positionOffset, &gx::g_gxState.pnMtx[0].pos, sizeof(Mat3x4)); - std::memcpy(source.data() + normalOffset, &gx::g_gxState.pnMtx[0].nrm, sizeof(Mat3x4)); - return gx::record_interpolation_draw(identity, projection, 1, { - .sourceUniformData = source.data(), .uniformSize = source.size(), .projectionOffset = 0, - .positionOffset = positionOffset, .normalOffset = normalOffset, .currentMatrix = 0, - .indexedMatrices = true}); - }; - gx::set_frame_interpolation_fps(0); - gx::begin_frame_interpolation(); - gx::set_frame_interpolation_fps(120); - gx::g_gxState.logicalViewport = {0.f, 0.f, 640.f, 240.f, 0.f, 1.f}; - std::array previous{}; - gx::begin_frame_interpolation(); - record(0.f, previous); - gx::finalize_frame_interpolation(); - gfx::testing::reset_uniform_allocations(); - gx::g_gxState.logicalViewport.top = 240.f; - std::array current{}; - gx::begin_frame_interpolation(); - const auto ranges = record(20.f, current); - const auto expected = current; - gx::finalize_frame_interpolation(); - EXPECT_EQ(current, expected); - if (ranges[0].size) { - const auto& duplicate = gfx::testing::uniform_allocation(ranges[0].offset); - ASSERT_EQ(duplicate.size(), expected.size()); - EXPECT_EQ(std::memcmp(duplicate.data(), expected.data(), expected.size()), 0); - } - gx::g_gxState.logicalViewport = savedViewport; - gx::set_frame_interpolation_fps(0); - gx::begin_frame_interpolation(); -} diff --git a/aurora-main/tests/test_dvd.cpp b/aurora-main/tests/test_dvd.cpp deleted file mode 100644 index b48f877..0000000 --- a/aurora-main/tests/test_dvd.cpp +++ /dev/null @@ -1,288 +0,0 @@ -#include -#include - -#include - -#include -#include -#include - -// ============================================================================= -// Tests that do NOT require a disc image -// ============================================================================= - -TEST(DVDStubs, Constants) { - EXPECT_EQ(DVD_STATE_END, 0); - EXPECT_EQ(DVD_STATE_BUSY, 1); - EXPECT_EQ(DVD_STATE_CANCELED, 10); - EXPECT_EQ(DVD_RESULT_GOOD, 0); - EXPECT_EQ(DVD_RESULT_FATAL_ERROR, -1); - EXPECT_EQ(DVD_RESULT_CANCELED, -6); -} - -TEST(DVDStubs, StructSizes) { - EXPECT_GT(sizeof(DVDDiskID), 0u); - EXPECT_GT(sizeof(DVDCommandBlock), 0u); - EXPECT_GT(sizeof(DVDFileInfo), 0u); - EXPECT_GT(sizeof(DVDDir), 0u); - EXPECT_GT(sizeof(DVDDirEntry), 0u); - EXPECT_GE(sizeof(DVDFileInfo), sizeof(DVDCommandBlock)); -} - -TEST(DVDStubs, InitWithoutDisc) { DVDInit(); } - -TEST(DVDStubs, GetDriveStatus) { EXPECT_EQ(DVDGetDriveStatus(), DVD_STATE_NO_DISK); } - -TEST(DVDStubs, Reset) { DVDReset(); } - -TEST(DVDStubs, ResetRequired) { EXPECT_EQ(DVDResetRequired(), FALSE); } - -TEST(DVDStubs, PauseResume) { - DVDPause(); - DVDResume(); -} - -TEST(DVDStubs, AutoInvalidation) { - BOOL prev = DVDSetAutoInvalidation(TRUE); - EXPECT_EQ(prev, FALSE); - prev = DVDSetAutoInvalidation(FALSE); - EXPECT_EQ(prev, TRUE); - prev = DVDSetAutoInvalidation(FALSE); - EXPECT_EQ(prev, FALSE); -} - -TEST(DVDStubs, Cancel) { - DVDCommandBlock block{}; - block.state = DVD_STATE_BUSY; - s32 result = DVDCancel(&block); - EXPECT_EQ(result, 0); - EXPECT_EQ(block.state, DVD_STATE_CANCELED); -} - -TEST(DVDStubs, CancelAsync) { - DVDCommandBlock block{}; - block.state = DVD_STATE_BUSY; - DVDCancelAsync(&block, [](s32, DVDCommandBlock*) {}); - EXPECT_EQ(block.state, DVD_STATE_CANCELED); -} - -TEST(DVDStubs, CancelAll) { EXPECT_EQ(DVDCancelAll(), DVD_RESULT_GOOD); } - -TEST(DVDStubs, SeekStubs) { - DVDFileInfo fi{}; - fi.cb.state = DVD_STATE_BUSY; - s32 result = DVDSeekPrio(&fi, 0, 2); - EXPECT_EQ(result, DVD_RESULT_FATAL_ERROR); - EXPECT_EQ(fi.cb.state, DVD_STATE_FATAL_ERROR); - - fi.cb.state = DVD_STATE_BUSY; - BOOL ok = DVDSeekAsyncPrio(&fi, 0, [](s32, DVDFileInfo*) {}, 2); - EXPECT_EQ(ok, TRUE); - EXPECT_EQ(fi.cb.state, DVD_STATE_FATAL_ERROR); -} - -TEST(DVDStubs, GetFSTLocation) { EXPECT_EQ(DVDGetFSTLocation(), nullptr); } - -TEST(DVDStubs, GetCurrentDiskID) { - DVDDiskID* id = DVDGetCurrentDiskID(); - EXPECT_NE(id, nullptr); -} - -TEST(DVDStubs, FileInfoStatus) { - DVDFileInfo fi{}; - fi.cb.state = DVD_STATE_END; - EXPECT_EQ(DVDGetFileInfoStatus(&fi), DVD_STATE_END); - fi.cb.state = DVD_STATE_BUSY; - EXPECT_EQ(DVDGetFileInfoStatus(&fi), DVD_STATE_BUSY); -} - -TEST(DVDStubs, TransferredSize) { - DVDFileInfo fi{}; - fi.cb.transferredSize = 1234; - EXPECT_EQ(DVDGetTransferredSize(&fi), 1234); -} - -TEST(DVDStubs, CommandBlockStatus) { - DVDCommandBlock block{}; - block.state = DVD_STATE_WAITING; - EXPECT_EQ(DVDGetCommandBlockStatus(&block), DVD_STATE_WAITING); -} - -// ============================================================================= -// Without a disc: operations should fail gracefully -// ============================================================================= - -TEST(DVDNoDisc, OpenFails) { - DVDFileInfo fi{}; - EXPECT_EQ(DVDOpen("test.bin", &fi), FALSE); -} - -TEST(DVDNoDisc, FastOpenFails) { - DVDFileInfo fi{}; - EXPECT_EQ(DVDFastOpen(0, &fi), FALSE); -} - -TEST(DVDNoDisc, CloseNullHandle) { - DVDFileInfo fi{}; - fi.cb.userData = nullptr; - fi.cb.state = DVD_STATE_BUSY; - EXPECT_EQ(DVDClose(&fi), TRUE); - EXPECT_EQ(fi.cb.state, DVD_STATE_END); -} - -TEST(DVDNoDisc, OpenDirFails) { - DVDDir dir{}; - EXPECT_EQ(DVDOpenDir("/", &dir), FALSE); -} - -TEST(DVDNoDisc, CloseDir) { - DVDDir dir{}; - EXPECT_EQ(DVDCloseDir(&dir), TRUE); -} - -TEST(DVDNoDisc, ChangeDirFails) { EXPECT_EQ(DVDChangeDir("/"), FALSE); } - -TEST(DVDNoDisc, ConvertPathFails) { EXPECT_EQ(DVDConvertPathToEntrynum("/test"), -1); } - -TEST(DVDNoDisc, GetCurrentDir) { - char buf[256]; - EXPECT_EQ(DVDGetCurrentDir(buf, sizeof(buf)), TRUE); - EXPECT_STREQ(buf, "/"); -} - -// ============================================================================= -// Tests that require a disc image (conditionally compiled) -// ============================================================================= - -#ifdef DVD_TEST_IMAGE - -class DVDDiscTest : public ::testing::Test { -protected: - static void SetUpTestSuite() { - ASSERT_TRUE(aurora_dvd_open(DVD_TEST_IMAGE)); - DVDInit(); - } - - static void TearDownTestSuite() { aurora_dvd_close(); } -}; - -// Helper: find the first file entry in root by iterating the directory. -// Returns the entry number and fills fileName, or returns -1 if none found. -static s32 findFirstRootFile(char* fileName, size_t fileNameSize) { - DVDDir dir{}; - if (!DVDOpenDir("/", &dir)) - return -1; - - DVDDirEntry dirent{}; - s32 fileEntry = -1; - while (DVDReadDir(&dir, &dirent)) { - if (!dirent.isDir) { - fileEntry = static_cast(dirent.entryNum); - std::snprintf(fileName, fileNameSize, "/%s", dirent.name); - break; - } - } - DVDCloseDir(&dir); - return fileEntry; -} - -TEST_F(DVDDiscTest, ConvertPathRoot) { EXPECT_EQ(DVDConvertPathToEntrynum("/"), 0); } - -TEST_F(DVDDiscTest, ConvertPathDotDotDot) { - EXPECT_EQ(DVDConvertPathToEntrynum("."), 0); - EXPECT_EQ(DVDConvertPathToEntrynum(".."), 0); -} - -TEST_F(DVDDiscTest, ConvertPathInvalid) { - EXPECT_EQ(DVDConvertPathToEntrynum("/nonexistent_file_that_should_not_exist"), -1); -} - -TEST_F(DVDDiscTest, OpenDirRoot) { - DVDDir dir{}; - EXPECT_EQ(DVDOpenDir("/", &dir), TRUE); - EXPECT_EQ(dir.entryNum, 0u); - EXPECT_EQ(dir.location, 1u); - - DVDDirEntry dirent{}; - BOOL hasEntry = DVDReadDir(&dir, &dirent); - if (hasEntry) { - EXPECT_NE(dirent.name, nullptr); - EXPECT_GT(std::strlen(dirent.name), 0u); - } - DVDCloseDir(&dir); -} - -TEST_F(DVDDiscTest, ChangeDirRoot) { - EXPECT_EQ(DVDChangeDir("/"), TRUE); - char buf[256]; - DVDGetCurrentDir(buf, sizeof(buf)); - EXPECT_STREQ(buf, "/"); -} - -TEST_F(DVDDiscTest, OpenCloseFile) { - char fileName[256] = {}; - s32 fileEntry = findFirstRootFile(fileName, sizeof(fileName)); - if (fileEntry < 0) { - GTEST_SKIP() << "No files in root directory"; - } - - DVDFileInfo fi{}; - EXPECT_EQ(DVDOpen(fileName, &fi), TRUE); - EXPECT_GT(fi.length, 0u); - EXPECT_EQ(fi.cb.state, DVD_STATE_END); - EXPECT_EQ(DVDClose(&fi), TRUE); - - EXPECT_EQ(DVDFastOpen(fileEntry, &fi), TRUE); - EXPECT_EQ(DVDClose(&fi), TRUE); -} - -TEST_F(DVDDiscTest, ReadFile) { - char fileName[256] = {}; - if (findFirstRootFile(fileName, sizeof(fileName)) < 0) { - GTEST_SKIP() << "No files in root directory"; - } - - DVDFileInfo fi{}; - ASSERT_EQ(DVDOpen(fileName, &fi), TRUE); - - u32 readSize = fi.length < 32 ? fi.length : 32; - std::vector buf(readSize); - s32 bytesRead = DVDReadPrio(&fi, buf.data(), static_cast(readSize), 0, 2); - EXPECT_EQ(bytesRead, static_cast(readSize)); - EXPECT_EQ(DVDGetTransferredSize(&fi), static_cast(readSize)); - - DVDClose(&fi); -} - -TEST_F(DVDDiscTest, ReadAsync) { - char fileName[256] = {}; - if (findFirstRootFile(fileName, sizeof(fileName)) < 0) { - GTEST_SKIP() << "No files in root directory"; - } - - DVDFileInfo fi{}; - ASSERT_EQ(DVDOpen(fileName, &fi), TRUE); - - u32 readSize = fi.length < 32 ? fi.length : 32; - std::vector buf(readSize); - BOOL ok = DVDReadAsyncPrio(&fi, buf.data(), static_cast(readSize), 0, [](s32, DVDFileInfo*) {}, 2); - EXPECT_EQ(ok, TRUE); - EXPECT_EQ(DVDGetTransferredSize(&fi), static_cast(readSize)); - - DVDClose(&fi); -} - -TEST_F(DVDDiscTest, DiskID) { - DVDDiskID* id = DVDGetCurrentDiskID(); - ASSERT_NE(id, nullptr); - bool hasGameName = false; - for (int i = 0; i < 4; i++) { - if (id->gameName[i] != '\0') { - hasGameName = true; - break; - } - } - EXPECT_TRUE(hasGameName); -} - -#endif // DVD_TEST_IMAGE diff --git a/aurora-main/tests/texture_bind_group_cache_key_test.cpp b/aurora-main/tests/texture_bind_group_cache_key_test.cpp deleted file mode 100644 index 9a28086..0000000 --- a/aurora-main/tests/texture_bind_group_cache_key_test.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "gx/texture_bind_group_cache_key.hpp" - -#include - -#include -#include -#include - -namespace aurora::gx { -namespace { - -TEST(TextureBindGroupCacheKeyTest, DistinctViewsDoNotAliasWhenWrapperStorageIsReused) { - struct SimulatedTextureRef { - const void* sampleTextureView; - }; - - alignas(SimulatedTextureRef) std::array wrapperStorage{}; - int firstView = 0; - int secondView = 0; - - TextureBindGroupCacheKey first{ - .sampledTextures = 1, - }; - TextureBindGroupCacheKey second = first; - auto* firstWrapper = new (wrapperStorage.data()) SimulatedTextureRef{&firstView}; - const void* const reusedWrapperAddress = firstWrapper; - set_texture_bind_group_cache_slot(first, 0, firstWrapper->sampleTextureView, 0x1234, 0x5678, 0x9abc); - firstWrapper->~SimulatedTextureRef(); - - auto* secondWrapper = new (wrapperStorage.data()) SimulatedTextureRef{&secondView}; - set_texture_bind_group_cache_slot(second, 0, secondWrapper->sampleTextureView, 0x1234, 0x5678, 0x9abc); - - // A freed TextureRef wrapper can be reconstructed at the same allocator - // address in one frame. The old key therefore saw these bindings as equal. - EXPECT_EQ(reusedWrapperAddress, static_cast(secondWrapper)); - EXPECT_NE(first, second); - - TextureBindGroupCacheKey sameView = first; - EXPECT_EQ(first, sameView); - secondWrapper->~SimulatedTextureRef(); -} - -} // namespace -} // namespace aurora::gx diff --git a/projects/mkwii-ntsc-j/MAP.txt b/projects/mkwii-ntsc-j/MAP.txt new file mode 100644 index 0000000..6bda49b --- /dev/null +++ b/projects/mkwii-ntsc-j/MAP.txt @@ -0,0 +1,29432 @@ +# NTSC-J (RMCJ01) function map, ported from ../mkwii/MAP.txt (PAL RMCP01). +# Every entry was validated against the RMCJ01 main.dol/StaticR.rel. +# Verdicts: PROVEN=12202, REFERENCED=12693, PLAUSIBLE=4513, IDENTITY=15, INTERPOLATED=0, ADDED=6 (binary-proven entries no PAL entry covers); entries=29429 +800018a8 0x800018a8 +80001d50 0x80001d50 +80001d6c 0x80001d6c +80001d90 0x80001d90 +80001dc0 0x80001dc0 +80001de8 0x80001de8 +80001dec 0x80001dec +80001e14 0x80001e14 +80001e30 0x80001e30 +80001f1c 0x80001f1c +80001f40 0x80001f40 +80001f54 0x80001f54 +80002440 0x80002440 +8000245c 0x8000245c +8000249c __TRKreset +80005f34 memcpy +80005f84 __fill_mem +80006038 memset +80006068 __check_pad3 +80006090 __set_debug_bba +8000609c __get_debug_bba +800060a4 __start +80006210 __init_registers +800062a0 __init_data +80006348 __init_hardware +8000636c __flush_cache +800063a0 0x800063a0 +800072c0 StrapScene::__ct +800073f0 RKScene::__dt +80007448 StrapScene::__dt +800074a4 StrapScene::LinkModule +800074d8 StrapScene::enter +800077c8 StrapScene::CheckInput +800079d0 StrapScene::calc +80007bc0 EGG::ColorFader::getStatus +80007bc8 StrapScene::draw +80007f2c StrapScene::exit +80007f34 EGG::Scene::outgoing_child_create +80007f38 EGG::Scene::incoming_child_destroy +80007f3c EGG::Scene::reinit +80007f40 EGG::Scene::exit +80007f44 EGG::Scene::enter +80007f48 EGG::Scene::draw +80007f4c EGG::Scene::calc +80007f50 getContentArcNameByIdx +80007f64 0x80007f64 +80007f7c DiscError::__ct +80007fac DiscError::__dt +80008004 setDiscReadErrorMessage +80008050 0x80008050 +80008054 DiscInfoMessageData_printError +80008b2c nw4r::ut::Color::__dt +80008b6c DiscCheckThread::create +80008c0c DiscCheckThread::__dt +80008c74 DvdThread_main +80008d7c DiscCheckThread::halt +80008dd0 DiscInfo_printError +80008dd8 0x80008dd8 +80008ddc 0x80008ddc +80008de0 RKSystem::GetStaticInstance +80008dec RKSystem::WPADAlloc +80008e0c RKSystem::WPADFree +80008e4c RKSystem::Main +80008f08 RKSystem::GetSystemHeap +80008f10 EGG::TSystem::Initialize +800090ec EGG::TSystem::InitRenderMode +800090f0 RKSystem::Initialize +80009478 RKSystem::Run +80009774 EGG::TSystem::GetDisplay +8000977c EGG::TSystem::OnBeginFrame +80009780 EGG::TSystem::OnEndFrame +80009784 EGG::TSystem::GetSceneMgr +8000978c EGG::TSystem::GetPerfView +800097a0 RKSceneManager::ChangeSceneByCreatorAfterFadeOut +800097a8 RKSceneManager::calcCurrentFader +800098e0 RKSceneManager::calc +800098e4 RKSceneManager::draw +800098e8 RKSceneManager::drawCurrentFaderImpl +800098f8 RKSceneManager::calcCurrentFaderImpl +80009908 EGG::TSystem::GetVideo +80009910 EGG::TSystem::GetSystemHeap +80009918 EGG::TSystem::GetXfbMgr +80009920 EGG::TSystem::GetAudioMgr +80009928 __sinit_\RKSystem_cpp +80009a9c EGG::Vector3f::__dt +80009adc EGG::Vector2f::__dt +80009b1c ExpHeapGroup::SetHeapsGroupId +80009b80 ExpHeapGroup::CalculateGroupSizeRecords +80009be8 RKParameterFile::__ct +80009c3c RKParameterFile::__dt +80009cc8 RKParameterFile::AddParameter +80009d38 RKParameterFile::ReadParameterFile +80009e54 RamStream::__dt +80009eac RKParameterFile::vf_0x18 +80009eb0 RKParameterFile::vf_0x14 +80009eb4 RKParameterFile::vf_0x10 +80009eb8 ModuleLinker::Disposer__dt +80009f4c ModuleLinker::Create +80009fc8 ModuleLinker::0x8000a06c +80009fcc ModuleLinker::0x8000a070 +80009fd0 ModuleLinker::__dt +8000a0e4 ModuleLinker::Link +8000a354 ModuleLinker::CallModule +8000a39c ModuleLinker::Report +8000a4ac RKSceneCreator::create +8000a504 RKSceneCreator::destroy +8000a52c SystemManager::create +8000a580 SystemManager::__dt +8000a5e4 SystemManager::__ct +8000a84c SystemManager::PrepareLaunch +8000aae4 SystemManager::LoadMapFile +8000abac SystemManager::Init +8000ae9c SystemManager::GetCountry +8000af10 SystemManager::GetLongitude +8000afc4 SystemManager::GetLatitude +8000b078 SystemManager::Shutdown +8000b0ac SystemManager::ReturnToMenu +8000b0e0 SystemManager::RestartGame +8000b118 0x8000b118 +8000b134 0x8000b134 +8000b150 SystemManager::SetSystemPowerCallbacks +8000b190 SystemManager::HandlePowerState +8000b1fc SystemManager::GetGameId +8000b204 SystemManager::GenerateGameId +8000b22c SystemManager::RipFromDiscAsync +8000b294 SystemManager::RipFromDiscImpl +8000b460 SystemManager::ProcessRipRequest +8000b4ec SystemManager::RipFromDisc(heap) +8000b514 SystemManager::RipFromDisc(no heap) +8000b534 SystemManager::GetDisplayModeType +8000b578 SystemManager::StopAllControllerMotors +8000b5d4 Main +8000b5d8 __DBMtrHandler +8000b5fc __DBIntrHandler +8000b620 DBInitComm +8000b67c DBInitInterrupts +8000b6d0 DBQueryData +8000b774 DBRead +8000b7f4 DBWrite +8000b904 DBOpen +8000b908 DBClose +8000b90c __EXI2Imm +8000bbf4 __DBEXIInit +8000bcb0 __DBEXIReadReg +8000bdd4 __DBEXIWriteReg +8000bed8 __DBEXIReadRam +8000bfb8 __DBEXIWriteRam +8000c098 _ftell +8000c140 ftell +8000c144 _fseek +8000c308 fseek +8000c30c rewind +8000c354 atexit +8000c358 Block_link +8000c4a8 SubBlock_merge_next +8000c550 deallocate_from_fixed_pools +8000c73c free +8000c86c __close_all +8000c910 __flush_line_buffered_output_files +8000c994 __flush_all +8000ca00 __ull2dec +8000cadc __timesdec +8000cd64 __str2dec +8000ce50 __two_exp +8000ce8c __two_exp_switch +8000ce90 __two_exp_caseD_ffffffc0 +8000cea4 __two_exp_caseD_ffffffcb +8000cebc __two_exp_caseD_ffffffe0 +8000ced4 __two_exp_caseD_fffffff0 +8000ceec __two_exp_caseD_fffffff8 +8000cf04 __two_exp_caseD_fffffff9 +8000cf1c __two_exp_caseD_fffffffa +8000cf34 __two_exp_caseD_fffffffb +8000cf4c __two_exp_caseD_fffffffc +8000cf64 __two_exp_caseD_fffffffd +8000cf7c __two_exp_caseD_fffffffe +8000cf94 __two_exp_caseD_ffffffff +8000cfac __two_exp_caseD_0 +8000cfc4 __two_exp_caseD_1 +8000cfdc __two_exp_caseD_2 +8000cff4 __two_exp_caseD_3 +8000d00c __two_exp_caseD_4 +8000d024 __two_exp_caseD_5 +8000d03c __two_exp_caseD_6 +8000d054 __two_exp_caseD_7 +8000d06c __two_exp_caseD_8 +8000d084 __two_exp_caseD_ffffffc1 +8000d1bc __equals_dec +8000d2a0 __less_dec +8000d3a0 __minus_dec +8000d8bc __num2dec_internal +8000da20 __num2dec +8000dbc0 __dec2num +8000e358 __prep_buffer +8000e380 __load_buffer +8000e47c __flush_buffer +8000e534 fread +8000e538 __fread +8000e878 __fwrite +8000eb80 fclose +8000ec3c fflush +8000ed70 __msl_strnicmp +8000ee28 __fpclassifyf +8000ee88 __signbitd +8000eea0 __fpclassifyd +8000ef1c mbtowc +8000ef34 __mbtowc_noconv +8000ef80 __wctomb_noconv +8000ef9c mbstowcs +8000f05c wcstombs +8000f114 memmove +8000f1e0 memchr +8000f20c __memrchr +8000f238 memcmp +8000f284 __copy_longs_aligned +8000f340 __copy_longs_rev_aligned +8000f3e8 __copy_longs_unaligned +8000f4a8 __copy_longs_rev_unaligned +8000f554 __stdio_atexit +8000f564 parse_format +8000f8f4 parse_format_switch +8000f8f8 parse_format_caseD_58 +8000f940 parse_format_caseD_46 +8000f988 parse_format_caseD_41 +8000f9d4 parse_format_caseD_47 +8000f9e8 parse_format_caseD_45 +8000fa38 parse_format_caseD_70 +8000fa5c parse_format_caseD_63 +8000fa94 parse_format_caseD_73 +8000fac0 0x8000fac0 +8000fb20 long2str +8000fd58 longlong2str +80010008 double2hex +800103d8 round_decimal +80010500 float2str +80010c98 _pformatter +80010d98 _pformatter_switch +80010d9c _pformatter_caseD_64 +80010ef8 _pformatter_caseD_58 +80011054 _pformatter_caseD_45 +800110c4 _pformatter_caseD_41 +80011134 _pformatter_caseD_73 +80011258 _pformatter_caseD_6e +80011310 _pformatter_caseD_63 +80011330 _pformatter_caseD_25 +80011340 _pformatter_caseD_26 +80011544 __FileWrite +8001159c __StringWrite +80011608 printf +800116d4 vprintf +80011750 vsnprintf +800117d8 vsprintf +8001185c snprintf +80011950 sprintf +80011a24 qsort +80011b94 rand +80011bb4 srand +80011bbc parse_format +80011e90 parse_format_switch +80011e94 parse_format_caseD_58 +80011eac parse_format_caseD_41 +80011ef4 parse_format_caseD_70 +80011f08 parse_format_caseD_63 +80011f34 parse_format_caseD_73 +80011fec parse_format_caseD_5b +800121d8 parse_format_caseD_42 +800121e0 parse_format_caseD_6e +80012244 __sformatter +800124c8 __sformatter_switch +800124cc __sformatter_caseD_64 +800124d4 __sformatter_caseD_69 +80012614 __sformatter_switch +80012618 __sformatter_caseD_0 +80012620 __sformatter_caseD_1 +80012628 __sformatter_caseD_2 +80012630 __sformatter_caseD_3 +80012638 __sformatter_caseD_4 +8001264c __sformatter_caseD_5 +80012654 __sformatter_caseD_6 +8001265c __sformatter_caseD_7 +80012680 __sformatter_caseD_6f +80012688 __sformatter_caseD_75 +80012690 __sformatter_caseD_58 +800127ac __sformatter_switch +800127b0 __sformatter_caseD_0 +800127b8 __sformatter_caseD_1 +800127c0 __sformatter_caseD_2 +800127c8 __sformatter_caseD_3 +800127d0 __sformatter_caseD_4 +800127e4 __sformatter_caseD_5 +800127ec __sformatter_caseD_6 +800127f4 __sformatter_caseD_7 +80012818 __sformatter_caseD_41 +800128c0 __sformatter_caseD_63 +80012a6c __sformatter_caseD_25 +80012b14 __sformatter_caseD_73 +80012bb8 __sformatter_caseD_5b +80012e20 __sformatter_caseD_6e +80012e90 __sformatter_caseD_26 +80012edc __StringRead +80012f64 sscanf +8001302c raise +80013044 strcpy +80013104 strncpy +80013148 strcat +80013174 strncat +800131c0 strcmp +800132dc strncmp +8001331c strchr +8001334c strcspn +800133f0 strtok +80013514 strstr +80013580 __strtold +800148b4 atof +80014910 __strtoul +80014d24 __strtoull +800151cc strtoul +80015274 strtol +80015360 atoi +80015424 __write_console +800154f4 0x800154f4 +800154fc fwide +80015574 wmemcpy +8001557c wmemchr +800155a4 parse_format +800158f4 parse_format_switch +800158f8 parse_format_caseD_58 +8001593c parse_format_caseD_46 +80015988 parse_format_caseD_41 +800159d8 parse_format_caseD_47 +800159ec parse_format_caseD_45 +80015a40 parse_format_caseD_70 +80015a64 parse_format_caseD_63 +80015aa0 parse_format_caseD_73 +80015ad0 parse_format_caseD_6e +80015ae8 parse_format_caseD_42 +80015b34 long2str +80015d78 longlong2str +80016034 double2hex +8001648c round_decimal +800165b4 float2str +80016d40 __wpformatter +80016e50 __wpformatter_switch +80016e54 __wpformatter_caseD_64 +80016fb0 __wpformatter_caseD_58 +8001710c __wpformatter_caseD_45 +80017188 __wpformatter_caseD_41 +80017204 __wpformatter_caseD_73 +800173b0 __wpformatter_caseD_6e +80017468 __wpformatter_caseD_63 +800174c0 __wpformatter_caseD_25 +800174d0 __wpformatter_caseD_26 +800176cc __wStringWrite +80017738 swprintf +80017830 vswprintf +800178bc wcslen +800178d8 wcscpy +800178f4 wcsncpy +80017938 wcscmp +8001796c wcschr +80017998 __ieee754_acos +80017c64 __ieee754_asin +80017efc __ieee754_atan2 +80018154 __ieee754_fmod +80018484 __ieee754_log +80018738 __ieee754_log10 +8001884c __ieee754_pow +80019060 __ieee754_rem_pio2 +800193e4 __ieee754_sqrt +8001962c __kernel_cos +8001973c __kernel_rem_pio2 +8001adf4 __kernel_sin +8001aeb4 __kernel_tan +8001b104 nan +8001b108 scalbn +8001b10c atan +8001b33c ceil +8001b488 copysign +8001b4b4 cos +8001b57c floor +8001b6cc frexp +8001b754 ldexp +8001b8c0 modf +8001b9bc sin +8001ba88 tan +8001bb00 acos +8001bb04 asin +8001bb08 atan2 +8001bb0c fmod +8001bb10 log10 +8001bb14 pow +8001bb18 sqrt +8001bb1c stricmp +8001bbbc strncasecmp +8001bbc0 strcasecmp +8001bc60 CBGetBytesAvailableForRead +8001bc68 CircleBufferInitialize +8001bc8c CircleBufferWriteBytes +8001bd94 CircleBufferReadBytes +8001bea0 MWEnterCriticalSection +8001bed0 MWExitCriticalSection +8001bed8 gdev_cc_initialize +8001bf14 0x8001bf14 +8001bf1c 0x8001bf1c +8001bf40 0x8001bf40 +8001bf48 gdev_cc_read +8001bffc gdev_cc_write +8001c070 gdev_cc_pre_continue +8001c094 gdev_cc_post_stop +8001c0b8 gdev_cc_peek +8001c12c gdev_cc_initinterrupts +8001c150 TRK_DispatchMessage +8001c194 TRK_DispatchMessage_switch +8001c198 TRK_DispatchMessage_caseD_1 +8001c1a8 TRK_DispatchMessage_caseD_2 +8001c1b8 TRK_DispatchMessage_caseD_3 +8001c1c8 TRK_DispatchMessage_caseD_7 +8001c1d8 TRK_DispatchMessage_caseD_10 +8001c1e8 TRK_DispatchMessage_caseD_11 +8001c1f8 TRK_DispatchMessage_caseD_12 +8001c208 TRK_DispatchMessage_caseD_13 +8001c218 TRK_DispatchMessage_caseD_18 +8001c228 TRK_DispatchMessage_caseD_19 +8001c238 TRK_DispatchMessage_caseD_1a +8001c248 TRK_DispatchMessage_caseD_17 +8001c254 TRK_DispatchMessage_caseD_0 +8001c270 InitMetroTRK +8001c308 InitMetroTRK_BBA +8001c39c EnableMetroTRKInterrupts +8001c3a0 TRKTargetTranslate +8001c408 __TRK_copy_vectors +8001c53c TRKInitializeTarget +8001c584 __TRKreset +8001c594 TRKLoadContext +8001c61c TRKEXICallBack +8001c654 InitMetroTRKCommTable +8001c78c TRKUARTInterruptHandler +8001c790 TRK_InitializeIntDrivenUART +8001c810 TRKPollUART +8001c824 TRKReadUARTN +8001c860 TRK_WriteUARTN +8001c89c ReserveEXI2Port +8001c8b0 UnreserveEXI2Port +8001c8c4 0x8001c8c4 +8001c8dc InitializeProgramEndTrap +8001c930 TRK_flush_cache +8001c968 TRK_main +8001c9a4 TRK_NubMainLoop +8001ca90 TRK_memcpy +8001cbcc TRK_memset +8001ccf4 TRKSaveExtended1Block +8001ceb8 TRKRestoreExtended1Block +8001d01c TRK_MessageSend +8001d080 TRK_InitializeMessageBuffers +8001d0a0 TRK_GetFreeBuffer +8001d13c TRKGetBuffer +8001d160 TRK_ReleaseBuffer +8001d188 TRKResetBuffer +8001d1b0 TRK_SetBufferPosition +8001d1e0 TRK_AppendBuffer +8001d284 TRK_ReadBuffer +8001d314 TRKAppendBuffer1_ui32 +8001d3e4 TRKAppendBuffer1_ui64 +8001d4d8 TRKAppendBuffer_ui8 +8001d53c TRKAppendBuffer_ui32 +8001d62c TRKReadBuffer1_ui64 +8001d70c TRKReadBuffer_ui8 +8001d7a4 TRKReadBuffer_ui32 +8001d88c GetTRKConnected +8001d894 TRK_DoConnect +8001d904 TRKDoDisconnect +8001d98c TRKDoReset +8001d9f8 TRKDoOverride +8001da64 TRKDoReadMemory +8001dbf0 TRKDoReadMemory_switch +8001dbf4 TRKDoReadMemory_caseD_702 +8001dbfc TRKDoReadMemory_caseD_700 +8001dc04 TRKDoReadMemory_caseD_704 +8001dc0c TRKDoReadMemory_caseD_705 +8001dc14 TRKDoReadMemory_caseD_706 +8001dc1c TRKDoReadMemory_caseD_701 +8001dc98 TRKDoWriteMemory +8001de00 TRKDoWriteMemory_switch +8001de04 TRKDoWriteMemory_caseD_702 +8001de0c TRKDoWriteMemory_caseD_700 +8001de14 TRKDoWriteMemory_caseD_704 +8001de1c TRKDoWriteMemory_caseD_705 +8001de24 TRKDoWriteMemory_caseD_706 +8001de2c TRKDoWriteMemory_caseD_701 +8001dea8 TRKDoReadRegisters +8001e0a4 TRKDoWriteRegisters +8001e344 TRKDoContinue +8001e408 TRKDoStep +8001e68c TRKDoStop +8001e744 TRKDoSetOption +8001e810 __read_console +8001e878 __TRK_write_console +8001e8e0 __read_file +8001e8e8 __access_file +8001e8f0 0x8001e8f0 +8001e99c TRKDoNotifyStopped +8001ea2c TRKInitializeEventQueue +8001ea50 TRKGetNextEvent +8001eadc TRKPostEvent +8001eba8 TRKConstructEvent +8001ebc0 TRKDestructEvent +8001ebc8 TRK_InitializeNub +8001ec74 TRK_TerminateNub +8001ec98 TRK_board_display +8001eca4 TRK_InitializeEndian +8001ed18 TRKTestForPacket +8001ede4 TRKGetInput +8001ee10 TRKProcessInput +8001ee50 TRKInitializeSerialHandler +8001ee58 TRKTerminateSerialHandler +8001ee60 TRK_strlen +8001ee7c TRK_SuppAccessFile +8001f070 TRK_RequestSend +8001f198 HandleOpenFileSupportRequest +8001f2b0 HandleCloseFileSupportRequest +8001f394 HandlePositionFileSupportRequest +8001f4a0 TRKTargetContinue +8001f4d4 SetUseSerialIO +8001f4dc GetUseSerialIO +8001f4e4 __TRK_get_MSR +8001f4ec __TRK_set_MSR +8001f4f4 TRKValidMemory32 +8001f5ec TRK_ppc_memcpy +8001f6b8 TRKTargetAccessMemory +8001f808 TRKTargetAccessDefault +8001f900 TRKTargetAccessFP +8001fa3c TRKTargetAccessExtended1 +8001fba0 TRKTargetAccessExtended2 +8001ff40 0x8001ff40 +8001fff8 TRKSwapAndGo +80020110 TRKTargetInterrupt +8002016c TRKTargetAddStopInfo +800202a0 TRKTargetAddExceptionInfo +8002033c TRKTargetCheckStep +80020458 TRKTargetSingleStep +800204dc TRKTargetStepOutOfRange +8002054c TRKTargetGetPC +8002055c TRKTargetSupportRequest +80020750 TRKTargetStopped +80020760 TRKTargetSetStopped +80020770 TRKTargetStop +80020788 TRKPPCAccessSPR +80020864 TRKPPCAccessPairedSingleRegister +8002090c ReadFPSCR +80020930 WriteFPSCR +80020954 TRKPPCAccessFPRegister +80020b1c TRKPPCAccessSpecialReg +80020b84 TRKTargetSetInputPendingPtr +80020b94 GetThreadInfo +80020c24 TRKAccessFile +80020c2c 0x80020c2c +80020c34 0x80020c34 +80020c3c 0x80020c3c +80020c44 __sys_free +80020cfc __register_fragment +80020d30 __unregister_fragment +80020d58 __construct_new_array +80020e5c __partial_array_destructor::__dt +80020f18 __construct_array +80021010 __destroy_array +80021088 __destroy_new_array +80021108 __init_cpp_exceptions +80021144 __fini_cpp_exceptions +80021178 strlen +80021194 __va_arg +8002125c __register__global_object +80021274 __destroy__global_chain +800212bc __register_atexit +80021308 __ptmf_test +80021338 __ptmf_cmpr +80021374 __ptmf_scall +8002139c __cvt_fp2unsigned +800213f8 __save_fpr +8002141c _save_fpr_23 +80021430 _save_fpr_28 +80021444 __restore_fpr +80021468 _rest_fpr_23 +8002147c _rest_fpr_28 +80021490 _save_gpr_14 +80021494 _save_gpr_15 +80021498 _save_gpr_16 +8002149c _save_gpr_17 +800214a0 _save_gpr_18 +800214a4 _save_gpr_19 +800214a8 _save_gpr_20 +800214ac _save_gpr_21 +800214b0 _save_gpr_22 +800214b4 _save_gpr_23 +800214b8 _save_gpr_24 +800214bc _save_gpr_25 +800214c0 _save_gpr_26 +800214c4 _save_gpr_27 +800214dc _rest_gpr_14 +800214e0 _rest_gpr_15 +800214e4 _rest_gpr_16 +800214e8 _rest_gpr_17 +800214ec _rest_gpr_18 +800214f0 _rest_gpr_19 +800214f4 _rest_gpr_20 +800214f8 _rest_gpr_21 +800214fc _rest_gpr_22 +80021500 _rest_gpr_23 +80021504 _rest_gpr_24 +80021508 _rest_gpr_25 +8002150c _rest_gpr_26 +80021510 _rest_gpr_27 +80021528 __div2u +80021614 __div2i +8002174c __mod2u +80021830 __mod2i +8002193c __shl2i +80021960 __shr2u +80021984 __cvt_ull_db +80021a24 __cvt_dbl_ull +80021ad0 nw4r::db::DirectPrint_Init +80021b90 nw4r::db::DirectPrint_IsActive +80021bc0 nw4r::db::DirectPrint_EraseXfb +80021d50 nw4r::db::DirectPrint_ChangeXfb +80021d90 nw4r::db::DirectPrint_StoreCache +80021db0 nw4r::db::DirectPrint_DrawString +80021ea0 nw4r::db::DrawStringToXfb +80022000 nw4r::db::DrawStringLineToXfb +800220e0 nw4r::db::DrawCharToXfb +800223a0 nw4r::db::DirectPrint_SetupFB +80022590 nw4r::db::RemoveConsoleFromList_ +80022640 nw4r::db::Console_Create +800227f0 nw4r::db::Console_Destroy +80022820 nw4r::db::DoDrawConsole_ +800229d0 nw4r::db::Console_DrawDirect +80022a50 nw4r::db::PrintToBuffer_ +80022e00 nw4r::db::Console_VFPrintf +80022ee0 nw4r::db::Console_Printf +80023000 nw4r::db::Console_GetTotalLines +80023070 nw4r::db::Exception_Init +80023160 nw4r::db::ErrorHandler_ +800232a0 nw4r::db::RunThread_ +80023330 nw4r::db::DumpException_ +800234c0 nw4r::db::Exception_Printf_ +800235a0 nw4r::db::PrintContext_ +800238a0 nw4r::db::ShowMainInfo_ +80023ae0 nw4r::db::ShowGPRMap_ +80023b90 nw4r::db::ShowFloat_ +80023fa0 nw4r::db::Exception_SetConsole +80023fc0 nw4r::db::Exception_SetUserCallback +80023fe0 nw4r::db::DbgPrintBase::GetInstance +80023ff0 nw4r::db::DbgPrintBase::Initialize +800240b0 nw4r::db::DbgPrintBase::Initialize +80024170 nw4r::db::DbgPrintBase::SetFont +80024180 nw4r::db::DbgPrintBase::GetFont +80024190 nw4r::db::DbgPrintBase::SetTextColor +800241c0 nw4r::db::DbgPrintBase::GetTextColor +800241f0 nw4r::db::DbgPrintBase::SetFontSize +80024200 nw4r::db::DbgPrintBase::GetFontSize +80024210 nw4r::db::DbgPrintBase::SetVisible +80024220 nw4r::db::DbgPrintBase::IsVisible +80024230 nw4r::db::DbgPrintBase::Registerf +80024340 nw4r::db::DbgPrintBase::Registerf +80024460 nw4r::db::DbgPrintBase::VRegisterf +80024530 nw4r::db::DbgPrintBase::Register +800245e0 nw4r::db::DbgPrintBase::Registf +800246f0 nw4r::db::DbgPrintBase::Registf +80024810 nw4r::db::DbgPrintBase::VRegistf +800248e0 nw4r::db::DbgPrintBase::Reset +800248f0 0x800248f0 +80024990 nw4r::db::DbgPrintBase::Flush +80024b30 nw4r::db::DbgPrintBase::Flush +80024bf0 nw4r::db::DbgPrintBase::__ct +80024c60 nw4r::db::DbgPrintBase::__dt +80024cb0 nw4r::db::DbgPrintBase::Unregister +80024cd0 0x80024cd0 +80024d10 nw4r::db::DbgPrintBase::SetBuffer +80024d40 nw4r::db::DbgPrintBase::ReleaseBuffer +80024da0 nw4r::db::DbgPrintBase::Operator.new +80024df0 nw4r::db::DbgPrintBase::GetInstance +80024e10 nw4r::db::DbgPrintBase::Initialize +80024ed0 nw4r::db::DbgPrintBase::Initialize +80024f90 nw4r::db::DbgPrintBase::SetFont +80024fa0 nw4r::db::DbgPrintBase::GetFont +80024fb0 nw4r::db::DbgPrintBase::SetTextColor +80024fe0 nw4r::db::DbgPrintBase::GetTextColor +80025010 nw4r::db::DbgPrintBase::SetFontSize +80025020 nw4r::db::DbgPrintBase::GetFontSize +80025030 nw4r::db::DbgPrintBase::SetVisible +80025040 nw4r::db::DbgPrintBase::IsVisible +80025050 nw4r::db::DbgPrintBase::Registerf +80025160 nw4r::db::DbgPrintBase::Registerf +80025280 nw4r::db::DbgPrintBase::VRegisterf +80025350 nw4r::db::DbgPrintBase::Register +80025400 nw4r::db::DbgPrintBase::Registf +80025510 nw4r::db::DbgPrintBase::Registf +80025630 nw4r::db::DbgPrintBase::VRegistf +80025700 nw4r::db::DbgPrintBase::Reset +80025710 0x80025710 +800257b0 nw4r::db::DbgPrintBase::Flush +80025950 nw4r::db::DbgPrintBase::Flush +80025a10 nw4r::db::DbgPrintBase::__ct +80025a80 nw4r::db::DbgPrintBase::__dt +80025ad0 nw4r::db::DbgPrintBase::Unregister +80025af0 0x80025af0 +80025b30 nw4r::db::DbgPrintBase::SetBuffer +80025b60 nw4r::db::DbgPrintBase::ReleaseBuffer +80025bc0 nw4r::db::DbgPrintBase::Operator.new +80025c10 nw4r::db::DbgPrintBase::Operator.delete +80025c20 nw4r::db::Assertion_Printf_ +80025ce0 PrintExceptionTrace +80025d90 nw4r::db::VPanic +80025ed0 nw4r_db_Panic +80025f70 nw4r::db::VWarning +80026120 nw4r::db::WarningAlarmFunc_ +80026140 nw4r::ef::DrawOrder::Draw +800261d0 nw4r::ef::DrawOrder::Add +80026250 nw4r::ef::DrawOrder::Remove +80026260 nw4r::ef::Effect::__ct +800262d0 nw4r::ef::Effect::__dt +80026330 nw4r::ef::Effect::Initialize +80026470 nw4r::ef::Effect::Closing +80026480 0x80026480 +80026490 0x80026490 +800265a0 nw4r::ef::Effect::CreateEmitter +800266a0 nw4r::ef::Effect::RetireEmitter +80026730 nw4r::ef::Effect::RetireEmitterAll +80026800 nw4r::ef::Effect::RetireParticleAll +80026890 nw4r::ef::Effect::Calc +80026c80 nw4r::ef::Effect::Draw +80026cb0 nw4r::ef::Effect::GetRootEmitter +80026cc0 nw4r::ef::Effect::GetNumEmitter +80026cd0 nw4r::ef::Effect::GetEmitter +80026ce0 nw4r::ef::Effect::ForeachParticleManager +80026d70 nw4r::ef::Effect::ForeachEmitterFrom +80026e50 nw4r::ef::Effect::SetRootMtx +80026ec0 nw4r::ef::Effect::CreateEmitter +80026fc0 nw4r::ef::EffectSystem::__dt +80027050 nw4r::ef::EffectSystem::GetInstance +80027060 nw4r::ef::EffectSystem::Initialize +80027170 nw4r::ef::ActivityList::__ct +800271c0 nw4r::ef::EffectSystem::Closing +80027230 nw4r::ef::EffectSystem::CreateEffect(name) +800272a0 nw4r::ef::EffectSystem::CreateEffect(res) +800273d0 nw4r::ef::EffectSystem::RetireEffectAll +800274c0 nw4r::ef::EffectSystem::RetireEmitterAll +80027550 nw4r::ef::EffectSystem::RetireParticleAll +800275e0 nw4r::ef::EffectSystem::Draw +80027670 nw4r::ef::EffectSystem::SetProcessCamera +80027700 nw4r::ef::Swap +80027750 nw4r::ef::EffectSystem::SortEffect +800278d0 nw4r::ef::EffectSystem::SortEffectOperatorZ +800279d0 __sinit_\ef_effectsystem_cpp +80027b00 nw4r::ef::Emitter::__ct +80027b60 nw4r::ef::Emitter::__dt +80027ba0 nw4r::ef::Emitter::RetireParticleAll +80027c30 nw4r::ef::Emitter::DestroyFunc +80027c40 0x80027c40 +80027d30 nw4r::ef::Emitter::Closing +80027de0 nw4r::ef::Emitter::RetireParticleManagerAll +80027eb0 nw4r::ef::Emitter::InitializeDatas +80028180 nw4r::ef::Emitter::Initialize +800282f0 nw4r::ef::Emitter::CreateEmitter +800285d0 nw4r::ef::Emitter::CreateEmitterTmp +80028cb0 nw4r::ef::GetLODratio +80028db0 nw4r::ef::Emitter::Emission +80029200 nw4r::ef::Emitter::CalcEmitter +800293c0 nw4r::ef::Emitter::CalcParticle +80029450 nw4r::ef::Emitter::CalcEmission +80029570 nw4r::ef::Emitter::CalcBillboard +80029750 nw4r::ef::Emitter::RestructMatrix +80029980 nw4r::ef::Emitter::CalcGlobalMtx +80029ad0 nw4r::ef::Emitter::SetMtxDirty +80029be0 nw4r::ef::Emitter::GetNumParticleManager +80029bf0 nw4r::ef::Emitter::GetParticleManager +80029c00 nw4r::ef::ForeachParticleManagerSub +80029c50 nw4r::ef::Emitter::ForeachParticleManager +80029d40 nw4r::ef::AnimCurveExecuteU8 +8002b020 nw4r::ef::AnimCurveExecuteF32 +8002bfd0 nw4r::ef::AnimCurveExecuteRotate +8002d080 nw4r::ef::AnimCurveExecuteTexture +8002d650 nw4r::ef::CreateChild +8002d7c0 nw4r::ef::AnimCurveExecuteChild +8002e580 nw4r::ef::AnimBakedExecuteU8 +8002e8d0 nw4r::ef::AnimBakedExecuteF32 +8002ec20 nw4r::ef::GetTypePositionSphere +8002ed40 nw4r::ef::GetTypePositionCube +8002ee20 nw4r::ef::GetTypePositionCylinder +8002eef0 nw4r::ef::GetTypePositionCircle +8002f000 nw4r::ef::GetTypePositionRectangle +8002f0f0 nw4r::ef::GetTypePositionPlane +8002f1a0 nw4r::ef::CrossCheckPlane +8002f640 nw4r::ef::CrossCheckRectangle +8002fbe0 nw4r::ef::CrossCheckCircle +80030170 nw4r::ef::CrossCheckSphere +800307b0 nw4r::ef::CrossCheckCylinder +80030fa0 nw4r::ef::CrossCheckCube +800316e0 nw4r::ef::CrossCheck +80031b00 nw4r::ef::CalcPostField +80032360 nw4r::ef::Particle::__ct +80032370 nw4r::ef::Particle::__dt +800323b0 nw4r::ef::Particle::SendClosing +800323c0 nw4r::ef::Particle::DestroyFunc +800323d0 nw4r::ef::ParticleParameter::Initialize +800326f0 nw4r::ef::Particle::Initialize +80033110 nw4r::ef::Particle::GetAlphaFlick +80033350 nw4r::ef::ParticleManager::__ct +800333b0 nw4r::ef::ParticleManager::SendClosing +800333c0 nw4r::ef::ParticleManager::DestroyFunc +800333d0 nw4r::ef::ParticleManager::Closing +80033460 nw4r::ef::ParticleManager::RetireParticleAll +80033510 nw4r::ef::ParticleManager::Initialize +80033660 nw4r::ef::ParticleManager::__dt +800336a0 nw4r::ef::ParticleManager::CreateParticle +800337d0 nw4r::ef::ParticleManager::Calc +80034ea0 nw4r::ef::ParticleManager::Draw +80035180 nw4r::ef::ParticleManager::CalcGlobalMtx +80035260 nw4r::ef::ParticleManager::BeginCalc +800352d0 nw4r::ef::ParticleManager::EndCalc +80035320 nw4r::ef::ParticleManager::BeginDraw +80035420 nw4r::ef::ParticleManager::EndDraw +80035430 nw4r::ef::ParticleManager::Draw_ModifyColor +80035850 __sinit_\ef_particlemanager_cpp +80035860 nw4r::ef::Resource::GetInstance +80035870 nw4r::ef::BreffRelocate +800359e0 nw4r::ef::BreffSearchName +80035aa0 nw4r::ef::BreffIndexOf +80035b40 nw4r::ef::BreftRelocate +80035bd0 nw4r::ef::BreftSearchName +80035c90 nw4r::ef::Resource::Add +80035d10 nw4r::ef::Resource::FindEmitter +80035dd0 nw4r::ef::Resource::FindEmitter +80035e80 nw4r::ef::Resource::AddTexture +80035f00 nw4r::ef::Resource::RelocateCurveTexture +80036020 nw4r::ef::Resource::RelocateCurveChild +80036120 nw4r::ef::Resource::RelocateCommand +80036360 nw4r::ef::Resource::RemoveEffectProject +80036400 nw4r::ef::Resource::RemoveTextureProject +800364a0 __sinit_\ef_resource_cpp +800364f0 nw4r::ef::UtlistToArray +80036580 nw4r::ef::GetDirMtxY +80036690 nw4r::ef::MtxGetRotationMtx +800367b0 nw4r::ef::MtxGetRotation +80036920 nw4r::ef::MtxGetTranslate +80036940 nw4r::ef::MtxGetScale +80036e20 nw4r::ef::Normalize +80036e90 nw4r::ef::_PSSinCosRad +80036f10 nw4r::ef::PSSinCosRad +80036f90 nw4r::ef::Rotation2VecY +800370e0 nw4r::ef::PSMTX34RotXYZRad +80037260 nw4r::ef::MTX34ScaleNonZero +800372e0 nw4r::ef::MTX34ScaleNonZero +80037370 nw4r::ef::MTX34ScaleInv +80037420 nw4r::ef::MTXColLen +80037480 nw4r::ef::HandleBase::__ct +80037490 nw4r::ef::HandleBase::Operator=(HandleBase) +800374b0 nw4r::ef::HandleBase::Operator=(LinkedObject) +800374e0 nw4r::ef::HandleBase::IsValid +80037510 nw4r::ef::HandleBase::GetPtr +80037550 nw4r::ef::EmitterForm::CalcVelocity +80037a20 nw4r::ef::EmitterForm::CalcLife +80037b00 nw4r::ef::CreationQueue::__ct +80037b10 nw4r::ef::CreationQueue::AddParticleCreation +80037c90 nw4r::ef::CreationQueue::AddEmitterCreation +80037e10 nw4r::ef::CreationQueue::Execute +80037f50 nw4r::ef::EmitFormBuilder::Create +80037fd0 __sinit_\ef_emform_cpp +80038030 nw4r::ef::EmitterFormPoint::Emission +80038380 nw4r::ef::EmitterFormLine::Emission +800386c0 nw4r::ef::EmitterFormDisc::Emission +80038bf0 nw4r::ef::EmitterFormSphere::Emission +80039450 nw4r::ef::EmitterFormCylinder::EmissionSub +800398b0 nw4r::ef::EmitterFormCylinder::Emission +80039c00 nw4r::ef::EmitterFormTorus::Emission +8003a240 nw4r::ef::EmitterFormCube::EmissionSub +8003a580 nw4r::ef::EmitterFormCube::Emission +8003be50 nw4r::ef::DrawStrategyBuilder::Create +8003bfd0 nw4r::ef::DrawStrategyImpl::__ct +8003c2e0 nw4r::ef::DrawStrategyImpl::Initialize +8003c3c0 nw4r::ef::DrawStrategyImpl::_InitTev +8003c6b0 nw4r::ef::DrawStrategyImpl::_InitColor +8003ca80 nw4r::ef::DrawStrategyImpl::SetupGP +8003cf20 nw4r::ef::DrawStrategyImpl::_SetupTevReg +8003d750 nw4r::ef::DrawStrategyImpl::_SetupTexture +8003ddc0 nw4r::ef::DrawStrategyImpl::GetGetFirstDrawParticle +8003dde0 nw4r::ef::DrawStrategyImpl::GetGetNextDrawParticle +8003de00 nw4r::ef::DrawStrategyImpl::GetFirstDrawParticle_EldersFirst +8003de30 nw4r::ef::DrawStrategyImpl::GetFirstDrawParticle_YoungersFirst +8003de80 nw4r::ef::DrawStrategyImpl::GetNextDrawParticle_EldersFirst +8003deb0 nw4r::ef::DrawStrategyImpl::GetNextDrawParticle_YoungersFirst +8003dee0 nw4r::ef::DrawStrategyImpl::AheadContext::__ct +8003e100 nw4r::ef::DrawStrategyImpl::__dt +8003e140 __sinit_\ef_drawstrategyimpl_cpp +8003e1d0 nw4r::ef::DrawBillboardStrategy::__ct +8003e210 nw4r::ef::DrawBillboardStrategy::Draw +8003e250 nw4r::ef::DrawBillboardStrategy::DrawNormalBillboard +8003ed10 nw4r::ef::DrawBillboardStrategy::DrawYBillboard +8003f640 nw4r::ef::DrawBillboardStrategy::DrawDirectionalB +8003fed0 nw4r::ef::DrawBillboardStrategy::InitGraphics +8003ffa0 nw4r::ef::DrawBillboardStrategy::GetCalcAheadFunc +80040020 nw4r::ef::DrawStrategyImpl::CalcAhead_Speed +80040100 nw4r::ef::DrawStrategyImpl::CalcAhead_EmitterCent +800401c0 nw4r::ef::DrawStrategyImpl::CalcAhead_EmitterDesi +800401e0 nw4r::ef::DrawStrategyImpl::CalcAhead_Particle +80040300 nw4r::ef::DrawStrategyImpl::CalcAhead_ParticleBot +80040570 nw4r::ef::DrawBillboardStrategy::__dt +800405b0 nw4r::ef::DrawDirectionalStrategy::DrawDirectiona +800405f0 nw4r::ef::DrawQuad +80040730 nw4r::math::VEC3::__ct +80040740 nw4r::math::VEC3Transform +80040780 0x80040780 +80040790 nw4r::ef::DrawQuad +80040930 nw4r::ef::DrawDirectionalStrategy::Draw +80040a40 nw4r::ef::EmitterResource::GetEmitterDrawSetting +80040a50 nw4r::ef::DrawDirectionalStrategy::DrawDirectiona +800417d0 nw4r::math::MTX34::__ct +800417e0 nw4r::ef::DrawInfo::GetViewMtxCooked +800419b0 nw4r::math::MTX34Mult +800419f0 nw4r::math::VEC3::Operator= +80041a10 nw4r::math::VEC3::__ct +80041a20 nw4r::ef::DrawStrategyImpl::Normalize +80041a90 nw4r::math::VEC3Dot +80041ab0 nw4r::ef::DrawStrategyImpl::GetYoungestParticle +80041ac0 nw4r::ef::DrawStrategyImpl::GetElderParticle +80041ad0 nw4r::ef::Particle::Draw_GetSizeX +80041b50 nw4r::ef::Particle::Draw_GetSizeY +80041c30 nw4r::ef::Particle::GetMoveDir +80041c80 nw4r::math::FSqrt +80041cd0 nw4r::ef::CalcRotate +80042040 nw4r::math::MTX34::__ct +80042090 nw4r::ef::CalcLocalTransform +80042290 nw4r::math::VEC3Cross +800422d0 nw4r::ef::DrawDirectionalStrategy::DrawDirectiona +80042910 nw4r::ef::DrawDirectionalStrategy::InitGraphics +800429d0 nw4r::ef::DrawDirectionalStrategy::GetCalcAheadFu +80042a60 nw4r::ef::DrawStrategyImpl::CalcAhead_NoDesign +80042a90 nw4r::ef::DrawDirectionalStrategy::~DrawDirection +80042ad0 nw4r::ef::DrawFreeStrategy::__ct +80042b10 nw4r::ef::DrawQuad +80042c50 nw4r::ef::DrawFreeStrategy::Draw +80043590 nw4r::ef::DrawFreeStrategy::__dt +800435d0 nw4r::ef::DrawLineStrategy::__ct +80043610 nw4r::ef::DrawLineStrategy::Draw +80043c90 nw4r::ef::DrawLineStrategy::__dt +80043cd0 nw4r::ef::DrawPointStrategy::__ct +80043d10 nw4r::ef::DrawPointStrategy::Draw +800441b0 nw4r::ef::DrawPointStrategy::__dt +800441f0 nw4r::ef::DrawStripeStrategy::__ct +80044230 nw4r::ef::DrawStripeStrategy::DrawStripe +80044570 nw4r::ef::DrawStrategyImpl::GetNumDrawParticle +80044580 nw4r::ef::DrawStripeStrategy::GetStripeTexmapType +80044590 nw4r::math::FInv +800445b0 nw4r::ef::DrawStripeStrategy::DrawParticle +80044a50 GXEnd +80044a60 nw4r::ef::DrawStripeStrategy::CalcVertexTube +80044f60 nw4r::ef::DrawStripeStrategy::DrawTubeSegment +80045340 nw4r::ef::DrawStripeStrategy::DrawStripeTube_Conn +80045600 nw4r::ef::DrawStripeStrategy::DrawStripeTube_Conn +80045940 nw4r::ef::DrawStripeStrategy::DrawStripeTube_Conn +80045d00 nw4r::ef::DrawStripeStrategy::DrawStripeTube +80045ef0 nw4r::ef::DrawStripeStrategy::Draw +80046760 nw4r::ef::DrawStripeStrategy::GetInitialPrevAxis +800468b0 nw4r::ef::DrawStripeStrategy::GetCalcAheadFunc +80046980 nw4r::ef::DrawStripeStrategy::CalcAhead_Particle_ +80046aa0 nw4r::ef::DrawStripeStrategy::CalcAhead_ParticleB +80046d10 nw4r::ef::DrawStripeStrategy::CalcAhead_ParticleB +80046fd0 nw4r::ef::DrawStripeStrategy::CalcAhead_ParticleB +80047200 nw4r::ef::DrawStripeStrategy::__dt +80047240 nw4r::ef::DrawSmoothStripeStrategy::DrawSmoothStr +80047280 nw4r::ef::DrawSmoothStripeStrategy::CalcVertex +80047670 nw4r::ef::DrawSmoothStripeStrategy::CalcVertexTub +80047b70 nw4r::ef::DrawSmoothStripeStrategy::DrawSection_B +80047e40 nw4r::math::VEC3::Operator+ +80047e70 nw4r::ef::DrawSmoothStripeStrategy::DrawSectionEn +80048090 nw4r::ef::DrawSmoothStripeStrategy::DrawSectionTu +80048b50 GXEnd +80048b60 nw4r::ef::DrawSmoothStripeStrategy::DrawSmoothStr +80048eb0 nw4r::ef::DrawSmoothStripeStrategy::GetDrawOrder +80048ec0 nw4r::ef::DrawSmoothStripeStrategy::GetStripeTexm +80048ed0 nw4r::ef::DrawSmoothStripeStrategy::Vertex::Verte +80048ee0 nw4r::ef::DrawSmoothStripeStrategy::DrawSmoothStr +80049300 nw4r::ef::DrawSmoothStripeStrategy::DrawSmoothStr +800497a0 nw4r::ef::DrawStrategyImpl::GetYoungestDrawPartic +800497f0 nw4r::math::VEC3::Operator- +80049820 nw4r::math::VEC3::Operator+= +80049850 nw4r::ef::DrawSmoothStripeStrategy::Vertex::Verte +80049890 nw4r::ef::DrawSmoothStripeStrategy::Vertex::Opera +800498d0 nw4r::ef::DrawSmoothStripeStrategy::DrawSmoothStr +80049bd0 nw4r::ef::DrawSmoothStripeStrategy::DrawSmoothStr +80049f80 nw4r::ef::DrawSmoothStripeStrategy::DrawSmoothStr +8004a500 nw4r::ef::DrawSmoothStripeStrategy::DrawSmoothStr +8004a710 nw4r::ef::DrawSmoothStripeStrategy::Draw +8004b0c0 nw4r::ef::DrawSmoothStripeStrategy::GetInitialPre +8004b210 nw4r::ef::DrawSmoothStripeStrategy::GetCalcAheadF +8004b2e0 nw4r::ef::DrawSmoothStripeStrategy::CalcAhead_Par +8004b400 nw4r::ef::DrawSmoothStripeStrategy::CalcAhead_Par +8004b670 nw4r::ef::DrawSmoothStripeStrategy::CalcAhead_Par +8004b930 nw4r::ef::DrawSmoothStripeStrategy::CalcAhead_Par +8004bb60 nw4r::ef::DrawSmoothStripeStrategy::~DrawSmoothSt +8004bba0 nw4r::ef::ResEmitter::GetEmitTrack +8004bbd0 nw4r::ef::ResAnimCurve::SetStop +8004bc00 nw4r::g3d::ResName::Operator== +8004bc50 nw4r::g3d::detail::ResWriteBPCmd +8004bc80 nw4r::g3d::detail::ResWriteBPCmd +8004bce0 nw4r::g3d::detail::ResWriteCPCmd +8004bd10 nw4r::g3d::detail::ResWriteXFCmd +8004bd50 nw4r::g3d::detail::ResWriteSSMask +8004bdb0 nw4r::g3d::ResDic::Get +8004be90 nw4r::g3d::ResDic::Get +8004bf70 ResDic_operator[] +8004bff0 ResDic_operator[] +8004c060 nw4r::g3d::ResDic::GetIndex +8004c0f0 nw4r::g3d::ResDic::GetIndex +8004c160 nw4r::g3d::ResFile::GetResMdl(name) +8004c1d0 nw4r::g3d::ResFile::GetResMdl(idx) +8004c270 nw4r::g3d::ResFile::GetResMdl(u32 idx) +8004c310 nw4r::g3d::ResFile::GetResMdlNumEntries +8004c380 nw4r::g3d::ResFile::GetResPltt +8004c400 nw4r::g3d::ResFile::GetResTex +8004c470 nw4r::g3d::ResFile::GetResTex +8004c4f0 nw4r::g3d::ResFile::GetResTex(idx) +8004c590 nw4r::g3d::ResFile::GetResTex(u32 idx) +8004c630 nw4r::g3d::ResFile::GetResTexNumEntries +8004c6a0 nw4r::g3d::ResFile::GetResAnmChr(name) +8004c710 nw4r::g3d::ResFile::GetResAnmChr(ResName) +8004c7b0 nw4r::g3d::ResFile::GetResAnmChrNumEntries +8004c820 nw4r::g3d::ResFile::GetResAnmClr(name) +8004c890 nw4r::g3d::ResFile::GetResAnmClr(ResName) +8004c930 nw4r::g3d::ResFile::GetResAnmClrNumEntries +8004c9a0 nw4r::g3d::ResFile::GetResAnmTexPat(name) +8004ca10 nw4r::g3d::ResFile::GetResAnmTexPat(ResName) +8004cab0 nw4r::g3d::ResFile::GetResAnmTexPatNumEntries +8004cb20 nw4r::g3d::ResFile::GetResAnmTexSrt(name) +8004cb90 nw4r::g3d::ResFile::GetResAnmTexSrt(ResName) +8004cc30 nw4r::g3d::ResFile::GetResAnmTexSrtNumEntries +8004cca0 nw4r::g3d::ResFile::GetResAnmShp(name) +8004cd10 nw4r::g3d::ResFile::GetResAnmShp(ResName) +8004cdb0 nw4r::g3d::ResFile::GetResAnmShpNumEntries +8004ce20 nw4r::g3d::ResFile::GetResAnmScn +8004ce90 nw4r::g3d::ResFile::HasResMdl +8004cee0 nw4r::g3d::ResFile::HasResAnmChr +8004cf30 nw4r::g3d::ResFile::HasResAnmVis +8004cf80 nw4r::g3d::ResFile::HasResAnmClr +8004cfd0 nw4r::g3d::ResFile::HasResAnmTexPat +8004d020 nw4r::g3d::ResFile::HasResAnmTexSrt +8004d070 nw4r::g3d::ResFile::HasResAnmShp +8004d0c0 nw4r::g3d::ResFile::HasResAnmScn +8004d110 nw4r::g3d::ResFile::Bind +8004d350 nw4r::g3d::ResFile::Release +8004d550 nw4r::g3d::ResFile::Init +8004d820 nw4r::g3d::ResFile::CheckRevision +8004e170 nw4r::g3d::ResMdl::GetResByteCode +8004e1c0 nw4r::g3d::ResMdl::GetResNode(name) +8004e210 nw4r::g3d::ResMdl::GetResNode(ResName) +8004e260 nw4r::g3d::ResMdl::GetResNode(idx) +8004e2c0 nw4r::g3d::ResMdl::GetResNode(u32 idx) +8004e320 nw4r::g3d::ResMdl::GetResNodeNumEntries +8004e360 nw4r::g3d::ResMdl::GetResVtxPos +8004e3b0 nw4r::g3d::ResMdl::GetResVtxPos +8004e410 nw4r::g3d::ResMdl::GetResVtxPos +8004e470 nw4r::g3d::ResMdl::GetResVtxPosNumEntries +8004e4b0 nw4r::g3d::ResMdl::GetResVtxNrm +8004e500 nw4r::g3d::ResMdl::GetResVtxNrm +8004e560 nw4r::g3d::ResMdl::GetResVtxNrm +8004e5c0 nw4r::g3d::ResMdl::GetResVtxNrmNumEntries +8004e600 nw4r::g3d::ResMdl::GetResVtxClr +8004e650 nw4r::g3d::ResMdl::GetResVtxClr +8004e6b0 nw4r::g3d::ResMdl::GetResVtxClr +8004e710 nw4r::g3d::ResMdl::GetResVtxClrNumEntries +8004e750 nw4r::g3d::ResMdl::GetResVtxTexCoord +8004e7b0 nw4r::g3d::ResMdl::GetResVtxFurPos +8004e810 nw4r::g3d::ResMdl::GetResMat(name) +8004e860 nw4r::g3d::ResMdl::GetResMat(resname) +8004e8b0 nw4r::g3d::ResMdl::GetResMat(idx) +8004e910 nw4r::g3d::ResMdl::GetResMat(u32 idx) +8004e970 nw4r::g3d::ResMdl::GetResMatNumEntries +8004e9b0 nw4r::g3d::ResMdl::GetResShp +8004ea10 nw4r::g3d::ResMdl::GetResShp +8004ea70 nw4r::g3d::ResMdl::GetResShpNumEntries +8004eab0 nw4r::g3d::ResMdl::GetResTexPlttInfoOffsetFromTexName +8004eb10 nw4r::g3d::ResMdl::GetResTexPlttInfoOffsetFromTexNameNumEntries +8004eb50 nw4r::g3d::ResMdl::Bind +8004ec60 nw4r::g3d::ResMdl::Release +8004ed50 nw4r::g3d::ResMdl::Init +8004f2f0 nw4r::g3d::ResShp::GetResVtxPos +8004f340 nw4r::g3d::ResShp::GetResVtxNrm +8004f3a0 nw4r::g3d::ResShp::GetResVtxClr +8004f410 nw4r::g3d::ResShp::GetResVtxFurPos +8004f470 nw4r::g3d::ResShp::Init +8004f800 nw4r::g3d::ResShp::CallPrePrimitiveDisplayList +8004f8e0 0x8004f8e0 +8004f950 nw4r::g3d::ResTev::GXSetTevSwapModeTable +8004fa00 nw4r::g3d::ResTev::GXSetTevSwapMode +8004fa60 nw4r::g3d::ResTev::GXSetTevAlphaIn +8004faf0 nw4r::g3d::ResTev::GXSetTevAlphaOp +8004fba0 nw4r::g3d::ResTev::GXSetTevKColorSel +8004fc30 nw4r::g3d::ResTev::GXSetTevKAlphaSel +8004fcc0 nw4r::g3d::ResTev::GXGetTevOrder +8004fd90 nw4r::g3d::ResTev::GXSetTevOrder +8004feb0 nw4r::g3d::ResTev::GXGetTevColorOp +8004ff90 nw4r::g3d::ResTev::GXSetTevColorIn +80050020 nw4r::g3d::ResTev::GXSetTevColorOp +800500d0 nw4r::g3d::ResTev::GXGetIndTexOrder +80050170 nw4r::g3d::ResTev::SetNumTevStages +80050260 nw4r::g3d::ResTev::CallDisplayList +800502c0 nw4r::g3d::ResTev::CopyTo +80050330 nw4r::g3d::ResTev::DCStore +80050350 nw4r::g3d::ResMat::GetParent +80050370 nw4r::g3d::ResMatPix::DCStore +80050390 nw4r::g3d::ResMatTevColor::DCStore +800503b0 nw4r::g3d::ResMatIndMtxAndScale::DCStore +800503d0 nw4r::g3d::ResMatTexCoordGen::DCStore +800503f0 0x800503f0 +80050420 0x80050420 +80050450 nw4r::g3d::ResMatPix::CopyTo +80050490 nw4r::g3d::ResMatTevColor::CopyTo +800504d0 nw4r::g3d::ResMatIndMtxAndScale::CopyTo +80050510 nw4r::g3d::ResMatTexCoordGen::CopyTo +80050550 nw4r::g3d::ResTexObj::GetTexObj +80050580 nw4r::g3d::ResTexObj::GetTexObj +800505b0 nw4r::g3d::ResTexObj::IsValidTexObj +800505f0 SetTextureUsed +80050620 nw4r::g3d::ResTexObj::CopyTo +800506b0 nw4r::g3d::ResTlutObj::GetTlut +800506e0 nw4r::g3d::ResTlutObj::GetTlut +80050710 nw4r::g3d::ResTlutObj::IsValidTlut +80050750 nw4r::g3d::ResTlutObj::CopyTo +800507e0 nw4r::g3d::ResTexSrt::CopyTo +800508c0 0x800508c0 +80050940 0x80050940 +80050990 0x80050990 +80050a10 nw4r::g3d::ResGenMode::GXSetNumTexGens +80050a30 nw4r::g3d::ResGenMode::GXSetNumTexStages +80050a50 nw4r::g3d::ResGenMode::GXSetCullMode +80050a70 nw4r::g3d::ResGenMode::CopyTo +80050ab0 nw4r::g3d::ResMatMisc::GXGetZCompLoc +80050ad0 nw4r::g3d::ResMatMisc::SetLightSetIdx +80050b00 nw4r::g3d::ResMatMisc::GetLightSetIdx +80050b20 nw4r::g3d::ResMatMisc::GetFogIdx +80050b40 nw4r::g3d::ResMatMisc::GetIndirectTexMtxCalcMetho +80050b90 nw4r::g3d::ResMatMisc::CopyTo +80050c00 nw4r::g3d::ResMatFur::GetLyrRate +80050cc0 nw4r::g3d::ResMatPix::GXSetZMode +80050ce0 nw4r::g3d::ResMatPix::GXSetDstAlpha +80050d00 nw4r::g3d::ResMatTevColor::GXGetTevColor +80050dc0 nw4r::g3d::ResMatTevColor::GXSetTevColor +80050e60 nw4r::g3d::ResMatTevColor::GXGetTevKColor +80050f20 nw4r::g3d::ResMatTevColor::GXSetTevKColor +80050fb0 nw4r::g3d::ResMatIndMtxAndScale::CallDisplayList +80050ff0 nw4r::g3d::ResMatIndMtxAndScale::GXGetIndTexMtx +800512b0 nw4r::g3d::ResMatIndMtxAndScale::GXGetIndTexMtx +800514a0 nw4r::g3d::ResMatIndMtxAndScale::GXSetIndTexMtx +80051610 nw4r::g3d::ResMatChan::GXGetChanMatColor +80051650 nw4r::g3d::ResMatChan::GXGetChanCtrl +80051710 nw4r::g3d::ResMatChan::CopyTo +80051770 nw4r::g3d::ResMatTexCoordGen::CallDisplayList +80051840 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2 +800519f0 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2 +80051a54 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_switch +80051a58 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_0 +80051a64 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_1 +80051a70 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_2 +80051a7c nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_3 +80051a88 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_13 +80051a90 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_14 +80051a98 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_4 +80051aa0 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_5 +80051aa8 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_6 +80051ab0 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_7 +80051ab8 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_8 +80051ac0 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_9 +80051ac8 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_a +80051ad0 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_b +80051ad8 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_c +80051ae0 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_d +80051ae8 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_e +80051af0 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_f +80051af8 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_10 +80051b00 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_11 +80051b08 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_12 +80051bf0 nw4r::g3d::ResMat::Bind +80051cc0 nw4r::g3d::ResMat::Release +80051d60 nw4r::g3d::ResMat::ForceBindTex +80051fb0 nw4r::g3d::ResMat::ReleaseTex +800520b0 nw4r::g3d::ResMat::Init +800520e0 nw4r::g3d::ResMat::GetResTev +80052100 nw4r::g3d::ResMat::GetResMatFur +80052120 nw4r::g3d::ResTexPlttInfo::Bind +800523e0 nw4r::g3d::ResVtxPos::SetArray +80052420 nw4r::g3d::ResVtxPos::GetArray +80052460 nw4r::g3d::ResVtxPos::CopyTo +800524c0 0x800524c0 +80052500 0x80052500 +80052540 nw4r::g3d::ResVtxNrm::CopyTo +800525a0 0x800525a0 +800525e0 nw4r::g3d::ResVtxClr::GetArray +80052620 nw4r::g3d::ResVtxClr::CopyTo +80052680 0x80052680 +800526c0 0x800526c0 +80052740 nw4r::g3d::ResVtxPos::DCStore +80052760 nw4r::g3d::ResVtxNrm::DCStore +80052780 nw4r::g3d::ResVtxClr::DCStore +800527a0 nw4r::g3d::ResVtxTexCoord::DCStore +800527c0 nw4r::g3d::ResVtxFurVec::DCStore +800527e0 nw4r::g3d::ResVtxFurPos::DCStore +80052800 0x80052800 +80052820 0x80052820 +80052850 nw4r::g3d::ResTex::GetTexObjParam +80052910 nw4r::g3d::ResTex::GetTexObjCIParam +800529d0 0x800529d0 +80052a00 nw4r::g3d::ResTex::Init +80052a10 nw4r::g3d::ResNode::PatchChrAnmResult +80052bb0 nw4r::g3d::ResNode::CalcChrAnmResult +80052d20 nw4r::g3d::ResNode::SetScale +80052dd0 nw4r::g3d::ResNode::SetTranslate +80052e60 nw4r::g3d::ResNode::SetRotate +80052ef0 nw4r::g3d::detail::GetResKeyFrameAnmResult +80053030 nw4r::g3d::detail::GetResColorAnmResult +80053140 nw4r::g3d::ResAnmClr::GetAnmResult +800532b0 nw4r::g3d::@unnamed@g3d_resanmtexpat_cpp@::Search +80053370 nw4r::g3d::ResAnmTexPat::GetAnmResult +800534f0 nw4r::g3d::ResAnmTexPat::Bind +80053660 nw4r::g3d::ResAnmTexPat::Release +80053800 0x80053800 +80053c20 0x80053c20 +80053ed0 0x80053ed0 +80054010 0x80054010 +80054190 0x80054190 +80054380 0x80054380 +80054df0 0x80054df0 +80055050 nw4r::g3d::ResAnmChr::GetAnmResult_ +80055070 nw4r::g3d::ResAnmChr::GetAnmResult_T +80055100 nw4r::g3d::ResAnmChr::GetAnmResult_R +80055170 nw4r::g3d::ResAnmChr::GetAnmResult_S +800551b0 nw4r::g3d::ResAnmChr::GetAnmResult_RT +80055260 nw4r::g3d::ResAnmChr::GetAnmResult_SR +80055300 nw4r::g3d::ResAnmChr::GetAnmResult_ST +800553a0 nw4r::g3d::ResAnmChr::GetAnmResult_SRT +80055460 nw4r::g3d::ResAnmChr::GetAnmResult +800554e0 nw4r::g3d::ChrAnmResult::GetScale +80055520 nw4r::g3d::ChrAnmResult::GetRotTrans +800555d0 nw4r::g3d::ChrAnmResult::SetRotTrans +80055760 nw4r::g3d::ResLightSet::Bind +800558d0 nw4r::g3d::ResAnmAmbLight::GetAnmResult +800559a0 0x800559a0 +80055d90 0x80055d90 +80055ef0 nw4r::g3d::ResAnmCamera::GetAnmResult +80056200 nw4r::g3d::ResAnmScn::HasResAnmAmbLight +80056260 nw4r::g3d::ResAnmScn::HasResAnmLight +800562c0 nw4r::g3d::ResAnmScn::GetResLightSetNumEntries +80056340 nw4r::g3d::ResAnmScn::GetResAnmAmbLight(ResName) +800563d0 nw4r::g3d::ResAnmScn::GetResAnmAmbLight(idx) +80056480 nw4r::g3d::ResAnmScn::GetResAnmAmbLightNumEntries +80056500 nw4r::g3d::ResAnmScn::GetResAnmLight(ResName) +80056590 nw4r::g3d::ResAnmScn::GetResAnmLight(idx) +80056640 nw4r::g3d::ResAnmScn::GetResAnmLightNumEntries +800566c0 nw4r::g3d::ResAnmScn::GetResAnmFog +80056770 nw4r::g3d::ResAnmScn::GetResAnmFogNumEntries +800567f0 nw4r::g3d::ResAnmScn::GetResAnmCamera +800568a0 nw4r::g3d::ResAnmScn::GetResAnmCameraNumEntries +80056920 nw4r::g3d::ResAnmScn::GetResLightSetByRefNumber(u32) +80056970 nw4r::g3d::ResAnmScn::GetResLightSetByRefNumber(int) +800569c0 nw4r::g3d::ResAnmScn::GetResAnmAmbLightByRefNumber +80056a10 nw4r::g3d::ResAnmScn::GetResAnmLightByRefNumber +80056a60 nw4r::g3d::ResAnmScn::GetResAnmFogByRefNumber +80056ab0 nw4r::g3d::ResAnmScn:GetResAnmCameraByRefNumber(u32) +80056b00 nw4r::g3d::ResAnmScn:GetResAnmCameraByRefNumber(int) +80056b50 nw4r::g3d::ResAnmScn::Bind +80056cc0 0x80056cc0 +80056e30 nw4r::g3d::ApplyVisAnmResult +80056ef0 nw4r::g3d::ApplyVisAnmResult +80056f80 0x80056f80 +80056fa0 0x80056fa0 +80056fe0 0x80056fe0 +80056ff0 0x80056ff0 +80057000 0x80057000 +80057010 0x80057010 +80057050 0x80057050 +800570c0 0x800570c0 +800571b0 0x800571b0 +800572d0 0x800572d0 +80057330 0x80057330 +800573b0 0x800573b0 +80057440 0x80057440 +800574a0 0x800574a0 +80057530 0x80057530 +80057590 0x80057590 +80057690 0x80057690 +80057750 0x80057750 +800577d0 0x800577d0 +80057910 0x80057910 +800579c0 0x800579c0 +80057bb0 0x80057bb0 +80057c70 0x80057c70 +80057c80 0x80057c80 +80057d40 0x80057d40 +80057d50 0x80057d50 +80057e30 0x80057e30 +80057f30 0x80057f30 +80057fb0 0x80057fb0 +80058000 nw4r::g3d::ApplyClrAnmResult +800584c0 0x800584c0 +80058530 0x80058530 +80058580 0x80058580 +800585b0 0x800585b0 +800585c0 0x800585c0 +80058610 0x80058610 +80058690 0x80058690 +80058700 0x80058700 +80058730 0x80058730 +80058740 0x80058740 +800587b0 0x800587b0 +800587e0 0x800587e0 +800587f0 0x800587f0 +80058820 0x80058820 +80058830 0x80058830 +80058850 nw4r::g3d::AnmObjTexPat::Release +80058890 nw4r::g3d::AnmObjTexPat::Attach +800588a0 nw4r::g3d::AnmObjTexPat::Detach +800588b0 nw4r::g3d::AnmObjTexPat::DetachAll +800588c0 nw4r::g3d::AnmObjTexPat::__dt +80058900 nw4r::g3d::AnmObjTexPatNode::__dt +80058970 nw4r::g3d::AnmObjTexPatNode::Attach +80058a60 nw4r::g3d::AnmObjTexPatNode::Detach +80058b80 nw4r::g3d::AnmObjTexPatNode::DetachAll +80058be0 nw4r::g3d::AnmObjTexPatNode::UpdateFrame +80058c60 nw4r::g3d::AnmObjTexPatNode::SetFrame +80058cf0 nw4r::g3d::AnmObjTexPatNode::GetFrame +80058d50 nw4r::g3d::AnmObjTexPatNode::SetUpdateRate +80058de0 nw4r::g3d::AnmObjTexPatNode::GetUpdateRate +80058e40 nw4r::g3d::AnmObjTexPatNode::Bind +80058f40 nw4r::g3d::AnmObjTexPatNode::Release +80059000 nw4r::g3d::AnmObjTexPatNode::G3dProc +80059080 nw4r::g3d::AnmObjTexPatOverride::Construct +800591c0 nw4r::g3d::AnmObjTexPatOverride::GetResult +80059280 nw4r::g3d::AnmObjTexPatRes::Construct +80059470 nw4r::g3d::AnmObjTexPatRes::SetFrame +80059530 nw4r::g3d::AnmObjTexPatRes::GetFrame +80059540 nw4r::g3d::AnmObjTexPatRes::SetUpdateRate +80059600 nw4r::g3d::AnmObjTexPatRes::GetUpdateRate +80059610 nw4r::g3d::AnmObjTexPatRes::UpdateFrame +800596f0 nw4r::g3d::AnmObjTexPatRes::Bind +800597f0 nw4r::g3d::AnmObjTexPatRes::GetResult +80059870 nw4r::g3d::AnmObjTexPatRes::G3dProc +800598c0 nw4r::g3d::ApplyTexPatAnmResult +80059ac0 nw4r::g3d::AnmObjTexPatRes::IsDerivedFrom +80059b30 nw4r::g3d::AnmObjTexPat::IsDerivedFrom +80059b80 nw4r::g3d::AnmObjTexPatRes::GetTypeName +80059bb0 nw4r::g3d::AnmObjTexPatRes::GetTypeObj +80059bc0 nw4r::g3d::AnmObjTexPatRes::__dt +80059c10 nw4r::g3d::AnmObjTexPatOverride::IsDerivedFrom +80059c90 nw4r::g3d::AnmObjTexPatNode::IsDerivedFrom +80059d00 nw4r::g3d::AnmObjTexPatOverride::GetTypeName +80059d30 nw4r::g3d::AnmObjTexPatOverride::GetTypeObj +80059d40 nw4r::g3d::AnmObjTexPatOverride::__dt +80059db0 nw4r::g3d::AnmObjTexPatNode::GetTypeName +80059de0 nw4r::g3d::AnmObjTexPatNode::GetTypeObj +80059df0 nw4r::g3d::AnmObjTexPat::GetTypeName +80059e20 nw4r::g3d::AnmObjTexPat::GetTypeObj +80059e30 0x80059e30 +80059e50 0x80059e50 +80059e90 0x80059e90 +80059ea0 0x80059ea0 +80059eb0 0x80059eb0 +80059ec0 0x80059ec0 +80059f00 0x80059f00 +80059f70 0x80059f70 +8005a060 0x8005a060 +8005a180 0x8005a180 +8005a1e0 0x8005a1e0 +8005a260 0x8005a260 +8005a2f0 0x8005a2f0 +8005a350 0x8005a350 +8005a3e0 0x8005a3e0 +8005a440 0x8005a440 +8005a540 0x8005a540 +8005a600 0x8005a600 +8005a680 0x8005a680 +8005a7c0 0x8005a7c0 +8005a870 0x8005a870 +8005aa60 nw4r::g3d::AnmObjTexSrtRes::SetFrame +8005ab20 0x8005ab20 +8005ab30 0x8005ab30 +8005abf0 0x8005abf0 +8005ac00 0x8005ac00 +8005ace0 0x8005ace0 +8005ade0 0x8005ade0 +8005ae60 0x8005ae60 +8005aeb0 0x8005aeb0 +8005af50 0x8005af50 +8005b100 0x8005b100 +8005b170 0x8005b170 +8005b1c0 0x8005b1c0 +8005b1f0 0x8005b1f0 +8005b200 0x8005b200 +8005b250 0x8005b250 +8005b2d0 0x8005b2d0 +8005b340 0x8005b340 +8005b370 0x8005b370 +8005b380 0x8005b380 +8005b3f0 0x8005b3f0 +8005b420 0x8005b420 +8005b430 0x8005b430 +8005b460 0x8005b460 +8005b470 nw4r::g3d::AnmObjChr::Release +8005b4b0 nw4r::g3d::AnmObjChr::Attach +8005b4c0 nw4r::g3d::AnmObjChr::Attach +8005b4d0 nw4r::g3d::AnmObjChr::SetWeight +8005b4e0 nw4r::g3d::AnmObjChr::GetWeight +8005b4f0 nw4r::g3d::AnmObjChr::DetachAll +8005b500 nw4r::g3d::AnmObjChr::__dt +8005b540 nw4r::g3d::AnmObjChrNode::__dt +8005b5b0 nw4r::g3d::AnmObjChrNode::Attach +8005b6a0 nw4r::g3d::AnmObjChrNode::Detach +8005b7c0 nw4r::g3d::AnmObjChrNode::DetachAll +8005b820 nw4r::g3d::AnmObjChrNode::UpdateFrame +8005b8a0 nw4r::g3d::AnmObjChrNode::SetFrame +8005b930 nw4r::g3d::AnmObjChrNode::GetFrame +8005b990 nw4r::g3d::AnmObjChrNode::SetUpdateRate +8005ba20 0x8005ba20 +8005ba80 nw4r::g3d::AnmObjChrNode::Bind +8005bb80 nw4r::g3d::AnmObjChrNode::Bind(BindOption) +8005bc90 nw4r::g3d::AnmObjChrNode::Release +8005bd50 nw4r::g3d::AnmObjChrNode::Release(BindOption) +8005bea0 nw4r::g3d::AnmObjChrNode::G3dProc +8005bf20 nw4r::g3d::AnmObjChrBlend::Construct +8005c0a0 nw4r::g3d::AnmObjChrBlend::GetResult +8005c6e0 nw4r::g3d::AnmObjChrBlend::SetWeight +8005c6f0 nw4r::g3d::AnmObjChrBlend::GetWeight +8005c700 nw4r::g3d::AnmObjChrRes::Construct +8005c8f0 nw4r::g3d::AnmObjChrRes::SetFrame +8005c9b0 nw4r::g3d::AnmObjChrRes::GetFrame +8005c9c0 nw4r::g3d::AnmObjChrRes::SetUpdateRate +8005ca80 nw4r::g3d::AnmObjChrRes::GetUpdateRate +8005ca90 nw4r::g3d::AnmObjChrRes::UpdateFrame +8005cb70 nw4r::g3d::AnmObjChrRes::Bind +8005cc80 nw4r::g3d::AnmObjChrRes::Bind(BindOption) +8005ce80 nw4r::g3d::AnmObjChrRes::Release(BindOption) +8005d050 nw4r::g3d::AnmObjChrRes::GetResult +8005d0d0 nw4r::g3d::AnmObjChrRes::G3dProc +8005d120 nw4r::g3d::AnmObjChrRes::IsDerivedFrom +8005d190 nw4r::g3d::AnmObjChr::IsDerivedFrom +8005d1e0 nw4r::g3d::AnmObjChrRes::GetTypeName +8005d210 nw4r::g3d::AnmObjChrRes::GetTypeObj +8005d220 nw4r::g3d::AnmObjChrRes::__dt +8005d270 nw4r::g3d::AnmObjChrBlend::IsDerivedFrom +8005d2f0 nw4r::g3d::AnmObjChrNode::IsDerivedFrom +8005d360 nw4r::g3d::AnmObjChrBlend::GetTypeName +8005d390 nw4r::g3d::AnmObjChrBlend::GetTypeObj +8005d3a0 nw4r::g3d::AnmObjChrBlend::__dt +8005d410 nw4r::g3d::AnmObjChrNode::GetTypeName +8005d440 nw4r::g3d::AnmObjChrNode::GetTypeObj +8005d450 nw4r::g3d::AnmObjChr::GetTypeName +8005d480 nw4r::g3d::AnmObjChr::GetTypeObj +8005d490 0x8005d490 +8005d4b0 0x8005d4b0 +8005d4f0 0x8005d4f0 +8005d500 0x8005d500 +8005d510 0x8005d510 +8005d520 0x8005d520 +8005d530 0x8005d530 +8005d540 0x8005d540 +8005d580 0x8005d580 +8005d5f0 0x8005d5f0 +8005d6e0 0x8005d6e0 +8005d800 0x8005d800 +8005d860 0x8005d860 +8005d8e0 0x8005d8e0 +8005d970 0x8005d970 +8005d9d0 0x8005d9d0 +8005da60 0x8005da60 +8005dac0 0x8005dac0 +8005dbc0 0x8005dbc0 +8005dc80 0x8005dc80 +8005dd00 0x8005dd00 +8005de80 0x8005de80 +8005e190 0x8005e190 +8005e1a0 0x8005e1a0 +8005e1b0 0x8005e1b0 +8005e3f0 0x8005e3f0 +8005e4c0 0x8005e4c0 +8005e4d0 0x8005e4d0 +8005e590 0x8005e590 +8005e5a0 0x8005e5a0 +8005e690 0x8005e690 +8005e850 0x8005e850 +8005e8d0 0x8005e8d0 +8005e920 0x8005e920 +8005e990 0x8005e990 +8005e9e0 0x8005e9e0 +8005ea10 0x8005ea10 +8005ea20 0x8005ea20 +8005ea70 0x8005ea70 +8005eaf0 0x8005eaf0 +8005eb60 0x8005eb60 +8005eb90 0x8005eb90 +8005eba0 0x8005eba0 +8005ec10 0x8005ec10 +8005ec40 0x8005ec40 +8005ec50 0x8005ec50 +8005ec80 0x8005ec80 +8005ec90 0x8005ec90 +8005ef10 nw4r::g3d::AnmScn::GetLightSetting +8005f240 0x8005f240 +8005f250 0x8005f250 +8005f260 0x8005f260 +8005f2a0 0x8005f2a0 +8005f2b0 0x8005f2b0 +8005f2c0 0x8005f2c0 +8005f2d0 0x8005f2d0 +8005f2e0 0x8005f2e0 +8005f2f0 0x8005f2f0 +8005f300 0x8005f300 +8005f310 0x8005f310 +8005f320 0x8005f320 +8005f330 0x8005f330 +8005f340 0x8005f340 +8005f350 nw4r::g3d::AnmScnRes::Construct +8005f4f0 nw4r::g3d::AnmScnRes::__ct +8005f600 0x8005f600 +8005f640 nw4r::g3d::AnmScnRes::SetFrame +8005f6a0 0x8005f6a0 +8005f6b0 0x8005f6b0 +8005f6e0 0x8005f6e0 +8005f6f0 0x8005f6f0 +8005f770 0x8005f770 +8005f7c0 0x8005f7c0 +8005f900 0x8005f900 +8005f970 0x8005f970 +8005fb00 nw4r::g3d::AnmScnRes::GetFog +8005fbb0 nw4r::g3d::AnmScnRes::GetCamera +8005fd10 0x8005fd10 +8005fdb0 0x8005fdb0 +8005fe40 0x8005fe40 +8005fed0 0x8005fed0 +8005ff60 0x8005ff60 +8005ffa0 0x8005ffa0 +8005fff0 0x8005fff0 +80060170 0x80060170 +800601c0 0x800601c0 +80060200 0x80060200 +80060230 0x80060230 +80060240 0x80060240 +80060270 0x80060270 +80060280 nw4r::g3d::G3dObj::__dt +800602d0 nw4r::g3d::G3dObj::Destroy +80060350 nw4r::g3d::G3dObj::DetachFromParent +800603b0 nw4r::g3d::G3dObj::IsDerivedFrom +800603d0 nw4r::g3d::G3dObj::GetTypeName +80060400 nw4r::g3d::G3dObj::GetTypeObj +80060410 0x80060410 +80060420 nw4r::g3d::PlayPolicy_Loop +80060490 nw4r::g3d::AnmObj::SetAnmFlag +800604c0 nw4r::g3d::AnmObj::TestAnmFlag +800604e0 nw4r::g3d::fifo::GDSetGenMode2 +80060560 0x80060560 +80060590 Fifo_GDSetTexCoordScale2 +80060600 nw4r::g3d::fifo::GDSetIndTexMtx +800608a0 0x800608a0 +80060900 0x80060900 +80060980 0x80060980 +80060a00 nw4r::g3d::tmem::SetTMemLayout +80060b00 TexRegionCallback(_GXTexObj_* +80060bd0 0x80060bd0 +80060c00 setTexRegion_(TMemCachePlan) +80060d60 nw4r::g3d::detail::Copy32ByteBlocks +80060e40 nw4r::g3d::detail::ZeroMemory32ByteBlocks +80060f10 nw4r::g3d::detail::ZeroMemory16ByteBlocks +80060fa0 0x80060fa0 +80061380 0x80061380 +80061490 0x80061490 +800618d0 nw4r::g3d::detail::ScnDependentMtxFunc::DefaultMa +800618e0 nw4r::g3d::G3DState::IndTexMtxInfo::FifoSend +80061950 0x80061950 +80061990 0x80061990 +800619a0 0x800619a0 +80061aa0 0x80061aa0 +80061ed0 nw4r::g3d::G3DState::CameraMtxState::CameraMtxSta +80061f70 nw4r::g3d::G3DState::LoadResMatMisc +80061fe0 nw4r::g3d::G3DState::LoadResTexObj +80062250 nw4r::g3d::G3DState::LoadResTlutObj +800623a0 nw4r::g3d::G3DState::LoadResGenMode +80062570 nw4r::g3d::G3DState::LoadResTev +80062780 nw4r::g3d::G3DState::LoadResMatPix +80062830 nw4r::g3d::G3DState::LoadResMatTevColor +800628e0 nw4r::g3d::G3DState::LoadResMatIndMtxAndScale +800629a0 nw4r::g3d::G3DState::LoadResMatIndMtxAndScale +80062b70 nw4r::g3d::G3DState::LoadResMatChan +800632a0 nw4r::g3d::G3DState::LoadResMatTexCoordGen +80063330 nw4r::g3d::G3DState::LoadResTexSrt +800635e0 0x800635e0 +80063790 0x80063790 +80063ae0 nw4r::g3d::G3DState::SetViewPosNrmMtxArray +80063b70 0x80063b70 +80063c40 nw4r::g3d::G3DState::SetScnDependentTexMtxFunc +80063cb0 nw4r::g3d::G3DState::GetScnDependentTexMtxFunc +80063d10 0x80063d10 +80063d50 0x80063d50 +80063d60 0x80063d60 +80063e00 nw4r::g3d::G3DState::LoadFog +80063ec0 0x80063ec0 +80063ed0 0x80063ed0 +80063f00 nw4r::g3d::G3DState::LoadLightSet +80063f60 nw4r::g3d::G3DState::LoadLightSet +80063ff0 nw4r::g3d::G3DState::SetCameraProjMtx +800640a0 nw4r::g3d::G3DState::GetCameraMtxPtr +800640c0 0x800640c0 +80064130 nw4r::g3d::G3DState::GetCameraMtxPtr +80064160 nw4r::g3d::G3DState::SetRenderModeObj +80064360 nw4r::g3d::G3DState::GetRenderModeObj +80064370 nw4r::g3d::G3DState::Invalidate +800644c0 nw4r::g3d::G3DState::IndMtxOpStd::SetNrmMapMtx +80064620 nw4r::g3d::G3DState::IndMtxOpStd::Reset +80064670 nw4r::g3d::G3DState::IndMtxOpStd::__cl +800647e0 __sinit_g3d_state_cpp +80064a50 nw4r::g3d::detail::LoadMaterial +80064ef0 0x80064ef0 +800657a0 0x800657a0 +80065850 0x80065850 +80065920 0x80065920 +80065b60 0x80065b60 +80065e40 0x80065e40 +80066120 0x80066120 +800664a0 0x800664a0 +80066720 0x80066720 +800669c0 0x800669c0 +80066cf0 0x80066cf0 +80067190 0x80067190 +800676f0 0x800676f0 +80067780 0x80067780 +800677e0 0x800677e0 +800677f0 nw4r::g3d::detail::workmem::GetMtxIDTemporary +80067800 0x80067800 +80067810 0x80067810 +80067820 0x80067820 +80067830 0x80067830 +80067840 nw4r::g3d::WorldMtxManip::SetScale +800678c0 nw4r::g3d::CalcWorld +80067e90 0x80067e90 +80068170 0x80068170 +80068690 0x80068690 +80068860 nw4r::g3d::DrawResMdlLoop(byteCode) +800689a0 nw4r::g3d::DrawResMdlLoop(byteCode, rep) +80068b70 nw4r::g3d::DrawResMdlLoop(MdlZ) +80068c80 nw4r::g3d::DrawResMdlLoop(MdlZ, rep) +80068de0 nw4r::g3d::SetUpMdlZ +80068f20 nw4r::g3d::DrawResMdlDirectly +80069150 0x80069150 +80069190 0x80069190 +80069200 0x80069200 +800697c0 0x800697c0 +80069d80 0x80069d80 +80069fe0 nw4r::g3d::Camera::__ct +80069ff0 nw4r::g3d::Camera::Init +8006a040 nw4r::g3d::Camera::Init +8006a160 nw4r::g3d::Camera::SetPosition +8006a190 nw4r::g3d::Camera::SetPosition +8006a1d0 nw4r::g3d::Camera::SetPosture +8006a3f0 nw4r::g3d::Camera::SetCameraMtxDirectly +8006a440 nw4r::g3d::Camera::SetPerspective +8006a480 nw4r::g3d::Camera::SetOrtho +8006a4c0 nw4r::g3d::Camera::SetProjectionMtxDirectly +8006a510 nw4r::g3d::Camera::SetScissor +8006a530 nw4r::g3d::Camera::SetScissorBoxOffset +8006a550 nw4r::g3d::Camera::SetViewport +8006a5f0 nw4r::g3d::Camera::SetViewportZRange +8006a610 nw4r::g3d::Camera::GetViewport +8006a680 nw4r::g3d::Camera::GetCameraMtx +8006a6e0 nw4r::g3d::Camera::GetProjectionMtx +8006a7c0 nw4r::g3d::Camera::GetProjectionTexMtx +8006a890 nw4r::g3d::Camera::GetEnvironmentTexMtx +8006a910 nw4r::g3d::Camera::GXSetViewport +8006a9a0 nw4r::g3d::Camera::GXSetProjection +8006aa70 nw4r::g3d::Camera::GXSetScissor +8006aaa0 nw4r::g3d::Camera::GXSetScissorBoxOffset +8006aac0 0x8006aac0 +8006aee0 0x8006aee0 +8006b040 nw4r::g3d::detail::dcc::CalcWorldMtx_Basic +8006b1b0 0x8006b1b0 +8006b1f0 0x8006b1f0 +8006b290 0x8006b290 +8006b2d0 0x8006b2d0 +8006b390 0x8006b390 +8006b440 0x8006b440 +8006b490 0x8006b490 +8006b570 0x8006b570 +8006b5f0 0x8006b5f0 +8006b720 0x8006b720 +8006b750 0x8006b750 +8006b8f0 0x8006b8f0 +8006ba40 0x8006ba40 +8006bad0 0x8006bad0 +8006bc80 0x8006bc80 +8006bd20 nw4r::g3d::detail::dcc::CalcWorldMtx_Maya_SSC_App +8006bec0 0x8006bec0 +8006bf00 0x8006bf00 +8006bf90 0x8006bf90 +8006bfd0 0x8006bfd0 +8006c070 0x8006c070 +8006c140 0x8006c140 +8006c190 0x8006c190 +8006c260 0x8006c260 +8006c2e0 0x8006c2e0 +8006c3f0 0x8006c3f0 +8006c420 0x8006c420 +8006c560 0x8006c560 +8006c690 0x8006c690 +8006c720 0x8006c720 +8006c880 0x8006c880 +8006c920 nw4r::g3d::detail::dcc::CalcWorldMtx_Xsi +8006cae0 0x8006cae0 +8006cb30 0x8006cb30 +8006cbe0 0x8006cbe0 +8006cc20 0x8006cc20 +8006cce0 0x8006cce0 +8006cdb0 0x8006cdb0 +8006ce10 0x8006ce10 +8006cee0 0x8006cee0 +8006cf60 0x8006cf60 +8006d090 0x8006d090 +8006d0c0 0x8006d0c0 +8006d210 0x8006d210 +8006d350 0x8006d350 +8006d3f0 0x8006d3f0 +8006d560 0x8006d560 +8006d600 nw4r::g3d::ScnObj::CalcWorldMtx +8006d6b0 nw4r::g3d::ScnObj::CalcViewMtx +8006d6d0 nw4r::g3d::ScnObj::__ct +8006d7c0 nw4r::g3d::ScnObj::__dt +8006d840 nw4r::g3d::ScnObj::SetScnObjOption +8006d860 nw4r::g3d::ScnObj::SetScnObjOption_caseD_1 +8006d888 nw4r::g3d::ScnObj::SetScnObjOption_caseD_2 +8006d8b0 nw4r::g3d::ScnObj::SetScnObjOption_caseD_3 +8006d8d8 nw4r::g3d::ScnObj::SetScnObjOption_caseD_4 +8006d900 nw4r::g3d::ScnObj::SetScnObjOption_caseD_5 +8006d928 nw4r::g3d::ScnObj::SetScnObjOption_caseD_6 +8006d950 nw4r::g3d::ScnObj::SetScnObjOption_caseD_7 +8006d978 nw4r::g3d::ScnObj::SetScnObjOption_caseD_8 +8006d9a0 nw4r::g3d::ScnObj::SetScnObjOption_caseD_9 +8006d9c8 nw4r::g3d::ScnObj::SetScnObjOption_caseD_0 +8006d9e0 nw4r::g3d::ScnObj::GetScnObjOption +8006da10 nw4r::g3d::ScnObj::GetScnObjOption_caseD_1 +8006da20 nw4r::g3d::ScnObj::GetScnObjOption_caseD_2 +8006da30 nw4r::g3d::ScnObj::GetScnObjOption_caseD_3 +8006da40 nw4r::g3d::ScnObj::GetScnObjOption_caseD_4 +8006da50 nw4r::g3d::ScnObj::GetScnObjOption_caseD_5 +8006da60 nw4r::g3d::ScnObj::GetScnObjOption_caseD_6 +8006da70 nw4r::g3d::ScnObj::GetScnObjOption_caseD_7 +8006da80 nw4r::g3d::ScnObj::GetScnObjOption_caseD_8 +8006da90 nw4r::g3d::ScnObj::GetScnObjOption_caseD_9 +8006daa0 nw4r::g3d::ScnObj::GetScnObjOption_caseD_0 +8006dab0 nw4r::g3d::ScnObj::SetMtx +8006db40 nw4r::g3d::ScnObj::SetMtx +8006dba0 nw4r::g3d::ScnObj::GetMtx +8006dbf0 nw4r::g3d::ScnObj::GetValueForSortOpa +8006dc00 nw4r::g3d::ScnObj::GetValueForSortXlu +8006dc10 nw4r::g3d::ScnObj::SetPriorityDrawOpa +8006dc40 nw4r::g3d::ScnObj::SetPriorityDrawXlu +8006dc70 nw4r::g3d::ScnObj::EnableScnObjCallbackTiming +8006dcb0 nw4r::g3d::ScnObj::EnableScnObjCallbackExecOp +8006dcd0 nw4r::g3d::ScnObj::SetBoundingVolume +8006dd60 nw4r::g3d::ScnObj::GetBoundingVolume +8006ddc0 nw4r::g3d::ScnLeaf::ForEach +8006de00 nw4r::g3d::ScnLeaf::SetScnObjOption +8006de40 nw4r::g3d::ScnLeaf::GetScnObjOption +8006de90 nw4r::g3d::ScnObj::CalcWorldMtx +8006df90 nw4r::g3d::ScnLeaf::GetScaleProperty +8006dfd0 nw4r::g3d::ScnLeaf::DefG3dProcScnLeaf +8006e2b0 nw4r::g3d::ScnGroup::Construct +8006e370 nw4r::g3d::ScnGroup::ForEach +8006e4b0 nw4r::g3d::ScnGroup::ScnGroup_G3DPROC_GATHER_SCNOBJ +8006e5d0 nw4r::g3d::ScnGroup::G3dProc +8006e610 nw4r::g3d::ScnGroup::DefG3dProcScnGroup +8006ea80 nw4r::g3d::ScnGroup::Insert +8006ec10 nw4r::g3d::ScnGroup::Remove(idx) +8006ecd0 nw4r::g3d::ScnGroup::Remove(ScnObj) +8006ed60 nw4r::g3d::ScnGroup::__ct +8006edd0 nw4r::g3d::ScnGroup::__dt +8006ee90 nw4r::g3d::ScnGroup::IsDerivedFrom +8006eee0 nw4r::g3d::G3dObj::IsDerivedFrom +8006ef20 nw4r::g3d::ScnGroup::GetTypeNameStatic +8006ef50 nw4r::g3d::ScnGroup::GetTypeObjStatic +8006ef60 nw4r::g3d::ScnLeaf::IsDerivedFrom +8006efb0 nw4r::g3d::ScnLeaf::GetTypeNameStatic +8006efe0 nw4r::g3d::ScnLeaf::GetTypeObjStatic +8006eff0 nw4r::g3d::ScnLeaf::destruct +8006f080 nw4r::g3d::ScnObj::GetTypeNameStatic +8006f0b0 nw4r::g3d::ScnObj::GetTypeObjStatic +8006f0c0 nw4r::g3d::ScnRoot::Construct +8006f200 nw4r::g3d::ScnRoot::G3dProc +8006f2b0 nw4r::g3d::ScnRoot::GetCamera +8006f310 nw4r::g3d::ScnRoot::GetCurrentCamera +8006f350 nw4r::g3d::ScnRoot::SetCurrentCamera +8006f360 nw4r::g3d::ScnRoot::GetFog +8006f3c0 nw4r::g3d::ScnRoot::GetLightSet +8006f410 nw4r::g3d::ScnRoot::SetAnmScn +8006f4b0 nw4r::g3d::ScnRoot::UpdateFrame +8006f520 0x8006f520 +8006f750 nw4r::g3d::ScnRoot::CalcAnmScn +8006f8e0 nw4r::g3d::ScnRoot::CalcWorld +8006f930 nw4r::g3d::ScnRoot::CalcMaterial +8006f950 nw4r::g3d::ScnRoot::CalcVtx +8006f970 nw4r::g3d::ScnRoot::CalcView +8006f9f0 nw4r::g3d::ScnRoot::GatherDrawScnObj +8006fae0 nw4r::g3d::ScnRoot::ZSort +8006fb40 nw4r::g3d::ScnRoot::DrawOpa +8006fbc0 nw4r::g3d::ScnRoot::DrawXlu +8006fc40 nw4r::g3d::ScnRoot::ForceDrawMode +8006fc70 nw4r::g3d::ScnRoot::__ct +8006fd70 0x8006fd70 +8006fdf0 nw4r::g3d::ScnObjGather::Add +8006ff10 nw4r::g3d::ScnObjGather::ZSort +8006ff70 0x8006ff70 +8006ffb0 0x8006ffb0 +8006fff0 std::sort(void_(nw4r::g3d::ScnObj_** +80070370 std::sort(void_(nw4r::g3d::ScnObj_** +800706f0 std::__sort132(void_(nw4r::g3d::ScnObj_** +800707f0 nw4r::g3d::ScnObjGather::Sort +80070850 nw4r::g3d::@unnamed@g3d_scnroot_cpp@::LessByGetVa +800708e0 nw4r::g3d::@unnamed@g3d_scnroot_cpp@::LessByGetVa +80070970 nw4r::g3d::ScnObjGather::Sort(CompFuncs) +800709e0 nw4r::g3d::ScnObjGather::DrawOpa +80070a70 nw4r::g3d::ScnObjGather::DraxXlu +80070b00 nw4r::g3d::ScnObjGather::CheckScnObj +80070b10 nw4r::g3d::ScnObjGather::__ct +80070b40 nw4r::g3d::ScnObjGather::Clear +80070b50 nw4r::g3d::ScnObjGather::__dt +80070b90 0x80070b90 +80070c00 0x80070c00 +80070c30 0x80070c30 +80070c40 nw4r::g3d::ScnMdlSimple::Construct +80070de0 nw4r::g3d::ScnMdlSimple::ScnMdlSmpl_CalcPosture +80071040 nw4r::g3d::ScnMdlSimple::ScnMdlSmpl_G3DPROC_GATHER_SCNOBJ +80071080 nw4r::g3d::ScnMdlSimple::ScnMdlSmpl_G3DPROC_CALC_ +800713d0 nw4r::g3d::ScnMdlSimple::G3dProc +80071c60 nw4r::g3d::ScnMdlSimple::SetScnObjOption +80071ca0 nw4r::g3d::ScnMdlSimple::GetScnObjOption +80071ce0 nw4r::g3d::ScnMdlSimple::GetScnMtxPos +80071e20 nw4r::g3d::ScnMdlSimple::SetAnmObj +80072430 nw4r::g3d::ScnMdlSimple::RemoveAnmObj +800725b0 nw4r::g3d::ScnMdlSimple::RemoveAnmObj +80072690 nw4r::g3d::ScnMdlSimple::GetAnmObj +800726f0 nw4r::g3d::ScnMdlSimple::GetAnmObj +80072750 nw4r::g3d::ScnMdlSimple::UpdateFrame +80072810 nw4r::g3d::ScnMdlSimple::EnableScnMdlCallbackTiming +80072850 nw4r::g3d::ScnMdlSimple::DisableScnMdlCallbackTiming +80072890 nw4r::g3d::ScnMdlSimple::GetViewPosMtxArray +800728c0 nw4r::g3d::ScnMdlSimple::GetViewNrmMtxArray +80072900 nw4r::g3d::ScnMdlSimple::GetViewTexMtxArray +80072940 nw4r::g3d::ScnMdlSimple::GetByteCode +80072990 0x80072990 +80072bb0 nw4r::g3d::ScnMdlSimple::destruct +80072cd0 nw4r::g3d::ScnMdlSimple::IsDerivedFrom +80072d40 nw4r::g3d::ScnMdlSimple::GetTypeNameStatic +80072d70 nw4r::g3d::ScnMdlSimple::GetTypeObj +80072d80 nw4r::g3d::ScnMdl::CopiedMatAccess::GetResTexObj +80072dd0 nw4r::g3d::ScnMdl::CopiedMatAccess::GetResMatTevColor +80072e20 nw4r::g3d::ScnMdl::CopiedMatAccess::GetResTexSrtEx +80072e80 nw4r::g3d::ScnMdl::CopiedMatAccess::GetResMatMiscEx +80072ee0 nw4r::g3d::ScnMdl::CopiedMatAccess::GetResMatTevColorEx +80072f60 nw4r::g3d::ScnMdl::CopiedMatAccess::GetResTevEx +80072fd0 nw4r::g3d::ScnMdl::CopiedMatAccess::__ct +80073250 nw4r::g3d::ScnMdl::CopiedVisAccess::IsVisible +800732d0 nw4r::g3d::ScnMdl::CopiedVisAccess::CopiedVisAcce +80073390 nw4r::g3d::ScnMdl::Construct +80073f20 nw4r::g3d::ScnMdl::ScnMdl_G3DPROC_CALC_MAT +80074690 nw4r::g3d::ScnMdl::G3dProc +80074b40 nw4r::g3d::ScnMdl::SetScnObjOption +80074b80 nw4r::g3d::ScnMdl::GetScnObjOption +80074bc0 nw4r::g3d::ScnMdl::InitBuffer +80074f60 nw4r::g3d::ScnMdl::CleanMatBuffer +800752a0 nw4r::g3d::ScnMdl::SetAnmObj +80075410 nw4r::g3d::ScnMdl::RemoveAnmObj +80075610 nw4r::g3d::ScnMdl::RemoveAnmObj +80075660 nw4r::g3d::ScnMdl::GetAnmObj +80075680 nw4r::g3d::ScnMdl::GetAnmObj +800756a0 nw4r::g3d::ScnMdl::__dt +80075710 nw4r::g3d::ScnMdl::IsDerivedFrom +80075790 nw4r::g3d::ScnMdl::GetTypeNameStatic +800757c0 nw4r::g3d::ScnMdl::GetTypeObjStatic +800757d0 0x800757d0 +800757e0 0x800757e0 +80075910 nw4r::g3d::ScnObjGatherExScnMdl::DrawOpa +80075940 nw4r::g3d::ScnObjGatherExScnMdl::DrawXlu +80075970 nw4r::g3d::ScnObjGatherExScnMdl::CheckScnObj +80075af0 nw4r::g3d::ScnObjGatherExScnMdl::GetResMdl +80075b00 nw4r::g3d::ScnObjGatherExScnMdl::DrawLoop +80075ef0 nw4r::g3d::ScnObjGatherExScnMdl::HasEqualTarget +80075f80 nw4r::g3d::ScnObjGatherExScnMdl::TypeID +80075f90 nw4r::g3d::ScnGroupEx::Construct +800760f0 nw4r::g3d::ScnGroupEx::SetResMdl +80076130 0x80076130 +80076170 nw4r::g3d::ScnGroupEx::G3dProc +800764a0 nw4r::g3d::ScnGroupEx::__dt +800764e0 nw4r::g3d::ScnObjGatherExScnMdl::SetResMdl +80076590 nw4r::g3d::ScnObjGatherExScnMdl::__dt +800765d0 0x800765d0 +800765e0 0x800765e0 +800765f0 0x800765f0 +80076600 0x80076600 +80076610 0x80076610 +80076620 0x80076620 +80076630 nw4r::g3d::ScnGroupEx::IsDerivedFrom +800766a0 nw4r::g3d::ScnGroupEx::GetTypeName +800766d0 nw4r::g3d::ScnGroupEx::GetTypeObj +800766e0 nw4r::g3d::ScnMdl1Mat1Shp::Construct +80076800 nw4r::g3d::ScnMdl1Mat1Shp::G3dProc +80076af0 nw4r::g3d::ScnMdl1Mat1Shp::IsDerivedFrom +80076b60 nw4r::g3d::ScnMdl1Mat1Shp::GetTypeName +80076b90 nw4r::g3d::ScnMdl1Mat1Shp::GetTypeObj +80076ba0 nw4r::g3d::ScnMdl1Mat1Shp::__dt +80076be0 nw4r::g3d::CalcMaterialDirectly +80076ff0 nw4r::g3d::G3dInit +800770e0 nw4r::g3d::G3dReset +800770f0 nw4r::g3d::ScnProc::Construct +80077200 nw4r::g3d::ScnProc::G3dProc +80077300 nw4r::g3d::ScnProc::IsDerivedFrom +80077370 nw4r::g3d::ScnProc::GetTypeName +800773a0 nw4r::g3d::ScnProc::GetTypeObj +800773b0 nw4r::g3d::ScnProc::__dt +800773f0 nw4r::g3d::Fog::__ct +80077400 nw4r::g3d::Fog::Init +80077470 nw4r::g3d::Fog::CopyTo +800774d0 nw4r::g3d::Fog::SetFogRangeAdjParam +800774f0 nw4r::g3d::Fog::SetGP +80077580 nw4r::g3d::LightObj::Clear +800775a0 nw4r::g3d::LightObj::InitLightColor +800775f0 nw4r::g3d::LightObj::InitLightPos +80077630 nw4r::g3d::LightObj::InitLightDir +80077670 nw4r::g3d::LightObj::InitLightSpot +800776b0 nw4r::g3d::LightObj::InitLightAttnA +800776f0 nw4r::g3d::LightObj::InitLightDistAttn +80077730 nw4r::g3d::LightObj::InitLightAttnK +80077770 nw4r::g3d::LightObj::InitSpecularDir +800777b0 nw4r::g3d::LightObj::InitLightShininess +80077810 nw4r::g3d::LightObj::GetLightPos +80077830 nw4r::g3d::LightObj::GetLightDir +80077850 nw4r::g3d::LightSetting::__ct +80077c90 nw4r::g3d::LightSetting::Import +80077e30 nw4r::g3d::LightSetting::ApplyViewMtx +80077f50 nw4r::g3d::LightSet::SelectLightObj +80077fc0 nw4r::g3d::LightSet::SelectAmbLightObj +80078030 nw4r::g3d::CalcVtx +80078840 nw4r::lyt::LytInit +800788a0 nw4r::lyt::Pane::__ct +800789e0 nw4r::lyt::Pane::__dt +80078b20 nw4r::lyt::Pane::AppendChild +80078b70 nw4r::lyt::Pane::GetPaneRect +80078c00 nw4r::lyt::Pane::GetVtxColor +80078c10 nw4r::lyt::Pane::SetVtxColor +80078c20 nw4r::lyt::Pane::GetColorElement +80078c50 nw4r::lyt::Pane::SetColorElement +80078c80 nw4r::lyt::Pane::GetVtxColorElement +80078c90 nw4r::lyt::Pane::SetVtxColorElement +80078ca0 nw4r::lyt::Pane::FindPaneByName +80078d50 nw4r::lyt::Pane::FindMaterialByName +80078e10 nw4r::lyt::Pane::CalculateMtx +80079110 nw4r::lyt::Pane::Draw +800791a0 nw4r::lyt::Pane::DrawSelf +800791b0 nw4r::lyt::Pane::Animate +80079240 nw4r::lyt::Pane::AnimateSelf +80079300 nw4r::lyt::Pane::BindAnimation +80079320 nw4r::lyt::Pane::UnbindAnimation +800793b0 nw4r::lyt::Pane::UnbindAllAnimation +800793d0 nw4r::lyt::UnbindAnimationSelf +80079430 nw4r::lyt::Pane::AddAnimationLink +80079470 nw4r::lyt::Pane::FindAnimationLinkSelf +80079480 nw4r::lyt::Pane::FindAnimationLinkSelf +80079490 nw4r::lyt::Pane::SetAnimationEnable +80079590 nw4r::lyt::Pane::SetAnimationEnable +80079690 nw4r::lyt::Pane::LoadMtx +800796f0 nw4r::lyt::Pane::GetVtxPos +800797c0 nw4r::lyt::Pane::GetMaterialNum +800797e0 nw4r::lyt::Pane::GetMaterial +800797f0 nw4r::lyt::Pane::GetMaterial +80079810 nw4r::lyt::Pane::GetRuntimeTypeInfo +80079820 0x80079820 +80079830 nw4r::lyt::Group::__ct +800798a0 nw4r::lyt::Group::__ct +800799c0 nw4r::lyt::Group::__dt +80079a70 nw4r::lyt::Group::AppendPane +80079b00 nw4r::lyt::GroupContainer::__dt +80079bd0 nw4r::lyt::GroupContainer::AppendGroup +80079c10 nw4r::lyt::GroupContainer::FindGroupByName +80079c90 nw4r::lyt::SetTagProcessorImpl +80079e50 nw4r::lyt::IsIncludeAnimationGroupRef +80079f20 nw4r::lyt::Layout::__ct +80079f60 nw4r::lyt::Layout::__dt +8007a090 nw4r::lyt::Layout::Build +8007a3e0 nw4r::lyt::Layout::CreateAnimTransform +8007a460 nw4r::lyt::Layout::CreateAnimTransform +8007a4c0 nw4r::lyt::Layout::CreateAnimTransform +8007a550 nw4r::lyt::Layout::BindAnimation +8007a580 nw4r::lyt::Layout::UnbindAnimation +8007a5b0 nw4r::lyt::Layout::UnbindAllAnimation +8007a5d0 nw4r::lyt::Layout::BindAnimationAuto +8007a860 nw4r::lyt::Layout::SetAnimationEnable +8007a890 nw4r::lyt::Layout::CalculateMtx +8007a8b0 nw4r::lyt::Layout::Draw +8007a8d0 nw4r::lyt::Layout::Animate +8007a8f0 nw4r::lyt::Layout::SetTagProcessor +8007aab0 nw4r::lyt::Layout::BuildPaneObj +8007aca0 nw4r::ut::Color::__ct +8007acb0 nw4r::lyt::Picture::__ct +8007ae00 nw4r::lyt::Picture::__dt +8007aee0 nw4r::lyt::Picture::Append +8007b0a0 nw4r::lyt::Picture::GetVtxColor +8007b0d0 nw4r::lyt::Picture::SetVtxColor +8007b100 nw4r::lyt::Picture::GetVtxColorElement +8007b120 nw4r::lyt::Picture::SetVtxColorElement +8007b140 nw4r::lyt::Picture::DrawSelf +8007b220 nw4r::lyt::Picture::GetRuntimeTypeInfo +8007b230 __sinit_\lyt_picture_cpp +8007b240 nw4r::lyt::TextBox::__ct +8007b530 nw4r::lyt::TextBox::__dt +8007b6d0 nw4r::lyt::TextBox::GetVtxColor +8007b700 nw4r::lyt::TextBox::SetVtxColor +8007b750 nw4r::lyt::TextBox::GetVtxColorElement +8007b770 nw4r::lyt::TextBox::SetVtxColorElement +8007b790 nw4r::lyt::TextBox::DrawSelf +8007be70 0x8007be70 +8007c250 0x8007c250 +8007c290 nw4r::lyt::TextBox::GetStringBufferLength +8007c2c0 nw4r::lyt::TextBox::AllocStringBuffer +8007c390 nw4r::lyt::TextBox::FreeStringBuffer +8007c3e0 nw4r::lyt::TextBox::SetString +8007c4c0 nw4r::lyt::TextBox::SetString +8007c590 nw4r::ut::Font__dt +8007c5d0 nw4r::lyt::TextBox::LoadMtx +8007c660 0x8007c660 +8007c9d0 0x8007c9d0 +8007cb30 nw4r::lyt::TextBox::GetRuntimeTypeInfo +8007cb40 0x8007cb40 +8007cb50 nw4r::lyt::Window::__ct +8007cde0 nw4r::lyt::Window::__dt +8007cf30 nw4r::lyt::Window::FindMaterialByName +8007d030 nw4r::lyt::Window::GetVtxColor +8007d060 nw4r::lyt::Window::SetVtxColor +8007d090 nw4r::lyt::Window::GetVtxColorElement +8007d0b0 nw4r::lyt::Window::SetVtxColorElement +8007d0d0 nw4r::lyt::Window::DrawSelf +8007d210 nw4r::lyt::Window::AnimateSelf +8007d2a0 nw4r::lyt::Window::UnbindAnimationSelf +8007d330 nw4r::lyt::Window::DrawContent +8007d440 nw4r::lyt::Window::DrawFrame +8007da20 nw4r::lyt::Window::DrawFrame4 +8007e170 nw4r::lyt::Window::DrawFrame8 +8007efc0 nw4r::lyt::Window::GetFrameSize +8007f0c0 nw4r::lyt::Window:GetMaterialNum +8007f0d0 nw4r::lyt::Window::GetMaterial +8007f100 nw4r::lyt::Window::GetFrameMaterial +8007f130 nw4r::lyt::Window::GetContent +8007f140 0x8007f140 +8007f150 0x8007f150 +8007f160 Bounding_construct +8007f1a0 0x8007f1a0 +8007f200 0x8007f200 +8007f210 nw4r::lyt::Window::GetRuntimeTypeInfo +8007f220 __sinit_\lyt_bounding_cpp +8007f230 0x8007f230 +8007f340 0x8007f340 +8007f540 nw4r::math::VEC2::__as +8007f560 nw4r::ut::LinkList::__ct +8007f580 nw4r::lyt::Material::__ct +8007fbf0 _GXColorS10::Operator= +8007fc20 nw4r::ut::Color::Operator= +8007fc30 nw4r::lyt::MaterialResourceNum::GetTexMapNum +8007fc40 nw4r::lyt::MaterialResourceNum::GetTexSRTNum +8007fc50 nw4r::lyt::MaterialResourceNum::GetCoordGenNum +8007fc60 nw4r::lyt::MaterialResourceNum::GetChanCtrlNum +8007fc70 nw4r::lyt::MaterialResourceNum::GetMapColNum +8007fc80 nw4r::lyt::MaterialResourceNum::HasTevSwapTable +8007fc90 nw4r::lyt::MaterialResourceNum::HasAlphaCompare +8007fca0 nw4r::lyt::MaterialResourceNum::HasBlendMode +8007fcb0 nw4r::lyt::MaterialResourceNum::GetIndTexStageNum +8007fcc0 nw4r::lyt::MaterialResourceNum::GetIndTexStageNum +8007fcd0 0x8007fcd0 +8007fce0 0x8007fce0 +8007fd00 nw4r::lyt::res::TexMap::GetWarpModeS +8007fd10 nw4r::lyt::res::TexMap::GetWarpModeT +8007fd20 0x8007fd20 +8007fd40 nw4r::lyt::res::TexMap::GetMinFilter +8007fd60 nw4r::lyt::res::TexMap::GetMagFilter +8007fd80 0x8007fd80 +8007fdb0 0x8007fdb0 +8007fde0 0x8007fde0 +8007fe10 nw4r::lyt::TevSwapMode::__as +8007fe20 nw4r::lyt::TexSRT::operator_= +8007fe50 0x8007fe50 +8007fe80 0x8007fe80 +8007ff30 0x8007ff30 +8007ff60 0x8007ff60 +8007ff90 0x8007ff90 +8007ffa0 0x8007ffa0 +8007ffb0 nw4r::snd::DvdSoundArchive::OpenExtStream +8007ffc0 0x8007ffc0 +8007ffd0 0x8007ffd0 +8007ffe0 0x8007ffe0 +8007fff0 0x8007fff0 +80080000 nw4r::lyt::detail::ConvertOffsToPtr +80080010 nw4r::lyt::detail::ConvertOffsToPtr +80080020 0x80080020 +80080030 0x80080030 +80080040 0x80080040 +80080050 nw4r::lyt::detail::ConvertOffsToPtr::CalcCompletion +80510898 0x80510898 +805108d8 0x805108d8 +805109b4 0x805109b4 +80510a90 KMP::Manager::CalcNextCPRecursive +80510e80 KMP::Manager::CalcNextCP +80511780 KMP::Manager::ResetCKPTScannedState +805117fc KMP::Manager::CalcExactFinishTime +80511848 KMP::Holder::CalcExactFinishTime +8051199c Vec2::Operator- +805119c0 Vec2::Operator+ +805119e4 KMP::CKPTSection::CalcDistanceFromCPRecursive +80511cf0 KMP::CKPTSection::CalcTotalDistance +80512014 KMP::Manager::CreateInstance +8051209c KMP::Manager::DestroyInstance +805120ec KMP::Manager::__ct +8051212c KMP::Manager::__dt +8051216c KMP::Manager::Init +80512590 KMP::Manager::GetRawKMP +805125ac KMP::RawHolder::__ct +805125ec KMP::Holder::GetType +805125f8 KMP::Manager::GetCAMECount +80512614 KMP::RawHolder::GetVersion +8051261c KMP::Holder::GetOpeningCamIdx +8051262c KMP::Holder::SetId +80512634 KMP::Manager::GetAREACount +80512650 KMP::Manager::GetEENPTCount +8051266c KMP::Manager::GetITPTCount +80512688 KMP::Manager::GetJGPTCount +805126a4 KMP::Manager::GetKTPTCount +805126c0 KMP::Holder::IsNarrowGrid +805126cc KMP::Holder::GetFilterEffectColor +805126d8 KMP::Holder::HasFilterEffect +805126e4 KMP::Manager::ParseSTGI +80512804 KMP::Manager::ParseMSPT +80512924 KMP::Manager::ParseCNPT +80512a44 KMP::Manager::ParseJGPT +80512b64 KMP::Manager::ParseCAME +80512c84 KMP::Manager::ParseAREA +80512d18 KMP::Manager::ParsePOTI +80512e48 KMP::Manager::ParseGOBJ +80512f80 Vec3::__dt +80512fc0 KMP::Manager::ParseCKPT +805130fc KMP::Manager::ParseCKPH +8051345c KMP::Manager::ParseITPT +8051357c KMP::Manager::ParseITPH +80513698 KMP::Manager::ParseENPT +805137c0 KMP::Manager::ParseENPH +805138dc KMP::Manager::ParseKTPT +80513a5c KMP::AREASection::GetHolder +80513a80 KMP::JGPTSection::GetHolder +80513aa4 KMP::KTPTSection::GetHolder +80513ac8 KMP::Manager::GetHolder +80513b14 KMP::Holder::GetRoute +80513b88 KMP::KTPTSection::GetBlock +80513bd8 KMP::KTPTSection::__ct +80513ce8 KMP::Holder::CalcCoordinates_0Indexed +80514114 0x80514114 +80514154 Vec3::Operator-(unary) +8051417c Vec3::RotateQuaternion +80514190 Vec3::MultiplyByScalar +805141b8 Vec3::Operator+ +805141ec Vec3::Operator- +80514220 KMP::Holder::InitLinks +805144a4 KMP::Holder::CalcCoordinates +805144b0 KMP::Manager::GetHolder +805144fc KMP::Manager::GetHolder +80514548 KMP::Manager::GetHolder +805145b0 KMP::Manager::CalcExtremes +805146bc KMP::Manager::GetHolder +80514708 KMP::Manager::GetHolder +80514770 KMP::CKPHSection::Init +80514994 KMP::CKPHSection::GetHolder +80514a18 KMP::Holder::Init +80514a60 KMP::Holder::CalcDepthRecursive +80514bc4 KMP::CKPTSection::Init +80514e64 KMP::Holder__ct +80514f60 KMP::LinkedCKPT::__ct +80514f64 KMP::LinkedCKPT::__dt +80514fa4 KMP::Holder::InitLinks +805153ec KMP::Holder::InitType +805155a4 KMP::Manager::GetHolder +805155f0 KMP::Manager::GetHolder +8051563c KMP::Manager::GetCKPHHolderByCT +805156bc KMP::Manager::POTISection::__ct +80515784 KMP::Manager::GetHolder +805157d0 KMP::AREASection::__ct +8051590c KMP::AREASection::SortByPriority +805159d0 KMP::Holder::__ct +80515a30 KMP::Holder::IsPointInAREA +80515ab8 KMP::Holder::GetRouteId +80515ae8 KMP::Holder::GetRoute +80515ba0 KMP::HolderAREABox::__ct +80515d34 KMP::Holder::__dt +80515d74 KMP::HolderAREABox::IsPointInAREAShape +80515e7c KMP::HolderAREACylinder::__ct +80516008 KMP::HolderAREACylinder::IsPointInAREAShape +805160e8 KMP::Manager::GetHolder +80516134 KMP::Manager::GetAREAHolderByPriority +80516188 KMP::Manager::FindAREA +805163e0 KMP::Manager::GetMiniMapAREAParams +80516530 KMP::Manager::GetHolder +8051657c KMP::Manager::GetCAMEHolderFromAREAId +80516654 KMP::Holder::GetNext +805166cc KMP::IsNonPrivateBattle +805166f4 KMP::Holder::InitLinks +80516f10 KMP::Manager::GetNextENPT +80516f8c KMP::Manager::GetNextENPTCount +80516ff0 KMP::Manager::GetPrevENPT +8051706c KMP::Manager::GetPrevENPTCount +805170d0 KMP::Manager::ToggleENPH +805171d8 KMP::Holder::ToggleENPHLink +80517664 KMP::Holder::AddPrevLink +805176b8 KMP::Holder::AddNextLink +8051770c KMP::Holder::AddLink +80517808 KMP::Holder::InitLinks +80517b70 KMP::Manager::GetNextITPT +80517be8 KMP::Manager::GetNextITPTCount +80517c4c KMP::Manager::GetPrevITPT +80517cc4 KMP::Manager::GetPrevITPTCount +80517d28 KMP::Holder::__ct +80517e7c KMP::Holder::InitLinks +805182a0 KMP::Manager::GetHolder +805182ec KMP::Holder::GetPosition +80518438 Vec3::MultiplyByScalar2 +80518460 KMP::Manager::GetHolder +805184ac KMP::Manager::GetHolder +805184f8 KMP::Manager::GetHolder +80518530 KMP::Holder::GetFilterEffectAlpha +8051855c KMP::AREASection::__dt +805185c0 KMP::Holder::__dt +80518640 ArchiveFile::__ct +80518674 ArchiveFile::__dt +8051874c ArchiveFile::Mount +8051878c 0x8051878c +80518790 ArchiveFile::Load +80518924 ArchiveFile::LoadUncompressed +8051893c ArchiveFile::MountFromRawArchive(void*) +805189c0 ArchiveFile::GetFileNewBuffer +80518a68 0x80518a68 +80518a70 ArchiveFile::Dump +80518b24 ArchiveFile::TryDump +80518bc0 ArchiveFile::ClearAll +80518c48 0x80518c48 +80518c4c ArchiveFile::Unmount +80518cf0 ArchiveFile::ClearArchive +80518d48 ArchiveFile::ClearDump +80518da0 ArchiveFile::GetFile +80518e88 ArchiveFile::Decompress +80518f24 ArchiveFile::SetDumpToDecompress +80518f58 ArchiveFile::MountFromRawArchive(ArchiveFile*) +80518ff0 Friend::__dt +80519030 Friend::SetFriend +80519070 Friend::StoreToDest +80519084 Friend::AddFriend +80519100 0x80519100 +805191ec 0x805191ec +80519300 Friend::SetData +80519350 Friend::AddLoss +80519368 Friend::AddWin +80519380 0x80519380 +805193cc 0x805193cc +8051949c 0x8051949c +805196b4 0x805196b4 +80519758 0x80519758 +80519938 0x80519938 +8051999c 0x8051999c +805199cc 0x805199cc +805199fc KCLController::CanReuseLastTrianglesList +80519a78 0x80519a78 +80519ae4 0x80519ae4 +80519af4 0x80519af4 +80519b24 0x80519b24 +80519b2c 0x80519b2c +80519b34 0x80519b34 +80519b60 GameScene::__ct +80519ce8 BaseScene::__dt +80519d40 GameScene::__dt +80519d9c GameScene::FadeIn +80519e00 GameScene::FadeOut +80519e5c GameScene::FinalizeEnter +8051a3cc GameScene::GetScreenCount +8051a3d4 GameScene::vf_0x58 +8051a3d8 GameScene::AddArchivesHolder +8051a468 GameScene::UnmountArchives +8051a4d8 GameScene::enter +8051a904 GameScene::SetFramerate +8051a968 GameScene::ChangeScene +8051aa0c 0x8051aa0c +8051aa14 GameScene::FadeOutToReinit +8051aa60 GameScene::CreateChildScene +8051aa74 GameScene::Reset +8051ab78 0x8051ab78 +8051abd0 GameScene::exit +8051acf4 BaseScene::ResetRacedataScenarios +8051ad00 0x8051ad00 +8051ad1c 0x8051ad1c +8051ad44 GameScene::vf_0x48 +8051ad48 GameScene::calc +8051b110 GameScene::isSpectating +8051b118 GameScene::vf_0x2c +8051b120 GameScene::vf_0x50 +8051b128 0x8051b128 +8051b130 GameScene::reinit +8051b250 GameScene::OnReinit +8051b254 GameScene::isPaused +8051b264 GameScene::CreateHeap +8051b308 GameScene::DestroyHeap +8051b350 GameScene::vf_0x5c +8051b354 0x8051b354 +8051b5f8 GameScene::draw +8051b6b4 0x8051b6b4 +8051b850 GameScene::GetCurrent +8051b880 0x8051b880 +8051b98c BaseScene::outgoing_child_create +8051b990 BaseScene::incoming_child_destroy +8051b994 0x8051b994 +8051b998 0x8051b998 +8051b99c BaseScene::reinit +8051b9a0 BaseScene::exit +8051b9a4 BaseScene::enter +8051b9a8 BaseScene::draw +8051b9ac BaseScene::calc +8051b9b0 0x8051b9b0 +8051ba08 RKG::ClearBuffer +8051ba14 RKG::CheckHeader +8051baa0 RKGFile::CheckValidity +8051bbbc RKGFile::SetCRC32 +8051bbf0 GhostData::__ct +8051bcb4 Timer::__dt +8051bcf4 Timer::__ct +8051bd18 GhostData::__ct(RKG) +8051be20 GhostData::Reset +8051beac 0x8051beac +8051beb0 GhostData::ReadRKG +8051c110 GhostData::Init +8051c174 GhostData::FillHeader +8051c38c GhostData::CreateRKGWithoutInputs +8051c400 GhostData::CreateRKG +8051c49c GhostData::Fill +8051c7fc Input::Controller::GetType +8051c804 0x8051c804 +8051c80c Input::ControllerHolder::GetInputsSize +8051c814 GhostGroup::__ct +8051c910 GhostData::__dt +8051c978 GhostGroup::__dt +8051c9e4 GhostGroup::DisableGhostData +8051ca04 GhostGroup::GetGhostData +8051ca3c GhostGroup::ReadRKG +8051ca60 RKG::CompressTo +8051cb34 RKG::DecompressTo +8051cd08 RKG::GetLength +8051ce54 HomeMenuMgr::CreateInstance +8051ceb4 HomeMenuMgr::DestroyInstance +8051cf04 HomeMenuMgr::__dt +8051cf68 HomeMenuMgr::LoadHBMArc +8051d01c 0x8051d01c +8051d020 HomeMenuMgr::__ct +8051d214 HomeMenuMgr::ResetControllerData +8051d298 HomeMenuMgr::Open +8051d374 HomeMenuMgr::Close +8051d444 0x8051d444 +8051d6f0 HomeMenuMgr::UpdateControllerData +8051d8f8 HomeMenuMgr::UpdateLockParams +8051d940 0x8051d940 +8051da94 HomeMenuMgr::Calc +8051dce0 0x8051dce0 +8051dda0 0x8051dda0 +8051def4 0x8051def4 +8051e168 HomeMenuMgr::Draw +8051e1dc Input::State::Reset +8051e21c Input::State::operator== +8051e284 Input::UIState::Reset +8051e2e0 Input::State::SetStickXMirrorCheck +8051e368 Input::State::SetStickX +8051e3a8 Input::State::ConvertQuantised +8051e3e0 Input::State::SetStickY +8051e420 Input::UIState::SetStickXMirrorCheck +8051e4a8 Input::UIState::SetStickY +8051e4e8 Input::State::SetControlMotionFlick +8051e528 Input::Controller::__ct +8051e614 Input::State::__dt +8051e654 Input::UIState::__dt +8051e694 Input::Controller::Update +8051e98c Input::Controller::ResetSelf +8051e990 Input::Controller::UpdateBatteryField +8051e9f4 Input::Controller::GetRemainingBattery +8051e9fc Input::Controller::GetRuntimeTypeInfo +8051ea08 Input::WiiController::__ct +8051eb6c Input::Controller::__dt +8051ebac Input::WiiController::Init +8051ec88 Input::Controller::Init +8051ecfc Input::Controller::SetDriftType +8051ed04 Input::WiiController::WPADInfoCallback +8051ed34 Input::WiiController::UpdateBattery +8051ed50 Input::WiiController::GetRemainingBattery +8051ed90 Input::WiiController::UpdateStatesClassic +8051f3fc Input::WiiController::UpdateStatesNunchuck +8051f560 Input::WiiController::UpdateStatesCore +8051f604 Input::WiiController::UpdateImpl +8051f938 Input::WiiController::TogglePointer +8051f950 Input::GCNController::__ct +8051fa98 Input::GCNController::Init +8051fb30 Input::GCNController::UpdateImpl +8052007c Input::GCNController::HasRumble +805200b0 Input::GhostController::__ct +805202a4 Input::GhostController::__dt +80520318 Input::GhostController::Init +805203cc Input::GhostController::HasRKGInputs +805203e0 0x805203e0 +80520498 0x80520498 +8052051c Input::GhostController::UpdateImpl +805206cc Input::GhostDirectionStream::Read +80520834 Input::GhostDirectionStream::GetInputSize +8052083c Input::ControllerHolder::CreateRumbleController +805208ac Input::RealControllerHolder::SetDriftType +805208e4 Input::ControllerHolder::__ct +80520a90 Input::ControllerHolder::Init +80520b18 Input::ControllerHolder::Update +80520ed4 Input::RealControllerHolder::SetController +80520f54 Input::RealControllerHolder::StartGhostReading +80521008 Input::RealControllerHolder::EndGhostWriting +805210e8 Input::RealControllerHolder::Update +805211c4 Input::RealControllerHolder::SetGhostController +805212b0 Input::RealControllerHolder::PrepareForRace +8052132c Input::AIControllerHolder::CopyCPUInputs +805213b4 Input::ControllerHolder::RequestRumble(3args) +8052144c Input::ControllerHolder::RequestRumble(4args) +80521704 Input::Controller::HasRumble +8052170c 0x8052170c +805217c8 0x805217c8 +80521850 Input::ControllerHolder::RequestRumbleByDuration +8052190c Input::ControllerHolder::RequestRumbleByDurationNoFaderCheck +80521994 Input::ControllerHolder::StopAllRumble +805219f8 Input::ControllerHolder::ActivateRumble +80521a0c Input::Controller::ActivateRumble +80521a10 Input::ControllerHolder::StopRumble +80521a24 Input::ControllerHolder::StopCurrentRumble +80521a28 Input::ControllerHolder::ResetSelfController +80521a3c Input::RealControllerHolder::__ct +80521c34 Input::ControllerHolder::__dt +80521c74 Input::RealControllerHolder::__dt +80521cd8 Input::Manager::SetFSStickClamp +80521ce4 Input::ControllerParams::Fill +80521e14 Input::Controller::GetChannel +80521e1c 0x80521e1c +80521e8c 0x80521e8c +80521f24 0x80521f24 +80522008 0x80522008 +80522010 Input::Manager::ResetKPAD +80522074 Input::ControllerHolder::CopyCPUInputs +80522078 Input::RealControllerHolder::GetInputsSize +80522080 Input::RealControllerHolder::GetRKGInputs +80522088 Input::RealControllerHolder::Init +8052211c Input::AIControllerHolder::__dt +8052215c Input::AIController::__dt +8052219c Input::Controller::IsPointerEnabled +805221a4 Input::Controller::TogglePointer +805221a8 Input::GhostController::SetDriftType +805221ac Input::GhostController::GetType +805221b4 Input::Controller::Func_0x24 +805221c0 Input::GCNController:ResetSelf +805221cc Input::GCNController:StopRumble +805221d8 Input::GCNController:ActivateRumble +805221e4 Input::GCNController:GetChannel +805221ec Input::GCNController:GetType +805221f4 Input::GCNController:__dt +80522234 Input::WiiController::ResetSelf +80522244 Input::WiiController::StopRumble +80522250 Input::WiiController::ActivateRumble +8052225c Input::WiiController::HasRumble +80522274 Input::WiiController::IsPointerEnabled +805222a4 Input::WiiController::GetChannel +805222ac Input::WiiController::GetType +805222b4 Input::WiiController::__dt +805222f4 Input::GhostDirectionStream::Write +80522468 Input::GhostTrickStream::Write +805225dc Input::GhostTrickStream::Read +80522744 Input::GhostTrickStream::GetInputSize +8052274c Input::GhostActionStream::Write +805228c0 Input::GhostActionStream::Read +80522a28 Input::GhostActionStream::GetInputSize +80522a30 Input_cpp_sinit_ +80522a60 Input::Manager::SyncSimpleCallback +80522abc Input::Manager::CreateInstance +80522b0c Input::Manager::DestroyInstance +80522b5c Input::Manager::__dt +80522c30 Input::DummyController::__dt +80522c70 Input::Manager::__ct +80522e20 Input::AIControllerHolder::__ct +80522ea0 Input::Manager::Init +80522ea4 0x80522ea4 +80522f2c Input::Manager::ResetIdleFrameCounter +80522f54 0x80522f54 +80523010 Input::Manager::Prepare +805230a4 Input::Manager::ResetSelfWiiAndGCNControllers +8052312c 0x8052312c +80523168 Input::Manager::UpdateControllers +80523270 Input::Manager::Update +80523310 0x80523310 +805233d8 Input::Manager::ConvertType +80523400 0x80523400 +80523548 0x80523548 +80523690 0x80523690 +8052382c Input::Manager::ResetDummyController +8052383c Input::Manager::TrySetController +80523a6c 0x80523a6c +80523be4 Input::Manager::ResetRealController +80523bfc 0x80523bfc +80523c58 Input::Manager::InitControllerHolders +80523db8 0x80523db8 +80523e80 0x80523e80 +80523ebc Input::Manager::InitGhostController +80523ed8 Input::Manager::PrepareRealControllerHolderForRace +80523ee8 Input::Manager::EnableGhostReading +80523f00 Input::Manager::StartGhostReading +80523f4c Input::Manager::EndGhostWriting +80523f5c Input::Manager::EndAllGhostWriting +80523fa8 Input::Manager::CopyPADStatus +80524040 Input::Manager::InitRumble +80524098 Input::Manager::ResetRumble +805240b4 0x805240b4 +80524108 Input::Manager::SyncWiimotes +80524164 0x80524164 +805241c0 Input::Manager::EnableAllPointers +80524258 Input::Manager::ToggleAllPointers +805242c4 0x805242c4 +80524318 0x80524318 +80524330 Input::Manager::RequestRumbleByDuration +80524348 0x80524348 +805243d0 0x805243d0 +805243d8 Input::AIController::UpdateImpl +80524428 Input::AIController::GetType +80524430 Input::DummyController::UpdateImpl +80524434 SITransferCommands +80524444 Input::GhostWriter::__ct +805245ac Input::GhostWriter::__dt +80524628 Input::GhostWriter::Init +805246a0 Input::GhostWriter::CopyToRKGInputsBuffer +80524750 Input::GhostWriter::IsInputsSumSmallEnough +805247f4 Input::GhostWriter::WriteFrame +805248f8 Input::GhostActionStream::WriteNewValue +80524908 Input::GhostActionStream::IncrementDuration +80524918 Input::GhostActionStream::IsNewInput +8052493c Input::GhostActionStream::ReadValue +80524944 Input::GhostActionStream::IsCurReadInputFinished +80524960 Input::GhostDirectionStream::WriteNewValue +80524970 Input::GhostDirectionStream::IncrementDuration +80524980 Input::GhostDirectionStream::IsNewInput +805249a4 Input::GhostDirectionStream::ReadValue +805249ac Input::GhostDirectionStream::IsCurReadInputFinished +805249c8 Input::GhostTrickStream::WriteNewValue +805249dc Input::GhostTrickStream::IncrementDuration +805249f4 Input::GhostTrickStream::IsNewInput +80524a1c Input::GhostTrickStream::ReadValue +80524a28 Input::GhostTrickStream::IsCurReadInputFinished +80524a48 Input::KRMMgr::Init +80524b84 Input::KRMMgr::__ct +80524bf8 Input::Rumble::Init +80524c24 Input::Rumble::Request(KRMEntry) +80524c68 Input::Rumble::Request(float) +80524ca4 0x80524ca4 +80524cb4 Input::Rumble::Update +80524e18 Input::RumbleController::__ct +80524e88 Input::RumbleController::Init +80524f3c Input::RumbleController::Stop +80524fcc Input::RumbleController::DeactivateRumble +8052508c Input::RumbleController::Update +805252f4 Input::RumbleController::Request(KRMEntry) +805253f4 Input::RumbleController::Request(float) +8052550c Input::RumbleController::GetFreeRumble +805255b8 Input::RumbleController::__dt +805255f8 Input::Rumble::__dt +80525638 0x80525638 +80525708 0x80525708 +80525738 0x80525738 +80525780 0x80525780 +805257e0 0x805257e0 +80525908 Mii::Init +80525974 0x80525974 +805259a0 Mii::Load +80525d3c 0x80525d3c +80525d80 0x80525d80 +80525de0 Mii::GetRFLArgs +80525fbc Mii::CreateScnRfl +80526134 0x80526134 +80526274 0x80526274 +8052637c 0x8052637c +80526390 0x80526390 +80526400 0x80526400 +805264e4 MiiManager::Disposer__dt +8052657c MiiManager::CreateInstance +805265cc 0x805265cc +80526600 MiiManager::__ct +805266bc MiiManagerSub::__ct +805266d4 MiiManagerSub::__dt +80526714 MiiManager::Init +80526ad8 MiiManager::__dt +80526c18 MiiManager::CountOfficialMiis +80526e18 0x80526e18 +80526e94 MiiManager::GetMiddleDB3 +80526e9c 0x80526e9c +80526f0c Mii::ComputeRFLStoreData +80526f6c Mii::IsMiiId +80526f84 Mii::GetMiiId +80527060 MiiManager::GetStatus +80527080 MiiManager::IsOfficialOrDefaultMii +805270f8 MiiManager::CreatePlayerMiiFromOfficial +8052748c MiiManager::CreateStoreMii(RFLCreateID) +805276e0 MiiManager::CreateOfficialMii(RFLIdx) +80527804 MiiManager::CreateOfficialMii(RFLCreateID) +80527904 MiiManager::CreateDefaultMii(RFLIdx) +805279e8 MiiManager::CreateDefaultMii(RFLCreateID) +80527aec MiiManager::CreateOfficialMii(IdxArray) +80527c10 MiiManager::AllowMiiDisplay +80527c30 MiiManager::CreateMiddleDBMii +80527f18 MiiManager::CreateRandomMii +8052813c MiiManager::CreateMii(CreationParams) +80528828 0x80528828 +805289b4 Mii::__dt +805289f4 MiiManager::CreateMiddleDB2Mii +80528cb0 MiiManager::CreateMii(RFLStoreData) +80528da0 MiiManager::CreateControllerMii +80528eb0 0x80528eb0 +80528f10 0x80528f10 +80528fc0 MiiManager::CreatePlayerMiiFromMiddleDB +805290b0 MiiManager::PrepareRFLWiFiPacket +805290c8 MiiManager::RFLWiFiInfo2MiddleDB +80529118 MiiManager::RFLWiFiInfo2StoreData +80529164 MiiCreationParams::InitAndReset +80529184 MiiCreationParams::Init +805291a4 MiiCreationParams::Reset +805291dc 0x805291dc +805291f0 0x805291f0 +80529218 0x80529218 +8052927c 0x8052927c +8052929c 0x8052929c +805292bc MiiCreationParams2::Init +805292f8 MiiCreationParams2::Reset +80529324 0x80529324 +80529338 0x80529338 +80529360 0x80529360 +805293c4 0x805293c4 +805293e4 0x805293e4 +80529404 0x80529404 +80529444 MovieManager::__ct +805294e8 MovieManager::__dt +80529564 MovieManager::IsMoviePlaying +8052958c MovieManager::DrawDone +805295c0 MovieManager::Init +805295c8 MovieManager::Quit +805295cc MovieManager::CheckForEnd +80529620 MovieManager::GetCurrentFrameNum +80529650 MovieManager::Prepare +805296e8 MovieManager::PrepareAsync +80529780 MovieManager::RequestPrepare +805297dc MovieManager::Play +80529824 MovieManager::PlayAsync +8052986c MovieManager::RequestPlay +80529884 MovieManager::Pause +805298c4 MovieManager::PauseAsync +80529904 MovieManager::RequestPause +8052991c MovieManager::Close +80529960 MovieManager::CloseAsync +805299a4 MovieManager::RequestClose +805299bc MovieManager::SetVolume +805299c8 MovieManager::GetVolume +805299cc MovieManager::FillCurTextureInfo +80529a18 ArchivesHolder::CreateByType +80529b48 CourseArchivesHolder::__ct +80529b9c CourseArchivesHolder::Reset +80529c28 UIArchivesHolder::__ct +80529c7c UIArchivesHolder::Reset +80529cec CommonArchivesHolder::__ct +80529d40 CommonArchivesHolder::Reset +80529db0 CourseArchivesHolder::__dt +80529e08 UIArchivesHolder::__dt +80529e60 CommonArchivesHolder::__dt +80529eb8 ArchivesHolder::ArchiveHolder +80529fc8 ArchivesHolder::Reset +8052a05c ArchivesHolder::__dt +8052a0e0 ArchivesHolder::GetFile +8052a180 ArchivesHolder::HasArchives +8052a1e4 ArchivesHolder::FileExists +8052a2d4 ArchivesHolder::LoadArchives +8052a408 ArchivesHolder::UnmountArchives +8052a468 ArchivesHolder::LoadFromOther +8052a4ec ArchivesHolder::DumpArchive +8052a5c0 ArchivesHolder::ClearArchives +8052a620 ArchivesHolder::GetTotalMountedArchivesSize +8052a688 ArchivesHolder::GetFirstMountedArchive +8052a700 ArchivesHolder::GetFirstMountedArchiveEnd +8052a788 ArchivesHolder::GetLoadedArchivesCount +8052a7dc NandUtils::SafeOpen +8052a858 NandUtils::SafeOpen_NandUtils::SafeOpen_switch +8052a85c NandUtils::SafeOpen_caseD_0 +8052a864 NandUtils::SafeOpen_caseD_-3 +8052a87c NandUtils::SafeOpen_caseD_-4 +8052a884 NandUtils::SafeOpen_caseD_-15 +8052a88c NandUtils::SafeOpen_caseD_-12 +8052a894 NandUtils::SafeOpen_caseD_-14 +8052a8e4 NandUtils::Open +8052a9d8 NandUtils::SafeClose +8052aac4 NandUtils::Close +8052aba8 NandUtils::Read +8052ad78 NandUtils::GetLength +8052ae54 NandUtils::Write +8052b004 NandUtils::Check +8052b0d4 NandUtils::CreateDir +8052b1cc NandUtils::GetType +8052b2dc NandUtils::Create +8052b3d4 NandUtils::Delete +8052b4c0 NandUtils::SetStatus +8052b5bc NandUtils::GetStatus +8052b6b8 NandUtils::FileExists +8052b6dc NandMgr::Disposer_dt +8052b774 NandMgr::CreateInstance +8052b818 NandMgr::DestroyInstance +8052b84c NandMgr::__ct +8052b8c4 NandMgr::__dt +8052b978 NandMgr::Init +8052ba30 NandMgr::ReadRKSYS +8052bae8 NandMgr::ReadFile +8052bb8c NandMgr::CheckRKSYSLength +8052bc50 NandMgr::WriteToRKSYS +8052bda8 NandMgr::WriteFile +8052be6c 0x8052be6c +8052bf50 0x8052bf50 +8052c00c NandMgr::CreateRKSYS +8052c164 NandMgr::DeleteRKSYS +8052c490 NandMgr::GetBannerType +8052c4ec 0x8052c4ec +8052c624 0x8052c624 +8052c748 0x8052c748 +8052c7d8 0x8052c7d8 +8052c878 0x8052c878 +8052c98c 0x8052c98c +8052c9e8 0x8052c9e8 +8052ca98 0x8052ca98 +8052cb40 0x8052cb40 +8052cbf0 RKSYS::Rating::AddPoints +8052cc18 ElineController::__ct +8052cc90 0x8052cc90 +8052cd04 0x8052cd04 +8052cd50 0x8052cd50 +8052cdec ElineMgr::__ct +8052d1a8 ElineMgr::GetController +8052d208 ElineMgr::Update +8052d2ec RacedataPlayer::__ct +8052d390 RKSYS::Rating::__dt +8052d3d0 RacedataPlayer::RegisterPlayerParams +8052d470 RacedataPlayer::ComputeGPRank +8052d548 RacedataScenario::__ct +8052d5e8 RacedataPlayer::__dt +8052d628 RacedataScenario::BlueTeamHasMorePoints +8052d698 RacedataPlayer::GetTeam +8052d6a0 RacedataScenario::GetPlayer(const) +8052d6b0 RacedataPlayer::GetPlayerCount +8052d6c0 Racedata::Init +8052ddac RacedataPlayer::SetCharacterId +8052ddb4 RacedataScenario::GetPlayer +8052ddc4 RacedataPlayer::SetKartId +8052ddcc RacedataPlayer::SetPlayerType +8052ddd4 Racedata::ResetScenarios +8052dfc0 RacedataPlayer::ResetScores +8052dfd8 RacedataPlayer::SetPrevFinishPos +8052dfe0 0x8052dfe0 +8052dfe8 0x8052dfe8 +8052e0e4 0x8052e0e4 +8052e0e8 0x8052e0e8 +8052e0ec 0x8052e0ec +8052e0f0 0x8052e0f0 +8052e1f0 0x8052e1f0 +8052e2d0 RacedataScenario::UpdatePoints +8052e698 RacedataScenario::GetGameType +8052e6a0 RacedataPlayer::GetPlayerType +8052e6a8 RacedataScenario::InitControllers +8052e870 RacedataScenario::InitGhostPlayer +8052e954 0x8052e954 +8052e9e4 0x8052e9e4 +8052eb60 RacedataScenario::UpdateFromPrevRace +8052ee68 RacedataScenario::InitScreens +8052f108 RacedataScenario::ComputePlayerCounts +8052f2a4 RacedataScenario::InitRng +8052f38c RacedataScenario::InitCompetitionSettings +8052f510 RacedataScenario::Init +8052f7d8 Racedata::CreateInstance +8052f968 Racedata::DestroyInstance +8052f9b8 Racedata::__dt +8052fa74 RacedataScenario::__dt +8052fadc Racedata::__ct +8052fc44 Racedata::InitRace +8052ff2c RacedataScenario::operator= +805301e4 Racedata::InitAwards +8053088c RacedataScenario::AreTeamsEnabled +80530898 0x80530898 +805308a0 RacedataPlayer::GetCharacterId +805308a8 RacedataPlayer::GetKartId +805308b0 RacedataPlayer::SetMii +805309e8 RacedataPlayer::GetMii +805309f0 Racedata::InitCredits +80531664 Racedata::UpdatePrevFromCur +80531764 RacedataScenario::RegisterParameters +80531898 Racedata::GetHudSlotId +805318ac Racedata::SetGhost +805318f0 Racedata::GetPlayerIdOfLocalPlayer +80531900 Racedata::HandleRaceFinish? +80531948 Racedata::LoadNextGPTrack +805319b0 Racedata::IsTTReplay +805319f0 Racedata::vf_0x18 +805319f4 Racedata::vf_0x14 +805319f8 Racedata::vf_0x10 +805319fc 0x805319fc +80531a04 Raceinfo::CreateInstance +80531a54 Raceinfo::DestroyInstance +80531aa4 GMDataGP::__ct +80531b08 Raceinfo::CreateGMData +80531b48 Raceinfo::CreateGMData_Raceinfo::CreateGMData_switch +80531b4c Raceinfo::CreateGMData_case_0 +80531ba0 Raceinfo::CreateGMData_case_1 +80531bc8 Raceinfo::CreateGMData_case_4 +80531bd4 Raceinfo::CreateGMData_case_3 +80531c48 Raceinfo::CreateGMData_case_7 +80531d60 Raceinfo::CreateGMData_case_9 +80531dc4 Raceinfo::CreateGMData_case_2 +80531e08 GMDataOnlineVSPlayer::__ct +80531e2c GMDataOnlineVSPlayer::__dt +80531e6c 0x80531e6c +80531eac 0x80531eac +80531eec 0x80531eec +80531f2c 0x80531f2c +80531f6c 0x80531f6c +80531fac 0x80531fac +80531fec 0x80531fec +8053202c 0x8053202c +8053206c Raceinfo::GetBattleDuration +80532120 Raceinfo::__ct +805326c4 RaceTimerMgrBase::Reset +80532760 RaceTimerMgrBase::__dt +805327bc Raceinfo::__dt +805328c8 RaceinfoPlayer::__dt +80532908 Raceinfo::Init +80532a0c GMData::Init +80532a10 Raceinfo::GetRemainingCountdownTime +80532a40 Raceinfo::ComputeDelfinoPierTideState +80532b34 Raceinfo::Update +80533020 RaceTimerMgrBase::Update +80533024 Raceinfo::GetLapCount +80533058 GMData::HandlePositionTracking +8053347c 0x8053347c +80533568 GMData::vf_0x20 +8053356c 0x8053356c +805335b4 GMData::vf_0x24 +805335ec Raceinfo::EndPlayerRace +80533704 Raceinfo::SetPlayerDisconnected +80533754 0x80533754 +80533858 RaceinfoPlayer::__ct +80533b14 0x80533b14 +80533c68 RaceinfoPlayer::UpdateRealLocal +80534004 0x80534004 +80534174 RaceinfoPlayer::EndRace +805342b4 0x805342b4 +80534338 RaceinfoPlayer::EndLap +805345f8 RaceinfoPlayer::Vanish +8053463c RaceinfoPlayer::Disconnect +8053464c 0x8053464c +805346ec 0x805346ec +80534778 RaceinfoPlayer::UpdateCheckPoint +80534b8c 0x80534b8c +80534c84 RaceinfoPlayer::Update +80535018 0x80535018 +8053501c 0x8053501c +80535098 RaceinfoPlayer::CopyCPUInputs +805350ac RaceinfoPlayer::FillTimerWithLapSplits +805351e4 RaceTimerMgr::Reset +80535284 RaceTimerMgr::Update +80535620 Raceinfo::CloneTimer +80535694 GMDataTT::CanRaceEnd +80535768 GMData::UpdateLocalPlayer +80535804 GMData::Update +80535874 GMData::GetJGPTHolder +805358a8 GMDataGP::CanRaceEnd +80535964 GMDataGP::Update +805359d4 GMDataVS::CanRaceEnd +80535b88 Raceinfo::CanRaceEnd +80535b9c Raceinfo::GetJGPTHolder +80535bb0 Raceinfo::IsAtLeastStage +80535bc8 0x80535bc8 +80535c5c Raceinfo::GetInitialPhysicsValues +80535ca4 Raceinfo::GetInitialPhysicsValues::switch +80535ca8 Raceinfo::GetInitialPhysicsValues::case_3 +80535dd0 Raceinfo::GetInitialPhysicsValues::case_b +80535e04 Raceinfo::GetInitialPhysicsValues::case_c +80535e14 Raceinfo::GetInitialPhysicsValues::case_2 +80535e24 Raceinfo::GetInitialPhysicsValues::case_4 +80535ec0 Raceinfo::GetInitialPhysicsValues::case_0 +80535f48 Raceinfo::GetKTPTHolder +80535f94 Raceinfo::GetKTPTHolder_switch +80535f98 Raceinfo::GetKTPTHolder_case_3 +805360b8 Raceinfo::GetKTPTHolder_case_4 +80536138 Raceinfo::GetKTPTHolder_case_b +80536164 Raceinfo::GetKTPTHolder_case_c +8053616c Raceinfo::GetKTPTHolder_case_2 +80536174 Raceinfo::GetKTPTHolder_case_0 +805361a8 Raceinfo::GetStartENPT +80536244 Raceinfo::GetRawKRT +80536278 RaceinfoPlayer::ComputeGPRank +80536604 0x80536604 +80536b10 0x80536b10 +80536b24 GMData::vf_0x28 +80536b28 0x80536b28 +80536b68 0x80536b68 +80536bcc 0x80536bcc +80536c34 0x80536c34 +80536c3c 0x80536c3c +80536ca0 0x80536ca0 +80536d08 0x80536d08 +80536d10 0x80536d10 +80536d74 0x80536d74 +80536ddc 0x80536ddc +80536de4 0x80536de4 +80536e48 0x80536e48 +80536eb0 0x80536eb0 +80536eb8 0x80536eb8 +80536f1c 0x80536f1c +80536f84 0x80536f84 +80536f8c 0x80536f8c +80536ff0 0x80536ff0 +80537058 0x80537058 +80537060 RaceTimerMgr::__dt +805370c0 0x805370c0 +805371b0 Vec3::Cross +805371fc 0x805371fc +80537500 Mtx34::GetColumnByIdx +80537524 0x80537524 +805375d4 0x805375d4 +80537614 0x80537614 +80537654 0x80537654 +80537918 0x80537918 +80537a04 0x80537a04 +80537af0 0x80537af0 +80537b24 0x80537b24 +80537ba0 0x80537ba0 +80537c9c KMGHolder::SetKMG +80537cc4 KMGHolder::ConvertArenaIdToIdx +80537d98 GMDataBattle::HandlePositionTracking +805380f0 GMDataBalloonBattle::OnItemCollision +80538314 GMDataBalloonBattle::OnKartCollision +80538540 GMDataBalloonBattle::OnOOBCollision +80538660 0x80538660 +80538780 0x80538780 +80538834 0x80538834 +805388d0 GMDataOnlineBalloonBattle::GetKMGSeconds2 +805388d8 GMDataOnlineBalloonBattle::GetKMGSeconds3 +805388e0 0x805388e0 +8053896c GMDataBattle::Init +80538b5c GMDataOnlineBalloonBattle::GetKMGSeconds1 +80538b64 GMDataBattle::GetJGPTHolder +80538c64 0x80538c64 +80538d84 0x80538d84 +80538ef4 GMDataBalloonBattle::Update +805390f0 GMDataBalloonBattle::CanRaceEnd +805391a4 GMDataCoinBattle::Update +80539404 GMDataCoinBattle::CanRaceEnd +80539410 GMDataCoinBattle::OnItemCollision +805394b0 GMDataCoinBattle::OnKartCollision +80539568 GMDataCoinBattle::OnOOBCollision +805395bc GMDataOnlineBalloonBattle::Init +80539908 GMDataOnlineBalloonBattle::__ct +80539b00 0x80539b00 +80539b40 0x80539b40 +80539b80 0x80539b80 +80539bc0 0x80539bc0 +80539c00 0x80539c00 +80539c40 0x80539c40 +80539c80 0x80539c80 +80539cc0 0x80539cc0 +80539d00 0x80539d00 +80539d40 0x80539d40 +8053a0a0 0x8053a0a0 +8053a104 0x8053a104 +8053a10c 0x8053a10c +8053a170 0x8053a170 +8053a178 0x8053a178 +8053a1e8 0x8053a1e8 +8053a1f0 0x8053a1f0 +8053a254 0x8053a254 +8053a25c 0x8053a25c +8053a2c0 0x8053a2c0 +8053a2c8 0x8053a2c8 +8053a32c 0x8053a32c +8053a334 0x8053a334 +8053a398 0x8053a398 +8053a3a0 0x8053a3a0 +8053a55c 0x8053a55c +8053a57c 0x8053a57c +8053a59c 0x8053a59c +8053aa28 0x8053aa28 +8053aa90 0x8053aa90 +8053aaf8 0x8053aaf8 +8053ab78 0x8053ab78 +8053abe0 0x8053abe0 +8053ac48 0x8053ac48 +8053acb0 0x8053acb0 +8053ad18 0x8053ad18 +8053ad4c 0x8053ad4c +8053ae4c GMDataOnlineBalloonBattle::OnItemCollision +8053af04 GMDataOnlineBalloonBattle::OnKartCollision +8053afbc GMDataOnlineBalloonBattle::OnOOBCollision +8053b068 GMDataOnlineBalloonBattle::vf_0x3c +8053b078 0x8053b078 +8053b124 GMDataOnlineBalloonBattle::OnObjectCollision +8053b1d0 0x8053b1d0 +8053b204 0x8053b204 +8053b290 0x8053b290 +8053b30c 0x8053b30c +8053b420 0x8053b420 +8053b574 GMDataOnlineBalloonBattle::Update +8053b6dc GMDataOnlineBalloonBattle::Update_switch +8053b6e0 GMDataOnlineBalloonBattle::Update_case_1 +8053b6f4 GMDataOnlineBalloonBattle::Update_case_2 +8053b704 GMDataOnlineBalloonBattle::Update_case_3 +8053b718 GMDataOnlineBalloonBattle::Update_case_4 +8053b79c GMDataOnlineBalloonBattle::Update_case_5 +8053b7ac GMDataOnlineBalloonBattle::Update_case_6 +8053b7f0 GMDataOnlineBalloonBattle::Update_case_7 +8053b7f8 GMDataOnlineBalloonBattle::Update_case_0 +8053b7fc GMDataOnlineBalloonBattle::Update_case_8 +8053c4ac 0x8053c4ac +8053c548 0x8053c548 +8053c790 0x8053c790 +8053c9e0 0x8053c9e0 +8053cb20 0x8053cb20 +8053cbe0 0x8053cbe0 +8053cd20 GMDataOnlineBalloonBattle::vf_0x28 +8053cda8 GMDataOnlineCoinBattle::Update +8053d1c8 0x8053d1c8 +8053d238 GMDataBattle::vf_0x3c +8053d23c GMDataCoinBattle::OnObjectCollision +8053d240 GMDataCoinBattle::GetKMGSeconds3 +8053d25c GMDataCoinBattle::GetKMGSeconds2 +8053d278 GMDataCoinBattle::GetKMGSeconds1 +8053d294 GMDataOnlineBalloonBattle::CanRaceEnd +8053d29c GMDataBalloonBattle::GetKMGSeconds3 +8053d2b8 GMDataBalloonBattle::GetKMGSeconds2 +8053d2d4 GMDataBalloonBattle::GetKMGSeconds1 +8053d2f0 0x8053d2f0 +8053d2f4 0x8053d2f4 +8053d2f8 0x8053d2f8 +8053d2fc Raceinfo::RaceinfoGamemodeDataMissionTournament +8053d338 Raceinfo::RaceinfoGamemodeDataMissionTournament_switch +8053d33c Raceinfo::RaceinfoGamemodeDataMissionTournament_caseD_0 +8053d368 Raceinfo::RaceinfoGamemodeDataMissionTournament_caseD_1 +8053d394 Raceinfo::RaceinfoGamemodeDataMissionTournament_caseD_7 +8053d3d0 0x8053d3d0 +8053d428 0x8053d428 +8053d42c 0x8053d42c +8053d478 0x8053d478 +8053d47c 0x8053d47c +8053d490 0x8053d490 +8053d498 0x8053d498 +8053d4b4 0x8053d4b4 +8053d978 0x8053d978 +8053d998 0x8053d998 +8053db14 0x8053db14 +8053dbfc 0x8053dbfc +8053dc18 0x8053dc18 +8053dc20 0x8053dc20 +8053dc30 0x8053dc30 +8053dc70 0x8053dc70 +8053dcb0 0x8053dcb0 +8053dcf0 GMDataOnlineVS::Init +8053ddfc 0x8053ddfc +8053e000 0x8053e000 +8053e12c 0x8053e12c +8053e53c 0x8053e53c +8053e5c0 0x8053e5c0 +8053e6e8 0x8053e6e8 +8053e7d0 0x8053e7d0 +8053e954 0x8053e954 +8053eb04 0x8053eb04 +8053ec24 GMDataOnlineVS::Update +8053ee20 GMDataOnlineVS::HandlePositionTracking +8053f390 GMDataOnlineVS::CanRaceEnd +8053f4b8 GMDataOnlineVS::vf_0x24 +8053f518 GMDataOnlineVS::UpdateLocalPlayers +8053f5cc ArchiveMgr::CreateInstance +8053f61c ArchiveMgr::DestroyInstance +8053f66c ArchiveMgr::__ct +8053f7e8 AllkartArchivesLoader::__ct +8053f814 AllkartArchivesLoader::__dt +8053f854 0x8053f854 +8053f894 0x8053f894 +8053f89c ArchiveMgr::__dt +8053f9b8 ArchiveMgr::LoadArchiveAsync +8053fa20 ArchiveMgr::WaitForLoad +8053fb6c 0x8053fb6c +8053fb7c 0x8053fb7c +8053fb8c ArchiveMgr::LoadArchive(holder) +8053fc40 ArchiveMgr::LoadArchive(file) +8053fd14 ArchiveMgr::LoadArchive(holder, 2heaps) +8053fdd0 ArchiveMgr::LoadArchive(type) +8053fed8 ArchiveMgr::LoadContentArchive +80540000 ArchiveMgr::LoadUIArchive +805400e0 ArchiveMgr::LoadCourseArchive +80540298 ArchiveRoot_loadMissionTrack +80540494 ArchiveMgr::LoadCompetitionArchives +8054067c ArchiveMgr::LoadKartArchive(holder) +805407bc ArchiveMgr::LoadKartArchive(playerId) +80540910 ArchiveMgr::LoadKartArchiveHolder2(playerId) +80540a64 0x80540a64 +80540b54 ArchiveMgr::Unmount(source) +80540b64 ArchiveMgr::Unmount(holder) +80540b6c ArchiveMgr::UnmountContentArchive +80540b7c ArchiveMgr::GetFile +80540bf8 ArchiveMgr::GetMenuKartBRRES +80540ca0 ArchiveMgr::GetKartBRRES +80540d48 ArchiveMgr::GetKartArchiveFile +80540db8 ArchiveMgr::GetKartArchiveFileHolder2 +80540e28 ArchiveMgr::GetBSP +80540edc ArchiveMgr::GetContentFileNewBuffer +80540f34 ArchiveMgr::HasArchives +80540f44 ArchiveMgr::HasKartArchive +80540f54 ArchiveMgr::HasKartArchiveHolder2 +80540f64 ArchiveMgr::HasContentArchive +80540f94 ArchiveMgr::GetArchive +8054101c ArchiveMgr::SetLayoutResources +805410b8 ArchiveMgr::GetArchiveCount +80541114 ArchiveMgr::GetUIArchiveCount +80541124 ArchiveMgr::AttachUIAccessor +805411f8 ArchiveMgr::AttachLayoutResources +80541318 ArchiveMgr::LoadCourseArchiveAsync +8054132c ArchiveMgr::RequestLoadCourseArchiveAsync +80541348 ArchiveMgr::GetKartArchivePostfix +8054136c ArchiveMgr::GetKartArchivePrefix +80541390 AsyncCourseArchiveLoader::__ct +805413f0 AsyncCourseArchiveLoader::Init +80541444 AsyncCourseArchiveLoader::__dt +805414d8 AsyncCourseArchiveLoader::Load +80541598 AsyncCourseArchiveLoader::CopyToHolder +805415b8 0x805415b8 +805415c8 ArchiveMgr::ExecuteTask +8054163c ArchiveMgr::RequestTask +80541660 ArchiveMgr::ProcessRequestsAndShutdown +805417c4 ArchiveMgr::LoadKartArchiveAsync +805419b0 0x805419b0 +80541b90 ArchiveMgr::RequestLoadKartArchives +80541c4c ArchiveMgr::InitAllkartArchivesLoaders +80541d3c ArchiveMgr::ResetAllkartArchivesLoaders +80541dfc ArchiveMgr::GetAllKartLoaderHeap +80541e0c ArchiveMgr::LoadEarthBrres(heap) +80541ea4 ArchiveMgr::CreateEarthHeap +80541f04 ArchiveMgr::DestroyEarthHeap +80541f50 ArchiveMgr::LoadEarthBrresAsync +80542014 ArchiveMgr::LoadEarthBrres +805420d4 ArchiveMgr::RequestLoadEarthBrres +8054213c ArchiveMgr::LoadStaffGhostAsync +805421e8 0x805421e8 +805421f8 RootScene::__ct +80542328 RootScene::__dt +80542390 RootScene::SetHeapsGroupId +80542398 RootScene::CreateArchiveMgr +80542400 RootScene::CreateGroup1Instances +80542460 RootScene::CreateAudioMgr +805424dc RootScene::CreateScnMgrCreator +80542520 RootScene::CreateRacedata +80542564 RootScene::CreateEffectsMgr +805425ac RootScene::CreateHomeMenuMgr +805425f4 RootScene::CreateRKNetInstances +80542644 RootScene::CreateUIInstances +8054268c 0x8054268c +805426cc RootScene::CreateInstances +80543234 RootScene::InitInstances +8054344c 0x8054344c +8054348c 0x8054348c +80543490 RootScene::RequestRootScene +805434fc 0x805434fc +80543504 RootScene::enter +80543604 RootScene::exit +80543608 RootScene::calc +8054360c RootScene::draw +80543610 0x80543610 +80543698 RKSYS::Mgr::Disposer__dt +80543730 RKSYS::Mgr::CreateInstance +8054385c RKSYS::Mgr::DestroyInstance +80543890 RKSYS::Mgr::__ct +8054398c RKSYS::LicenseMgr::__ct +80543c1c RKSYS::LicenseCup::__ct +80543c40 Timer::__ct(bool) +80543c90 Timer::SetActive +80543c98 RKSYS::LicenseCup::__dt +80543cd8 RKSYS::LicenseLdbEntry::__ct +80543cfc RKSYS::LicenseLdbEntry::__dt +80543d3c RKSYS::LicenseUnkTimer::__ct +80543d60 RKSYS::LicenseUnkTimer::__dt +80543da0 RKSYS::LicenseFriends::__dt +80543de0 RKSYS::LicenseCompletion::__ct +80543e04 RKSYS::LicenseCompletion::__dt +80543e44 RKSYS::LicenseStaffGhostStatus::__ct +80543e50 RKSYS::Rating::__ct +80543e68 RKSYS::LicenseUnkTimer2::__ct +80543e8c RKSYS::LicenseUnkTimer2::__dt +80543ecc RKSYS::LicenseMgr::SetInitialized +80543ed8 RKSYS::LicenseMgr::__dt +80543f8c RKSYS::Mgr::__dt +80544068 0x80544068 +805441a4 RKSYS::Mgr::RequestTask +805441c0 RKSYS::Mgr::LoadTask +805441cc RKSYS::Mgr::LoadRKSYS +805443b8 RKSYS::Mgr::Init +805443dc RKSYS::Mgr::SaveCoreTask +8054445c RKSYS::Mgr::SaveCoreImpl +805444c8 RKSYS::Mgr::SaveCore +80544544 RKSYS::Mgr::WriteLicenses +805445ac RKSYS::Mgr::WriteCoreAndRequestSaveCore +80544658 RKSYS::LicenseMgr::SetCurLicense +80544690 RKSYS::Mgr::CheckLicenseMagic +805446c0 RKSYS::Mgr::ReadLicense +80544f60 RKSYS::LicenseMgr::ReadMiiName +80544fd8 RKSYS::LicenseMgr::GetMiiName +80544fdc RKSYS::LicenseMgr::ReadRFLCreateID +80545030 RKSYS::LicenseMgr::SetRFLCreateID +80545074 RKSYS::LicenseMgr::ReadDWCAccUserData +80545118 RKSYS::LicenseMgr::SetDWCUserData +805451b0 RKSYS::LicenseMgr::ReadFriendData +805451d4 RKSYS::LicenseMgr::GetFriends +805451dc RKSYS::LicenseMgr::ReadCup +805452b4 RKSYS::LicenseMgr::GetCup +805452cc RKSYS::LicenseMgr::ReadLdbEntry +80545380 RKSYS::LicenseMgr::GetLdbEntry(SaveCourseId) +80545398 RKSYS::LicenseMgr::ReadUnkTimer +80545414 RKSYS::LicenseMgr::GetUnkTimer +80545424 RKSYS::LicenseMgr::ReadCompletion +80545458 RKSYS::LicenseMgr::SetCompletion +80545480 RKSYS::LicenseMgr::ReadPBGhostBitfield +8054549c RKSYS::LicenseMgr::SetPBGhostBitfield +805454a8 RKSYS::LicenseMgr::ReadDLGhostBitfield +805454c4 RKSYS::LicenseMgr::SetDLGhostBitfield +805454d0 RKSYS::LicenseMgr::SetRKPDEA_2 +805454dc RKSYS::LicenseMgr::ReadRKPDEA_2 +80545504 RKSYS::LicenseMgr::ReadStaffGhostStatus +80545528 RKSYS::LicenseMgr::SetStaffGhostStatus +80545540 RKSYS::LicenseMgr::SetRKPD1BC_31 +8054554c RKSYS::LicenseMgr::ReadRKPD1BC_31 +80545568 RKSYS::LicenseMgr::GetRKPDVR +80545584 RKSYS::LicenseMgr::SetVR +80545594 RKSYS::LicenseMgr::GetRKPDBR +805455b0 RKSYS::LicenseMgr::SetBR +805455c0 RKSYS::LicenseMgr::SetOfflineVSWins +805455e0 RKSYS::LicenseMgr::ReadOfflineVSWins +805455f8 RKSYS::LicenseMgr::SetOfflineVSLosses +80545618 RKSYS::LicenseMgr::ReadOfflineVSLosses +80545630 RKSYS::LicenseMgr::SetOfflineBattleWins +80545650 RKSYS::LicenseMgr::ReadOfflineBattleWins +80545668 RKSYS::LicenseMgr::SetOfflineBattleLosses +80545688 RKSYS::LicenseMgr::ReadOfflineBattleLosses +805456a0 RKSYS::LicenseMgr::SetWFCVSWins +805456c0 RKSYS::LicenseMgr::ReadWFCVSWins +805456d8 RKSYS::LicenseMgr::SetWFCVSLosses +805456f8 RKSYS::LicenseMgr::ReadWFCVSLosses +80545710 RKSYS::LicenseMgr::SetWFCBattleWins +80545730 RKSYS::LicenseMgr::ReadWFCBattleWins +80545748 RKSYS::LicenseMgr::SetWFCBattleLosses +80545768 RKSYS::LicenseMgr::ReadWFCBattleLosses +80545780 RKSYS::LicenseMgr::SetGhostRacesWins +805457a0 RKSYS::LicenseMgr::ReadGhostRacesWins +805457b8 RKSYS::LicenseMgr::SetGhostRacesLosses +805457d8 RKSYS::LicenseMgr::ReadGhostRacesLosses +805457f0 RKSYS::LicenseMgr::SetTotalRacePlayed +80545810 RKSYS::LicenseMgr::ReadTotalRacePlayed +80545828 RKSYS::LicenseMgr::SetTotalBattlePlayed +80545848 RKSYS::LicenseMgr::ReadTotalBattlePlayed +80545860 RKSYS::LicenseMgr::SetRacesOnWheel +80545880 RKSYS::LicenseMgr::ReadRacesOnWheel +80545898 RKSYS::LicenseMgr::SetBattlesOnWheel +805458b8 RKSYS::LicenseMgr::ReadBattlesOnWheel +805458d0 RKSYS::LicenseMgr::ReadDistanceTravelled +805458e8 RKSYS::LicenseMgr::SetDistanceTravelled +80545924 RKSYS::LicenseMgr::SetGhostDataChallengesSent +80545944 RKSYS::LicenseMgr::ReadGhostDataChallengesSent +8054595c RKSYS::LicenseMgr::SetGhostDataChallengesReceived +8054597c RKSYS::LicenseMgr::ReadGhostDataChallengesReceived +80545994 RKSYS::LicenseMgr::SetItemHitsDelivered +805459b4 RKSYS::LicenseMgr::ReadItemHitsDelivered +805459cc RKSYS::LicenseMgr::SetItemHitsReceived +805459ec RKSYS::LicenseMgr::ReadItemHitsReceived +80545a04 RKSYS::LicenseMgr::SetTricksPerformed +80545a24 RKSYS::LicenseMgr::ReadTricksPerformed +80545a3c RKSYS::LicenseMgr::SetTimes1stPlaceAchieved +80545a5c RKSYS::LicenseMgr::ReadTimes1stPlaceAchieved +80545a74 RKSYS::LicenseMgr::ReadDistancetravelledwhilein1stplace +80545a8c RKSYS::LicenseMgr::SetDistancetravelledwhilein1stplace +80545ac8 RKSYS::LicenseMgr::ReadDistancetravelledonVSRaces +80545ae0 RKSYS::LicenseMgr::SetDistancetravelledonVSRaces +80545b1c RKSYS::LicenseMgr::SetCompetitionsEntered +80545b3c RKSYS::LicenseMgr::ReadCompetitionsEntered +80545b54 RKSYS::LicenseMgr::SetRacesOnCharacter +80545b7c RKSYS::LicenseMgr::ReadRacesOnCharacter +80545b9c RKSYS::LicenseMgr::SetRacesOnKart +80545bc4 RKSYS::LicenseMgr::ReadRacesOnKart +80545be4 RKSYS::LicenseMgr::SetRacesOnTrack +80545c0c RKSYS::LicenseMgr::ReadRacesOnTrack +80545c2c RKSYS::LicenseMgr::SetRacesOnBattleArena +80545c54 RKSYS::LicenseMgr::ReadRacesOnBattleArena +80545c74 RKSYS::LicenseMgr::SetUnk55f0 +80545c90 RKSYS::LicenseMgr::ReadUnk55f0 +80545ccc RKSYS::LicenseMgr::SetDefaultDrift +80545cd8 RKSYS::LicenseMgr::ReadDefaultDrift +80545cf4 RKSYS::LicenseMgr::Set CC +80545d08 RKSYS::LicenseMgr::ReadCC +80545d2c RKSYS::LicenseMgr::SetCPUDifficulty +80545d40 RKSYS::LicenseMgr::ReadCPUDifficulty +80545d64 RKSYS::LicenseMgr::SetVehicleType +80545d78 RKSYS::LicenseMgr::ReadVehicleType +80545d9c RKSYS::LicenseMgr::SetCourseChoice +80545db0 RKSYS::LicenseMgr::ReadCourseChoice +80545dd4 RKSYS::LicenseMgr::SetItemsType +80545de8 RKSYS::LicenseMgr::ReadItemsType +80545e0c RKSYS::LicenseMgr::SetTotalRaceCount +80545e20 RKSYS::LicenseMgr::ReadTotalRaceCount +80545e44 RKSYS::LicenseMgr::ReadUnkTimer2 +80545eac RKSYS::LicenseMgr::SetUnkTimer2 +80545eec RKSYS::LicenseMgr::ReadRKPD_1BC +80545f4c RKSYS::LicenseMgr::SetRKPD_1BC +80545f78 RKSYS::LicenseMgr::ReadRKPD_5680 +80545fe0 RKSYS::LicenseUnk5680::Set +80546034 RKSYS::LicenseMgr::SetRKPD_5680 +8054605c RKSYS::LicenseMgr::ReadRKPD_5688 +805460b4 RKSYS::LicenseMgr::SetRKPD_5688 +805460c4 RKSYS::LicenseMgr::ReadRKPD_568c +805460fc RKSYS::LicenseMgr::SetRKPD_568c +80546128 RKSYS::LicenseMgr::SetRKPD_568c_31 +80546134 RKSYS::LicenseMgr::ReadRKPD_5688_31 +80546150 RKSYS::LicenseMgr::WriteToRKPD +80546934 RKSYS::LicenseMgr::IsInitialized +80546940 RKSYS::LicenseMgr::WriteMiiName +8054695c RKSYS::LicenseMgr::GetMiiName +80546960 RKSYS::LicenseMgr::WriteRFLCreateID +805469b4 RKSYS::LicenseMgr::GetRFLCreateID +805469bc RKSYS::LicenseMgr::WriteDWCAccUserData +80546a50 RKSYS::LicenseMgr::GetDWCAccUserData +80546a5c RKSYS::LicenseMgr::WriteFriendData +80546a7c RKSYS::LicenseMgr::GetFriends +80546a84 RKSYS::LicenseMgr::WriteCup +80546aa8 RKSYS::LicenseMgr::GetCup +80546ac0 RKSYS::LicenseMgr::WriteLdbEntry +80546bec RKSYS::LicenseMgr::GetLdbEntry +80546c04 RKSYS::LicenseMgr::WriteUnkTimer +80546cf4 RKSYS::LicenseMgr::GetUnkTimer +80546d04 RKSYS::LicenseMgr::WriteCompletion +80546d38 RKSYS::LicenseMgr::GetCompletion +80546d44 RKSYS::LicenseMgr::WritePBGhostBitfield +80546d5c RKSYS::LicenseMgr::GetPBGhostBitfield +80546d68 RKSYS::LicenseMgr::WriteDLGhostBitfield +80546d80 RKSYS::LicenseMgr::GetDLGhostBitfield +80546d8c RKSYS::LicenseMgr::WriteRKPD_EA_2 +80546dac RKSYS::LicenseMgr::GetRKPD_EA_2 +80546db8 RKSYS::LicenseMgr::WriteRKPD1BC_31 +80546dd8 RKSYS::LicenseMgr::GetRKPD1BC_31 +80546de4 RKSYS::LicenseMgr::WriteVR +80546e00 RKSYS::LicenseMgr::GetVR +80546e0c RKSYS::LicenseMgr::WriteBR +80546e28 RKSYS::LicenseMgr::GetBR +80546e34 RKSYS::LicenseMgr::WriteOfflineVSWins +80546e4c RKSYS::LicenseMgr::GetOfflineVSWins +80546e58 RKSYS::LicenseMgr::WriteOfflineVSLosses +80546e70 RKSYS::LicenseMgr::GetOfflineVSLosses +80546e7c RKSYS::LicenseMgr::WriteOfflineBattleWins +80546e94 RKSYS::LicenseMgr::GetOfflineBattleWins +80546ea0 RKSYS::LicenseMgr::WriteOfflineBattleLosses +80546eb8 RKSYS::LicenseMgr::GetOfflineBattleLosses +80546ec4 RKSYS::LicenseMgr::WriteWFCVSWins +80546edc RKSYS::LicenseMgr::GetWFCVSWins +80546ee8 RKSYS::LicenseMgr::WriteWFCVSLosses +80546f00 RKSYS::LicenseMgr::GetWFCVSLosses +80546f0c RKSYS::LicenseMgr::WriteWFCBattleWins +80546f24 RKSYS::LicenseMgr::GetWFCBattleWins +80546f30 RKSYS::LicenseMgr::WriteWFCBattleLosses +80546f48 RKSYS::LicenseMgr::GetWFCBattleLosses +80546f54 RKSYS::LicenseMgr::WriteGhostRacesWins +80546f6c RKSYS::LicenseMgr::GetGhostRacesWins +80546f78 RKSYS::LicenseMgr::WriteGhostRacesLosses +80546f90 RKSYS::LicenseMgr::GetGhostRacesLosses +80546f9c RKSYS::LicenseMgr::WriteTotalRacePlayed +80546fb4 RKSYS::LicenseMgr::GetTotalRacePlayed +80546fd4 RKSYS::LicenseMgr::WriteTotalBattlePlayed +80546fec RKSYS::LicenseMgr::WriteRacesOnWheel +8054700c RKSYS::LicenseMgr::GetTotalBattlePlayed +80547024 RKSYS::LicenseMgr::GetRacesOnWheel +80547044 RKSYS::LicenseMgr::WriteBattlesOnWheel +8054705c RKSYS::LicenseMgr::GetBattlesOnWheel +8054707c RKSYS::LicenseMgr::WriteDistanceTravelled +80547094 RKSYS::LicenseMgr::GetDistanceTravelled +805470b4 RKSYS::LicenseMgr::WriteGhostDataChallengesSent +805470cc RKSYS::LicenseMgr::GetGhostDataChallengesSent +805470ec RKSYS::LicenseMgr::WriteGhostDataChallengesReceived +80547104 RKSYS::LicenseMgr::GetGhostDataChallengesReceived +80547124 RKSYS::LicenseMgr::WriteItemHitsDelivered +8054713c RKSYS::LicenseMgr::GetItemHitsDelivered +8054715c RKSYS::LicenseMgr::WriteItemHitsReceived +80547174 RKSYS::LicenseMgr::GetItemHitsReceived +80547194 RKSYS::LicenseMgr::WriteTricksPerformed +805471ac RKSYS::LicenseMgr::GetTricksPerformed +805471cc RKSYS::LicenseMgr::WriteTimes1stPlaceAchieved +805471e4 RKSYS::LicenseMgr::GetTimes1stPlaceAchieved +80547204 RKSYS::LicenseMgr::WriteDistancetravelledwhilein1stplace +8054721c RKSYS::LicenseMgr::GetDistancetravelledwhilein1stplace +8054723c RKSYS::LicenseMgr::WriteDistancetravelledonVSRaces +80547254 RKSYS::LicenseMgr::GetDistancetravelledonVSRaces +80547274 RKSYS::LicenseMgr::WriteCompetitionsEntered +8054728c RKSYS::LicenseMgr::GetCompetitionsEntered +805472b0 RKSYS::LicenseMgr::WriteRacesOnCharacter +805472d0 RKSYS::LicenseMgr::GetRacesOnCharacter +805472fc RKSYS::LicenseMgr::WriteRacesOnKart +8054731c RKSYS::LicenseMgr::GetRacesOnKart +80547348 RKSYS::LicenseMgr::WriteRacesOnTrack +80547368 RKSYS::LicenseMgr::GetRacesOnTrack +80547394 RKSYS::LicenseMgr::WriteRacesOnBattleArena +805473b4 RKSYS::LicenseMgr::WriteUnk55f0 +805473e4 RKSYS::LicenseMgr::GetUnk55f0 +80547400 RKSYS::LicenseMgr::WriteStaffGhostStatus +80547424 RKSYS::LicenseMgr::GetStaffGhostStatus +80547438 RKSYS::LicenseMgr::WriteDefaultDrift +80547458 RKSYS::LicenseMgr::GetDefaultDrift +80547464 RKSYS::LicenseMgr::WriteCC +8054748c RKSYS::LicenseMgr::GetCC +805474a0 RKSYS::LicenseMgr::WriteCPUDifficulty +805474c8 RKSYS::LicenseMgr::GetCPUDifficulty +805474dc RKSYS::LicenseMgr::WriteVehicleType +80547504 RKSYS::LicenseMgr::GetVehicleType +80547518 RKSYS::LicenseMgr::WriteCourseChoice +80547540 RKSYS::LicenseMgr::GetCourseChoice +80547554 RKSYS::LicenseMgr::WriteItemsType +8054757c RKSYS::LicenseMgr::GetItemsType +80547590 RKSYS::LicenseMgr::WriteTotalRaceCount +805475b8 RKSYS::LicenseMgr::GetTotalRaceCount +805475cc RKSYS::LicenseMgr::WriteUnkTimer2 +8054769c RKSYS::LicenseMgr::GetUnkTimer2 +805476b0 RKSYS::LicenseMgr::GetRKPD_1BC +805476f4 RKSYS::LicenseMgr::WriteRKPD_1BC +8054779c RKSYS::LicenseMgr::GetRKPD_5680 +805477a8 RKSYS::LicenseMgr::WriteRKPD_5680 +80547804 RKSYS::LicenseUnk5680::Get_0 +8054780c RKSYS::LicenseUnk5680::Get_7 +80547814 RKSYS::LicenseUnk5680::Get_11 +8054781c RKSYS::LicenseMgr::GetRKPD_5688 +8054782c RKSYS::LicenseMgr::WriteRKPD_5688 +80547888 RKSYS::LicenseMgr::WriteRKPD_568c +805478c0 RKSYS::LicenseMgr::GetRKPD_568c +805478cc RKSYS::LicenseMgr::WriteRKPD_5688_31 +805478ec RKSYS::LicenseMgr::GetRKPD_5688_31 +805478f8 RKSYS::LicenseMgr::WriteMagic +80547918 RKSYS::LicenseUnk5680::__ct(copy) +8054793c RKSYS::Mgr::EraseLicense +805479b0 RKSYS::Mgr::CreateLicense +80547a80 0x80547a80 +80547a84 RKSYS::Reset +80547ba4 RKSYS::SetCRC +80547be0 RKSYS::IsCRCCorrect +80547c28 RKSYS::CheckMagicAndVersion +80547c58 RKSYS::CheckRegion +80547c80 RKSYS::ResetRKPD +80547dd4 RKSYS::CreateRKPD +80547e74 RKSYS::ReadRKPDCup +80547f38 RKSYS::ReadRKPDLdbEntry +80547fd8 RKSYS::ReadRKPDUnkTimer +80548040 RKSYS::ReadRKPDUnkTimer2 +805481cc RKSYS::WriteRKPDLdbEntry +805482e4 RKSYS::WriteRKPDUnkTimer +805483c0 RKSYS::WriteRKPDUnkTimer2 +8054847c RKSYS::ResetRKGD +8054850c RKSYS::GetRKGDUnk8Idx +805485d8 RKSYS::SetRKGDUnk8 +805487b0 RKSYS::LicenseMgr::GetLdbEntry(CourseId) +80548810 RKSYS::LicenseMgr::OverwriteAndStoreLdbEntry +80548904 RKSYS::LicenseMgr::StoreLdbEntry +80548a74 RKSYS::LicenseMgr::GetGhostPosition +80548b64 RKSYS::LicenseMgr::GetBestRank +80548d30 RKSYS::LicenseMgr::GetFavouriteCharacter +80548df0 RKSYS::LicenseMgr::GetFavouriteKart +80548ed0 RKSYS::LicenseMgr::GetFavouriteTrack +80548ff0 RKSYS::LicenseMgr::GetFavouriteBattleArena +805490a0 RKSYS::LicenseMgr::GetWheelRacesPercentage +80549190 RKSYS::LicenseMgr::GetInFirstPercentage +805491f8 RKSYS::LicenseMgr::Copy5680To5688 +80549218 RKSYS::LicenseMgr::Generate5688Bitfield +80549250 RKSYS::LicenseCompletion::Reset +80549268 RKSYS::LicenseCompletion::GetOffsetAndRelativeBit +8054927c RKSYS::LicenseCompletion::SetComplete +805492a4 RKSYS::LicenseCompletion::ResetComplete +805492cc RKSYS::LicenseCompletion::IsCompleted +805492fc RKSYS::Mgr::GetGhostOffset +8054933c RKSYS::Mgr::ReadGhostTask +80549394 RKSYS::Mgr::ReadGhost +805493e8 RKSYS::Mgr::ReadGhostAsync +805495c4 RKSYS::Mgr::LoadGhostGroupTask +805495d0 RKSYS::Mgr::LoadGhostGroup +8054972c RKSYS::Mgr::LoadGhostGroupAsync +80549864 RKSYS::Mgr::WriteGhostTask +80549918 RKSYS::Mgr::WriteGhost +805499c8 RKSYS::Mgr::SaveGhostAsync +80549c08 RKSYS::Mgr::EraseGhostTask +80549ca8 RKSYS::Mgr::EraseGhost +80549d44 RKSYS::Mgr::EraseGhostAsync +80549f48 RKSYS::Mgr::GetValidLicensesCount +80549fd8 RKSYS::Mgr::GetCombinedLicenseCompletions +8054a0bc RKSYS::Mgr::ReplaceBinaryTask +8054a0c8 RKSYS::Mgr::ReplaceBinary +8054a1e8 RKSYS::Mgr::EraseBinary +8054a338 RKSYS::Mgr::GetCountry +8054a360 RKSYS::Mgr::GetLongitude +8054a388 RKSYS::Mgr::GetLatitude +8054a3b0 GameSceneCreator::CreateInstance +8054a3e4 GameSceneCreator::create +8054a4a8 GameSceneCreator::destroy +8054a4ac LensFlare::QuadDrawer::__ct +8054a730 0x8054a730 +8054a734 GameScreenEffectsMgr::GetRootScreenWidth +8054a750 GameScreenEffectsMgr::GetRootScreenHeight +8054a770 LensFlare::QuadDrawer::Draw +8054a944 0x8054a944 +8054aa14 LensFlare::Texture::__ct +8054aae4 LensFlare::Texture::SetPosition +8054ab28 LensFlare::Texture::CopyFromEFB +8054ab54 0x8054ab54 +8054ac90 LensFlare::__ct +8054ae94 0x8054ae94 +8054aef8 LensFlare::__dt +8054afac LensFlare::OnFadeOutPrepareStart +8054afec LensFlare::FadeOutPrepareUpdate +8054b144 LensFlare::OnFadeOutStart +8054b148 LensFlare::FadeOutUpdate +8054b1f0 LensFlare::OnNoTargetStart +8054b240 LensFlare::NoTargetUpdate +8054b29c LensFlare::OnNormalStateStart +8054b34c LensFlare::OnNormalStateUpdate +8054b488 LensFlare::Update +8054b790 Vec2::MultiplyByScalar +8054b7ac LensFlare::DrawQuads +8054b814 LensFlare::CopyEFBToTexture +8054b840 0x8054b840 +8054b848 0x8054b848 +8054b8d0 LensFlareMgr::__ct +8054bcd0 LensFlareMgr::__dt +8054bd94 LensFlareMgr::GetBRRESTexCount +8054bd9c LensFlareMgr::GetRawTexture +8054be18 LensFlareMgr::GetTextureWidth +8054be80 LensFlareMgr::GetTextureHeight +8054bee8 LensFlareMgr::GetTextureName +8054bf64 LensFlareMgr::GetTextureFormat +8054bf74 LensFlareMgr::Update +8054bfe0 LensFlareMgr::DrawTextures +8054c130 LensFlareMgr::Draw +8054c1b4 LensFlareMgr::CopyEFBToTextures +8054c270 LensFlareMgr::AddLensFX +8054c2d8 LensFlareMgr::EnableExternalLens +8054c2fc LensFlareMgr::GetTargetPosition +8054c5c4 LensFlareMgr::GetScreenPosition +8054c7ac 0x8054c7ac +8054c7d8 0x8054c7d8 +8054c810 FilterEffect::__ct +8054ca30 0x8054ca30 +8054ca94 FilterEffectMgr::SetColor +8054cabc FilterEffect::Update +8054cb90 0x8054cb90 +8054cba0 0x8054cba0 +8054cbac 0x8054cbac +8054cc48 0x8054cc48 +8054cc4c 0x8054cc4c +8054cca0 0x8054cca0 +8054cca4 0x8054cca4 +8054ccbc 0x8054ccbc +8054cccc 0x8054cccc +8054ccec 0x8054ccec +8054ccf0 0x8054ccf0 +8054cd08 FilterEffect::Draw +8054ce08 FilterEffectMgr::__ct +8054d074 FilterEffectMgr::__dt +8054d12c FilterEffect:__dt +8054d194 FilterEffectMgr::Update +8054d288 FilterEffectMgr::Draw +8054d3d0 0x8054d3d0 +8054d3f4 0x8054d3f4 +8054d424 0x8054d424 +8054d5c4 CourseFilterEffect::__ct +8054d7a4 0x8054d7a4 +8054d808 CourseFilterEffect::Update +8054d8dc CourseFilterEffect::OnNoFilterStart +8054d8ec CourseFilterEffect::OnWhiteFilterPrepareStart +8054d910 CourseFilterEffect::WhiteFilterPrepareUpdate +8054d964 CourseFilterEffect::OnWhiteFilterStart +8054d968 CourseFilterEffect::WhiteFilterUpdate +8054d980 CourseFilterEffect::OnBlackFilterStart +8054d9a0 CourseFilterEffect::BlackFilterUpdate +8054d9b8 CourseFilterEffect::OnAlphaFadeoutStart +8054d9bc CourseFilterEffect::AlphaFadeoutUpdate +8054da18 CourseFilterEffect::Draw +8054db18 CourseFilterEffectMgr::__ct +8054dd48 CourseFilterEffectMgr::__dt +8054de00 CourseFilterEffect::__dt +8054de68 CourseFilterEffectMgr::Update +8054df5c CourseFilterEffectMgr:Draw +8054e094 0x8054e094 +8054e0ac 0x8054e0ac +8054e24c CreditsBars::__ct +8054e328 0x8054e328 +8054e32c CreditsBars::Init +8054e354 CreditsBars::Draw +8054e4d4 GameScreenEffectsMgr::__ct +8054eaa0 GameScreenEffectsMgr::__dt +8054eb30 GameScreenEffectsMgr::Update +8054ed48 0x8054ed48 +8054ed9c GameScreenEffectsMgr::Draw +8054f124 GameScreenEffectsMgr::DrawCourseFilterEffects +8054f260 GameScreenEffectsMgr::CopyEFBToLensFlareTextures +8054f328 GameScreenEffectsMgr::AddLensFX +8054f390 GameScreenEffectsMgr::EnableExternalLensFlare +8054f3b8 0x8054f3b8 +8054f3e0 0x8054f3e0 +8054f414 GameScreenEffectsMgr::RequestWhiteCourseFilter +8054f430 CreditsBars::__dt +8054f470 GameScreenEffects_cpp_sinit_ +8054f4ac IsVehicleTypeUnlocked +8054f554 0x8054f554 +8054f564 GetCupType +8054f5c4 IsCupUnlocked +8054f858 IsCharacterUnlocked +8054f88c IsCharacterUnlocked_switch +8054f890 IsCharacterUnlocked_caseD_11 +8054f928 IsCharacterUnlocked_caseD_18 +8054f9b0 IsCharacterUnlocked_caseD_1a +8054fa34 IsCharacterUnlocked_caseD_10 +8054fa4c IsKartUnlocked +8054fb24 0x8054fb24 +8054fb44 0x8054fb44 +8054fde8 isFastStaffGhostUnlocked +8054fec8 0x8054fec8 +80550068 0x80550068 +8055006c BitRotator::__ct +8055008c BitRotator::Update +805500b0 GetTick +805500b4 GetHour +80550130 THP::CreateAudioDecodeThread +80550200 THP::AudioDecodeThreadStart +80550220 THP::AudioDecodeThreadCancel +80550268 THP::AudioDecoder +80550290 THP::AudioDecoderForOnMemory +8055033c THP::AudioDecode +80550428 THP::PopFreeAudioBuffer +8055045c THP::PushFreeAudioBuffer +80550470 THP::PopDecodedAudioBuffer +805504b4 THP::PushDecodedAudioBuffer +805504c8 THP::PlayerInit +805505e8 THP::PlayerQuit +80550640 THP::PlayerOpen +805508c8 THP::PlayerClose +8055091c THP::PlayerCalcNeedMemory +805509d4 THP::PlayerSetBuffer +80550c14 THP::InitAllMessageQueue +80550ce4 THP::PrepareReady +80550cf8 THP::PlayerPrepare +80550f78 THP::PlayerPlay +80550fd8 THP::PlayerStop +805510b4 THP::PlayerPause +805510f0 THP::PlayerSkip +805512c0 THP::PlayControl +80551584 THP::ProperTimingForGettingNextFrame +805516b0 THP::PlayerDrawCurrentFrame +805516b8 THP::PlayerGetVideoInfo +80551700 THP::PlayerGetAudioInfo +80551748 THP::PlayerGetFrameRate +80551770 THP::PlayerGetTotalFrame +80551794 THP::PlayerGetState +805517a4 THP::PlayerDrawDone +80551814 0x80551814 +80551880 THP::AudioMixCallback +805519ec THP::MixAudio +80551db8 THP::PlayerSetVolume +80551ee4 THP::PlayerGetVolume +80551f1c THP::CreateReadThread +80551fbc THP::ReadThreadStart +80551fdc THP::ReadThreadCancel +80552024 THP::Reader +80552114 THP::PopReadedBuffer +80552148 THP::PopReadedBuffer2 +8055215c THP::PopFreeReadBuffer +80552190 THP::PushFreeReadBuffer +805521a4 THP::PopReadedBuffer2 +805521d8 THP::PushReadedBuffer2 +805521ec THP::CreateVideoDecodeThread +805522c0 THP::VideoDecodeThreadStart +805522e0 THP::VideoDecodeThreadCancel +80552328 THP::VideoDecoder +805523f4 THP::VideoDecoderOnMemory +80552524 THP::VideoDecode +80552670 THP::PopFreeTextureSet +805526a4 THP::PushFreeTextureSet +805526b8 THP::PopDecodedTextureSet +805526fc THP::PushDecodedTextureSet +80552710 courseIdToGhostIndex +805527f4 GetCourseIdBySlot +80552818 0x80552818 +805529b8 0x805529b8 +80552b00 0x80552b00 +80552c94 0x80552c94 +80552ee4 0x80552ee4 +8055300c 0x8055300c +8055307c 0x8055307c +80553080 0x80553080 +80553088 0x80553088 +805530a0 0x805530a0 +805530a8 0x805530a8 +80553108 0x80553108 +8055314c 0x8055314c +805531a4 0x805531a4 +805531a8 0x805531a8 +805531ac 0x805531ac +805531b8 0x805531b8 +805531c4 0x805531c4 +805531d0 GlobeScene::__ct +80553214 GlobeScene::__dt +8055326c GlobeScene::OnEnter +80553338 GlobeScene::CreateAndInitInstances +80553408 GlobeScene::OnEnterEnd +80553448 GlobeScene::OnExit +80553490 GlobeScene::OnCalc +80553508 RaceScene::__ct +80553554 RaceScene::__dt +805535d0 RaceScene::OnEnter +80553b88 RaceScene::CreateAndInitInstances +805540ac RaceScene::OnEnterEnd +8055432c RaceScene::vf_0x58 +80554330 RaceScene::OnExit +80554414 RaceScene::OnReinit +80554454 RaceScene::UpdateRaceInstances +80554690 0x80554690 +80554710 RaceScene::UpdateSomeInstances +80554794 RaceScene::isPaused +805547ec RaceScene::OnCalc +805548e8 RaceScene::GetScreenCount +805548f8 RaceScene::isSpectating +80554908 RaceScene::vf_0x48 +80554914 RaceScene::vf_0x50 +8055491c RaceScene::vf_0x58 +80554924 MenuScene::__ct +80554968 MenuScene::__dt +805549c0 MenuScene::OnEnter +80554ad4 MenuScene::CreateAndInitInstances +80554be4 MenuScene::OnEnterEnd +80554c18 MenuScene::OnExit +80554c48 MenuScene::OnCalc +80554c9c RelProlog +80554ce8 RelEpilog +80554d30 RelUnresolvedSection +80554de4 Random::__ct +80554e50 Random::Reset +80554e94 Random::__ct(seed) +80554eb8 Random::__dt +80554ef8 Random::Next +80554f4c Random::NextLimited +80554fa8 Random::NextFloat +80555028 Random::NextFloatLimited +805550ac 0x805550ac +805550d0 ModelTransformator::__ct +805551dc ModelTransformator::AppendAnmHolder +805551e4 ModelTransformator::AppendAnmBlend +805551ec ModelTransformator::SetBlendWeightDecrement +80555210 ModelTransformator::GetBlendWeightDecrement +8055523c ModelTransformator::DecrementBlendWeight +8055526c ModelTransformator::DetachAllAnmFromBlend(type) +8055529c ModelTransformator::DetachAllAnmFromBlend(listIdx) +805552fc ModelTransformator::LinkAnimationByName +80556098 ModelTransformator::IsG3dObj +805560b4 AnmChrBlendHolder::__dt +805560f4 0x805560f4 +80556134 ModelTransformator::LinkAnimationByBRRESIdx +80556890 ModelTransformator::LinkChrAnmToBone +80556a6c 0x80556a6c +80556b24 ModelTransformator::LinkEmptyAnm +80556bb4 ModelTransformator::GetAnmHolderByIdx +80556bbc ModelTransformator::GetAnmObjByIdx +80556be4 ModelTransformator::AddAnmToScnMdlAndSetupBRASD +80556c70 ModelTransformator::AddAnmToScnMdl +80556c88 ModelTransformator::OverwriteAnm +80556ca8 ModelTransformator::RestoreAnm +80556cc0 ModelTransformator::GetAnmHolderByType +80556cd0 ModelTransformator::GetPrevAnmHolderByType +80556ce0 ModelTransformator::IsTypeActive +80556cfc ModelTransformator::IsTypeInPrev +80556d18 ModelTransformator::GetAnmObjByType +80556d2c ModelTransformator::DetachHolderFromParent +80556d4c ModelTransformator::PlayAnmNoBlend +80556ec8 0x80556ec8 +80556fd0 ModelTransformator::AddAnmBlendToScnMdl +80557004 ModelTransformator::PlayAnmWithBlend +805571b0 ModelTransformator::StopAnmType +80557258 ModelTransformator::UpdateBRASDAndBlend +805572d4 AnmHolder::GetFrame +805572e0 ModelTransformator::UpdateBlend +805574a0 AnmHolder::IsLooped +805574a8 AnmHolder::GetFrameCount +805574b4 0x805574b4 +80557538 ModelTransformator::Bind +80557590 ModelTransformator::UpdateActiveAnms +80557678 0x80557678 +80557710 0x80557710 +80557750 0x80557750 +80557874 0x80557874 +80557930 ModelTransformator::vf_0x8 +80557934 AnmHolder::SetUpdateRate +80557938 AnmHolder::GetUpdateRate +80557944 AnmHolder::UpdateRateAndSetFrame +80557948 AnmHolder::SetFrame +8055794c 0x8055794c +8055798c 0x8055798c +805579d4 0x805579d4 +80557a24 0x80557a24 +80557c68 0x80557c68 +80557d68 0x80557d68 +80557eb8 0x80557eb8 +80558084 0x80558084 +80558114 AnmTexPatOverrideHolder::__dt +80558154 AnmTexPatOverrideHolder::SetWeight +8055819c AnmTexPatOverrideHolder::GetWeight +805581ec AnmTexPatOverrideHolder::AttachNew +80558430 AnmTexPatOverrideHolder::Attach +80558530 AnmTexPatOverrideHolder::DecrementWeight +80558680 AnmTexPatOverrideHolder::ShouldDetachFromParent +8055884c AnmTexPatOverrideHolder::DetachAll +805588dc 0x805588dc +8055891c 0x8055891c +80558964 0x80558964 +805589b4 0x805589b4 +80558bf8 0x80558bf8 +80558cf8 0x80558cf8 +80558e48 0x80558e48 +80559014 0x80559014 +805590a4 0x805590a4 +805590e4 0x805590e4 +8055912c 0x8055912c +8055917c 0x8055917c +805593c0 0x805593c0 +805594c0 0x805594c0 +80559610 0x80559610 +805597dc 0x805597dc +8055986c AnmChrBlendHolder::__dt +805598ac AnmChrBlendHolder::SetWeight +8055995c AnmChrBlendHolder::GetWeight +805599fc AnmChrBlendHolder::AttachNew +80559c40 AnmChrBlendHolder::Attach +80559d40 AnmChrBlendHolder::DecrementWeight +80559e90 AnmChrBlendHolder::ShouldDetachFromParent +8055a05c AnmChrBlendHolder::DetachAll +8055a0ec 0x8055a0ec +8055a100 0x8055a100 +8055a114 0x8055a114 +8055a180 0x8055a180 +8055a204 0x8055a204 +8055a268 0x8055a268 +8055a27c 0x8055a27c +8055a290 AnmTexPatHolder::GetFrame +8055a2a4 AnmTexPatHolder::SetFrame +8055a2b8 AnmTexPatHolder::UpdateRateAndSetFrame +8055a324 AnmTexPatHolder::GetFrameCount +8055a3a8 AnmTexPatHolder::IsLooped +8055a40c AnmTexPatHolder::GetUpdateRate +8055a420 AnmTexPatHolder::SetUpdateRate +8055a434 0x8055a434 +8055a448 0x8055a448 +8055a45c 0x8055a45c +8055a4c8 0x8055a4c8 +8055a54c 0x8055a54c +8055a5b0 0x8055a5b0 +8055a5c4 0x8055a5c4 +8055a5d8 0x8055a5d8 +8055a5ec 0x8055a5ec +8055a600 0x8055a600 +8055a66c 0x8055a66c +8055a6f0 0x8055a6f0 +8055a754 0x8055a754 +8055a768 0x8055a768 +8055a77c AnmChrHolder::GetFrame +8055a790 AnmChrHolder::SetFrame +8055a7a4 AnmChrHolder::UpdateRateAndSetFrame +8055a810 AnmChrHolder::GetFrameCount +8055a894 AnmChrHolder::IsLooped +8055a8f8 AnmChrHolder::GetUpdateRate +8055a90c AnmChrHolder::SetUpdateRate +8055a920 0x8055a920 +8055a950 0x8055a950 +8055a970 0x8055a970 +8055a9dc ModelDirector::SetScale +8055aa30 0x8055aa30 +8055aaa8 0x8055aaa8 +8055ab14 0x8055ab14 +8055ab68 0x8055ab68 +8055ab78 0x8055ab78 +8055abd8 0x8055abd8 +8055ac18 ModelDirector::__ct(ClipInfo) +8055ae8c ModelDirector::__ct +8055aed8 ModelDirector::__ct(ScnMgrIdx) +8055af3c ModelDirector::__dt +8055af7c ModelDirector::GetBRRES +8055af98 ModelDirector::BindBRRES +8055b024 ModelDirector::BindBRRESFallback +8055b0d4 ModelDirector::RipAndBindBRRES +8055b178 ModelDirector::BindBRRESImpl +8055b380 ModelDirector::BRRESExists +8055b3c4 ModelDirector::GetResMdl(string) +8055b3d4 ModelDirector::GetResMdl(idx) +8055b3e4 ModelDirector::MdlExists +8055b41c ModelDirector::HasResMdl +8055b420 ModelDirector::Init +8055b680 ModelDirector::InitG3D +8055b854 ModelDirector::AppendToScnMgr +8055b890 ModelDirector::CreateScn +8055ba68 ModelDirector::LoadWithAnm(name) +8055bb50 ModelDirector::LoadWithAnm(idx) +8055bc38 ModelDirector::LoadNoAnm(name) +8055bc98 ModelDirector::LoadNoAnm(idx) +8055bcf8 ModelDirector::LoadWithOption(name) +8055bdcc ModelDirector::LoadWithOption(idx) +8055bea0 ModelDirector::LoadScnMdl1Mat1Shp +8055bf00 MiiHeadsModel::InitModel +8055c174 0x8055c174 +8055c244 0x8055c244 +8055c2bc 0x8055c2bc +8055c370 ModelDirector::ToggleVisible +8055c488 ModelDirector::EnableDraw +8055c550 0x8055c550 +8055c58c ModelDirector::UpdateVisibility +8055c660 ModelDirector::EnableScreen +8055c678 ModelDirector::DisableScreen +8055c690 ModelDirector::IsVisibleOnScreen +8055c6b0 ModelDirector::EnableScreen2 +8055c6c8 ModelDirector::IsVisibleOnScreen2 +8055c6e8 ModelDirector::SetScnMdlOptions +8055c804 0x8055c804 +8055c888 0x8055c888 +8055c910 0x8055c910 +8055c9bc 0x8055c9bc +8055ca74 0x8055ca74 +8055cbbc ModelDirector::Update +8055cc74 0x8055cc74 +8055cdc8 ModelDirector::SetAllScnOptionsFromClipInfo +8055ced4 ModelDirector::SetDisableDrawScnOptionsFromClipInfo +8055d03c 0x8055d03c +8055d1ac 0x8055d1ac +8055d2a0 0x8055d2a0 +8055d370 ModelDirector::CreateTransformator +8055d470 0x8055d470 +8055d580 0x8055d580 +8055d664 ModelDirector::SetAudioActor +8055d76c ModelDirector::LinkAnimation +8055d900 0x8055d900 +8055da74 0x8055da74 +8055dbf4 ModelDirector::LinkEmptyAnm +8055dd08 0x8055dd08 +8055e460 ModelDirector::LinkAllAnimations +8055eb64 ModelDirector::PrepareAllAnms +8055ebfc 0x8055ebfc +8055ec0c 0x8055ec0c +8055ec2c 0x8055ec2c +8055ec34 ModelDirector::SetLight +8055ec44 ModelDirector::GetScnMgr +8055ec7c ModelDirector::RemoveFromGroup +8055eccc ModelDirector::ToggleTransparent +8055ed68 ModelDirector::ReplaceMatGXTexObj +8055ed9c 0x8055ed9c +8055ee44 ModelDirector::UpdateDrawPriority +8055ee88 0x8055ee88 +8055ef64 0x8055ef64 +8055f028 0x8055f028 +8055f0d4 0x8055f0d4 +8055f158 ModelDirector::ChangeTransformator +8055f1c8 ModelDirector::GetScale +8055f214 ModelDirector::SetScale(float) +8055f250 ModelCalcBase::__ct +8055f25c 0x8055f25c +8055f33c 0x8055f33c +8055f410 ModelCalcCallback::GetBoneWorldMtx +8055f4e4 0x8055f4e4 +8055f5c4 0x8055f5c4 +8055f698 0x8055f698 +8055f76c 0x8055f76c +8055f7b4 ModelCalcCallback::__ct +8055f868 0x8055f868 +8055f8a8 ModelCalcCallback::ExecCallback_CALC_WORLD +8055f8cc ModelCalcCBBoneLinked::__ct +8055f990 ModelCalcCallback::__dt +8055f9d0 ModelCalcCBBoneLinked::ExecWorldCBImpl +8055fbac 0x8055fbac +8055fc74 ModelCalcCBBoneLinked::__dt +8055fcb4 ModelCalcCallback::ExecCallback_CALC_XLU +8055fcb8 ModelCalcCallback::ExecCallback_CALC_OPA +8055fcbc ModelCalcCallback::ExecCallback_CALC_VIEW +8055fcc0 ModelCalcCallback::ExecCallback_CALC_MAT +8055fcc4 0x8055fcc4 +8055fcc8 0x8055fcc8 +8055fd08 ModelCalcCallback::__dt(thunk) +8055fd10 ModelCalcCBBoneLinked::__dt(thunk) +8055fd18 ModelCalcCallback::ExecCallback_CALC_WORLD(thunk) +8055fd20 0x8055fd20 +8055fd28 Light::__ct +8055ff0c 0x8055ff0c +8055ffc8 Light::Init +8056017c 0x8056017c +80560324 0x80560324 +80560420 0x80560420 +8056047c Light::InitLightObject +805605b4 0x805605b4 +80560610 0x80560610 +805606a0 Light::Update +80560980 0x80560980 +805609a4 LightMgrHolder::__ct +80560a68 LightMgrHolder::805610e8 +80560b8c LightMgrHolder::8056120c +80560c68 LightMgrHolder::LoadBLIGHT +80560c6c LightMgrHolder::805612ec +80560d0c 0x80560d0c +80560d18 LightMgrHolder::AcquireLight +80560d84 LightMgrHolder::moveFromAtoB +80560dd0 LightMgrHolder::vf_0x10 +80560eec LightMgrHolder::Update +80560f70 LightMgrHolder::LoadBLMAP +80561008 LightMgrHolderRace::__ct +805612c8 LightMgrHolder::__dt +80561308 LightMgrHolderRace::LoadBLIGHT +80561408 LightMgrHolder::LoadBLMAP +80561498 LightMgrHolderMenu_construct +80561568 LightMgrHolderMenu_loadBlight +805615c0 LightMgrHolderMenu_loadLightMap +8056161c LightMgrHolderMiiBody_construct +805616ec LightMgrHolderMiiBody_loadBlight +80561754 LightMgrHolderMiiBody_loadLightMap +805617c0 LightMgrHolderMiiBody_destruct +80561800 LightMgrHolderMenu_destruct +80561840 LightMgrHolderRace::destruct +80561880 Light::__dt +805618c0 ScnMgr::__ct +805619e4 0x805619e4 +80561a3c ScnMgr::__dt +80561ac4 ScnMgr::ResetRenderModeObj +80561b00 ScnMgr::InitImpl +80561cd0 ScnMgr::LoadPostEffects +80561cd4 ScnMgr::vf_0x28 +80561cd8 ScnMgr::CreateAllGroups +80561dc4 ScnMgr::CreateScnGroup +80561df0 ScnMgr::LoadLights +80561e4c ScnMgr::DrawLights +80561e9c 0x80561e9c +80561ea0 ScnMgr::DoneDraw +80561f28 ScnMgr::DrawModelsImpl +80562208 ScnMgr::UpdateScnRoot +805624b4 ScnMgr::UpdateCameras +80562570 GameCamera::GetViewMatrix +80562578 ScnMgr::RemoveShadowTextureMgr +8056258c 0x8056258c +8056260c 0x8056260c +8056263c ScnMgr::InsertModelDirectorInScn +80562810 ScnMgr::SetModelDrawPriority +805628e0 ScnMgr::SetModelXluDrawPriority +80562900 0x80562900 +805629e8 0x805629e8 +80562a6c 0x80562a6c +80562b2c 0x80562b2c +80562bec ScnMgr::SetAnmScn +80562d90 ScnMgr::SetRootAnmScn +80562f34 ScnMgr::AppendScnGroupExHolder +80562f44 ScnMgr::RemoveModelDirector +80562f4c ScnMgr::AppendScreenSpecificModelDirector +80562f54 ScnMgr::AppendMatModelDirector +80562f5c ScnMgr::RemoveMatModelDirector +80562f64 ScnMgr::SwitchScnRoot +80562ff4 ScnMgr::UpdateVisibility +8056305c 0x8056305c +80563174 0x80563174 +8056327c ScnMgr::CreateScnGroupEx +805633f8 ScnMgr::RearrangeDirectorGroups +8056351c ScnMgr::80563b9c +80563568 ScnMgr::80563be8 +805635b8 ScnMgr::80563c38 +80563604 ScnGroupExHolder::__ct +80563664 TextureHolder::__ct +80563730 TextureHolder::CopyFromEFB +80563868 TextureHolder::80563ee8 +805639f4 ScnMgr::UpdateModelDrawPriority +80563a8c ScnMgr::RemoveGroup +80563ac0 ScnMgr::InsertGroup +80563afc ScnMgr::GetScnGroup +80563b58 TextureHolder::__dt +80563b98 ScnMgr::vf_0x2c +80563b9c ScnMgr::DrawModels +80563ba4 ScnMgr::CalcSelf +80563ba8 ScnMgr::vf_0xC +80563bac ScnMgr::Init +80563bb8 ScnGroupHolder::__dt +80563bf8 ScnGroupExHolder::__dt +80563c38 Renderer::__ct +80563c8c Renderer::__dt +80563cf8 RendererWithModels::__ct +80563d4c RendererWithModels::__dt +80563dc4 RendererWithModels::Calc +80563dd8 RendererWithModels::Draw +80563e28 RendererWithModels::DrawWithProjection +80563e6c 0x80563e6c +80563f98 RendererMixed::__ct +80563fec RendererMixed::Draw +80564008 RendererMii::__ct +80564064 RendererMixed::__dt +805640e0 RendererMii::DrawModels +8056413c RendererMii::__dt +805641bc ScnMgr::InitScn +80564320 0x80564320 +80564368 0x80564368 +80564394 0x80564394 +8056445c ScnMgr::CalcAll +805644fc ScnMgr::Calc(idx) +805645c4 0x805645c4 +805645e4 ScnMgr::Draw(idx) +805646e0 ScnMgr::DrawMain +805647b8 ScnMgr::DrawSecondary +80564924 0x80564924 +8056493c Renderer::Remove(internal idx) +80564974 ScnMgr::Unregister +805649b0 ScnMgr::Reset +80564a30 ScnMgr::Finalize +80564a94 Renderer::Register(listIdx) +80564ae4 Renderer::RegisterAndAppendScreen +80564be8 Renderer::Register2ndList(NoAppend) +80564c2c Renderer::Remove(listIdx) +80564c44 Renderer::RemoveFrom1stList +80564c54 Renderer::RemoveFrom2ndList +80564c68 Renderer::Register(bool Append) +80564d1c ScnMgr::Register +80564d50 0x80564d50 +80564dbc 0x80564dbc +80564e14 0x80564e14 +80564e6c 0x80564e6c +80564fb0 ScnMgr::AcquireLight +80564fc0 0x80564fc0 +80564fd4 0x80564fd4 +80564fe4 0x80564fe4 +80564ff4 0x80564ff4 +80565044 0x80565044 +80565048 0x80565048 +805650ac 0x805650ac +80565124 0x80565124 +8056519c GameScreen::__ct +80565448 0x80565448 +80565488 0x80565488 +805654c8 0x805654c8 +80565508 0x80565508 +80565548 0x80565548 +80565638 0x80565638 +80565720 GameScreen::SetAndLoadOrthoProj +80565808 0x80565808 +805658f0 0x805658f0 +805659a0 GameScreen::SetAndLoadProjection +80565a50 0x80565a50 +80565b00 0x80565b00 +80565b68 GameScreen::SetProjection +80565bf8 0x80565bf8 +80565cb0 0x80565cb0 +80565d38 0x80565d38 +80565ddc 0x80565ddc +80565e64 0x80565e64 +80565f04 0x80565f04 +80565ff0 0x80565ff0 +80566030 0x80566030 +80566070 0x80566070 +805661a4 0x805661a4 +805662d8 0x805662d8 +80566538 GameScreen::Set16_9AspectRatio +805665a0 GameScreen::Set4_3AspectRatio +80566620 GameScreen::Init +8056673c 0x8056673c +805667b8 GameScreen::CalcDimensions +805668ec GameScreen::GetAbsoluteToView +80566940 GameScreen::GetViewToScreen +80566944 GameScreen::GetAbsoluteToScreen +805669c4 0x805669c4 +80566a34 0x80566a34 +80566ab0 GameScreen::__dt +80566af0 RendererGlobe::__ct +80566b2c RendererMenu::__dt +80566b8c 0x80566b8c +80566be8 RendererGlobe::__dt +80566c4c Kart::Damage::__ct +80566cdc 0x80566cdc +80566d1c Kart::Damage::Reset +80566d30 Kart::Damage::Update +80566e74 Kart::Damage::SetAffectedByPOW +80566e7c Kart::Damage::SetPOWParams +80566ea4 Kart::Damage::SetPOWParams(static) +80566ecc Kart::Damage::ShouldReceivePOWDamage +80566ef8 Kart::Damage::ResetPOWParams +80566f14 Kart::Damage::UpdatePOWParams +80566f5c Kart::Damage::SetDamage +805673d4 Kart::Damage::UpdateCurDamage +80567408 Kart::Damage::EndCurDamage +80567518 0x80567518 +805675e8 0x805675e8 +80567664 Kart::Damage::UpdateCurDamageSpeed +805676bc Kart::Damage::ApplySpinDamage +805678e8 Kart::Damage::ApplyBananaDamage +80567934 Kart::Damage::ApplyGoombaDamage +80567980 Kart::Damage::ApplyFireDamage +805679cc Kart::Damage::ApplyShockDamage +805679d8 Kart::Damage::ApplyZapperDamage +805679e4 Kart::Damage::ApplyPOWDamage +80567b18 0x80567b18 +80567b84 Kart::Damage::UpdateSpinOutdamage +80567cfc Kart::Damage::OnSpinOutDamageEnd +80567d38 Kart::Damage::UpdatePOWDamage +80567ed8 Kart::Damage::vf_0x10 +80567fa0 Kart::Damage::OnPOWDamageEnd +80567fdc Kart::Damage::ApplyShellFIBDamage +8056805c Kart::Damage::OnShellFIBDamageEnd +80568098 Kart::Damage::ApplyStarDamage +80568114 Kart::Damage::ApplyKnockback +80568428 Kart::Damage::UpdateKnockbackDamage +805685c0 0x805685c0 +805685fc Kart::Damage::OnStarCarDamageEnd +80568638 Kart::Damage::ApplyChompDamage +805686b4 Kart::Damage::UpdateBigKnockbackDamage +805688e8 Kart::Damage::OnBigKnockbackDamageEnd +80568924 Kart::Damage::ApplyCarDamage +805689a4 Kart::Damage::ApplyBulletDamage +80568a20 Kart::Damage::ApplyLaunchDamage +80568c34 Kart::Damage::UpdateLaunchDamage +80569048 Kart::Damage::OnLaunchDamageEnd +8056904c 0x8056904c +805690f4 Kart::Damage::ApplyThwompDamage +80569198 Kart::Damage::ApplyMegaDamage +8056923c Kart::Damage::ApplySquishRespawnDamage +805692f8 Kart::Damage::ApplyCarSquishDamage +8056939c Kart::Damage::UpdateSquishDamage +80569450 Kart::Damage::OnSquishDamageEnd +80569468 Kart::Damage::ApplyDrivingDirKnockback +80569514 Kart::Damage::ApplySidewaysKnockback +805696cc 0x805696cc +80569724 0x80569724 +8056977c 0x8056977c +8056981c 0x8056981c +805698ac 0x805698ac +80569930 0x80569930 +805699cc 0x805699cc +80569ae4 Kart::Damage::vf_0x14 +80569ae8 0x80569ae8 +80569b28 Kart::Damage::__dt +80569b68 0x80569b68 +80569ba8 KartDamageCpp_sinit_ +80569be4 Kart::ModelsVisibility::__ct +80569c30 0x80569c30 +80569c70 Kart::ModelsVisibility::SetInvisible +80569c80 Kart::ModelsVisibility::SetModelsVisibility +80569df0 Kart::ModelsVisibility::UpdateModelsVisibility +80569f00 Kart::ModelsVisibility::SetModelDraw +80569f1c Kart::ModelsVisibility::__dt +80569f5c Kart::MatTEVHandler::SetPartTEVSwapMode +80569f6c Kart::MatTEVHandler::__ct +80569fb0 Kart::MatTEVHandler::SetTexSwapModeAndSetTEVSwapModes +8056a058 Kart::MatTEVHandler::SetTEVSwapModes +8056a100 Kart::MatTEVHandler::SetModelTEVSwapMode(bool) +8056a21c Kart::MatTEVHandler::SetModelTevColorOp +8056a318 Kart::MatTEVHandler::SetTEVSwapModesNoTexModeUpdate +8056a3a8 Kart::MatTEVHandler::SetModelTEVSwapMode +8056a4ac Kart::MatTEVHandler::__dt +8056a4ec Kart::ScaleAnmController::LoadAnimations +8056a61c Kart::ScaleAnmController::GetAnmScale +8056a674 Kart::ScaleAnmController::GetPressUpAnmScale +8056a6c4 Kart::ScaleAnmController::__ct +8056a810 0x8056a810 +8056a850 0x8056a850 +8056a890 Kart::ScaleAnmController::Reset +8056a934 Kart::ScaleAnmController::RequestScaleChange +8056a9e0 0x8056a9e0 +8056aa14 0x8056aa14 +8056aa4c 0x8056aa4c +8056aae8 Kart::ScaleAnmController::RequestEndScale +8056ab98 Kart::ScaleAnmController::Update +8056addc 0x8056addc +8056af28 Kart::ScaleAnmController::__dt +8056af68 KartScaleAnmController_cpp_sinit_ +8056afb0 Kart::ScaleAnmController::__ct +8056afbc Kart::StarAnmMgr::LoadAnm +8056b228 Kart::StarAnmMgr::__ct +8056b26c Kart::StarAnmMgr::Activate +8056b290 Kart::StarAnmMgr::Update +8056b52c Kart::StarAnmMgr::StartEnding +8056b540 Kart::StarAnmMgr::End +8056b54c Kart::StarAnmMgr::Reset +8056b688 0x8056b688 +8056b7a0 Kart::StarAnmMgr::SetModelColorsImpl +8056b8a0 0x8056b8a0 +8056b9b0 Kart::StarAnmMgr::SetModelColors +8056b9b4 Kart::StarAnmMgr::__dt +8056b9f4 0x8056b9f4 +8056ba4c Kart::Part::__dt +8056ba8c Kart::Arm::LoadModel +8056baa4 Kart::Arm::UpdateMatrix +8056bd14 Kart::Body::__ct +8056bd7c Kart::Body::LoadModel +8056bd90 Kart::Body::CreateModelDirectors +8056bdd8 Kart::Body::Init +8056be34 Kart::Body::Reset +8056be80 Kart::Body::vf_0x58 +8056bec4 0x8056bec4 +8056bf08 0x8056bf08 +8056bf84 Kart::Body::GetMatrix +8056bfe4 Kart::Body::UpdateMatrix +8056c080 0x8056c080 +8056c138 0x8056c138 +8056c1f4 Kart::Body::vf_0x60 +8056c270 0x8056c270 +8056c2d0 0x8056c2d0 +8056c2e4 0x8056c2e4 +8056c344 0x8056c344 +8056c368 Kart::Body::Load2ndModel +8056c3c8 0x8056c3c8 +8056c4dc 0x8056c4dc +8056c5f4 0x8056c5f4 +8056c640 Kart::BodyKart::__ct +8056c704 Kart::Body::__dt +8056c744 Kart::BodyKart::SetDispParams +8056c784 Kart::BodyKart::Load +8056c818 Kart::BodyKart::UpdateMatrix +8056ca98 Kart::BodyKart::vf_0xc +8056cb2c Kart::BodyKart::vf_0x64 +8056cbb0 Kart::BodyKart::vf_0x24 +8056cc00 Kart::BodyKart::ApplyStarColors +8056cc78 Kart::BodyKart::vf_0x2c +8056ccf0 Kart::BodyKart::vf_0x30 +8056cd68 Kart::BodyKart::UpdateModelDrawPriority +8056cdf0 0x8056cdf0 +8056ce30 Kart::BikeHandle::LoadModel +8056ce40 Kart::BikeHandle::UpdateMatrix +8056cfc0 0x8056cfc0 +8056d000 Kart::BikeSwingArm::LoadModel +8056d010 Kart::BikeSwingArm::UpdateMatrix +8056d1d8 Kart::BodyBike::__ct +8056d270 Kart::BikeHandle::__dt +8056d2b0 Kart::BikeSwingArm::__dt +8056d2f0 Kart::BodyBike::SetDispParams +8056d304 Kart::BodyBike::LoadModel +8056d318 Kart::BodyBike::Load +8056d38c Kart::BodyBike::vf_0x60 +8056d408 Kart::BodyBike::UpdateMatrix +8056d6d4 Kart::Body::GetMatrix +8056d814 Kart::BodyBike::UpdateWheelMatrix +8056d940 Kart::BodyBike::vf_0xC +8056d9b4 Kart::BodyBike::vf_0x64 +8056da14 Kart::BodyBike::vf_0x24 +8056da34 Kart::BodyBike::ApplyStarColors +8056da88 Kart::BodyBike::vf_0x2c +8056dadc Kart::BodyBike::vf_0x30 +8056db30 Kart::BodyBike::UpdateModelDrawPriority +8056db98 Kart::BodyQuacker::__ct +8056dc3c Kart::BodyBike::__dt +8056dc7c Kart::BodyQuacker::GetMatrix +8056dcdc Kart::BodyQuacker::UpdateMatrix +8056dd9c Kart::Body::SetHandleDistance +8056dda4 Kart::Body::SetFloat_0x98 +8056ddac Kart::BodyQuacker::__dt +8056ddec Kart::Part::vf_0x24 +8056de14 Kart::BodyKart::__dt +8056de54 Kart::Arm::__dt +8056de94 0x8056de94 +8056de9c 0x8056de9c +8056dea4 0x8056dea4 +8056deac 0x8056deac +8056deb4 0x8056deb4 +8056debc 0x8056debc +8056dec4 0x8056dec4 +8056decc 0x8056decc +8056ded4 0x8056ded4 +8056dedc 0x8056dedc +8056dee4 0x8056dee4 +8056deec Kart::Collision::__ct +8056df64 0x8056df64 +8056dfa4 Kart::Collision::Reset +8056e08c 0x8056e08c +8056e0e4 Kart::Collision::ProcessVehicleBodyCollision +8056e254 Kart::Collision::ProcessWheelCollision +8056e2b0 Kart::Collision::ProcessMovingRoad +8056e384 Kart::Collision::ProcessFloor +8056e7a4 0x8056e7a4 +8056e874 0x8056e874 +8056eb04 0x8056eb04 +8056ebec 0x8056ebec +8056ee10 0x8056ee10 +8056ee90 Kart::Collision::ProcessTriggers +8056f0bc 0x8056f0bc +8056f170 Kart::Collision::CheckKartCollision +805706a0 Kart::Movement::vf_0x30 +805706a4 0x805706a4 +80570728 0x80570728 +80570bb4 0x80570bb4 +80570d38 0x80570d38 +80570d58 0x80570d58 +80570d7c 0x80570d7c +80570e04 0x80570e04 +80570ef0 0x80570ef0 +80570f74 0x80570f74 +80570fb4 Kart::Collision::CheckTriggersAndOOB +80571254 0x80571254 +805715dc 0x805715dc +80571684 0x80571684 +80571718 0x80571718 +80571890 Kart::Collision::CheckObjectCollision +80571ec4 0x80571ec4 +80571ef4 Object::GetId +80571efc Kart::Collision::CheckItemCollision +80572514 0x80572514 +805725a0 Kart::Collision::UpdateCollisions +805728cc 0x805728cc +80572a54 Kart::Collision::InitHitboxes +80572af0 Kart::Collision::HandleNoopCollision +80572af8 Kart::Collision::HandleBananaCollision +80572b10 Kart::Collision::HandleShellCollision +80572b30 Kart::Collision::HandleBlueShellCollision +80572b48 Kart::Collision::HandleBombCollision +80572b60 Kart::Collision::HandleMushroomCollision +80572ba4 Kart::Collision::HandleStarCollision +80572bdc Kart::Collision::HandleFibCollision +80572d44 0x80572d44 +80572d4c 0x80572d4c +80572d54 0x80572d54 +80572d5c 0x80572d5c +80572d64 0x80572d64 +80572d6c 0x80572d6c +80572d74 0x80572d74 +80572de4 0x80572de4 +80572e98 ObjectCollidable::GetCollision +80572ea0 0x80572ea0 +80572ebc 0x80572ebc +80572f2c 0x80572f2c +80572f34 0x80572f34 +80572f3c 0x80572f3c +80572f54 0x80572f54 +80572f5c 0x80572f5c +80572f64 0x80572f64 +80572f6c 0x80572f6c +80572fbc 0x80572fbc +80573048 0x80573048 +805730d4 0x805730d4 +80573110 0x80573110 +80573138 0x80573138 +805731a4 0x805731a4 +805733ac 0x805733ac +80573480 Kart::Collision::ActivateOOB +80573844 0x80573844 +80573854 Kart::Collision::UpdateRespawn +80573970 Kart::Collision::__dt +805739b0 0x805739b0 +805739e8 0x805739e8 +80573a88 0x80573a88 +80573a94 Kart::Zipper::__ct +80573af0 Kart::Zipper::__dt +80573b30 0x80573b30 +80573b48 0x80573b48 +80573b90 0x80573b90 +80573c74 0x80573c74 +80573cc0 Kart::Zipper::Update +805745fc Vec3::RotateQuaternionConjugate +80574610 0x80574610 +805747e0 0x805747e0 +80574a4c 0x80574a4c +80574c68 0x80574c68 +80575224 Kart::Zipper::End +80575264 0x80575264 +805753c4 Kart::Trick::__ct +80575428 Kart::Trick::__dt +80575468 Kart::Trick::Reset +805754b8 Kart::Trick::UpdateNext +805755ec 0x805755ec +805756d0 0x805756d0 +805756e4 0x805756e4 +805756fc Kart::Trick::TryStart +80575868 Kart::Trick::Start +80575998 0x80575998 +805759f8 0x805759f8 +80575abc 0x80575abc +80575aec Kart::Trick::StartInner +80575bb0 0x80575bb0 +80575d64 Kart::Trick::Update +80575de0 Kart::Trick::SetupProperties +80575e7c Kart::Trick::UpdateRot +80575f98 0x80575f98 +80576004 0x80576004 +80576038 Kart::Trick::End +805760c4 0x805760c4 +805760d8 Kart::TrickBike::Start +8057621c Kart::TrickBike::StartInner +80576314 Kart::TrickBike::UpdateRot +8057647c Kart::TrickBike::__ct +805764bc Kart::BRRESHandle::__ct +805765d4 Kart::BRRESHandle::__dt +80576614 0x80576614 +80576690 0x80576690 +8057670c Kart::BRRESHandle::LoadKartBRRES +80576810 Kart::BRRESHandle::LoadDriverBRRES +805768ac 0x805768ac +80576968 0x80576968 +805769e4 Kart::BRRESHandle::LoadBodyModel +80576ba0 0x80576ba0 +80576c58 0x80576c58 +80576c70 Kart::BRRESHandle::LoadLeftBackWheelModel +80576d28 Kart::BRRESHandle::LoadLeftFrontWheelModel +80576de0 Kart::BRRESHandle::LoadRightBackWheelModel +80576e98 Kart::BRRESHandle::LoadRightFrontWheelModel +80576f50 0x80576f50 +80577054 Kart::BRRESHandle::LoadArmModel +8057722c Kart::BRRESHandle::LoadDriverModels +8057729c Kart::BRRESHandle::LoadBikeHandleModel +80577364 Kart::BRRESHandle::LoadBikeSwingArmModel +8057741c Kart::BRRESHandle::LoadBikeFrontWheelModel +805774d4 Kart::BRRESHandle::LoadBikeBackWheelModel +8057758c Kart::BRRESHandle::LoadBikeSuspensionsModel +80577644 0x80577644 +805776fc Kart::BRRESHandle::LoadShadowModel +80577780 Kart::BRRESHandle::LoadKillerModels +80577880 0x80577880 +80577924 0x80577924 +80577944 Kart::Movement::__ct +80577a9c Kart::Boost::__dt +80577adc 0x80577adc +80577b1c 0x80577b1c +80577b5c 0x80577b5c +80577b9c Kart::Movement::CreateTrickZipper +80577c1c Kart::Movement::SetTurnParams +80577e54 Kart::Movement::Reset +8057825c Kart::Movement::Update +805792e0 0x805792e0 +805792e8 Kart::Movement::UpdateHopPhysics +8057932c Kart::Movement::Respawn +805793d0 0x805793d0 +80579664 0x80579664 +80579728 0x80579728 +805798a0 0x805798a0 +805798ec 0x805798ec +80579964 Kart::Movement::SomethingWheelieBump +80579abc 0x80579abc +80579ac0 Kart::Movement::UpdateDir +8057a234 Kart::Movement::UpdateTurn +8057a4e8 Kart::Movement::UpdateVehicleSpeed +8057a9a8 0x8057a9a8 +8057aa88 Kart::Movement::ComputeWallCollisionSpeedFactor +8057ac1c Kart::Movement::vf_0x68 +8057ac20 0x8057ac20 +8057b0fc 0x8057b0fc +8057b1e8 Kart::Movement::GetAccelerationFromSpeed +8057b31c Kart::Movement::ResetBulletSpeed +8057b32c Kart::Movement::ResetMaxSpeed +8057b33c Kart::Movement::UpdateAcceleration +8057bd48 Kart::Movement::GetWheelieSoftSpeedLimitBonus +8057bd54 Kart::Movement::UpdateOffroad +8057bf68 0x8057bf68 +8057c01c Kart::Movement::UpdateRotate +8057c754 0x8057c754 +8057c88c Kart::Movement::UpdateVehicleRotationVector +8057cb54 Kart::Movement::UpdateSSMTRotation +8057cd18 Kart::Movement::UpdateUps +8057d208 Kart::Movement::UpdateUpsWhileAirbone +8057d398 Kart::Movement::CheckIfCanHop +8057d3dc Kart::Movement::Hop +8057d5c0 Kart::Movement::CancelWheelie +8057d5c4 Kart::Movement::UpdateManualDrift +8057da5c Kart::Movement::UpdateAutoDrift +8057dcc8 0x8057dcc8 +8057dd74 Kart::Movement::StartManualDrift +8057dfb8 0x8057dfb8 +8057e074 0x8057e074 +8057e0fc 0x8057e0fc +8057e184 Kart::Movement::UpdateHopAndSlipdrift +8057e31c 0x8057e31c +8057e3d0 0x8057e3d0 +8057e414 0x8057e414 +8057e438 0x8057e438 +8057e5a8 0x8057e5a8 +8057e6a0 0x8057e6a0 +8057e6b4 0x8057e6b4 +8057e70c 0x8057e70c +8057e7d0 Kart::Movement::UpdateMTCharge +8057e960 Kart::Movement::GetMTMaxCharge +8057e96c Kart::Movement::GetSMTMaxCharge +8057e978 0x8057e978 +8057e9a4 0x8057e9a4 +8057e9dc 0x8057e9dc +8057ea10 0x8057ea10 +8057eb50 0x8057eb50 +8057ed58 Kart::Movement::ActivateMushroom +8057efb0 0x8057efb0 +8057f128 Kart::Movement::EndTrick +8057f2ec Kart::Movement::ActivateZipperBoost +8057f4ec 0x8057f4ec +8057f698 Kart::Movement::TryStartJumpPad +8057fa3c 0x8057fa3c +8057fbe8 Kart::Movement::ActivateStar +8057fd70 0x8057fd70 +8057fdb8 Kart::Movement::ApplyShock +8057fe9c 0x8057fe9c +8057ff6c 0x8057ff6c +8057ffc8 0x8057ffc8 +80580024 0x80580024 +805800e8 0x805800e8 +805800f8 Kart::Movement::ApplyShockEffect +80580318 0x80580318 +80580404 0x80580404 +80580494 Kart::Movement::ActivateMega +8058065c 0x8058065c +80580740 0x80580740 +805808a8 0x805808a8 +8058091c 0x8058091c +805809b4 0x805809b4 +80580a28 0x80580a28 +80580d24 0x80580d24 +80580d68 0x80580d68 +80580f8c Kart::Movement::UpdateScale +805810a0 Kart::Movement::SetScale +805810bc 0x805810bc +805810f8 0x805810f8 +805811a4 Kart::Movement::CalcBlink +805812ec 0x805812ec +80581328 0x80581328 +805813a4 0x805813a4 +805813a8 Kart::Movement::ActivateTC +805813c0 Kart::Movement::DeactivateTC +805813d8 Kart::Movement::ApplyInk +8058149c Kart::Movement::UpdateCharacterInk +805815f0 0x805815f0 +80581610 Kart::Movement::SomethingRespawnBoost +80581aac Kart::Movement::ApplyStartBoost +80581bf8 0x80581bf8 +80581d24 0x80581d24 +80581e08 0x80581e08 +80581e48 0x80581e48 +80581e70 0x80581e70 +80581eb0 Kart::Movement::TryEndJumpPad +80582014 Kart::Movement::UpdateBoost +80582184 0x80582184 +8058224c 0x8058224c +80582714 0x80582714 +80582734 0x80582734 +80582758 0x80582758 +805827b4 0x805827b4 +805828b8 0x805828b8 +805828d8 0x805828d8 +805828fc 0x805828fc +8058291c Kart::Movement::ReleaseMT +80582bfc 0x80582bfc +80582c44 0x80582c44 +80582c64 Kart::Movement::CancelBoost +80582da4 0x80582da4 +80582e0c Kart::Movement::vf_0x24 +80582fd8 Kart::Movement::OnOOB +8058314c Kart::Movement::vf_0x2c +80583504 0x80583504 +80583508 Kart::Movement::UpdateStickyRoad +805838ac 0x805838ac +805839c4 Kart::Movement::SetInitialPhysicsValues +80583cb4 Kart::Movement::DoRespawn +80583fc8 0x80583fc8 +805840bc 0x805840bc +805842a8 thunk_0x8058473c +805842ac thunk_0x8058473c +805842b0 0x805842b0 +8058430c Kart::Movement::EnterCannon +805846d8 Kart::Movement::UpdateCannon +80584c48 0x80584c48 +80584d1c Kart::Movement::GetCannonPosAndDir +80584f3c 0x80584f3c +8058522c Kart::Movement::ActivateBullet +80585384 0x80585384 +805853a8 0x805853a8 +805853e0 0x805853e0 +80585420 0x80585420 +80585468 0x80585468 +80585478 0x80585478 +80585a3c 0x80585a3c +805860fc Kart::Movement::UpdateFromPseaVenice +8058635c Kart::Movement::UpdateDiving +80586698 0x80586698 +80586734 0x80586734 +80586810 0x80586810 +80586928 Kart::Movement::UpdateSlipStream +80586e40 0x80586e40 +80586f0c Kart::Movement::UpdateWheelie +80586f10 Kart::Movement::UpdateSpecialFloor +805872b8 0x805872b8 +80587324 0x80587324 +805874b0 Kart::MovementBike::__ct +805874f8 Kart::Movement::__dt +80587538 Kart::MovementBike::CreateTrickZipper +805875d4 Kart::MovementBike::SetTurnParams +80587680 Kart::MovementBike::Reset +805876e4 Kart::MovementBike::UpdateWheelie +805876e8 Kart::MovementBike::UpdateVehicleRotationVector +80587ca4 Kart::MovementBike::GetWheelieSoftSpeedLimitBonus +80587cd0 Kart::MovementBike::StartWheelie +80587d44 Kart::MovementBike::CancelWheelie2 +80587d74 Kart::MovementBike::UpdateWheelie +80588118 Kart::MovementBike::TryStartWheelie +805881e0 0x805881e0 +80588208 Kart::MovementBike::UpdateMtCharge +805882d0 Kart::MovementBike::vf_0x24 +805884b0 Kart::MovementBike::CancelWheelie +805884d8 Kart::MovementBike::OnOoB +8058862c Kart::MovementBike::vf_0x2c +805886a8 Kart::Boost::__ct +805886f4 Kart::Boost::Reset +80588730 Kart::Boost::Activate +80588798 Kart::Boost::CancelAll +805887a4 Kart::Boost::Update +80588940 Kart::MovementBike::vf_0x30 +80588950 Kart::MovementBike::vf_0x68 +80588960 Kart::MovementBike::CheckWheelie +805889a4 Kart::Movement::GetStarDuration +805889b0 0x805889b0 +805889dc 0x805889dc +80588a30 0x80588a30 +80588a98 0x80588a98 +80588b40 0x80588b40 +80588b8c 0x80588b8c +80588bb0 0x80588bb0 +80588bd4 0x80588bd4 +80588bec 0x80588bec +80588c88 0x80588c88 +80588d7c 0x80588d7c +80588d80 Kart::MovementRealLocal::Hop +80588dc0 Kart::MovementBikeRealLocal::Hop +80588e00 Kart::MovementBikeRealLocal::StartWheelie +80588e94 Kart::MovementBikeRealLocal::CancelWheelie2 +80588eec Kart::MovementRemote::CanHop +80588f4c Kart::MovementBikeRemote::CanHop +80588fac Kart::MovementBikeRemote::TryStartWheelie +80589038 Kart::Movement::vf_0x58 +8058903c Kart::MovementBike::GetLeanRot +80589044 Kart::MovementBikeRemote::__dt +80589084 Kart::MovementBike::__dt +805890c4 Kart::Movement::CheckWheelie +805890cc Kart::Movement::GetLeanRot +805890d8 Kart::MovementRemote::__dt +80589118 Kart::MovementBikeRealLocal::__dt +80589158 Kart::MovementRealLocal::__dt +80589198 0x80589198 +805891b0 0x805891b0 +805891c4 0x805891c4 +805891dc RacedataHandler_consstruct +80589264 0x80589264 +805892a4 0x805892a4 +805892e4 0x805892e4 +8058930c 0x8058930c +805898e4 0x805898e4 +8058a0f4 0x8058a0f4 +8058a134 0x8058a134 +8058a174 0x8058a174 +8058a1b4 0x8058a1b4 +8058a1f4 0x8058a1f4 +8058a234 0x8058a234 +8058a274 0x8058a274 +8058a2b4 0x8058a2b4 +8058a2f4 0x8058a2f4 +8058a334 0x8058a334 +8058a374 0x8058a374 +8058a3b4 0x8058a3b4 +8058a3f4 0x8058a3f4 +8058a434 0x8058a434 +8058a474 0x8058a474 +8058a4b4 0x8058a4b4 +8058a4f4 0x8058a4f4 +8058a534 0x8058a534 +8058a588 0x8058a588 +8058a5dc 0x8058a5dc +8058a630 0x8058a630 +8058a684 0x8058a684 +8058a6d8 0x8058a6d8 +8058a758 0x8058a758 +8058a760 0x8058a760 +8058a7c8 0x8058a7c8 +8058a7d0 0x8058a7d0 +8058a838 0x8058a838 +8058a840 0x8058a840 +8058a8a8 0x8058a8a8 +8058a8b0 0x8058a8b0 +8058a918 0x8058a918 +8058a920 0x8058a920 +8058a988 0x8058a988 +8058a990 0x8058a990 +8058a9f8 0x8058a9f8 +8058aa00 0x8058aa00 +8058aa68 0x8058aa68 +8058aa70 0x8058aa70 +8058aa8c 0x8058aa8c +8058aaa8 0x8058aaa8 +8058aac4 0x8058aac4 +8058ab18 RacedataHandler_processInputs +8058ae14 0x8058ae14 +8058b228 0x8058b228 +8058b378 0x8058b378 +8058b760 Audio::KartActor::Reset +8058b7a0 0x8058b7a0 +8058ba08 0x8058ba08 +8058ba0c 0x8058ba0c +8058ba5c 0x8058ba5c +8058bd58 0x8058bd58 +8058be10 0x8058be10 +8058be40 0x8058be40 +8058bf64 0x8058bf64 +8058bf94 0x8058bf94 +8058bf9c 0x8058bf9c +8058bfcc 0x8058bfcc +8058bfd4 0x8058bfd4 +8058c004 0x8058c004 +8058c00c 0x8058c00c +8058c03c 0x8058c03c +8058c044 0x8058c044 +8058c074 0x8058c074 +8058c07c 0x8058c07c +8058c0e0 0x8058c0e0 +8058c144 0x8058c144 +8058c1a8 0x8058c1a8 +8058c20c 0x8058c20c +8058c270 0x8058c270 +8058c2d4 0x8058c2d4 +8058c338 0x8058c338 +8058c3a8 RacedataFactory_construct +8058c3f4 0x8058c3f4 +8058c434 0x8058c434 +8058c438 0x8058c438 +8058c43c RacedataFactory_sendRacedataRecord +8058c4b0 RacedataFactory_packRacedataRecord +8058cd4c RacedataFactoryFlags_construct +8058cd94 RacedataFactoryFlags_destroy +8058cdd4 0x8058cdd4 +8058cde4 0x8058cde4 +8058cdfc 0x8058cdfc +8058ce20 0x8058ce20 +8058ce5c 0x8058ce5c +8058ce9c 0x8058ce9c +8058cea0 0x8058cea0 +8058cef0 0x8058cef0 +8058cfc4 0x8058cfc4 +8058d158 0x8058d158 +8058d228 0x8058d228 +8058d258 0x8058d258 +8058d288 0x8058d288 +8058d2bc 0x8058d2bc +8058d2e0 0x8058d2e0 +8058d304 0x8058d304 +8058d328 0x8058d328 +8058d3ac 0x8058d3ac +8058d3d0 0x8058d3d0 +8058d424 0x8058d424 +8058d460 0x8058d460 +8058d4b0 0x8058d4b0 +8058d4d4 0x8058d4d4 +8058d55c 0x8058d55c +8058d58c 0x8058d58c +8058d5cc 0x8058d5cc +8058d5d8 0x8058d5d8 +8058d61c 0x8058d61c +8058d660 0x8058d660 +8058d6a4 0x8058d6a4 +8058d6e0 0x8058d6e0 +8058d73c Kart::Player::__ct +8058d830 0x8058d830 +8058d870 Kart::Player::__dt +8058d8e0 0x8058d8e0 +8058d8fc 0x8058d8fc +8058d994 0x8058d994 +8058db08 Kart::Player::InitSub +8058dbac Kart::Player::Init +8058df78 Kart::Player::CreateBody +8058dfc8 0x8058dfc8 +8058e0a4 0x8058e0a4 +8058e144 0x8058e144 +8058e184 Kart::Player::PrepateTiresAndSUspensions +8058e310 0x8058e310 +8058e38c Kart::Player::InitWheels +8058e588 Kart::Wheel::__dt +8058e5c8 0x8058e5c8 +8058e660 Kart::Player::CreateSound +8058e6a8 0x8058e6a8 +8058e6e8 0x8058e6e8 +8058e7c8 Kart::Player::SetStartPosition +8058e834 Kart::Player::UpdateKartSub +8058e83c Kart::Player::Update2 +8058e9cc 0x8058e9cc +8058eb74 Kart::Wheel::vf_0x24 +8058eb8c 0x8058eb8c +8058ebe0 Kart::PlayerBike::CreateBody +8058ec68 Kart::PlayerBike::InitWheels +8058ee2c Kart::WheelFront::__dt +8058ee6c Kart::WheelBikeFront::__dt +8058eeac Kart::Suspensions::__dt +8058eeec Kart::PlayerBike::CreateSound +8058ef34 Kart::Manager::SetupPlayer +8058f1a0 Kart::Player::CreateModel +8058f230 Kart::PlayerBike::__dt +8058f2a4 0x8058f2a4 +8058f310 0x8058f310 +8058f350 0x8058f350 +8058f390 Kart::Manager::Disposer__dt +8058f428 Kart::Manager::CreateInstance +8058f478 Kart::Manager::DestroyInstance +8058f4ac Kart::Manager::__ct +8058f754 Kart::Manager::__dt +8058f860 Kart::Manager::Init +8058f968 Kart::Manager::Update +8058fa80 Kart::Manager::GetKartPlayer +8058fa90 0x8058fa90 +8058faa8 Kart::Link::InitList +8058fab8 Kart::Link::LinkKartList +8058fb0c Kart::Link::__ct +8058fb50 Kart::Link::SetPointersFromPlayer +8058fb8c Kart::Link::GetKartPosition +8058fba4 Kart::Player::GetPreviousPosition +8058fbb8 Kart::Link::SetKartPosition +8058fbe4 Kart::Link::GetMtx +8058fbf8 Kart::Link::GetKartBodyMtx +8058fc08 Kart::Link::SetKartRotation +8058fc5c Kart::Link::GetWheelCount0 +8058fc6c Kart::Link::GetWheelCount1 +8058fc7c Kart::Link::GetWheelCountReciprocal +8058fc8c Kart::Link::GetWheelCountPlus1Reciprocal +8058fc9c Kart::Link::GetWheelPosition +8058fcb8 Kart::Link::WheelHasFloorCollision +8058fcd0 Kart::Link::SetBody0x94 +8058fce8 Kart::Link::SetBodyHandleDistance +8058fd00 Kart::Link::SetStartBoost +8058fd10 Kart::Link::GetWheelSpeed +8058fd2c Kart::Link::GetPhysicsHolder +8058fd3c Kart::Link::GetPhysicsHolder(const) +8058fd4c Kart::Link::GetPhysics +8058fd60 Kart::Link::GetPhysics(const) +8058fd74 Kart::Link::GetControllerHolder +8058fd9c Kart::Link::ActivateRumble(3 args) +8058fdf8 Kart::Link::ActivateRumble(1 arg) +8058fef0 Kart::Link::ActivateRumble(no arg) +8058ffd0 Kart::Link::IsLocal +8058ffe4 Kart::Link::IsCPU +8058fff8 Kart::Link::IsGhost +8059000c Kart::Link::IsMii +8059001c Kart::Link::GetBody +80590028 Kart::Link::GetBody(const) +80590034 Kart::Link::GetSuspensions +80590048 Kart::Link::GetSuspensions(const) +8059005c Kart::Link::GetWheels +80590070 Kart::Link::GetWheels(const) +80590084 Kart::Link::GetWheelPhysicsHolder +8059009c Kart::Link::GetWheelPhysicsHolder(const) +805900b4 Kart::Link::GetWheelPhysics +805900cc Kart::Link::GetWheelPhysics(const) +805900e4 Kart::Link::GetSub +805900f0 Kart::Link::GetSub(const) +805900fc Kart::Link::GetMovement +80590108 Kart::Link::GetMovement(const) +80590114 Kart::Link::GetKartActor +80590120 Kart::Link::GetCharacterActor +80590130 Kart::Link::PlayCharacterSound +80590140 Kart::Link::GetObject +8059014c Kart::Link::GetShadow +80590158 Kart::Link::GetPhysicsHolderHitboxGroup +8059016c Kart::Link::GetPhysicsHolderHitboxGroup(const) +80590180 Kart::Link::GetWheelPhysicsHitboxGroup +8059019c Kart::Link::GetVehicleBodyCollisionData +805901b4 Kart::Link::GetWheelCollisionData +805901cc Kart::Link::GetCollision +805901d8 Kart::Link::GetCollision(const) +805901e4 Kart::Link::GetStatsAndBsp +805901f4 Kart::Link::GetStats +80590208 Kart::Link::GetBsp +8059021c Kart::Link::GetBspHitboxes +80590234 Kart::Link::GetBspWheel +80590254 Kart::Link::GetValues0x18 +80590264 Kart::Link::GetKartDriverDispEntry +80590274 Kart::Link::GetRotatingItemsParams +8059028c Kart::Link::GetKartPartsDispEntry +8059029c Kart::Link::GetBikePartsDispEntry +805902ac Kart::Link::GetExhaustParticleSet2 +805902d8 Kart::Link::GetExhaustParticleSet +8059030c Kart::Link::GetBalloonsPosition +80590338 Kart::Link::GetDriverDispEntry +80590348 Kart::Link::GetCameraVerticalDistance +80590374 Kart::Link::GetBaseHopStickX +80590384 Kart::Link::GetHopStickX +80590390 Kart::Link::GetType +805903a8 Kart::Link::GetStatsWheelCount +805903c0 Kart::Link::GetDriverController +805903cc Kart::Link::GetTriggersCollisionRadius +805903dc Kart::Link::GetPlayerIdx +805903ec Kart::Link::IsBike +805903fc Kart::Link::GetKartId +8059040c Kart::Link::ToggleKartVisible +8059041c Kart::Link::ToggleVisible +805905c4 Kart::Link::GetBodyMatCol0(copy) +805905ec Kart::Link::GetBodyMatCol1(copy) +80590614 Kart::Link::GetBodyMatCol2(copy) +8059063c Kart::Link::GetBodyMatCol0 +80590650 Kart::Link::GetBodyMatCol1 +80590664 Kart::Link::GetBodyMatCol2 +80590678 Kart::Link::GetEngineSpeed +80590688 Kart::Link::GetSpeed +805906a0 Kart::Link::GetDamage +805906ac Kart::Link::GetDamage(const) +805906b8 Kart::Link::80590d38 +805906dc Kart::Link::SetDamageType +80590708 Kart::Link::SetAffectedByPOW +80590714 Kart::Link::80590d94 +80590724 Kart::Link::GetCurDamageType +80590734 Kart::Link::CancelBoost +80590740 Kart::Link::GetSpeedRatioCapped +80590750 Kart::Link::GetSpeedRatio +80590760 Kart::Link::HasCamera +80590778 Kart::Link::SetCamera +80590784 Kart::Link::GetScreenIdx +805907a8 Kart::Link::UpdateCameraOnRespawn +805907c0 Kart::Link::UpdateCameraOnBoost +805907d8 Kart::Link::ResetCameraFov +805907f0 Kart::Link::UpdateCameraOnExplosion +80590808 Kart::Link::80590e88 +8059080c Kart::Link::80590e8c +80590824 Kart::Link::80590ea4 +80590858 Kart::Link::StopCloseCamera +80590878 Kart::Link::SetCamera +80590898 Kart::Link::StopCameraMovAndRotation +805908b8 Kart::Link::80590f38 +805908d8 Kart::Link::80590f58 +805908f0 Kart::Link::UpdateCameraOnOOBHit +80590910 Kart::Link::ActivateStarAnm +8059091c Kart::Link::80590f9c +805909ac Kart::Link::UpdateStarAnm +805909b8 Kart::Link::StopStarAnm +805909c4 Kart::Link::80591044 +805909d0 Kart::Link::80591050 +805909f0 Kart::Link::GetStarAnm +805909fc Kart::Link::GetStarColor +80590a0c Kart::Link::GetModelsVisibility +80590a18 Kart::Link::GetModelsVisibility +80590a24 Kart::Link::GetMatTEVHandler +80590a30 Kart::Link::GetBaseSpeed +80590a40 Kart::Link::GetAIController +80590a4c Kart::Link::GetBodyClosestFloorFlags +80590a64 Kart::Link::GetBodyClosestFloorSettings +80590a7c Kart::Link::IsWheelHittingWall +80590ab8 Kart::Link::GetClosestFloorKCLFlags +80590af0 Kart::Link::GetClosestFloorKCLSettingss +80590b28 Kart::Link::GetBodyKCLIntensity +80590b40 Kart::Link::805911c0 +80590b58 Kart::Link::GetDriftState +80590b68 Kart::Link::GetMTCharge +80590b78 Kart::Link::GetSMTCharge +80590b88 Kart::Link::GetMTMaxCharge +80590b94 Kart::Link::GetSMTMaxCharge +80590ba0 Kart::Link::TranslateBody +80590be4 Kart::Link::80591264 +80590c94 Kart::Link::IsRespawning +80590cc4 Kart::Link::80591344 +80590cf8 Kart::Link::80591378 +80590d28 Kart::Link::805913a8 +80590d7c Kart::Link::IsWaitingForBackwards +80590d98 Kart::Link::GetBackwardsAllowCounter +80590da8 Kart::Link::Get1stLight +80590db4 Kart::Link::Get2ndLight +80590dc0 Kart::Link::GetRacedataFactory +80590dcc Kart::Link::GetRacedataHandler +80590dd8 Kart::Link::GetRacedataFactoryFlags +80590de8 Kart::Link::80591468 +80590df8 Kart::Link::SetScale +80590e3c Kart::Link::GetScale +80590e4c Kart::Link::IsWheelieing +80590e64 Kart::Link::GetStartBoostCharge +80590e74 Kart::Link::805914f4 +80590ea0 Kart::Link::GetEntity +80590eac Kart::Link::GetClipInfo +80590eb8 Kart::Link::CallOnAllPartsFunc +80590f88 Kart::Link::AreKartModelsVisible +80590f98 Kart::Link::GetKiller +80590fa4 Kart::Link::GetBillViewMtx +80590fe4 Kart::Link::ResetInertia +8059108c Kart::Link::8059170c +80591104 Kart::Link::StartOobWipe +80591120 Kart::Link::GetOobWipeState +80591130 Kart::Link::805917b0 +80591140 Kart::Link::805917c0 +80591174 Kart::Link::805917f4 +805911a8 Kart::Link::80591828 +805911cc Kart::Link::8059184c +80591218 Kart::Link::80591898 +8059123c Kart::Link::IncrementItemsHitCount +80591260 Kart::Link::IncrementItemsCollisionCount +80591284 Kart::Link::GetZipper +80591294 Kart::Link::GetTrick +805912a4 Kart::Link::InitLights +805912fc Kart::Link::SetLightObjIdx +80591318 0x80591318 +80591368 0x80591368 +80591374 Kart::InitParamBinsFromCommon +805914f4 Kart::InitParamBinsFromRace +8059161c Kart::ResetParamBins +80591668 Kart::GetParamBinFromCommon +80591680 Kart::GetParamBinFromRace +805916cc Kart::GetParamBin +8059173c Kart::GetBSP +80591750 Kart::LoadKartAndDriverParamBinsFromCommon +805917d8 Kart::LoadKartParamBinFromCommon +80591828 Kart::LoadDriverParamBinFromCommon +80591878 Kart::LoadStatsParamFileFromCommon +805918cc Kart::GetKartParamEntry +805918e0 Kart::GetDriverParamEntry +80591924 Kart::ComputeStats +80591d8c Kart::LoadKartDriverDisp +80591e18 Kart::GetKartDriverDispEntry +80591e4c Kart::LoadKartPartsDisp +80591ed8 Kart::GetKartPartsDispEntry +80591f14 Kart::LoadBikePartsDisp +80591fa0 Kart::GetBikePartsDispEntry +80591fe0 Kart::SetMiiDispParam +80591ff8 Kart::LoadMiiDisp +80592048 Kart::LoadMiiDispFromMiiBody +80592098 Kart::LoadCameraParam +805920dc Kart::LoadDriverDisp +8059212c Kart::GetMiiDispEntry +80592140 Kart::GetDriverDispEntry +80592154 Kart::Link::GetCameraParamBin +805921c8 Kart::Part::__ct +8059225c 0x8059225c +805922a0 Kart::Part::CreateModelDirectors +805923a8 Kart::Part::LoadModel +805923b0 Kart::Part::Create2ndModelDirector +805924d4 Kart::Part::Load +805924e4 Kart::Part::UpdateMatrix +80592578 0x80592578 +8059263c Kart::Part::vf_0xC +8059265c Kart::Part::SetModelScale +80592684 Kart::Part::SetModelMtx +80592708 Kart::Part::ToggleModelVisible +80592730 Kart::Part::vf_0x20 +80592764 0x80592764 +80592778 Kart::Part::ApplyStarColors +805927dc Kart::Part::vf_0x2c +80592860 Kart::Part::vf_0x30 +805928cc Kart::Part::UpdateModelDrawPriority +80592928 0x80592928 +80592940 Kart::Values::__ct +80592a0c 0x80592a0c +80592a64 0x80592a64 +80592aa4 0x80592aa4 +80592aa8 0x80592aa8 +80592ab8 0x80592ab8 +80592c90 0x80592c90 +80592ddc 0x80592ddc +805930fc 0x805930fc +80593154 0x80593154 +80593194 0x80593194 +805935a0 0x805935a0 +805935f8 0x805935f8 +80593638 0x80593638 +8059368c 0x8059368c +8059369c 0x8059369c +805936d4 0x805936d4 +8059373c 0x8059373c +80593788 0x80593788 +80593798 0x80593798 +80593924 0x80593924 +80593a14 0x80593a14 +80593a54 0x80593a54 +80593ab4 0x80593ab4 +80593b3c 0x80593b3c +80593d34 Kart::Status::__ct +80593edc Kart::Status::Reset +80593f14 Kart::Status::Init +80593fb4 0x80593fb4 +80593fc4 0x80593fc4 +80594084 0x80594084 +805940cc Kart::Status::UpdateCollisionsAndMore +805941fc Kart::Status::UpdateFromInput +80594554 Kart::Status::UpdateCollisions +8059526c 0x8059526c +80595270 0x80595270 +80595298 Kart::Status::UpdateStartBoostCharge +80595354 Kart::Status::ComputeStartBoost +80595478 Kart::Status::ApplyStartBoost +805955dc 0x805955dc +80595624 0x80595624 +80595634 0x80595634 +80595644 Kart::Status::__dt +80595684 0x80595684 +805956c8 Kart::Sub::Init +805958f8 Kart::Sub::InitParts +80595a7c 0x80595a7c +80595afc Kart::Sub::ResetPhysics +80595d64 0x80595d64 +80595dd4 Kart::Sub::SetPointers +80595e00 Kart::Sub::Update +8059667c Kart::Player::ApplyPhysics +805971bc Kart::Sub::UpdateTransforms +805972b4 0x805972b4 +8059736c 0x8059736c +805973c0 0x805973c0 +80597408 Kart::Sub::UpdateMovingRoad +805976cc Kart::Player::ApplyCollisionForce +80597a58 0x80597a58 +80597c0c Kart::Sub::InitEntity +80597cb8 0x80597cb8 +80597d5c 0x80597d5c +80597d74 0x80597d74 +80597d8c 0x80597d8c +80597fb0 0x80597fb0 +805980c4 0x805980c4 +80598210 0x80598210 +80598448 Kart::Sub::__dt +80598488 Kart::Suspensions::__ct +805984d0 Kart::Suspensions::LoadModel +805984e0 Kart::Suspensions::Init +80598554 Kart::Suspensions::InitPhysicsHolder +8059855c Kart::Suspensions::Reset +80598564 0x80598564 +8059856c Kart::Suspensions::UpdateMatrix +80598968 Kart::SuspensionsBike::LoadModel +80598978 Kart::SuspensionsBike::UpdateMatrix +80598aa4 0x80598aa4 +80598ab4 0x80598ab4 +80598d0c 0x80598d0c +80598d4c Kart::SuspensionsBike::__dt +80598d8c WheelPhysics::__ct +80598df0 WheelPhysics::InitHitboxGroup +80598e54 0x80598e54 +80598e88 WheelPhysics::Reset +80598f40 0x80598f40 +80599010 WheelPhysics::UpdateCollision +80599450 WheelPhysics::Realign +8059971c 0x8059971c +80599740 0x80599740 +8059982c WheelPhysics::HasFloorCollision +8059983c AnimatedModelExplodable_GetWorldMatrix +80599848 WheelPhysics::GetCollisionData +80599854 WheelPhysicsHolder::__ct +805998d4 WheelPhysicsHolder::Reset +80599920 0x80599920 +805999ac 0x805999ac +80599bf8 WheelPhysicsHolder::Update +80599e78 Vec3::MultMtxByVec +80599ef4 WheelPhysicsHolder::ApplySuspensions +8059a344 WheelPhysics::__dt +8059a384 0x8059a384 +8059a3c4 Kart::Wheel::__ct +8059a430 Kart::Wheel::Init +8059a494 Kart::Wheel::CreatePhysics +8059a4e8 0x8059a4e8 +8059a4f0 Kart::Wheel::LoadModel +8059a574 Kart::WheelFront::LoadModel +8059a59c Kart::WheelFront::CreatePhysics +8059a5f0 Kart::Wheel::UpdateMatrix +8059a7bc 0x8059a7bc +8059a84c Kart::WheelFront::UpdateMatrix +8059a9b8 Kart::WheelBikeFront::CreatePhysics +8059aa0c Kart::WheelBikeFront::LoadModel +8059aa1c Kart::WheelBikeFront::UpdateMatrix +8059ab7c Kart::WheelBikeRear::CreatePhysics +8059abd0 Kart::WheelBikeRear::LoadModel +8059abe0 Kart::WheelBikeRear::UpdateMatrix +8059ad38 0x8059ad38 +8059aea4 0x8059aea4 +8059aee4 Kart::WheelBikeRear::__dt +8059af24 0x8059af24 +8059af80 Kart::Killer::ModelCalc::ExecWorldCBImpl +8059afd8 Kart::Killer::__ct +8059b138 Kart::Killer::Activate +8059b5c4 Kart::Killer::Update +8059b80c Kart::Killer::Init +8059ba38 Kart::Killer::ToggleVisible +8059ba98 cancelBullet +8059bc1c 0x8059bc1c +8059bdcc 0x8059bdcc +8059c118 0x8059c118 +8059c1e8 0x8059c1e8 +8059c208 0x8059c208 +8059c2d4 0x8059c2d4 +8059c434 0x8059c434 +8059c4d4 0x8059c4d4 +8059c5e0 Kart::Killer::UpdateDuration +8059c7a4 0x8059c7a4 +8059c884 0x8059c884 +8059c944 0x8059c944 +8059ca04 0x8059ca04 +8059ca40 Kart::Killer::UpdateUps +8059cc38 0x8059cc38 +8059cc54 Kart::Killer::UpdateSettings +8059cdcc Kart::Killer::UpdateGravity +8059cf1c 0x8059cf1c +8059cfd8 0x8059cfd8 +8059d260 0x8059d260 +8059d2e4 0x8059d2e4 +8059d2fc 0x8059d2fc +8059d464 0x8059d464 +8059d65c 0x8059d65c +8059d81c Kart::Killer::__dt +8059d85c Kart::Killer::ModelCalc::__dt +8059d89c Kart::Killer::ModelCalc::__dt(thunk) +8059d8a4 MenuModelMgr::Disposer__dt +8059d93c MenuModelMgr::CreateInstance +8059d9cc MenuModelMgr::DestroyInstance +8059da00 MenuModelMgr::__ct +8059da64 MenuModelMgr::__dt +8059db7c MenuModelMgr::Start +8059dbd0 MenuModelMgr::Init +8059de28 MenuModelMgr::Update +8059de7c MenuModelMgr::Draw +8059ded0 MenuModelMgr::ResetKartModels +8059dee8 MenuModelMgr::RequestDriverModel +8059df00 MenuModelMgr::RequestKartModel +8059df18 MenuModelMgr::RequestBackModel +8059df24 MenuModelMgr::TogglePlayerModel +8059df3c 0x8059df3c +8059df54 MenuModelMgr::ToggleBackModel +8059df5c MenuModelMgr::GetTexObj +8059df70 0x8059df70 +8059df98 0x8059df98 +8059dfb4 MenuModelMgr::GetDriverTexture +8059dfc4 MenuModelMgr::GetKartTexture +8059e01c 0x8059e01c +8059e02c 0x8059e02c +8059e0ec ScnMgrMenu::__ct +8059e148 ScnMgrMenu::__dt +8059e1a0 ScnMgrMenu::UpdateCameras +8059e234 0x8059e234 +8059e244 ScnMgrMenu::LoadLights +8059e2a0 ScnMgrMenu::CreateScnGroup +8059e2f8 ScnMgrMenu::SetAnmScn +8059e30c ScnMgrMii::__ct +8059e364 ScnMgrMii::__dt +8059e3bc ScnMgrMii::LoadLights +8059e424 0x8059e424 +8059e460 0x8059e460 +8059e464 0x8059e464 +8059e514 0x8059e514 +8059e578 0x8059e578 +8059e5d0 0x8059e5d0 +8059e628 RendererMenu::__ct +8059e6b0 RendererMenu::Calc +8059e6e8 RendererMenu::DrawModels +8059ee70 MenuModel::vf_0x18 +8059ee88 RendererMenu::Draw +8059ef3c Kart::PhysicsHolder::Init +8059eff8 Kart::Physics::__dt +8059f038 0x8059f038 +8059f078 Kart::PhysicsHolder::__dt +8059f108 0x8059f108 +8059f148 Kart::PhysicsHolder::Reset +8059f2e8 Kart::PhysicsHolder::Update +8059f588 0x8059f588 +8059f5b0 0x8059f5b0 +8059f5c8 0x8059f5c8 +8059f68c 0x8059f68c +8059f750 0x8059f750 +8059f814 0x8059f814 +8059f8d8 0x8059f8d8 +8059f9d0 0x8059f9d0 +8059fa50 0x8059fa50 +8059facc 0x8059facc +8059fb4c 0x8059fb4c +8059fc38 0x8059fc38 +8059fcc0 Kart::PhysicsHolder::UpdateMat +8059fd44 0x8059fd44 +8059fd90 Kart::PhysicsHolder::ResetQuaternions +8059fe00 0x8059fe00 +8059fe20 Kart::PhysicsHolder::__ct +8059fed0 0x8059fed0 +8059ff20 AutoCameraMoverRace::__dt +8059ff60 CamMove::__dt +8059ffa0 0x8059ffa0 +8059ffe0 AutoCameraMover::__dt +805a0020 0x805a0020 +805a0060 0x805a0060 +805a01e8 0x805a01e8 +805a022c 0x805a022c +805a026c 0x805a026c +805a0270 0x805a0270 +805a039c 0x805a039c +805a043c 0x805a043c +805a04f0 0x805a04f0 +805a0594 0x805a0594 +805a0608 0x805a0608 +805a0780 0x805a0780 +805a084c 0x805a084c +805a0920 0x805a0920 +805a0b38 0x805a0b38 +805a0c9c 0x805a0c9c +805a0d40 0x805a0d40 +805a0da4 0x805a0da4 +805a0df8 AutoCameraMoverRace::vf_0x14 +805a0e00 AutoCameraMoverRace::vf_0x18 +805a0e08 0x805a0e08 +805a0e48 0x805a0e48 +805a0e88 0x805a0e88 +805a0ebc 0x805a0ebc +805a0ee0 0x805a0ee0 +805a0f60 0x805a0f60 +805a0fd0 0x805a0fd0 +805a10d0 0x805a10d0 +805a1160 0x805a1160 +805a11a0 0x805a11a0 +805a11e0 0x805a11e0 +805a11e4 CameraLink::__ct +805a123c GameCamera::__ct +805a1358 CameraLink::__dt +805a1398 GameCamera::Update +805a13b4 CameraMgr::__ct +805a13c4 CameraLink::InitCameraList +805a13e4 CameraMgr::SetInstance +805a13fc CameraLink::Register +805a140c 0x805a140c +805a1470 CameraLink::UpdateAllCameras +805a14f8 CameraMgr::Update +805a14fc CameraMgr::__dt +805a153c GameCamera::__dt +805a157c GameCamera::vf_0xC +805a1580 GameCamera::GetPosition +805a159c GameCamera::GetViewMatrix(const) +805a15a4 GameCamera::Update(thunk) +805a15ac GameCamera::vf_0xC(thunk) +805a15b4 GameCamera::__dt(thunk) +805a15bc GameCamValues::Reset +805a1674 RaceCamera::CopyVec(2vecs) +805a1690 RaceCamera::_ct +805a192c 0x805a192c +805a1930 Vec3::__ct(no args) +805a1934 0x805a1934 +805a1974 0x805a1974 +805a19b4 RaceCamera::Init +805a1b48 RaceCamera::GetCamParams +805a1b50 RaceCamera::Update +805a2488 0x805a2488 +805a24a0 RaceCamera::CopyVec(1vec) +805a24bc RaceCamera::CheckBitfield334 +805a24d4 0x805a24d4 +805a24dc RaceCamera::NegateVec +805a2504 0x805a2504 +805a25b4 0x805a25b4 +805a2614 RaceCamera::SubtractVecs +805a2648 RaceCamera::AddVecs(3vecs) +805a267c 0x805a267c +805a2960 RaceCamera::LinearTransfo(2vecs) +805a29a0 RaceCamera::DotVec +805a29d0 RaceCamera::CheckKartStatusField1 +805a29f0 0x805a29f0 +805a2c94 RaceCamera::CheckKartStatusField0 +805a2cb4 RaceCamera::IsAutomatic +805a2cc8 RaceCamera::ClampFloat +805a2cfc RaceCamera::AcosDeg +805a2de8 0x805a2de8 +805a2e30 RaceCamera::UpdateCamValues +805a37ac RaceCamera::CrossVec +805a37f8 RaceCamera::NormalizeAndGetNorm +805a37fc RaceCamera::CompareFloats +805a381c PSMTXMultVec +805a3820 RaceCamera::ScaleVec(2vecs) +805a3848 0x805a3848 +805a3850 0x805a3850 +805a3858 0x805a3858 +805a3860 0x805a3860 +805a3910 0x805a3910 +805a3944 RaceCamera::SubtractVecsPS +805a3968 RaceCamera::AddVecs(2vecs) +805a399c RaceCamera::ScaleVec(3vecs) +805a39c4 0x805a39c4 +805a39cc 0x805a39cc +805a3a0c 0x805a3a0c +805a3a14 RaceCamera::GetVecMag +805a3a18 RaceCamera::NormalizeVecPS +805a3a50 0x805a3a50 +805a3fbc 0x805a3fbc +805a4124 0x805a4124 +805a42b0 0x805a42b0 +805a433c RaceCamera::OnRespawn +805a4564 0x805a4564 +805a4588 0x805a4588 +805a465c RaceCamera::FlushPrevValues +805a4690 0x805a4690 +805a473c RaceCamera::OnBoost +805a475c RaceCamera::ResetAddedFov +805a476c RaceCamera::OnExplosion +805a47a0 0x805a47a0 +805a47b4 0x805a47b4 +805a4ec8 0x805a4ec8 +805a514c 0x805a514c +805a56b0 0x805a56b0 +805a56f0 RaceCamera::vf_0x50 +805a5f44 0x805a5f44 +805a5f78 0x805a5f78 +805a5fa8 0x805a5fa8 +805a6058 0x805a6058 +805a613c 0x805a613c +805a6200 0x805a6200 +805a6278 0x805a6278 +805a6438 0x805a6438 +805a6518 0x805a6518 +805a6584 0x805a6584 +805a65c8 0x805a65c8 +805a65d8 RaceCamera::GetViewMtx +805a674c 0x805a674c +805a6764 0x805a6764 +805a67b0 0x805a67b0 +805a67c0 BCPInfo::Load +805a6834 0x805a6834 +805a6884 0x805a6884 +805a68c4 OpeningPan::Load +805a6a20 OpeningPan::Init +805a6c5c 0x805a6c5c +805a6cd8 OpeningPan::Calc +805a6ee8 0x805a6ee8 +805a6f0c cPN_Feather_SetNodeWeight +805a6f1c 0x805a6f1c +805a6f2c FormationSet_GetFormationSpec +805a6f3c 0x805a6f3c +805a6f4c 0x805a6f4c +805a7050 0x805a7050 +805a70ac 0x805a70ac +805a7170 0x805a7170 +805a71a0 0x805a71a0 +805a7ccc RaceCameraMgr::Disposer__dt +805a7d64 RaceCameraMgr::CreateInstance +805a7db4 RaceCameraMgr::DestroyInstance +805a7de8 RaceCameraMgr::__ct +805a865c RaceCameraMgr::__dt +805a8714 0x805a8714 +805a88fc RaceCamera::__dt +805a893c RaceCameraMgr::HasEveryOpeningPanEnded +805a898c RaceCameraMgr::Update +805a89ec RaceCameraMgr::ApplyShaking +805a8c34 0x805a8c34 +805a8db0 0x805a8db0 +805a8e58 0x805a8e58 +805a8eb0 0x805a8eb0 +805a902c 0x805a902c +805a9088 0x805a9088 +805a921c 0x805a921c +805a9284 0x805a9284 +805a92f0 0x805a92f0 +805a9330 0x805a9330 +805a9364 0x805a9364 +805a9394 0x805a9394 +805a93c0 0x805a93c0 +805a9484 RaceCameraMgr::ChangeFocusedPlayer +805a94e4 0x805a94e4 +805a9524 OpeningPan::__dt +805a9564 RaceCamera::__dt(thunk) +805a956c RaceCamera::Update(thunk) +805a9574 RaceCamera::Init(thunk) +805a957c 0x805a957c +805a9584 AutoCameraMover::__ct +805a9638 0x805a9638 +805a96b0 0x805a96b0 +805a96c0 0x805a96c0 +805a96d0 0x805a96d0 +805a985c 0x805a985c +805a98d4 0x805a98d4 +805a9ab8 0x805a9ab8 +805a9ac0 0x805a9ac0 +805a9bac 0x805a9bac +805aa090 0x805aa090 +805aa168 0x805aa168 +805aa218 0x805aa218 +805aa264 0x805aa264 +805aa2c0 0x805aa2c0 +805aa37c 0x805aa37c +805aa564 0x805aa564 +805aa5e4 0x805aa5e4 +805aa688 0x805aa688 +805aa8e4 AutoCameraMoverRace::__ct +805aaef4 AutoCameraMoverRace::ResetActions +805aaefc AutoCameraMoverRace::vf_0x10 +805ab450 0x805ab450 +805ab610 0x805ab610 +805ab714 0x805ab714 +805ab7b8 0x805ab7b8 +805ab7bc 0x805ab7bc +805ab7cc 0x805ab7cc +805ab7dc 0x805ab7dc +805ab7ec 0x805ab7ec +805ab7fc 0x805ab7fc +805ab80c 0x805ab80c +805ab81c 0x805ab81c +805ab84c AutoCameraMoverRace::OnAction0Start +805ab850 AutoCameraMoverRace::OnAction0Update +805ab934 AutoCameraMoverRace::OnAction1Start +805ab960 AutoCameraMoverRace::OnAction1Update +805aba98 AutoCameraMoverRace::OnAction2Start +805abb70 AutoCameraMoverRace::OnAction2Update +805abca8 AutoCameraMoverRace::OnRaceEndStart +805abd04 AutoCameraMoverRace::OnRaceEndUpdate +805abe24 AutoCameraMoverRace::OnAction4Start +805abee0 AutoCameraMoverRace::OnAction4Update +805abfec AutoCameraMoverRace::OnAction5Start +805ac0c4 AutoCameraMoverRace::OnAction5Update +805ac23c AutoCameraMoverRace::OnAction6Start +805ac3ac AutoCameraMoverRace::OnAction6Update +805ac49c 0x805ac49c +805ac5b4 0x805ac5b4 +805ac79c 0x805ac79c +805ac80c 0x805ac80c +805ac8dc 0x805ac8dc +805acb0c 0x805acb0c +805acb30 0x805acb30 +805acba8 DemoCamera_ct +805acda0 0x805acda0 +805acde0 DemoCamera_init +805acf34 0x805acf34 +805acf48 0x805acf48 +805ad19c 0x805ad19c +805ad22c 0x805ad22c +805ad2a4 0x805ad2a4 +805ad3a8 0x805ad3a8 +805ad464 0x805ad464 +805ad4c0 0x805ad4c0 +805ad630 0x805ad630 +805ad718 0x805ad718 +805ad758 0x805ad758 +805ad7a0 0x805ad7a0 +805ad7d0 0x805ad7d0 +805ad818 CamMove::OnStart +805ad860 CamMove::Update +805ad890 CamMove::OnEnd +805ad8d8 0x805ad8d8 +805ad970 BFGHolder::__ct +805ada78 BFGHolder::Update +805adcdc 0x805adcdc +805add3c 0x805add3c +805addc0 FogManager::__ct +805adebc FogManager::Update +805adf74 0x805adf74 +805ae090 0x805ae090 +805ae0b4 FogManager::__dt +805ae0f4 BFGHolder::__dt +805ae134 0x805ae134 +805ae250 0x805ae250 +805ae36c VEC3_perpInPlane +805ae458 0x805ae458 +805ae508 Vec3_projUnit +805ae550 VEC3_rejUnit +805ae5a4 VEC3_projAndRej +805ae60c 0x805ae60c +805ae628 0x805ae628 +805ae694 0x805ae694 +805ae794 0x805ae794 +805ae844 GetPath +805ae8ec 0x805ae8ec +805ae9a0 0x805ae9a0 +805ae9c8 0x805ae9c8 +805aea70 0x805aea70 +805aeac8 0x805aeac8 +805aeb3c 0x805aeb3c +805aeba8 0x805aeba8 +805aecb0 0x805aecb0 +805aecf0 ScnMgrCreator::Disposer__dt +805aed88 ScnMgrCreator::CreateInstance +805aee0c 0x805aee0c +805aee4c ScnMgrCreator::DestroyInstance +805aee80 ScnMgrCreator::__dt +805aef28 ScnMgrCreator::CreateScnMgr +805af0f4 ScnMgrCreator::CreateRace +805af2c8 0x805af2c8 +805af368 ScnMgrCreator::CreateMenu +805af430 ScnMgrCreator::CreateGlobe +805af4f8 0x805af4f8 +805af5c8 0x805af5c8 +805af5d8 0x805af5d8 +805af618 0x805af618 +805af694 0x805af694 +805af7a0 0x805af7a0 +805af808 0x805af808 +805afa34 0x805afa34 +805afc1c 0x805afc1c +805afe14 0x805afe14 +805afeac 0x805afeac +805b04a8 0x805b04a8 +805b07c0 0x805b07c0 +805b0c7c 0x805b0c7c +805b0c80 ScnMgrRace::__ct +805b0cd4 ScnMgrRace::__ct +805b0d2c 0x805b0d2c +805b0dcc ScnMgrRace::805b144c +805b0df0 ScnMgrRace::SetModelXluDrawPriority +805b0e60 ScnMgrRace::LoadPostEffects +805b1398 ScnMgrRace::LoadLights +805b13f4 ScnMgrRace::vf_0xC +805b15f8 ScnMgrRace::CalcSelf +805b1658 ScnMgrRace::Draw +805b16dc 0x805b16dc +805b18ac 0x805b18ac +805b1a90 ScnMgrRace::UpdateCameras +805b1ae8 0x805b1ae8 +805b1b68 0x805b1b68 +805b1bc4 0x805b1bc4 +805b1cfc 0x805b1cfc +805b1ed0 0x805b1ed0 +805b1ee8 0x805b1ee8 +805b1fd4 0x805b1fd4 +805b20c0 0x805b20c0 +805b2c0c 0x805b2c0c +805b2cb0 0x805b2cb0 +805b2df0 0x805b2df0 +805b2ecc 0x805b2ecc +805b2ff0 0x805b2ff0 +805b3064 0x805b3064 +805b3068 0x805b3068 +805b33d8 0x805b33d8 +805b33ec ScnProcShadows::Draw +805b33f8 ScnProcShadows2::Draw +805b3404 0x805b3404 +805b3410 0x805b3410 +805b341c ScnProcEffects::Draw +805b3454 ScnProcCourseFilterEffect::Draw +805b3474 ScnProcEffectsSelfItem::Draw +805b3480 ScnMgrRace::Init +805b3828 ScnProcEffectsSelfItem::__dt +805b3880 ScnProcCourseFilterEffect::__dt +805b38d8 ScnProcEffects::__dt +805b3930 0x805b3930 +805b3988 0x805b3988 +805b39e0 ScnProcShadows2::__dt +805b3a38 ScnProcShadows::__dt +805b3a90 RendererRaceUIScreen::__ct +805b3ad4 RendererRaceUIScreen::__dt +805b3b2c RendererRaceUIScreen::Draw +805b3bbc RendererRaceUIOrtho::__ct +805b3c00 RendererRaceUIOrtho::__dt +805b3c58 RendererRaceUIOrtho::Draw +805b3c94 RendererRaceUIOrtho::Calc +805b3c98 RendererRaceUIScreen::Calc +805b3c9c RendererRaceModels::__ct +805b3ce8 RendererRaceModels::DrawModels +805b3d3c RendererRaceModels::vf_0x1c +805b3e08 RendererRaceModels::Draw +805b3e8c 0x805b3e8c +805b4004 RendererRaceModels::__dt +805b405c 0x805b405c +805b4068 0x805b4068 +805b422c 0x805b422c +805b43b0 0x805b43b0 +805b440c 0x805b440c +805b4418 0x805b4418 +805b4478 Kart::Physics::__ct +805b44d4 Kart::Physics::Reset +805b46a4 Kart::Physics::ResetSpeed +805b4740 Kart::Physics::Init(Reset Thunk) +805b4744 Kart::Physics::Init +805b4804 Kart::Physics::InitInertia +805b48b4 Kart::Physics::CalcInvInertia +805b48c4 0x805b48c4 +805b4a78 0x805b4a78 +805b4af0 Kart::Physics::Update +805b54e4 0x805b54e4 +805b54e8 Kart::Physics::Stabilize +805b5668 0x805b5668 +805b57c0 0x805b57c0 +805b58c4 0x805b58c4 +805b58f8 0x805b58f8 +805b5ad0 Kart::Physics::ApplyWheelSuspension +805b5c1c 0x805b5c1c +805b5d08 0x805b5d08 +805b5d3c 0x805b5d3c +805b5db8 0x805b5db8 +805b5dc8 Kart::PhysicsBike::Stabilize +805b6064 Kart::PhysicsBike::__dt +805b60a4 Kart::Collision::UpdateCollisionsInner +805b641c 0x805b641c +805b66c8 Kart::Collision::ApplyBodyCollision +805b68cc Kart::Collision::UpdateWheelCollision +805b6bdc 0x805b6bdc +805b6c38 0x805b6c38 +805b7250 0x805b7250 +805b72a8 0x805b72a8 +805b78c8 Hitbox::Set +805b7904 Hitbox::Reset +805b793c Hitbox::Update +805b7a28 0x805b7a28 +805b7ad8 0x805b7ad8 +805b7b50 0x805b7b50 +805b7b64 0x805b7b64 +805b7b9c CollisionData::__ct +805b7c3c HitboxGroup::__ct +805b7cb0 HitboxGroup::Reset +805b7d58 0x805b7d58 +805b7da0 0x805b7da0 +805b7e00 0x805b7e00 +805b7e40 HitboxGroup::__ct(hitboxes) +805b8028 0x805b8028 +805b80dc HitboxGroup::__ct(radius,position) +805b81bc HitboxGroup::UpdateBoundingRadius +805b8304 ShadowModelDirector::__ct(ClipInfo) +805b8374 ShadowModelDirector::__ct +805b83c8 ShadowModelDirector::__dt +805b8420 ShadowModelDirector::SetScnOptions +805b8524 ShadowModelsMgr::Disposer__dt +805b85bc ShadowModelsMgr::CreateInstance +805b867c ShadowModelsMgr::DestroyInstance +805b86b0 ShadowModelsMgr::__ct +805b8744 ShadowModelsMgr::__dt +805b87e0 ShadowModelsMgr::InsertModel +805b87e8 ShadowModelsMgr::InsertModel2 +805b87f0 ShadowModelsMgr::Draw +805b88c0 ShadowModelsMgr::Draw2 +805b8990 MatModelDirector::__ct +805b89ec MatModelDirector::__ct(scnMgrIdx) +805b8a48 MatModelDirector::__ct(ClipInfo) +805b8aa4 MatModelDirector::__dt +805b8b0c MatModelDirector::AppendToScnMgr +805b8b50 MatModelDirector::SetMaterialNames +805b8b60 MatModelDirector::CopyMaterialsTevColors +805b8c48 MatModelDirector::ReplaceDefaultScnMdlTevColorDL +805b8c78 MatModelDirector::__dt(thunk) +805b8c80 NdevArgsExtractor::__ct +805b8c84 NdevArgsExtractor::__dt +805b8cc4 NdevArgsExtractor::ExtractAllArgs +805b9a0c NdevArgsExtractor::ExtractSection +805b9b04 NdevArgsExtractor::ExtractLicense +805b9bf4 NdevArgsExtractor::ExtractPad +805b9d58 NdevArgsExtractor::ExtractGhostType +805b9e48 NdevArgsExtractor::ExtractCourseId +805b9f38 NdevArgsExtractor::ExtractGhostLicense +805ba060 NdevArgsExtractor::ExtractFriendIdx +805ba118 NdevArgsExtractor::ExtractW +805ba20c NdevArgsExtractor::ExtractD +805ba30c NdevArgsExtractor::ExtractInt +805ba3e0 NdevArgsExtractor::ExtractU64 +805ba4c0 Pages::ActionLess::__ct +805ba504 Pages::ActionLess::__dt +805ba56c Pages::ActionLess::OnInit +805ba5c0 Pages::ActionLess::OnActivate +805ba5cc Pages::ActionLess::AfterControlUpdate +805ba604 Pages::ActionLess::RequestEnd +805ba610 Pages::AutoEndingTransparent::__ct +805ba678 Pages::AutoEndingTransparent::__dt +805ba70c Pages::AutoEndingTransparent::OnInit +805ba800 Pages::AutoEndingTransparent::ResetText +805ba810 Pages::AutoEndingTransparent::SetMessageWindowText +805ba818 Pages::AutoEnding::__ct +805ba890 CtrlMenuPageTitleText::__dt +805ba8e8 Pages::AutoEnding::__dt +805ba9a4 Pages::AutoEnding::OnInit +805bab40 Pages::AutoEnding::ResetText +805bab90 Pages::AutoEnding::SetTitleText +805bab98 Pages::AutoEnding::SetMessageWindowText +805baba0 Page::vf_0x5c +805baba4 Page::OnSectionChange +805baba8 Page::OnResume +805babac Page::OnUpdate +805babb0 Page::BeforeControlUpdate +805babb4 Page::AfterExitAnimations +805babb8 Page::BeforeExitAnimations +805babbc Page::AfterEntranceAnimations +805babc0 Page::BeforeEntranceAnimations +805babc4 Page::OnDeactivate +805babc8 Page::OnDispose +805babcc Page::IsDVDEnabled +805babd4 Page::IsHomeMenuWorking +805babdc Page::Getpage +805babe4 0x805babe4 +805babec Pages::AutoEnding::GetRuntimeTypeInfo +805babf8 Page::GetNextPage +805bac00 Pages::AutoEndingTransparent::GetRuntimeTypeInfo +805bac0c Pages::ActionLess::GetRuntimeTypeInfo +805bac18 ActionLessPage_cpp_sinit_ +805bac38 Pages::AwardFade::GetPlayersVolumeMgr +805bac44 Pages::AwardFade::__ct +805bacc8 Pages::AwardFade::__dt +805bad3c Pages::AwardFade::OnInit +805bae5c Pages::AwardFade::OnActivate +805baea8 Pages::AwardFade::BeforeEntranceAnimations +805baeac Pages::AwardFade::BeforeExitAnimations +805baeb0 Pages::AwardFade::AfterControlUpdate +805baff8 Pages::AwardFade::HandleClick +805bb0a4 AwardDemoCongratulations::GetClassName +805bb0b4 AwardDemoCongratulations::__ct +805bb0f0 AwardDemoCongratulations::__dt +805bb148 AwardDemoCongratulations::Load +805bb220 AwardDemoCongratulations::InitSelf +805bb258 0x805bb258 +805bb290 0x805bb290 +805bb2c8 AwardDemoResultItem::GetClassName +805bb2d8 AwardDemoResultItem::__ct +805bb314 AwardDemoResultItem::__dt +805bb36c AwardDemoResultItem::Load +805bb518 AwardDemoResultItem::InitSelf +805bb550 AwardDemoResultItem::SetValues +805bb9bc Pages::AwardResults::__ct +805bba88 Pages::AwardResults::__dt +805bbb30 Pages::AwardResults::OnInit +805bbfa0 Pages::AwardResults::OnActivate +805bbfc0 Pages::AwardResults::BeforeEntranceAnimations +805bbfe0 Pages::AwardResults::AfterControlUpdate +805bc0bc Pages::AwardResults::HandleClick +805bc25c Pages::AwardResults::InitConfig +805bc35c Pages::AwardResults::SetWinOrLose +805bc520 0x805bc520 +805bc5a4 Pages::AwardResults::PrepareCongratulations +805bc744 Pages::AwardResults::PrepareResultItems +805bc8b0 Pages::AwardResults::PrepareCup +805bc93c Pages::AwardResults::PrepareCup_switch +805bc940 Pages::AwardResults::PrepareCup_caseD_0 +805bc948 Pages::AwardResults::PrepareCup_caseD_1 +805bc950 Pages::AwardResults::PrepareCup_caseD_2 +805bc958 Pages::AwardResults::PrepareCup_caseD_3 +805bc960 Pages::AwardResults::PrepareCup_caseD_4 +805bc968 Pages::AwardResults::PrepareCup_caseD_5 +805bc970 Pages::AwardResults::PrepareCup_caseD_6 +805bc978 Pages::AwardResults::PrepareCup_caseD_7 +805bc9d0 Pages::AwardResults::InitRank +805bcc4c Pages::AwardResults::GetRuntimeTypeInfo +805bcc58 UIControl::805bd2d8 +805bcc5c UIControl::OnPlayAnimSound +805bcc60 UIControl::OnUpdate +805bcc64 AwardDemoResultItem::GetRuntimeTypeInfo +805bcc70 AwardDemoCongratulations::GetRuntimeTypeInfo +805bcc7c 0x805bcc7c +805bcc84 Pages::AwardFade::GetRuntimeTypeInfo +805bcc90 TriggerPtmf +805bccc0 TriggerPtmf +805bccf0 AwardPages_cpp_sinit_ +805bcd1c PushButton::GetClassName +805bcd28 PushButton::__ct +805bce30 PushButton::__dt +805bce98 PushButton::Load +805bd084 ManipulatorManager::GetRuntimeTypeInfo +805bd090 PushButton::OnLoad +805bd094 0x805bd094 +805bd0a0 PushButton::LoadWithAnims +805bd448 PushButton::SetOnClickHandler +805bd460 PushButton::SetOnSelectHandler +805bd468 PushButton::SetOnDeSelectHandler +805bd470 PushButton::SelectInitial +805bd4c4 PushButton::Select +805bd4d8 PushButton::SelectFocus +805bd554 PushButton::SetPlayerBitfield +805bd560 PushButton::Init +805bd718 PushButton::Update +805bd8c4 PushButton::IsSelected +805bd908 PushButton::GetAnimationFrameSize +805bd97c PushButton::HandleSelect +805bdaac PushButton::OnSelect +805bdab0 PushButton::HandleDeselect +805bdcd4 PushButton::OnDeselect +805bdcd8 PushButton::HandleClick +805bddac PushButton::OnClick +805bddb0 PushButton::SetSelectionSoundId +805bddb8 PushButtonScaleFade::GetClassName +805bddc8 PushButtonScaleFade::__ct +805bdedc PushButtonScaleFade::__dt +805bdf48 PushButtonScaleFade::SetPositionAnim +805bdf80 0x805bdf80 +805bdf84 PushButtonScaleFade::GetRuntimeTypeInfo +805bdf90 PushButton::GetRuntimeTypeInfo +805bdf9c PushButton::TriggerPtmf +805bdfcc PushButton_cpp_sinit_ +805bdfec Pages::AddMKChannel::__ct +805be174 CtrlMenuBackButton::__dt +805be1cc Pages::AddMKChannel::__dt +805be278 Pages::AddMKChannel::OnInit +805be4a8 Pages::AddMKChannel::OnDispose +805be4ac Pages::AddMKChannel::OnActivate +805be4b0 Pages::AddMKChannel::OnDeactivate +805be4b4 Pages::AddMKChannel::GetNextPage +805be4cc Pages::AddMKChannel::OnAddButtonClick +805be6e8 Page::GetRuntimeTypeInfo +805be6f4 Pages::AddMKChannel::OnCancelButtonClick +805be780 Pages::AddMKChannel::OnBackButtonClick +805be7bc Pages::AddMKChannel::OnBackPress +805be7cc Pages::MKChannelExplanation::__ct +805be8e4 Pages::MKChannelExplanation::__dt +805be984 Pages::MKChannelExplanation::OnInit +805beb20 Pages::MKChannelExplanation::OnActivate +805beb2c Pages::MKChannelExplanation::GetNextPage +805beb64 Pages::MKChannelExplanation::OnButtonClick +805bec10 Pages::MKChannelExplanation::OnBackPress +805bec58 0x805bec58 +805bec5c Pages::MKChannelExplanation::GetRuntimeTypeInfo +805bec68 Pages::AddMKChannel::GetRuntimeTypeInfo +805bec74 Pages::MKChannelExplanation::TriggerButtonPtmf +805beca4 Pages::AddMKChannel::TriggerButtonPtmf +805becd4 Pages::MKChannelExplanation::TriggerBackPtmf +805bed04 Pages::AddMKChannel::TriggerBackPtmf +805bed34 AddMKChannelPage_cpp_sinit_ +805bed50 NotifyButton::GetClassName +805bed5c NotifyButton::__ct +805bed98 NotifyButton::__dt +805bedf0 NotifyButton::Load +805beeac NotifyButton::InitSelf +805bef80 NotifyButton::OnUpdate +805bf318 NotifyButton::OnClick +805bf35c NotifyButton::OnClick_switch +805bf360 NotifyButton::OnClick_caseD_0 +805bf368 NotifyButton::OnClick_caseD_1 +805bf370 NotifyButton::OnClick_caseD_2 +805bf478 NotifyButton::OnClick_caseD_3 +805bf480 NotifyButton::OnClick_caseD_5 +805bf488 NotifyButton::OnClick_caseD_7 +805bf490 NotifyButton::OnClick_caseD_8 +805bf498 NotifyButton::OnClick_caseD_9 +805bf4a0 NotifyButton::OnClick_caseD_a +805bf4f0 NotifyButton::OnClick_switch_805bfb90::CaseD_a +805bf514 0x805bf514 +805bf51c 0x805bf51c +805bf524 0x805bf524 +805bf52c 0x805bf52c +805bf534 0x805bf534 +805bf53c 0x805bf53c +805bf544 0x805bf544 +805bf54c 0x805bf54c +805bf554 0x805bf554 +805bf55c 0x805bf55c +805bf564 0x805bf564 +805bf574 NotifyButton::CheckStatusAvailabilities +805bf79c NotifyButton::UpdateText +805bf7d8 NotifyButton::UpdateText_switch +805bf7dc NotifyButton::UpdateText_caseD_0 +805bf7e4 NotifyButton::UpdateText_caseD_1 +805bf7ec NotifyButton::UpdateText_caseD_2 +805bf7f4 NotifyButton::UpdateText_caseD_3 +805bf7fc NotifyButton::UpdateText_caseD_4 +805bf804 NotifyButton::UpdateText_caseD_5 +805bf80c NotifyButton::UpdateText_caseD_6 +805bf814 NotifyButton::UpdateText_caseD_7 +805bf81c NotifyButton::UpdateText_caseD_8 +805bf824 NotifyButton::UpdateText_caseD_9 +805bf82c NotifyButton::UpdateText_caseD_a +805bf898 Pages::Channel::__ct +805bfa40 CtrlMenuInstructionText::__dt +805bfa98 Pages::Channel::__dt +805bfb7c Pages::Channel::OnInit +805c0204 Pages::Channel::OnDispose +805c0208 Pages::Channel::OnActivate +805c0260 Pages::Channel::OnButtonClick +805c04f8 Pages::Channel::OnButtonSelect +805c05a0 Pages::Channel::OnButtonSelect_switch +805c05a4 Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_0 +805c05ac Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_1 +805c05b4 Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_2 +805c05bc Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_3 +805c05c4 Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_4 +805c05cc Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_5 +805c05d4 Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_6 +805c05dc Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_7 +805c05e4 Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_8 +805c05ec Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_9 +805c05f4 Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_a +805c0610 Pages::Channel::OnBackPress +805c0648 Pages::ChannelGhostChoice::__ct +805c07b8 Pages::ChannelGhostChoice::__dt +805c0868 Pages::ChannelGhostChoice::OnInit +805c0b80 Pages::ChannelGhostChoice::OnActivate +805c0bd8 Pages::ChannelGhostChoice::OnButtonClick +805c0cc0 Pages::ChannelGhostChoice::OnButtonSelect +805c0d14 Pages::ChannelGhostChoice::OnBackPress +805c0d2c Pages::ChannelRankingChoice::__ct +805c0e9c Pages::ChannelRankingChoice::__dt +805c0f4c Pages::ChannelRankingChoice::OnInit +805c11bc Pages::ChannelRankingChoice::OnActivate +805c120c Pages::ChannelRankingChoice::GetNextPage +805c1224 Pages::ChannelRankingChoice::OnButtonClick +805c1450 Pages::ChannelRankingChoice::OnButtonSelect +805c14a4 Pages::ChannelRankingChoice::OnBackPress +805c14b4 Pages::ChannelRankingChoice::GetRuntimeTypeInfo +805c14c0 Pages::ChannelGhostChoice::GetNextPage +805c14c8 Pages::ChannelGhostChoice::GetRuntimeTypeInfo +805c14d4 Pages::Channel::GetNextPage +805c14dc Pages::Channel::GetRuntimeTypeInfo +805c14e8 NotifyButton::GetRuntimeTypeInfo +805c14f4 TriggerPtmf +805c1524 TriggerPtmf +805c1554 TriggerPtmf +805c1584 TriggerPtmf +805c15b4 TriggerPtmf +805c15e4 TriggerPtmf +805c1614 ChannelPage_cpp_sinit_ +805c1640 Pages::Approve::__ct +805c1798 Pages::Approve::__dt +805c1838 Pages::Approve::OnInit +805c1a0c Pages::Approve::OnActivate +805c1a98 Pages::Approve::OnDeactivate +805c1a9c Pages::Approve::Reset +805c1b28 Pages::Approve::SetTitleMessage +805c1b30 Pages::Approve::SetMessageWindowMessage +805c1b38 Pages::Approve::SetApproveButtonMessage +805c1b40 Pages::Approve::OnClick +805c1bbc Pages::Approve::OnBackButtonClick +805c1c38 Pages::Approve::OnBackPress +805c1ca4 Pages::Approve::BeforeEntranceAnimations +805c1cc0 0x805c1cc0 +805c1cdc 0x805c1cdc +805c1ce4 Pages::Approve::GetRuntimeTypeInfo +805c1cf0 Pages::Approve::TriggerApprovePtmf +805c1d20 Pages::Approve::TriggerDisapprovePtmf +805c1d50 ApprovePage_cpp_sinit_ +805c1d64 ControlGroup::__ct +805c1d80 ControlGroup::__dt +805c1de0 ControlGroup::Init(UIControl) +805c1fa0 ControlGroup::Init(Page) +805c215c ControlGroup::SetControl +805c2184 ControlGroup::805c2804 +805c21e8 ControlGroup::InitControls +805c2258 ControlGroup::Update +805c22c8 ControlGroup::Draw +805c23dc ControlGroup::ResetControlsPosition +805c2440 ControlGroup::GetControl +805c2450 ControlGroup::DoAction +805c2598 ControlLoader::__ct +805c25a0 ControlLoader::__dt +805c25e0 ControlLoader::Load +805c2800 ControlLoader::LoadBRCTR +805c28b4 ControlLoader::LoadAnimations +805c2b98 ControlLoader::IsStringInArray +805c2c30 ControlLoader::FindStringInArray +805c2ca8 ControlLoader::GetVariant +805c2d28 ControlLoader::LoadVariant +805c2df0 ControlLoader::LoadMessages +805c2ed0 ControlLoader::LoadPictures +805c2f78 Pages::BatteryMgr::__ct +805c2fbc Pages::BatteryMgr::__dt +805c3024 Pages::BatteryMgr::OnInit +805c3080 Pages::BatteryMgr::OnActivate +805c30cc Pages::BatteryMgr::BeforeEntranceAnimations +805c30d0 0x805c30d0 +805c30d4 Pages::BatteryMgr::BeforeExitAnimations +805c30d8 Pages::BatteryMgr::AfterControlUpdate +805c3160 Pages::LowBattery::__ct +805c31f4 Pages::LowBattery::__dt +805c3280 Pages::LowBattery::OnInit +805c33a8 Pages::LowBattery::OnActivate +805c340c Pages::LowBattery::AfterControlUpdate +805c3444 Pages::LowBattery::OnClick +805c3458 Pages::LowBattery::BeforeEntranceAnimations +805c349c Pages::LowBattery::AfterExitAnimations +805c34e0 Pages::LowBattery::GetRuntimeTypeInfo +805c34ec Pages::BatteryMgr::GetNextPage +805c34f4 Pages::BatteryMgr::GetRuntimeTypeInfo +805c3500 TriggerPtmf +805c3530 LowBatteryPage_cpp_sinit_ +805c354c CountDown::__ct +805c356c CountDown::__dt +805c35ac Countdown::SetInitial +805c35c4 Countdown::Update +805c3648 CountDownTimerControl::GetClassName +805c3654 CountDownTimerControl::__ct +805c3698 CountDownTimerControl::__dt +805c36f0 CountDownTimerControl::Load +805c377c CountDownTimerControl::InitSelf +805c39fc CountDownTimerControl::OnUpdate +805c3d00 CountDownTimerControl::AnimateCurrentCountDown +805c3db0 CountDownTimerControl::Reset +805c3e60 0x805c3e60 +805c40c8 CountDownTimerControl::GetRuntimeTypeInfo +805c40d4 CountDown_cpp_sinit_ +805c40e8 0x805c40e8 +805c419c 0x805c419c +805c4204 0x805c4204 +805c4270 0x805c4270 +805c4668 Page::EndActivationState +805c466c 0x805c466c +805c468c Page::EndExitState +805c4690 0x805c4690 +805c4800 0x805c4800 +805c4d08 0x805c4d08 +805c4f0c 0x805c4f0c +805c502c 0x805c502c +805c504c 0x805c504c +805c50a8 0x805c50a8 +805c50b0 0x805c50b0 +805c50bc TriggerPtmf +805c50ec TriggerPtmf +805c511c 0x805c511c +805c5130 0x805c5130 +805c51b4 0x805c51b4 +805c521c 0x805c521c +805c5298 0x805c5298 +805c5458 Page::EndExitState +805c545c 0x805c545c +805c5460 0x805c5460 +805c5ad8 0x805c5ad8 +805c6170 0x805c6170 +805c61a8 0x805c61a8 +805c63c8 0x805c63c8 +805c6498 0x805c6498 +805c649c 0x805c649c +805c64a4 0x805c64a4 +805c64ac 0x805c64ac +805c64b4 0x805c64b4 +805c64bc 0x805c64bc +805c64c4 0x805c64c4 +805c64cc 0x805c64cc +805c64d4 0x805c64d4 +805c64dc 0x805c64dc +805c64e4 0x805c64e4 +805c6588 0x805c6588 +805c65f8 0x805c65f8 +805c6838 0x805c6838 +805c6914 0x805c6914 +805c6be8 0x805c6be8 +805c6d38 0x805c6d38 +805c6d78 0x805c6d78 +805c70b8 0x805c70b8 +805c71a4 0x805c71a4 +805c7288 0x805c7288 +805c7368 0x805c7368 +805c7534 0x805c7534 +805c788c 0x805c788c +805c7988 0x805c7988 +805c7a20 0x805c7a20 +805c7a88 0x805c7a88 +805c7a98 0x805c7a98 +805c7c68 0x805c7c68 +805c7d18 0x805c7d18 +805c7e10 0x805c7e10 +805c7ee4 0x805c7ee4 +805c7f88 0x805c7f88 +805c8128 0x805c8128 +805c8164 0x805c8164 +805c816c 0x805c816c +805c81b0 0x805c81b0 +805c81f4 0x805c81f4 +805c8200 0x805c8200 +805c8208 0x805c8208 +805c8214 0x805c8214 +805c821c 0x805c821c +805c8228 TriggerPtmf +805c8258 TriggerPtmf +805c8288 TriggerPtmf +805c82b8 TriggerPtmf +805c82e8 TriggerPtmf +805c8318 __sinit_DownloadGhostList_cpp +805c8338 DpdPointerControl::GetClassName +805c8344 DpdPointerControl::DpadpointerControl +805c8388 DpdPointerControl::__dt +805c83e0 DpdPointerControl::Load +805c86ec DpdPointerControl::InitSelf +805c883c DpdPointerControl::OnUpdate +805c8eb4 Pages::DpdPointer::__ct +805c8f18 Pages::DpdPointer::__dt +805c8f8c Pages::DpdPointer::OnInit +805c9018 Pages::DpdPointer::OnActivate +805c9024 Pages::DpdPointer::BeforeControlUpdate +805c908c Pages::DpdPointer::CheckForConditions +805c9094 Pages::System::AddPageLayer +805c909c Pages::System::Func_0x20 +805c90a0 Pages::System::ChangeSection +805c90a4 Pages::System::IsVisible +805c90ac Pages::DpdPointer::GetClassName +805c90b8 Pages::DpdPointer::GetRuntimeTypeInfo +805c90c4 DpdPointerControl::GetRuntimeTypeInfo +805c90d0 __sinit_DpdPointer_cpp +805c90f4 Pages::Empty::__ct +805c9138 Pages::Empty::__dt +805c91a0 Pages::Empty::OnInit +805c9208 Page::OnActivate +805c920c Pages::Empty::BeforeExitAnimations +805c9210 Pages::Empty::BeforeEntranceAnimations +805c9214 NumericEditBox::GetClassName +805c9220 NumericEditBox::__ct +805c9378 NumericEditBox::__dt +805c93fc NumericEditBox::Load +805c983c NumericEditBox::vf_0x3c +805c9840 NumericEditBox::SelectInitial +805c9894 NumericEditBox::Select +805c98b4 NumericEditBox::RemoveAllDigits +805c9968 NumericEditBox::HasFullDigits +805c99a8 NumericEditBox::HasUnusedDigit +805c99e8 NumericEditBox::ComputeSum +805c9a48 NumericEditBox::AddDigit +805c9bd0 NumericEditBox::RemoveDigit +805c9db8 NumericEditBox::Init +805c9ebc NumericEditBox::Update +805ca068 NumericEditBox::HandleUpPress +805ca140 NumericEditBox::HandleDownPress +805ca1f0 NumericEditBox::HandleClick +805ca2cc NumericEditBox::HandleRightPress +805ca3a4 NumericEditBox::HandleLeftPress +805ca460 NumericEditBox::EditLetter::GetClassName +805ca470 NumericEditBox::EditLetter::__ct +805ca4ac NumericEditBox::EditLetter::__dt +805ca504 NumericEditBox::EditLetter::Load +805ca58c NumericEditBox::EditLetter::Init +805ca60c NumericEditBox::EditLetter::Update +805ca610 NumericEditBox::EditLetter::AddDigit +805ca664 NumericEditBox::EditLetter::RemoveDigit +805ca670 NumericEditBox::EditLetter::ToggleCursor +805ca6bc NumericEditBox::EditLetter::AnimateDigit +805ca6f4 0x805ca6f4 +805ca6f8 NumericEditBox::GetRuntimeTypeInfo +805ca704 NumericEditBox::EditLetter::GetRuntimeTypeInfo +805ca710 TriggerPtmf +805ca740 NumericEditBox_cpp_sinit_ +805ca75c 0x805ca75c +805ca768 0x805ca768 +805ca7a4 StaffRollControl::__dt +805ca7fc StaffRollControl::Load +805ca8b0 StaffRollControl::InitSelf +805ca8e8 StaffRollControl::AppearAnimated +805ca920 StaffRollControl::DisappearAnimated +805ca958 Pages::StaffRoll::__ct +805ca9f4 StaffRollText::__ct +805caa50 StaffRollText::__dt +805caac4 Pages::StaffRoll::__dt +805cab44 Pages::StaffRoll::OnInit +805cb084 Pages::StaffRoll::OnActivate +805cb0d4 Pages::StaffRoll::BeforeEntranceAnimations +805cb0d8 Pages::StaffRoll::BeforeExitAnimations +805cb0dc Pages::StaffRoll::AfterControlUpdate +805cb458 Pages::StaffRoll::SetHasNotStarted +805cb470 Pages::StaffRoll::OnClick +805cb47c EndingMovieControl::GetClassName +805cb48c EndingMovieControl::__ct +805cb4c8 EndingMovieControl::__dt +805cb520 EndingMovieControl::Load +805cb618 EndingMovieControl::InitSelf +805cb650 EndingMovieControl::FadeIn +805cb688 EndingMovieControl::FadeOut +805cb6c0 EndingMovieControl::IsCurrentAnimation1Or2 +805cb708 Pages::EndingMovie::__ct +805cb7a4 Pages::EndingMovie::__dt +805cb824 Pages::EndingMovie::OnInit +805cba28 0x805cba28 +805cba94 Pages::EndingMovie::AfterEntranceAnimations +805cba98 Pages::EndingMovie::AfterControlUpdate +805cbbc8 Pages::EndingMovie::OnMovieActivate +805cbc94 Pages::CreditsCongrats::__ct +805cbd28 Pages::CreditsCongrats::__dt +805cbdd8 Pages::CreditsCongrats::OnInit +805cbfc4 Pages::CreditsCongrats::OnActivate +805cc140 Pages::CreditsCongrats::AfterControlUpdate +805cc4e0 Pages::CreditsCongrats::OnResumt +805cca88 Pages::CreditsCongrats::OnClick +805cca94 Pages::CreditsCongrats::Publish +805ccbc4 Pages::CreditsCongrats::AfterPublish +805cccc4 Pages::CreditsCongrats::AfterPublishMsg +805ccdc4 Pages::CreditsCongrats::AfterDontPostTooMany +805ccec4 Pages::CreditsCongrats::HandlePublishError +805ccf94 Pages::CreditsCongrats::HandlePublishError_switch +805ccf98 Pages::CreditsCongrats::HandlePublishError_caseD_1 +805ccfa0 Pages::CreditsCongrats::HandlePublishError_caseD_2 +805ccfa8 Pages::CreditsCongrats::HandlePublishError_caseD_3 +805ccfb0 Pages::CreditsCongrats::HandlePublishError_caseD_4 +805ccfb8 Pages::CreditsCongrats::HandlePublishError_caseD_5 +805ccfc0 Pages::CreditsCongrats::HandlePublishError_caseD_6 +805ccfc8 Pages::CreditsCongrats::HandlePublishError_caseD_8 +805ccfd0 Pages::CreditsCongrats::HandlePublishError_caseD_9 +805ccfd8 Pages::CreditsCongrats::HandlePublishError_caseD_7 +805ccfec Pages::CreditsCongrats::HandlePublishError_caseD_0 +805cd060 0x805cd060 +805cd12c Pages::CreditsCongrats::GetRuntimeTypeInfo +805cd138 Pages::EndingMovie::GetRuntimeTypeInfo +805cd144 EndingMovieControl::GetRuntimeTypeInfo +805cd150 Pages::StaffRoll::GetRuntimeTypeInfo +805cd15c StaffRollControl::GetRuntimeTypeInfo +805cd168 TriggerPtmf +805cd198 TriggerPtmf +805cd1c8 TriggerPtmf +805cd1f8 Ending_cpp_sinit_ +805cd228 Text::Info::__ct +805cd310 Text::PaneHandler::__ct +805cd32c Text::PaneHandler::__dt +805cd39c Text::Mgr::CreateInstance +805cd444 Text::Mgr::DestroyInstance +805cd4c0 Text::PaneHandler::Init +805cd5dc Text::PaneHandler::SetMessage +805cdd14 Text::PaneHandler::SetMessage_switch +805cdd18 Text::PaneHandler::SetMessage_case0 +805cdda8 Text::PaneHandler::SetMessage_case10 +805cde10 Text::PaneHandler::SetMessage_case12 +805cde60 Text::PaneHandler::SetMessage_case13 +805cdf0c Text::PaneHandler::SetMessage_case14 +805ce078 Text::PaneHandler::SetMessage_case15 +805ce1b4 Text::PaneHandler::SetMessage_case1 +805ce6a0 ManipulatorHandler::CheckPlayerPointer +805ce6a8 Text::PaneHandler::ResetMessage +805ce6e4 Text::PaneHandler::Draw +805ce7b4 0x805ce7b4 +805ce7d0 0x805ce7d0 +805ce7ec Text::PaneHandler::GetBMGInfo +805ce8a0 0x805ce8a0 +805ce944 Text::GlyphParams::__ct +805ce948 Text::GlyphParams::__dt +805ce988 Text::GlyphParams::SetCharacter +805ce9ec Text::GlyphUnicodeExternal::__ct +805ce9f0 Text::GlyphUnicodeExternal::__dt +805cea30 Text::GlyphUnicodeExternal::SetCharacter +805ceb58 Text::GlyphDrawer::__dt +805ceb98 Text::GlyphDrawer::Init +805cee74 Text::GlyphDrawer::Draw +805cef5c Text::GlyphDrawer::DrawExternalUnicode +805cf0c0 Text::GlyphDrawer::SetupGXColors +805cf2c8 Text::GlyphDrawer::SetupGXColors_switch +805cf2cc Text::GlyphDrawer::SetupGXColors_caseD_1 +805cf2e4 Text::GlyphDrawer::SetupGXColors_caseD_10 +805cf2fc Text::GlyphDrawer::SetupGXColors_caseD_11 +805cf318 Text::GlyphDrawer::SetupGXColors_caseD_12 +805cf334 Text::GlyphDrawer::SetupGXColors_caseD_13 +805cf350 Text::GlyphDrawer::SetupGXColors_caseD_14 +805cf36c Text::GlyphDrawer::SetupGXColors_caseD_15 +805cf388 Text::GlyphDrawer::SetupGXColors_caseD_16 +805cf3a4 Text::GlyphDrawer::SetupGXColors_caseD_17 +805cf3bc Text::GlyphDrawer::SetupGXColors_caseD_20 +805cf3d4 Text::GlyphDrawer::SetupGXColors_caseD_21 +805cf3f0 Text::GlyphDrawer::SetupGXColors_caseD_30 +805cf408 Text::GlyphDrawer::SetupGXColors_caseD_31 +805cf424 Text::GlyphDrawer::SetupGXColors_caseD_32 +805cf43c Text::GlyphDrawer::SetupGXColors_caseD_33 +805cf454 Text::GlyphDrawer::SetupGXColors_caseD_40 +805cf470 Text::GlyphDrawer::SetupGXColors_caseD_18 +805cf4b4 Text::GlobalHandler::__ct +805cf4c0 Text::GlobalHandler::__dt +805cf500 Text::GlobalHandler::SetPaneHandler +805cf850 0x805cf850 +805cf98c Text::GlobalHandler::SetCharacter +805cfc00 Text::GlobalHandler::SetExternalUnicodeChar +805cfe60 0x805cfe60 +805cfef8 0x805cfef8 +805cff3c 0x805cff3c +805cff50 Text::GlobalHandler::Calc +805d056c 0x805d056c +805d05b0 Text::GlobalHandler::CalcMessageParams +805d0674 Text::GlobalHandler::GetGlyphParamsAndIncrement +805d06ac Text::GlobalHandler::GetUnicodeGlyphParamsAndIncrement +805d06e4 Text::GlobalHandler::SetPaneHandlerAndPane +805d0810 Text::GameFont::__ct +805d085c Text::GameFont::__dt +805d08cc Text::GameFont::Load +805d0920 Text::GameFont::GetTextureByCode +805d0a10 Text::GameFont::GetTextureByIdx +805d0af0 Text::GameFont::Init +805d0be8 Text::FontMgr::__ct +805d0c08 Text::FontMgr::__dt +805d0ca0 Text::FontMgr::CreateInstance +805d0cf0 Text::FontMgr::DestroyInstance +805d0d80 Text::FontMgr::Init +805d1034 Text::FontMgr::InitFont +805d10e0 Text::FontMgr::GetFont +805d1164 HandleDisplayControl::GetClassName +805d1170 HandleDisplayControl::__ct +805d11ac HandleDisplayControl::__dt +805d1204 HandleDisplayControl::Load +805d1284 0x805d1284 +805d12e8 HandleDisplayControl::InitSelf +805d1394 Pages::WheelOnlyComp::__ct +805d1400 Pages::WheelOnlyComp::__dt +805d1484 Pages::WheelOnlyComp::OnInit +805d15ac Pages::WheelOnlyComp::OnActivate +805d15c0 Pages::WheelOnlyComp::AfterEntranceAnimations +805d15d4 Pages::WheelOnlyComp::AfterControlUpdate +805d1724 Pages::WheelOnlyComp::GetRuntimeTypeInfo +805d1730 HandleDisplayControl::GetRuntimeTypeInfo +805d173c WheelOnlyComp_cpp_sinit_ +805d1760 FriendList::__ct +805d17d4 0x805d17d4 +805d1814 FriendListEntry::__ct +805d185c FriendListEntry::__dt +805d189c 0x805d189c +805d18dc 0x805d18dc +805d191c FriendList::__dt +805d1980 FriendList::Init +805d1a90 FriendList::SaveToRKSYS +805d1b40 FriendList::Update +805d1ba4 0x805d1ba4 +805d1cb4 0x805d1cb4 +805d1d9c FriendList::GetFriendCount +805d1e38 FriendList::AddFriend +805d1fdc FriendList::RemoveFriend +805d2054 FriendList::GetFriendIdx +805d2150 FriendList::GetFriendEntry +805d216c FriendList::GetFriend +805d21a4 FriendList::GetFriendStatus +805d21dc FriendList::IsFriendStatusLessThan25 +805d2228 FriendList::IsUpdated +805d2244 FriendList::UpdateKeyController +805d226c 0x805d226c +805d22b8 0x805d22b8 +805d22e0 0x805d22e0 +805d232c FriendList::UpdateStatuses +805d2420 FriendList::UpdateStatuses_switch +805d2424 FriendList::UpdateStatuses_caseD_1 +805d242c FriendList::UpdateStatuses_caseD_2 +805d2434 FriendList::UpdateStatuses_caseD_3 +805d243c FriendList::UpdateStatuses_caseD_5 +805d2444 FriendList::UpdateStatuses_caseD_6 +805d244c FriendList::UpdateStatuses_caseD_7 +805d2454 FriendList::UpdateStatuses_caseD_8 +805d245c FriendList::UpdateStatuses_caseD_9 +805d2464 FriendList::UpdateStatuses_caseD_a +805d246c FriendList::UpdateStatuses_caseD_b +805d24d0 FriendList::UpdateStatuses_caseD_4 +805d24dc FriendList::UpdateStatuses_caseD_c +805d2534 FriendList::UpdateStatuses_caseD_d +805d259c FriendList::UpdateStatuses_caseD_e +805d25f4 FriendList::UpdateStatuses_caseD_0 +805d2620 FriendList::UpdateFriendData +805d29e4 0x805d29e4 +805d29e8 0x805d29e8 +805d2a10 0x805d2a10 +805d2a14 0x805d2a14 +805d2a34 0x805d2a34 +805d2a38 0x805d2a38 +805d2a84 0x805d2a84 +805d2a88 0x805d2a88 +805d2ad4 0x805d2ad4 +805d2ad8 FriendCodesController::Update +805d2b94 FriendCodesController::TrySaveMgrToRKSYS +805d2bf8 FriendCodesController::SaveMgrToRKSYS +805d2d2c FriendCodesController::ResetMgrKeys +805d2d3c FriendReceiver::TrySaveToRKSYS +805d2db0 FriendReceiver::TryReceiveData +805d2f98 FriendReceiver::SaveToRKSYS +805d3048 FriendReceiver::vf_0x10 +805d30dc FriendButton::GetClassName +805d30e8 FriendButton::__ct +805d312c FriendButton::__dt +805d3184 FriendButton::Load +805d325c FriendButton::SetMii +805d3438 0x805d3438 +805d3530 FriendButton::InitSelf +805d3534 FriendButton::OnUpdate +805d3904 FriendButton::OnSelect +805d39fc FriendButton::OnDeselect +805d3aa4 Pages::FriendList::__ct +805d3c84 Pages::FriendList::__dt +805d3d48 Pages::FriendList::OnInit +805d410c Pages::FriendList::OnDispose +805d4110 Pages::FriendList::OnActivate +805d4330 Pages::FriendList::BeforeEntranceAnimations +805d4438 Pages::FriendList::BeforeExitAnimations +805d444c Pages::FriendList::OnDeactivate +805d44ec Pages::FriendList::AfterControlUpdate +805d4568 Pages::FriendList::AddNewFriend +805d45e4 Pages::FriendList::OnFriendButtonClick +805d472c Pages::FriendList::OnBackButtonClick +805d47c0 Pages::FriendList::OnRightArrowPress +805d48f0 Pages::FriendList::OnLeftArrowPress +805d49e8 Pages::FriendList::OnBackPress +805d4a68 Pages::FriendList::CompareFriendIndexes +805d4af8 Pages::FriendList::FriendStatusToValue +805d4b18 Pages::FriendList::FriendStatusToValue_switch +805d4b1c Pages::FriendList::FriendStatusToValue_Case_fffffffe +805d4b24 Pages::FriendList::FriendStatusToValue_Case_ffffffff +805d4b2c Pages::FriendList::FriendStatusToValue_Case_0 +805d4b34 Pages::FriendList::FriendStatusToValue_Case_1 +805d4b3c Pages::FriendList::FriendStatusToValue_Case_2 +805d4b44 Pages::FriendList::FriendStatusToValue_Case_3 +805d4b4c Pages::FriendList::FriendStatusToValue_Case_4 +805d4b54 Pages::FriendList::FriendStatusToValue_Case_5 +805d4b5c Pages::FriendList::FriendStatusToValue_Case_6 +805d4b64 Pages::FriendList::FriendStatusToValue_Case_7 +805d4b6c Pages::FriendList::FriendStatusToValue_Case_8 +805d4b74 Pages::FriendList::FriendStatusToValue_Case_9 +805d4b7c Pages::FriendList::FriendStatusToValue_Case_a +805d4b84 Pages::FriendList::FriendStatusToValue_Case_b +805d4b8c Pages::FriendList::FriendStatusToValue_Case_c +805d4b94 Pages::FriendList::FriendStatusToValue_Case_d +805d4b9c Pages::FriendList::FriendStatusToValue_Case_e +805d4ba4 Pages::FriendList::FriendStatusToValue_Case_f +805d4bac Pages::FriendList::FriendStatusToValue_Case_10 +805d4bb4 Pages::FriendList::FriendStatusToValue_Case_11 +805d4bbc Pages::FriendList::FriendStatusToValue_Case_12 +805d4bc4 Pages::FriendList::FriendStatusToValue_Case_13 +805d4bcc Pages::FriendList::FriendStatusToValue_Case_14 +805d4bd4 Pages::FriendList::FriendStatusToValue_Case_15 +805d4bdc Pages::FriendList::FriendStatusToValue_Case_16 +805d4be4 Pages::FriendList::FriendStatusToValue_Case_17 +805d4bec Pages::FriendList::FriendStatusToValue_Case_18 +805d4bf4 Pages::FriendList::FriendStatusToValue_Case_19 +805d4bfc Pages::FriendList::FriendStatusToValue_Case_1a +805d4c0c Pages::FriendList::UpdatePageCounter +805d4cd4 Pages::FriendList::UpdateMiiGroup +805d4ddc JoinFriendButton::GetClassName +805d4dec JoinFriendButton::__ct +805d4e28 JoinFriendButton::__dt +805d4e80 JoinFriendButton::__dt +805d4f88 JoinFriendButton::SetStatus +805d50f4 JoinFriendButton::OnUpdate +805d5138 Pages::FriendInfo::__ct +805d52f0 Pages::FriendInfo::__dt +805d53d0 Pages::FriendInfo::OnInit +805d58dc Pages::FriendInfo::OnActivate +805d5a04 Pages::FriendInfo::AfterControlUpdate +805d5c6c Pages::FriendInfo::PlaySound +805d5d4c Pages::FriendInfo::SetInfoText +805d5f30 0x805d5f30 +805d5f54 Pages::FriendInfo::OnJoinButtonClick +805d61e8 Pages::FriendInfo::OnRemoveButtonClick +805d622c Pages::FriendInfo::OnBackButtonClick +805d6270 Pages::FriendInfo::OnBackPress +805d6288 Pages::FriendRemove::__ct +805d63e0 Pages::FriendRemove::__dt +805d6480 Pages::FriendRemove::OnInit +805d661c Pages::FriendRemove::OnActivate +805d66ec Pages::FriendRemove::OnDeactivate +805d67a4 Pages::FriendRemove::OnResume +805d6878 Pages::FriendRemove::OnRemoveButtonClick +805d6a6c Pages::FriendRemove::OnCancelAndBackButtonClick +805d6ac8 Pages::FriendRemove::OnBackPress +805d6ae0 Pages::FriendRemoving::__ct +805d6b54 Pages::FriendRemoving::__dt +805d6be4 Pages::FriendRemoving::OnInit +805d6ce0 Pages::FriendRemoving::OnActivate +805d6dd0 Pages::FriendRemoving::BeforeExitAnimations +805d6f34 Pages::FriendRemoving::AfterControlUpdate +805d7248 Pages::FriendJoinMgr::__ct +805d728c Pages::FriendJoinMgr::__dt +805d72f4 Pages::FriendJoinMgr::OnInit +805d7360 Pages::FriendJoinMgr::OnActivate +805d7630 Pages::FriendJoinMgr::BeforeEntranceAnimations +805d7634 Pages::FriendJoinMgr::AfterEntranceAnimations +805d7644 Pages::FriendJoinMgr::BeforeExitAnimations +805d7648 Pages::FriendJoinMgr::GetNextPage +805d7650 Pages::FriendJoinMgr::GetRuntimeTypeInfo +805d765c Pages::FriendRemoving::IsHomeMenuWorking +805d7664 Pages::FriendRemoving::GetNextPage +805d766c Pages::FriendRemoving::GetRuntimeTypeInfo +805d7678 Pages::FriendRemove::GetNextPage +805d7680 Pages::FriendRemove::GetRuntimeTypeInfo +805d768c Pages::FriendInfo::GetNextPage +805d7694 Pages::FriendInfo::GetRuntimeTypeInfo +805d76a0 JoinFriendButton::GetRuntimeTypeInfo +805d76ac Pages::FriendList::GetNextPage +805d76b4 Pages::FriendList::GetRuntimeTypeInfo +805d76c0 FriendButton::GetRuntimeTypeInfo +805d76cc TriggerPtmf +805d76fc TriggerPtmf +805d772c TriggerPtmf +805d775c TriggerPtmf +805d778c TriggerPtmf +805d77bc TriggerPtmf +805d77ec TriggerPtmf +805d781c FriendListPage_cpp_sinit_ +805d7854 Pages::FriendRoom::__ct +805d7a3c Pages::FriendRoom::__dt +805d7ae8 Pages::FriendRoom::OnInit +805d7d20 Pages::FriendRoom::OnActivate +805d7dd8 Pages::FriendRoom::OnDeactivate +805d7de4 Pages::FriendRoom::AfterControlUpdate +805d8574 Pages::FriendRoom::OnResume +805d881c Pages::FriendRoom::SetStatus +805d8824 0x805d8824 +805d8860 Pages::FriendRoom::OnMessagesButtonClick +805d8948 Pages::FriendRoom::OnStartButtonClick +805d8a30 Pages::FriendRoom::OnAddFriendsButtonClick +805d8a3c Pages::FriendRoom::OnBackButtonClick +805d8b7c Pages::FriendRoom::OnButtonSelect +805d8be8 Pages::FriendRoom::OnBackPress +805d8d28 FriendMatchingPlayer::GetClassName +805d8d38 FriendMatchingPlayer::__ct +805d8dac FriendMatchingPlayer::__dt +805d8e04 FriendMatchingPlayer::Load +805d8ef0 FriendMatchingPlayer::InitSelf +805d8fdc FriendMatchingPlayer::OnUpdate +805d9158 0x805d9158 +805d9270 0x805d9270 +805d92d4 0x805d92d4 +805d9384 FriendMatchingPlayer::OnMessageSent +805d9414 Pages::FriendRoomManager::__ct +805d94a8 Pages::FriendRoomManager::__dt +805d9550 Pages::FriendRoomManager::OnInit +805d968c Pages::FriendRoomManager::OnActivate +805d97fc Pages::FriendRoomManager::AfterEntranceAnimations +805d9904 Pages::FriendRoomManager::BeforeExitAnimations +805d99d0 Pages::FriendRoomManager::OnDeactivate +805d9a1c Pages::FriendRoomManager::AfterControlUpdate +805da52c AvoidController_UseMinimumAvoidance +805da53c 0x805da53c +805da58c Pages::FriendRoomManager::GetMessageBmg +805da680 Pages::FriendRoomManager::SetToSendPacket +805da704 0x805da704 +805da70c 0x805da70c +805da734 0x805da734 +805da744 0x805da744 +805da758 0x805da758 +805da75c 0x805da75c +805da79c 0x805da79c +805da814 0x805da814 +805daae0 0x805daae0 +805dab54 0x805dab54 +805dabfc 0x805dabfc +805dac24 0x805dac24 +805dac34 0x805dac34 +805daf10 0x805daf10 +805daf94 MessageSelectControl::GetClassName +805dafa4 MessageSelectControl::__ct +805db000 MessageSelectControl::__dt +805db074 MessageSelectControl::Load +805db1c8 MessageSelectControl::InitSelf +805db1cc MessageSelectControl::OnUpdate +805db2c4 MessageSelectControl::SetPositionAnim +805db2fc MessageSelectControl::Activate +805db394 MessageSelectControl::Deactivate +805db404 MessageSelectControl::ChangeToPage +805db464 MessageSelectControl::ChangeFromPage +805db4fc MessageSelectControl::IsActivated +805db534 MessageSelectControl::IsDeactivated +805db568 MessageSelectControl::SetButtonBmg +805db5a0 MessageSelectControl::SetOnClickHandler +805db600 MessageSelectControl::SelectInitialButton +805db610 MessageSelectControl::GetSelectedButtonId +805db670 Pages::FriendRoomMessages::__ct +805db8b8 SheetSelectControlScaleFade::__dt +805db910 Pages::FriendRoomMessages::__dt +805db9e0 Pages::FriendRoomMessages::OnInit +805dbc54 Pages::FriendRoomMessages::OnActivate +805dbff8 Pages::FriendRoomMessages::OnDeactivate +805dc094 Pages::FriendRoomMessages::BeforeControlUpdate +805dc11c 0x805dc11c +805dc378 Pages::FriendRoomMessages::End +805dc390 Pages::FriendRoomMessages::UpdateMessage +805dc54c Pages::FriendRoomMessages::OnMessageButtonClick +805dc654 Pages::FriendRoomMessages::OnModeButtonClick +805dc75c Pages::FriendRoomMessages::OnAddFriendsButtonClick +805dc9a4 Pages::FriendRoomMessages::OnRightArrowPress +805dcab0 Pages::FriendRoomMessages::OnLeftArrowPress +805dcbb8 Pages::FriendRoomMessages::OnBackButtonClick +805dcbf4 Pages::FriendRoomMessages::OnBackPress +805dcc0c Pages::FriendRoomWaiting::__ct +805dcc68 Pages::FriendRoomWaiting::__dt +805dccf4 Pages::FriendRoomWaiting::OnInit +805dce88 Pages::FriendRoomWaiting::OnActivate +805dd000 Pages::FriendRoomWaiting::OnDeactivate +805dd010 Pages::FriendRoomWaiting::BeforeEntranceAnimations +805dd09c Pages::FriendRoomWaiting::BeforeExitAnimations +805dd0a0 Pages::FriendRoomWaiting::AfterControlUpdate +805dd5a4 Pages::FriendRoomWaiting::OnResume +805dd964 0x805dd964 +805dd96c Pages::FriendRoomWaiting::StartRoom +805de114 Pages::Menu::GetRuntimeTypeInfo +805de120 0x805de120 +805de128 Pages::FriendRoomWaiting::IsHomeMenuWorking +805de130 Pages::FriendRoomWaiting::GetRuntimeTypeInfo +805de13c Pages::FriendRoomMessages::GetRuntimeTypeInfo +805de148 MessageSelectControl::GetRuntimeTypeInfo +805de154 Pages::FriendRoomManager::GetRuntimeTypeInfo +805de160 FriendMatchingPlayer::GetRuntimeTypeInfo +805de16c Pages::FriendRoom::GetRuntimeTypeInfo +805de178 TriggerPtmf +805de1a8 TriggerPtmf +805de1d8 TriggerPtmf +805de208 TriggerPtmf +805de238 TriggerPtmf +805de268 TriggerPtmf +805de298 FriendRoomPage_cpp_sinit_ +805de2cc Pages::GhostRaceExplanation::__ct +805de3e4 Pages::GhostRaceExplanation::__dt +805de484 Pages::GhostRaceExplanation::OnInit +805de600 Pages::GhostRaceExplanation::OnActivate +805de788 Pages::GhostRaceExplanation::GetNextPage +805de7d8 Pages::GhostRaceExplanation::OnButtonClick +805de864 Pages::GhostRaceExplanation::OnBackPress +805de8b0 Pages::GhostRaceMgr::__ct +805de934 Pages::GhostRaceMgr::__dt +805de99c Pages::GhostRaceMgr::OnInit +805deaac Pages::GhostRaceMgr::OnActivate +805debcc Pages::GhostRaceMgr::BeforeEntranceAnimations +805debd0 Pages::GhostRaceMgr::BeforeExitAnimations +805debd4 Pages::GhostRaceMgr::AfterControlUpdate +805dee1c Pages::GhostRaceMgr::OnResume +805df254 Pages::GhostRaceMgr::DownloadGhost +805df9d0 0x805df9d0 +805dfae0 0x805dfae0 +805dfc20 Pages::GhostRaceMgr::PrepareRace +805dfe18 Pages::GhostRaceMgr::OnErrorBoxClick +805dfe60 Pages::GhostRaceInfo::__ct +805dff78 Pages::GhostRaceInfo::__dt +805e0018 Pages::GhostRaceInfo::OnInit +805e0190 Pages::GhostRaceInfo::OnActivate +805e019c Pages::GhostRaceInfo::UpdateGhostInfo +805e01f4 Pages::GhostRaceInfo::OnButtonClick +805e0320 Pages::GhostRaceInfo::OnBackPress +805e03d8 Pages::GhostRaceInfo::GetRuntimeTypeInfo +805e03e4 Pages::GhostRaceMgr::GetNextPage +805e03ec Pages::GhostRaceMgr::GetRuntimeTypeInfo +805e03f8 Pages::GhostRaceExplanation::GetRuntimeTypeInfo +805e0404 TriggerPtmf +805e0434 TriggerPtmf +805e0464 TriggerPtmf +805e0494 TriggerPtmf +805e04c4 TriggerPtmf +805e04f4 GhostRacePage_cpp_sinit_ +805e0514 Pages::GhostManager::__ct +805e0594 Pages::GhostManager::__dt +805e0660 Pages::GhostManager::OnInit +805e08d8 Pages::GhostManager::OnActivate +805e09d4 Pages::GhostManager::BeforeEntranceAnimations +805e09d8 Pages::GhostManager::BeforeExitAnimations +805e09dc Pages::GhostManager::OnDeactivate +805e09e0 Pages::GhostManager::AfterControlUpdate +805e09e4 Pages::GhostManager::OnSectionChange +805e0a8c Pages::GhostManager::RequestAllGhosts +805e0af0 Pages::GhostManager::UpdateState +805e0b28 Pages::GhostManager::UpdateState_switch +805e0b2c Pages::GhostManager::UpdateState_case_1 +805e0c3c Pages::GhostManager::UpdateState_case_2 +805e0c60 Pages::GhostManager::UpdateState_case_3 +805e0c98 Pages::GhostManager::UpdateState_case_4 +805e0cd0 Pages::GhostManager::UpdateState_case_5 +805e0d08 Pages::GhostManager::UpdateState_case_6 +805e0d38 Pages::GhostManager::UpdateState_case_7 +805e0d5c Pages::GhostManager::UpdateState_case_9 +805e0d88 Pages::GhostManager::UpdateState_case_a +805e0db4 Pages::GhostManager::UpdateState_case_b +805e0de0 Pages::GhostManager::UpdateState_case_c +805e0e04 Pages::GhostManager::UpdateState_case_d +805e0e24 Pages::GhostManager::UpdateState_case_0 +805e0ea0 Pages::GhostManager::AreStaffGhostsLoading +805e0f18 0x805e0f18 +805e1024 Pages::GhostManager::PrepareRaceState +805e10a8 Pages::GhostManager::PrepareReplayState +805e10dc 0x805e10dc +805e10fc 0x805e10fc +805e1170 0x805e1170 +805e1274 Pages::GhostManager::RequestGhost +805e13e0 Pages::GhostManager::SetupGhostRace +805e1638 Pages::GhostManager::SetupGhostReplay +805e17d4 0x805e17d4 +805e18ac 0x805e18ac +805e1968 GhostList::__ct +805e1978 GhostList::__dt +805e19b8 GhostList::FillWithAllGhosts +805e1a74 GhostList::FillWithAllDLdGhosts +805e1adc GhostList::Init +805e1ba4 GhostList::Reset +805e1bb0 GhostList::FillFromGroup +805e1cf8 GhostList::Sort +805e1d0c GhostList::CompareEntries +805e1ddc GhostList::GetHeader +805e1e04 GhostList::CheckIsNew +805e1e30 GhostList::AllAreGhostsNrw +805e1e64 GhostList::SetSectionParamsGhostValues +805e1eec GhostList::EraseEntry +805e1ffc Pages::GhostManager::GetRuntimeTypeInfo +805e2008 GhostManagerPage_cpp_sinit_ +805e201c GhostInfoControl::GetClassName +805e2028 GhostInfoControl::__ct +805e20b8 GhostInfoControl::__dt +805e2120 GhostInfoControl::Load +805e2240 GhostInfoControl::InitSelf +805e2244 GhostInfoControl::OnUpdate +805e2248 GhostInfoControl::UpdateInfo +805e255c 0x805e255c +805e261c GhostInfoControl::UpdateInfoAnimate +805e267c 0x805e267c +805e26cc 0x805e26cc +805e2704 0x805e2704 +805e273c 0x805e273c +805e2774 0x805e2774 +805e27ac 0x805e27ac +805e27e4 0x805e27e4 +805e281c GhostInfoControl::GetRuntimeTypeInfo +805e2828 GhostInfoControl_cpp_sinit_ +805e283c SectionParams::__ct +805e28d4 SectionParams::__dt +805e295c SectionParams::Reset +805e2b00 SectionParams::ResetMiisGhostsAndSubs +805e2b88 SectionParams::ResetBattleParams +805e2ba0 0x805e2ba0 +805e2bc8 SectionParams::RandomizeVSTracks +805e2d48 SectionParams::SetVStracks +805e2f7c SectionParams::IsCourseUnlockedInOneCC +805e308c SectionParams::IsCupUnlockedInOneCC +805e3134 SectionParams::RandomizeBattleArenas +805e31d8 SectionParams::SetBattleArenas +805e32b4 SectionParams::CopyMiisToRacedata +805e3474 OnlineParams::ResetRaceNumberAndCC +805e3484 OnlineParams::Reset +805e3614 OnlineParams::CalcRank +805e3624 OnlineParams::SetRankBMG +805e3648 0x805e3648 +805e365c 0x805e365c +805e3674 0x805e3674 +805e3698 0x805e3698 +805e36a4 TitleParams::__ct +805e36d8 TitleParams::Reset +805e37d8 TitleParams::ForceDemo +805e37e4 0x805e37e4 +805e3828 0x805e3828 +805e3838 0x805e3838 +805e3844 SectionParams::TrackIdxToCourseId +805e387c SectionParams::CourseIdToTrackIdx +805e38d4 SectionParams::CourseIdToCupIdx +805e3950 SectionParams::ArenaIdToCupIdx +805e3984 SectionParams::ResetLicenseParams +805e3b08 Pages::Globe::__ct +805e3b9c Pages::Globe::MessageWindow::__dt +805e3bf4 Pages::Globe::__dt +805e3c78 Pages::Globe::OnInit +805e3e98 Pages::Globe::OnActivate +805e3f9c Pages::Globe::BeforeEntranceAnimations +805e3fa0 Pages::Globe::BeforeExitAnimations +805e3fa4 Pages::Globe::AfterControlUpdate +805e4990 0x805e4990 +805e4b30 0x805e4b30 +805e4e0c 0x805e4e0c +805e50cc 0x805e50cc +805e51e0 0x805e51e0 +805e52e8 Pages::Globe::SetMessage +805e56bc 0x805e56bc +805e57c0 0x805e57c0 +805e58c4 0x805e58c4 +805e59c8 0x805e59c8 +805e5b14 0x805e5b14 +805e5c60 0x805e5c60 +805e5d48 0x805e5d48 +805e5dc0 0x805e5dc0 +805e5e90 0x805e5e90 +805e5f00 0x805e5f00 +805e5f94 0x805e5f94 +805e5fe4 0x805e5fe4 +805e6020 Pages::Globe::GetFriendActivityBMG +805e603c Pages::Globe::GetFriendActivityBMG_switch +805e6040 Pages::Globe::GetFriendActivityBMG_caseD_1 +805e6048 Pages::Globe::GetFriendActivityBMG_caseD_2 +805e6050 Pages::Globe::GetFriendActivityBMG_caseD_3 +805e6058 Pages::Globe::GetFriendActivityBMG_caseD_4 +805e6060 Pages::Globe::GetFriendActivityBMG_caseD_5 +805e6068 Pages::Globe::GetFriendActivityBMG_caseD_6 +805e6070 Pages::Globe::GetFriendActivityBMG_caseD_7 +805e6078 Pages::Globe::GetFriendActivityBMG_caseD_8 +805e6080 Pages::Globe::GetFriendActivityBMG_caseD_9 +805e6088 Pages::Globe::GetFriendActivityBMG_caseD_a +805e6090 Pages::Globe::GetFriendActivityBMG_caseD_b +805e6098 Pages::Globe::GetFriendActivityBMG_caseD_c +805e60a0 Pages::Globe::GetFriendActivityBMG_caseD_d +805e60a8 Pages::Globe::GetFriendActivityBMG_caseD_e +805e60b0 Pages::Globe::GetFriendActivityBMG_caseD_f +805e60b8 Pages::Globe::GetFriendActivityBMG_caseD_10 +805e60c0 Pages::Globe::GetFriendActivityBMG_caseD_11 +805e60c8 Pages::Globe::GetFriendActivityBMG_caseD_12 +805e60d0 Pages::Globe::GetFriendActivityBMG_caseD_13 +805e60d8 Pages::Globe::GetFriendActivityBMG_caseD_14 +805e60e0 Pages::Globe::GetFriendActivityBMG_caseD_15 +805e60e8 Pages::Globe::GetFriendActivityBMG_caseD_16 +805e60f0 Pages::Globe::GetFriendActivityBMG_caseD_17 +805e60f8 Pages::Globe::GetFriendActivityBMG_caseD_18 +805e6100 Pages::Globe::GetFriendActivityBMG_caseD_19 +805e6108 Pages::Globe::GetFriendActivityBMG_caseD_1a +805e6110 Pages::Globe::GetFriendActivityBMG_caseD_0 +805e6118 Pages::Globe::MessageWindow::GetClassName +805e6128 0x805e6128 +805e620c Pages::Globe::MessageWindow::InitSelf +805e6270 0x805e6270 +805e630c 0x805e630c +805e63bc 0x805e63bc +805e63f0 Pages::Globe::GetRuntimeTypeInfo +805e63fc Pages::Globe::MessageWindow::GetRuntimeTypeInfo +805e6408 GlobePage_cpp_sinit_ +805e642c 0x805e642c +805e6478 0x805e6478 +805e64e0 0x805e64e0 +805e654c 0x805e654c +805e6604 Page::EndActivationState +805e6608 0x805e6608 +805e66b8 0x805e66b8 +805e6734 0x805e6734 +805e6afc 0x805e6afc +805e6d1c 0x805e6d1c +805e6d28 0x805e6d28 +805e6d3c PaneManager::SearchForPane +805e6dd4 PaneManager::GetParentPane +805e6ddc 0x805e6ddc +805e6fdc PaneManager::IsPaneAndParentsVisible +805e70d4 PaneManager::IsPaneVisible +805e70e0 PaneManager::SetTextBoxMessage +805e71cc PaneManager::DoAction +805e7348 PaneManager::CheckForUserInfo +805e7388 PaneManager::CheckForUserInfo2 +805e73c8 PaneManager::GetNextUserInfo +805e741c PaneManager::ConvertColorS10ToUT +805e74d0 0x805e74d0 +805e74f8 PaneManagerHolder::__dt +805e7584 PaneManagerHolder::__ct +805e7670 PicturePaneManager::__ct +805e768c TextPaneManager::__ct +805e76a8 MoviePaneManager::__ct +805e76c4 0x805e76c4 +805e76c8 PaneManagerHolder::InsertPicturePane +805e7718 PaneManagerHolder::InsertTextPane +805e7768 PaneManagerHolder::InsertMoviePane +805e77b8 PaneManagerHolder::Draw +805e7814 PicturePaneManager::Draw +805e7938 TextPaneManager::Draw +805e7a54 MoviePaneManager::Draw +805e7b70 PaneManagerHolder::InsertManager +805e7ba0 Layout::__ct +805e7be8 Layout::__dt +805e7c44 Layout::GetPaneByName +805e7c5c Layout::CreateResourceAccessor +805e7e04 Layout::Build +805e7e84 MainLayout::__ct +805e7f0c MainLayout::__dt +805e7fd0 MainLayout::CreateResourceAccessor +805e8178 MainLayout::Build +805e8904 MainLayout::GetTextPaneHandlerByName +805e897c MainLayout::GetTextPaneHandlerByPane +805e89c4 MainLayout::GetMoviePaneHandlerByName +805e8a3c MainLayout::GetMoviePaneHandlerByPane +805e8a84 MainLayout::Animate +805e8a98 MainLayout::Update +805e8b44 MainLayout::Draw +805e8bac Text::PaneHandler::Initializer::Calc +805e8cb0 MoviePaneHander::Initializer::Calc +805e8db4 PaneTypeCounter::Calc +805e8fe4 PaneManager::Initializer::Calc +805e9404 PictureLayout::__ct +805e949c PictureLayout::__dt +805e94fc PictureLayout::CreateResourceAccessor +805e96b4 PictureLayout::Build +805e9754 PictureLayout::SetPrevLayout +805e975c PictureLayout::IsLinkedToLYT +805e97c8 PictureLayoutList::__ct +805e97d4 PictureLayoutList::__dt +805e985c PictureLayoutList::Attach +805e9b68 LayoutResourceAccessorList::__ct +805e9b74 LayoutResourceAccessorList::__dt +805e9c34 LayoutFont::__dt +805e9c74 0x805e9c74 +805e9cb4 0x805e9cb4 +805e9cf4 LayoutResources::__dt +805e9d6c LayoutResourceLink::__dt +805e9dac LayoutResourceAccessorList::Attach +805e9f48 LayoutResourceAccessor::Init +805ea04c LayoutResourceLink::__ct +805ea05c 0x805ea05c +805ea060 0x805ea060 +805ea0a0 0x805ea0a0 +805ea0f4 LicenseControl::GetClassName +805ea100 LicenseButton::GetClassName +805ea110 Pages::LicenseSelect::__ct +805ea348 LicenseButton::__ct +805ea384 LicenseButton::__dt +805ea3dc Pages::LicenseSelect::__dt +805ea494 Pages::LicenseSelect::OnInit +805ea770 Pages::LicenseSelect::SetControlMii +805eb050 Pages::LicenseSelect::OnActivate +805eb074 Pages::LicenseSelect::OnResume +805eb078 Pages::LicenseSelect::AfterControlUpdate +805eb07c Pages::LicenseSelect::OnLicenseButtonClick +805eb420 Pages::LicenseSelect::OnOptionsButtonClick +805eb568 Pages::LicenseSelect::OnBackButtonClick +805eb5ac Pages::LicenseSelect::OnBackPress +805eb5c4 Pages::LicenseSelect::OnNewLicenseApprove +805eb620 Pages::LicenseSelect::OnNewLicenseDisapprove +805eb67c Pages::LicenseSelect::OnNewLicenseBack +805eb688 Pages::LicenseChangeMii::__ct +805eb7ec LicenseControl::__dt +805eb844 Pages::LicenseChangeMii::__dt +805eb8e4 Pages::LicenseChangeMii::OnInit +805ebb50 Pages::LicenseChangeMii::OnActivate +805ebdc4 Pages::LicenseChangeMii::SetControlMii +805ec6a4 Pages::LicenseChangeMii::UpdateMiiGroup +805ec6b4 Pages::LicenseChangeMii::PrepareMessageBox +805ec808 0x805ec808 +805ec8cc 0x805ec8cc +805eca48 0x805eca48 +805ecbb0 Pages::LicenseChangeMii::OnClick +805ecd2c Pages::LicenseChangeMii::OnMiiApprove +805ecd38 Pages::LicenseChangeMii::OnMiiDisapprove +805ecd44 Pages::LicenseChangeMii::OnMessageBoxClick +805ecdc8 Pages::LicenseSettings::__ct +805ecfe8 Pages::LicenseSettings::__dt +805ed0c0 Pages::LicenseSettings::OnInit +805ed4d4 Pages::LicenseSettings::OnActivate +805ed52c Pages::LicenseSettings::OnRecordsButtonClick +805ed570 Pages::LicenseSettings::OnChangeMiiButtonClick +805ed5b4 Pages::LicenseSettings::OnEraseLicenseButtonClick +805ed5f8 Pages::LicenseSettings::OnBackPress +805ed644 Pages::LicenseSettings::OnSelectButton +805ed6b0 Pages::LicenseSettings::OnBackPress +805ed6d0 Pages::LicenseErase::__ct +805ed860 Pages::LicenseErase::__dt +805ed90c Pages::LicenseErase::OnInit +805edb14 Pages::LicenseErase::OnActivate +805edb20 Pages::LicenseErase::OnResume +805edcf8 Pages::LicenseErase::GetNextPage +805edd10 Pages::LicenseErase::OnYesButtonClick +805ede54 Pages::LicenseErase::OnNoButtonClick +805edea8 Pages::LicenseErase::OnBackPress +805edeb8 Pages::LicenseErase::OnErasedLicense +805edf00 Pages::LicenseErase::GetRuntimeTypeInfo +805edf0c Pages::LicenseSettings::GetNextPage +805edf14 Pages::LicenseSettings::GetRuntimeTypeInfo +805edf20 Pages::LicenseChangeMii::GetNextPage +805edf28 Pages::LicenseChangeMii::GetRuntimeTypeInfo +805edf34 Pages::LicenseSelect::GetNextPage +805edf3c Pages::LicenseSelect::GetRuntimeTypeInfo +805edf48 LicenseButton::GetRuntimeTypeInfo +805edf54 LicenseControl::GetRuntimeTypeInfo +805edf60 LicenseUI_cpp_sinit_ +805edf90 TriggerPtmf +805edfc0 TriggerPtmf +805edff0 TriggerPtmf +805ee020 TriggerPtmf +805ee050 TriggerPtmf +805ee080 TriggerPtmf +805ee0b0 TriggerPtmf +805ee0e0 TriggerPtmf +805ee110 TriggerPtmf +805ee140 TriggerPtmf +805ee170 0x805ee170 +805ee1ac MiiNameMsgPrinter::__ct +805ee1dc MiiNameMsgPrinter::__dt +805ee234 MiiNameMsgPrinter::Load +805ee354 MiiNameMsgPrinter::PrintMessage +805ee444 ManipulatorManager::__ct +805ee468 ManipulatorManager::__dt +805ee4a8 ManipulatorManager::Init +805ee52c ManipulatorManager::UpdatePlayerBitfield2 +805ee534 ManipulatorManager::CheckActions +805ee538 ManipulatorManager::Activate +805ee5c4 ManipulatorManager::OnLoad +805ee64c ManipulatorManager::Load +805ee660 ManipulatorManager::OnReset +805ee674 ManipulatorManager::Update +805ee6e8 ManipulatorManager::GetControllerHolder +805ee700 ButtonInfo::__ct +805ee7ac ButtonInfo::__dt +805ee7ec ButtonInfo::Reset +805ee7fc ButtonInfo::Update +805eea14 ButtonInfo::Init +805eea98 0x805eea98 +805eeb1c PageManipulatorManager::__ct +805eebd8 PageManipulatorManager::__dt +805eec40 PageManipulatorManager::Init +805eed18 PageManipulatorManager::CheckActions +805eee84 PageManipulatorManager::Activate +805eef64 PageManipulatorManager::OnReset +805ef044 PageManipulatorManager::SetGlobalHandler +805ef05c ControlButtonInfo::__ct +805ef124 ControlButtonInfo::__dt +805ef164 ControlButtonInfo::Reset +805ef174 ControlButtonInfo::Update +805ef234 ControlButtonInfo::Init +805ef2c8 ControlButtonInfo::LockNonDirectionalActions +805ef34c ControlButtonInfo::IsADirectionHeldForMultipleOf15 +805ef3b8 ControlButtonInfo::GetFramesOnCurControl +805ef3d4 ControlManipulator::__ct +805ef4b0 ControlManipulator::__dt +805ef51c 0x805ef51c +805ef524 ControlManipulator::Init +805ef5d4 ControlManipulator::SetAction +805ef5ec 0x805ef5ec +805ef5f0 ControlManipulator::SetEnabledHudSlots +805ef5f8 0x805ef5f8 +805ef6a4 ControlManipulator::HasDirectionalHandler +805ef71c ControlManipulator::TriggerAction +805ef770 0x805ef770 +805ef7d0 ControlManipulator::Load +805ef91c ControlManipulator::Update +805efcb8 ControlManipulator::GetHudColor +805efd1c ControlManipulator::GetHudSlotIdColor +805efdb4 ControlManipulator::GetHudSlotIdColorSingle +805efe68 ControlBoundingBox::__ct +805efea8 ControlBoundingBox::__dt +805efee8 0x805efee8 +805efef0 0x805efef0 +805efef4 ControlBoundingBox::CalculateBounds +805f017c ControlBoundingBox::TriggerOnSelectHandler +805f01cc ControlBoundingBox::TriggerOnDeselectHandler +805f021c 0x805f021c +805f0284 ControlsManipulatorManager::__ct +805f0374 ControlManipulatorHolder::__ct +805f0470 ControlManipulatorHolder::__dt +805f04b0 ControlsManipulatorManager::__dt +805f0524 ControlsManipulatorManager::Init +805f0614 ControlManipulator::CalcDistanceBothWrapping +805f0620 ControlsManipulatorManager::AddControlManipulator +805f0660 ControlsManipulatorManager::SetGlobalHandler +805f067c ControlsManipulatorManager::SetControlManipulator +805f0690 ControlsManipulatorManager::SetDistanceFunc +805f06f4 ControlManipulator::CalcDistanceVerticalWrappingOnly +805f0700 ControlManipulator::CalcDistanceNoWrapping +805f070c ControlsManipulatorManager::GetHolderList +805f0770 ControlsManipulatorManager::CheckActions +805f149c ControlsManipulatorManager::Activate +805f15d0 ControlsManipulatorManager::OnLoad +805f16f0 ControlsManipulatorManager::OnReset +805f1818 ControlsManipulatorManager::OnActivate +805f181c ControlsManipulatorManager::Update +805f19c8 ControlsManipulatorManager::SetChildControlManipulator +805f19dc ControlsManipulatorManager::InitHolders +805f1a10 ControlsManipulatorManager::IsActionAllowed +805f1a48 ControlsManipulatorManager::HasDirectionalGlobalHandler +805f1ac0 ControlsManipulatorManager::Func_805f21e4 +805f1b48 ControlsManipulatorManager::Func_805f226c +805f1bb0 ControlsManipulatorManager::CheckPlayerPointer +805f1c60 ControlManipulator::CalcDistance +805f1d28 ControlManipulator::CalcDistance_Switch +805f1d2c ControlManipulator::CalcDistance_Case_1 +805f1f80 ControlManipulator::CalcDistance_Case_5 +805f2208 ControlManipulator::CalcDistance_Case_0 +805f2224 ControlManipulator::CalcDistanceLinear +805f23c4 ControlManipulator::CalcDistanceLinear_Switch +805f23c8 ControlManipulator::CalcDistanceLinear_case_1 +805f2418 ControlManipulator::CalcDistanceLinear_case_4 +805f2468 ControlManipulator::CalcDistanceLinear_case_5 +805f24c8 ControlManipulator::CalcDistanceLinear_case_6 +805f2528 ControlManipulator::CalcDistanceLinear_case_0 +805f2540 0x805f2540 +805f25b0 ControlsManipulatorManager:IsWiimoteCursorEnabled +805f25b8 ControlsManipulatorManager::GetRuntimeTypeInfo +805f25c4 ManipulatorManager::IsPointerEnabled +805f25cc ManipulatorManager::OnActivate +805f25d0 ManipulatorManager::GetHolderList +805f25d4 PageManipulatorManager::GetRuntimeTypeInfo +805f25e0 0x805f25e0 +805f2600 BackGroundModelControl::GetClassName +805f260c BackGroundModelControl::__ct +805f2648 BackGroundModelControl::__dt +805f26a0 BackGroundModelControl::Load +805f2760 BackGroundModelControl::RequestModel +805f2780 BackGroundModelControl::InitSelf +805f2784 BackGroundModelControl::OnUpdate +805f2b14 DriverModelControl::GetClassName +805f2b24 DriverModelControl::__ct +805f2b60 DriverModelControl::__dt +805f2bb8 DriverModelControl::Load +805f2d48 DriverModelControl::SetAnimationType +805f2d70 DriverModelControl::RequestModel +805f2e44 DriverModelControl::InitSelf +805f2e48 DriverModelControl::OnUpdate +805f30c0 DriverModelControl::SetPositionAnim +805f310c DriverModelControl::SetModelPositionOnAnim +805f3288 VehicleModelControl::GetClassName +805f3298 VehicleModelControl::__ct +805f32d4 VehicleModelControl::__dt +805f332c VehicleModelControl::Load +805f3474 VehicleModelControl::SetAnimationType +805f34a0 VehicleModelControl::RequestNewModel +805f3568 VehicleModelControl::InitSelf +805f35d4 VehicleModelControl::OnUpdate +805f3980 VehicleModelControl::SetPositionAnim +805f39ec VehicleModelControl::SetModelPositionOnAnim +805f3b80 NoteModelControl::GetClassName +805f3b90 NoteModelControl::__ct +805f3bcc NoteModelControl::__dt +805f3c24 NoteModelControl::Load +805f3d7c NoteModelControl::SetAnimationType +805f3d9c NoteModelControl::InitSelf +805f3ed4 NoteModelControl::OnUpdate +805f45d8 NoteModelControl::SetPositionAnim +805f4728 NoteModelControl::SetModelPositionOnAnim +805f4858 NoteModelControl::GetRuntimeTypeInfo +805f4864 VehicleModelControl::GetRuntimeTypeInfo +805f4870 DriverModelControl::GetRuntimeTypeInfo +805f487c BackGroundModelControl::GetRuntimeTypeInfo +805f4888 ModelControl_cpp_sinit_ +805f48ac Pages::ModelRenderer::__ct +805f4aa4 Pages::ModelRenderer::__dt +805f4b0c Pages::ModelRenderer::OnInit +805f4de0 Pages::ModelRenderer::OnDispose +805f4dfc Pages::ModelRenderer::OnActivate +805f4fb0 Pages::ModelRenderer::BeforeEntranceAnimations +805f4fb4 Pages::ModelRenderer::BeforeExitAnimations +805f4fb8 Pages::ModelRenderer::BeforeControlUpdate +805f4fbc Pages::ModelRenderer::RequestCharacterModel +805f4fe8 Pages::ModelRenderer::LoadKartModelsByCharacter +805f5094 0x805f5094 +805f5234 Pages::ModelRenderer::RequestKartModel +805f5260 Pages::ModelRenderer::RequestBackgroundModel +805f5288 0x805f5288 +805f530c Pages::ModelRenderer::SetBackgroundModelVisibility +805f5328 Pages::ModelRenderer::GetModelTexObj +805f534c Pages::ModelRenderer::GetBackgroundModelTexObj +805f5374 Pages::ModelRenderer::GetVariantType +805f5570 Pages::ModelRenderer::PrepareParams +805f5634 Pages::ModelRenderer::GetModelCount +805f5704 ModelRendererParams::Reset +805f5720 0x805f5720 +805f5880 ModelValuesHolder::GetValues +805f58b8 Pages::ModelRenderer::GetRuntimeTypeInfo +805f58c4 ModelRendererPage_cpp_sinit_ +805f58d8 ModelRendererValuesHolder::Init +805f8400 ModelRendererValues::SetValues +805f8410 BMGHolder::__ct +805f842c BMGHolder::__dt +805f846c BMGHolder::Load +805f84dc BMGHolder::Init +805f8564 BMGHolder::GetMsgId +805f85cc BMGHolder::GetMessageById +805f8608 BMGHolder::GetFontIndex +805f8638 Pages::Click::__ct +805f86bc Pages::Click::__dt +805f8724 Pages::Click::OnInit +805f8794 Pages::Click:::OnLoad +805f87b8 Pages::Click::AfterControlUpdate +805f881c Pages::Click::Reset +805f8830 Pages::Click::OnClick +805f8888 Pages::MessageBoxTransparent::__ct +805f8930 Pages::MessageBoxTransparent::__dt +805f89c4 Pages::MessageBoxTransparent::OnInit +805f8b00 Pages::MessageBoxTransparent::Reset +805f8b20 Pages::MessageBoxTransparent::SetMessageWindowText +805f8b28 Pages::MessageBoxTransparent::BeforeEntranceAnimations +805f8b6c Pages::MessageBox::AfterExitAnimations +805f8bb0 Pages::MessageBoxTransparent::SetButtonImage +805f8bf8 Pages::MessageBox::__ct +805f8cb8 Pages::MessageBox::__dt +805f8d50 Pages::MessageBox::OnInit +805f8e9c Pages::MessageBox::Reset +805f8efc Pages::MessageBox::SetTitleText +805f8f04 Pages::MessageBox::SetMessageWindowText +805f8f0c Pages::MessageBox::SetButtonImage +805f8f54 Pages::MessageBox::GetNextPage +805f8f5c Pages::MessageBox::GetRuntimeTypeInfo +805f8f68 Pages::MessageBoxTransparent::GetRuntimeTypeInfo +805f8f74 Pages::Click::GetRuntimeTypeInfo +805f8f80 Pages::Click::TriggerPtmf +805f8fb0 MessagePagecpp_sinit_ +805f8fd0 MessageWindowControl::GetClassName +805f8fdc MessageWindowControl::__ct +805f9018 MessageWindowControl::__dt +805f9070 MessageWindowControl::Load +805f90ec MessageWindowControlScaleFade::GetClassName +805f90fc MessageWindowControlScaleFade::__ct +805f9138 MessageWindowControlScaleFade::__dt +805f9194 MessageWindowControlScaleFade::SetPositionAnim +805f91cc 0x805f91cc +805f91dc SimpleMessageWindowControl::__ct +805f9218 SimpleMessageWindowControl::__dt +805f9270 SimpleMessageWindowControl::Load +805f9324 SimpleMessageWindowControl::InitSelf +805f9388 BlackBackControlForMessage::GetClassName +805f9398 BlackBackControlForMessage::__ct +805f93d4 BlackBackControlForMessage::__dt +805f942c BlackBackControlForMessage::Load +805f94a0 BlackBackControlForMessage::SetPositionAnim +805f9500 BusySymbol::GetClassName +805f9510 BusySymbol::__ct +805f954c BusySymbol::__dt +805f95a4 BusySymbol::Load +805f9638 BusySymbol::InitSelf +805f9670 BusySymbol::SetPositionAnim +805f96d0 BusySymbol::OnUpdate +805f96ec BusySymbol::GetRuntimeTypeInfo +805f96f8 BlackBackControlForMessage::GetRuntimeTypeInfo +805f9704 SimpleMessageWindowControl::GetRuntimeTypeInfo +805f9710 MessageWindowControlScaleFade::GetRuntimeTypeInfo +805f971c MessageWindowControl::GetRuntimeTypeInfo +805f9728 0x805f9728 +805f9754 MiiGroup::__ct +805f97f4 MiiCreationParams2::__dt +805f9834 MiiGroup::__dt +805f9928 MiiGroup::Init +805f9c4c MiiGroup::Reset +805f9ca0 MiiGroup::ResetCreationParams +805f9cd8 MiiGroup::AddMii +805f9e5c MiiGroup::LoadMiddleDB2Mii +805f9eec MiiGroup::LoadMii(RFLStoreData) +805f9f54 MiiGroup::LoadOfficialMii +805f9fbc MiiGroup::LoadStoreMii +805fa024 MiiGroup::LoadDefaultMii +805fa08c 0x805fa08c +805fa194 MiiGroup::ReplaceMiiByPlayerMii +805fa20c MiiGroup::GetMii +805fa21c 0x805fa21c +805fa240 MiiGroup::GetMiiTexObj +805fa258 MiiGroup::HasAllMiiTexObjs +805fa360 MiiGroup::DeleteMii +805fa484 0x805fa484 +805fa4d0 MiiGroup::CopyMii +805fa810 MiiGroup::CopyMiiToOtherGroup +805fac68 0x805fac68 +805fada8 0x805fada8 +805fade0 0x805fade0 +805fae18 0x805fae18 +805fae34 0x805fae34 +805fae94 0x805fae94 +805fae98 Pages::BackModel::__ct +805faeec Pages::BackModel::__dt +805faf6c Pages::BackModel::OnInit +805fb088 Pages::BackModel::OnInit_switch +805fb08c Pages::BackModel::OnInit_case_60 +805fb09c Pages::BackModel::OnInit_case_49 +805fb0ac Pages::BackModel::OnInit_case_4b +805fb0bc Pages::BackModel::OnInit_case_4c +805fb0c8 Pages::BackModel::OnInit_case_4d +805fb0dc Pages::BackModel::GetRuntimeTypeInfo +805fb0e8 BackModelPage_cpp_sinit_ +805fb0fc MoviePaneHandler::__ct +805fb12c MoviePaneHandler::__dt +805fb16c MoviePaneHandler::Init +805fb278 MoviePaneHandler::Crop(Rect*) +805fb344 MoviePaneHandler::Crop(4floats) +805fb43c MoviePaneHandler::Draw +805fc61c MoviePlayer::__ct +805fc66c MoviePlayer::__dt +805fc6c4 MoviePlayer::Init +805fc6c8 MoviePlayer::Quit +805fc758 MoviePlayer::Update +805fc984 MoviePlayer::Prepare +805fcbf8 0x805fcbf8 +805fcc74 MoviePlayer::Close +805fccbc MoviePlayer::GetCurTHPTextureInfo +805fccd8 MoviePlayer::IsPlaying +805fcd14 MoviePlayer::Pause +805fcd30 MoviePlayer::Play +805fcd4c MoviePlayer::GetCurTextureIdx +805fcd54 MoviePlayer::Reprepare +805fcda0 0x805fcda0 +805fcdf4 Pages::Options::__ct +805fcf14 Pages::Options::__dt +805fcfc0 Pages::Options::OnInit +805fd1c0 Pages::Options::OnDispose +805fd1c4 Pages::Options::OnActivate +805fd1e8 Pages::Options::OnButtonClick +805fd35c Pages::Options::OnBackPress +805fd384 Pages::WifiOptions::__ct +805fd4b4 Pages::WifiOptions::__dt +805fd578 Pages::WifiOptions::OnInit +805fd810 Pages::WifiOptions::OnActivate +805fd834 Pages::WifiOptions::OnButtonClick +805fd9ec Pages::WifiOptions::OnBackPress +805fda04 Pages::OptionExplanation::__ct +805fdb1c Pages::OptionExplanation::__dt +805fdbbc Pages::OptionExplanation::OnInit +805fdd3c Pages::OptionExplanation::OnActivate +805fdd68 Pages::OptionExplanation::OnButtonClick +805fde58 Pages::OptionExplanation::OnBackPress +805fded4 Pages::OptionChoice::__ct +805fe004 Pages::OptionChoice::__dt +805fe0b0 Pages::OptionChoice::OnInit +805fe334 Pages::OptionChoice::OnActivate +805fe364 Pages::OptionChoice::OnResume +805fe43c Pages::OptionChoice::SetTitleText +805fe448 Pages::OptionChoice::SetMessageWindowText +805fe454 Pages::OptionChoice::SetButtonText +805fe4b8 Pages::OptionChoice::SetInitialButton +805fe4c0 Pages::OptionChoice::OnButtonClick +805fe668 Pages::OptionChoice::OnBackPress +805fe680 Pages::RegionOptions::__ct +805fe7d8 Pages::RegionOptions::__dt +805fe878 Pages::RegionOptions::OnInit +805fea04 Pages::RegionOptions::OnActivate +805fea10 Pages::RegionOptions::GetNextPage +805fea70 Pages::RegionOptions::OnButtonClick +805feabc Pages::RegionOptions::OnBackButtonClick +805feb7c Pages::RegionOptions::OnBackPress +805fec04 Pages::MasterOptions::__ct +805fec80 Pages::MasterOptions::__dt +805fece8 Pages::MasterOptions::OnInit +805fed54 Pages::MasterOptions::OnActivate +805fedb4 Pages::MasterOptions::BeforeEntranceAnimations +805fedb8 Pages::MasterOptions::BeforeExitAnimations +805fedbc Pages::MasterOptions::AfterControlUpdate +805fefa0 Pages::MasterOptions::OnResume +805fefe0 0x805fefe0 +805ff184 0x805ff184 +805ff224 0x805ff224 +805ff7f0 Pages::MasterOptions::OnResume_case4 +805ff818 Pages::MasterOptions::OnResume_case5 +805ff820 Pages::MasterOptions::OnResume_case7 +805ff848 Pages::MasterOptions::OnResume_case8 +805ff850 Pages::MasterOptions::OnResume_case9 +805ff860 Pages::MasterOptions::OnResume_case3 +805ff87c Pages::MasterOptions::SetNextPageType +805ff8e0 Pages::MasterOptions::LoadOptionFirstExplanation +805ffa9c Pages::MasterOptions::LoadOptionNextExplanation +805ffb98 Pages::MasterOptions::LoadOptionChoice +80600198 0x80600198 +80600534 Pages::MasterOptions::LoadOptionChoiceSavedNetwork +80600604 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_switch +80600608 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case1 +80600610 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case2 +80600618 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case3 +80600620 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case4 +80600628 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case5 +80600630 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case6 +80600638 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case8 +80600640 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case9 +80600648 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case7 +80600670 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case0 +806006fc Pages::MasterOptions::OnClick +80600788 Pages::MasterOptions::GetNextPage +80600790 Pages::MasterOptions::GetRuntimeTypeInfo +8060079c Pages::RegionOptions::GetRuntimeTypeInfo +806007a8 Pages::OptionChoice::GetRuntimeTypeInfo +806007b4 Pages::OptionExplanation::GetRuntimeTypeInfo +806007c0 Pages::WifiOptions::GetNextPage +806007c8 Pages::WifiOptions::GetRuntimeTypeInfo +806007d4 Pages::Options::GetNextPage +806007dc Pages::Options::GetRuntimeTypeInfo +806007e8 Pages::RegionOptions::TriggerPtmf +80600818 Pages::OptionChoice::TriggerPtmf +80600848 Pages::OptionExplanation::TriggerPtmf +80600878 Pages::WifiOptions::TriggerPtmf +806008a8 Pages::Options::TriggerPtmf +806008d8 Pages::MasterOptions::TriggerPtmf +80600908 Pages::RegionOptions::TriggerBackPtmf +80600938 Pages::OptionChoice::TriggerBackPtmf +80600968 Pages::OptionExplanation::TriggerBackPtmf +80600998 Pages::WifiOptions::TriggerBackPtmf +806009c8 Pages::Options::TriggerBackPtmf +806009f8 Optionscpp_sinit_ +80600a24 PadControl::GetClassName +80600a30 PadControl::__ct +80600a6c PadControl::__dt +80600ac4 PadControl::Load +80600b84 PadControl::InitSelf +80600bf0 PadControl::OnUpdate +80600cc8 PadControl::SetParams +80600cd8 PadControl::SetPadID +80600ce0 PadControl::RegisterPad +80600d18 PadControl::UpdateFromParams +80600e70 0x80600e70 +80600e80 0x80600e80 +80600ebc 0x80600ebc +80600f18 0x80600f18 +80600f48 RecognizePadWindow::GetClassName +80600f58 RecognizePadWindow::__ct +80600f94 RecognizePadWindow::__dt +80600fec RecognizePadWindow::Load +80601068 RecognizePadWindow::InitSelf +8060106c RecognizePadWindow::OnUpdate +80601070 RecognizePadWindow::SetPositionAnim +806010a8 RecognizePadWindow::GetRuntimeTypeInfo +806010b4 0x806010b4 +806010c0 PadControl::GetRuntimeTypeInfo +806010cc PadControl_sinit_ +806010f0 Page::__ct +80601178 Page::__dt +806011d4 Page::Init +8060124c Page::OnInit +80601250 Page::Dispose +80601260 Page::Activate +8060137c Page::Deactivate +806013bc Page::IncrementDuration +806013d8 Page::CheckActions +80601498 Page::UpdateState +806016b8 Page::Exit +806018b8 Page::Enter +80601a40 Page::UpdateControls +80601aac Page::Update +80601ad0 Page::Draw +80601aec Page::ResetManipulatorManager +80601b00 0x80601b00 +80601b04 Page::Resume +80601b9c Page::HandleSectionChange +80601bc0 Page::SetAnimDirection +80601bd0 Page::InitControlGroup +80601be0 Page::AddControl +80601be8 Page::SetManipulatorManager +80601bf0 Page::EndState +80601bfc Page::EndStateAnimated +80601c18 Page::EndExitState +80601c24 Page::ChangeSectionBySceneChange +80601ca4 Page::ChangeSectionByReinit +80601d24 Page::AddPageLayer +80601dd0 Page::AnimateControls +80601f20 Page::ControlAnimator::Calc +80602040 Pages::System::GetAnimDelay +80602094 Page::MaxAnimDelayGetter::Calc +806020d4 Page::OnStateChangeAnimator::Calc +806020e4 Page::StartEntrance +80602168 Page::EndEntrance +80602278 Page::StartExit +806023d4 Page::EndExit +8060245c Page::80602ce8 +8060246c Page::PlaySound +80602480 0x80602480 +80602494 Page::SetTransitionSound +806024a0 Pages::System::__ct +80602534 Pages::System::__dt +806025c8 Pages::System::Setup +80602660 Pages::System::CheckForConditions +80602668 SystemPagecpp_sinit_ +80602678 Pages::RegisteredPads::__ct +806026dc Pages::RegisteredPads::__dt +8060275c Pages::RegisteredPads::OnInit +80602850 Pages::RegisteredPads::OnActivate +806029c4 Pages::RegisteredPads::BeforeEntranceAnimations +806029c8 Pages::RegisteredPads::AfterEntranceAnimations +806029cc Pages::RegisteredPads::AfterControlUpdate +80602a78 Pages::RegisteredPads::AfterExitAnimations +80602a7c Pages::RegisteredPads::GetNextPage +80602ac4 Pages::RegisteredPads::Register +80602b2c ConnectController::GetClassName +80602b3c ConnectController::__ct +80602b78 ConnectController::__dt +80602bd0 ConnectController::Load +80602d4c ConnectController::InitSelf +80602e04 ConnectController::OnUpdate +80602ed8 Pages::RegisterPad::__ct +80603004 CtrlMenuDummyBack::__dt +8060305c Pages::RegisterPad::__dt +80603118 Pages::RegisterPad::OnInit +80603304 Pages::RegisterPad::OnActivate +80603318 Pages::RegisterPad::AfterControlUpdate +80603684 Pages::RegisterPad::GetNextPage +8060369c Pages::RegisterPad::IsDVDEnabled +806036e4 Pages::RegisterPad::OnBackPress +80603730 Pages::RegisterPad::OnStartPress +806037e8 EasyPairingController::GetClassName +806037f8 EasyPairingController::__ct +80603834 EasyPairingController::__dt +8060388c EasyPairingController::Load +80603a1c EasyPairingController::InitSelf +80603b2c EasyPairingController::OnUpdate +80603c8c 0x80603c8c +80603cf8 Pages::PairWiimotes::__ct +80603dac Pages::PairWiimotes::__dt +80603e50 Pages::PairWiimotes::OnInit +806040b4 Pages::PairWiimotes::OnActivate +80604134 Pages::PairWiimotes::AfterEntranceAnimations +80604140 Pages::PairWiimotes::BeforeEntranceAnimations +8060414c Pages::PairWiimotes::BeforeExitAnimations +80604158 Pages::PairWiimotes::OnDeactivate +806041fc Pages::PairWiimotes::AfterControlUpdate +80604274 Pages::PairWiimotes::SyncWiimotes +806043f8 Pages::PairWiimotes::OnBackAndStartPress +8060444c Pages::ConfirmPads::__ct +80604614 Pages::ConfirmPads::__dt +806046c4 Pages::ConfirmPads::OnInit +8060490c Pages::ConfirmPads::OnActivate +80604958 Pages::ConfirmPads::OnDeactivate +80604978 Pages::ConfirmPads::OnOkButtonClick +806049d4 Pages::ConfirmPads::OnChangeButtonClick +80604ab4 Pages::ConfirmPads::OnBackButtonClick +80604be4 Pages::ConfirmPads::OnButtonSelect +80604c38 Pages::ConfirmPads::OnBackPress +80604d40 Pages::ConfirmPads::GetNextPage +80604d48 Pages::ConfirmPads::GetRuntimeTypeInfo +80604d54 Pages::PairWiimotes::GetRuntimeTypeInfo +80604d60 EasyPairingController::GetRuntimeTypeInfo +80604d6c Pages::RegisterPad::IsHomeMenuWorking +80604d74 Pages::RegisterPad::GetRuntimeTypeInfo +80604d80 ConnectController::GetRuntimeTypeInfo +80604d8c Pages::RegisterPad::GetRuntimeTypeInfo +80604d98 TriggerPtmf +80604dc8 TriggerPtmf +80604df8 TriggerPtmf +80604e28 TriggerPtmf +80604e58 RegisterPadPage_cpp_sinit_ +80604e8c RadioButtonControl::GetClassName +80604e98 RadioButtonControl::__ct +8060503c RadioButtonControl::__dt +806050c0 RadioButtonControl::Load +806054c4 RadioButtonControl::OnLoadingEnd +806054c8 RadioButtonControl::SetOnClickHandler +806054d0 RadioButtonControl::SetOnSelectHandler +806054d8 RadioButtonControl::SetOnDeselectHandler +806054e0 RadioButtonControl::SetOnChangeHandler +806054e8 RadioButtonControl::SelectInitialButton +80605570 0x80605570 +80605590 0x80605590 +80605628 0x80605628 +80605698 RadioButtonControl::Init +80605874 RadioButtonControl::Update +80605a4c RadioButtonControl::HandleSelect +80605ba8 RadioButtonControl::HandleDeselect +80605cdc RadioButtonControl::HandleButtonSelect +80605d94 RadioButtonControl::HandleClick +80605e48 RadioButtonControl::HandleRightPress +80605f04 RadioButtonControl::HandleLeftPress +80605fbc RadioButtonControl::OptionButton::GetClassName +80605fcc RadioButtonControl::OptionButton::__ct +80606008 RadioButtonControl::OptionButton::__dt +80606060 RadioButtonControl::OptionButton::Load +80606108 RadioButtonControl::OptionButton::Init +80606188 RadioButtonControl::OptionButton::Update +80606244 RadioButtonControl::OptionButton::GetParentControl +80606344 GetInstanceUnusedControl? +80606350 GetInstanceUnusedControl? +8060635c 0x8060635c +806063bc RadioButtonControl::OptionButton::ToggleChose +80606538 0x80606538 +80606598 RadioButtonControl::OptionButton::ToggleSelect +806066fc RadioButtonControl::OptionButton::SetBorderColours +806067b0 RadioButtonControl::OptionButton::SetColor_BaseColours +80606858 RadioButtonControl::Func_0x40 +8060685c RadioButtonControl::GetRuntimeTypeInfo +80606868 RadioButtonControl::OptionButton::GetRuntimeTypeInfo +80606874 RadioButtonControl_cpp_sinit_ +806068a4 RadioButtonControl_cpp_sinit_ +806068c0 RandomMatchingPlayer::GetClassName +806068cc RandomMatchingPlayer::__ct +80606940 RandomMatchingPlayer::__dt +80606998 RandomMatchingPlayer::Load +80606adc RandomMatchingPlayer::InitSelf +80606c34 RandomMatchingPlayer::OnUpdate +80606ea4 0x80606ea4 +80606fe0 0x80606fe0 +80607098 0x80607098 +80607130 0x80607130 +806072b4 0x806072b4 +806072cc RandomMatchingPlayer::SetMii +80607358 RandomMatchingPlayer::IsShowing +80607390 RandomMatchingPlayer::OnMiiShowing +80607450 RandomMatchingPlayer::CalcAngle +806074a0 0x806074a0 +806074fc MatchingMessageWindow::GetClassName +8060750c MatchingMessageWindow::__ct +80607548 MatchingMessageWindow::__dt +806075a0 MatchingMessageWindow::Load +80607604 MatchingMessageWindow::InitSelf +80607668 MatchingMessageWindow::OnUpdate +8060766c MatchingMessageWindow::SetMessage +80607724 MatchingMessageWindow::Hide +806077d4 Pages::GlobeSearch::__ct +80607908 Pages::GlobeSearch::__dt +806079dc Pages::GlobeSearch::OnInit +80607c08 Pages::GlobeSearch::OnActivate +8060848c Pages::GlobeSearch::BeforeEntranceAnimations +80608490 Pages::GlobeSearch::BeforeExitAnimations +806084e0 Pages::GlobeSearch::BeforeControlUpdate +80608a34 Pages::GlobeSearch::AfterControlUpdate +806091a4 Pages::GlobeSearch::OnResume +8060942c 0x8060942c +8060946c 0x8060946c +806095f8 Pages::GlobeSearch::PrepareLiveView +80609b80 0x80609b80 +80609dcc 0x80609dcc +80609de4 Pages::GlobeSearch::GetNextPage +80609dec Pages::GlobeSearch::IsHomeMenuWorking +80609df4 Pages::GlobeSearch::GetRuntimeTypeInfo +80609e00 MatchingMessageWindow::GetRuntimeTypeInfo +80609e0c RandomMatchingPlayer::GetRuntimeTypeInfo +80609e18 TriggerPtmf +80609e48 TriggerPtmf +80609e78 __sinit_RandomMatchingPage_cpp +80609ea0 RankingDetailItem_getTypeName +80609eac RankingDetailItem_ct +80609ee8 RankingDetailPage_dt +80609f40 0x80609f40 +8060a064 0x8060a064 +8060a09c 0x8060a09c +8060a248 0x8060a248 +8060a4ac RankingDetailPage_ct +8060a5d4 0x8060a5d4 +8060a688 0x8060a688 +8060a92c 0x8060a92c +8060a970 0x8060a970 +8060a974 0x8060a974 +8060aa7c 0x8060aa7c +8060ad60 0x8060ad60 +8060ad84 0x8060ad84 +8060adc4 0x8060adc4 +8060af10 0x8060af10 +8060b2cc 0x8060b2cc +8060b450 0x8060b450 +8060b48c 0x8060b48c +8060b49c 0x8060b49c +8060b500 0x8060b500 +8060b524 0x8060b524 +8060b564 0x8060b564 +8060b5cc 0x8060b5cc +8060b654 0x8060b654 +8060b704 0x8060b704 +8060b850 0x8060b850 +8060b9a8 0x8060b9a8 +8060bc80 0x8060bc80 +8060bcb0 0x8060bcb0 +8060bcbc 0x8060bcbc +8060bf18 0x8060bf18 +8060c330 0x8060c330 +8060c6e0 0x8060c6e0 +8060c7f8 0x8060c7f8 +8060c95c 0x8060c95c +8060c968 0x8060c968 +8060c974 0x8060c974 +8060c980 TriggerPtmf +8060c9b0 TriggerPtmf +8060c9e0 0x8060c9e0 +8060ca08 0x8060ca08 +8060cb80 0x8060cb80 +8060cc28 0x8060cc28 +8060ce08 0x8060ce08 +8060ce1c 0x8060ce1c +8060ce20 0x8060ce20 +8060cf20 0x8060cf20 +8060cf74 0x8060cf74 +8060d168 0x8060d168 +8060d1ac 0x8060d1ac +8060d1c4 0x8060d1c4 +8060d394 0x8060d394 +8060d418 0x8060d418 +8060d480 0x8060d480 +8060d4ec 0x8060d4ec +8060d4fc 0x8060d4fc +8060d508 0x8060d508 +8060d510 0x8060d510 +8060dcd8 0x8060dcd8 +8060dd10 0x8060dd10 +8060dd14 0x8060dd14 +8060dd1c 0x8060dd1c +8060dec0 0x8060dec0 +8060df94 0x8060df94 +8060e040 0x8060e040 +8060e048 0x8060e048 +8060e12c 0x8060e12c +8060e280 0x8060e280 +8060e374 0x8060e374 +8060e5c4 0x8060e5c4 +8060e5cc 0x8060e5cc +8060e5d4 0x8060e5d4 +8060e6a0 0x8060e6a0 +8060e6d0 0x8060e6d0 +8060fbf4 0x8060fbf4 +8060fcd0 0x8060fcd0 +8060fddc 0x8060fddc +8060ff08 0x8060ff08 +806104dc 0x806104dc +80610914 0x80610914 +80610a18 0x80610a18 +80610b30 0x80610b30 +80610cf0 0x80610cf0 +80610dc0 0x80610dc0 +80610dc4 0x80610dc4 +80610dcc 0x80610dcc +80610dd4 0x80610dd4 +80610ddc 0x80610ddc +80610de4 0x80610de4 +80610dec 0x80610dec +80610df4 0x80610df4 +80610dfc 0x80610dfc +80610e04 0x80610e04 +80610ea8 0x80610ea8 +80610f14 0x80610f14 +80610f1c 0x80610f1c +80610f28 0x80610f28 +80610f34 TriggerPtmf +80610f64 TriggerPtmf +80610f94 TriggerPtmf +80610fc4 0x80610fc4 +80610fe0 RankingGraphControl::GetClassName +80610fec RankingGraphControl::__ct +80611064 RankingGraphControl::__dt +80611104 RankingGraphControl::LoadAssets +8061118c 0x8061118c +806111b0 RankingGraphControl::UpdateImpl +806118c0 0x806118c0 +8061195c 0x8061195c +806119d4 0x806119d4 +80611a4c 0x80611a4c +80611a94 0x80611a94 +80611ae4 0x80611ae4 +80611b2c RankingGraphControlTimeAttack::GetClassName +80611b3c RankingGraphControlTimeAttack::__ct +80611c80 RankingGraphControlTimeAttack::__dt +80611df0 RankingGraphControlTimeAttack::Load +806121dc 0x806121dc +80612200 0x80612200 +80612204 RankingGraphControlTimeAttack::GetWindow +80612270 0x80612270 +806123b0 RankingGraphControlTimeAttack::DisplayItems +80612410 RankingGraphControlTimeAttack::DisableAllItems +80612530 RankingGraphControlTimeAttack:: DisplayItemsOnlineRankings +80612fd8 0x80612fd8 +80613018 RankingGraphControlTimeAttack:: DisplayItemsFriendsRankings +80613404 0x80613404 +80613414 0x80613414 +80613534 0x80613534 +80613670 0x80613670 +80613998 0x80613998 +806139bc 0x806139bc +806139c0 0x806139c0 +80613a0c 0x80613a0c +80613a6c 0x80613a6c +80613b50 0x80613b50 +806143d0 0x806143d0 +80614770 0x80614770 +8061477c RankingGraphControlTimeAttack::GetRuntimeTypeInfo +80614788 RankingGraphControl::GetRuntimeTypeInfo +80614794 0x80614794 +806147b8 0x806147b8 +80614824 0x80614824 +806148a8 0x806148a8 +806149d0 0x806149d0 +806149e0 0x806149e0 +80614a1c 0x80614a1c +80614a74 0x80614a74 +80614aec 0x80614aec +80614b24 0x80614b24 +80614b28 Pages::RankingGraph::__ct +80614dc4 Pages::RankingGraph::__dt +80614eac Pages::RankingGraph::OnInit +8061534c Pages::RankingGraph::OnDispose +80615400 Pages::RankingGraph::OnActivate +806155c4 0x806155c4 +806156c0 Pages::RankingGraph::OnTAUpDownChange +806156dc Pages::RankingGraph::OnTAUpDownClick +80615728 Pages::RankingGraph::OnTATextChange +806157ac Pages::RankingGraph::OnCompetitionUpDownChange +806157c8 Pages::RankingGraph::OnCompetitionTextChange +806158f4 Pages::RankingGraph::OnRankingTypeUpDownChange +80615a18 Pages::RankingGraph::OnRankingTypeTextChange +80615a28 Pages::RankingGraph::OnBackButtonClick +80615a74 Pages::RankingGraph::OnBackPress +80615a94 Pages::RankingGraph::SetBottomText +80615a9c 0x80615a9c +80615bcc 0x80615bcc +80615cac 0x80615cac +80615d30 0x80615d30 +80615d40 0x80615d40 +80615d50 0x80615d50 +80615e74 Pages::RankingGraph::GetNextPage +80615e7c Pages::RankingGraph::GetRuntimeTypeInfo +80615e88 0x80615e88 +80615e94 0x80615e94 +80615ea0 TriggerPtmf +80615ed0 TriggerPtmf +80615f00 TriggerPtmf +80615f30 TriggerPtmf +80615f60 TriggerPtmf +80615f90 0x80615f90 +80615fb8 0x80615fb8 +80616108 RankingItem::GetClassName +80616114 0x80616114 +80616164 RankingItem::__dt +806161bc RankingItem::FinishLoad +80616398 RankingItem::OnUpdate +80616824 0x80616824 +80616838 RankingItem::Disable +8061684c RankingItem::Enable +80616860 RankingItem::Appear +80616964 RankingItem::MakeAccessible +80616968 RankingItem::Disappear +80616998 0x80616998 +806169f4 0x806169f4 +80616b1c RankingItemSelectable::GetClassName +80616b2c RankingItemSelectable::__ct +80616c40 RankingItemSelectable::__dt +80616cb0 RankingItemSelectable::Load +80616cf4 RankingItemSelectable::Load_switch +80616cf8 RankingItemSelectable::Load_caseD_0 +80616d08 RankingItemSelectable::Load_caseD_1 +80616d18 RankingItemSelectable::Load_caseD_2 +80616d28 RankingItemSelectable::Load_caseD_3 +80616d38 RankingItemSelectable::Load_caseD_4 +80616d48 RankingItemSelectable::Load_caseD_5 +80616d58 RankingItemSelectable::Load_caseD_6 +80616d68 RankingItemSelectable::Load_caseD_7 +80617110 RankingItemSelectable::InitSelf +806171a4 RankingItemSelectable::Disable +806171c0 RankingItemSelectable::Enable +806176d8 RankingItemSelectable::MakeAccessible +806176f4 RankingItemSelectable::Disappear +8061772c RankingItemSelectable::vf_0x50 +80617748 RankingItemSelectable::vf_0x54 +80617760 RankingItemSelectable::vf_0x58 +80617778 RankingItemSelectable::vf_0x5c +80617794 RankingItemSelectable::vf_0x60 +80617a60 RankingItemSelectable::vf_0x64 +80617a64 RankedItemSelectable::OnSelect +8061809c RankedItemSelectable::OnSelect_switch +806180a0 RankedItemSelectable::OnSelect_caseD_0 +806180a8 RankedItemSelectable::OnSelect_caseD_1 +806180b0 RankedItemSelectable::OnSelect_caseD_3 +806180dc RankedItemSelectable::OnSelect_caseD_5 +806180e4 RankedItemSelectable::OnSelect_caseD_6 +80618120 RankedItemSelectable::OnSelect_caseD_7 +80618260 RankedItemSelectable::OnDeselect +806183c4 RankedItemSelectable::OnClick +80618608 0x80618608 +80618630 0x80618630 +80618634 0x80618634 +8061863c 0x8061863c +80618644 0x80618644 +8061864c 0x8061864c +80618654 0x80618654 +8061865c 0x8061865c +80618664 0x80618664 +8061866c 0x8061866c +80618690 RankingItemStranger::GetClassName +806186a0 RankingItemStranger::__ct +806186fc RankingItemStranger::__dt +80618758 RankingItemStranger::Load +806187f0 RankingItemStranger::Enable +80618820 RankingItemStranger::vf_0x50 +8061883c RankingItemStranger::vf_0x54 +80618854 RankingItemStranger::vf_0x58 +8061886c RankingItemStranger::vf_0x5c +80618870 RankingItemStranger::vf_0x60 +80618874 RankingItemStranger::vf_0x64 +80618878 RankingRuler::GetClassName +80618888 RankingRuler::__ct +806188c4 RankingRuler::__dt +8061891c RankingRuler::Load +80618990 RankingRuler::InitSelf +8061899c 0x8061899c +80618ae0 0x80618ae0 +80618b8c 0x80618b8c +80618b98 RankingWindow::GetClassName +80618ba8 RankingWindow::__ct +80618be4 RankingWindow::__dt +80618c3c 0x80618c3c +80618dac RankingWindow::InitSelf +80618db8 RankingWindow::OnUpdate +80618e38 0x80618e38 +80618e44 0x80618e44 +80619070 RankingWindow::GetRuntimeTypeInfo +8061907c RankingRuler::GetRuntimeTypeInfo +80619088 RankingItemStranger::GetRuntimeTypeInfo +80619094 RankingItemSelectable::GetRuntimeTypeInfo +806190a0 RankingItem::GetRuntimeTypeInfo +806190ac TriggerPtmf +806190dc 0x806190dc +80619130 0x80619130 +80619170 0x80619170 +806191cc 0x806191cc +806191dc 0x806191dc +806193c4 GLMeshWriterCore_ColourPlat +806193e4 0x806193e4 +80619430 0x80619430 +806196d0 0x806196d0 +806196ec 0x806196ec +8061975c 0x8061975c +806199b0 0x806199b0 +80619a30 0x80619a30 +80619aa0 0x80619aa0 +80619b90 0x80619b90 +80619bd8 0x80619bd8 +80619c78 0x80619c78 +80619d18 0x80619d18 +80619d64 0x80619d64 +80619dc4 0x80619dc4 +80619fec 0x80619fec +8061a290 0x8061a290 +8061a314 0x8061a314 +8061a360 0x8061a360 +8061a3c0 0x8061a3c0 +8061a570 0x8061a570 +8061a5e0 SectionPad::__ct +8061a5f0 SectionPad::__dt +8061a630 SectionPad::Init +8061a694 SectionPad::Update +8061aaac SectionPad::ResetPadsStatusAndSet0x54 +8061aacc SectionPad::GetCurrentID +8061aaec SectionPad::GetNewID +8061ab0c SectionPad::GetControllerHolder +8061ab40 SectionPad::HasAController +8061ab94 SectionPad::SetDriftType +8061abb4 SectionPad::IsDriftAuto +8061abe4 0x8061abe4 +8061ac04 SectionPad::SetID +8061ac1c 0x8061ac1c +8061ad18 0x8061ad18 +8061ae60 SectionPad::RequestPad +8061af38 SectionPad::ResetPad +8061b010 SectionPad::SetPadDisconnected +8061b024 SectionPad::DisconnectPad +8061b114 SectionPad::ResetPadsStatus +8061b130 SectionPad::GetFirstDeactivatedPad +8061b1bc SectionPad::HasControllerChanged +8061b1f4 0x8061b1f4 +8061b3c8 SectionPad::Has4WiimotePads +8061b43c SectionPad::ResetAllPads +8061b488 SectionPad::EnablePointer +8061b530 SectionPad::GetControllerHolderByIdx +8061b5b4 SectionPad::CalculateID +8061b720 SectionPad::GetType +8061b770 Pages::RecognizePad::__ct +8061b7cc Pages::RecognizePad::__dt +8061b84c Pages::RecognizePad::OnInit +8061b934 Pages::RecognizePad::OnActivate +8061b9fc Pages::RecognizePad::OnDeactivate +8061ba58 Pages::RecognizePad::AfterControlUpdate +8061baf8 Pages::RecognizePad::BeforeEntranceAnimations +8061bb3c Pages::RecognizePad::AfterExitAnimations +8061bb80 Pages::RecognizePad::CheckForConditions +8061bc8c Pages::RecognizePad::IsVisible +8061bcb0 Pages::RecognizePadMenu::__ct +8061bd18 Pages::RecognizePadMenu::__dt +8061bd9c Pages::RecognizePadMenu::BeforeEntranceAnimations +8061be94 Pages::RecognizePadMenu::AfterEntranceAnimations +8061bee0 Pages::RecognizePadMenu::BeforeExitAnimations +8061bef4 Pages::RecognizePadMenu::AfterExitAnimations +8061bf38 Pages::RecognizePadMenu::BeforeControlUpdate +8061bfe0 Pages::RecognizePadMenu::IsDVDEnabled +8061bff4 0x8061bff4 +8061c05c 0x8061c05c +8061c0e0 0x8061c0e0 +8061c1b4 0x8061c1b4 +8061c21c 0x8061c21c +8061c308 0x8061c308 +8061c354 0x8061c354 +8061c368 0x8061c368 +8061c3ac 0x8061c3ac +8061c498 0x8061c498 +8061c4b4 0x8061c4b4 +8061c51c 0x8061c51c +8061c5a0 0x8061c5a0 +8061c674 0x8061c674 +8061c760 0x8061c760 +8061c7ac 0x8061c7ac +8061c7c0 0x8061c7c0 +8061c804 0x8061c804 +8061c8f0 0x8061c8f0 +8061c90c 0x8061c90c +8061c918 0x8061c918 +8061c924 0x8061c924 +8061c930 0x8061c930 +8061c93c Pages::RecognizePadMenu::GetClassName +8061c948 Pages::RecognizePadMenu::GetRuntimeTypeInfo +8061c954 Pages::RecognizePad::GetRuntimeTypeInfo +8061c960 0x8061c960 +8061c988 Pages::RegisteringFriend::__ct +8061c9fc Pages::RegisteringFriend::__dt +8061ca74 Pages::RegisteringFriend::OnInit +8061cb1c Pages::RegisteringFriend::OnActivate +8061cc3c Pages::RegisteringFriend::BeforeEntranceAnimations +8061cc40 Pages::RegisteringFriend::BeforeExitAnimations +8061cc44 Pages::RegisteringFriend::AfterControlUpdate +8061cd9c Pages::RegisteringFriend::OnResume +8061d3b4 Pages::RegisteringFriend::GetNextPage +8061d410 Pages::RegisteringFriend::IsHomeMenuWorking +8061d42c Pages::RegisterFriend::__ct +8061d664 Pages::RegisterFriend::__dt +8061d728 Pages::RegisterFriend::OnInit +8061d9e4 Pages::RegisterFriend::OnActivate +8061da5c 0x8061da5c +8061dab4 0x8061dab4 +8061dabc Pages::RegisterFriend::OnDigitClick +8061db28 Pages::RegisterFriend::OnBackSpaceClick +8061db74 Pages::RegisterFriend::OnOkButtonClick +8061de60 Pages::RegisterFriend::OnBackButtonClick +8061dea4 Pages::RegisterFriend::OnOkButtonSelect +8061dee0 Pages::RegisterFriend::OnOkButtonDeselect +8061def0 Pages::RegisterFriend::OnBackPress +8061df78 Pages::RegisterFriend::GetRuntimeTypeInfo +8061df84 Pages::xA5::GetRuntimeTypeInfo +8061df90 TriggerPtmf +8061dfc0 TriggerPtmf +8061dff0 RegisterFriendPage_cpp_sinit_ +8061e00c 0x8061e00c +8061e090 0x8061e090 +8061e104 0x8061e104 +8061e184 0x8061e184 +8061e31c Page::EndExitState +8061e320 0x8061e320 +8061e324 0x8061e324 +8061e940 0x8061e940 +8061ec58 0x8061ec58 +8061ec5c 0x8061ec5c +8061ec64 0x8061ec64 +8061ec6c 0x8061ec6c +8061ec74 0x8061ec74 +8061ec7c 0x8061ec7c +8061ec84 0x8061ec84 +8061ec8c 0x8061ec8c +8061ec94 0x8061ec94 +8061ec9c 0x8061ec9c +8061ed64 0x8061ed64 +8061ee0c 0x8061ee0c +8061ee18 TriggerPtmf +8061ee48 0x8061ee48 +8061ee5c Pages::CorruptSaveMgr::__ct +8061eed8 Pages::CorruptSaveMgr::__dt +8061ef40 Pages::CorruptSaveMgr::OnInit +8061ef9c Pages::CorruptSaveMgr::OnActivate +8061f128 Pages::CorruptSaveMgr::AfterControlUpdate +8061f360 Pages::CorruptSaveMgr::OnResume +8061f4f8 Pages::CorruptSaveMgr::IsHomeMenuWorking +8061f510 Pages::CorruptSaveMgr::InitYesNoValues +8061f6b4 0x8061f6b4 +8061f7c0 Pages::CorruptSaveMgr::OnReturnToWiiMenuClick +8061f830 Pages::CannotSave::__ct +8061f8ac Pages::CannotSave::__dt +8061f914 Pages::CannotSave::OnInit +8061f970 Pages::CannotSave::OnActivate +8061fb14 Pages::CannotSave::OnYesNoClick +8061fbb4 Pages::CorruptMemory::__ct +8061fc00 Pages::CorruptMemory::__dt +8061fc74 Pages::CorruptMemory::OnInit +8061fd38 Pages::CorruptMemory::OnActivate +8061fdac Pages::CorruptMiiData::__ct +8061fe38 Pages::CorruptMiiData::__dt +8061feb8 Pages::CorruptMiiData::OnInit +8061ffbc Pages::CorruptMiiData::OnActivate +80620014 Pages::CorruptMiiData::OnButtonClick +80620060 Pages::CorruptMiiData::IsHomeMenuWorking +80620068 Pages::CorruptMiiData::GetRuntimeTypeInfo +80620074 Pages::CorruptMemory::IsHomeMenuWorking +8062007c Pages::CorruptMemory::GetRuntimeTypeInfo +80620088 Pages::CannotSave::__dt +80620090 Pages::CannotSave::GetRuntimeTypeInfo +8062009c Pages::CorruptSaveMgr::GetRuntimeTypeInfo +806200a8 TriggerPtmf +806200d8 TriggerPtmf +80620108 TriggerPtmf +80620138 CorruptPages_cpp_sinit_ +8062015c RKSYSRequester::__ct +80620190 0x80620190 +80620200 RKSYSRequester::__dt +80620278 RKSYSRequester::Reset +806202b4 RKSYSRequester::Update +806203d0 RKSYSRequester::Init +806204f0 RKSYSRequester::Close +80620524 RKSYSRequester::HandleRequest +80620928 RKSYSRequester::HandleAllRequests +80620a48 RKSYSRequester::CheckRequests +80620af0 RKSYSRequester::HasError +80620b04 0x80620b04 +80620b18 RKSYSRequester::RequestEraseAllGhosts +80620b30 RKSYSRequester::RequestSaveLicense +80620b5c RKSYSRequester::NotifyNewLicenseContent +80620b80 RKSYSRequester::RequestSaveLicenseIfNewContent +80620bd0 RKSYSRequester::RequestSaveGhost +80620f78 RKSYSRequester::RequestSaveGhost_0x18 +8062131c RKSYSRequester::RequestEraseGhost +80621354 RKSYSRequester::RequestEraseGhostFromLicense +80621388 RKSYSRequester::RequestGetDLdGhost +806213c4 RKSYSRequester::RequestGetGhostFromLicense +806213fc RKSYSRequester::RequestGetGroupGhosts +8062142c RKSYSRequester::RequestGetGroupGhostsFromLicense +80621458 Section::__ct +806214d0 Section::__dt +8062154c Section::Init +806217fc Section::Enter +80621924 Section::Exit +80621aec Section::UpdateSystemPages +80621c44 Section::Update +80621eb0 Section::Draw +8062222c Section::Pause +80622298 Section::Resume +80622354 Section::OnTransition +806223b4 Section::CreateMoviePlayer +80622404 Section::CreateFriendList +80622454 Section::CreateAndInitPage +806224a0 Section::CreateSystemPage +806224ec Section::AddPageLayer +8062254c Section::AddPageLayerAnimatedReturnTopLayer +806225b8 Section::IsPageTopLayer +806225ec Section::GetTopLayerPage +80622614 Section::IsHomeMenuWorking +806226d4 Section::IsDVDEnabled +806227a0 Section::ScheduleDisconnection +806227b4 Section::UpdateLayers +80622974 Section::AddPageLayerAnimated +806229d4 Section::TopLayerPage +80622a34 Section::RemovePageLayers +80622adc Section::CreatePageById +80622b04 Section::CreatePageById_switch +80622b08 Section::CreatePageById_case0 +80622b20 Section::CreatePageById_case1 +80622b38 Section::CreatePageById_case2 +80622b50 Section::CreatePageById_case3 +80622b68 Section::CreatePageById_case4 +80622b80 Section::CreatePageById_case5 +80622b98 Section::CreatePageById_case6 +80622bb0 Section::CreatePageById_case7 +80622bc8 Section::CreatePageById_case8 +80622be0 Section::CreatePageById_case9 +80622bf8 Section::CreatePageById_casea +80622c10 Section::CreatePageById_caseb +80622c28 Section::CreatePageById_casec +80622c40 Section::CreatePageById_cased +80622c58 Section::CreatePageById_casee +80622c70 Section::CreatePageById_case10 +80622c88 Section::CreatePageById_case12 +80622ca0 Section::CreatePageById_case13 +80622cb8 Section::CreatePageById_case16 +80622cd0 Section::CreatePageById_case17 +80622ce8 Section::CreatePageById_case18 +80622d00 Section::CreatePageById_case19 +80622d18 Section::CreatePageById_case1a +80622d30 Section::CreatePageById_case1b +80622d48 Section::CreatePageById_case1c +80622d60 Section::CreatePageById_case1d +80622d78 Section::CreatePageById_case1e +80622d90 Section::CreatePageById_case1f +80622da8 Section::CreatePageById_case20 +80622dc0 Section::CreatePageById_case21 +80622dd8 Section::CreatePageById_case22 +80622df0 Section::CreatePageById_case23 +80622e08 Section::CreatePageById_case24 +80622e20 Section::CreatePageById_case25 +80622e38 Section::CreatePageById_case26 +80622e50 Section::CreatePageById_case27 +80622e68 Section::CreatePageById_case28 +80622e80 Section::CreatePageById_case29 +80622e98 Section::CreatePageById_case2a +80622eb0 Section::CreatePageById_case2b +80622ec8 Section::CreatePageById_case2c +80622ee0 Section::CreatePageById_case2d +80622ef8 Section::CreatePageById_case2e +80622f10 Section::CreatePageById_case2f +80622f28 Section::CreatePageById_case30 +80622f40 Section::CreatePageById_case31 +80622f58 Section::CreatePageById_case32 +80622f70 Section::CreatePageById_case33 +80622f88 Section::CreatePageById_case34 +80622fa0 Section::CreatePageById_case35 +80622fb8 Section::CreatePageById_case36 +80622fd0 Section::CreatePageById_case37 +80622fe8 Section::CreatePageById_case38 +80623000 Section::CreatePageById_case39 +80623018 Section::CreatePageById_case3a +80623030 Section::CreatePageById_case3b +80623048 Section::CreatePageById_case3c +80623060 Section::CreatePageById_case3d +80623078 Section::CreatePageById_case3e +80623090 Section::CreatePageById_case3f +806230a8 Section::CreatePageById_case40 +806230c0 Section::CreatePageById_case41 +806230d8 Section::CreatePageById_case42 +806230f0 Section::CreatePageById_case43 +80623108 Section::CreatePageById_case44 +80623120 Section::CreatePageById_case45 +80623138 Section::CreatePageById_case46 +80623150 Section::CreatePageById_case47 +80623168 Section::CreatePageById_case48 +80623180 Section::CreatePageById_case49 +80623198 Section::CreatePageById_case4a +806231b0 Section::CreatePageById_case4b +806231c8 Section::CreatePageById_case4c +806231e0 Section::CreatePageById_case4d +806231f8 Section::CreatePageById_case4e +80623210 Section::CreatePageById_case4f +80623228 Section::CreatePageById_case51 +80623240 Section::CreatePageById_case52 +80623258 Section::CreatePageById_case53 +80623270 Section::CreatePageById_case54 +80623288 Section::CreatePageById_case55 +806232a0 Section::CreatePageById_case56 +806232b8 Section::CreatePageById_case57 +806232d0 Section::CreatePageById_case58 +806232e8 Section::CreatePageById_case59 +80623300 Section::CreatePageById_case5a +80623318 Section::CreatePageById_case5b +80623330 Section::CreatePageById_case5c +80623348 Section::CreatePageById_case5d +80623360 Section::CreatePageById_case5e +80623378 Section::CreatePageById_case5f +80623390 Section::CreatePageById_case60 +806233a8 Section::CreatePageById_case61 +806233c0 Section::CreatePageById_case62 +806233d8 Section::CreatePageById_case63 +806233f0 Section::CreatePageById_case64 +80623408 Section::CreatePageById_case65 +80623420 Section::CreatePageById_case66 +80623438 Section::CreatePageById_case67 +80623450 Section::CreatePageById_case68 +80623468 Section::CreatePageById_case69 +80623480 Section::CreatePageById_case6a +80623498 Section::CreatePageById_case6b +806234b0 Section::CreatePageById_case6c +806234c8 Section::CreatePageById_case6d +806234e0 Section::CreatePageById_case6e +806234f8 Section::CreatePageById_case6f +80623510 Section::CreatePageById_case70 +80623528 Section::CreatePageById_case71 +80623540 Section::CreatePageById_case72 +80623558 Section::CreatePageById_case73 +80623570 Section::CreatePageById_case74 +80623588 Section::CreatePageById_case75 +806235a0 Section::CreatePageById_case76 +806235b8 Section::CreatePageById_case77 +806235d0 Section::CreatePageById_case78 +806235e8 Section::CreatePageById_case79 +80623600 Section::CreatePageById_case7a +80623618 Section::CreatePageById_case7b +80623630 Section::CreatePageById_case7c +80623648 Section::CreatePageById_case7d +80623660 Section::CreatePageById_case7e +80623678 Section::CreatePageById_case7f +80623690 Section::CreatePageById_case80 +806236a8 Section::CreatePageById_case81 +806236c0 Section::CreatePageById_case82 +806236d8 Section::CreatePageById_case83 +806236f0 Section::CreatePageById_case84 +80623708 Section::CreatePageById_case85 +80623720 Section::CreatePageById_case86 +80623738 Section::CreatePageById_case87 +80623750 Section::CreatePageById_case88 +80623768 Section::CreatePageById_case89 +80623780 Section::CreatePageById_case8a +80623798 Section::CreatePageById_case8b +806237b0 Section::CreatePageById_case8c +806237c8 Section::CreatePageById_case8d +806237e0 Section::CreatePageById_case8e +806237f8 Section::CreatePageById_case8f +80623810 Section::CreatePageById_case90 +80623828 Section::CreatePageById_case91 +80623840 Section::CreatePageById_case92 +80623858 Section::CreatePageById_case93 +80623870 Section::CreatePageById_case94 +80623888 Section::CreatePageById_case95 +806238a0 Section::CreatePageById_case96 +806238b8 Section::CreatePageById_case97 +806238d0 Section::CreatePageById_case98 +806238e8 Section::CreatePageById_case99 +80623900 Section::CreatePageById_case9a +80623918 Section::CreatePageById_case9b +80623930 Section::CreatePageById_case9c +80623948 Section::CreatePageById_case9d +80623960 Section::CreatePageById_case9e +80623978 Section::CreatePageById_case9f +80623990 Section::CreatePageById_casea0 +806239a8 Section::CreatePageById_casea1 +806239c0 Section::CreatePageById_casea2 +806239d8 Section::CreatePageById_casea3 +806239f0 Section::CreatePageById_casea4 +80623a08 Section::CreatePageById_casea5 +80623a20 Section::CreatePageById_casea6 +80623a38 Section::CreatePageById_casea7 +80623a50 Section::CreatePageById_casea8 +80623a68 Section::CreatePageById_caseaa +80623a80 Section::CreatePageById_caseab +80623a98 Section::CreatePageById_caseac +80623ab0 Section::CreatePageById_casead +80623ac8 Section::CreatePageById_caseae +80623ae0 Section::CreatePageById_caseaf +80623af8 Section::CreatePageById_caseb0 +80623b10 Section::CreatePageById_caseb1 +80623b28 Section::CreatePageById_caseb2 +80623b40 Section::CreatePageById_caseb3 +80623b58 Section::CreatePageById_caseb4 +80623b70 Section::CreatePageById_caseb5 +80623b88 Section::CreatePageById_caseb6 +80623ba0 Section::CreatePageById_caseb7 +80623bb8 Section::CreatePageById_caseb8 +80623bd0 Section::CreatePageById_caseb9 +80623be8 Section::CreatePageById_caseba +80623c00 Section::CreatePageById_casebb +80623c18 Section::CreatePageById_casebc +80623c30 Section::CreatePageById_casebd +80623c48 Section::CreatePageById_casebe +80623c60 Section::CreatePageById_casebf +80623c78 Section::CreatePageById_casec0 +80623c90 Section::CreatePageById_casec1 +80623ca8 Section::CreatePageById_casec2 +80623cc0 Section::CreatePageById_casec3 +80623cd8 Section::CreatePageById_casec5 +80623cf0 Section::CreatePageById_casec6 +80623d08 Section::CreatePageById_casec7 +80623d20 Section::CreatePageById_casec8 +80623d38 Section::CreatePageById_casec9 +80623d50 Section::CreatePageById_caseca +80623d68 Section::CreatePageById_casecb +80623d80 Section::CreatePageById_casecc +80623d98 Section::CreatePageById_casecd +80623db0 Section::CreatePageById_casece +80623ddc Pages::RaceIntro::__ct +80623e30 Pages::GPHUD::__ct +80623eb0 Pages::RaceHUD::__dt +80623f18 Pages::TTHUD::__ct +80623fc0 Pages::VSHUD::__ct +80624040 Pages::VSMultiHUD::__ct +806240c0 Pages::BattleHUD::__ct +80624140 Pages::BattleMultiHUD::__ct +806241c0 Pages::TournamentHUD::__ct +80624240 Pages::GPPause::__ct +80624284 Pages::RaceMenu::__dt +806242ec Pages::VSPause::__ct +80624330 Pages::TTPause::__ct +80624374 Pages::BattlePause::__ct +806243b8 0x806243b8 +806243fc 0x806243fc +80624440 0x80624440 +80624484 0x80624484 +806244c8 Pages::GhostReplayPause::GhostReplayPausePage +8062450c Pages::GPEnd::__ct +80624550 Pages::TTEnd::__ct +80624594 Pages::VSRaceEnd::VSRaceEndPage +806245d8 Pages::BattleEnd::__ct +8062461c Pages::BattleFinalRaceEnd::__ct +80624660 0x80624660 +806246a4 0x806246a4 +806246e8 0x806246e8 +8062472c 0x8062472c +80624770 Pages::TTFriendGhostEnd::__ct +806247b4 0x806247b4 +806247f8 Pages::CheckRankings::__ct +8062483c Pages::QuitConfirmation::__ct +80624880 Pages::TTLeaderboard::__ct +806248e4 Pages::Leaderboard::__dt +8062494c 0x8062494c +806249b8 Pages::GPVSLeaderboardUpdate::__ct +806249f4 Pages::GPVSLeaderboardTotal::__ct +80624a30 Pages::WWLeaderboardUpdate::__ct +80624a6c Pages::TeamVSLeaderboardTotal::__ct +80624ad4 CtrlRaceResultTeam::__ct +80624b38 CtrlRaceResultTeam::__dt +80624bac Pages::TeamVSLeaderboardBase::__dt +80624c34 Pages::BattleLeaderboardUpdate::__ct +80624c9c Pages::BattleLeaderboardTotal::__ct +80624d04 0x80624d04 +80624d40 Pages::GPReplayHUD::__ct +80624dc0 Pages::GhostRaceHUD::__ct +80624e40 Pages::GPReplayPause::__ct +80624e84 Pages::TTReplayPause::__ct +80624ec8 Pages::WifiVSHUD::__ct +80624f48 Pages::WifiVSMultiHUD::__ct +80624fc8 Pages::WiFiFriendVSHUD::__ct +80625048 Pages::WiFiFriendTeamVSHUD::__ct +806250c8 Pages::LiveViewHUD::__ct +80625148 Pages::LiveBattleViewHUD::__ct +806251c8 Pages::StartRace::__ct +8062547c Pages::Menu::__dt +806254e8 Pages::DriftSelect::OnStartPress +806254ec Pages::MainMenu::__ct +806257c4 Pages::MenuBG::__ct +80625934 Pages::TopMenuOverlay::__ct +80625aa8 Pages::MiiSelect::__ct +80625d8c MiiName::__dt +80625de4 Pages::SinglePlayer::__ct +8062609c Pages::GPClassSelect::__ct +8062635c Pages::CharacterSelect::__ct +80626754 CtrlMenuCharacterSelect::__dt +806267ac Pages::KartSelect::__ct +80626a84 CtrlMenuMachineGraph::__ct +80626ac0 CtrlMenuMachineGraph::__dt +80626b18 Pages::DriftSelect::__ct +80626dd0 Pages::CupSelect::__ct +8062718c CtrlMenuMovieHandler::__dt +806271cc CtrlMenuMovieLayout::__dt +80627228 CtrlMenuCupSelectCup::__dt +806272b0 CtrlMenuCupSelectCourse::__dt +80627324 Pages::CourseSelect::__ct +806276b8 CtrlMenuCourseSelectCupSub::__ct +806276f4 CtrlMenuCourseSelectCupSub::__dt +8062774c CtrlMenuCourseSelectCup::__dt +806277c0 CourseButton::__ct +80627820 CtrlMenuMovieButton::__dt +8062787c CourseButton::__dt +806278dc 0x806278dc +8062795c Pages::VSModeSelect::__ct +80627c14 Pages::VSSettings::VSSetting +80627f2c Pages::VSTeamsView::__ct +80628200 CtrlMenuTeamConfirmTeam::__ct +8062825c CtrlMenuTeamConfirmTeam::__dt +806282d0 Pages::BattleModeSelect::__ct +80628588 Pages::BattleKartSelect::__ct +80628878 CharaName::__dt +806288d0 Pages::BattleSettings::__ct +80628be8 Pages::BattleCupSelect::__ct +80628fa4 CtrlMenuBattleCupSelectCup::__dt +8062902c CtrlMenuBattleCupSelectStage::__dt +806290a0 Pages::BattleStageSelect::__ct +80629434 0x80629434 +80629470 0x80629470 +806294c8 CtrlMenuBattleStageSelectCup::__dt +8062953c StageButton::__ct +8062959c StageButton::__dt +806295fc CtrlMenuBattleStageSelectStage::__ct +8062967c 0x8062967c +80629a38 0x80629a38 +80629ac0 0x80629ac0 +80629b34 0x80629b34 +80629ec8 0x80629ec8 +80629f04 0x80629f04 +80629f5c 0x80629f5c +80629fd0 0x80629fd0 +8062a030 0x8062a030 +8062a090 0x8062a090 +8062a110 0x8062a110 +8062a3e8 0x8062a3e8 +8062a6d4 0x8062a6d4 +8062a98c Pages::MultiPlayer::__ct +8062ac40 Pages::MultiKartSelect::__ct +8062af74 MultiKartBox::__ct +8062afb0 MultiKartBox::__dt +8062b008 Pages::MultiDriftSelect::__ct +8062b2bc Pages::MultiTeamSelect::__ct +8062b570 Pages::Unlock::__ct +8062b840 Pages::LicenseRecords::__ct +8062baf0 Section::CreateSectionPages +8062bb24 Section::CreateSectionPages_switch +8062bb28 Section::CreateSectionPages_case6 +8062bb34 Section::CreateSectionPages_case7 +8062bb40 Section::CreateSectionPages_case8 +8062bb4c Section::CreateSectionPages_case9 +8062bb58 Section::CreateSectionPages_casea +8062bb64 Section::CreateSectionPages_caseb +8062bb70 Section::CreateSectionPages_casec +8062bb7c Section::CreateSectionPages_cased +8062bb88 Section::CreateSectionPages_casee +8062bb94 Section::CreateSectionPages_casef +8062bba0 Section::CreateSectionPages_case10 +8062bbc4 Section::CreateSectionPages_case11 +8062bbf4 Section::CreateSectionPages_case12 +8062bc24 Section::CreateSectionPages_case13 +8062bc48 Section::CreateSectionPages_case14 +8062bc60 Section::CreateSectionPages_case15 +8062bc78 Section::CreateSectionPages_case16 +8062bc84 Section::CreateSectionPages_case17 +8062bc90 Section::CreateSectionPages_case18 +8062bc9c Section::CreateSectionPages_case19 +8062bca8 Section::CreateSectionPages_case1a +8062bcb4 Section::CreateSectionPages_case1b +8062bcc0 Section::CreateSectionPages_case1c +8062bccc Section::CreateSectionPages_case1d +8062bcd8 Section::CreateSectionPages_case1e +8062bd2c Section::CreateSectionPages_case1f +8062bd98 Section::CreateSectionPages_case20 +8062bde0 Section::CreateSectionPages_case21 +8062be34 Section::CreateSectionPages_case22 +8062be88 Section::CreateSectionPages_case23 +8062bedc Section::CreateSectionPages_case24 +8062bf24 Section::CreateSectionPages_case25 +8062bf78 Section::CreateSectionPages_case26 +8062bfcc Section::CreateSectionPages_case27 +8062c020 Section::CreateSectionPages_case28 +8062c074 Section::CreateSectionPages_case29 +8062c0d4 Section::CreateSectionPages_case2a +8062c134 Section::CreateSectionPages_case2b +8062c194 Section::CreateSectionPages_case2c +8062c1d0 Section::CreateSectionPages_case2d +8062c218 Section::CreateSectionPages_case2e +8062c248 Section::CreateSectionPages_case2f +8062c290 Section::CreateSectionPages_case30 +8062c308 Section::CreateSectionPages_case31 +8062c38c Section::CreateSectionPages_case32 +8062c3c8 Section::CreateSectionPages_case33 +8062c404 Section::CreateSectionPages_case34 +8062c440 Section::CreateSectionPages_case35 +8062c458 Section::CreateSectionPages_case36 +8062c470 Section::CreateSectionPages_case37 +8062c488 Section::CreateSectionPages_case38 +8062c4a0 Section::CreateSectionPages_case39 +8062c4ac Section::CreateSectionPages_case3a +8062c4b8 Section::CreateSectionPages_case3b +8062c4d0 Section::CreateSectionPages_case3c +8062c4e8 Section::CreateSectionPages_case3d +8062c524 Section::CreateSectionPages_case3e +8062c560 Section::CreateSectionPages_case3f +8062c5e4 Section::CreateSectionPages_case40 +8062c668 Section::CreateSectionPages_case41 +8062c6ec Section::CreateSectionPages_case42 +8062c770 Section::CreateSectionPages_case43 +8062c7f4 Section::CreateSectionPages_case44 +8062c80c Section::CreateSectionPages_case45 +8062c854 Section::CreateSectionPages_case46 +8062c89c Section::CreateSectionPages_case47 +8062c944 Section::CreateSectionPages_case48 +8062ca88 Section::CreateSectionPages_case49 +8062cbcc Section::CreateSectionPages_case4a +8062cd10 Section::CreateSectionPages_case4b +8062cd94 Section::CreateSectionPages_case4c +8062ce18 Section::CreateSectionPages_case4d +8062cf5c Section::CreateSectionPages_case4e +8062cfc8 Section::CreateSectionPages_case4f +8062d034 Section::CreateSectionPages_case50 +8062d0a0 Section::CreateSectionPages_case51 +8062d0e8 Section::CreateSectionPages_case52 +8062d130 Section::CreateSectionPages_case53 +8062d178 Section::CreateSectionPages_case54 +8062d2b0 Section::CreateSectionPages_case55 +8062d454 Section::CreateSectionPages_case56 +8062d5f8 Section::CreateSectionPages_case57 +8062d79c Section::CreateSectionPages_case58 +8062d82c Section::CreateSectionPages_case59 +8062d8bc Section::CreateSectionPages_case5a +8062d91c Section::CreateSectionPages_case5b +8062dac0 Section::CreateSectionPages_case5c +8062dc64 Section::CreateSectionPages_case5d +8062de08 Section::CreateSectionPages_case5e +8062de98 Section::CreateSectionPages_case5f +8062df28 Section::CreateSectionPages_case60 +8062dfb8 Section::CreateSectionPages_case61 +8062e048 Section::CreateSectionPages_case62 +8062e0d8 Section::CreateSectionPages_case63 +8062e168 Section::CreateSectionPages_case64 +8062e1f8 Section::CreateSectionPages_case65 +8062e288 Section::CreateSectionPages_case66 +8062e318 Section::CreateSectionPages_case67 +8062e3a8 Section::CreateSectionPages_case68 +8062e420 Section::CreateSectionPages_case69 +8062e498 Section::CreateSectionPages_case6a +8062e4ec Section::CreateSectionPages_case6b +8062e540 Section::CreateSectionPages_case6c +8062e5c4 Section::CreateSectionPages_case6d +8062e648 Section::CreateSectionPages_case6e +8062e6a8 Section::CreateSectionPages_case6f +8062e708 Section::CreateSectionPages_case70 +8062e774 Section::CreateSectionPages_case71 +8062e7e0 Section::CreateSectionPages_case72 +8062e84c Section::CreateSectionPages_case73 +8062e8b8 Section::CreateSectionPages_case74 +8062e924 Section::CreateSectionPages_case75 +8062e990 Section::CreateSectionPages_case76 +8062e9fc Section::CreateSectionPages_case77 +8062ea68 Section::CreateSectionPages_case78 +8062ea80 Section::CreateSectionPages_case79 +8062ea98 Section::CreateSectionPages_case7a +8062eaec Section::CreateSectionPages_case7b +8062eb40 Section::CreateSectionPages_case7c +8062eb94 Section::CreateSectionPages_case7d +8062ec90 Section::CreateSectionPages_case7e +8062ed5c Section::CreateSectionPages_case7f +8062ede0 Section::CreateSectionPages_case80 +8062eec4 Section::CreateSectionPages_case81 +8062ef9c Section::CreateSectionPages_case82 +8062effc Section::CreateSectionPages_case83 +8062f188 Section::CreateSectionPages_case84 +8062f320 Section::CreateSectionPages_case85 +8062f398 Section::CreateSectionPages_case86 +8062f410 Section::CreateSectionPages_case87 +8062f494 Section::CreateSectionPages_case88 +8062f4ac Section::CreateSectionPages_case89 +8062f4c4 Section::CreateSectionPages_case8a +8062f518 Section::CreateSectionPages_case8b +8062f554 Section::CreateSectionPages_case8c +8062f614 Section::CreateSectionPages_case8d +8062f644 Section::CreateSectionPages_case8e +8062f668 Section::CreateSectionPages_case8f +8062f6d4 Section::CreateSectionPages_case90 +8062f704 Section::CreateSectionPages_case91 +8062f734 Section::CreateSectionPages_case92 +8062f764 Section::CreateSectionPages_case93 +8062f794 Section::CreateSectionPages_case94 +8062f7e0 Section::AddInitialLayers +8062f814 Section::AddInitialLayers_switch +8062f818 Section::AddInitialLayers_caseD_6 +8062f824 Section::AddInitialLayers_caseD_7 +8062f830 Section::AddInitialLayers_caseD_8 +8062f83c Section::AddInitialLayers_caseD_9 +8062f848 Section::AddInitialLayers_caseD_a +8062f854 Section::AddInitialLayers_caseD_b +8062f860 Section::AddInitialLayers_caseD_c +8062f86c Section::AddInitialLayers_caseD_d +8062f878 Section::AddInitialLayers_caseD_e +8062f884 Section::AddInitialLayers_caseD_f +8062f890 Section::AddInitialLayers_caseD_10 +8062f8a8 Section::AddInitialLayers_caseD_11 +8062f8c0 Section::AddInitialLayers_caseD_12 +8062f8d8 Section::AddInitialLayers_caseD_13 +8062f8f0 Section::AddInitialLayers_caseD_14 +8062f908 Section::AddInitialLayers_caseD_15 +8062f920 Section::AddInitialLayers_caseD_16 +8062f92c Section::AddInitialLayers_caseD_17 +8062f938 Section::AddInitialLayers_caseD_18 +8062f944 Section::AddInitialLayers_caseD_19 +8062f950 Section::AddInitialLayers_caseD_1a +8062f95c Section::AddInitialLayers_caseD_1b +8062f968 Section::AddInitialLayers_caseD_1c +8062f974 Section::AddInitialLayers_caseD_1d +8062f980 Section::AddInitialLayers_caseD_1e +8062f998 Section::AddInitialLayers_caseD_1f +8062f9bc Section::AddInitialLayers_caseD_20 +8062f9d4 Section::AddInitialLayers_caseD_21 +8062f9ec Section::AddInitialLayers_caseD_22 +8062fa04 Section::AddInitialLayers_caseD_23 +8062fa1c Section::AddInitialLayers_caseD_24 +8062fa34 Section::AddInitialLayers_caseD_25 +8062fa4c Section::AddInitialLayers_caseD_26 +8062fa64 Section::AddInitialLayers_caseD_27 +8062fa7c Section::AddInitialLayers_caseD_28 +8062fa94 Section::AddInitialLayers_caseD_29 +8062faac Section::AddInitialLayers_caseD_2a +8062fac4 Section::AddInitialLayers_caseD_2b +8062fadc Section::AddInitialLayers_caseD_2c +8062faf4 Section::AddInitialLayers_caseD_2d +8062fb0c Section::AddInitialLayers_caseD_2e +8062fb24 Section::AddInitialLayers_caseD_2f +8062fb48 Section::AddInitialLayers_caseD_30 +8062fb60 Section::AddInitialLayers_caseD_31 +8062fb84 Section::AddInitialLayers_caseD_32 +8062fba8 Section::AddInitialLayers_caseD_33 +8062fbcc Section::AddInitialLayers_caseD_34 +8062fbf0 Section::AddInitialLayers_caseD_35 +8062fbfc Section::AddInitialLayers_caseD_36 +8062fc08 Section::AddInitialLayers_caseD_37 +8062fc14 Section::AddInitialLayers_caseD_38 +8062fc20 Section::AddInitialLayers_caseD_39 +8062fc2c Section::AddInitialLayers_caseD_3a +8062fc38 Section::AddInitialLayers_caseD_3b +8062fc50 Section::AddInitialLayers_caseD_3c +8062fc68 Section::AddInitialLayers_caseD_3d +8062fc80 Section::AddInitialLayers_caseD_3e +8062fc98 Section::AddInitialLayers_caseD_3f +8062fcc8 Section::AddInitialLayers_caseD_40 +8062fcf8 Section::AddInitialLayers_caseD_41 +8062fd28 Section::AddInitialLayers_caseD_42 +8062fd58 Section::AddInitialLayers_caseD_43 +8062fd88 Section::AddInitialLayers_caseD_44 +8062fda0 Section::AddInitialLayers_caseD_45 +8062fdc4 Section::AddInitialLayers_caseD_46 +8062fde8 Section::AddInitialLayers_caseD_47 +8062fe0c Section::AddInitialLayers_caseD_48 +8062fe48 Section::AddInitialLayers_caseD_49 +8062fe84 Section::AddInitialLayers_caseD_4a +8062fec0 Section::AddInitialLayers_caseD_4b +8062fefc Section::AddInitialLayers_caseD_4c +8062ff38 Section::AddInitialLayers_caseD_4d +8062ff68 Section::AddInitialLayers_caseD_4e +8062ffa4 Section::AddInitialLayers_caseD_4f +8062ffe0 Section::AddInitialLayers_caseD_50 +8063001c Section::AddInitialLayers_caseD_51 +8063004c Section::AddInitialLayers_caseD_52 +8063007c Section::AddInitialLayers_caseD_53 +806300ac Section::AddInitialLayers_caseD_54 +806300dc Section::AddInitialLayers_caseD_55 +80630124 Section::AddInitialLayers_caseD_56 +8063016c Section::AddInitialLayers_caseD_57 +806301b4 Section::AddInitialLayers_caseD_58 +806301f0 Section::AddInitialLayers_caseD_59 +8063022c Section::AddInitialLayers_caseD_5a +80630244 Section::AddInitialLayers_caseD_5b +8063028c Section::AddInitialLayers_caseD_5c +806302d4 Section::AddInitialLayers_caseD_5d +8063031c Section::AddInitialLayers_caseD_5e +80630358 Section::AddInitialLayers_caseD_5f +80630394 Section::AddInitialLayers_caseD_60 +806303d0 Section::AddInitialLayers_caseD_61 +8063040c Section::AddInitialLayers_caseD_62 +80630448 Section::AddInitialLayers_caseD_63 +80630484 Section::AddInitialLayers_caseD_64 +806304c0 Section::AddInitialLayers_caseD_65 +806304fc Section::AddInitialLayers_caseD_66 +80630538 Section::AddInitialLayers_caseD_67 +80630574 Section::AddInitialLayers_caseD_68 +806305a4 Section::AddInitialLayers_caseD_69 +806305d4 Section::AddInitialLayers_caseD_6a +80630604 Section::AddInitialLayers_caseD_6b +80630634 Section::AddInitialLayers_caseD_6c +80630664 Section::AddInitialLayers_caseD_6d +80630694 Section::AddInitialLayers_caseD_6e +806306c4 Section::AddInitialLayers_caseD_6f +806306f4 Section::AddInitialLayers_caseD_70 +80630724 Section::AddInitialLayers_caseD_71 +80630754 Section::AddInitialLayers_caseD_72 +80630784 Section::AddInitialLayers_caseD_73 +806307b4 Section::AddInitialLayers_caseD_74 +806307e4 Section::AddInitialLayers_caseD_75 +80630814 Section::AddInitialLayers_caseD_76 +80630844 Section::AddInitialLayers_caseD_77 +80630874 Section::AddInitialLayers_caseD_78 +8063088c Section::AddInitialLayers_caseD_79 +806308a4 Section::AddInitialLayers_caseD_7a +806308bc Section::AddInitialLayers_caseD_7b +806308d4 Section::AddInitialLayers_caseD_7c +806308ec Section::AddInitialLayers_caseD_7d +80630934 Section::AddInitialLayers_caseD_7e +80630970 Section::AddInitialLayers_caseD_7f +80630994 Section::AddInitialLayers_caseD_80 +806309c4 Section::AddInitialLayers_caseD_81 +806309f4 Section::AddInitialLayers_caseD_82 +80630a18 Section::AddInitialLayers_caseD_83 +80630a60 Section::AddInitialLayers_caseD_84 +80630aa8 Section::AddInitialLayers_caseD_85 +80630acc Section::AddInitialLayers_caseD_86 +80630af0 Section::AddInitialLayers_caseD_87 +80630b14 Section::AddInitialLayers_caseD_88 +80630b2c Section::AddInitialLayers_caseD_89 +80630b44 Section::AddInitialLayers_caseD_8a +80630b5c Section::AddInitialLayers_caseD_8b +80630b74 Section::AddInitialLayers_caseD_8c +80630b98 Section::AddInitialLayers_caseD_8d +80630bbc Section::AddInitialLayers_caseD_8e +80630be0 Section::AddInitialLayers_caseD_8f +80630c04 Section::AddInitialLayers_caseD_90 +80630c34 Section::AddInitialLayers_caseD_91 +80630c64 Section::AddInitialLayers_caseD_92 +80630c94 Section::AddInitialLayers_caseD_93 +80630cd4 Section::GetSceneId +80630e80 Section::GetArchiveName +806311a4 Section::HasBackModel +80631244 Section::HasDriverController +8063133c Section::GetPageName +8063134c Section::GetSectionName +8063135c 0x8063135c +806313b4 Section::GetSoundId +80631644 Section::GetGroupId +806317cc 0x806317cc +80631900 Section::GetAudioStreamIdx +8063191c Section::GetAudioStreamIdx_switch +80631920 Section::GetAudioStreamIdx_caseD_0 +80631928 Section::GetAudioStreamIdx_caseD_1 +80631930 Section::GetAudioStreamIdx_caseD_2 +80631938 Section::GetAudioStreamIdx_caseD_5 +80631940 Section::GetAudioStreamIdx_caseD_6 +80631948 Section::GetAudioStreamIdx_caseD_10 +80631950 Section::GetAudioStreamIdx_caseD_4b +80631958 Section::GetAudioStreamIdx_caseD_4c +80631960 Section::GetAudioStreamIdx_caseD_4d +80631968 Section::GetAudioStreamIdx_caseD_4e +80631970 Section::GetAudioStreamIdx_caseD_57 +80631978 Section::GetAudioStreamIdx_caseD_58 +80631980 Section::GetAudioStreamIdx_caseD_5a +80631988 Section::GetAudioStreamIdx_caseD_5b +80631990 Section::GetAudioStreamIdx_caseD_5c +80631998 Section::GetAudioStreamIdx_caseD_5d +806319a0 Section::GetAudioStreamIdx_caseD_5e +806319a8 Section::GetAudioStreamIdx_caseD_5f +806319b0 Section::GetAudioStreamIdx_caseD_60 +806319b8 Section::GetAudioStreamIdx_caseD_65 +806319c0 Section::GetAudioStreamIdx_caseD_66 +806319c8 Section::GetAudioStreamIdx_caseD_69 +806319d0 Section::GetAudioStreamIdx_caseD_6b +806319d8 Section::GetAudioStreamIdx_caseD_6e +806319e0 Section::GetAudioStreamIdx_caseD_70 +806319e8 Section::GetAudioStreamIdx_caseD_72 +806319f0 Section::GetAudioStreamIdx_caseD_74 +806319f8 Section::GetAudioStreamIdx_caseD_75 +80631a00 Section::GetAudioStreamIdx_caseD_76 +80631a08 Section::GetAudioStreamIdx_caseD_77 +80631a10 Section::GetAudioStreamIdx_caseD_78 +80631a18 Section::GetAudioStreamIdx_caseD_7a +80631a20 Section::GetAudioStreamIdx_caseD_7f +80631a28 Section::GetAudioStreamIdx_caseD_80 +80631a30 Section::GetAudioStreamIdx_caseD_81 +80631a38 Section::GetAudioStreamIdx_caseD_84 +80631a40 Section::GetAudioStreamIdx_caseD_85 +80631a48 Section::GetAudioStreamIdx_caseD_8a +80631a50 Section::GetAudioStreamIdx_caseD_8b +80631a58 Section::GetAudioStreamIdx_caseD_8c +80631a60 Section::GetAudioStreamIdx_caseD_8d +80631a68 Section::GetAudioStreamIdx_caseD_8e +80631a70 Section::GetAudioStreamIdx_caseD_8f +80631a78 Section::GetAudioStreamIdx_caseD_90 +80631a80 Section::GetAudioStreamIdx_caseD_93 +80631a88 Section::GetAudioStreamIdx_caseD_95 +80631a90 Section::GetAudioStreamIdx_caseD_96 +80631a98 Section::GetAudioStreamIdx_caseD_98 +80631aa0 Section::GetAudioStreamIdx_caseD_9a +80631aa8 Section::GetAudioStreamIdx_caseD_9b +80631ab0 Section::GetAudioStreamIdx_caseD_9c +80631ab8 Section::GetAudioStreamIdx_caseD_9d +80631ac0 Section::GetAudioStreamIdx_caseD_9f +80631ac8 Section::GetAudioStreamIdx_caseD_a0 +80631ad0 Section::GetAudioStreamIdx_caseD_a1 +80631ad8 Section::GetAudioStreamIdx_caseD_a2 +80631ae0 Section::GetAudioStreamIdx_caseD_a5 +80631ae8 Section::GetAudioStreamIdx_caseD_a8 +80631af0 Section::GetAudioStreamIdx_caseD_b1 +80631af8 Section::GetAudioStreamIdx_caseD_b3 +80631b00 Section::GetAudioStreamIdx_caseD_b4 +80631b08 Section::GetAudioStreamIdx_caseD_b5 +80631b10 Section::GetAudioStreamIdx_caseD_b6 +80631b18 Section::GetAudioStreamIdx_caseD_b8 +80631b20 Section::GetAudioStreamIdx_caseD_b9 +80631b28 Section::GetAudioStreamIdx_caseD_bb +80631b30 Section::GetAudioStreamIdx_caseD_c0 +80631b38 Section::GetAudioStreamIdx_caseD_ca +80631b40 Section::GetAudioStreamIdx_caseD_cc +80631b48 Section::GetAudioStreamIdx_caseD_cd +80631b58 Pages::RaceMenu::SetNextPage +80631b60 Pages::RaceMenu::GetNextPage +80631b68 0x80631b68 +80631b70 0x80631b70 +80631b78 0x80631b78 +80631b84 0x80631b84 +80631b90 0x80631b90 +80631b98 0x80631b98 +80631c04 0x80631c04 +80631c10 Pages::QuitConfirmation::GetMessageBMG +80631c18 Pages::QuitConfirmation::IsPausePage +80631c20 Pages::QuitConfirmation::GetButtonsBRCTRName +80631c2c Pages::QuitConfirmation::GetVariantsIdxArray +80631c38 Pages::QuitConfirmation::GetButtonCount +80631c40 Pages::QuitConfirmation::__dt +80631cac Pages::QuitConfirmation::GetRuntimeTypeInfo +80631cb8 Pages::CheckRankings::GetMessageBMG +80631cc0 Pages::CheckRankings::IsPausePage +80631cc8 Pages::CheckRankings::GetButtonsBRCTRName +80631cd4 Pages::CheckRankings::GetVariantsIdxArray +80631ce0 Pages::CheckRankings::GetButtonCount +80631ce8 Pages::CheckRankings::__dt +80631d54 Pages::CheckRankings::GetRuntimeTypeInfo +80631d60 Pages::TTFriendGhostEnd::GetMessageBMG +80631d68 Pages::TTFriendGhostEnd::IsPausePage +80631d70 Pages::TTFriendGhostEnd::GetButtonsBRCTRName +80631d7c Pages::TTFriendGhostEnd::GetVariantsIdxArray +80631d88 Pages::TTFriendGhostEnd::GetButtonCount +80631d90 Pages::TTFriendGhostEnd::__dt +80631dfc Pages::TTFriendGhostEnd::GetRuntimeTypeInfo +80631e08 0x80631e08 +80631e10 0x80631e10 +80631e18 0x80631e18 +80631e24 0x80631e24 +80631e30 0x80631e30 +80631e38 0x80631e38 +80631ea4 0x80631ea4 +80631eb0 0x80631eb0 +80631eb8 0x80631eb8 +80631ec0 0x80631ec0 +80631ecc 0x80631ecc +80631ed8 0x80631ed8 +80631ee0 0x80631ee0 +80631f4c 0x80631f4c +80631f58 0x80631f58 +80631f60 0x80631f60 +80631f68 0x80631f68 +80631f74 0x80631f74 +80631f80 0x80631f80 +80631f88 0x80631f88 +80631ff4 0x80631ff4 +80632000 0x80632000 +80632008 0x80632008 +80632010 0x80632010 +8063201c 0x8063201c +80632028 0x80632028 +80632030 0x80632030 +8063209c 0x8063209c +806320a8 Pages::BattleFinalRaceEnd::GetMessageBMG +806320b0 Pages::BattleFinalRaceEnd::IsPausePage +806320b8 Pages::BattleFinalRaceEnd::GetButtonsBRCTRName +806320c4 Pages::BattleFinalRaceEnd::GetVariantsIdxArray +806320d0 Pages::BattleFinalRaceEnd::GetButtonCount +806320d8 Pages::BattleFinalRaceEnd::__dt +80632144 Pages::BattleFinalRaceEnd::GetRuntimeTypeInfo +80632150 Pages::BattleEnd::GetMessageBMG +80632158 Pages::BattleEnd::IsPausePage +80632160 Pages::BattleEnd::GetButtonsBRCTRName +8063216c Pages::BattleEnd::GetVariantsIdxArray +80632178 Pages::BattleEnd::GetButtonCount +80632180 Pages::BattleEnd::__dt +806321ec Pages::BattleEnd::GetRuntimeTypeInfo +806321f8 Pages::VSRaceEnd::GetMessageBMG +80632200 Pages::VSRaceEnd::IsPausePage +80632208 Pages::VSRaceEnd::GetButtonsBRCTRName +80632240 Pages::VSRaceEnd::GetVariantsIdxArray +8063224c Pages::VSRaceEnd::GetButtonCount +8063227c Pages::VSRaceEnd::__dt +806322e8 Pages::VSRaceEnd::GetRuntimeTypeInfo +806322f4 Pages::GPEnd::GetMessageBMG +806322fc Pages::GPEnd::IsPausePage +80632304 Pages::GPEnd::GetButtonsBRCTRName +8063233c Pages::GPEnd::GetVariantsIdxArray +80632348 Pages::GPEnd::GetButtonCount +80632378 Pages::GPEnd::__dt +806323e4 Pages::GPEnd::GetRuntimeTypeInfo +806323f0 Pages::TTEnd::GetMessageBMG +806323f8 Pages::TTEnd::IsPausePage +80632400 Pages::TTEnd::GetButtonsBRCTRName +8063240c Pages::TTEnd::GetVariantsIdxArray +80632418 Pages::TTEnd::GetButtonCount +80632420 Pages::TTEnd::__dt +8063248c Pages::TTEnd::GetRuntimeTypeInfo +80632498 0x80632498 +806324a0 0x806324a0 +806324a8 0x806324a8 +806324b4 0x806324b4 +806324c0 0x806324c0 +806324c8 0x806324c8 +80632534 0x80632534 +80632540 0x80632540 +80632548 0x80632548 +80632550 0x80632550 +8063255c 0x8063255c +80632568 0x80632568 +80632570 0x80632570 +806325dc 0x806325dc +806325e8 0x806325e8 +806325f0 0x806325f0 +806325f8 0x806325f8 +80632604 0x80632604 +80632610 0x80632610 +80632618 0x80632618 +80632684 0x80632684 +80632690 Pages::GhostReplayPause::GetMessageBMG +80632698 Pages::GhostReplayPause::IsPausePage +806326a0 Pages::GhostReplayPause::GetButtonsBRCTRName +806326ac Pages::GhostReplayPause::GetVariantsIdxArray +806326b8 Pages::GhostReplayPause::GetButtonCount +806326c0 Pages::GhostReplayPause::__dt +8063272c Pages::GhostReplayPause::GetRuntimeTypeInfo +80632738 Pages::GPReplayPause::GetMessageBMG +80632740 Pages::GPReplayPause::IsPausePage +80632748 Pages::GPReplayPause::GetButtonsBRCTRName +80632780 Pages::GPReplayPause::GetVariantsIdxArray +8063278c Pages::GPReplayPause::GetButtonCount +806327bc Pages::GPReplayPause::__dt +80632828 Pages::GPReplayPause::GetRuntimeTypeInfo +80632834 Pages::TTReplayPause::GetMessageBMG +8063283c Pages::TTReplayPause::IsPausePage +80632844 Pages::TTReplayPause::GetButtonsBRCTRName +80632850 Pages::TTReplayPause::GetVariantsIdxArray +8063285c Pages::TTReplayPause::GetButtonCount +80632864 Pages::TTReplayPause::__dt +806328d0 Pages::TTReplayPause::GetRuntimeTypeInfo +806328dc 0x806328dc +806328e4 0x806328e4 +806328ec 0x806328ec +806328f8 0x806328f8 +80632904 0x80632904 +8063290c 0x8063290c +80632978 0x80632978 +80632984 Pages::BattlePause::GetMessageBMG +8063298c Pages::BattlePause::IsPausePage +80632994 Pages::BattlePause::GetButtonsBRCTRName +806329bc Pages::BattlePause::GetVariantsIdxArray +806329c8 Pages::BattlePause::GetButtonCount +806329d0 Pages::BattlePause::__dt +80632a3c Pages::BattlePause::GetRuntimeTypeInfo +80632a48 Pages::VSPause::GetMessageBMG +80632a50 Pages::VSPause::IsPausePage +80632a58 Pages::VSPause::GetButtonsBRCTRName +80632a80 Pages::VSPause::GetVariantsIdxArray +80632a8c Pages::VSPause::GetButtonCount +80632a94 Pages::VSPause::__dt +80632b00 Pages::VSPause::GetRuntimeTypeInfo +80632b0c Pages::GPPause::GetMessageBMG +80632b14 Pages::GPPause::IsPausePage +80632b1c Pages::GPPause::GetButtonsBRCTRName +80632b28 Pages::GPPause::GetVariantsIdxArray +80632b34 Pages::GPPause::GetButtonCount +80632b3c Pages::GPPause::__dt +80632ba8 Pages::GPPause::GetRuntimeTypeInfo +80632bb4 Pages::TTPause::GetMessageBMG +80632bbc Pages::TTPause::IsPausePage +80632bc4 Pages::TTPause::GetButtonsBRCTRName +80632bd0 Pages::TTPause::GetVariantsIdxArray +80632bdc Pages::TTPause::GetButtonCount +80632be4 Pages::TTPause::__dt +80632c50 Pages::TTPause::GetRuntimeTypeInfo +80632c5c Pages::RaceHUD::GetNextPage +80632c64 Pages::LiveBattleViewHUD::GetCtrlRaceNameBalloonCount +80632c6c Pages::LiveBattleViewHUD::GetEnabledCtrlRaceBases +80632c74 Pages::LiveBattleViewHUD::GetPausePageId +80632c7c Pages::LiveBattleViewHUD::__dt +80632ce8 Pages::LiveBattleViewHUD::GetRuntimeTypeInfo +80632cf4 Pages::LiveViewHUD::GetCtrlRaceNameBalloonCount +80632cfc Pages::LiveViewHUD::GetEnabledCtrlRaceBases +80632d04 Pages::LiveViewHUD::GetPausePageId +80632d0c Pages::LiveViewHUD::__dt +80632d78 Pages::LiveViewHUD::GetRuntimeTypeInfo +80632d84 Pages::WiFiFriendTeamVSHUD::GetCtrlRaceNameBalloonCount +80632d8c Pages::WiFiFriendTeamVSHUD::GetEnabledCtrlRaceBases +80632d94 Pages::WiFiFriendTeamVSHUD::GetPausePageId +80632d9c Pages::WiFiFriendTeamVSHUD::__dt +80632e08 Pages::WiFiFriendVSHUD::GetRuntimeTypeInfo +80632e14 Pages::WiFiFriendVSHUD::GetCtrlRaceNameBalloonCount +80632e1c Pages::WiFiFriendVSHUD::GetEnabledCtrlRaceBases +80632e24 Pages::WiFiFriendVSHUD::GetPausePageId +80632e2c Pages::WiFiFriendVSHUD::__dt +80632e98 Pages::WiFiFriendVSHUD::GetRuntimeTypeInfo +80632ea4 Pages::WifiVSMultiHUD::GetCtrlRaceNameBalloonCount +80632eac Pages::WifiVSMultiHUD::GetEnabledCtrlRaceBases +80632eb4 Pages::WifiVSMultiHUD::GetPausePageId +80632ebc Pages::WifiVSMultiHUD::__dt +80632f28 Pages::WifiVSMultiHUD::GetRuntimeTypeInfo +80632f34 Pages::WifiVSHUD::GetCtrlRaceNameBalloonCount +80632f3c Pages::WifiVSHUD::GetEnabledCtrlRaceBases +80632f44 Pages::WifiVSHUD::GetPausePageId +80632f4c Pages::WifiVSHUD::__dt +80632fb8 Pages::WifiVSHUD::GetRuntimeTypeInfo +80632fc4 Pages::BattleMultiHUD::GetCtrlRaceNameBalloonCount +80632fcc Pages::BattleMultiHUD::GetEnabledCtrlRaceBases +80632fd4 Pages::BattleMultiHUD::GetPausePageId +8063300c Pages::BattleMultiHUD::__dt +80633078 Pages::BattleMultiHUD::GetRuntimeTypeInfo +80633084 Pages::BattleHUD::GetCtrlRaceNameBalloonCount +8063308c Pages::BattleHUD::GetEnabledCtrlRaceBases +80633094 Pages::BattleHUD::GetPausePageId +806330cc Pages::BattleHUD::__dt +80633138 Pages::BattleHUD::GetRuntimeTypeInfo +80633144 Pages::VSMultiHUD::GetCtrlRaceNameBalloonCount +8063314c Pages::VSMultiHUD::GetEnabledCtrlRaceBases +80633154 Pages::VSMultiHUD::GetPausePageId +8063315c Pages::VSMultiHUD::__dt +806331c8 Pages::VSMultiHUD::GetRuntimeTypeInfo +806331d4 Pages::VSHUD::GetCtrlRaceNameBalloonCount +806331dc Pages::VSHUD::GetEnabledCtrlRaceBases +806331e4 Pages::VSHUD::GetPausePageId +806331ec Pages::VSHUD::__dt +80633258 Pages::VSHUD::GetRuntimeTypeInfo +80633264 Pages::GPHUD::GetCtrlRaceNameBalloonCount +8063326c Pages::GPHUD::GetEnabledCtrlRaceBases +80633274 Pages::GPHUD::GetPausePageId +8063327c Pages::GPHUD::__dt +806332e8 Pages::GPHUD::GetRuntimeTypeInfo +806332f4 Pages::TTHUD::GetCtrlRaceNameBalloonCount +806332fc Pages::TTHUD::GetEnabledCtrlRaceBases +80633304 Pages::TTHUD::GetPausePageId +80633350 Pages::TTHUD::__dt +806333bc Pages::TTHUD::GetRuntimeTypeInfo +806333c8 Pages::GhostRaceHUD::GetCtrlRaceNameBalloonCount +806333d0 Pages::GhostRaceHUD::GetEnabledCtrlRaceBases +806333d8 Pages::GhostRaceHUD::GetPausePageId +80633418 Pages::GhostRaceHUD::__dt +80633484 Pages::GhostRaceHUD::GetRuntimeTypeInfo +80633490 Pages::RaceHUD::GetCtrlRaceNameBalloonCount +80633498 Pages::GPReplayHUD::GetEnabledCtrlRaceBases +806334a0 Pages::GPReplayHUD::GetPausePageId +806334a8 Pages::GPReplayHUD::__dt +80633514 Pages::GPReplayHUD::GetRuntimeTypeInfo +80633520 TriggerPtmf +80633550 TriggerPtmf +80633580 TriggerPtmf +806335b0 TriggerPtmf +806335e0 TriggerPtmf +80633610 TriggerPtmf +80633640 TriggerPtmf +80633670 TriggerPtmf +806336a0 TriggerPtmf +806336d0 TriggerPtmf +80633700 TriggerPtmf +80633730 TriggerPtmf +80633760 TriggerPtmf +80633790 TriggerPtmf +806337c0 TriggerPtmf +806337f0 TriggerPtmf +80633820 TriggerPtmf +80633850 TriggerPtmf +80633880 TriggerPtmf +806338b0 TriggerPtmf +806338e0 TriggerPtmf +80633910 TriggerPtmf +80633940 TriggerPtmf +80633970 TriggerPtmf +806339a0 TriggerPtmf +806339d0 TriggerPtmf +80633a00 TriggerPtmf +80633a30 TriggerPtmf +80633a60 TriggerPtmf +80633a90 TriggerPtmf +80633ac0 TriggerPtmf +80633af0 TriggerPtmf +80633b20 TriggerPtmf +80633b50 TriggerPtmf +80633b80 TriggerPtmf +80633bb0 TriggerPtmf +80633be0 TriggerPtmf +80633c10 TriggerPtmf +80633c40 TriggerPtmf +80633c70 TriggerPtmf +80633ca0 TriggerPtmf +80633cd0 TriggerPtmf +80633d00 TriggerPtmf +80633d30 TriggerPtmf +80633d60 TriggerPtmf +80633d90 TriggerPtmf +80633dc0 TriggerPtmf +80633df0 TriggerPtmf +80633e20 TriggerPtmf +80633e50 TriggerPtmf +80633e80 TriggerPtmf +80633eb0 TriggerPtmf +80633ee0 TriggerPtmf +80633f10 TriggerPtmf +80633f40 TriggerPtmf +80633f70 TriggerPtmf +80633fa0 TriggerPtmf +80633fd0 TriggerPtmf +80634000 TriggerPtmf +80634030 TriggerPtmf +80634060 TriggerPtmf +80634090 TriggerPtmf +806340c0 TriggerPtmf +806340f0 TriggerPtmf +80634120 TriggerPtmf +80634150 TriggerPtmf +80634180 TriggerPtmf +806341b0 SectionMgr::CreateSystemPages +806342cc SectionMgr::GetSectionPriority +806343dc SectionMgr::CreateInstance +80634414 SectionMgr::DestroyInstance +8063448c SectionMgr::__ct +80634510 SectionMgr::__dt +80634590 SectionMgr::Init +806346ec SectionMgr::GetBootSectionSceneId +80634708 SectionMgr::LoadSection +806347cc SectionMgr::EnterSection +806348e8 SectionMgr::ExitSection +80634c04 0x80634c04 +80634c0c SectionMgr::RaceUpdate +80634c58 SectionMgr::Update +80634f88 SectionMgr::MenuUpdate +80634fdc SectionMgr::UnkUpdate +80635178 SectionMgr::Pause +80635180 SectionMgr::Resume +80635188 SectionMgr::SetNextSection +80635214 SectionMgr::RequestSceneChange +80635278 SectionMgr::RequestSceneReinit +806352bc SectionMgr::HandleHomeAction +80635358 SectionMgr::RequestGoToWiiMenu +806353c0 SectionMgr::RequestPowerOff +80635428 SectionMgr::GetNextSectionArchiveName +80635430 SectionMgr::NextSectionHasBackModel +80635438 SectionMgr::NextSectionHasDriverController +80635440 SectionMgr::UpdateStatusBitfield +80635554 SectionMgr::UpdateDVDStatus +80635604 SheetSelectControl::GetClassName +80635610 SheetSelectControl::__ct +806357c8 SheetSelectControl::__dt +8063586c SheetSelectControl::Load +80635930 SheetSelectControl::Func_0x38 +80635934 SheetSelectControl::SetRightArrowHandler +8063593c SheetSelectControl::SetLeftArrowHandler +80635944 SheetSelectControl::SetEnabledHudSlots +806359b0 SheetSelectControl::Toggle +80635a34 SheetSelectControl::Init +80635a98 SheetSelectControl::Update +80635a9c SheetSelectControl::HandleRightArrowSelect +80635b20 SheetSelectControl::AfterRightScroll +80635b24 SheetSelectControl::HandleLeftArrowSelect +80635ba8 SheetSelectControl::AfterLeftScroll +80635bac SheetSelectControl::SheetSelectButton::GetClassName +80635bbc SheetSelectControl::SheetSelectButton::__ct +80635cb0 SheetSelectControl::SheetSelectButton::__dt +80635d18 SheetSelectControl::SheetSelectButton::Load +80635f44 SheetSelectControl::SheetSelectButton::Init +80636130 SheetSelectControl::SheetSelectButton::Update +80636378 SheetSelectControl::SheetSelectButton::SetEnabledHudSlots +80636394 SheetSelectControl::SheetSelectButton::Toggle +806363b8 SheetSelectControl::SheetSelectButton::GetParentControl +80636454 SheetSelectControl::SheetSelectButton::HandleSelect +80636710 SheetSelectControl::SheetSelectButton::HandleDeselect +806368f8 SheetSelectControl::SheetSelectButton::Select +80636a90 SheetSelectControl::SheetSelectButton::SetPositionAnim +80636bc0 SheetSelectControl::GetArrowAnimationType +80636bc8 SheetSelectControlScaleFade::GetClassName +80636bd8 SheetSelectControlScaleFade::GetArrowAnimationType +80636be0 SheetSelectControlScaleFade::GetRuntimeTypeInfo +80636bec SheetSelectControl::GetRuntimeTypeInfo +80636bf8 SheetSelectControl::SheetSelectButton::GetRuntimeTypeInfo +80636c04 SheetSelectControl::SheetSelectButton::TriggerPtmf +80636c34 SheetSelect_cpp_sinit_ +80636c60 Pages::ESRBNotice::__ct +80636cac Pages::ESRBNotice::__dt +80636d20 Pages::ESRBNotice::OnInit +80636dc4 Pages::ESRBNotice::AfterControlUpdate +80636e34 Pages::Suggest60Hz::__ct +80636e80 Pages::Suggest60Hz::__dt +80636ef4 Pages::Suggest60Hz::OnInit +80636f9c Pages::Suggest60Hz::OnActivate +80636fe8 Pages::Suggest60Hz::AfterControl +806370a0 Pages::Suggest60Hz::IsHomeMenuWorking +806370a8 Pages::Suggest60Hz::GetRuntimeTypeInfo +806370b4 Pages::ESRBNotice::IsHomeMenuWorking +806370bc Pages::ESRBNotice::GetRuntimeTypeInfo +806370c8 NoticePages_cpp_sinit_ +806370e4 SystemBMGHolder::__ct +80637114 SystemBMGHolder::__dt +8063716c SystemBMGHolder::Init +80637178 SystemBMGHolder::GetMessage +806371b0 TabControl::GetClassName +806371bc TabControl::__ct +80637218 TabControl::__dt +80637290 TabControl::Load +8063740c TabControl::OnLoadingEnd +80637410 TabControl::SetOnClickHandler +80637418 TabControl::SetEnabledHudSlots +80637494 TabControl::SelectInitial +80637534 TabControl::SelectButtonNoPtmf +806375ac TabControl::Init +80637680 TabControl::Update +80637684 TabControl::SelectButton +80637724 TabControl::OptionButton::GetClassName +80637734 TabControl::OptionButton::__ct +80637828 TabControl::OptionButton::__dt +80637890 TabControl::OptionButton::Load +80637a5c TabControl::OptionButton::Init +80637c08 TabControl::OptionButton::Update +80637db4 TabControl::OptionButton::SetEnabledHudSlots +80637dbc TabControl::OptionButton::GetParentControl +80637ebc TabControl::OptionButton::SetInitialState +80637f1c TabControl::OptionButton::ChangeButtonState +80638074 TabControl::OptionButton::HandleSelect +80638168 TabControl::OptionButton::HandleDeselect +80638350 TabControl::OptionButton::HandleClick +8063850c TabControl::Func_0x40 +80638510 TabControl::GetRuntimeTypeInfo +8063851c TabControl::OptionButton::GetRuntimeTypeInfo +80638528 TabControl::OptionButton::TriggerPtmf +80638558 TabControl_cpp_sinit_ +80638574 Pages::GhostSelectSupporting::__ct +806385b8 Pages::GhostSelectSupporting::__dt +80638620 Pages::GhostSelectSupporting::OnInit +8063868c Pages::GhostSelectSupporting::OnActivate +80638830 Pages::GhostSelectSupporting::BeforeEntranceAnimations +80638834 Pages::GhostSelectSupporting::BeforeExitAnimations +80638838 Pages::GhostSelectSupporting::AfterControlUpdate +8063894c Pages::GhostSelectSupporting::OnResume +80638ab4 Pages::GhostSelectSupporting::InitGhostList +80638cd8 Pages::GhostSelect::__ct +80638f18 Pages::GhostSelect::__dt +80638ff4 Pages::GhostSelect::OnInit +806392bc Pages::GhostSelect::OnActivate +80639420 Pages::GhostSelect::BeforeEntranceAnimations +80639458 Pages::GhostSelect::OnResume +80639890 Pages::GhostSelect::OnRightArrowPress +80639990 Pages::GhostSelect::OnLeftArrowPress +80639a8c Pages::GhostSelect::OnChallengeGhostPress +80639aac Pages::GhostSelect::OnWatchReplayPress +80639acc Pages::GhostSelect::OnSoloTTPress +80639aec 0x80639aec +80639b30 Pages::GhostSelect::OnBackPress +80639b48 0x80639b48 +80639ba4 Pages::GhostSelect::GetNextPage +80639bac Pages::GhostSelect::GetRuntimeTypeInfo +80639bb8 Pages::GhostSelectSupporting::GetNextPage +80639bc0 Pages::GhostSelectSupporting::GetRuntimeTypeInfo +80639bcc TriggerPtmf +80639bfc TriggerPtmf +80639c2c TriggerPtmf +80639c5c GhostSelectPage_cpp_sinit_ +80639c78 TitleImage::GetClassName +80639c84 TitleImage::__ct +80639cc0 TitleImage::__dt +80639d18 TitleImage::Load +80639db8 TitleImage::InitSelf +80639df0 0x80639df0 +80639ea0 0x80639ea0 +80639ed8 0x80639ed8 +80639f88 0x80639f88 +80639fc0 TitleImage::ChangeImage +8063a0f4 Pages::Title::__ct +8063a178 CtrlMenuPressStart::__dt +8063a1d0 Pages::Title::__dt +8063a258 Pages::Title::OnInit +8063a44c Pages::Title::OnDispose +8063a450 Pages::Title::OnActivate +8063a4d0 Pages::Title::BeforeEntranceAnimations +8063a580 Pages::Title::AfterEntranceAnimations +8063a5cc Pages::Title::BeforeExitAnimations +8063a67c Pages::Title::AfterExitAnimations +8063a6b4 Pages::Title::AfterControlUpdate +8063a810 Pages::Title::OnResume +8063a81c Pages::Title::PrepareDemo +8063ac00 Pages::BlurryTitle::__ct +8063ac4c Pages::BlurryTitle::__dt +8063acc0 Pages::BlurryTitle::OnInit +8063ad84 Pages::BlurryTitle::OnActivate +8063aedc Pages::BlurryTitle::BeforeEntranceAnimations +8063aee0 TitleMovieControl::GetClassName +8063aef0 TitleMovieControl::__ct +8063af2c TitleMovieControl::__dt +8063af84 TitleMovieControl::Load +8063b024 TitleMovieControl::InitSelf +8063b05c TitleMovieControl::OnUpdate +8063b060 0x8063b060 +8063b110 0x8063b110 +8063b1c0 0x8063b1c0 +8063b1f4 Pages::TitleMovie::__ct +8063b258 Pages::TitleMovie::__dt +8063b2d0 Pages::TitleMovie::OnInit +8063b3e4 0x8063b3e4 +8063b4b0 Pages::TitleMovie::AfterExitAnimations +8063b4f4 Pages::TitleMovie::OnDeactivate +8063b508 Pages::TitleMovie::BeforeControlUpdate +8063b638 Pages::TitleMovie::AfterControlUpdate +8063b718 Pages::BlinkingPressA::__ct +8063b77c Pages::BlinkingPressA::__dt +8063b7f4 Pages::BlinkingPressA::OnInit +8063b87c Pages::BlinkingPressA::OnActivate +8063b8d4 Pages::BlinkingPressA::OnDeactivate +8063b8e8 Pages::BlinkingPressA::AfterControlUpdate +8063b9d4 Pages::BlinkingPressA::GetRuntimeTypeInfo +8063b9e0 Pages::TitleMovie::GetRuntimeTypeInfo +8063b9ec TitleMovieControl::GetRuntimeTypeInfo +8063b9f8 Pages::BlurryTitle::GetRuntimeTypeInfo +8063ba04 Pages::Title::GetNextPage +8063ba0c Pages::Title::GetRuntimeTypeInfo +8063ba18 TitleImage::GetRuntimeTypeInfo +8063ba24 Title_cpp_sinit_ +8063ba58 UIAnimator::__ct +8063ba70 UIAnimator::__dt +8063bad0 UIAnimator::SetLayout +8063badc UIAnimator::Init +8063bb40 UIAnimator::InitAnimationGroup +8063bba8 Animation::__ct +8063bbcc UIAnimator::AppendGroup +8063bcbc UIAnimator::LoadNewAnimation +8063bd80 UIAnimator::LoadAnimation +8063be28 UIAnimator::Update +8063be8c UIAnimator::GetAnimationGroupById +8063be9c UIAnimator::GetAnimationGroupById +8063beac 0x8063beac +8063beb0 AnimationGroup::__ct +8063bf18 AnimationGroup::__dt +8063bf88 AnimationGroup::PlayAnimationAtFrame +8063c104 AnimationGroup::PlayAnimationAtPercent +8063c18c AnimationGroup::PlayAnimationAtFrameAndDisable +8063c1c0 AnimationGroup::PlayAnimationAtPercentAndDisable +8063c250 AnimationGroup::Update +8063c448 0x8063c448 +8063c4d8 UIControl::__ct +8063c5cc 0x8063c5cc +8063c60c UIControl::__dt +8063c668 UIControl::8063cffc +8063c670 UIControl::Init +8063c6b0 UIControl::Update +8063c6f0 UIControl::Draw +8063c724 UIControl::SetPosition +8063c74c UIControl::PlayAnimationSound +8063c800 UIControl::SetPositionAnim +8063c8d4 UIControl::InitControlGroup +8063c8e4 UIControl::AddControl +8063c8f0 UIControl::GetAnimationDelay +8063ca04 UIControl::SetParentControlGroup +8063ca10 UIControl::SetSoundIds +8063ca1c UIControl::GetClassName +8063ca2c 0x8063ca2c +8063ca38 UIControl::PositionFromBasePosition +8063cbbc UIControl::CalculatePosition +8063cc74 UIControl::vf_0x30 +8063ccb4 UIControl::8063d648 +8063cdb8 UIControl::PlaySound +8063cdd0 UIControl::StopSound +8063cddc UIControl::HoldSound +8063cdf4 LayoutUIControl::GetClassName +8063ce04 LayoutUIControl::__ct +8063cf2c LayoutUIControl::__dt +8063cfc0 LayoutUIControl::LoadLayout +8063d02c LayoutUIControl::LoadPictureLayout +8063d06c LayoutUIControl::SetRootPane +8063d12c LayoutUIControl::Init +8063d16c LayoutUIControl::Update +8063d1f0 LayoutUIControl::Draw +8063d328 LayoutUIControl::SetTextBoxMessage +8063d420 LayoutUIControl::SetMessage +8063d460 LayoutUIControl::MessageRequester::Calc +8063d558 LayoutUIControl::ResetTextBoxMsg +8063d634 LayoutUIControl::ResetMsg +8063d66c LayoutUIControl::MessageResetter::Calc +8063d75c LayoutUIControl::SetPicturePane +8063d994 LayoutUIControl::PicturePaneExists +8063da48 LayoutUIControl::SetMiiPane +8063dbb8 LayoutUIControl::SetPaneVisibility +8063dbf8 LayoutUIControl::CropMovie(Rect) +8063dc30 LayoutUIControl::CropMovie(4floats) +8063dc88 LayoutUIControl::vf_0x30 +8063dcd0 LayoutUIControlScaleFade::GetClassName +8063dce0 LayoutUIControlScaleFade::__ct +8063de14 LayoutUIControlScaleFade::__dt +8063deac LayoutUIControlScaleFade::SetPositionAnim +8063df90 LayoutUIControlScaleFade::GetRuntimeTypeInfo +8063df9c LayoutUIControlcpp_sinit_ +8063dfc0 UpDownControl::GetClassName +8063dfcc UpDownControl::__ct +8063e1c8 UpDownControl::__dt +8063e248 UpDownControl::Load +8063e688 UpDownControl::OnLoadingEnd +8063e68c UpDownControl::SetOnChangeHandler +8063e694 UpDownControl::SetOnClickHandler +8063e69c UpDownControl::SetOnElementSelectHandler +8063e6a4 UpDownControl::SetOnDeselectHandler +8063e6ac 0x8063e6ac +8063e718 0x8063e718 +8063e72c UpDownControl::SelectInitial(count+initial) +8063e74c UpDownControl::SelectInitial(initial) +8063e764 0x8063e764 +8063e7cc UpDownControl::SetPlayerBitfield +8063e7d8 UpDownControl::Init +8063e914 UpDownControl::Update +8063ed00 UpDownControl::HandleSelect +8063ee30 UpDownControl::HandleDeselect +8063ef34 UpDownControl::HandleButtonSelect +8063ef4c UpDownControl::HandleButtonDeselect +8063ef64 UpDownControl::HandleClick +8063f1d0 UpDownControl::HandleRightPress +8063f2fc UpDownControl::HandleLeftPress +8063f41c UpDownControl::UpDownButton::GetClassName +8063f42c UpDownControl::UpDownButton::__ct +8063f468 UpDownControl::UpDownButton::__dt +8063f4c0 UpDownControl::UpDownButton::Load +8063f584 UpDownControl::UpDownButton::Init +8063f61c UpDownControl::UpDownButton::Update +8063f708 UpDownControl::UpDownButton::GetParentControl +8063f808 UpDownControl::UpDownButton::ToggleSelect +8063f9cc 0x8063f9cc +8063fa30 0x8063fa30 +8063fb74 0x8063fb74 +8063fc1c 0x8063fc1c +8063fc24 0x8063fc24 +8063fc2c TextUpDownValueControl::GetClassName +8063fc3c TextUpDownValueControl::__ct +8063fca8 TextUpDownValueControl::__dt +8063fd1c TextUpDownValueControl::Load +8063fe40 TextUpDownValueControl::SetOnTextChangeHandler +8063fe48 TextUpDownValueControl::Init +8063ff68 TextUpDownValueControl::Update +8064000c 0x8064000c +8064010c TextUpDownValueControl::InitText +806401d4 TextUpDownValueControl::OnSelect +80640348 TextUpDownValueControl::SetMessage +80640378 TextUpDownValueControl::SetMessageAnimated +80640468 TextUpDownValueControl::OnClick +806404d4 TextUpDownValueControl::IsOKStop +8064056c TextUpDownValueControl::Get3rdAnimStartFrame +806405e0 TextUpDownValueControl::SetBorderColours +80640694 TextUpDownValueControl::SetColor_BaseColours +8064073c TextUpDownValueControl::TextControl::GetClassName +8064074c TextUpDownValueControl::TextControl::__ct +80640788 TextUpDownValueControl::TextControl::__dt +806407e0 TextUpDownValueControl::TextControl::Load +80640854 TextUpDownValueControl::TextControl::InitSelf +80640904 0x80640904 +80640964 TextUpDownValueControl::TextControl::ToggleState +80640ac8 UpDownControlOld::1 +80640ad8 UpDownControlOld::2 +80640c90 UpDownControlOld::3 +80640cf8 UpDownControlOld::4 +80641040 UpDownControlOld::5 +80641048 UpDownControlOld::6 +8064112c UpDownControlOld::7 +806412f8 UpDownControlOld::8 +8064130c 0x8064130c +80641314 UpDownControlOld::9 +806413f4 UpDownControlOld::10 +806413f8 UpDownControlOld::11 +806415f8 UpDownControlOld::12 +806415fc UpDownControlOld::13 +806416dc UpDownControlOld::14 +80641924 UpDownControlOld::15 +806419dc UpDownControlOld::16 +80641a90 UpDownControlOld::17 +80641be0 UpDownControlOld::18 +80641c98 UpDownControlOld::19 +80641c9c UpDownControlOld::20 +80641d50 UpDownControlOld::21 +80641d54 TextUpDownControlOld::1 +80641d64 TextUpDownControlOld::2 +80641f28 TextUpDownControlOld::3 +80641f94 TextUpDownControlOld::4 +80641fc8 0x80641fc8 +80641fd0 0x80641fd0 +80641fd8 0x80641fd8 +80641fdc 0x80641fdc +80641fe8 0x80641fe8 +80641ff4 TextUpDownValueControl::GetTextControl +80641ff8 TextUpDownValueControl::GetRuntimeTypeInfo +80642004 TextUpDownValueControl::TextControl::GetRuntimeTypeInfo +80642010 UpDownControl::Func_0x40 +80642014 UpDownControl::GetRuntimeTypeInfo +80642020 UpDownControl::UpDownButton::GetRuntimeTypeInfo +8064202c TriggerPtmf +8064205c TriggerPtmf +8064208c UpDownControl_cpp_sinit_ +806420bc TextUpDownValueControl::SetColor_BaseColours(UpDownDisplayedText) +806420c4 TextUpDownValueControl::SetBorderColours(UpDownDisplayedText) +806420cc TextUpDownValueControl::Get3rdAnimStartFrame(UpDownDisplayedText) +806420d4 TextUpDownValueControl::Animate(UpDownDisplayedText) +806420dc TextUpDownValueControl::OnClick(UpDownDisplayedText) +806420e4 TextUpDownValueControl::SetMessageAnimated(UpDownDisplayedText) +806420ec TextUpDownValueControl::SetMessage(UpDownDisplayedText) +806420f4 TextUpDownValueControl::OnSelect(UpDownDisplayedText) +806420fc TextUpDownValueControl::InitText(UpDownDisplayedText) +80642104 TextUpDownValueControl::GetTextControl(UpDownDisplayedText) +8064210c VoteControl::GetClassName +80642118 VoteControl::__ct +80642154 VoteControl::__dt +806421ac VoteControl::Load +80642258 VoteControl::InitSelf +8064230c VoteControl::OnUpdate +80642310 VoteControl::Fill +80642480 VoteControl::AnimateSelect +806424d4 VoteControl::AnimateDeselect +8064250c VoteControl::AnimateChose +80642568 VoteControl::AnimateFadeOut +806425c4 VoteControl::IsAnimationShow +806425fc Pages::Vote::__ct +80642728 Pages::Vote::__dt +806427d4 Pages::Vote::OnInit +80642874 Pages::Vote::OnInit_switch +80642878 Pages::Vote::OnInit_case58 +80642884 Pages::Vote::OnInit_case59 +8064288c Pages::Vote::OnInit_case5a +80642a34 Pages::Vote::OnDispose +80642a38 Pages::Vote::BeforeEntranceAnimations +80642e54 Pages::Vote::BeforeControlUpdate +80643390 Pages::Vote::BeforeControlUpdate_switch +80643394 Pages::Vote::BeforeControlUpdate_case58 +8064339c Pages::Vote::BeforeControlUpdate_case59 +806433a4 Pages::Vote::BeforeControlUpdate_case5e +806433ac Pages::Vote::BeforeControlUpdate_case5f +806433b4 Pages::Vote::BeforeControlUpdate_case60 +806433bc Pages::Vote::BeforeControlUpdate_case61 +806433c4 Pages::Vote::BeforeControlUpdate_case62 +806433cc Pages::Vote::BeforeControlUpdate_case63 +806433d4 Pages::Vote::BeforeControlUpdate_case64 +806433dc Pages::Vote::BeforeControlUpdate_case65 +806433e4 Pages::Vote::BeforeControlUpdate_case66 +806433ec Pages::Vote::BeforeControlUpdate_case67 +806433f0 Pages::Vote::BeforeControlUpdate_caseDefault +80643504 Pages::Vote::BeforeExitAnimations +80643584 Pages::Vote::GetNextPage +806435b4 Pages::Vote::SetVotedCourseId +806435e4 Pages::Vote::SetCourseButtonId_switch +806435e8 Pages::Vote::SetCourseButtonId_case58 +806435f0 Pages::Vote::SetCourseButtonId_case59 +806435f4 Pages::Vote::SetCourseButtonId_case5a +806435f8 Pages::Vote::FillVoteControl +80643854 Pages::Vote::StartRoulette +80643a9c Pages::Vote::FillVotesCounter +80643c14 Pages::Vote::OnMessageBoxClick +80643cb8 Pages::Vote::GetRuntimeTypeInfo +80643cc4 VoteControl::GetRuntimeTypeInfo +80643cd0 TriggerPtmf +80643d00 VotePage_cpp_sinit_ +80643d24 0x80643d24 +80643d68 0x80643d68 +80643dd0 0x80643dd0 +80643e2c 0x80643e2c +80643f24 Page::EndExitState +80643f28 0x80643f28 +80643f2c 0x80643f2c +80644054 0x80644054 +80644064 0x80644064 +806441bc 0x806441bc +8064425c 0x8064425c +806443c4 0x806443c4 +806444ac 0x806444ac +806446e4 0x806446e4 +8064477c 0x8064477c +806447e4 0x806447e4 +806449b4 0x806449b4 +806449c0 0x806449c0 +806449c8 0x806449c8 +806449d4 0x806449d4 +80644a04 0x80644a04 +80644a34 0x80644a34 +80644a50 0x80644a50 +80644a5c 0x80644a5c +80644a98 0x80644a98 +80644af0 0x80644af0 +80644b90 0x80644b90 +80644bc8 0x80644bc8 +80644c00 0x80644c00 +80644c38 WifiAwardResultItem::GetClassName +80644c48 WifiAwardResultItem::__ct +80644c84 WifiAwardResultItem::__dt +80644cdc WifiAwardResultItem::Load +80644e54 WifiAwardResultItem::InitSelf +80644e8c 0x80644e8c +80645234 Pages::WiFiVSResults::__ct +806452f8 Pages::WiFiVSResults::__dt +80645394 Pages::WiFiVSResults::OnInit +806456c8 Pages::WiFiVSResults::OnActivate +806457b4 Pages::WiFiVSResults::BeforeEntranceAnimations +806457c8 Pages::WiFiVSResults::AfterEntranceAnimations +80645820 Pages::WiFiVSResults::BeforeExitAnimations +80645834 Pages::WiFiVSResults::AfterControlUpdate +8064586c Pages::WiFiVSResults::OnClick +80645878 0x80645878 +806458e4 0x806458e4 +80645a0c 0x80645a0c +80645c4c 0x80645c4c +80645dbc Pages::WiFiVSResults::GetNextPage +80645dc4 Pages::WiFiVSResults::GetRuntimeTypeInfo +80645dd0 WifiAwardResultItem::GetRuntimeTypeInfo +80645ddc 0x80645ddc +80645de8 TriggerPtmf +80645e18 WiFiVSResults_cpp_sinit_ +80645e40 Pages::WFCConnect::__ct +80645ebc Pages::WFCConnect::__dt +80645f24 Pages::WFCConnect::OnInit +80645f90 Pages::WFCConnect::OnActivate +80646440 Pages::WFCConnect::BeforeEntranceAnimations +80646444 Pages::WFCConnect::AfterEntranceAnimations +80646464 Pages::WFCConnect::BeforeExitAnimations +80646468 Pages::WFCConnect::AfterExitAnimations +8064646c Pages::WFCConnect::OnDeactivate +8064651c Pages::WFCConnect::AfterControlUpdate +80646b54 Pages::WFCConnect::OnResume +80646f30 Pages::WFCConnect::GetNextPage +80647004 Pages::WFCConnect::IsHomeMenuWorking +80647048 Pages::WFCConnect::SetText +80647358 Pages::WFCConnect::GetTitleBMGId +80647424 Pages::WFCConnect::OnDisconnect +80647538 Pages::WFCDataStatement::__ct +80647650 Pages::WFCDataStatement::__dt +806476f0 Pages::WFCDataStatement::OnInit +8064788c Pages::WFCDataStatement::OnActivate +80647a34 Pages::WFCDataStatement::SetType +80647a70 Pages::WFCDataStatement::OnButtonClick +80647aec Pages::WFCDataStatement::OnBackPress +80647b14 Pages::WFCAllowData::__ct +80647c7c Pages::WFCAllowData::__dt +80647d28 Pages::WFCAllowData::OnInit +80647f20 Pages::WFCAllowData::OnActivate +80648090 Pages::WFCAllowData::OnResume +80648168 Pages::WFCAllowData::OnButtonClick +80648308 Pages::WFCAllowData::OnBackButtonClick +80648320 Pages::WFCAllowData::OnBackPress +80648454 Pages::WFCDisconnect::__ct +806484d0 Pages::WFCDisconnect::__dt +80648538 Pages::WFCDisconnect::OnInit +80648594 Pages::WFCDisconnect::OnActivate +80648790 Pages::WFCDisconnect::BeforeEntranceAnimations +80648794 Pages::WFCDisconnect::BeforeExitAnimations +80648798 Pages::WFCDisconnect::OnDeactivate +80648848 Pages::WFCDisconnect::OnResume +80648858 Pages::WFCDisconnect::OnYesNoYesClick +80648938 Pages::WFCDisconnect::GetRuntimeTypeInfo +80648944 Pages::WFCAllowData::GetRuntimeTypeInfo +80648950 Pages::WFCDataStatement::GetRuntimeTypeInfo +8064895c Pages::WFCConnect::GetRuntimeTypeInfo +80648968 TriggerPtmf +80648998 TriggerPtmf +806489c8 TriggerPtmf +806489f8 TriggerPtmf +80648a28 TriggerPtmf +80648a58 TriggerPtmf +80648a88 TriggerPtmf +80648ab8 WFCConnectPage_cpp_sinit_ +80648adc Pages::DisconnectMgr::__ct +80648b28 Pages::DisconnectMgr::__dt +80648b90 Pages::DisconnectMgr::OnInit +80648bfc Pages::DisconnectMgr::OnUpdate +80648ff4 Pages::DisconnectError::__ct +80649080 Pages::DisconnectError::__dt +80649100 Pages::DisconnectError::OnInit +806491fc Pages::DisconnectError::OnActivate +80649384 Pages::DisconnectError::AfterControlUpdate +806493cc Pages::DisconnectError::BeforeEntranceAnimations +806493d8 Pages::DisconnectError::IsHomeMenuWorking +80649410 Pages::DisconnectError::GetErrorBMGId +80649644 Pages::DisconnectError::OnClick +806496b8 Pages::DisconnectError::GetRuntimeTypeInfo +806496c4 Pages::DisconnectMgr::GetRuntimeTypeInfo +806496d0 TriggerPtmf +80649700 DisconnectPage_cpp_sinit_ +8064971c Pages::LiveViewWaiting::__ct +80649778 Pages::LiveViewWaiting::__dt +80649804 Pages::LiveViewWaiting::OnInit +80649904 Pages::LiveViewWaiting::AfterControlUpdate +80649944 Pages::LiveViewWaiting::GetNextPage +80649990 Pages::LiveViewWaiting::BeforeExitAnimations +806499dc Pages::LiveViewWaiting::BeforeEntranceAnimations +80649a34 Pages::LiveViewWaiting::AfterExitAnimations +80649a40 Pages::LiveViewWaiting::GetRuntimeTypeInfo +80649a4c LiveViewWaitingPage_cpp_sinit_ +80649a60 Pages::VR::__ct +80649b4c Pages::VR::__dt +80649bf8 Pages::VR::OnInit +80649cdc Pages::VR::OnInit_switch +80649ce0 Pages::VR::OnInit_case58 +80649cf4 Pages::VR::OnInit_case59 +80649d04 Pages::VR::OnInit_case5a +80649eb8 Pages::VR::OnActivate +80649f74 Pages::VR::OnActivate_switch +80649f78 Pages::VR::OnActivate_case58 +80649f80 Pages::VR::OnActivate_case59 +80649f84 Pages::VR::OnActivate_case5a +8064a130 Pages::VR::AfterControlUpdate +8064a174 Pages::VR::FillVRControl +8064a4d8 Pages::VR::OnButtonClick +8064a514 Pages::VR::GetRuntimeTypeInfo +8064a520 TriggerPtmf +8064a550 VRPage_cpp_sinit_ +8064a564 Pages::Approve2PWFC::__ct +8064a5e0 Pages::Approve2PWFC::__dt +8064a648 Pages::Approve2PWFC::OnInit +8064a6b4 Pages::Approve2PWFC::OnActivate +8064a7c8 Pages::Approve2PWFC::BeforeEntranceAnimations +8064a7cc Pages::Approve2PWFC::BeforeExitAnimations +8064a7d0 Pages::Approve2PWFC::OnResume +8064a890 Pages::Approve2PWFC::GetNextPage +8064a8a8 Pages::Approve2PWFC::OnApprove +8064a920 FriendsStatusButton::GetClassName +8064a92c FriendsStatusButton::__ct +8064a968 FriendsStatusButton::__dt +8064a9c0 FriendsStatusButton::Load +8064aab0 FriendsStatusButton::InitSelf +8064aabc FriendsStatusButton::OnUpdate +8064ab2c FriendsStatusButton::OnSelect +8064ab30 FriendsStatusButton::OnDeselect +8064ab34 FriendsStatusButton::UpdateFriendStatus +8064acac Pages::WFCMainMenu::__ct +8064aebc Pages::WFCMainMenu::__dt +8064af7c Pages::WFCMainMenu::OnInit +8064b2fc Pages::WFCMainMenu::OnActivate +8064b354 Pages::WFCMainMenu::OnWorldwideButtonClick +8064b430 Pages::WFCMainMenu::OnRegionalButtonClick +8064b50c Pages::WFCMainMenu::OnFriendsButtonClick +8064b550 Pages::WFCMainMenu::OnBackButtonClick +8064b5b8 Pages::WFCMainMenu::OnButtonSelect +8064b624 Pages::WFCMainMenu::OnBackPress +8064b644 Pages::WFCModeSelect::__ct +8064b7dc Pages::WFCModeSelect::__dt +8064b88c Pages::WFCModeSelect::OnInit +8064bb64 Pages::WFCModeSelect::OnActivate +8064bc7c Pages::WFCModeSelect::OnModeButtonClick +8064bd84 Pages::WFCModeSelect::OnBackButtonClick +8064bdc8 Pages::WFCModeSelect::OnModeButtonSelect +8064be1c Pages::WFCModeSelect::OnBackPress +8064be34 Pages::WFCFriendsMenu::__ct +8064c044 Pages::WFCFriendsMenu::__dt +8064c104 Pages::WFCFriendsMenu::OnInit +8064c584 Pages::WFCFriendsMenu::OnActivate +8064c664 Pages::WFCFriendsMenu::OnDeactivate +8064c70c Pages::WFCFriendsMenu::OnRosterButtonClick +8064c854 Pages::WFCFriendsMenu::OnRegisterButtonClick +8064c99c Pages::WFCFriendsMenu::OnCreateRoomClick +8064cb60 Pages::WFCFriendsMenu::OnBackButtonClick +8064cc0c Pages::WFCFriendsMenu::OnButtonSelect +8064cc78 Pages::WFCFriendsMenu::OnBackPress +8064cccc Pages::WFCFriendsMenu::GetNextPage +8064ccd4 Pages::WFCFriendsMenu::GetRuntimeTypeInfo +8064cce0 Pages::WFCModeSelect::GetNextPage +8064cce8 Pages::WFCModeSelect::GetRuntimeTypeInfo +8064ccf4 Pages::WFCMainMenu::GetNextPage +8064ccfc Pages::WFCMainMenu::GetRuntimeTypeInfo +8064cd08 FriendsStatusButton::GetRuntimeTypeInfo +8064cd14 Pages::Approve2PWFC::GetRuntimeTypeInfo +8064cd20 TriggerPtmf +8064cd50 TriggerPtmf +8064cd80 TriggerPtmf +8064cdb0 TriggerPtmf +8064cde0 TriggerPtmf +8064ce10 TriggerPtmf +8064ce40 TriggerPtmf +8064ce70 WFCMainMenuPage__cpp__sinit +8064cea0 Pages::WWRaceEndCountDown::__ct +8064cef4 Pages::WWRaceEndCountDown::__dt +8064cf74 Pages::WWRaceEndCountDown::OnInit +8064d000 Pages::WWRaceEndCountDown::OnActivate +8064d16c Pages::WWRaceEndCountDown::BeforeControlUpdate +8064d1b8 FriendStatusButtonRaceAfter::GetClassName +8064d1c8 0x8064d1c8 +8064d1d4 FriendStatusButtonRaceAfter::__ct +8064d210 FriendStatusButtonRaceAfter::__dt +8064d268 FriendStatusButtonRaceAfter::8064dbfc +8064d3a4 FriendStatusButtonRaceAfter::OnInit +8064d3a8 FriendStatusButtonRaceAfter::OnUpdate +8064d408 FriendStatusButtonRaceAfter::UpdateStatus +8064d554 Pages::WWRaceEnd::__ct +8064d680 Pages::WWRaceEnd::__dt +8064d71c Pages::WWRaceEnd::OnInit +8064da44 Pages::WWRaceEnd::OnActivate +8064db48 Pages::WWRaceEnd::BeforeEntranceAnimations +8064db5c Pages::WWRaceEnd::AfterControlUpdate +8064dcfc Pages::WWRaceEnd::OnContinueRaceClick +8064de78 Pages::WWRaceEnd::OnFriendButtonClick +8064df58 Pages::WWRaceEnd::OnQuitClick +8064e03c Pages::WWRaceEndQuit::__ct +8064e100 Pages::WWRaceEndQuit::__dt +8064e18c Pages::WWRaceEndQuit::OnInit +8064e320 Pages::WWRaceEndQuit::OnDispose +8064e3a0 Pages::WWRaceEndQuit::OnActivate +8064e464 Pages::WWRaceEndQuit::OnDeactivate +8064e470 Pages::WWRaceEndQuit::AfterControlUpdate +8064e610 Pages::WWRaceEndQuit::OnYesButtonClick +8064e790 Pages::WWRaceEndQuit::OnNoButtonClick +8064e7d4 Pages::WWRaceEndWait::__ct +8064e820 Pages::WWRaceEndWait::__dt +8064e894 Pages::WWRaceEndWait::OnInit +8064e8d8 Pages::WWRaceEndWait::OnInit_switch +8064e8dc Pages::WWRaceEndWait::OnInit_case_68 +8064e8f8 Pages::WWRaceEndWait::OnInit_case_69 +8064e98c Pages::WWRaceEndWait::OnActivate +8064e9e0 Pages::WWRaceEndWait::AfterControlUpdate +8064ea90 Pages::WWRaceEndWait::AfterControlUpdate_switch +8064ea94 Pages::WWRaceEndWait::AfterControlUpdate_case_68 +8064ea9c Pages::WWRaceEndWait::AfterControlUpdate_case_69 +8064eaa4 Pages::WWRaceEndWait::AfterControlUpdate_case_6c +8064eaac Pages::WWRaceEndWait::AfterControlUpdate_case_6d +8064ec24 Pages::WWRaceEndWait::AfterControlUpdate_switch2D +8064ec28 Pages::WWRaceEndWait::AfterControlUpdate_case2_70 +8064ec30 Pages::WWRaceEndWait::AfterControlUpdate_case2_71 +8064ec38 Pages::WWRaceEndWait::AfterControlUpdate_case2_72 +8064ec40 Pages::WWRaceEndWait::AfterControlUpdate_case2_73 +8064ec48 Pages::WWRaceEndWait::AfterControlUpdate_case2_74 +8064ec50 Pages::WWRaceEndWait::AfterControlUpdate_case2_75 +8064ec58 Pages::WWRaceEndWait::AfterControlUpdate_case2_76 +8064ec60 Pages::WWRaceEndWait::AfterControlUpdate_case2_77 +8064ecc8 0x8064ecc8 +8064ef4c 0x8064ef4c +8064ef50 0x8064ef50 +8064efa8 0x8064efa8 +8064f044 Pages::DisableHomeButton::__ct +8064f088 Pages::DisableHomeButton::__dt +8064f0f0 Pages::DisableHomeButton::OnInit +8064f14c Pages::DisableHomeButton::IsHomeMenuWorking +8064f154 Pages::DisableHomeButton::GetRuntimeTypeInfo +8064f160 Pages::RaceEndWait::GetRuntimeTypeInfo +8064f16c Pages::WWRaceEndQuit::GetNextPage +8064f174 Pages::WWRaceEndQuit::GetRuntimeTypeInfo +8064f180 Pages::WWRaceEnd::GetNextPage +8064f188 Pages::WWRaceEnd::GetRuntimeTypeInfo +8064f194 FriendStatusButtonRaceAfter::GetRuntimeTypeInfo +8064f1a0 Pages::WWRaceEndCountDown::GetNextPage +8064f1a8 Pages::WWRaceEndCountDown::GetRuntimeTypeInfo +8064f1b4 TriggerPtmf +8064f1e4 TriggerPtmf +8064f214 WWRaceSupportingPages_cpp_sinit_ +8064f248 Pages::SELECTStageMgr::__ct +8064f2dc Pages::SELECTStageMgr::__dt +8064f368 Pages::SELECTStageMgr::OnInit +8064f3c0 Pages::SELECTStageMgr::OnInit_switch +8064f3c4 Pages::SELECTStageMgr::OnInit_case58 +8064f3d0 Pages::SELECTStageMgr::OnInit_case60 +8064f3dc Pages::SELECTStageMgr::OnInit_case59 +8064f3e8 Pages::SELECTStageMgr::OnInit_case62 +8064f3f0 Pages::SELECTStageMgr::OnInit_case5a +8064f49c Pages::SELECTStageMgr::OnDispose +8064f4a0 Pages::SELECTStageMgr::OnActivate +8064f574 Pages::SELECTStageMgr::OnActivate_Pages::SELECTStageMgr::OnActivate_switch +8064f578 Pages::SELECTStageMgr::OnActivate_case58 +8064f598 Pages::SELECTStageMgr::OnActivate_case59 +8064f5b4 Pages::SELECTStageMgr::OnActivate_case5a +8064f684 Pages::SELECTStageMgr::OnActivate_switch2 +8064f688 Pages::SELECTStageMgr::OnActivate_2case58 +8064f844 Pages::SELECTStageMgr::OnActivate_2case59 +8064f864 Pages::SELECTStageMgr::OnActivate_2case5a +8064f880 Pages::SELECTStageMgr::OnDeactivate +8064f884 Pages::SELECTStageMgr::BeforeControlUpdate +8064f8e0 Pages::SELECTStageMgr::AfterControlUpdate +8064fe0c Pages::SELECTStageMgr::OnResume +80650018 Pages::SELECTStageMgr::OnResume_Pages::SELECTStageMgr::OnResume_switch +8065001c Pages::SELECTStageMgr::OnResume_case58 +80650024 Pages::SELECTStageMgr::OnResume_case59 +80650028 Pages::SELECTStageMgr::OnResume_case5a +80650160 Pages::SELECTStageMgr::IsPublicBattle +80650190 Pages::SELECTStageMgr::IsPublicBattle_switch +80650194 Pages::SELECTStageMgr::IsPublicBattle_case58 +8065019c Pages::SELECTStageMgr::IsPublicBattle_case59 +806501a4 Pages::SELECTStageMgr::IsPublicBattle_case5a +806501ac Pages::SELECTStageMgr::GetEngineClass +806501fc Pages::SELECTStageMgr::GetBattleType +8065024c Pages::SELECTStageMgr::GetInstructionBmgId +8065027c Pages::SELECTStageMgr::GetInstructionBmgId_switch +80650280 Pages::SELECTStageMgr::GetInstructionBmgId_case58 +806502f0 Pages::SELECTStageMgr::GetInstructionBmgId_case59 +80650350 Pages::SELECTStageMgr::GetInstructionBmgId_case60 +806503c0 Pages::SELECTStageMgr::GetInstructionBmgId_case61 +80650430 Pages::SELECTStageMgr::GetInstructionBmgId_case62 +80650438 Pages::SELECTStageMgr::GetInstructionBmgId_case63 +80650440 Pages::SELECTStageMgr::GetInstructionBmgId_case5a +80650448 Pages::SELECTStageMgr::GetPlayerId +80650490 Pages::SELECTStageMgr::PrepareRace +80650550 Pages::SELECTStageMgr::PrepareRace_switch +80650554 Pages::SELECTStageMgr::PrepareRace_case58 +80650574 Pages::SELECTStageMgr::PrepareRace_case60 +80650594 Pages::SELECTStageMgr::PrepareRace_case61 +806505b4 Pages::SELECTStageMgr::PrepareRace_case59 +806505d4 Pages::SELECTStageMgr::PrepareRace_case62 +806505f0 Pages::SELECTStageMgr::PrepareRace_case5a +80650620 Pages::SELECTStageMgr::PrepareRace_case5a_switch +80650624 Pages::SELECTStageMgr::PrepareRace_2case58 +806506e8 Pages::SELECTStageMgr::PrepareRace_2case59 +80650760 Pages::SELECTStageMgr::PrepareRace_2case62 +8065078c Pages::SELECTStageMgr::PrepareRace_2case63 +806507b8 Pages::SELECTStageMgr::PrepareRace_2case5a +80650c38 Pages::SELECTStageMgr::UpdateOnlineParams +80650e1c Pages::SELECTStageMgr::OnDisconnect +80650ec0 Pages::SELECTStageMgr::SetModeTypes +80650f04 Pages::SELECTStageMgr::SetModeTypes_switch +80650f08 Pages::SELECTStageMgr::SetModeTypes_case58 +80650f1c Pages::SELECTStageMgr::SetModeTypes_case59 +80650f30 Pages::SELECTStageMgr::SetModeTypes_case60 +80650f6c Pages::SELECTStageMgr::SetModeTypes_case62 +80650f78 Pages::SELECTStageMgr::SetModeTypes_case63 +80650f80 Pages::SELECTStageMgr::SetModeTypes_loop +806510f0 0x806510f0 +806510fc 0x806510fc +8065113c 0x8065113c +80651214 Pages::SELECTStageMgr::IsHomeMenuWorking +8065121c Pages::SELECTStageMgr::GetRuntimeTypeInfo +80651228 Pages::SELECTStageMgr::TriggerPtmf +80651258 CountDownTimerPage_cpp_sinit_ +8065126c WipeControl::GetClassName +80651278 WipeControl::__ct +806512b4 WipeControl::__dt +8065130c WipeControl::Load +806513c0 WipeControl::InitSelf +806513f8 WipeControl::OnUpdate +806514ec Pages::Wipe::__ct +80651558 Pages::Wipe::__dt +806515e4 Pages::Wipe::OnInit +80651930 Pages::Wipe::GetRuntimeTypeInfo +8065193c WipeControl::GetRuntimeTypeInfo +80651948 WipePagecpp_sinit_ +8065196c Pages::YesNo::__ct +80651a10 Pages::YesNo::__dt +80651a9c Pages::YesNo::OnInit +80651b30 Pages::YesNo::OnActivate +80651bd0 Pages::YesNo::AfterControlUpdate +80651c0c Pages::YesNo::Reset +80651c68 Pages::YesNo::SetMessageBoxMsg +80651c70 Pages::YesNo::PrepareButton +80651ce4 Pages::YesNo::OnButtonClick +80651d6c Pages::YesNo::SelectInitialButton +80651de0 Pages::YesNoPopUp::__ct +80651eb8 Pages::YesNoPopUp::__dt +80651f68 Pages::YesNoPopUp::OnInit +806521b4 Pages::YesNoPopUp::BeforeEntranceAnimations +806521f8 Pages::YesNoPopUp::AfterExitAnimations +8065223c Pages::YesNoPopUp::Container::GetClassName +8065224c Pages::YesNoPopUp::Container::__ct +80652288 Pages::YesNoPopUp::Container::__dt +806522e0 Pages::YesNoPopUp::Container::Load +80652354 Pages::YesNoPopUp::Reset +806523b0 Pages::YesNoPopUp::Container::SetPositionAnim +806523e8 Pages::YesNoFull::__ct +806524b8 Pages::YesNoFull::__dt +8065255c Pages::YesNoFull::OnInit +8065273c Pages::YesNoFull::Reset +806527a8 Pages::YesNoFull::SetTitleMsg +806527b0 Pages::YesNoFull::BeforeEntranceAnimations +806527cc Pages::YesNoFull::AfterExitAnimations +806527e8 Pages::YesNoFull::GetRuntimeTypeInfo +806527f4 Pages::YesNoPopUp::GetRuntimeTypeInfo +80652800 Pages::YesNoPopUp::Container::GetRuntimeTypeInfo +8065280c Pages::YesNo::GetRuntimeTypeInfo +80652818 Pages::YesNo::TriggerPtmf +80652848 YesNoPagecpp_sinit_ +80652874 RKNet::PacketMgr::CreateInstance +806528f0 RKNet::PacketMgr::DestroyInstance +80652944 RKNet::PacketMgr::Reset +80652d94 RKNet::PacketMgr::Update +80652fcc RKNet::PacketMgr::ExportRacedata +80653128 RKNet::PacketMgr::GetRacedata +80653274 RKNet::PacketMgr::ExportRH2 +80653324 RKNet::PacketMgr::GetRH2 +80653380 RKNet::PacketMgr::ClearSentRacedata +806533e4 RKNet::PacketMgr::ClearSentRH2 +80653448 RKNet::PacketMgr::ProcessPlayerDC +80653460 RKNet::PacketMgr::__ct +806534b8 0x806534b8 +806534f8 0x806534f8 +80653538 RKNet::PacketMgr::__dt +80653590 RKNet::PacketMgr::UpdateAsSpectator +806536a4 RKNet::PacketMgr::EveryoneIsConnected +806537bc RKNet::PacketMgr::UpdateAsRacer +80653b14 RKNet::PacketMgr::GetPlayerRH1Timer +80653bd4 RKNet::PacketMgr::GetPlayerLagFrames +80653c48 RKNet::PacketMgr::GetMaxRH1Timer +80653d88 RKNet::PacketMgr::SetITEMItem +80653da0 RKNet::PacketMgr::IsITEMItemNew +80653dac RKNet::PacketMgr::GetITEMStoredItem +80653db8 RKNet::PacketMgr::AddEVENTEntry +80653dc4 RKNet::PacketMgr::HasFreeEVENTEntries +80653e7c RKNet::PacketMgr::GetEVENTFreeDataSpace +80653e8c RKNet::PacketMgr::IsPlayerConnected +80653f14 RKNet::PacketMgr::IsPlayerLocal +80653f84 RKNet::PacketMgr::GetHudSlotId +80653ff0 RKNet::PacketMgr::UpdateRaceinfoConnectionStatus +806540a0 0x806540a0 +8065416c RKNet::PacketMgr::ProcessLagFrames +80654374 RKNet::PacketMgr::CreateRH1AndExportRH1andUSERandRacedata +806547d0 RKNet::PacketMgr::CreateAndExportRH1andUSER +80654b0c RKNet::PacketMgr::ProcessReceived +80654db8 RKNet::PacketMgr::UpdateAidsBitfield +80654ea4 0x80654ea4 +80654eb8 0x80654eb8 +80654ec4 0x80654ec4 +80655058 0x80655058 +8065505c 0x8065505c +80655180 0x80655180 +80655188 0x80655188 +80655190 RKNet::Controller::CreateInstance +80655218 RKNet::Controller::DestroyInstance +8065527c RKNet::Controller::Init +80655814 RKNet::Controller::ScheduleShutdown +80655820 RKNet::Controller::StartSearchWW +806558dc RKNet::Controller::StartSearchRegion +80655998 RKNet::Controller::StartSearchBTWW +80655a54 RKNet::Controller::StartSearchBTRegional +80655b10 RKNet::Controller::JoinFriend +80655c40 0x80655c40 +80655d70 RKNet::Controller::JoinRoom +80655e44 RKNet::Controller::StartRoom +80655f04 RKNet::Controller::ResetRH1andROOM +80655f5c 0x80655f5c +80655f74 0x80655f74 +80655f8c 0x80655f8c +80656020 RKNet::Controller::GetErrorParams +8065609c RKNet::Controller::ResetErrorParams +806560f8 RKNet::Controller::GetSubTickDiff +80656158 RKNet::Controller::UpdateServersAsyncAlt +806561b0 RKNet::Controller::UpdateServersAsync +806561d8 RKNet::Controller::UpdateFriendsStatus +8065630c RKNet::Controller::SetFriendsAddedBack +806563d8 RKNet::Controller::SetFriendDeleted +80656408 RKNet::Controller::CanExchangeFriendData +806564b0 RKNet::Controller::IsIdle +806564dc 0x806564dc +8065656c RKNet::Controller::IsConnectedToAnyone +806565ac RKNet::Controller::ClearSplitSendRACEPointers +80656664 RKNet::Controller::SetConnectionStateToFailed +80656670 RKNet::Controller::__ct +80656a48 RKNet::FriendManager::__dt +80656a88 RKNet::Controller::__dt +80656b6c RKNet::Controller::MainNetworkLoop +80656b70 RKNet::Controller::MainLoop +806570dc RKNet::Controller::SendPacketsAndUpdateUSER +8065711c RKNet::Controller::CombineSplitSendPackets +8065749c RKNet::Controller::TrySendNextRACEPacket +80657650 RKNet::Controller::SendAidNextRACEPacket +80657730 RKNet::Controller::GetSplitSendPacketsTotalSize +806577ac RKNet::Controller::SetConnectionState +806577b4 RKNet::Controller::GetConnectionState +80657838 RKNet::Controller::HandleError +80657998 RKNet::Controller::Alloc +80657a20 RKNet::Controller::Free +80657a84 RKNet::Controller::SOAlloc +80657b04 RKNet::Controller::SOFree +80657b6c RKNet::Controller::DWCAlloc +80657bf8 RKNet::Controller::DWCFree +80657c60 RKNet::Controller::UserRecvCallback +80657c80 RKNet::Controller::LoginCallback +80657d84 RKNet::Controller::MatchedSCCallback +80657dd4 RKNet::Controller::ConnectionAttemptCallback +80657e90 RKNet::Controller::ConnectionClosedCallback +80657f44 RKNet::Controller::UpdateServerCallback +80657f68 RKNet::Controller::UpdateServerCallbackAlt +80657f84 RKNet::Controller::FriendStatusChangeCallback +80657f88 RKNet::Controller::BuddyFriendCallback +80657f94 RKNet::Controller::SetDWCRecvBuffers +80657ffc RKNet::Controller::ProcessPlayerDisconnect +80658208 RKNet::Controller::ConnectToWFC +806583a8 RKNet::Controller::InitSubs +8065844c RKNet::Controller::UpdateSubsAndVR +806585ec RKNet::Controller::ResetFriendArray +806586b0 RKNet::Controller::StartMatching +806587dc RKNet::Controller::ConnectToAnybodyAsync +80658c24 RKNet::Controller::SetupGameServer +80658c88 0x80658c88 +80658cec RKNet::Controller::ConnectToGameServerFromGroupId +80658f30 0x80658f30 +806590a8 RKNet::Controller::CalcRACEPacketCRC32 +806590f0 RKNet::Controller::ProcessRACEPacket +8065922c RKNet::Controller::UpdateAidsBelongingToPlayerIds +8065938c RKNet::Controller::ResetAidsBelongingToPlayerIds +806593c4 RKNet::Controller::GetLocalPlayerId +80659610 RKNet::Controller::GetFriendsSearchType +80659720 RKNet::Controller::UpdateStatusDatas +806598b8 RKNet::PacketHolder::__ct +80659918 RKNet::PacketHolder::__dt +80659978 RKNet::PacketHolder::Clear +806599b8 RKNet::PacketHolder::Copy +806599f8 RKNet::PacketHolder::Append +80659a48 RKNet::SplitRACEPointers::__ct +80659ae0 RKNet::SplitRACEPointers::__dt +80659b64 RKNet::RatingRangeMaker::Init +80659c4c RKNet::RatingRangeMaker::GetLowerRange +80659cb8 RKNet::RatingRangeMaker::GetUpperRange +80659d20 0x80659d20 +80659dd4 RKNet::RatingRangeMaker::GetRatingGroup +80659f40 RKNet::GPReverseBuddiesListCallback +80659fe0 RKNet::SetGPError +8065a0f4 RKNet::ROOMHandler::CreateInstance +8065a1b8 RKNet::ROOMHandler::DestroyInstance +8065a1f8 RKNet::ROOMHandler::Init +8065a300 RKNet::ROOMHandler::Reset +8065a384 RKNet::ROOMHandler::Update +8065a4dc RKNet::ROOMHandler::SetAllToSendPackets +8065a5d0 RKNet::ROOMHandler::GetRecvPacket +8065a5e0 RKNet::ROOMHandler::SetToSendPacket +8065a5f0 RKNet::ROOMHandler::__ct +8065a674 RKNet::ROOMHandler::__dt +8065a6b4 RKNet::ROOMHandler::ExportROOMandUSER +8065a800 RKNet::ROOMHandler::ImportNewPackets +8065a8cc RKNet::ROOMHandler::ResetAllPackets +8065a94c RKNet::ROOMHandler::InitPacket +8065a958 RKNet::ROOMHandler::ClearToSendPacket +8065a96c RKNet::ROOMHandler::ClearRecvPacket +8065a980 RKNet::ROOMHandler::SetToSendPacket2 +8065a990 RKNet::ROOMHandler::SetRecvPacket +8065a9a0 RKNet::ROOMHandler::GetToSendPacketPtr +8065a9b0 RKNet::ROOMHandler::GetRecvPacketPtr +8065a9c0 0x8065a9c0 +8065aa24 0x8065aa24 +8065aa78 0x8065aa78 +8065aabc 0x8065aabc +8065aafc 0x8065aafc +8065ab54 RKNet::EVENTHandler::CreateInstance +8065ac6c RKNet::EVENTHandler::DestroyInstance +8065acac RKNet::EVENTHandler::__ct +8065ad98 0x8065ad98 +8065ad9c RKNet::EVENTHandler::Update +8065adec RKNet::EVENTHandler::AddEntry +8065b004 RKNet::EVENTHandler::Reset +8065b0f8 RKNet::EVENTHandler::__dt +8065b138 RKNet::EVENTHandler::FreeExpiredSendEntries +8065b200 RKNet::EVENTHandler::ExportSendEntries +8065b350 RKNet::EVENTHandler::ImportReceivedEntries +8065b4ac RKNet::EVENTHandler::ProcessReceivedEntries +8065b6b8 RKNet::EVENTHandler::ResetEntry +8065b6e4 RKNet::EVENTHandler::GetEventType +8065b71c RKNet::EVENTHandler::SetEntryItemAndActionFromType +8065b730 RKNet::EVENTHandler::ProcessEntry +8065b758 RKNet::ITEMHandler::CreateInstance +8065b9d4 RKNet::ITEMHandler::DestroyInstance +8065ba14 RKNet::ITEMHandler::__ct +8065bc50 0x8065bc50 +8065bc54 RKNet::ITEMHandler::Update +8065bd2c RKNet::ITEMHandler::SetItem +8065bdb8 RKNet::ITEMHandler::RemoveItem +8065be4c RKNet::ITEMHandler::OnRouletteEnd +8065bf38 0x8065bf38 +8065c0d0 0x8065c0d0 +8065c298 0x8065c298 +8065c460 RKNet::ITEMHandler::GetModeRelatedInt +8065c52c 0x8065c52c +8065c630 RKNet::ITEMHandler::SetItemAndMode +8065c68c 0x8065c68c +8065c74c RKNet::ITEMHandler::SetDraggedItemAndMode +8065c7a8 0x8065c7a8 +8065c888 RKNet::ITEMHandler::GetStoredItem +8065c91c RKNet::ITEMHandler::GetDraggedItem +8065c9d0 RKNet::ITEMHandler::GetStoredItemMode +8065ca64 RKNet::ITEMHandler::GetDraggedItemMode +8065cb18 RKNet::ITEMHandler::GetTimer +8065cbc8 RKNet::ITEMHandler::IsPlayerConnected +8065cbd4 RKNet::ITEMHandler::IsItemNew +8065cc74 RKNet::ITEMHandler::IsDraggingItem +8065cd50 RKNet::ITEMHandler::HasStartedDraggingItem +8065d05c 0x8065d05c +8065d298 RKNet::ITEMHandler::__dt +8065d2d8 RKNet::ITEMHandler::ExportSendPackets +8065d3a8 RKNet::ITEMHandler::ImportNewPackets +8065d70c RKNet::ITEMHandler::UpdateItemStatusAndSums +8065dcb0 RKNet::ITEMHandler::AcknowledgeAid +8065df14 RKNet::ITEMHandler::UpdateLocalPlayersItems +8065dfa4 RKNet::ITEMHandler::UpdateStoredItem +8065e3e0 RKNet::ITEMHandler::UpdateDraggedItem +8065e6d4 RKNet::ITEMHandler::UpdateLocalPlayers +8065ed48 RKNet::ItemHandler::GetStoredItemCount +8065f038 0x8065f038 +8065f078 0x8065f078 +8065f0b8 0x8065f0b8 +8065f1d8 0x8065f1d8 +8065f4b8 0x8065f4b8 +8065f4f8 RKNet::SELECTHandler::CreateInstance +8065f5cc RKNet::SELECTHandler::DestroyInstance +8065f610 RKNet::SELECTHandler::InitPackets +8065f964 0x8065f964 +8065f968 RKNet::SELECTHandler::Update +8065faa0 RKNet::SELECTHandler::GetWinningVoter +8065fabc RKNet::SELECTHandler::GetWinningCourse +8065fadc RKNet::SELECTHandler::GetOwnSelectId +8065faf8 RKNet::SELECTHandler::GetEngineClass +8065fb14 RKNet::SELECTHandler::GetBattleType +8065fb38 RKNet::SELECTHandler::GetOwnPlayerIdToAid +8065fb40 RKNet::SELECTHandler::GetCharacterId +8065fb90 RKNet::SELECTHandler::GetKartId +8065fbe0 RKNet::SELECTHandler::GetCourseVote +8065fc30 RKNet::SELECTHandler::GetPlayerData +8065fc78 RKNet::SELECTHandler::GetStarRank +8065fcc0 RKNet::SELECTHandler::GetTeam +8065fcf8 RKNet::SELECTHandler::HasUnprocessedPackets +8065fd7c RKNet::SELECTHandler::IsPrepared +8065fdbc RKNet::SELECTHandler::SetPlayerData +8065fdd8 RKNet::SELECTHandler::__ct +8065fe60 RKNet::SELECTHandler::__dt +8065ff20 RKNet::SELECTHandler::ResetSendPacket +8066006c RKNet::SELECTHandler::ResetReceivedPackets +80660160 RKNet::SELECTHandler::ResetPacket +8066023c RKNet::SELECTHandler::ResetPlayerData +806602a8 RKNet::SELECTHandler::HandleReceivedPacketTimes +80660398 RKNet::SELECTHandler::IsBattle +806603ac RKNet::SELECTHandler::IsTrackDecided +806603c8 RKNet::SELECTHandler::EveryoneHasAccurateRaceSettings +80660438 RKNet::SELECTHandler::EveryoneHasVoted +806604a8 RKNet::SELECTHandler::EveryoneHasAccurateAidPidMap +8066051c RKNet::SELECTHandler::ClearRH1ReceivedBuffers +80660588 RKNet::SELECTHandler::PrepareAndExportSELECTandUSER +806606e4 RKNet::SELECTHandler::ImportNewPackets +806608f4 RKNet::SELECTHandler::PrepareAndExportPacket +80660b1c RKNet::SELECTHandler::ProcessNewPacketVoting +80660fa0 RKNet::SELECTHandler::DecideBattleTypeAndTeams +80661080 RKNet::SELECTHandler::GenerateOwnSELECTId +806610c8 RKNet::SELECTHandler::DecideEngineClass +80661354 RKNet::SELECTHandler::DecideTrack +806616a0 RKNet::SELECTHandler::AllocatePlayerIdsToAids +80661848 RKNet::SELECTHandler::HasMatchingPlayerIdToAid +806618fc RKNet::SELECTHandler::DecidePublicTeams +80661bf4 RKNet::SELECTHandler::DecidePrivateTeams +80661de4 RKNet::USERHandler::CreateInstance +80661e64 RKNet::USERHandler::DestroyInstance +80661eb8 RKNet::USERHandler::Prepare +80661fb0 RKNet::USERHandler::Reset +8066202c RKNet::USERHandler::Update +80662128 RKNet::USERHandler::CopySendToPacketHolder +8066216c RKNet::USERHandler::ProcessPlayerDisconnect +80662258 0x80662258 +806622c4 0x806622c4 +806622d4 0x806622d4 +806622f4 0x806622f4 +8066238c 0x8066238c +806623ec RKNet::USERHandler::SetSendVR +80662430 RKNet::USERHandler::SetSendBR +80662474 RKNet::USERHandler::__ct +806624d0 RKNet::USERHandler::__dt +80662528 RKNet::USERHandler::ImportNewPackets +80662624 0x80662624 +80662678 RKNet::USERHandler::CreateSendPacket +80662800 RKNet::FriendMgr::CreateInstance +80662928 RKNet::FriendMgr::DestroyInstance +80662968 RKNet::FriendMgr::ReadDataFromRKSYS +80662ab0 RKNet::FriendMgr::Update +80662c14 RKNet::FriendMgr::CreateAccUserData +80662c1c RKNet::FriendMgr::CheckAccUserData +80662c4c RKNet::FriendMgr::IsAccUserDataDirt +80662c7c RKNet::FriendMgr::ClearAccUserDataDirtyFlag +80662c84 RKNet::FriendMgr::CreateFriendCode +80662cb0 RKNet::FriendMgr::SetCodesForUnusedIdxs +80662db8 RKNet::FriendMgr::IsAvailable +80662dc8 RKNet::FriendMgr::IsBuddyFriend +80662e00 RKNet::FriendMgr::IsValidFriend +80662e30 RKNet::FriendMgr::CheckFriendCode +80662e68 RKNet::FriendMgr::GetFriendIdx +80662ee0 RKNet::FriendMgr::GetFriendCodeLicenseIdx +80662f84 RKNet::FriendMgr::GetLicenseFriendCode +80662fac RKNet::FriendMgr::GetFirstFreeFriendIdx +8066300c RKNet::FriendMgr::__ct +80663110 RKNet::RH1Handler::CreateInstance +806632a4 RKNet::RH1Handler::DestroyInstance +806632e8 RKNet::RH1Handler::Activate +806632f4 RKNet::RH1Handler::Reset +80663440 RKNet::RH1Handler::Update +80663778 RKNet::RH1Handler::Reset +8066381c RKNet::RH1Handler::HasValidCourse +80663a2c RKNet::RH1Handler::GetKart +80663a44 RKNet::RH1Handler::GetCharacter +80663a5c 0x80663a5c +80663bb8 RKNet::RH1Handler::GetStarRank +80663bcc RKNet::RH1Handler::GetValidCourse +80663d34 0x80663d34 +80663e3c RKNet::RH1Handler::GetPlayerCount +80663fb0 RKNet::RH1Handler::GetSELECTId +806640a8 RKNet::RH1Handler::GetEngineClass +806641a0 RKNet::RH1Handler::GetAidsBelongingToPlayer +80664298 0x80664298 +80664408 RKNet::RH1Handler::__dt +8066456c 0x8066456c +80664664 0x80664664 +806646d8 0x806646d8 +80664820 RKNet::RH1Handler::ImportNewPackets +806649a0 0x806649a0 +80664a34 RKNet::RH1Handler::ExportDefaultPacket +80664aec RKNet::RH1Handler::ExportDefaultPacket2 +80664ba4 0x80664ba4 +80664ccc 0x80664ccc +80664d6c 0x80664d6c +80664ef8 0x80664ef8 +80664f88 0x80664f88 +80664fd8 0x80664fd8 +80665004 0x80665004 +8066501c 0x8066501c +80665098 0x80665098 +806650b8 0x806650b8 +806650fc 0x806650fc +80665164 0x80665164 +806651d8 0x806651d8 +80665260 Page::EndExitState +80665264 0x80665264 +80665268 0x80665268 +80665290 0x80665290 +806652a8 0x806652a8 +80665658 0x80665658 +8066574c 0x8066574c +806657e8 0x806657e8 +806658f4 0x806658f4 +80665a74 0x80665a74 +80665c38 0x80665c38 +80665c50 0x80665c50 +80665cb8 0x80665cb8 +80665d00 0x80665d00 +80665d0c 0x80665d0c +80665d18 0x80665d18 +80665d24 0x80665d24 +80665d54 0x80665d54 +80665d84 0x80665d84 +80665db4 0x80665db4 +80665dd4 0x80665dd4 +80665eec 0x80665eec +80665f8c 0x80665f8c +80666118 0x80666118 +8066616c 0x8066616c +80666184 0x80666184 +80666200 0x80666200 +80666220 0x80666220 +80666230 0x80666230 +8066628c 0x8066628c +80666300 0x80666300 +80666454 0x80666454 +80666458 0x80666458 +80666550 0x80666550 +806665e8 0x806665e8 +80666658 0x80666658 +806666b8 0x806666b8 +80666750 0x80666750 +80666788 0x80666788 +806667bc 0x806667bc +806668a0 0x806668a0 +80666900 0x80666900 +80666910 0x80666910 +80666b20 0x80666b20 +80666c04 0x80666c04 +80666edc 0x80666edc +806670b4 0x806670b4 +806670b8 0x806670b8 +806670bc 0x806670bc +80667220 0x80667220 +80667318 0x80667318 +80667424 0x80667424 +8066752c 0x8066752c +80667568 0x80667568 +80667578 0x80667578 +80667590 0x80667590 +806675dc 0x806675dc +80667650 0x80667650 +806676e4 0x806676e4 +806676ec 0x806676ec +80667820 Page::EndExitState +80667824 0x80667824 +80667828 0x80667828 +80667b60 0x80667b60 +80667b64 0x80667b64 +80667b6c 0x80667b6c +80667b74 0x80667b74 +80667b7c 0x80667b7c +80667b84 0x80667b84 +80667b8c 0x80667b8c +80667b94 0x80667b94 +80667b9c 0x80667b9c +80667c44 0x80667c44 +80667d2c 0x80667d2c +80667d34 0x80667d34 +80667d40 0x80667d40 +80667d4c 0x80667d4c +80667d58 0x80667d58 +80667d64 0x80667d64 +80667d94 0x80667d94 +80667dc4 0x80667dc4 +80667df4 0x80667df4 +80667e24 0x80667e24 +80667e54 0x80667e54 +80667e80 ServerMgr::__dt +80667fc8 0x80667fc8 +80668024 ServerMgr::DestroyInstance +80668120 ServerMgr::CreateInstance +80668184 ServerMgr::__ct +8066831c 0x8066831c +80668340 0x80668340 +80668380 0x80668380 +806683e8 0x806683e8 +806684ec 0x806684ec +806685b8 0x806685b8 +806685cc 0x806685cc +80668610 ServerMgr::GetServerState +80668618 ServerMgr::GetState +80668620 0x80668620 +8066863c 0x8066863c +80668648 ServerMgr::GetError +80668650 ServerMgr::CountFriendsToInviteViaMsgBoard +80668764 0x80668764 +8066876c 0x8066876c +80668774 0x80668774 +806688d0 ServerMgr::Update +80668910 ServerMgr::Update_switch +80668914 ServerMgr::Update_caseD_1 +80668938 ServerMgr::Update_caseD_8 +80668940 ServerMgr::Update_caseD_16 +80668948 ServerMgr::Update_caseD_9 +80668a60 ServerMgr::Update_caseD_3 +80668d8c ServerMgr::Update_caseD_0 +80668da0 0x80668da0 +80668ec4 0x80668ec4 +806692e0 0x806692e0 +80669320 0x80669320 +80669360 BundleSortProc +80669370 0x80669370 +80669378 0x80669378 +80669454 0x80669454 +80669458 0x80669458 +806694c8 0x806694c8 +806696bc 0x806696bc +80669784 0x80669784 +80669844 0x80669844 +80669a10 0x80669a10 +80669aac 0x80669aac +80669e28 0x80669e28 +8066a0e0 0x8066a0e0 +8066a144 0x8066a144 +8066a394 0x8066a394 +8066a408 0x8066a408 +8066a618 0x8066a618 +8066a93c 0x8066a93c +8066aa84 0x8066aa84 +8066ab28 ServerMgr::GetRKG +8066ac5c 0x8066ac5c +8066aeb8 0x8066aeb8 +8066af24 0x8066af24 +8066b32c 0x8066b32c +8066b420 0x8066b420 +8066b448 0x8066b448 +8066b6d8 0x8066b6d8 +8066b7e8 ServerMgr::CheckNWC24Available +8066b7f4 0x8066b7f4 +8066b954 0x8066b954 +8066b9fc 0x8066b9fc +8066ba8c 0x8066ba8c +8066bb28 0x8066bb28 +8066bb94 ServerMgr::HasCourseNewFriendRecord +8066bc84 0x8066bc84 +8066bcd8 0x8066bcd8 +8066be64 0x8066be64 +8066bee0 0x8066bee0 +8066bf44 ServerMgr::GetCompetitionInfo +8066c070 0x8066c070 +8066c0c0 0x8066c0c0 +8066c0d0 0x8066c0d0 +8066c19c ServerMgr::GetSpecialGhostInfo +8066c1b8 0x8066c1b8 +8066c238 0x8066c238 +8066c9c8 0x8066c9c8 +8066ccd4 0x8066ccd4 +8066cda0 0x8066cda0 +8066ce60 0x8066ce60 +8066d13c 0x8066d13c +8066d228 0x8066d228 +8066d3b4 0x8066d3b4 +8066d400 0x8066d400 +8066d6b4 0x8066d6b4 +8066d7cc 0x8066d7cc +8066d9c8 0x8066d9c8 +8066db1c 0x8066db1c +8066dcc0 0x8066dcc0 +8066deb0 0x8066deb0 +8066df7c 0x8066df7c +8066e0ec 0x8066e0ec +8066e1c8 0x8066e1c8 +8066e298 0x8066e298 +8066e520 0x8066e520 +8066e5d0 0x8066e5d0 +8066e738 0x8066e738 +8066e7d8 0x8066e7d8 +8066e930 0x8066e930 +8066eb18 0x8066eb18 +8066ebfc 0x8066ebfc +8066ef28 0x8066ef28 +8066f0b4 0x8066f0b4 +8066f234 0x8066f234 +8066f478 0x8066f478 +8066f610 0x8066f610 +8066f8b4 0x8066f8b4 +8066fd18 0x8066fd18 +80670274 0x80670274 +8067066c 0x8067066c +80670878 0x80670878 +80670980 0x80670980 +806709fc 0x806709fc +80670aac 0x80670aac +80670bf4 0x80670bf4 +80670c78 0x80670c78 +80670ddc 0x80670ddc +80670eb4 0x80670eb4 +806711b8 0x806711b8 +806712e8 ServerMgr::PublishMsgBoardAsync +80671464 ServerMgr::PublishMsgBoard +8067173c ServerMgr::InitCHJObj +80671990 0x80671990 +806719a8 0x806719a8 +806719bc ServerMgr::RequestMsgBoardPublish +80671b0c 0x80671b0c +80671c8c 0x80671c8c +80671cf8 0x80671cf8 +80671eac 0x80671eac +8067206c 0x8067206c +806721a8 0x806721a8 +80672334 0x80672334 +80672480 0x80672480 +80672750 0x80672750 +806727dc 0x806727dc +80672884 0x80672884 +80672934 0x80672934 +80672bd4 0x80672bd4 +80672f3c 0x80672f3c +806730ac 0x806730ac +80673108 0x80673108 +80673258 0x80673258 +806733a8 0x806733a8 +806734f8 0x806734f8 +8067366c 0x8067366c +806737c0 0x806737c0 +80673940 0x80673940 +80673b84 0x80673b84 +80673cc4 0x80673cc4 +80673e00 0x80673e00 +80673e98 0x80673e98 +80673fc8 0x80673fc8 +806740a4 0x806740a4 +80674150 0x80674150 +806741cc 0x806741cc +80674238 0x80674238 +806742a4 0x806742a4 +806742f4 0x806742f4 +8067443c 0x8067443c +80674574 0x80674574 +806746e8 0x806746e8 +8067475c 0x8067475c +80674798 ServerMgr::CreateRKGFromRKG +8067489c ServerMgr::CheckGhostDataValidity +80674970 0x80674970 +806749f0 0x806749f0 +806749f8 0x806749f8 +80674ab0 0x80674ab0 +80674ac0 0x80674ac0 +80674b98 0x80674b98 +80674c90 0x80674c90 +80674cf8 0x80674cf8 +80674d10 0x80674d10 +80674d34 0x80674d34 +80674d3c 0x80674d3c +80674d90 0x80674d90 +80674eb4 0x80674eb4 +80675140 0x80675140 +806751ec 0x806751ec +806754b4 0x806754b4 +806755d8 0x806755d8 +8067573c 0x8067573c +80675748 0x80675748 +8067579c 0x8067579c +806757f0 0x806757f0 +80675834 0x80675834 +8067583c 0x8067583c +8067588c 0x8067588c +80675894 0x80675894 +806758b4 0x806758b4 +806758f4 0x806758f4 +80675940 0x80675940 +80675a50 0x80675a50 +80675aa8 0x80675aa8 +80675bb4 0x80675bb4 +80675d20 0x80675d20 +80675ecc 0x80675ecc +80675ed8 0x80675ed8 +80675f70 0x80675f70 +80675fdc 0x80675fdc +80675fe8 0x80675fe8 +80675ffc 0x80675ffc +80676838 0x80676838 +80676864 0x80676864 +80676888 0x80676888 +80676894 0x80676894 +8067689c 0x8067689c +806768a4 0x806768a4 +806768ac 0x806768ac +806769ec 0x806769ec +80676a34 0x80676a34 +80676ab0 0x80676ab0 +80676c50 0x80676c50 +80676d1c 0x80676d1c +80676dc4 0x80676dc4 +80676eec 0x80676eec +80676f78 0x80676f78 +80676ffc 0x80676ffc +806770f8 0x806770f8 +806771d0 0x806771d0 +80677260 0x80677260 +80677354 0x80677354 +806773ec 0x806773ec +806774d0 0x806774d0 +806775d0 0x806775d0 +8067761c 0x8067761c +806776c8 0x806776c8 +80677848 0x80677848 +80677904 0x80677904 +80677984 0x80677984 +806779f0 0x806779f0 +80677a54 0x80677a54 +80677a68 0x80677a68 +80677b10 0x80677b10 +80677bf8 0x80677bf8 +80677c94 0x80677c94 +80677cac 0x80677cac +80677cd8 0x80677cd8 +80677ce4 0x80677ce4 +80677cec 0x80677cec +80677dac 0x80677dac +80677eb8 0x80677eb8 +80677ebc 0x80677ebc +80678020 0x80678020 +80678094 0x80678094 +80678118 0x80678118 +806781e4 0x806781e4 +80678500 0x80678500 +806785b8 0x806785b8 +80678638 0x80678638 +80678690 0x80678690 +806786d8 0x806786d8 +806786e4 0x806786e4 +806786ec 0x806786ec +806786f4 0x806786f4 +80678708 0x80678708 +806788e8 0x806788e8 +806789e8 thunk_0x801de348 +806789ec 0x806789ec +806789fc 0x806789fc +80678bd4 0x80678bd4 +80678d8c 0x80678d8c +80679114 0x80679114 +806792d8 0x806792d8 +80679560 0x80679560 +80679724 0x80679724 +80679908 0x80679908 +80679aec 0x80679aec +80679bf8 0x80679bf8 +80679e1c 0x80679e1c +80679f28 0x80679f28 +8067a26c 0x8067a26c +8067a2b0 0x8067a2b0 +8067a318 0x8067a318 +8067a3a0 0x8067a3a0 +8067a3a8 0x8067a3a8 +8067a4ac Page::EndExitState +8067a4b0 0x8067a4b0 +8067a4b4 0x8067a4b4 +8067a798 0x8067a798 +8067a79c 0x8067a79c +8067a7a4 0x8067a7a4 +8067a7ac 0x8067a7ac +8067a7b4 0x8067a7b4 +8067a7bc 0x8067a7bc +8067a7c4 0x8067a7c4 +8067a7cc 0x8067a7cc +8067a7d4 0x8067a7d4 +8067a87c 0x8067a87c +8067a964 Effects::Mgr::GetRuntimeTypeInfo +8067a970 EffectsMgrcpp_sinit_ +8067a984 Effects::MGWhiteFog::__ct +8067a9f4 Effects::MGWhiteFog::__dt +8067aa34 Effects::MGWhiteFog::Update +8067aab4 Effects::MGWhiteFog::UpdateEffect +8067ab20 Effects::MGWhiteFog::Kill +8067ab34 Effects::Mgr::CreateInstance +8067abec Effects::Mgr::Init +8067af5c Effects::Mgr::Reset +8067b160 Effects::Sub9d8::__dt +8067b1a0 Effects::Mgr::LoadRaceEffects +8067bb60 Effects::Mgr::CreatePlayerEffects +8067bbec Effects::Mgr::CreateEffects::Items +8067bc2c Effects::Mgr::LoadObjectEffect +8067c050 0x8067c050 +8067c0b8 Effects::Mgr::InitRace +8067c1f4 Effects::Mgr::Update +8067c290 0x8067c290 +8067c30c Effects::Mgr::CalcPlayerEffects +8067c4b0 Effects::Mgr::UpdatePlayersVisibility +8067c5e0 Effects::Mgr::Draw +8067cd60 0x8067cd60 +8067cf78 0x8067cf78 +8067d0c0 Object::GetClipInfo +8067d0c8 Effects::Mgr::UpdatePlayerFromWheelCollision +8067d0e4 Effects::Mgr::UpdatePlayerFromKartCollision +8067d114 Effects::Mgr::GetMenuEffectByIdx +8067d11c Effects::Mgr::CalcEffect1 +8067d13c Effects::Mgr::DrawEffect1 +8067d160 Effects::Mgr::DrawSelfItem +8067d310 0x8067d310 +8067d32c Effects::Mgr::IsEveryoneLookingForwards +8067d388 Effects::Mgr::IsMTOrPlayer0xF4 +8067d3c4 0x8067d3c4 +8067d480 Effects::Sub9d8::Update +8067d728 0x8067d728 +8067d89c 0x8067d89c +8067d8dc dGeomEnable +8067d8ec 0x8067d8ec +8067d9f0 ObjectCollidable::__dt +8067da30 Object::__dt +8067da70 Objects::FlamePoleEff::OnStart +8067da7c Objects::FlamePoleEff::Update +8067dc34 0x8067dc34 +8067dcdc 0x8067dcdc +8067dd58 0x8067dd58 +8067dd60 Objects::FlamePole::__ct +8067e158 Vec3::EulerFromMatrix +8067e168 ObjectExternKCL::__dt +8067e1a8 ObjectKCL::__dt +8067e1e8 0x8067e1e8 +8067e24c Objects::FlamePole::__dt +8067e300 Objects::FlamePole::OnStart +8067e5dc Objects::FlamePole::OnUpdate +8067e8ac Objects::FlamePole::UpdateModelMatrix +8067e948 0x8067e948 +8067e95c 0x8067e95c +8067e960 Objects::FlamePole::CalcOtherEntityDistance +8067eaf0 0x8067eaf0 +8067eba4 0x8067eba4 +8067ebb0 0x8067ebb0 +8067ec58 0x8067ec58 +8067ec70 0x8067ec70 +8067ecbc 0x8067ecbc +8067ed18 0x8067ed18 +8067ed1c 0x8067ed1c +8067ed20 0x8067ed20 +8067ed24 0x8067ed24 +8067ee34 0x8067ee34 +8067eed0 0x8067eed0 +8067eed4 0x8067eed4 +8067ef50 0x8067ef50 +8067f0f8 0x8067f0f8 +8067f224 Objects::FlamePole::GetTransformationMatrix +8067f2bc 0x8067f2bc +8067f460 0x8067f460 +8067f488 Objects::FlamePole::UpdateOtherEntityPosWithRot +8067f4f4 Objects::FlamePole::IsCollidingNoTriangleCheckImpl +8067f884 0x8067f884 +8067fc14 ObjectEffect::__dt +8067fc6c Object::DoCalcShadowMtx +8067fc74 Object::vf_0xa8 +8067fc7c Object::IsLodDisabled +8067fc84 Object::GetEntity +8067fc8c Object::vf_0x84 +8067fc94 Object::GetShadowListIdx +8067fc9c Object::UpdateShadowScale +8067fcc8 Object::UpdateModelScale +8067fd38 Object::GetShadowResName +8067fd40 Object::GetLowResourceName +8067fd48 Object::GetSubFileName +8067fd9c Object::GetBRRESName +8067fdf0 Object::GetName +8067fe44 do_nothing_7d8 +8067fe48 do_nothing_7dc +8067fe4c ObjectKCL::GetScnObjDrawOptionsIdx +8067fe54 ObjectExternKCL::UpdateKCL +8067fe5c ObjectExternKCL::IsCollidingNoTerrainInfo +8067ff58 ObjectExternKCL::HasCurrentCollision +8067ff60 ObjectExternKCL::vf_0x13c +8067ff68 ObjectExternKCL::IsCollidingAddEntryNoTerrainInfo +80680064 ObjectExternKCL::HasCollision +8068006c ObjectExternKCL::IsDriveable +80680074 ObjectExternKCL::vf_0xfc +80680170 ObjectExternKCL::IsCollidingAddEntry +80680180 ObjectExternKCL::IsCollidingNoTerrainInfo(no radius) +80680238 ObjectExternKCL::IsCollidingAddEntryNoTerrainInfo(no radius) +806802f0 ObjectExternKCL::vf_0xec +806803a8 ObjectExternKCL::IsCollidingAddEntry(no radius) +80680460 ObjectExternKCL::IsCollidingNoTerrainInfoNoTriangleCheck +8068055c ObjectExternKCL::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +80680658 ObjectExternKCL::IsColliding +80680754 ObjectExternKCL::IsCollidingAddEntryNoTriangleCheck +80680764 ObjectExternKCL::vf_0xc0 +8068081c ObjectExternKCL::vf_0xc4 +806808d4 ObjectExternKCL::vf_0xc8 +8068098c ObjectExternKCL::vf_0xcc +80680a44 ObjectExternKCL::UpdateOtherEntityPos +80680a98 ObjectExternKCL::SetObjInfoCalcBit +80680aa8 ObjectExternKCL::GetPeriod +80680ab4 ObjectExternKCL::GetPosition +80680abc ObjectExternKCL::UpdateDiffPosVector +80680ae8 ObjectExternKCL::vf_0xb4 +80680afc ObjectExternKCL::UpdateCollision +80680b10 Objects::FlamePole::vf__0x11c +80680b1c Objects::FlamePole::vf_0x108 +80680b28 Objects::FlamePole::AreItemsAllowed +80680b30 Objects::FlamePole::GetCollisionDiameter +80680b74 Objects::FlamePole::LoadAnimations +80680bf4 0x80680bf4 +80680bfc Objects::FlamePole::GetPropertiesBitfield +80680c04 Object::GetPosition +80680c0c ObjectCollidable::GetCollisionDiameter +80680d24 ObjectCollidable::GetSolidityCenter +80680d44 ObjectCollidable::InitEntity +80680da0 ObjectCollidable::IsSolid +80680da8 ObjectCollidable::GetCollisionTranslation +80680db4 ObjectCollidable::CheckCollision +80680e08 ObjectCollidable::OnCollision +80680e10 ObjectCollidable::OnItemCollision +80680e18 ObjectCollidable::GetScnObjDrawOptionsIdx +80680e20 Objects::FlamePoleEff::LoadAnimations +80680e78 Objects::FlamePoleEff::vf_0xec +80680e80 Objects::FlamePoleEff::GetBRRESName +80680e8c Objects::FlamePoleEff::GetPropertiesBitfield +80680e94 Objects::FlamePoleEff::__dt +80680ed4 Objects::FlamePole::__dt(thunk) +80680edc 0x80680edc +80680fbc 0x80680fbc +80681490 0x80681490 +80681504 0x80681504 +806817cc 0x806817cc +80681da8 0x80681da8 +80681f54 ObjectKCL::vf_0x111c +80681f5c ObjectKCL::vf_0x1118 +80681f60 ObjectKCL::UpdateOtherEntityPos +80681f64 ObjectKCL::SetObjInfoCalcBit +80681f68 ObjectKCL::CalcOtherEntityDistance +80681f6c ObjectKCL::vf_0x108 +80681f78 ObjectKCL::AreItemsAllowed +80681f80 ObjectKCL::UpdateKCL +80681f84 ObjectKCL::GetCollisionDiameter +80681f90 ObjectKCL::InitCollision +80681f94 0x80681f94 +80681f98 0x80681f98 +80681f9c 0x80681f9c +80681fa0 0x80681fa0 +80681fa4 0x80681fa4 +80681fac 0x80681fac +80681fb4 0x80681fb4 +80681fbc 0x80681fbc +80681fc4 0x80681fc4 +80681fc8 0x80681fc8 +80681fcc 0x80681fcc +80681fd0 0x80681fd0 +80681fd4 0x80681fd4 +80681fdc 0x80681fdc +80681fe4 0x80681fe4 +80681fec 0x80681fec +80681ff4 0x80681ff4 +80681ff8 0x80681ff8 +80681ffc 0x80681ffc +80682000 0x80682000 +80682004 0x80682004 +8068200c 0x8068200c +8068204c 0x8068204c +80682e28 0x80682e28 +80683c04 0x80683c04 +806849e0 0x806849e0 +806857bc 0x806857bc +80685bdc 0x80685bdc +80685ff4 0x80685ff4 +806862f8 0x806862f8 +806865f0 0x806865f0 +806867e8 0x806867e8 +8068684c 0x8068684c +8068690c 0x8068690c +80686a28 0x80686a28 +80686dd4 0x80686dd4 +80686dd8 0x80686dd8 +80686ddc 0x80686ddc +80686de0 0x80686de0 +80686e2c 0x80686e2c +80686e6c 0x80686e6c +80687010 0x80687010 +80687038 0x80687038 +80687098 0x80687098 +8068732c 0x8068732c +806873c4 ObjectExternKCL::UpdateOtherEntityPosWithRot +806873c8 ObjectExternKCL::vf_0x108 +806873d4 ObjectExternKCL::AreItemsAllowed +806873dc ObjectExternKCL::GetCollisionDiameter +8068741c ObjectExternKCL::GetYScale +80687424 0x80687424 +8068742c 0x8068742c +80687478 0x80687478 +80687480 0x80687480 +80687488 0x80687488 +80687490 obj_gnd_sphere::__ct +80687670 0x80687670 +80687714 0x80687714 +80687908 0x80687908 +8068790c 0x8068790c +80687b18 0x80687b18 +80687b58 0x80687b58 +80687e20 0x80687e20 +80687e7c 0x80687e7c +80688264 0x80688264 +80688308 0x80688308 +80688418 0x80688418 +806884cc 0x806884cc +8068851c 0x8068851c +8068856c 0x8068856c +806885bc 0x806885bc +8068860c 0x8068860c +8068865c 0x8068865c +806886ac 0x806886ac +806886fc 0x806886fc +8068874c 0x8068874c +8068879c 0x8068879c +8068896c 0x8068896c +806890e4 0x806890e4 +806891f0 0x806891f0 +806891f4 0x806891f4 +806891f8 0x806891f8 +806891fc 0x806891fc +80689200 0x80689200 +80689208 0x80689208 +80689210 0x80689210 +80689218 0x80689218 +80689220 0x80689220 +80689224 0x80689224 +80689228 0x80689228 +8068922c 0x8068922c +80689230 0x80689230 +80689238 0x80689238 +80689240 0x80689240 +80689248 0x80689248 +80689250 0x80689250 +80689254 0x80689254 +80689258 0x80689258 +8068925c 0x8068925c +80689260 0x80689260 +80689268 0x80689268 +806893f8 0x806893f8 +80689448 0x80689448 +80689498 0x80689498 +806894e8 0x806894e8 +80689538 0x80689538 +80689588 0x80689588 +806895d8 0x806895d8 +80689628 0x80689628 +80689678 0x80689678 +806896c8 0x806896c8 +806898a8 0x806898a8 +80689a38 0x80689a38 +80689a88 0x80689a88 +80689ad8 0x80689ad8 +80689b28 0x80689b28 +80689b78 0x80689b78 +80689bc8 0x80689bc8 +80689c18 0x80689c18 +80689c68 0x80689c68 +80689cb8 0x80689cb8 +80689d08 0x80689d08 +80689ef4 0x80689ef4 +8068a080 0x8068a080 +8068a0d0 0x8068a0d0 +8068a120 0x8068a120 +8068a170 0x8068a170 +8068a1c0 0x8068a1c0 +8068a210 0x8068a210 +8068a260 0x8068a260 +8068a2b0 0x8068a2b0 +8068a300 0x8068a300 +8068a350 0x8068a350 +8068a654 0x8068a654 +8068a7e0 0x8068a7e0 +8068a830 0x8068a830 +8068a880 0x8068a880 +8068a8d0 0x8068a8d0 +8068a920 0x8068a920 +8068a970 0x8068a970 +8068a9c0 0x8068a9c0 +8068aa10 0x8068aa10 +8068aa60 0x8068aa60 +8068aab0 0x8068aab0 +8068adbc 0x8068adbc +8068ae30 0x8068ae30 +8068afe8 0x8068afe8 +8068aff0 obj_gnd_wave1::__ct +8068b1d4 0x8068b1d4 +8068b278 0x8068b278 +8068b434 0x8068b434 +8068b438 obj_gnd_wave2::__ct +8068b650 0x8068b650 +8068b6f4 0x8068b6f4 +8068b89c 0x8068b89c +8068b8a0 0x8068b8a0 +8068bad0 0x8068bad0 +8068bb74 0x8068bb74 +8068c040 0x8068c040 +8068c044 0x8068c044 +8068c224 0x8068c224 +8068c2c8 0x8068c2c8 +8068c544 0x8068c544 +8068c548 Effects::Items::__ct +8068c8a0 Effects::Items::__dt +8068c8e0 Effects::Items::Init +8068c8ec 0x8068c8ec +8068c8f0 Effects::Items::CreateKouraTailGEffect +8068c944 Effects::Items::CreateKouraTailREffect +8068c998 Effects::Items::CreateKouraTailBEffect +8068c9ec 0x8068c9ec +8068ca14 0x8068ca14 +8068ca3c 0x8068ca3c +8068ca5c Effects::Items::FadeKouraTailGEffect +8068ca88 Effects::Items::FadeKouraTailREffect +8068cab4 Effects::Items::FadeKouraTailBEffect +8068cae0 Effects::Items::KillKouraTailGEffect +8068cb0c Effects::Items::KillKouraTailREffect +8068cb38 Effects::Items::KillKouraTailBEffect +8068cb64 Effects::Items::CreateKouraBrkGEffect +8068cbdc Effects::Items::CreateKouraBrkREffect +8068cc54 Effects::Items::CreateItemVanEffect +8068cc74 Effects::Items::CreateBombHeiEffect +8068cdb4 Effects::Items::CreateHaneKouraEffect +8068cdf0 Effects::Items::CreateBombHeiSparkEffect +8068ce88 Effects::Items:KillBombHeiEffect +8068ceb4 Effects::Items::CreateBananaEffect +8068cfc0 0x8068cfc0 +8068d054 Effects::Items::CreateKaminariGumoPreEffect +8068d144 Effects::Items::KillKaminariGumoPreEffect +8068d160 Effects::Items::CreateKaminariGumoVanEffect +8068d1f8 Effects::Items::UpdateKaminariGumoVanEffect +8068d374 Effects::Items::CreateKouraTailEffect +8068d600 0x8068d600 +8068d604 Effects::Player::__ct +8068de9c Effects::Player::GetRacedata +8068dea8 Effects::Player::GetCourseId +8068deb0 Effects::Player::Color::__ct +8068deb4 Effects::Player::Color::__dt +8068def4 Effects::Player::__dt +8068e014 Effects::Player::Init +8068e0c4 Effects::Player::Reset +8068e6b0 Effects::Player::LoadEffects +8068fde8 Effects::Player::LoadEffects_switch +8068fdec Effects::Player::LoadEffects_case0 +8068feb8 Effects::Player::LoadEffects_case1 +8068ff84 Effects::Player::LoadEffects_case2 +80690050 Effects::Player::LoadEffects_case3 +8069011c Effects::Player::LoadEffects_case4 +806901e8 Effects::Player::LoadEffects_case5 +806902b4 Effects::Player::LoadEffects_case6 +80690380 Effects::Player::LoadEffects_case7 +8069044c Effects::Player::LoadEffects_case8 +80690518 Effects::Player::LoadEffects_case9 +806905e4 Effects::Player::LoadEffects_casea +806906b0 Effects::Player::LoadEffects_caseb +806933c4 Effects::Player::Toggle +806933f0 Effects::Player::Update +80693500 Effects::Player::UpdateValues +80693d28 0x80693d28 +80694378 Effects::Player::UpdateItemEffect +80694c70 0x80694c70 +80694cd8 0x80694cd8 +80694f24 0x80694f24 +80694f60 Effects::Player::KillEffects +80695214 Effects::Player::UpdateNonItemEffects +8069635c 0x8069635c +80696588 0x80696588 +80696628 0x80696628 +806966a8 0x806966a8 +806967a4 0x806967a4 +806968a0 0x806968a0 +80696960 0x80696960 +80696a20 0x80696a20 +80696b30 0x80696b30 +80696c40 Effects::Player::CreateAndUpdateEffectsByIdx +80696df4 Effects::Player::FollowFadeEffectsByIdx +80696fe8 Effects::Player::CreateEffectsByIdx +8069705c Effects::Player::UpdateEffectsByIdx +80697198 Effects::Player::KillEffectsByIdx +8069724c Effects::Player::UpdateCollisionEffects +806973ac Effects::Player::UpdateCollisionEffects_caseD_0 +806973bc Effects::Player::UpdateCollisionEffects_caseD_1 +806973cc Effects::Player::UpdateCollisionEffects_caseD_2 +806973dc Effects::Player::UpdateCollisionEffects_caseD_3 +806973ec Effects::Player::UpdateCollisionEffects_caseD_4 +806973fc Effects::Player::UpdateCollisionEffects_caseD_5 +8069740c Effects::Player::UpdateCollisionEffects_caseD_6 +8069741c Effects::Player::UpdateCollisionEffects_caseD_7 +80697544 Effects::Player::UpdateCollisionEffects_case2D_0 +80697554 Effects::Player::UpdateCollisionEffects_case2D_1 +80697564 Effects::Player::UpdateCollisionEffects_case2D_2 +80697574 Effects::Player::UpdateCollisionEffects_case2D_3 +80697584 Effects::Player::UpdateCollisionEffects_case2D_4 +80697594 Effects::Player::UpdateCollisionEffects_case2D_5 +806975a4 Effects::Player::UpdateCollisionEffects_case2D_6 +806975b4 Effects::Player::UpdateCollisionEffects_case2D_7 +80697668 Effects::Player::UpdateVehicleEffects +80697694 Effects::Player::UpdateKartEffects +806985dc Effects::Player::UpdateBikeEffects +8069931c Effects::Player::UpdateJumpSmokeEffects +80699da4 0x80699da4 +80699f80 0x80699f80 +8069a260 0x8069a260 +8069a3ac 0x8069a3ac +8069a780 0x8069a780 +8069aa00 Effects::Player::UpdateStartUpEffects +8069adb4 Effects::Player::UpdateSlipStreamEffects +8069b164 Effects::Player::UpdateGasSmokeEffects +8069b6ac 0x8069b6ac +8069b828 0x8069b828 +8069b958 0x8069b958 +8069bcb4 0x8069bcb4 +8069bdfc 0x8069bdfc +8069be5c Effects::Player::UpdateWaterEffects +8069c584 0x8069c584 +8069c728 0x8069c728 +8069c78c Effects::Player::UpdateInBillEffects +8069d1a8 0x8069d1a8 +8069d210 Effects::Player::UpdateThunderEffects +8069d970 0x8069d970 +8069db80 0x8069db80 +8069df18 Effects::Player::Create228Effect +8069e1c8 Effects::Player::Create25CEffect +8069ea50 0x8069ea50 +8069ea88 0x8069ea88 +8069ecfc 0x8069ecfc +8069ef84 0x8069ef84 +8069f35c Effects::Player::UpdateInkEffect +8069f950 0x8069f950 +8069f9dc 0x8069f9dc +8069fa94 0x8069fa94 +806a01b8 0x806a01b8 +806a0648 Effects::Player::UpdateFromWheelCollision +806a07c8 Effects::Player::UpdateFromWheelCollision_switch +806a07cc Effects::Player::UpdateFromWheelCollision_caseD_0 +806a07e8 Effects::Player::UpdateFromWheelCollision_caseD_1 +806a0804 Effects::Player::UpdateFromWheelCollision_caseD_4 +806a0820 Effects::Player::UpdateFromWheelCollision_caseD_5 +806a083c Effects::Player::UpdateFromWheelCollision_caseD_3 +806a0854 Effects::Player::UpdateFromWheelCollision_caseD_2 +806a0868 Effects::Player::UpdateFromWheelCollision_caseD_6 +806a087c Effects::Player::UpdateFromWheelCollision_caseD_7 +806a0ccc Effects::Player::UpdateFromKartCollision +806a0e74 0x806a0e74 +806a0e8c 0x806a0e8c +806a0fa4 0x806a0fa4 +806a1044 Effects::Player::CreateAndUpdateEffectsByIdxVelocity +806a11d4 Effects::Player::FollowFadeEffectsByIdxVelocity +806a1334 0x806a1334 +806a1388 0x806a1388 +806a13dc 0x806a13dc +806a14b8 0x806a14b8 +806a151c 0x806a151c +806a1644 0x806a1644 +806a1720 0x806a1720 +806a1784 0x806a1784 +806a1860 0x806a1860 +806a18c4 0x806a18c4 +806a19b4 0x806a19b4 +806a1a90 0x806a1a90 +806a1af4 0x806a1af4 +806a1be4 0x806a1be4 +806a1c58 0x806a1c58 +806a1d0c 0x806a1d0c +806a1dec 0x806a1dec +806a1e50 0x806a1e50 +806a1f78 0x806a1f78 +806a2058 0x806a2058 +806a20bc 0x806a20bc +806a21e4 0x806a21e4 +806a2280 0x806a2280 +806a229c 0x806a229c +806a2350 0x806a2350 +806a2470 0x806a2470 +806a24f8 0x806a24f8 +806a258c 0x806a258c +806a27a4 0x806a27a4 +806a27f0 0x806a27f0 +806a28d8 0x806a28d8 +806a2a20 0x806a2a20 +806a2b10 0x806a2b10 +806a2c38 0x806a2c38 +806a2c84 0x806a2c84 +806a2d34 0x806a2d34 +806a2e24 0x806a2e24 +806a2e88 0x806a2e88 +806a2f04 0x806a2f04 +806a2f50 0x806a2f50 +806a2fb4 0x806a2fb4 +806a3130 0x806a3130 +806a33b4 0x806a33b4 +806a35fc 0x806a35fc +806a368c 0x806a368c +806a371c 0x806a371c +806a37b8 0x806a37b8 +806a38b4 0x806a38b4 +806a3984 0x806a3984 +806a3a20 0x806a3a20 +806a3b1c 0x806a3b1c +806a3bec 0x806a3bec +806a3c88 0x806a3c88 +806a3d84 0x806a3d84 +806a3e54 0x806a3e54 +806a3edc 0x806a3edc +806a3f8c 0x806a3f8c +806a4034 0x806a4034 +806a40e4 0x806a40e4 +806a418c 0x806a418c +806a4200 0x806a4200 +806a42a4 0x806a42a4 +806a4354 0x806a4354 +806a4418 0x806a4418 +806a44c8 0x806a44c8 +806a458c 0x806a458c +806a463c 0x806a463c +806a4700 0x806a4700 +806a47b0 0x806a47b0 +806a4874 0x806a4874 +806a4944 0x806a4944 +806a49e8 0x806a49e8 +806a4b3c 0x806a4b3c +806a4ccc 0x806a4ccc +806a4fe8 0x806a4fe8 +806a506c 0x806a506c +806a53f8 0x806a53f8 +806a541c 0x806a541c +806a54a0 0x806a54a0 +806a581c 0x806a581c +806a58a0 0x806a58a0 +806a5910 Vec3::DivideByScalar +806a5944 0x806a5944 +806a59a0 0x806a59a0 +806a5a94 0x806a5a94 +806a5c58 Effects::Player::CreateRKHitEffect +806a5d10 Effects::Player::OnBushCollision +806a5e50 0x806a5e50 +806a5e64 Effects::Player::CreateSpinEffect +806a6098 0x806a6098 +806a6144 0x806a6144 +806a62a0 0x806a62a0 +806a634c 0x806a634c +806a64a8 0x806a64a8 +806a6554 0x806a6554 +806a66b0 0x806a66b0 +806a675c 0x806a675c +806a68b8 0x806a68b8 +806a692c 0x806a692c +806a69d0 0x806a69d0 +806a6a44 0x806a6a44 +806a6ae8 0x806a6ae8 +806a6b94 0x806a6b94 +806a6c38 0x806a6c38 +806a6cac 0x806a6cac +806a6d50 0x806a6d50 +806a6e20 0x806a6e20 +806a6ec4 0x806a6ec4 +806a7060 0x806a7060 +806a7150 0x806a7150 +806a71d4 0x806a71d4 +806a7274 0x806a7274 +806a72f8 0x806a72f8 +806a739c 0x806a739c +806a7440 0x806a7440 +806a7510 0x806a7510 +806a7574 0x806a7574 +806a75ec 0x806a75ec +806a760c 0x806a760c +806a76b8 0x806a76b8 +806a775c 0x806a775c +806a77c0 0x806a77c0 +806a7830 0x806a7830 +806a78d4 Effects::Player::CreateKartBrakeBackwardsEffects +806a79e8 Effects::Player::KillKartBrakeBackwardsEffects +806a7b08 0x806a7b08 +806a7b50 0x806a7b50 +806a7bf4 Effects::Player::CreateBikeBrakeBackwardsEffects +806a7ce8 Effects::Player::KillBikeBrakeBackwardsEffects +806a7de8 0x806a7de8 +806a7e88 0x806a7e88 +806a7f64 0x806a7f64 +806a8004 0x806a8004 +806a8084 0x806a8084 +806a8140 Effects::Player::CreateStarEffect +806a831c Effects::Player::UpdateStarEffect +806a8598 Effects::Player::CreateRKKiller +806a86dc Effects::Player::UpdateRKKiller +806a8910 0x806a8910 +806a8994 0x806a8994 +806a8a14 0x806a8a14 +806a8a98 0x806a8a98 +806a8bbc 0x806a8bbc +806a8c5c 0x806a8c5c +806a8d38 0x806a8d38 +806a8f38 0x806a8f38 +806a91b4 0x806a91b4 +806a93b4 0x806a93b4 +806a9630 0x806a9630 +806a9834 0x806a9834 +806a98e0 0x806a98e0 +806a99a8 0x806a99a8 +806a9b38 0x806a9b38 +806a9b74 0x806a9b74 +806a9b9c Effects::Player::UpdatePowEffect +806a9df0 Effects::Player::UpdatePow1Effect +806a9ff4 0x806a9ff4 +806aa098 0x806aa098 +806aa214 0x806aa214 +806aa264 0x806aa264 +806aa350 0x806aa350 +806aa46c 0x806aa46c +806aa570 Effects::Player::UpdateNiseBoxBiriEffect +806aa740 0x806aa740 +806aa840 0x806aa840 +806aa904 0x806aa904 +806aa9a8 0x806aa9a8 +806aaad4 0x806aaad4 +806aab78 0x806aab78 +806aac78 0x806aac78 +806aad1c 0x806aad1c +806aaf0c Effects::Player::TriggerPochaEffect +806ab160 0x806ab160 +806ab188 0x806ab188 +806ab1c8 Effects::Player::CreatePochaEffect +806ab3a8 0x806ab3a8 +806ab57c 0x806ab57c +806ab614 0x806ab614 +806ab72c 0x806ab72c +806ab7ac 0x806ab7ac +806ab87c 0x806ab87c +806ab924 0x806ab924 +806aba6c 0x806aba6c +806abc84 0x806abc84 +806abd08 0x806abd08 +806abda8 0x806abda8 +806abe7c 0x806abe7c +806abf90 0x806abf90 +806ac170 0x806ac170 +806ac188 0x806ac188 +806ac628 0x806ac628 +806ac6f4 0x806ac6f4 +806acb84 0x806acb84 +806acc50 0x806acc50 +806ad0e0 0x806ad0e0 +806ad1ac 0x806ad1ac +806ad338 0x806ad338 +806ad34c 0x806ad34c +806ad4c4 0x806ad4c4 +806ad4d8 0x806ad4d8 +806ad54c 0x806ad54c +806ad560 Effects::Player::CreateSandEffect +806ad9d8 Effects::Player::Color::__ct(args) +806ad9ec Effects::Player::Color::operator= +806ada10 0x806ada10 +806adbf8 Effects::Player::CreateGrassEffect +806adf58 0x806adf58 +806ae134 Effects::Player::CreateSnowDirtEffect +806ae428 0x806ae428 +806ae5f4 0x806ae5f4 +806ae6a4 Effects::Player::CreateSnowRoadEffect +806aeb3c 0x806aeb3c +806aedd4 Effects::Player::CreateWaterEffect +806af058 0x806af058 +806af270 Effects::Player::CreateMudEffect +806af57c 0x806af57c +806af704 Effects::Player::CreateFlowerEffect +806af9a0 0x806af9a0 +806afb28 Effects::Player::CreateStoneEffect +806afdc0 0x806afdc0 +806aff44 0x806aff44 +806b0220 0x806b0220 +806b0470 0x806b0470 +806b081c 0x806b081c +806b0d88 Effects::Player::SetOffroadColors +806b1c18 0x806b1c18 +806b1d88 0x806b1d88 +806b1dd0 0x806b1dd0 +806b1eec 0x806b1eec +806b1f34 0x806b1f34 +806b1fb8 0x806b1fb8 +806b1fd0 0x806b1fd0 +806b22cc 0x806b22cc +806b2418 0x806b2418 +806b2968 0x806b2968 +806b2a4c 0x806b2a4c +806b2ac8 0x806b2ac8 +806b2d04 Effects::Player::SetGessoEffectsVisibility +806b2e38 Effects::Player::UpdateGessoEffectsVisibility +806b2f14 0x806b2f14 +806b2f6c Vector3_rotate +806b304c 0x806b304c +806b3130 0x806b3130 +806b31ac 0x806b31ac +806b3310 Vec3::CalcYAxisRotMtx +806b3488 0x806b3488 +806b35dc 0x806b35dc +806b3774 0x806b3774 +806b384c 0x806b384c +806b3934 0x806b3934 +806b3ae0 0x806b3ae0 +806b3c24 0x806b3c24 +806b3d10 0x806b3d10 +806b3d64 0x806b3d64 +806b3dc8 0x806b3dc8 +806b49ec 0x806b49ec +806b4b9c 0x806b4b9c +806b4c30 0x806b4c30 +806b5014 -bx^2+ax +806b5078 CreateParabola +806b509c 0x806b509c +806b50a0 0x806b50a0 +806b50a4 0x806b50a4 +806b50a8 0x806b50a8 +806b50ac 0x806b50ac +806b5134 Effects::Mgr::CreateOneTimeEffect(pos) +806b5194 Effects::Mgr::CreateOneTimeEffect(mtx) +806b51f4 Effects::Mgr::CreateOneTimeEffect(pos, scale) +806b5270 Effects::Mgr::CreateOneTimeEffect(mtx, scale) +806b52ec 0x806b52ec +806b52f0 Objects::Basabasa::__ct +806b5488 0x806b5488 +806b54ec Objects::Basabasa::OnStart +806b5694 Objects::Basabasa::vf_0x10 +806b5698 Objects::Basabasa::Update +806b576c 0x806b576c +806b58f4 0x806b58f4 +806b5b98 0x806b5b98 +806b5ee0 Objects::Basabasa::OnCollision +806b6084 Objects::Basabasa::OnItemCollision +806b6518 Objects::Basabasa::UpdateShadow +806b673c Objects::BasabasaMgr::__ct +806b6960 Objects::BasabasaMgr::__dt +806b69a0 Objects::BasabasaMgr::OnStart +806b6b2c Objects::BasabasaMgr::vf_0x10 +806b6b30 Objects::BasabasaMgr::Update +806b6c84 Objects::BasabasaMgr::LoadClipInfo +806b6c88 Objects::BasabasaMgr::LoadCollision +806b6c8c Objects::BasabasaMgr::LoadRoute +806b6c90 Objects::BasabasaMgr::LoadModels +806b6c94 Objects::BasabasaMgr::GetPropertiesBitfield +806b6c9c Objects::Basabasa::__dt +806b6d08 0x806b6d08 +806b6d10 Objects::Basabasa::LoadAnimations +806b6d54 Objects::Basabasa::GetName +806b6d60 Objects::Basabasa::GetSubFileName +806b6d6c Objects::Basabasa::GetPropertiesBitfield +806b6d74 Objects::Basabasa::__dt(thunk) +806b6d7c Objects::CarA::__ct +806b6ed4 0x806b6ed4 +806b6f38 Objects::CarA::__dt +806b6fb0 Objects::CarA::LoadModels +806b71b0 Objects::CarA::LoadCollision +806b7230 Objects::CarA::UpdateCollision +806b734c Objects::CarA::OnStart +806b74cc Objects::CarA::OnCollision +806b7698 Objects::CarA::OnItemCollision +806b7938 Objects::CarA::Update +806b7b68 0x806b7b68 +806b7bf4 0x806b7bf4 +806b7c18 0x806b7c18 +806b7d5c Objects::CarA::UpdateRoute +806b7ea4 0x806b7ea4 +806b7eb0 0x806b7eb0 +806b7f80 0x806b7f80 +806b8014 0x806b8014 +806b8338 0x806b8338 +806b83a8 0x806b83a8 +806b84c0 0x806b84c0 +806b8548 0x806b8548 +806b8550 Objects::CarA::LoadAnimations +806b85b0 Objects::CarA::GetPropertiesBitfield +806b85b8 MiiCreationParams::__dt +806b85f8 Objects::CarA::__dt(thunk) +806b8600 0x806b8600 +806b86e0 0x806b86e0 +806b8720 0x806b8720 +806b8750 0x806b8750 +806b87d0 0x806b87d0 +806b88d8 0x806b88d8 +806b88e0 0x806b88e0 +806b8a38 0x806b8a38 +806b8a94 0x806b8a94 +806b8b0c 0x806b8b0c +806b8b80 0x806b8b80 +806b8c00 0x806b8c00 +806b8ce0 0x806b8ce0 +806b8d0c 0x806b8d0c +806b9194 0x806b9194 +806b91f8 0x806b91f8 +806b9264 0x806b9264 +806b94cc 0x806b94cc +806b97b0 0x806b97b0 +806b99e4 0x806b99e4 +806b9d44 0x806b9d44 +806b9e68 0x806b9e68 +806ba258 0x806ba258 +806ba7b0 0x806ba7b0 +806baa00 0x806baa00 +806baa04 0x806baa04 +806baa08 0x806baa08 +806bac5c 0x806bac5c +806baea4 0x806baea4 +806baea8 0x806baea8 +806baeac 0x806baeac +806bb0e8 0x806bb0e8 +806bb154 0x806bb154 +806bb1ec 0x806bb1ec +806bb308 0x806bb308 +806bb448 0x806bb448 +806bb450 0x806bb450 +806bb4a0 0x806bb4a0 +806bb4a8 0x806bb4a8 +806bb4ac 0x806bb4ac +806bb4b0 0x806bb4b0 +806bb4b8 0x806bb4b8 +806bb4c4 0x806bb4c4 +806bb4d0 0x806bb4d0 +806bb4d8 0x806bb4d8 +806bb518 0x806bb518 +806bb51c 0x806bb51c +806bb524 0x806bb524 +806bb52c Objects::CowBase::__ct +806bb590 Objects::CowBase::__dt +806bb5d0 0x806bb5d0 +806bb790 0x806bb790 +806bb918 Objects::CowBase::OnCollision +806bba5c Objects::CowBase::OnItemCollision +806bbc2c 0x806bbc2c +806bbd44 0x806bbd44 +806bbee8 Objects::CowBase::vf_0xf0 +806bc040 0x806bc040 +806bc194 0x806bc194 +806bc210 0x806bc210 +806bc32c 0x806bc32c +806bc430 0x806bc430 +806bc4f4 0x806bc4f4 +806bc5b8 0x806bc5b8 +806bc640 0x806bc640 +806bc6ec Objects::CowLeader::__ct +806bc800 0x806bc800 +806bc864 Objects::CowLeader::__dt +806bc8d0 Objects::CowLeader::OnStart +806bc9f4 Objects::CowLeader::Update +806bcd1c 0x806bcd1c +806bcda4 0x806bcda4 +806bce44 0x806bce44 +806bceb8 0x806bceb8 +806bd088 0x806bd088 +806bd0dc 0x806bd0dc +806bd344 Objects::CowLeader::vf_0xf0 +806bd3b0 0x806bd3b0 +806bd3b4 Objects::CowVassal::__ct +806bd5fc 0x806bd5fc +806bd660 Objects::CowVassal::__dt +806bd6cc Objects::CowVassal::OnStart +806bd814 Objects::CowVassal::Update +806bdb54 0x806bdb54 +806bdbec 0x806bdbec +806bdc98 0x806bdc98 +806bde00 0x806bde00 +806bdf9c 0x806bdf9c +806be038 0x806be038 +806be1c0 Objects::CowGroup::__ct +806be658 Objects::CowGroup::__dt +806be698 Objects::CowGroup::OnStart +806be6d0 Objects::CowGroup::Update +806be780 0x806be780 +806be9b0 Objects::CowGroup::LoadClipInfo +806be9b4 Objects::CowGroup::LoadCollision +806be9b8 Objects::CowGroup::LoadRoute +806be9bc Objects::CowGroup::LoadModels +806be9c0 Objects::CowGroup::GetPropertiesBitfield +806be9c8 Objects::CowBase::vf_0xec +806be9d0 Objects::CowBase::LoadAnimations +806bea8c Objects::CowVassal::LoadRoute +806bea90 Objects::CowVassal::GetPropertiesBitfield +806bea98 Objects::CowLeader::GetPropertiesBitfield +806beaa0 Object::GetGetPropertiesBitfield +806beab4 Object::Update +806beb24 Objects::CowLeader::__dt(thunk) +806beb2c Objects::CowVassal::__dt(thunk) +806beb34 0x806beb34 +806beba4 0x806beba4 +806bebe4 0x806bebe4 +806bec50 0x806bec50 +806bec70 0x806bec70 +806bedd0 0x806bedd0 +806bedd4 0x806bedd4 +806beddc 0x806beddc +806bee1c 0x806bee1c +806bee24 0x806bee24 +806bee68 0x806bee68 +806beeec 0x806beeec +806beef4 0x806beef4 +806bef84 0x806bef84 +806befc4 0x806befc4 +806bf05c 0x806bf05c +806bf060 0x806bf060 +806bf140 0x806bf140 +806bf180 Objects::Cannon::__ct +806bf2b4 Objects::Cannon::LoadAnimations +806bf3fc Objects::Cannon::__dt +806bf448 Objects::Cannon::OnStart +806bf53c Objects::Cannon::Update +806bfa78 Objects::Cannon::OnActivation +806bfb60 Objects::Cannon::vf_0xec +806bfb68 0x806bfb68 +806bfb70 Objects::Cannon::GetScnObjDrawOptionsIdx +806bfb78 Objects::EffectSpawner::__ct +806bfbcc Objects::EffectSpawner::OnStart +806bfbdc Objects::EffectSpawner::OnCollision +806bfd5c Objects::EffectSpawner::Update +806bfe50 Objects::EffectSpawner::__dt +806bfe90 Objects::EffectSpawner::OnItemCollision +806bfebc Objects::EffectSpawner::OnWallCollision +806bfec0 Objects::EffectSpawner::GetPropertiesBitfield +806bfec8 Objects::LeafEffect::__ct +806c0008 Objects::LeafEffect::OnCollision +806c01c0 Objects::LeafEffect::Update +806c0344 Objects::LeafEffect::__dt +806c0384 Objects::FireSnake_ball::__ct +806c03f4 Objects::FireSnake_ball::OnStart +806c046c Objects::FireSnake_ball::vf_0xec +806c048c Objects::FireSnake_ball::ToggleVisible +806c0490 Objects::FireSnake_ball::Update +806c0494 0x806c0494 +806c0534 0x806c0534 +806c0588 0x806c0588 +806c059c Objects::FireSnake::__ct +806c08f0 Objects::MapObjProjectile::__dt +806c0930 Objects::FireSnake_ball::SetScale +806c094c 0x806c094c +806c09b0 Objects::FireSnake::__dt +806c0a1c Objects::FireSnake::OnStart +806c0b50 Objects::FireSnake::Update +806c0e84 Objects::FireSnake::OnCollision +806c0f14 Objects::FireSnake::OnItemCollision +806c0f9c Objects::FireSnake::OnCycleEnd +806c1050 Objects::FireSnake::OnCycleEnd2 +806c1054 Objects::FireSnake::OnCycleStart +806c10f4 Objects::FireSnake::OnCycleStart2 +806c1438 Objects::FireSnake::OnInitialGroundCollision +806c14fc Objects::FireSnake::vf_0x114 +806c166c Objects::FireSnake::vf_0x118 +806c17a4 Objects::FireSnake::vf_0x11c +806c1834 0x806c1834 +806c18bc Objects::FireSnake::vf_0x120 +806c18c0 Objects::FireSnake::vf_0x124 +806c1a24 Objects::FireSnake::vf_0x128 +806c1a30 Objects::FireSnake::vf_0x12c +806c1a34 Objects::FireSnake::vf_0xec +806c1b9c 0x806c1b9c +806c1f70 Objects::FireSnake_ball::GetEntity +806c1f78 Objects::FireSnake_ball::UpdateDrawInfo +806c1fd4 Objects::FireSnake_ball::vf_0x8c +806c1fd8 Objects::FireSnake_ball::vf_0xf8 +806c2068 Objects::FireSnake::RequestShoot +806c2074 Objects::FireSnake::vf_0x130 +806c207c Objects::FireSnake::LoadAnimations +806c20c8 Objects::FireSnake::GetPropertiesBitfield +806c20d0 Objects::FireSnake_eye::LoadCollision +806c20d4 Objects::FireSnake_eye::LoadRoute +806c20d8 Objects::FireSnake_eye::GetName +806c20e4 Objects::FireSnake_eye::GetSubFileName +806c20f0 Objects::FireSnake_eye::GetPropertiesBitfield +806c20f8 Objects::FireSnake_eye::__dt +806c2138 Objects::FireSnake_ball::__dt +806c2178 Objects::FireSnake_ball::vf_0xf0 +806c2180 Objects::FireSnake_ball::LoadAnimations +806c21cc Objects::FireSnake_ball::GetPropertiesBitfield +806c21d4 Objects::FireSnake::__dt(thunk) +806c21dc Objects::FireSnake_v::__ct +806c2328 Objects::FireSnake_v::OnStart +806c23c0 Objects::FireSnake_v::Update +806c2410 0x806c2410 +806c275c Objects::FireSnake_v::OnCycleEnd +806c2760 Objects::FireSnake_v::OnCycleEnd2 +806c2764 Objects::FireSnake_v::OnCycleStart +806c285c Objects::FireSnake_v::OnCycleStart2 +806c2a20 Objects::FireSnake_v::OnInitialGroundCollision +806c2a30 Objects::FireSnake_v::vf_0x114 +806c2bb4 Objects::FireSnake_v::__dt +806c2c0c 0x806c2c0c +806c2c14 0x806c2c14 +806c2d08 0x806c2d08 +806c2d48 0x806c2d48 +806c2dc8 0x806c2dc8 +806c2e5c 0x806c2e5c +806c2ed0 0x806c2ed0 +806c2ed4 0x806c2ed4 +806c2fa8 0x806c2fa8 +806c2fb0 0x806c2fb0 +806c2ff4 0x806c2ff4 +806c3034 0x806c3034 +806c30a8 0x806c30a8 +806c30ac 0x806c30ac +806c30b0 0x806c30b0 +806c30b8 0x806c30b8 +806c3108 0x806c3108 +806c3110 obj_FlamePole_v::__ct +806c3498 0x806c3498 +806c34fc 0x806c34fc +806c3638 obj_FlamePole_v_update +806c3750 0x806c3750 +806c379c 0x806c379c +806c37e4 0x806c37e4 +806c385c obj_FlamePole_v_raiseUpdate +806c38ec obj_FlamePole_v_beforeShake +806c390c obj_FlamePole_v_calcShake +806c3a28 obj_FlamePole_v_dropUpdate +806c3a54 0x806c3a54 +806c3ae4 0x806c3ae4 +806c3b34 0x806c3b34 +806c3b50 0x806c3b50 +806c3e20 0x806c3e20 +806c3e8c 0x806c3e8c +806c3ee4 0x806c3ee4 +806c3eec 0x806c3eec +806c3ef8 0x806c3ef8 +806c3f04 0x806c3f04 +806c3f0c 0x806c3f0c +806c3f14 0x806c3f14 +806c42a0 0x806c42a0 +806c42a4 0x806c42a4 +806c4500 0x806c4500 +806c4540 ManagedObjects::RegisterObject +806c455c Objects::HwanwanItembox::__ct +806c45e0 Objects::Itembox::__dt +806c4620 0x806c4620 +806c4660 Objects::HwanwanItembox::OnStart +806c46dc Objects::HwanwanItembox::Update +806c48c0 Objects::HwanwanItembox::UpdateShadow +806c49c0 Objects::Hwanwan::__ct +806c4d48 Objects::Hwanwan::__dt +806c4d88 0x806c4d88 +806c5130 Objects::Hwanwan::Update +806c5238 Objects::Hwanwan::vf_0xec +806c544c 0x806c544c +806c57b4 0x806c57b4 +806c5808 0x806c5808 +806c5880 0x806c5880 +806c5a14 RouteController::SetPercent +806c5a1c 0x806c5a1c +806c5d44 0x806c5d44 +806c5d60 0x806c5d60 +806c5de8 0x806c5de8 +806c5f98 0x806c5f98 +806c6014 0x806c6014 +806c6018 Objects::Hwanwan::LoadClipInfo +806c601c Objects::Hwanwan::LoadCollision +806c6020 Objects::Hwanwan::LoadModels +806c6024 Objects::Hwanwan::GetPropertiesBitfield +806c602c Objects::Itembox::IsActive +806c6040 Objects::Itembox::IsSolid +806c6048 Objects::Itembox::OnNormalCollision +806c604c Objects::Itembox::UpdateModelScale +806c6050 Objects::Itembox::UpdateModelMatrix +806c6054 Objects::Itembox::LoadShadow +806c6068 Objects::Itembox::GetPropertiesBitfield +806c6070 Objects::HwanwanItembox::GetBRRESName +806c607c Objects::HwanwanItembox::GetSubFileName +806c6088 Objects::HwanwanItembox::GetName +806c6094 Objects::HwanwanItembox::GetID +806c60ac Objects::HwanwanItembox::__dt +806c60ec Objects::HwanwanItembox::LoadRoute +806c60f0 Objects::Itembox::UpdateShadow +806c60f4 0x806c60f4 +806c60f8 Objects::OnStart +806c6144 Objects::Hwanwan_Chn::ToggleVisible +806c6148 Objects::Hwanwan_Chn::__dt +806c6188 Objects::Hwanwan_Chn::LoadCollision +806c618c Objects::Hwanwan_Chn::LoadRoute +806c6190 Objects::Hwanwan_Chn::GetName +806c619c Objects::Hwanwan_Chn::GetSubFileName +806c61a8 Objects::Hwanwan_Chn::GetPropertiesBitfield +806c61b0 Objects::HanachanPart::LoadModels +806c61e8 Objects::HanachanPart::OnStart +806c6274 Objects::HanachanPart::vf_0x100 +806c627c Objects::HanachanPart::Update +806c6300 Objects::HanachanPart::OnCollision +806c64ac Objects::HanachanPart::OnItemCollision +806c66d0 0x806c66d0 +806c67f4 0x806c67f4 +806c68a8 0x806c68a8 +806c6924 0x806c6924 +806c6ce0 0x806c6ce0 +806c6e04 0x806c6e04 +806c6e24 0x806c6e24 +806c6f38 0x806c6f38 +806c6f60 0x806c6f60 +806c7080 0x806c7080 +806c7180 0x806c7180 +806c72d8 nw4r::g3d::ICalcWorldCallback::__dt +806c7318 Objects::BossHanachanHead::CalcWorldCB::ExecCallbackB +806c73d4 0x806c73d4 +806c73e0 Objects::BossHanachanHead::__ct +806c74d4 Objects::HanachanPart::__dt +806c7514 0x806c7514 +806c77f8 Objects::BossHanachanHead::LoadCollision +806c7870 Objects::BossHanachanHead::OnStart +806c7918 Objects::BossHanachanHead::Update +806c7abc Objects::BossHanachanHead::UpdateCollision +806c7c40 0x806c7c40 +806c7d90 0x806c7d90 +806c7e28 0x806c7e28 +806c7e38 Objects::HanachanBody::LoadAnimations +806c7ee4 Objects::HanachanBody::OnStart +806c7f74 0x806c7f74 +806c80c8 Objects::Hanachan::__ct +806c8ba0 0x806c8ba0 +806c8c04 Objects::Hanachan::__dt +806c8c9c Objects::Hanachan::OnStart +806c8ecc Objects::Hanachan::Update +806c9224 0x806c9224 +806c922c 0x806c922c +806c93a4 0x806c93a4 +806c9534 0x806c9534 +806c9604 0x806c9604 +806c98b4 Objects::Hanachan::vf_0xC(parent) +806c98b8 0x806c98b8 +806c98e8 0x806c98e8 +806c995c 0x806c995c +806c9bc0 0x806c9bc0 +806c9bc8 0x806c9bc8 +806c9c50 0x806c9c50 +806c9d38 0x806c9d38 +806c9d98 0x806c9d98 +806c9f4c 0x806c9f4c +806ca018 0x806ca018 +806ca0f8 0x806ca0f8 +806ca13c 0x806ca13c +806ca1c8 0x806ca1c8 +806ca33c 0x806ca33c +806ca540 0x806ca540 +806ca608 0x806ca608 +806ca624 0x806ca624 +806ca714 0x806ca714 +806ca854 0x806ca854 +806ca998 0x806ca998 +806caa68 0x806caa68 +806cabf4 0x806cabf4 +806cabfc 0x806cabfc +806cadd0 0x806cadd0 +806cafbc 0x806cafbc +806cb04c 0x806cb04c +806cb230 0x806cb230 +806cb498 0x806cb498 +806cb4b4 0x806cb4b4 +806cb514 0x806cb514 +806cb584 0x806cb584 +806cb5f4 0x806cb5f4 +806cb664 0x806cb664 +806cb7b8 0x806cb7b8 +806cb8b8 0x806cb8b8 +806cbaa8 0x806cbaa8 +806cbaf8 0x806cbaf8 +806cbd2c 0x806cbd2c +806cbf54 0x806cbf54 +806cc050 nw4r::g3d::ICalcWorldCallback::ExecCallbackC +806cc054 nw4r::g3d::ICalcWorldCallback::ExecCallbackA +806cc058 Objects::Hanachan::UpdateModel +806cc05c Objects::Hanachan::LoadClipInfo +806cc060 Objects::Hanachan::LoadCollision +806cc064 Objects::Hanachan::LoadModels +806cc068 Objects::Hanachan::GetPropertiesBitfield +806cc070 Objects::HanachanPart::vf_0x104 +806cc078 Objects::HanachanPart::vf_0x84 +806cc080 Objects::HanachanPart::UpdateModelMatrix +806cc138 Objects::HanachanPart::LoadRoute +806cc13c Objects::HanachanPart::GetPropertiesBitfield +806cc144 Objects::HanachanBody::__dt +806cc184 Objects::HanachanBody::vf_0xfc +806cc18c Objects::HanachanBody::vf_0xf8 +806cc194 Objects::HanachanBody::vf_0x108 +806cc19c 0x806cc19c +806cc1b8 0x806cc1b8 +806cc1d8 0x806cc1d8 +806cc1e0 Objects::HanachanBody::GetShadowResName +806cc1ec Objects::HanachanBody::GetSubFileName +806cc1f4 Objects::HanachanPart::GetSubFileName +806cc200 Objects::BossHanachanHead::__dt +806cc240 Objects::BossHanachanHead::vf_0xfc +806cc25c Objects::BossHanachanHead::vf_0xf8 +806cc264 Objects::BossHanachanHead::vf_0xf4 +806cc2b0 Objects::BossHanachanHead::vf_0xf0 +806cc310 Objects::BossHanachanHead::vf_0xec +806cc390 Objects::BossHanachanHead::UpdateShadow +806cc404 Objects::BossHanachanHead::vf_0x108 +806cc40c Objects::BossHanachanHead::LoadAnimations +806cc494 Objects::BossHanachanHead::GetBRRESName +806cc4a0 nw4r::g3d::ICalcWorldCallback::ExecCallbackB +806cc4a4 Objects::BossHanachanHead::CalcWorldCB::__dt +806cc4e4 Objects::BossHanachanHead::CalcWorldCB::ExecCallbackB(thunk) +806cc4ec Objects::BossHanachanHead::CalcWorldCB::__dt(thunk) +806cc4f4 Objects::Hanachan::__dt(thunk) +806cc4fc 0x806cc4fc +806cc6b0 0x806cc6b0 +806cc994 0x806cc994 +806ccac4 0x806ccac4 +806ccb2c 0x806ccb2c +806ccd4c 0x806ccd4c +806cced4 0x806cced4 +806cd000 0x806cd000 +806cd32c 0x806cd32c +806cd330 0x806cd330 +806cd38c 0x806cd38c +806cd448 0x806cd448 +806cd44c 0x806cd44c +806cd450 0x806cd450 +806cd534 0x806cd534 +806cd6a8 0x806cd6a8 +806cd7d4 0x806cd7d4 +806cd9c0 0x806cd9c0 +806cda08 0x806cda08 +806cda3c 0x806cda3c +806cda9c 0x806cda9c +806cdbb4 0x806cdbb4 +806cde1c 0x806cde1c +806cde74 0x806cde74 +806cde7c 0x806cde7c +806cde84 0x806cde84 +806cde8c 0x806cde8c +806cde94 Objects::Heyho::__ct +806ce12c 0x806ce12c +806ce190 Objects::Heyho::__dt +806ce1fc Objects::Heyho::OnStart +806ce460 Objects::Heyho::vf_0x10 +806ce464 Objects::Heyho::Update +806ce690 Objects::Heyho::OnCollision +806ce804 Objects::Heyho::OnItemCollision +806cea10 Objects::Heyho::UpdateShadow +806ceb38 0x806ceb38 +806ceb3c obj_heyho_move_update +806ced80 obj_heyho_beforeJump +806ced98 obj_heyho_jump_update +806cf12c 0x806cf12c +806cf1a4 0x806cf1a4 +806cf3b4 0x806cf3b4 +806cf41c 0x806cf41c +806cf61c 0x806cf61c +806cf694 0x806cf694 +806cf71c 0x806cf71c +806cf7a8 Objects::Heyho::LoadAnimations +806cf838 Objects::Heyho::vf_0xc +806cf840 Objects::Heyho::UpdateCollision +806cf920 Objects::Heyho::GetPropertiesBitfield +806cf928 0x806cf928 +806cf930 Objects::HeyHoBallGBA::__ct +806cfbf8 0x806cfbf8 +806cfc5c Objects::HeyHoBallGBA::OnStart +806cfdec Objects::HeyHoBallGBA::Update +806cfeec Objects::HeyHoBallGBA::OnCollision +806cffe4 Objects::HeyHoBallGBA::OnItemCollision +806d006c 0x806d006c +806d0080 0x806d0080 +806d00a8 0x806d00a8 +806d0144 0x806d0144 +806d0278 0x806d0278 +806d0344 0x806d0344 +806d03f0 0x806d03f0 +806d0590 0x806d0590 +806d0710 Objects::HeyHoBallGBA::vf_0xec +806d0834 0x806d0834 +806d0974 0x806d0974 +806d09f0 0x806d09f0 +806d0b44 0x806d0b44 +806d0bdc 0x806d0bdc +806d0c14 0x806d0c14 +806d0e8c Objects::HeyHoBallGBA::__dt +806d0ef8 Objects::HeyHoBallGBA::RequestShoot +806d0f04 0x806d0f04 +806d0f0c Objects::HeyHoBallGBA::LoadAnimations +806d0f58 Objects::HeyHoBallGBA::GetPropertiesBitfield +806d0f60 0x806d0f60 +806d0f68 Objects::HeyHoShipGBA::__ct +806d1004 Objects::MapObjShooter::__dt +806d1044 Objects::HeyHoShipGBA::OnStart +806d1208 Objects::HeyHoShipGBA::Update +806d1310 Objects::HeyHoShipGBA::GetShootFromRoutePointID +806d1330 0x806d1330 +806d137c 0x806d137c +806d1440 0x806d1440 +806d16a8 0x806d16a8 +806d1730 0x806d1730 +806d198c Objects::HeyHoShipGBA::__dt +806d19cc Objects::HeyHoShipGBA::GetPropertiesBitfield +806d19d4 Objects::HeyHoShipManager::__ct +806d1b80 Objects::HeyHoShipManager::__dt +806d1bfc Objects::HeyHoShipManager::OnStart +806d1ed4 Objects::HeyHoShipManager::Update +806d1f58 0x806d1f58 +806d1f5c Objects::MapObjSniper::LoadClipInfo +806d1f60 Objects::MapObjSniper::LoadCollision +806d1f64 Objects::MapObjSniper::LoadRoute +806d1f68 Objects::MapObjSniper::LoadModels +806d1f6c Objects::MapObjSniper::GetPropertiesBitfield +806d1f74 Objects::HighwayManager::__ct +806d2654 Objects::HighwayManager::__dt +806d2728 0x806d2728 +806d2998 Objects::HighwayManager::OnStart +806d2ab4 0x806d2ab4 +806d2ac8 Objects::HighwayManager::Update +806d2fb8 0x806d2fb8 +806d3308 0x806d3308 +806d34c8 0x806d34c8 +806d3688 0x806d3688 +806d39c8 0x806d39c8 +806d3d08 0x806d3d08 +806d3f9c 0x806d3f9c +806d4230 0x806d4230 +806d4384 0x806d4384 +806d44d8 0x806d44d8 +806d4520 0x806d4520 +806d4568 0x806d4568 +806d45b0 0x806d45b0 +806d45f8 0x806d45f8 +806d4640 0x806d4640 +806d4688 0x806d4688 +806d46d0 0x806d46d0 +806d4718 0x806d4718 +806d4834 0x806d4834 +806d494c 0x806d494c +806d4b28 0x806d4b28 +806d4c0c 0x806d4c0c +806d4c58 0x806d4c58 +806d4d6c 0x806d4d6c +806d4f30 0x806d4f30 +806d4f38 Objects::K_truck_light::LoadAnimations +806d4fc8 Objects::K_truck_light::LoadCollision +806d4fcc Objects::K_truck_light::LoadRoute +806d4fd0 Objects::K_truck_light::GetSubFileName +806d4fdc Objects::K_truck_light::GetBRRESName +806d4fe8 Objects::K_truck_light::GetPropertiesBitfield +806d4ff0 Objects::K_truck_light::GetID +806d4ff8 Objects::K_truck_light::__dt +806d5038 0x806d5038 +806d5040 Objects::K_car_light::LoadAnimations +806d50d0 Objects::K_car_light::LoadCollision +806d50d4 Objects::K_car_light::LoadRoute +806d50d8 Objects::K_car_light::GetSubFileName +806d50e4 Objects::K_car_light::GetBRRESName +806d50f0 Objects::K_car_light::GetPropertiesBitfield +806d50f8 Objects::K_car_light::GetID +806d5100 Objects::K_car_light::__dt +806d5140 0x806d5140 +806d5148 Objects::K_truck_tire::LoadAnimations +806d5194 Objects::K_truck_tire::LoadCollision +806d5198 Objects::K_truck_tire::LoadRoute +806d519c Objects::K_truck_tire::GetSubFileName +806d51a8 Objects::K_truck_tire::GetBRRESName +806d51b4 Objects::K_truck_tire::GetPropertiesBitfield +806d51bc Objects::K_truck_tire::GetID +806d51c4 Objects::K_truck_tire::__dt +806d5204 0x806d5204 +806d520c Objects::K_car_tire::LoadAnimations +806d5258 Objects::K_car_tire::LoadCollision +806d525c Objects::K_car_tire::LoadRoute +806d5260 Objects::K_car_tire::GetSubFileName +806d526c Objects::K_car_tire::GetBRRESName +806d5278 Objects::K_car_tire::GetPropertiesBitfield +806d5280 Objects::K_car_tire::GetID +806d5288 Objects::K_car_tire::__dt +806d52c8 Objects::HighwayManager::LoadClipInfo +806d52cc Objects::HighwayManager::LoadCollision +806d52d0 Objects::HighwayManager::LoadRoute +806d52d4 Objects::HighwayManager::LoadModels +806d52d8 Objects::HighwayManager::GetPropertiesBitfield +806d52e0 0x806d52e0 +806d53b8 0x806d53b8 +806d5504 0x806d5504 +806d5544 0x806d5544 +806d5548 0x806d5548 +806d5550 Objects::HighwayCar::__ct +806d5f1c Objects::HighwayCar::GetBRRESName +806d5f24 0x806d5f24 +806d5f88 Objects::HighwayCar::__dt +806d5ff4 Objects::HighwayCar::LoadModels +806d602c Objects::HighwayCar::GetCollisionDiameter +806d6180 Objects::HighwayCar::OnStart +806d6538 Objects::HighwayCar::Update +806d6994 Objects::HighwayCar::OnCollision +806d6dec Objects::HighwayCar::OnItemCollision +806d7164 Objects::HighwayCar::LoadCollision +806d7264 Objects::HighwayCar::UpdateCollision +806d7364 Objects::HighwayCar::GetSolidityCenter +806d73d0 0x806d73d0 +806d73d4 0x806d73d4 +806d73d8 0x806d73d8 +806d73dc 0x806d73dc +806d7474 0x806d7474 +806d7478 0x806d7478 +806d7510 0x806d7510 +806d75c4 0x806d75c4 +806d78e8 0x806d78e8 +806d81c8 0x806d81c8 +806d8454 0x806d8454 +806d866c 0x806d866c +806d8a14 0x806d8a14 +806d8a9c 0x806d8a9c +806d8b70 0x806d8b70 +806d8c0c 0x806d8c0c +806d8d4c 0x806d8d4c +806d8ea4 0x806d8ea4 +806d8f80 0x806d8f80 +806d8ff8 0x806d8ff8 +806d9070 0x806d9070 +806d90a8 0x806d90a8 +806d91e8 0x806d91e8 +806d92dc 0x806d92dc +806d9398 0x806d9398 +806d9408 0x806d9408 +806d95cc 0x806d95cc +806d9638 0x806d9638 +806d9b24 0x806d9b24 +806d9bf8 0x806d9bf8 +806d9ccc Objects::HighwayCar::ProcessCollision +806d9d94 Objects::HighwayCar::UpdateShadow +806d9e08 Objects::HighwayCar::GetShadowResName +806d9e10 Objects::HighwayCar::GetSubFileName +806d9e18 Objects::HighwayCar::GetPropertiesBitfield +806d9e20 0x806d9e20 +806d9e28 Objects::Kbomneji::LoadAnimations +806d9e6c Objects::Kbomneji::LoadCollision +806d9e70 Objects::Kbomneji::LoadRoute +806d9e74 Objects::Kbomneji::GetSubFileName +806d9e80 Objects::Kbomneji::GetPropertiesBitfield +806d9e88 Objects::Kbomneji::__dt +806d9ec8 0x806d9ec8 +806d9ed0 Objects::K_bomb_tire00::LoadAnimations +806d9f1c Objects::K_bomb_tire00::LoadCollision +806d9f20 Objects::K_bomb_tire00::LoadRoute +806d9f24 Objects::K_bomb_tire00::GetSubFileName +806d9f30 Objects::K_bomb_tire00::GetPropertiesBitfield +806d9f38 Objects::K_bomb_tire00::__dt +806d9f78 Objects::HighwayCar::__dt(thunk) +806d9f80 Objects::KoopaFigure64::__ct +806da0b0 Objects::KoopaFigure64::OnStart +806da1c8 Objects::KoopaFigure64::Update +806da57c Objects::KoopaFigure64::UpdateForCPURace +806da624 Objects::KoopaFigure64::UpdateCollision +806da780 Objects::KoopaFigure64::__dt +806da7c0 Objects::KoopaFigure64::LoadCollision +806da7d4 Objects::KoopaFigure64::OnCollision +806da7f0 Objects::Kuribo::__ct +806da9a8 0x806da9a8 +806daa0c Objects::Kuribo::__dt +806daa78 Objects::Kuribo::OnStart +806dac18 Objects::Kuribo::vf_0x10 +806dac1c Objects::Kuribo::Update +806dadd0 Objects::Kuribo::OnCollision +806db104 Objects::Kuribo::OnItemCollision +806db888 Objects::Kuribo::OnRouteEnd +806db88c Objects::Kuribo::UpdateRouteEnd +806dba60 Objects::Kuribo::OnCycleBegin +806dba64 Objects::Kuribo::UpdateCycle +806dbacc 0x806dbacc +806dbc4c 0x806dbc4c +806dbde8 0x806dbde8 +806dbdfc 0x806dbdfc +806dbfe4 0x806dbfe4 +806dc044 0x806dc044 +806dc1c4 0x806dc1c4 +806dc308 0x806dc308 +806dc3b4 0x806dc3b4 +806dc43c 0x806dc43c +806dc448 0x806dc448 +806dc644 0x806dc644 +806dc6a4 0x806dc6a4 +806dc794 0x806dc794 +806dc8dc Objects::Kuribo::vf_0xC(ObjectCycleManager) +806dc8e4 Objects::Kuribo::LoadAnimations +806dc934 0x806dc934 +806dc93c Objects::Kuribo::__dt(thunk) +806dc944 Objects::Balloon::__ct +806dcaac Objects::Balloon::__dt +806dcaec Objects::Balloon::OnStart +806dcc48 Objects::Balloon::vf_0x10 +806dcc4c Objects::Balloon::Update +806dce3c 0x806dce3c +806dcec4 Objects::Balloon::UpdateShadow +806dcf90 Objects::Balloon::GetShadowListIdx +806dcf98 Objects::Balloon::GetPropertiesBitfield +806dcfa0 0x806dcfa0 +806dd004 0x806dd004 +806dd044 0x806dd044 +806dd0c0 0x806dd0c0 +806dd0ec 0x806dd0ec +806dd0f0 Objects::MapObjSniper::__ct +806dd160 Objects::MapObjSniper::__dt +806dd1a0 Objects::MapObjSniper::OnStart +806dd2b0 Objects::MapObjSniper::Update +806dd31c 0x806dd31c +806dd38c 0x806dd38c +806dd40c 0x806dd40c +806dd428 0x806dd428 +806dd42c 0x806dd42c +806dd434 0x806dd434 +806dd438 0x806dd438 +806dd43c 0x806dd43c +806dd440 0x806dd440 +806dd444 Objects::SunDS::__ct +806dd570 0x806dd570 +806dd5d4 Objects::SunDS::__dt +806dd640 Objects::SunDS::OnStart +806dd6a8 Objects::SunDS::Update +806dd834 0x806dd834 +806dd850 0x806dd850 +806dda74 0x806dda74 +806ddac0 0x806ddac0 +806ddac4 0x806ddac4 +806ddb50 0x806ddb50 +806ddb7c 0x806ddb7c +806ddbd4 0x806ddbd4 +806ddc04 Objects::SunDS::GetShootFromRoutePointID +806ddc34 0x806ddc34 +806ddc3c Objects::SunDS::LoadAnimations +806ddc80 Objects::SunDS::GetPropertiesBitfield +806ddc88 Objects::SunDS::__dt(thunk) +806ddc90 Objects::SunDSManager::__ct +806dddec Objects::SunDSManager::__dt +806dde68 0x806dde68 +806ddf80 0x806ddf80 +806de01c 0x806de01c +806de088 0x806de088 +806de1ac Objects::TruckChimSmk::__ct +806de3a0 Objects::TruckChimSmk::__dt +806de3e0 Objects::TruckChimSmk::OnStart +806de578 Objects::TruckChimSmk::Update +806dea60 Objects::TruckChimSmk::OnCollision +806debc4 Objects::TruckChimSmk::OnItemCollision +806debf0 Objects::TruckChimSmk::UpdateCollision +806dece8 Objects::TruckChimSmk::vf_0x10 +806decec 0x806decec +806deddc Objects::TruckChimSmk::OnWallCollision +806dede0 Objects::TruckChimSmk::LoadAnimations +806dee2c 0x806dee2c +806dee34 Objects::TruckChimSmk::GetPropertiesBitfield +806dee3c Objects::TruckChimSmkW::__ct +806defb8 Objects::TruckChimSmkW::LoadModels +806defcc Objects::TruckChimSmkW::LoadAnimations +806df024 Objects::TruckChimSmkW::LoadCollision +806df038 Objects::TruckChimSmkW::GetSolidityCenter +806df0d0 Objects::TruckChimSmkW::OnStart +806df184 Objects::TruckChimSmkW::Update +806df338 Objects::TruckChimSmkW::__dt +806df378 Objects::TruckChimSmkW::GetScnObjDrawOptionsIdx +806df380 0x806df380 +806df400 0x806df400 +806df4a0 0x806df4a0 +806df4f0 0x806df4f0 +806df508 0x806df508 +806df6bc 0x806df6bc +806df6fc 0x806df6fc +806df760 0x806df760 +806df7cc 0x806df7cc +806df82c 0x806df82c +806dfa50 0x806dfa50 +806dfa54 0x806dfa54 +806dfcbc 0x806dfcbc +806dfea0 0x806dfea0 +806e019c 0x806e019c +806e03b4 0x806e03b4 +806e045c 0x806e045c +806e08b4 0x806e08b4 +806e093c 0x806e093c +806e09dc 0x806e09dc +806e0e60 0x806e0e60 +806e0f00 0x806e0f00 +806e0f04 0x806e0f04 +806e0fac 0x806e0fac +806e143c 0x806e143c +806e14a0 0x806e14a0 +806e158c 0x806e158c +806e15fc 0x806e15fc +806e16cc 0x806e16cc +806e16d8 ObjTruckWagon_construct +806e1858 0x806e1858 +806e1898 0x806e1898 +806e1a08 0x806e1a08 +806e1a0c 0x806e1a0c +806e1a10 0x806e1a10 +806e1af8 0x806e1af8 +806e1b48 0x806e1b48 +806e1b4c 0x806e1b4c +806e1b50 0x806e1b50 +806e1b54 0x806e1b54 +806e1b58 0x806e1b58 +806e1b60 0x806e1b60 +806e1b68 0x806e1b68 +806e1bd8 0x806e1bd8 +806e1be0 0x806e1be0 +806e1c70 obj_draw_shadow_init +806e1c74 0x806e1c74 +806e1c78 0x806e1c78 +806e1c84 0x806e1c84 +806e1c90 0x806e1c90 +806e1db0 0x806e1db0 +806e1db8 0x806e1db8 +806e1e10 0x806e1e10 +806e1e68 0x806e1e68 +806e1e70 0x806e1e70 +806e1ecc 0x806e1ecc +806e1ed8 0x806e1ed8 +806e1ee4 0x806e1ee4 +806e1ee8 0x806e1ee8 +806e1eec 0x806e1eec +806e1ef4 0x806e1ef4 +806e1f34 0x806e1f34 +806e1f3c 0x806e1f3c +806e1f40 0x806e1f40 +806e1f44 0x806e1f44 +806e1f50 0x806e1f50 +806e1f5c 0x806e1f5c +806e1f60 0x806e1f60 +806e1f68 0x806e1f68 +806e1f70 0x806e1f70 +806e21e8 0x806e21e8 +806e224c 0x806e224c +806e22b8 0x806e22b8 +806e235c 0x806e235c +806e23ec 0x806e23ec +806e2474 0x806e2474 +806e2590 0x806e2590 +806e25a0 0x806e25a0 +806e25a4 0x806e25a4 +806e26a0 0x806e26a0 +806e28e8 0x806e28e8 +806e2990 0x806e2990 +806e2ab8 0x806e2ab8 +806e2ac4 0x806e2ac4 +806e2eb8 0x806e2eb8 +806e2ef8 0x806e2ef8 +806e2f8c 0x806e2f8c +806e30d0 0x806e30d0 +806e30d4 0x806e30d4 +806e30d8 0x806e30d8 +806e30dc 0x806e30dc +806e30e0 0x806e30e0 +806e30e8 0x806e30e8 +806e30f0 0x806e30f0 +806e30f8 0x806e30f8 +806e31f8 0x806e31f8 +806e3234 0x806e3234 +806e344c 0x806e344c +806e348c Objects::Pile::OnStart +806e3548 Objects::Pile::Update +806e355c 0x806e355c +806e358c 0x806e358c +806e3810 Objects::Wanwan_Chn::LoadCollision +806e3874 Objects::Wanwan_Chn::Update +806e3884 0x806e3884 +806e388c Objects::Wanwan_Chn::UpdateCollision +806e3890 Objects::Wanwan::__ct +806e40d0 Objects::Wanwan_Chn::OnStart +806e40f4 0x806e40f4 +806e4158 Objects::Wanwan::__dt +806e4204 Objects::Wanwan::vf_0x10 +806e4208 Objects::Wanwan::OnStart +806e4598 Objects::Wanwan::Update +806e48d8 Objects::Wanwan::OnCollision +806e4ad8 Objects::Wanwan::OnItemCollision +806e4d30 0x806e4d30 +806e5028 0x806e5028 +806e50f8 0x806e50f8 +806e53dc 0x806e53dc +806e5548 0x806e5548 +806e5874 Objects::Wanwan::BeforeWanderB +806e5a10 Objects::Wanwan::WanderBUpdate +806e5d9c Objects::Wanwan::BeforeWanderA +806e5ea4 Objects::Wanwan::WanderAUpdate +806e61c4 Objects::Wanwan::BeforeLookUp +806e61e8 Objects::Wanwan::LookUpUpdate +806e62c0 Objects::Wanwan::BeforeDigDown +806e6304 Objects::Wanwan::DigDownUpdate +806e6440 Objects::Wanwan::BeforeLookStraight +806e6444 Objects::Wanwan::LookStraightUpdate +806e651c Objects::Wanwan::BeforeAttack +806e65d8 Objects::Wanwan::AttackUpdate +806e6a30 Objects::Wanwan::BeforeRetreat +806e6b00 Objects::Wanwan::RetreatUpdate +806e6c00 0x806e6c00 +806e6ca4 0x806e6ca4 +806e6f1c 0x806e6f1c +806e6fb8 0x806e6fb8 +806e7050 0x806e7050 +806e71e8 0x806e71e8 +806e7210 0x806e7210 +806e74a4 0x806e74a4 +806e7548 vector3_lerp +806e75d0 0x806e75d0 +806e767c 0x806e767c +806e7680 0x806e7680 +806e79ac 0x806e79ac +806e7af4 0x806e7af4 +806e7b8c 0x806e7b8c +806e7e34 0x806e7e34 +806e7fd8 0x806e7fd8 +806e80cc 0x806e80cc +806e85b8 0x806e85b8 +806e86f0 0x806e86f0 +806e8ad0 Objects::Wanwan::UpdateModelMatrix +806e8ad4 Objects::Wanwan::LoadAnimations +806e8b20 Objects::Wanwan::vf_0xC +806e8b28 Objects::Wanwan::GetPropertiesBitfield +806e8b30 Objects::Wanwan_Chn::GetCollisionDiameter +806e8b48 Objects::Wanwan_Chn::GetName +806e8b54 Objects::Wanwan_Chn::GetSubFileName +806e8b60 Objects::Wanwan_Chn::GetPropertiesBitfield +806e8b68 Objects::Wanwan_Chn::__dt +806e8ba8 Objects::Pile::GetName +806e8bb4 Objects::Pile::GetSubFileName +806e8bc0 Objects::Pile::GetBRRESName +806e8bcc Objects::Pile::GetPropertiesBitfield +806e8bd4 Objects::Pile::__dt +806e8c14 Objects::Wanwan::__dt +806e8c1c Objects::HwanwanBall::__ct +806e8d2c 0x806e8d2c +806e8d90 Objects::HwanwanBall::OnStart +806e90e4 Objects::HwanwanBall::Update +806e9318 Objects::HwanwanBall::OnCollision +806e93d8 Objects::HwanwanBall::OnItemCollision +806e9470 0x806e9470 +806e947c 0x806e947c +806e964c 0x806e964c +806e9650 0x806e9650 +806e98f4 0x806e98f4 +806e9968 0x806e9968 +806e9d30 0x806e9d30 +806e9df0 0x806e9df0 +806ea154 0x806ea154 +806ea2b8 0x806ea2b8 +806ea340 0x806ea340 +806ea714 0x806ea714 +806ea7f0 0x806ea7f0 +806eaacc 0x806eaacc +806eacbc 0x806eacbc +806eaed8 0x806eaed8 +806eb3c4 0x806eb3c4 +806eb4fc Objects::HwanwanBall::UpdateShadow +806eb5f8 0x806eb5f8 +806eb69c 0x806eb69c +806eb75c 0x806eb75c +806eb8ec 0x806eb8ec +806eb968 0x806eb968 +806ebab8 0x806ebab8 +806ebb8c 0x806ebb8c +806ebc54 0x806ebc54 +806ebd4c Objects::HwanwanBall::__dt +806ebdb8 Objects::HwanwanBall::UpdateModelMatrix +806ebdbc Objects::HwanwanBall::LoadAnimations +806ebe0c Objects::HwanwanBall::vf_0xc +806ebe14 Objects::HwanwanBall::LoadRoute +806ebe18 Objects::HwanwanBall::GetSubFileName +806ebe24 Objects::HwanwanBall::GetPropertiesBitfield +806ebe2c Objects::HwanwanBall::__dt(thunk) +806ebe34 Effects::Menus::__ct +806ebf80 Effects::Menus::__dt +806ec000 Effects::Menus::GetEffectByIdx +806ec010 Route::__ct(POTI) +806ec168 RoutePoint::__ct +806ec16c RoutePoint::__dt +806ec1ac Route::__ct(PointsArray) +806ec2ac Route::__dt +806ec32c Route::FillNormals +806ec4c8 Route::FillBLIGHTIndexes +806ec5f4 Route::UpdatePoints +806ec77c Route::AddPoint +806ec7bc Route::GetPointById +806ec7cc RouteController::__ct +806ec870 0x806ec870 +806ec8b8 RouteController::GetNormal +806ec920 RouteController::GetBLIGHTIndex +806ec978 RouteController::GetTotalDistance +806ec9b8 0x806ec9b8 +806eca50 0x806eca50 +806eca94 0x806eca94 +806ecba8 RouteController::__dt +806ecbe8 RouteCurved::__ct(POTI) +806ecd2c RouteArc::__ct +806ecd30 RouteArc::__ct +806ecd70 RouteCurved::__ct(PointsArray) +806ece94 RouteCurved::__dt +806ecf28 RouteCurved::Update +806ecfcc RouteCurved::UpdateTotalDistance +806ed070 RouteCurved::Init +806ed8e8 0x806ed8e8 +806eda74 0x806eda74 +806edb24 RouteCurved::Calc +806edbd8 0x806edbd8 +806edd98 0x806edd98 +806ede9c RouteCurvedController::__ct +806edf90 RouteCurvedController::Init +806ee144 RouteCurvedController::SetParams +806ee200 RouteCurvedController::UpdateSpeed +806ee258 RouteCurvedController::Update +806ee528 RouteCurvedController::vf_0x24 +806ee60c RouteCurvedController::vf_0x28 +806ee708 RouteCurvedController::GetDistanceToNextPoint +806ee744 RouteCurvedController::GetTotalPercent +806ee764 RouteCurvedController::GetTotalPercentNormalDir +806ee890 RouteCurvedController::CalculateBezier +806ee9bc RouteCurvedController::CalculateBezierCurve +806eeac0 RouteCurvedController::CalculateBezierDir +806eecb4 RouteController::IsAtRouteEnd +806eecd0 0x806eecd0 +806eee70 0x806eee70 +806eeedc 0x806eeedc +806eef5c 0x806eef5c +806eefa8 RouteCurvedController::GetSpeed +806eefb0 RouteCurvedController::__dt +806eeff0 RouteCurved::GetPercentFromOriginArrays +806eeff8 RouteCurved::GetPercent +806ef000 RouteCurved::GetPointsPerArc +806ef008 RouteCurved::GetArcArray +806ef010 RouteCurved::GetSegmentArray +806ef018 RouteCurved::GetTotalDistance +806ef020 RouteStraight::__ct(POTI) +806ef25c RouteSegment::__ct +806ef260 RouteSegment::__dt +806ef2a0 RouteStraight::__ct(PointsArray) +806ef3d8 RouteStraight::__dt +806ef430 RouteStraightController::__ct +806ef4bc RouteStraightController::SetParams +806ef518 RouteStraightController::Init +806ef660 RouteStraightController::UpdateSpeed +806ef6bc RouteStraightController::Update +806ef958 RouteStraightController::vf_0x24 +806efa88 RouteStraightController::vf_0x28 +806efb78 RouteStraightController::GetDistanceToNextPoint +806efbac 0x806efbac +806efc60 0x806efc60 +806efc7c 0x806efc7c +806efe80 0x806efe80 +806efeec 0x806efeec +806eff6c 0x806eff6c +806effb0 RouteStraightController::GetSpeed +806effb8 RouteStraightController::__dt +806efff8 RouteStraight::UpdateTotalDistance +806efffc RouteStraight::Update +806f0000 RouteStraight::GetPercentFromOriginArrays +806f0008 RouteStraight::GetPercent +806f0014 RouteStraight::GetPointsPerArc +806f001c RouteStraight::GetArcArray +806f0024 RouteStraight::GetSegmentArray +806f002c RouteStraight::GetTotalDistance +806f0034 RouteHolder::CreateInstance +806f00a8 RouteHolder::__ct +806f00b8 RouteHolder::DestroyInstance +806f0104 RouteHolder::__dt +806f0144 RouteHolder::Init +806f04c4 RouteHolder::CreateRoute +806f0634 RouteHolder::UpdateRoutePoints +806f06d0 RouteHolder::AddRoutePoint +806f0768 RouteHolder::GetRouteById +806f0778 0x806f0778 +806f07c0 0x806f07c0 +806f07c4 0x806f07c4 +806f0800 0x806f0800 +806f0890 0x806f0890 +806f0920 0x806f0920 +806f09a8 0x806f09a8 +806f0a68 0x806f0a68 +806f0b28 0x806f0b28 +806f0bd4 0x806f0bd4 +806f0c98 0x806f0c98 +806f0d58 0x806f0d58 +806f0ee4 0x806f0ee4 +806f1004 0x806f1004 +806f1064 0x806f1064 +806f10c0 0x806f10c0 +806f12c4 0x806f12c4 +806f1424 0x806f1424 +806f1580 0x806f1580 +806f16e0 0x806f16e0 +806f1878 0x806f1878 +806f1934 0x806f1934 +806f19ec 0x806f19ec +806f1aa8 0x806f1aa8 +806f1abc 0x806f1abc +806f1adc 0x806f1adc +806f1afc 0x806f1afc +806f1d9c 0x806f1d9c +806f1fb0 0x806f1fb0 +806f1fe4 0x806f1fe4 +806f20a4 0x806f20a4 +806f2418 0x806f2418 +806f24a0 0x806f24a0 +806f2654 Linked3DPoints::__ct +806f2860 Linked3DPoints::__dt +806f28f0 0x806f28f0 +806f29dc 0x806f29dc +806f2abc 0x806f2abc +806f3120 0x806f3120 +806f3354 0x806f3354 +806f33e4 0x806f33e4 +806f3598 0x806f3598 +806f3698 0x806f3698 +806f3764 0x806f3764 +806f37cc 0x806f37cc +806f39f0 0x806f39f0 +806f3a54 0x806f3a54 +806f3a98 0x806f3a98 +806f3b88 0x806f3b88 +806f3bcc 0x806f3bcc +806f3c10 0x806f3c10 +806f3c6c 0x806f3c6c +806f3c9c 0x806f3c9c +806f3d14 0x806f3d14 +806f3d58 0x806f3d58 +806f3d88 0x806f3d88 +806f3dec 0x806f3dec +806f3e1c 0x806f3e1c +806f3e40 0x806f3e40 +806f3e64 0x806f3e64 +806f3e88 0x806f3e88 +806f3eac 0x806f3eac +806f3ed0 0x806f3ed0 +806f3ef4 0x806f3ef4 +806f3f18 aramGetFirstUserAddress +806f3f3c 0x806f3f3c +806f3f78 0x806f3f78 +806f4020 0x806f4020 +806f4024 0x806f4024 +806f4028 0x806f4028 +806f4454 0x806f4454 +806f48fc 0x806f48fc +806f4988 0x806f4988 +806f4a24 0x806f4a24 +806f4aac 0x806f4aac +806f4c98 0x806f4c98 +806f4d40 0x806f4d40 +806f4f6c 0x806f4f6c +806f50f8 0x806f50f8 +806f515c 0x806f515c +806f525c 0x806f525c +806f52fc 0x806f52fc +806f533c 0x806f533c +806f53bc 0x806f53bc +806f56b0 0x806f56b0 +806f5730 0x806f5730 +806f579c 0x806f579c +806f5800 0x806f5800 +806f5968 0x806f5968 +806f5b18 0x806f5b18 +806f5c88 0x806f5c88 +806f5ea4 0x806f5ea4 +806f5fd8 Audio::Engine3D::Disposer__dt +806f6070 Audio::Engine3D::CreateInstance +806f6100 Audio::Engine3D::DestroyInstance +806f6134 Audio::Engine3D::SetCurSound +806f6140 0x806f6140 +806f61c8 0x806f61c8 +806f6258 0x806f6258 +806f62d4 Audio::Engine3D::__ct +806f6338 0x806f6338 +806f6378 0x806f6378 +806f63b8 Audio::Engine3D::__dt +806f6460 Audio::Engine3D::UpdateAmbientParam +806f6c74 Audio::Engine3D::GetRequiredVoiceOutCount +806f6c7c 0x806f6c7c +806f6d04 Audio::ItemWarning::GetPan +806f6d98 Audio::ItemWarning::__ct +806f6dac 0x806f6dac +806f6dec 0x806f6dec +806f6e40 Audio::ItemWarning::Init +806f6e94 Audio::ItemWarningMgr::PlayTargetedWarning +806f70c0 0x806f70c0 +806f7114 Audio::ItemWarningMgr::PlayUntargetedWarning +806f734c Audio::ItemWarningMgr::PlayWarningOnWiimote +806f73c4 Audio::ItemWarningMgr::Disposer__dt +806f7554 Audio::ItemWarningMgr::CreateInstance +806f75dc Audio::ItemWarning::__dt +806f7638 Audio::ItemWarningMgr::DestroyInstance +806f7718 Audio::ItemWarningMgr::__dt +806f77f4 Audio::ItemWarningMgr::Init +806f7870 Audio::ItemWarningMgr::Shutdown +806f787c Audio::ItemWarningMgr::GetItemWarning +806f788c Audio::SinglePlayer::CalcWaitTime +806f7b14 Audio::SinglePlayer::Disposer__dt +806f7cb4 Audio::SinglePlayer::CreateInstance +806f7d5c Audio::SinglePlayer::DestroyInstance +806f7ed8 Audio::SinglePlayer::__ct +806f7f54 Audio::Handle::__ct +806f7f60 Audio::Handle::__dt +806f7fa0 Audio::SinglePlayer::__dt +806f80d0 Audio::SinglePlayer::Calc +806f81e8 Audio::SinglePlayer::PlaySound +806f8404 Audio::Manager::PrepareSound +806f8438 Audio::SinglePlayer::PrepareSound +806f8544 0x806f8544 +806f86a0 Audio::SinglePlayer::PlayPreparedSound +806f8724 Audio::SinglePlayer::PreventActiveSoundStop +806f8730 Audio::SinglePlayer::StopSound +806f87a8 Audio::SinglePlayer::StartSound +806f89a8 Audio::SinglePlayer::SetupActiveHandle +806f8a74 Audio::SinglePlayer::SetupActiveHandle_switch +806f8a78 Audio::SinglePlayer::SetupActiveHandle_caseD_83 +806f8aa8 Audio::SinglePlayer::SetupActiveHandle_caseD_91 +806f8ac4 Audio::SinglePlayer::SetupActiveHandle_caseD_85 +806f8b04 Audio::SinglePlayer::SetupActiveHandle_caseD_7b +806f8b30 Audio::SinglePlayer::SetupActiveHandle_caseD_7d +806f8b4c 0x806f8b4c +806f8c44 Audio::SinglePlayer::StartActiveSound +806f8d04 Audio::SinglePlayer::GetFreeHandle +806f8d90 0x806f8d90 +806f8d94 Audio::SinglePlayer::GetFanfareLength +806f8f18 0x806f8f18 +806f8f6c Audio::SinglePlayer::StopInactiveSounds +806f8ffc Audio::SinglePlayerValuesMgr::Disposer__dt +806f9128 Audio::SinglePlayerValuesMgr::CreateInstance +806f91d0 Audio::SinglePlayerValuesMgr::DestroyInstance +806f9284 Audio::SinglePlayerValuesMgr::__dt +806f9328 Audio::SinglePlayerValuesMgr::SetHandle +806f934c Audio::SinglePlayerValuesMgr::Calc +806f9480 Audio::SinglePlayerValuesMgr::DetachHandle +806f948c Audio::SinglePlayerValuesMgr::UpdateTracks +806f94e4 Audio::SinglePlayerValuesMgr::SetVolume +806f9528 0x806f9528 +806f95ec Audio::StreamsMgr::Disposer_dt +806f9718 Audio::StreamsMgr::CreateInstance +806f97c0 Audio::StreamsMgr::DestroyInstance +806f9874 Audio::StreamsMgr::__dt +806f9918 Audio::StreamsMgr::PrepareStreams +806f9a68 Audio::StreamsMgr::ChangeStreamVolume +806f9a8c Audio::StreamsMgr::Calc +806f9c18 Audio::StreamsMgr::ResetVolume +806f9c70 Audio::SinglePlayer::PlayBGSound +806f9ce4 Audio::SinglePlayer::UpdateWaitTime +806f9d50 0x806f9d50 +806f9da4 Audio::SinglePlayer::CalcTitlePageNext +806fa120 Audio::StreamsMgr::ChangeMultipleStreamsVolume +806fa198 Audio::StreamsMgr::ChangeStream +806fa4cc Audio::EngineMgr::Init +806fa620 Audio::EngineMgr::Update +806fa968 Audio::EngineMgr::CalcSoundId +806faa00 0x806faa00 +806faab0 Audio::EngineMgr::CalcAccelerating +806fabc4 Audio::EngineMgr::CalcBraking +806facac Audio::EngineMgr::CalcPitch +806fad8c Audio::RaceAmbienceMgr::Disposer__dt +806faf24 Audio::RaceAmbienceMgr::CreateInstance +806fafd0 Audio::RaceAmbienceMgr::DestroyInstance +806fb11c Audio::RaceAmbienceMgr::__ct +806fb19c 0x806fb19c +806fb1dc Audio::RaceAmbienceMgr::__dt +806fb2fc Audio::RaceAmbienceMgr::Init +806fb330 Audio::RaceAmbienceMgr::StopGlobalSound +806fb348 Audio::RaceAmbienceMgr::Update +806fb480 Audio::RaceAmbienceMgr::StopGlobalSoundFadeOut +806fb49c Audio::RaceAmbienceMgr::PlayIntroAmbience +806fb52c Audio::RaceAmbienceMgr::PlayIntroAmbience_switch +806fb530 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_1 +806fb5d4 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_2 +806fb5fc Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_3 +806fb6d0 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_4 +806fb7ac Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_5 +806fb868 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_6 +806fb8e4 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_7 +806fb930 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_3a +806fb958 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_a +806fb9d4 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_b +806fba48 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_c +806fbab8 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_d +806fbb3c Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_e +806fbb88 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_f +806fbc0c Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_10 +806fbc94 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_11 +806fbccc Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_12 +806fbd70 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_13 +806fbe28 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_14 +806fbecc Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_16 +806fbf38 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_17 +806fbfcc Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_19 +806fc01c Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_1a +806fc048 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_1b +806fc098 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_1c +806fc0f8 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_1d +806fc19c Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_1e +806fc1c8 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_1f +806fc1f0 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_0 +806fc20c Audio::RaceAmbienceMgr::PlayGlobalSound +806fc3e0 Audio::RaceAmbienceMgr::StopGlobalSound(soundId) +806fc414 Audio::RaceAmbienceMgr::PlayAmbience +806fc568 Audio::RaceAmbienceMgr::SetAmbienceVolume +806fc60c Audio::RaceAmbienceMgr::SetAllAmbiencesVolume +806fc6a8 Audio::RaceAmbienceMgr::UpdateAmbiences +806fc718 Audio::RaceAmbienceMgr::UpdateVeniceAndRingMissionAmbiences +806fcbc8 0x806fcbc8 +806fcc90 Audio::Ambience::__ct +806fcd1c Audio::Ambience::__dt +806fcda8 Audio::Ambience::IsPlayingSoundId +806fcddc Audio::Ambience::PlayAmbience +806fce40 Audio::Ambience::ResetVolume +806fce6c Audio::Ambience::SetVolume +806fce84 Audio::Ambience::Update +806fd04c 0x806fd04c +806fd150 Audio::GameHeap::Disposer__dt +806fd288 Audio::GameHeap::CreateInstance +806fd358 Audio::GameHeap::DestroyInstance +806fd474 Audio::GameHeap::__ct +806fd518 Audio::GameHeapImpl::__dt +806fd584 Audio::GameHeap::__dt +806fd668 Audio::GameHeap::Initialize +806fd6b0 Audio::GameHeap::DestroySoundHeap +806fd6f0 Audio::GameHeap::SetType +806fd70c 0x806fd70c +806fd74c EGG::SoundHeapMgr::SaveState(using) +806fd820 EGG::SoundHeapMgr::LoadState(using) +806fd8ac EGG::SoundHeapMgr::GetCurrentLevel(using) +806fd900 0x806fd900 +806fd924 Audio::ReverbMgr::Disposer__dt +806fda50 Audio::ReverbMgr::CreateInstance +806fdb3c Audio::ReverbMgr::DestroyInstance +806fdbf0 Audio::ReverbMgr::__ct +806fdcc0 Audio::ReverbMgr::__dt +806fdd64 Audio::ReverbMgr::Disable +806fdd88 Audio::ReverbMgr::Clear +806fded8 0x806fded8 +806fdf18 Audio::ReverbMgr::Prepare +806fdfb0 Audio::ReverbMgr::Play +806fe028 Audio::ReverbMgr::Disable2 +806fe04c Audio::FileManager::__dt +806fe08c 0x806fe08c +806fe0cc 0x806fe0cc +806fe10c Audio::FileManager::Init +806fe238 0x806fe238 +806fe304 0x806fe304 +806fe4fc Audio::FileManager::LoadBank +806fe63c 0x806fe63c +806fe77c 0x806fe77c +806fe7e8 Audio::FileManager::IsBankLoaded +806fe870 0x806fe870 +806fe8f8 0x806fe8f8 +806feb38 0x806feb38 +806febe4 Audio::FileManager::InvalidateWaveData +806fec30 Audio::FileManager::InvalidateData +806fec7c Audio::FileManager::GetFileWaveDataAddress +806feca4 Audio::FileManager::GetFileAddress +806feccc Audio::FileManager::AudioFileManager +806fed1c Audio::FileManager::__dt(thunk) +806fed24 Audio::FileManager::InvalidateData(thunk) +806fed2c Audio::FileManager::InvalidateWaveData(thunk) +806fed34 Audio::FileManager::SetRequest +806feed0 0x806feed0 +806fef10 Audio::FileManager::LoadGroupAsync +806ff120 0x806ff120 +806ff218 Audio::GroupBankRequester::Disposer__dt +806ff344 Audio::GroupBankRequester::CreateInstance +806ff4ac Audio::GroupBankRequester::DestroyInstance +806ff560 Audio::GroupBankRequester::__ct +806ff69c Audio::GroupBankRequester::__dt +806ff740 Audio::GroupBankRequester::RequestLoad(id) +806ff778 Audio::GroupBankRequester::RequestLoad(actorId) +806ff7f0 0x806ff7f0 +806ff810 Audio::Manager::LoadState +806ff89c Audio::GroupBankRequester::ProcessRequests +806ff928 Audio::GroupBankRequester::LoadAsync +806ffaac Audio::GroupBankRequester::GroupBankLoader +806ffacc Audio::GroupBankRequester::ConstructRequests +806ffae0 Audio::GroupBankRequester::Request::__ct +806ffbe4 0x806ffbe4 +806ffc24 Audio::Actor<4>::__dt +806ffc98 0x806ffc98 +806ffd20 0x806ffd20 +806ffd94 Audio::RaceActor::SetupBRASD +806ffdc0 Audio::RaceActor::UpdateBRASDFrame +806ffe38 Audio::RaceActor::Update +806ffe80 Audio::Actor<4>::SetPosition +806ffe84 Audio::RaceActor::SetupSound +806fff00 ObjectSoundAnimNoHandle::__ct +80700028 Audio::RaceActor::__dt +807000ec ObjectSoundAnimNoHandle::Update +80700134 ObjectSoundAnimNoHandle::Link +807001a4 ObjectSoundAnimNoHandle::DisableConditional +807001ec Audio::RaceActor::DisableConditional +80700208 ObjectSoundAnimNoHandle::UpdateUserParam3 +80700228 Audio::RaceActor::UpdateUserParam3 +80700248 ObjectSoundAnimNoHandle::StartSoundLimited +807003b8 Audio::RaceActor::StartSoundLimited +80700514 ObjectSoundAnimNoHandle::HoldSoundLimited +80700684 Audio::RaceAnimActor::__ct +807007ac Audio::RaceAnimActor::StartSound +807007c0 Audio::RaceActor::StartSound +80700834 0x80700834 +8070084c Audio::RaceActor::StartSound(StartInfo) +807008cc Audio::RaceAnimActor::HoldSound +807008e0 0x807008e0 +80700954 0x80700954 +8070096c Audio::RaceActor::HoldSound +807009ec Audio::RaceAnimActor::StopSound +80700a00 Audio::RaceActor::StopSound +80700a04 Audio::RaceActor::HoldSound +80700a0c Audio::RaceActor::StartSound +80700a14 Audio::RaceActor::StartNewSoundLimited +80700b54 Audio::RaceActor::HoldSoundLimited +80700d68 Audio::RaceActor::StopAllSound +80700dcc Audio::RaceActor::GetPosition +80700dd4 Audio::RaceActor::UpdateUserParam +80700de8 Audio::RaceActor::UpdateUserParam2 +80700e00 Audio::RaceActor::detail_UpdateAmbientArg +80700e64 Audio::Actor<4>::TryStartSound(u32) +80700ef0 Audio::Actor<4>::TryStartSound(ul) +80700f7c Audio::Actor<4>::TryStartSound(str) +8070103c Audio::Actor<4>::TryStopAndStartSound(u32) +807010d0 Audio::Actor<4>::TryStopAndStartSound(ul) +80701164 Audio::Actor<4>::TryStopAndStartSound(str) +80701220 Audio::Actor<4>::TryHoldSound(u32) +80701308 Audio::Actor<4>::TryHoldSound(ul) +807013f0 Audio::Actor<4>::TryHoldSound(str) +8070150c Audio::Actor<4>::TryHoldSound(u32, handleId) +80701574 Audio::Actor<4>::TryHoldSound(u3l, handleId) +807015dc Audio::Actor<4>::TryHoldSound(str, handleId) +80701680 Audio::Actor<4>::TryPrepareSound(u32) +8070170c Audio::Actor<4>::TryPrepareSound(ul) +80701798 Audio::Actor<4>::TryPrepareSound(str) +80701858 Audio::Actor<4>::TryStopAndPrepareSound(u32) +807018ec Audio::Actor<4>::TryStopAndPrepareSound(ul) +80701980 Audio::Actor<4>::TryStopAndPrepareSound(str) +80701a3c ObjectSoundAnimNoHandle::__dt +80701b04 Audio::RaceAnimActor::__dt +80701bdc Audio::Actor::detail_UpdateAmbientArg +80701be4 0x80701be4 +80701bec 0x80701bec +80701bf4 Audio::RaceActor::__dt +80701bfc ObjectSoundAnimNoHandle::__dt +80701c04 ObjectSoundAnimNoHandle::HoldSoundLimited +80701c0c ObjectSoundAnimNoHandle::StartSoundLimited +80701c14 ObjectSoundAnimNoHandle::UpdateUserParam3 +80701c1c ObjectSoundAnimNoHandle::DisableConditional +80701c24 ObjectSoundAnimNoHandle::Update +80701c2c ObjectSoundAnimNoHandle::Link +80701c34 Audio::RaceActor::detail_UpdateAmbientArg +80701c3c 0x80701c3c +80701c44 Audio::RaceActor::UpdateBRASDFrame +80701c4c Audio::RaceActor::SetupBRASD +80701c54 Audio::RaceActor::HoldSound +80701c5c Audio::RaceActor::HoldSound(StartInfo) +80701c64 Audio::RaceActor::StartSound +80701c6c Audio::RaceActor::StartSound(StartInfo) +80701c74 Audio::RaceAnimActor::StopSound +80701c7c Audio::RaceAnimActor::HoldSound +80701c84 Audio::RaceAnimActor::StartSound +80701c8c Audio::RaceActor::StartNewSoundLimited +80701c94 Audio::RaceActor::StopAllSound +80701c9c Audio::RaceActor::HoldSoundLimited +80701ca4 Audio::RaceActor::StartSoundLimited +80701cac Audio::RaceActor::UpdateUserParam3 +80701cb4 Audio::RaceActor::DisableCondition +80701cbc Audio::RaceActor::UpdateUserParam2 +80701cc4 Audio::RaceActor::UpdateUserParam +80701ccc Audio::RaceActor::Reset +80701cd4 Audio::RaceActor::GetPosition +80701cdc Audio::RaceActor::Update +80701ce4 Audio::LinkedRaceActor::__ct +80701d38 Audio::LinkedRaceActor::__dt +80701d80 Audio::LinkedRaceActor::Link +80701e3c Audio::LinkedRaceActor::Unlink +80701e94 0x80701e94 +80701eb4 0x80701eb4 +80701f50 Audio::LinkedRaceActor::CannotPlaySounds +80701fd8 0x80701fd8 +80701fdc Audio::LinkedRaceActor::Toggle +80702038 Audio::LinkedRaceActor::GetKartPosition +80702040 Audio::LinkedRaceActor::GetObjectPosition +8070204c Audio::LinkedRaceActor::SetSoundParams +8070205c Audio::ObjectActorAnim::__ct +807020b0 0x807020b0 +807020f0 Audio::ObjectActorAnim::Link +80702160 Audio::ObjectActorAnim::Unlink +80702168 Audio::ObjectActorAnim::Update +8070216c Audio::ObjectActorAnim::StartSoundLimited +80702710 Audio::ObjectActorAnim::HoldSoundLimited +80702b30 Audio::ObjectActorAnim::StartNewSoundLimited +80702d38 Audio::ObjectActorAnim::StartSound +80703134 Audio::ObjectActorAnim::SetupSound +807033d0 Audio::ObjectActorAnim::DisableConditional +8070356c Audio::ObjectActorAnim::UpdateUserParam3 +8070361c Audio::ObjectActorAnim::__dt +807036f8 Audio::ObjectActorAnim::__dt(thunk) +80703700 Audio::ObjectActorAnim::StartSound(thunk) +80703708 Audio::ObjectActorAnim::StartNewSoundLimited(thunk) +80703710 Audio::ObjectActorAnim::HoldSoundLimited(thunk) +80703718 Audio::ObjectActorAnim::StartSoundLimited(thunk) +80703720 Audio::ObjectActorAnim::UpdateUserParam3(thunk) +80703728 Audio::ObjectActorAnim::DisableConditional(thunk) +80703730 Audio::ObjectActorAnim::Update(thunk) +80703738 Audio::ObjectActorAnim::Unlink(thunk) +80703740 Audio::ObjectActorAnim::Link(thunk) +80703748 Audio::ItemActor::__ct +807037f0 0x807037f0 +80703830 Audio::Actor<2>::__dt +807038a4 0x807038a4 +8070392c Audio::ItemActor::Link +80703934 Audio::ItemActor::Unlink +8070393c Audio::ItemActor::Update +80703954 Audio::Actor<2>::SetPosition +80703958 Audio::ItemActor::DisableConditional +80703974 0x80703974 +80703990 Audio::ItemActor::UpdateUserParam3 +807039b0 0x807039b0 +807039d0 Audio::ItemActor::StartSoundLimited +80703c00 0x80703c00 +80703d0c Audio::ItemActor::HoldSoundLimited +80703e98 0x80703e98 +80704004 Audio::ItemActor::StartNewSoundLimited +80704100 0x80704100 +807041e8 0x807041e8 +80704240 Audio::GessoActor::__ct +807042e8 0x807042e8 +8070435c 0x8070435c +807043e4 Audio::GessoActor::Link +807043ec Audio::GessoActor::Update +807043f0 0x807043f0 +80704400 0x80704400 +80704404 Audio::GessoActor::StartSoundLimited +807044fc 0x807044fc +807045e0 Audio::GessoActor::SetupBRASD +807045e4 Audio::GessoActor::UpdateBRASDFrame +807045e8 Audio::ItemActor::SetupBRASD +807045ec Audio::ItemActor::UpdateBRASD +807045f0 Audio::GessoActor::StartNewSoundLimited +807046ac Audio::GessoActor::HoldSoundLimited +807047c4 Audio::GessoActor::StopAllSound +807047d8 Audio::GessoActor::StartSound +8070484c Audio::GessoActor::StartSound(StartInfo) +807048cc Audio::GessoActor::HoldSound +80704940 Audio::GessoActor::HoldSound(StartInfo) +807049c0 Audio::GessoActor::Reset +80704a00 Audio::GessoActor::GetPosition +80704a08 Audio::GessoActor::UpdateUserParam +80704a1c Audio::GessoActor::UpdateUserParam2 +80704a34 Audio::GessoActor::DisableConditional +80704a50 Audio::GessoActor::UpdateUserPar +80704a70 Audio::GessoActor::detail_UpdateAmbientArg +80704ad4 Audio::ItemActor::StopAllSound +80704b38 Audio::ItemActor::StartSound +80704bac Audio::ItemActor::StartSound(StartInfo) +80704c2c Audio::ItemActor::HoldSound +80704ca0 Audio::ItemActor::HoldSound(StartInfo) +80704d20 Audio::ItemActor::Reset +80704d60 Audio::ItemActor::GetPosition +80704d68 Audio::ItemActor::UpdateUserParam +80704d7c Audio::ItemActor::UpdateUserParam2 +80704d94 Audio::ItemActor::detail_UpdateAmbientArg +80704df8 0x80704df8 +80704e84 0x80704e84 +80704f10 0x80704f10 +80704fd0 0x80704fd0 +80705064 0x80705064 +807050f8 0x807050f8 +807051b4 0x807051b4 +8070529c 0x8070529c +80705384 0x80705384 +807054a0 0x807054a0 +80705508 0x80705508 +80705570 0x80705570 +80705614 0x80705614 +807056a0 0x807056a0 +8070572c 0x8070572c +807057ec 0x807057ec +80705880 0x80705880 +80705914 0x80705914 +807059d0 Audio::Actor<2>::TryStartSound(u32) +80705a5c Audio::Actor<2>::TryStartSound(ul) +80705ae8 Audio::Actor<2>::TryStartSound(str) +80705ba8 Audio::Actor<2>::TryStopAndStartSound(u32) +80705c3c Audio::Actor<2>::TryStopAndStartSound(ul) +80705cd0 Audio::Actor<2>::TryStopAndStartSound(str) +80705d8c Audio::Actor<2>::TryHoldSound(u32) +80705e74 Audio::Actor<2>::TryHoldSound(ul) +80705f5c Audio::Actor<2>::TryHoldSound(str) +80706078 Audio::Actor<2>::TryHoldSound(u32, handleId) +807060e0 Audio::Actor<2>::TryHoldSound(ul, handleId) +80706148 Audio::Actor<2>::TryHoldSound(str, handleId) +807061ec Audio::Actor<2>::TryPrepareSound(u32) +80706278 Audio::Actor<2>::TryPrepareSound(ul) +80706304 Audio::Actor<2>::TryPrepareSound(str) +807063c4 Audio::Actor<2>::TryStopAndPrepareSound(u32) +80706458 Audio::Actor<2>::TryStopAndPrepareSound(ul) +807064ec Audio::Actor<2>::TryStopAndPrepareSound(str) +807065a8 Audio::ItemActor::__dt +80706634 Audio::GessoActor::__dt +807066c0 0x807066c0 +807066c8 0x807066c8 +807066d0 0x807066d0 +807066d8 0x807066d8 +807066e0 0x807066e0 +807066e8 0x807066e8 +807066f0 0x807066f0 +807066f8 Audio::ItemActor::detail_UpdateAmbientArg(thunk) +80706700 Audio::ItemActor::__dt(thunk) +80706708 Audio::ItemActor::UpdateBRASDFrame(thunk) +80706710 Audio::ItemActor::SetupBRASD(thunk) +80706718 Audio::ItemActor::HoldSound(thunk) +80706720 Audio::ItemActor::HoldSound(StartInfo)(thunk) +80706728 Audio::ItemActor::StartSound(thunk) +80706730 Audio::ItemActor::StartSound(StartInfo)(thunk) +80706738 Audio::ItemActor::StartNewSoundLimited(thunk) +80706740 Audio::ItemActor::StopAllSound(thunk) +80706748 Audio::ItemActor::HoldSoundLimited(thunk) +80706750 Audio::ItemActor::StartSoundLimited(thunk) +80706758 Audio::ItemActor::UpdateUserParam3(thunk) +80706760 Audio::ItemActor::DisableConditional(thunk) +80706768 Audio::ItemActor::UpdateUserParam2(thunk) +80706770 Audio::ItemActor::UpdateUserParam(thunk) +80706778 Audio::ItemActor::Reset(thunk) +80706780 Audio::ItemActor::GetPosition(thunk) +80706788 Audio::ItemActor::Update(thunk) +80706790 Audio::ItemActor::Unlink(thunk) +80706798 Audio::ItemActor::Link(thunk) +807067a0 0x807067a0 +807067a8 0x807067a8 +807067b0 0x807067b0 +807067b8 Audio::GessoActor::detail_UpdateAmbientArg(thunk) +807067c0 Audio::GessoActor::__dt(thunk) +807067c8 Audio::GessoActor::UpdateBRASDFrame(thunk) +807067d0 Audio::GessoActor::SetupBRASD(thunk) +807067d8 Audio::GessoActor::HoldSound(thunk) +807067e0 Audio::GessoActor::HoldSound(StartInfo)(thunk) +807067e8 Audio::GessoActor::StartSound(thunk) +807067f0 Audio::GessoActor::StartSound(StartInfo)(thunk) +807067f8 Audio::GessoActor::StartNewSoundLimited(thunk) +80706800 Audio::GessoActor::StopAllSound(thunk) +80706808 Audio::GessoActor::HoldSoundLimited(thunk) +80706810 Audio::GessoActor::StartSoundLimited(thunk) +80706818 Audio::GessoActor::UpdateUserParam3(thunk) +80706820 Audio::GessoActor::DisableConditional(thunk) +80706828 Audio::GessoActor::UpdateUserParam2(thunk) +80706830 Audio::GessoActor::UpdateUserParam(thunk) +80706838 Audio::GessoActor::Reset(thunk) +80706840 Audio::GessoActor::GetPosition(thunk) +80706848 Audio::GessoActor::Update(thunk) +80706850 Audio::GessoActor::Link(thunk) +80706858 0x80706858 +80706898 Audio::KartActor::__ct +807069cc Audio::SimpleRaceActor::__dt +80706a58 Audio::KartActor::__dt +80706b1c Audio::KartActor::SetActorType +80706b3c Audio::KartActor::DisableConditional +80706b80 Audio::KartActor::UpdateUserParam3 +80706ba0 Audio::KartActor::Link +80706cb4 Audio::KartActor::Unlink +80706d3c Audio::KartActor::Update +807074b0 0x807074b0 +807075e8 Audio::KartActor::StopAllSound +807076a8 Audio::KartActor::SetupSound +807076ac Audio::KartActor::HoldSoundLimited +80707944 Audio::KartActor::StartSoundLimited +8070818c Audio::KartActor::OutputSoundToWiimotes +807081b0 Audio::KartActor::ApplyKCLSoundTrigger +80708218 Audio::KartActor::PlayBoostSound +807083b4 Audio::KartActor::PlayRampSound +80708550 0x80708550 +807087bc Audio::KartActor::PlayCannonSound +80708818 Audio::KartActor::PlayHornSound +80708920 Audio::KartActor::StartSound +807089a4 Audio::KartActor::HoldSound +80708a30 Audio::KartActor::PlayMTSounds +80708c7c Audio::KartActor::PlayRoadSound +80708e90 0x80708e90 +80708f44 0x80708f44 +80708fec Audio::KartActor::StartNewSoundLimited +80709174 Audio::KartActor::OnObjectNormalCollision +80709310 Audio::KartActor::OnObjectWallCollision +80709464 Audio::KartActor::PlayObjectCollisionSounds +8070a638 Audio::KartActor::PlayWallCollisionSound +8070a708 Audio::KartActor::PlayBushCollisionSound +8070a768 0x8070a768 +8070a814 0x8070a814 +8070a83c 0x8070a83c +8070a8bc Audio::KartActor::UpdateLapSounds +8070aafc Audio::KartActor::UpdateKCLValues +8070ae84 0x8070ae84 +8070af48 Audio::KartActor::SetRoadState +8070af5c Audio::KartActor::GetDriftAndSSMTRoadSoundId +8070afc0 Audio::KartActor::GetDriftAndSSMTRoadSoundId_switch +8070afc4 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_16 +8070afd8 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_15 +8070afe4 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_13 +8070aff8 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_b +8070b00c Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_5 +8070b020 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_4 +8070b034 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_3 +8070b048 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_2 +8070b05c Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_1 +8070b070 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_0 +8070b080 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_17 +8070b094 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_1d +8070b0a4 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_10 +8070b0ac Audio::KartActor::GetLandingSoundId +8070b0ec Audio::KartActor::GetLandingSoundId_switch +8070b0f0 Audio::KartActor::GetLandingSoundId_caseD_16 +8070b104 Audio::KartActor::GetLandingSoundId_caseD_15 +8070b110 Audio::KartActor::GetLandingSoundId_caseD_13 +8070b124 Audio::KartActor::GetLandingSoundId_caseD_b +8070b138 Audio::KartActor::GetLandingSoundId_caseD_5 +8070b14c Audio::KartActor::GetLandingSoundId_caseD_4 +8070b160 Audio::KartActor::GetLandingSoundId_caseD_3 +8070b174 Audio::KartActor::GetLandingSoundId_caseD_2 +8070b188 Audio::KartActor::GetLandingSoundId_caseD_1 +8070b19c Audio::KartActor::GetLandingSoundId_caseD_0 +8070b1ac Audio::KartActor::GetLandingSoundId_caseD_17 +8070b1c0 Audio::KartActor::GetLandingSoundId_caseD_1d +8070b1d0 Audio::KartActor::GetLandingSoundId_caseD_10 +8070b1d8 Audio::KartActor::GetRoadSoundId +8070b240 Audio::KartActor::GetRoadSoundId_caseD_16 +8070b254 Audio::KartActor::GetRoadSoundId_caseD_15 +8070b260 Audio::KartActor::GetRoadSoundId_caseD_13 +8070b274 Audio::KartActor::GetRoadSoundId_caseD_b +8070b288 Audio::KartActor::GetRoadSoundId_caseD_5 +8070b29c Audio::KartActor::GetRoadSoundId_caseD_4 +8070b2b0 Audio::KartActor::GetRoadSoundId_caseD_3 +8070b2c4 Audio::KartActor::GetRoadSoundId_caseD_2 +8070b2d8 Audio::KartActor::GetRoadSoundId_caseD_1 +8070b2ec Audio::KartActor::GetRoadSoundId_caseD_0 +8070b2fc Audio::KartActor::GetRoadSoundId_caseD_17 +8070b310 Audio::KartActor::GetRoadSoundId_caseD_1d +8070b320 Audio::KartActor::GetRoadSoundId_caseD_10 +8070b328 Audio::KartActor::GetBrakingSoundId +8070b390 Audio::KartActor::GetBrakingSoundId_caseD_16 +8070b3a4 Audio::KartActor::GetBrakingSoundId_caseD_15 +8070b3b0 Audio::KartActor::GetBrakingSoundId_caseD_13 +8070b3c4 Audio::KartActor::GetBrakingSoundId_caseD_b +8070b3d8 Audio::KartActor::GetBrakingSoundId_caseD_5 +8070b3ec Audio::KartActor::GetBrakingSoundId_caseD_4 +8070b400 Audio::KartActor::GetBrakingSoundId_caseD_3 +8070b414 Audio::KartActor::GetBrakingSoundId_caseD_2 +8070b428 Audio::KartActor::GetBrakingSoundId_caseD_1 +8070b43c Audio::KartActor::GetBrakingSoundId_caseD_0 +8070b44c Audio::KartActor::GetBrakingSoundId_caseD_17 +8070b460 Audio::KartActor::GetBrakingSoundId_caseD_1d +8070b470 Audio::KartActor::GetBrakingSoundId_caseD_10 +8070b478 Audio::KartActor::SetNonLocalVolumeAndPriority +8070bad4 0x8070bad4 +8070bbd0 Audio::KartActor::PlayEngineSound +8070bdc4 Audio::KartActor::SetPitch +8070bed4 0x8070bed4 +8070bf1c 0x8070bf1c +8070bf50 Audio::KartActor::PlayOtherKartCollisionSound +8070bff4 0x8070bff4 +8070c074 Audio::SimpleRaceActor::SetupBRASD +8070c078 Audio::SimpleRaceActor::UpdateBRASDFrame +8070c07c 0x8070c07c +8070c080 Audio::SimpleRaceActor::__dt(thunk) +8070c088 Audio::KartActor::__dt(thunk) +8070c090 Audio::SimpleRaceActor::UpdateBRASDFrame(thunk) +8070c098 Audio::SimpleRaceActor::SetupBRASD(thunk) +8070c0a0 Audio::KartActor::HoldSound(thunk) +8070c0a8 Audio::KartActor::StartSound(thunk) +8070c0b0 Audio::KartActor::StartNewSoundLimited(thunk) +8070c0b8 Audio::KartActor::StopAllSound(thunk) +8070c0c0 Audio::KartActor::HoldSoundLimited(thunk) +8070c0c8 Audio::KartActor::StartSoundLimited(thunk) +8070c0d0 Audio::KartActor::UpdateUserParam3(thunk) +8070c0d8 Audio::KartActor::DisableConditional(thunk) +8070c0e0 Audio::KartActor::Update(thunk) +8070c0e8 Audio::KartActor::Unlink(thunk) +8070c0f0 Audio::KartActor::Link(thunk) +8070c0f8 Audio::ObjectActor::__ct +8070c1a4 0x8070c1a4 +8070c1e4 Audio::ObjectActor::__dt +8070c274 Audio::ObjectActor::Update +8070c39c Audio::ObjectActor::Unlink +8070c3a4 Audio::ObjectActor::Link +8070c414 0x8070c414 +8070c46c Audio::ObjectActor::StartNewSoundLimited +8070cfe4 Audio::ObjectActor::HoldSoundLimited +8070d2f8 Audio::ObjectActor::StartSoundLimited +8070d4b4 0x8070d4b4 +8070d7f4 Audio::ObjectActor::DisableConditional +8070dc5c Audio::ObjectActor::UpdateUserParam3 +8070dce0 Audio::ObjectActor::SetupSound +8070dd98 0x8070dd98 +8070dddc Audio::ObjectActor::__dt(thunk) +8070dde4 Audio::ObjectActor::StartNew(thunk) +8070ddec Audio::ObjectActor::HoldSoundLimited(thunk) +8070ddf4 Audio::ObjectActor::StartSoundLimited(thunk) +8070ddfc Audio::ObjectActor::UpdateUserParam3(thunk) +8070de04 Audio::ObjectActor::DisableConditional(thunk) +8070de0c Audio::ObjectActor::Update(thunk) +8070de14 Audio::ObjectActor::Unlink(thunk) +8070de1c Audio::ObjectActor::Link(thunk) +8070de24 0x8070de24 +8070dee0 0x8070dee0 +8070df20 0x8070df20 +8070dfac 0x8070dfac +8070e090 0x8070e090 +8070e19c 0x8070e19c +8070e1a4 0x8070e1a4 +8070e2fc 0x8070e2fc +8070e338 0x8070e338 +8070e33c 0x8070e33c +8070e378 0x8070e378 +8070e388 0x8070e388 +8070e398 0x8070e398 +8070e3c8 0x8070e3c8 +8070e404 0x8070e404 +8070e424 0x8070e424 +8070e434 0x8070e434 +8070e454 0x8070e454 +8070e4e4 0x8070e4e4 +8070e4e8 0x8070e4e8 +8070e4ec 0x8070e4ec +8070e4f4 0x8070e4f4 +8070e4fc 0x8070e4fc +8070e504 0x8070e504 +8070e50c 0x8070e50c +8070e514 0x8070e514 +8070e51c 0x8070e51c +8070e524 0x8070e524 +8070e52c 0x8070e52c +8070e534 Audio::PlayersVolumeMgr::Disposer__dt +8070e660 Audio::PlayersVolumeMgr::CreateInstance +8070e754 Audio::PlayersVolumeMgr::DestroyInstance +8070e808 Audio::PlayersVolumeMgr::__dt +8070e8ac 0x8070e8ac +8070e974 0x8070e974 +8070ea24 0x8070ea24 +8070ea3c 0x8070ea3c +8070ea54 Audio::PlayersVolumeMgr::Calc +8070eadc Audio::PlayersVolumeMgr::StopAllPlayersButTrackUI +8070eb3c Audio::PlayersVolumeMgr::MuteAllButTrackUI +8070ebc0 Audio::PlayersVolumeMgr::ResetAllButUI +8070ec08 Audio::PlayersVolumeMgr::Reset +8070ecb4 Audio::PlayersVolumeMgr::PauseAllButTrackUI +8070ed24 Audio::PlayersVolumeMgr::SetVolume +8070ee10 0x8070ee10 +8070eec8 0x8070eec8 +8070eee8 0x8070eee8 +8070ef24 Audio::ItemAlterationMgr::Disposer__dt +8070f074 Audio::ItemAlterationMgr::CreateInstance +8070f0e8 0x8070f0e8 +8070f128 Audio::ItemAlterationMgr::DestroyInstance +8070f22c Audio::ItemAlterationMgr::__dt +8070f304 Audio::ItemAlterationMgr::Init +8070f35c Audio::ItemAlterationMgr::IsDemo +8070f37c Audio::ItemAlterationMgr::Update +8070f51c Audio::ItemAlterationMgr::ResetItemState +8070f534 Audio::ItemAlterationMgr::UpdateStatus +8070f6e8 Audio::ItemAlterationMgr::SetAudioAlteration +8070f860 Audio::ItemAlterationMgr::GetCourseSoundId +8070f880 Audio::ItemAlterationMgr::CalcStatus2Values +8070f91c Audio::ItemAlterationMgr::PlayStarMusic +8070f974 Audio::ItemAlterationMgr::PlayMegaMusic +8070f9ac Audio::RaceMgr::Disposer__dt +8070fb3c Audio::RaceMgr::CreateInstance +8070fb8c Audio::RaceMgr::DestroyInstance +8070fcd0 Audio::RaceMgr::ActorHolder::Compare +8070fcf4 Audio::RaceMgr::__ct +8070ff14 0x8070ff14 +8070ff54 Audio::RaceMgr::__dt +8071006c Audio::RaceMgr::Init +80710218 Audio::RaceMgr::Shutdown +8071030c Audio::RaceMgr::Calc +8071070c 0x8071070c +80710804 Audio::RaceMgr::UpdatePlayerMatrix +80710968 0x80710968 +807109fc 0x807109fc +80710a84 Audio::RaceMgr::StartRace +80710b10 Audio::RaceMgr::UpdateActors +80710b80 Audio::RaceMgr::UpdateLocalPlayerParams +80710cd4 Audio::RaceMgr::IsAPlayerSquishedOrSmall +80710d98 Audio::RaceMgr::IsAPlayerInStar +80710e0c Audio::RaceMgr::IsAPlayerInMega +80710e80 0x80710e80 +80710ec8 0x80710ec8 +80710fcc Audio::RaceMgr::SetNonTrackVolumes +80711078 Audio::RaceMgr::SetEngineVolume +80711080 Audio::RaceMgr::SetNonTrackAndEngineVolume +80711130 Audio::RaceMgr::SetRaceState +8071182c 0x8071182c +807118a0 0x807118a0 +807118a4 0x807118a4 +807118b8 0x807118b8 +807118cc 0x807118cc +807118ec 0x807118ec +807119ec 0x807119ec +80711a0c 0x80711a0c +80711ab8 0x80711ab8 +80711b14 0x80711b14 +80711bac 0x80711bac +80711c40 Audio::RaceMgr::CheckRaceState +80712148 0x80712148 +807121c4 Audio::RaceMgr::SortAndToggleActors +80712dc0 Audio::RaceMgr::SetKartSound +80712e14 0x80712e14 +80712e58 0x80712e58 +80712e60 0x80712e60 +80712efc 0x80712efc +80712f3c 0x80712f3c +80713068 0x80713068 +807130d0 0x807130d0 +80713184 0x80713184 +80713228 0x80713228 +80713230 0x80713230 +807132ec Audio::RSARPlayer::OutputSoundToWiimotes +807133d0 0x807133d0 +80713438 Audio::RSARPlayer::IsDemo +80713454 0x80713454 +8071347c 0x8071347c +807134fc Audio::RSARPlayer::CreateInstance +80713720 Audio::RSARPlayer::DestroyInstance +80713798 Audio::RSARPlayer::Close +807137f0 Audio::RSARPlayer::OnLoad +807137fc Audio::RSARPlayer::Stop +80713858 Audio::RSARPlayer::HasFinishedLoadingGroups +80713864 Audio::RSARPlayer::Calc +807139dc Audio::RSARPlayer::OnNewPageLayer +807139e0 Audio::MenuRSARPlayer::OnNewPageLayer +80713c04 0x80713c04 +80713cfc 0x80713cfc +80713d08 0x80713d08 +80713d14 Audio::RSARPlayer::PlaySoundById +80713dd8 Audio::RSARPlayer::HoldSoundById +80713e3c 0x80713e3c +80713fa8 0x80713fa8 +80713fe8 Audio::RSARPlayer::PlaySound +80714c50 Audio::RSARPlayer::StopSoundById +80714c90 Audio::RSARPlayer::HoldSound +80714cb4 0x80714cb4 +80714d60 0x80714d60 +80714f4c 0x80714f4c +80714ff4 0x80714ff4 +807150b8 0x807150b8 +807150dc Audio::RSARPlayer::PrepareReverb +807150e0 Audio::RSARPlayer::Reset +80715104 Audio::MenuRSARPlayer::__ct +80715138 Audio::MenuRSARPlayer::Prepare +807151e8 Audio::MenuRSARPlayer::Close +80715240 Audio::MenuRSARPlayer::OnLoad +807152a8 Audio::MenuRSARPlayer::Stop +80715304 Audio::MenuRSARPlayer::PrepareReverb +80715410 Audio::RaceRSARPlayer::__ct +80715490 Audio::RaceRSARPlayer::OnLoad +807154d0 Audio::RaceRSARPlayer::Stop +80715538 Audio::RaceRSARPlayer::Pause +807155cc Audio::RaceRSARPlayer::Resume +8071565c Audio::RaceRSARPlayer::PlayEndRaceMenuButtonClickSound +80715674 Audio::RaceRSARPlayer::SetFullVolume +80715684 Audio::RaceRSARPlayer::HalveVolume +80715694 Audio::RaceRSARPlayer::Prepare +807157dc Audio::RaceRSARPlayer::LoadCharacterGroups +80715920 Audio::RaceRSARPlayer::PrepareReverb +80715a70 Audio::RaceRSARPlayer::Close +80715ad8 Audio::RaceRSARPlayer::Calc +80715c74 Audio::RaceRSARPlayer::PlaySound +80715de8 Audio::RaceRSARPlayer::HoldSound +80715e24 Audio::TestRSARPlayer::__ct +80715e58 Audio::TestRSARPlayer::Prepare +80715e88 Audio::TestRSARPlayer::Close +80715ee0 Audio::TestRSARPlayer::OnDeactivate +80715eec Audio::GlobeRSARPlayer::__ct +80715f28 Audio::RSARPlayer::__dt +80715fac Audio::GlobeRSARPlayer::OnDeactivate +80715ff8 Audio::GlobeRSARPlayer::Prepare +8071608c Audio::GlobeRSARPlayer::Calc +80716204 Audio::GlobeRSARPlayer::PrepareReverb +80716310 Audio::GlobeRSARPlayer::Close +80716368 0x80716368 +807163d4 Audio::Manager::OpenBRSAR +80716400 Audio::Manager::Disposer__dt +80716498 Audio::Manager::CreateInstance +8071657c Audio::Manager::DestroyInstance +807165b0 Audio::Manager::__ct +80716670 Audio::Manager::__dt +80716770 Audio::Manager::DestroyAudioInstances +807167bc Audio::Manager::Init +807168b8 Audio::Manager::InitSelf +80716a90 0x80716a90 +80716b0c 0x80716b0c +80716b4c 0x80716b4c +80716b8c Audio::Manager::CreateAudioInstances +80716c0c Audio::Manager::LoadControlsGroup +80716ca8 Audio::Manager::Calc +80716db0 Audio::Manager::StartSound +80716df8 Audio::Manager::HoldSound +80716e40 Audio::Manager::EnterHBM +80716eb8 Audio::Manager::ExitHBM +80716f40 Audio::Manager::AudioUtilityCallback +80716f58 Audio::Manager::Lock +80716f64 Audio::Manager::Unlock +80716f70 Audio::Manager::PauseOnDVDBusy +80717020 Audio::Manager::SetupMemoryArchive +80717030 Audio::Manager::HoldSound +80717064 Audio::Manager::HoldSound(str) +807170d4 Audio::Manager::PrepareSound +80717108 Audio::Manager::PrepareSound(str) +80717178 Audio::Manager::StartSound +807171ac Audio::Manager::StartSound(str) +8071721c 0x8071721c +8071723c Audio::Manager::LoadState(thunk) +80717244 Audio::Manager::HoldSound(thunk) +8071724c Audio::Manager::StartSound(thunk) +80717254 Audio::Manager::Calc(thunk) +8071725c Audio::Manager::LoadGroup(thunk) +80717264 Audio::Manager::LoadGroup(thunk) +8071726c Audio::Manager::LoadGroup(thunk) +80717274 Audio::Manager::CloseArchive(thunk) +8071727c Audio::Manager::SetupMemoryArchive(thunk) +80717284 Audio::Manager::SetupMemoryArchive(thunk) +8071728c Audio::Manager::OpenMemoryArchive(thunk) +80717294 Audio::Manager::OpenNANDArchive(thunk) +8071729c Audio::Manager::OpenDVDArchive(thunk) +807172a4 Audio::Manager::OpenArchive(thunk) +807172ac Audio::Manager::__dt(thunk) +807172b4 Audio::Manager::WriteSeqVariable +80717334 0x80717334 +80717374 Audio::Track::SetValue +80717398 Audio::Track::Calc +807173dc Audio::PitchModuler::_ct +807173f0 Audio::PitchModuler::Update +8071746c Audio::PitchModuler::GetNextLimit +807174a0 Audio::EchoMgr::Disposer__dt +807175cc Audio::EchoMgr::CreateInstance +80717680 Audio::EchoMgr::DestroyInstance +80717734 Audio::EchoMgr::__ct +807177bc Audio::EchoMgr::__dt +80717860 Audio::EchoMgr::Init +80717884 Audio::EchoMgr::Shutdown +80717888 Audio::EchoMgr::Update +80717924 Audio::EchoMgr::SetVolume +8071793c Audio::EchoMgr::SetEcho +80717954 Audio::SoundTriggerMgr::Disposer__dt +80717a80 Audio::SoundTriggerMgr::CreateInstance +80717b04 Audio::SoundTriggerMgr::DestroyInstance +80717bb8 Audio::SoundTriggerMgr::__ct +80717c10 Audio::SoundTriggerMgr::__dt +80717cb4 Audio::SoundTriggerMgr::Init +80717d0c Audio::SoundTriggerMgr::Init_switch +80717d10 Audio::SoundTriggerMgr::Init_caseD_3a +80717d8c Audio::SoundTriggerMgr::Init_caseD_1 +80717e08 Audio::SoundTriggerMgr::Init_caseD_4 +80717e84 Audio::SoundTriggerMgr::Init_caseD_0 +80717f00 Audio::SoundTriggerMgr::Init_caseD_5 +80717f7c Audio::SoundTriggerMgr::Init_caseD_6 +80717ff8 Audio::SoundTriggerMgr::Init_caseD_3 +80718074 Audio::SoundTriggerMgr::Init_caseD_c +807180f0 Audio::SoundTriggerMgr::Init_caseD_18 +8071816c Audio::SoundTriggerMgr::Init_caseD_1a +807181e8 Audio::SoundTriggerMgr::Init_caseD_1d +80718264 Audio::SoundTriggerMgr::Init_caseD_10 +807182e0 Audio::SoundTriggerMgr::Init_caseD_13 +8071835c Audio::SoundTriggerMgr::Init_caseD_14 +807183d8 Audio::SoundTriggerMgr::Init_caseD_17 +80718454 Audio::SoundTriggerMgr::Init_caseD_15 +807184d0 Audio::SoundTriggerMgr::Init_caseD_20 +80718548 Audio::SoundTriggerMgr::Init_caseD_2a +80718564 Audio::SoundTriggerMgr::IsAPlayerOnVariant +807185a8 Audio::SoundTriggerMgr::Shutdown +807185b4 Audio::SoundTriggerMgr::Update +807185f0 Audio::SoundTriggerMgr::IsPlayerAheadOfOtherLocal +807186b0 Audio::SoundTriggerMgr::ApplyTrigger +80718808 Audio::SoundTriggerMgr::ApplyTrigger_switch +8071880c Audio::SoundTriggerMgr::ApplyTrigger_caseD_3a +80718960 Audio::SoundTriggerMgr::ApplyTrigger_caseD_2 +80718c04 Audio::SoundTriggerMgr::ApplyTrigger_caseD_4 +80718c24 Audio::SoundTriggerMgr::ApplyTrigger_switch +80718c28 Audio::SoundTriggerMgr::ApplyTrigger_caseD_0 +80718cac Audio::SoundTriggerMgr::ApplyTrigger_caseD_1 +80718d58 Audio::SoundTriggerMgr::ApplyTrigger_caseD_2 +80718ddc Audio::SoundTriggerMgr::ApplyTrigger_caseD_3 +80718e80 Audio::SoundTriggerMgr::ApplyTrigger_caseD_4 +80718f2c Audio::SoundTriggerMgr::ApplyTrigger_caseD_5 +8071904c Audio::SoundTriggerMgr::ApplyTrigger_caseD_6 +807190b8 Audio::SoundTriggerMgr::ApplyTrigger_caseD_7 +80719178 Audio::SoundTriggerMgr::ApplyTrigger_caseD_0 +807191e8 Audio::SoundTriggerMgr::ApplyTrigger_caseD_5 +80719420 Audio::SoundTriggerMgr::ApplyTrigger_caseD_6 +80719574 Audio::SoundTriggerMgr::ApplyTrigger_caseD_7 +80719670 Audio::SoundTriggerMgr::ApplyTrigger_caseD_f +807198e0 Audio::SoundTriggerMgr::ApplyTrigger_caseD_9 +80719950 Audio::SoundTriggerMgr::ApplyTrigger_caseD_e +80719b14 Audio::SoundTriggerMgr::ApplyTrigger_caseD_3 +80719ba8 Audio::SoundTriggerMgr::ApplyTrigger_caseD_a +80719db4 Audio::SoundTriggerMgr::ApplyTrigger_caseD_b +80719e78 Audio::SoundTriggerMgr::ApplyTrigger_caseD_c +80719e98 Audio::SoundTriggerMgr::ApplyTrigger_switch2 +80719e9c Audio::SoundTriggerMgr::ApplyTrigger_case2D_0 +80719ef8 Audio::SoundTriggerMgr::ApplyTrigger_case2D_1 +80719f68 Audio::SoundTriggerMgr::ApplyTrigger_case2D_2 +80719fb8 Audio::SoundTriggerMgr::ApplyTrigger_case2D_3 +8071a008 Audio::SoundTriggerMgr::ApplyTrigger_case2D_4 +8071a058 Audio::SoundTriggerMgr::ApplyTrigger_case2D_5 +8071a074 Audio::SoundTriggerMgr::ApplyTrigger_case2D_6 +8071a090 Audio::SoundTriggerMgr::ApplyTrigger_case2D_7 +8071a0c8 Audio::SoundTriggerMgr::ApplyTrigger_case2D_d +8071a2b4 Audio::SoundTriggerMgr::ApplyTrigger_case2D_1e +8071a320 Audio::SoundTriggerMgr::ApplyTrigger_case2D_1f +8071a350 Audio::SoundTriggerMgr::ApplyTrigger_case2D_1b +8071a4f8 Audio::SoundTriggerMgr::ApplyTrigger_case2D_1a +8071a5f0 Audio::SoundTriggerMgr::ApplyTrigger_case2D_1c +8071a7d8 Audio::SoundTriggerMgr::ApplyTrigger_case2D_1d +8071a8fc Audio::SoundTriggerMgr::ApplyTrigger_case2D_12 +8071a968 Audio::SoundTriggerMgr::ApplyTrigger_case2D_11 +8071a9d8 Audio::SoundTriggerMgr::ApplyTrigger_case2D_13 +8071aae8 Audio::SoundTriggerMgr::ApplyTrigger_case2D_14 +8071ab18 Audio::SoundTriggerMgr::ApplyTrigger_case2D_16 +8071ab48 Audio::SoundTriggerMgr::ApplyTrigger_case2D_17 +8071ae28 Audio::SoundTriggerMgr::ApplyTrigger_case2D_23 +8071ae58 Audio::SoundTriggerMgr::ApplyTrigger_case2D_1 +8071ae74 SetTRKConnected +8071ae80 0x8071ae80 +8071aecc 0x8071aecc +8071aed0 0x8071aed0 +8071aed4 0x8071aed4 +8071aed8 MotionControllerSub::__ct +8071b388 MotionControllerSub::__dt +8071b488 0x8071b488 +8071b710 0x8071b710 +8071b7b0 0x8071b7b0 +8071b7d0 0x8071b7d0 +8071b7f4 0x8071b7f4 +8071b85c 0x8071b85c +8071b890 0x8071b890 +8071b90c 0x8071b90c +8071b918 0x8071b918 +8071b934 0x8071b934 +8071b950 0x8071b950 +8071b99c 0x8071b99c +8071b9dc 0x8071b9dc +8071ba08 0x8071ba08 +8071ba3c 0x8071ba3c +8071ba68 0x8071ba68 +8071bb90 0x8071bb90 +8071bc88 0x8071bc88 +8071bd38 0x8071bd38 +8071bd90 0x8071bd90 +8071bdf0 0x8071bdf0 +8071be04 0x8071be04 +8071be5c 0x8071be5c +8071be70 0x8071be70 +8071be84 0x8071be84 +8071bf14 0x8071bf14 +8071bf6c 0x8071bf6c +8071bf94 0x8071bf94 +8071bfd4 0x8071bfd4 +8071bfe4 0x8071bfe4 +8071c244 0x8071c244 +8071c418 0x8071c418 +8071c58c 0x8071c58c +8071c63c 0x8071c63c +8071c6a0 0x8071c6a0 +8071c714 0x8071c714 +8071c8cc 0x8071c8cc +8071c90c 0x8071c90c +8071caa8 0x8071caa8 +8071cc0c 0x8071cc0c +8071cc98 0x8071cc98 +8071cd0c 0x8071cd0c +8071ce08 0x8071ce08 +8071cea4 0x8071cea4 +8071cecc 0x8071cecc +8071cf0c 0x8071cf0c +8071cfc8 0x8071cfc8 +8071cfd4 0x8071cfd4 +8071d040 0x8071d040 +8071d0ac 0x8071d0ac +8071d148 0x8071d148 +8071d174 0x8071d174 +8071d1a8 0x8071d1a8 +8071d20c 0x8071d20c +8071d2cc 0x8071d2cc +8071d300 0x8071d300 +8071d6e8 0x8071d6e8 +8071d828 0x8071d828 +8071d844 Lakitu::Manager::Disposer__dt +8071d8dc Lakitu::Manager::CreateInstance +8071d968 Lakitu::Manager::DestroyInstance +8071d99c Lakitu::Manager::__ct +8071d9fc Lakitu::Manager::__dt +8071daec Lakitu::Manager::CreatePlayers +8071dca4 Lakitu::Manager::Init +8071dd2c Lakitu::Manager::Update +8071dda0 Lakitu::Manager::DoEnableRespawnAction +8071de18 Lakitu::Manager::ToggleVisible +8071de98 0x8071de98 +8071df10 Lakitu::Manager::StartCountdownAnm +8071df78 0x8071df78 +8071dff0 Lakitu::Manager::GetCountdownStartFrame +8071e020 Lakitu::Movement::__ct +8071e0ec 0x8071e0ec +8071e1d8 Lakitu::Movement::Reset +8071e330 0x8071e330 +8071e48c 0x8071e48c +8071e614 0x8071e614 +8071e644 Lakitu::Movement::SetBasePosition +8071e660 0x8071e660 +8071e6b0 AI::CalcLinearTransfo +8071e738 0x8071e738 +8071e870 0x8071e870 +8071e988 0x8071e988 +8071ea70 Lakitu::Movement::Update +8071f098 0x8071f098 +8071f2b4 0x8071f2b4 +8071f2c8 0x8071f2c8 +8071f2ec 0x8071f2ec +8071f690 Lakitu::Movement::UpdateRotation +8071f81c 0x8071f81c +8071f928 Lakitu::Movement::UpdateExtMtx +8071fb58 0x8071fb58 +8071fb6c 0x8071fb6c +8071fc34 0x8071fc34 +8071fcd0 0x8071fcd0 +8071fd98 0x8071fd98 +8071fdb8 0x8071fdb8 +8071ff0c 0x8071ff0c +8072008c Lakitu::Movement::UpdateScale +80720278 0x80720278 +8072039c 0x8072039c +807204f8 0x807204f8 +807205b0 Lakitu::PlayerBase::__ct +807205f8 Lakitu::PlayerBase::__dt +80720688 Lakitu::PlayerBase::Init +80720690 Lakitu::PlayerBase::Update +807206fc Lakitu::PlayerBase::ToggleModelsScreenVisibility +80720794 Lakitu::PlayerBase::SetModelsVisibility +807208c8 0x807208c8 +807209d4 0x807209d4 +80720aa8 0x80720aa8 +80720b14 0x80720b14 +80720b80 Lakitu::Player::__ct +80721280 AI::Base::__dt +807212c0 AI::Actions::__dt +80721300 0x80721300 +80721358 Lakitu::Action::__dt +80721398 Lakitu::Player::__dt +807214d0 0x807214d0 +8072152c Lakitu::Player::CreateEnableActions +807215f4 0x807215f4 +80721668 0x80721668 +807216c0 0x807216c0 +8072176c Lakitu::Player::Init +80721830 Lakitu::Player::Update +80721a08 Lakitu::Player::GetPlayerIdx +80721a10 Lakitu::Player::StartRespawnAction +80721a28 Lakitu::Player::StartCountdownAction +80721a78 Lakitu::Player::GetCountdownArmSwipeDuration +80721a84 0x80721a84 +80721b70 Lakitu::Player::LoadGraphics +807224c0 0x807224c0 +8072250c 0x8072250c +80722544 0x80722544 +807225d8 0x807225d8 +80722740 Lakitu::Player::MapToWorldSpace +80722950 0x80722950 +80722a2c 0x80722a2c +80722ac4 Lakitu::Player::OnStartIdle +80722b10 Lakitu::Player::UpdateIdle +80722c04 Lakitu::Player::OnStartCountdown +80722d78 0x80722d78 +80722e18 Lakitu::Player::UpdateCountdown +80723164 0x80723164 +80723208 0x80723208 +8072328c Lakitu::Player::OnEndCountdown +807232e8 Lakitu::Player::OnStartLap +8072352c Lakitu::Player::UpdateLap +80723908 0x80723908 +80723960 Lakitu::Player::OnStartRespawn +80723a9c Lakitu::Player::UpdateRespawn +80723de4 0x80723de4 +80723e00 Lakitu::Player::OnStartBackwards +80723eec Lakitu::Player::UpdateBackwards +807245dc Lakitu::Player::OnEndBackwards +807246cc Lakitu::Player::OnStartEnding +807247dc Lakitu::Player::UpdateEnding +80724a90 Lakitu::Player::OnEndEnding +80724b0c Lakitu::Player::OnStartUnknown +80724b2c Lakitu::Player::UpdateUnknown +80724c14 AI::Base::OnStartDefaultAction +80724c18 AI::Base::UpdateDefaultAction +80724c1c Lakitu::Action::OnStart +80724c64 Lakitu::Action::Update +80724c94 Lakitu::Action::OnEnd +80724cdc 0x80724cdc +80725050 Lakitu::Player::__dt(thunk) +80725058 Lakitu::EnableLakituAction::__ct +80725078 Lakitu::EnableLakituAction::__dt +807250b8 Lakitu::EnableLakituAction::ResetState +807250c8 Lakitu::EnableLakituAction::HasActionHappened +807250e4 Lakitu::EnableCountdownAction::__ct +80725104 Lakitu::EnableCountdownAction::__dt +80725144 Lakitu::EnableCountdownAction::ResetState +80725154 Lakitu::EnableCountdownAction::EnableAction +807251b4 Lakitu::EnableDisplayLapAction::__ct +807251d4 Lakitu::EnableDisplayLapAction::__dt +80725214 Lakitu::EnableDisplayLapAction::ResetState +80725244 Lakitu::EnableDisplayLapAction::EnableAction +80725288 Lakitu::EnableBackwardsAction::__ct +807252a8 Lakitu::EnableBackwardsAction::__dt +807252e8 Lakitu::EnableBackwardsAction::ResetState +80725304 Lakitu::EnableBackwardsAction::EnableAction +80725444 Lakitu::EnableRespawnAction::__ct +80725464 Lakitu::EnableRespawnAction::__dt +807254a4 Lakitu::EnableRespawnAction::ResetState +807254b4 Lakitu::EnableRespawnAction::EnableAction +807254b8 Lakitu::EnableEndingAction::__ct +807254d8 Lakitu::EnableEndingAction::__dt +80725518 Lakitu::EnableEndingAction::ResetState +80725528 Lakitu::EnableEndingAction::EnableAction +80725578 0x80725578 +80725598 0x80725598 +807255d8 cGameSFX_Init +807255e8 0x807255e8 +80725648 KartAIController::__ct +807256f4 KartAIController::__dt +8072577c KartAIController::Init +80725824 KartAIController::Update +80725870 KartAIController::GetStick +807258b8 KartAIController::IsCPU +807258fc KartAIController::IsRealLocal +8072593c 0x8072593c +807259a4 thunk_0x80590664 +807259a8 KartAIController::IsGhost +807259ec KartAIController::HaveSameTeam +80725a14 0x80725a14 +80725a1c 0x80725a1c +80725a30 0x80725a30 +80725a38 0x80725a38 +80725b54 KartAIController::IsOnTheGround +80725b68 KartAIController::IsInTheAir +80725b7c 0x80725b7c +80725b90 KartAIController::IsManuallyDrifting +80725ba4 KartAIController::IsHopping +80725bb8 KartAIController::IsAutomaticDrifting +80725bcc KartAIController::IsInABill +80725be0 0x80725be0 +80726084 0x80726084 +807260c4 0x807260c4 +80726104 0x80726104 +80726144 0x80726144 +80726200 0x80726200 +80726254 0x80726254 +8072625c 0x8072625c +80726380 0x80726380 +807264c8 0x807264c8 +807264e4 0x807264e4 +80726664 0x80726664 +807266f0 0x807266f0 +80726708 0x80726708 +80726930 0x80726930 +807269e0 0x807269e0 +80726a50 0x80726a50 +80726a5c 0x80726a5c +80726a6c 0x80726a6c +80726b3c 0x80726b3c +80726b48 0x80726b48 +80726b58 0x80726b58 +80726b8c 0x80726b8c +80726c20 0x80726c20 +80726d28 0x80726d28 +80726d34 0x80726d34 +80726d7c 0x80726d7c +80726dac 0x80726dac +80726df4 0x80726df4 +80727158 0x80727158 +80727198 0x80727198 +80727244 0x80727244 +80727310 0x80727310 +80727364 0x80727364 +807273ac 0x807273ac +807273bc 0x807273bc +8072740c 0x8072740c +807274f0 0x807274f0 +80727560 0x80727560 +807275cc 0x807275cc +807276f4 0x807276f4 +80727878 0x80727878 +8072787c 0x8072787c +80727880 AI::CPUDriving::GetCalculator +80727888 0x80727888 +8072788c 0x8072788c +80727900 0x80727900 +80727904 0x80727904 +80727908 0x80727908 +807279c8 0x807279c8 +80727b3c 0x80727b3c +80727c34 0x80727c34 +80727c38 0x80727c38 +80727c80 0x80727c80 +80727cb0 0x80727cb0 +80727cf8 0x80727cf8 +80727e24 0x80727e24 +80727edc 0x80727edc +80728010 0x80728010 +80728084 0x80728084 +807280c4 0x807280c4 +80728104 0x80728104 +807281e8 0x807281e8 +807282c0 0x807282c0 +80728334 0x80728334 +80728400 0x80728400 +80728498 0x80728498 +807284dc 0x807284dc +807285cc 0x807285cc +80728778 0x80728778 +807287f4 0x807287f4 +80728884 0x80728884 +807289a4 0x807289a4 +807289ac 0x807289ac +807289b4 0x807289b4 +807289bc 0x807289bc +80728c80 0x80728c80 +80728cc0 0x80728cc0 +80728d00 0x80728d00 +80728d20 0x80728d20 +80728d8c 0x80728d8c +80728d94 0x80728d94 +80728ed4 0x80728ed4 +80728fb0 0x80728fb0 +807290f8 0x807290f8 +80729104 0x80729104 +8072912c 0x8072912c +80729138 0x80729138 +807291f4 0x807291f4 +807291fc 0x807291fc +80729208 0x80729208 +80729320 0x80729320 +80729368 0x80729368 +80729398 0x80729398 +807293e0 0x807293e0 +80729408 AI::CPUDriving::__ct +80729584 AI::CPUDriving::__dt +80729714 0x80729714 +80729754 AI::CPUDriving::Init +80729888 AI::CPUDriving::InitEnemyRoute +80729914 0x80729914 +80729954 0x80729954 +8072995c 0x8072995c +80729964 0x80729964 +8072996c 0x8072996c +8072997c AI::CPUDriving::CalcStartBoost +807299dc 0x807299dc +807299e0 ParamActionCalculator::GetStartBoost +807299e8 0x807299e8 +80729bcc 0x80729bcc +80729bd4 0x80729bd4 +80729bdc 0x80729bdc +80729cbc 0x80729cbc +80729ce0 0x80729ce0 +80729d20 0x80729d20 +80729d34 0x80729d34 +80729d48 0x80729d48 +80729dac 0x80729dac +80729dc0 0x80729dc0 +80729e00 0x80729e00 +80729e0c 0x80729e0c +80729eb0 0x80729eb0 +80729ef8 AI::CPUDriving::IsBattle +80729f00 0x80729f00 +80729f04 0x80729f04 +80729f0c 0x80729f0c +80729f14 0x80729f14 +80729f18 0x80729f18 +80729f54 0x80729f54 +8072a6e8 0x8072a6e8 +8072a728 0x8072a728 +8072a848 0x8072a848 +8072aa44 0x8072aa44 +8072aa48 0x8072aa48 +8072aac0 0x8072aac0 +8072ab04 0x8072ab04 +8072ab6c 0x8072ab6c +8072ac64 0x8072ac64 +8072ac84 0x8072ac84 +8072acec 0x8072acec +8072aed8 0x8072aed8 +8072aee0 0x8072aee0 +8072afc8 0x8072afc8 +8072afd0 0x8072afd0 +8072afe0 0x8072afe0 +8072b024 0x8072b024 +8072b184 0x8072b184 +8072b36c 0x8072b36c +8072b388 0x8072b388 +8072b4d4 0x8072b4d4 +8072b5f8 0x8072b5f8 +8072b7cc 0x8072b7cc +8072b9a8 0x8072b9a8 +8072b9d0 0x8072b9d0 +8072bab0 0x8072bab0 +8072bab4 0x8072bab4 +8072bac8 0x8072bac8 +8072bad4 0x8072bad4 +8072bbb4 0x8072bbb4 +8072bbd4 0x8072bbd4 +8072bc14 0x8072bc14 +8072bc54 0x8072bc54 +8072bdac 0x8072bdac +8072be78 0x8072be78 +8072be80 0x8072be80 +8072bff0 0x8072bff0 +8072c070 0x8072c070 +8072c084 0x8072c084 +8072c0c4 0x8072c0c4 +8072c0d4 0x8072c0d4 +8072c0e8 WorldLoader_GetStadiumTerrain +8072c0fc 0x8072c0fc +8072c10c 0x8072c10c +8072c120 0x8072c120 +8072c160 0x8072c160 +8072c2d4 0x8072c2d4 +8072c2dc 0x8072c2dc +8072c2f0 0x8072c2f0 +8072c330 0x8072c330 +8072c848 0x8072c848 +8072c85c 0x8072c85c +8072c89c 0x8072c89c +8072cb60 0x8072cb60 +8072cb94 0x8072cb94 +8072cbd4 0x8072cbd4 +8072cc28 0x8072cc28 +8072cc38 0x8072cc38 +8072ce54 0x8072ce54 +8072d040 0x8072d040 +8072d1ac 0x8072d1ac +8072d294 0x8072d294 +8072d350 0x8072d350 +8072d384 0x8072d384 +8072d3c4 0x8072d3c4 +8072d41c 0x8072d41c +8072d450 0x8072d450 +8072d490 0x8072d490 +8072d4d0 0x8072d4d0 +8072d4d8 0x8072d4d8 +8072d4e0 0x8072d4e0 +8072d4e8 0x8072d4e8 +8072d4f0 0x8072d4f0 +8072d4f8 0x8072d4f8 +8072d500 0x8072d500 +8072d508 0x8072d508 +8072d50c 0x8072d50c +8072d54c 0x8072d54c +8072d554 0x8072d554 +8072d55c 0x8072d55c +8072d564 0x8072d564 +8072d56c 0x8072d56c +8072d574 0x8072d574 +8072d57c 0x8072d57c +8072d5c4 0x8072d5c4 +8072d5f4 0x8072d5f4 +8072d63c 0x8072d63c +8072d91c 0x8072d91c +8072d95c 0x8072d95c +8072d9b4 0x8072d9b4 +8072da54 0x8072da54 +8072dacc 0x8072dacc +8072dadc 0x8072dadc +8072db00 0x8072db00 +8072db1c 0x8072db1c +8072db44 0x8072db44 +8072dce4 0x8072dce4 +8072dcec 0x8072dcec +8072dcf4 0x8072dcf4 +8072dcfc 0x8072dcfc +8072dd0c 0x8072dd0c +8072dd10 0x8072dd10 +8072dd18 0x8072dd18 +8072dd20 0x8072dd20 +8072dd28 0x8072dd28 +8072dd30 0x8072dd30 +8072dd38 0x8072dd38 +8072dd40 0x8072dd40 +8072dd48 0x8072dd48 +8072dd4c 0x8072dd4c +8072dd8c 0x8072dd8c +8072ddd4 0x8072ddd4 +8072de04 0x8072de04 +8072de4c 0x8072de4c +8072e048 0x8072e048 +8072e088 0x8072e088 +8072e0e0 0x8072e0e0 +8072e1f0 0x8072e1f0 +8072e26c 0x8072e26c +8072e294 0x8072e294 +8072e330 0x8072e330 +8072e438 0x8072e438 +8072e508 0x8072e508 +8072e678 0x8072e678 +8072e984 0x8072e984 +8072e994 0x8072e994 +8072eb94 0x8072eb94 +8072ebc0 0x8072ebc0 +8072ecc0 0x8072ecc0 +8072eda0 0x8072eda0 +8072ee6c 0x8072ee6c +8072ef8c 0x8072ef8c +8072efcc 0x8072efcc +8072f024 0x8072f024 +8072f064 0x8072f064 +8072f0e0 0x8072f0e0 +8072f1e8 0x8072f1e8 +8072f304 0x8072f304 +8072f314 0x8072f314 +8072f388 0x8072f388 +8072f3a4 0x8072f3a4 +8072f5cc 0x8072f5cc +8072f5d4 0x8072f5d4 +8072f5dc 0x8072f5dc +8072f5e4 0x8072f5e4 +8072f5ec 0x8072f5ec +8072f5f4 0x8072f5f4 +8072f63c 0x8072f63c +8072f66c 0x8072f66c +8072f6b4 0x8072f6b4 +8072f6fc 0x8072f6fc +8072f72c 0x8072f72c +8072f774 0x8072f774 +8072f804 AI::CPUDrivingRace::__ct +8072f990 AI::CPUDrivingAction::__dt +8072f9d0 AI::CPUDrivingRace::__dt +8072fa8c AI::CPUDrivingRace::Init +8072fb7c AI::CPUDrivingRace::InitEnemyRoute +8072fd18 0x8072fd18 +8072fdc4 0x8072fdc4 +8072fdf8 AI::CPUDrivingRace::Update +8072fef4 0x8072fef4 +8072ff48 0x8072ff48 +807300e4 0x807300e4 +807300e8 0x807300e8 +807300ec AI::CPUDrivingAction::OnStart +80730134 AI::CPUDrivingAction::Update +80730164 AI::CPUDrivingAction::OnEnd +807301ac 0x807301ac +807301cc 0x807301cc +8073020c 0x8073020c +80730244 0x80730244 +8073040c 0x8073040c +80730420 0x80730420 +80730508 0x80730508 +80730670 0x80730670 +807306a4 0x807306a4 +807306b0 0x807306b0 +807307b4 0x807307b4 +80730870 0x80730870 +8073093c 0x8073093c +80730b0c 0x80730b0c +80730da4 0x80730da4 +80730de8 0x80730de8 +80730e14 0x80730e14 +80730e54 0x80730e54 +80730fcc AI::Inputs::__ct +80730ff0 AI::Inputs::Reset +80731008 AI::Inputs::AddInputs +80731018 AI::Inputs::RemoveInputs +80731028 0x80731028 +80731030 AI::Player::__ct +807319cc AI::PlayerActions::__dt +80731a0c AI::Player::__dt +80731b74 AI::Player::Init +80731ce4 AI::Player::Update +80731d08 AI::Player::vf_0x20 +80731d98 0x80731d98 +80731db8 0x80731db8 +80731e5c 0x80731e5c +80731efc AI::Player::OnStartPreRace +80731f4c AI::Player::UpdatePreRace +807320d8 AI::Player::OnStartAI::CPUDriving +807320dc AI::Player::UpdateAI::CPUDriving +807322d8 AI::Player::OnStartRealPlayerDriving +807322dc AI::Player::UpdateRealPlayerDriving +807323f0 AI::Player::OnStartAction3 +807323f4 AI::Player::UpdateAction3 +807323f8 AI::Player::OnStartPostRaceDriving +80732448 0x80732448 +8073244c AI::Player::UpdatePostRaceDriving +807325f0 AI::Player::OnStartPostBattleDriving +80732640 AI::Player::UpdatePostBattleDriving +80732760 AI::PlayerActions::OnStart +807327a8 AI::PlayerActions::Update +807327d8 AI::PlayerActions::OnEnd +80732820 AI::PlayerBike::__ct +807328a4 AI::PlayerBike::__dt +807328fc AI::PlayerBike::Init +80732900 AI::PlayerBike::Update +80732904 AI::PlayerBike::vf_0x20 +80732908 AI::PlayerBike::OnStartAction1 +8073290c AI::PlayerBike::UpdateAction1 +80732910 AI::PlayerKart::__ct +80732968 AI::PlayerKart::__dt +807329c0 AI::PlayerKart::Init +80732a24 AI::PlayerKart::Update +80732a28 AI::PlayerKart::vf_0x20 +80732a2c AI::PlayerKart::OnStartAction1 +80732a30 AI::PlayerKart::UpdateAction1 +80732a34 0x80732a34 +807330e8 0x807330e8 +80733128 0x80733128 +80733168 0x80733168 +80733188 0x80733188 +807331cc 0x807331cc +80733210 0x80733210 +80733218 0x80733218 +80733220 0x80733220 +80733228 0x80733228 +80733230 0x80733230 +80733238 0x80733238 +807332cc 0x807332cc +80733350 0x80733350 +8073338c 0x8073338c +807333b8 0x807333b8 +807333cc 0x807333cc +807333e8 0x807333e8 +80733400 0x80733400 +8073341c 0x8073341c +80733484 0x80733484 +80733490 0x80733490 +807336c4 0x807336c4 +807336cc 0x807336cc +807336d0 0x807336d0 +807337b8 0x807337b8 +807337bc 0x807337bc +80733888 0x80733888 +8073388c 0x8073388c +80733954 0x80733954 +80733958 0x80733958 +80733964 0x80733964 +80733a60 0x80733a60 +80733a6c 0x80733a6c +80733b68 0x80733b68 +80733b6c 0x80733b6c +80733bf8 0x80733bf8 +80733bfc 0x80733bfc +80733c00 0x80733c00 +80733c48 0x80733c48 +80733c88 0x80733c88 +80733ce0 0x80733ce0 +80733d24 0x80733d24 +80733d30 0x80733d30 +80733e24 0x80733e24 +80733f2c 0x80733f2c +807340b8 0x807340b8 +807340c4 0x807340c4 +807340dc 0x807340dc +807341ac 0x807341ac +807342a0 0x807342a0 +807342e0 0x807342e0 +80734478 0x80734478 +80734550 0x80734550 +8073473c 0x8073473c +8073474c 0x8073474c +80734750 0x80734750 +80734848 0x80734848 +80734890 0x80734890 +807348c0 0x807348c0 +80734908 0x80734908 +8073491c 0x8073491c +8073495c 0x8073495c +80734960 0x80734960 +80734964 0x80734964 +807349b4 0x807349b4 +80734a64 0x80734a64 +80734a78 0x80734a78 +80734ab8 0x80734ab8 +80734abc 0x80734abc +80734acc 0x80734acc +80734ad0 0x80734ad0 +80734bc8 0x80734bc8 +80734bdc 0x80734bdc +80734c1c 0x80734c1c +80734c20 0x80734c20 +80734c60 0x80734c60 +80734c6c 0x80734c6c +80734d90 0x80734d90 +80734e98 0x80734e98 +80734eac 0x80734eac +80734eec 0x80734eec +80734fb4 AI::Character::__ct +80735884 AI::CharacterActions::__dt +807358c4 AI::Character::__dt +80735948 AI::Character::Init +80735a2c AI::Character::Update +80735a6c AI::Character::vf_0x20 +80735aec AI::Character::StartDriving +80735b44 0x80735b44 +80735bf4 0x80735bf4 +80735c30 0x80735c30 +80735c34 0x80735c34 +80735c3c 0x80735c3c +80735c40 0x80735c40 +80735c48 0x80735c48 +80735c50 0x80735c50 +80735c54 0x80735c54 +80735c60 0x80735c60 +80735cbc 0x80735cbc +80735cf8 0x80735cf8 +80735d50 0x80735d50 +80735dd0 AI::Character::ArePlayersClose +80735eb8 0x80735eb8 +80736028 AI::Character::vf_0x8c +80736150 0x80736150 +80736238 0x80736238 +8073630c AI::Character::vf_0x94 +80736390 AI::Character::OnStartAction0 +8073639c AI::Character::UpdateAction0 +807363f8 AI::Character::OnStartAction1 +807363fc AI::Character::UpdateAction1 +80736530 AI::Character::OnStartAction2 +80736534 AI::Character::UpdateAction2 +80736678 AI::Character::OnEndAction2 +807366b4 AI::Character::OnStartAction3 +807366c0 AI::Character::UpdateAction3 +80736814 AI::Character::OnStartAction4 +80736950 AI::Character::UpdateAction4 +80736a14 AI::Character::OnEndAction4 +80736a50 AI::Character::OnStartAction5 +80736a64 AI::Character::UpdateAction5 +80736c6c AI::Character::OnEndAction5 +80736ca8 AI::Character::OnStartAction6 +80736e04 AI::Character::UpdateAction6 +80736ef4 AI::Character::OnEndAction6 +80736f30 AI::Character::OnStartAction7 +80736f40 AI::Character::UpdateAction7 +80736fa0 AI::Character::OnEndAction7 +80736fdc AI::Character::OnStartLookAhead +80737018 AI::Character::UpdateLookAhead +8073701c AI::Character::OnStartLookAtCamera +80737028 AI::Character::UpdateLookAtCamera +8073729c 0x8073729c +807372bc 0x807372bc +807372fc 0x807372fc +80737308 0x80737308 +80737538 0x80737538 +80737810 0x80737810 +80737bc4 AI::CharacterBattle::__ct +80737c00 AI::CharacterBattle::__dt +80737c58 AI::CharacterBattle::Init +80737c90 AI::CharacterBattle::OnStartAction1 +80737c94 AI::CharacterBattle::UpdateAction1 +80737cd0 AI::CharacterAwards::__ct +80737d0c AI::CharacterAwards::__dt +80737d64 AI::CharacterAwards::Init +80737d9c AI::CharacterAwards::OnStartAction1 +80737da0 AI::CharacterAwards::UpdateAction1 +80737ddc 0x80737ddc +80737e18 0x80737e18 +80737e70 0x80737e70 +80737eb4 0x80737eb4 +80737fcc 0x80737fcc +807380b4 0x807380b4 +807380b8 0x807380b8 +80738130 0x80738130 +80738210 0x80738210 +80738320 0x80738320 +8073835c AI::CharacterAwards::vf_0x94 +80738364 AI::CharacterActions::OnStart +807383ac AI::CharacterActions::Update +807383dc AI::CharacterActions::OnEnd +80738424 AI::Manager::Disposer__dt +807384bc AI::Manager::CreateInstance +8073850c AI::Manager::DestroyInstance +80738540 AI::Manager::__ct +80738718 AI::Manager::__dt +80738898 AI::Manager::AddKartAIController +8073896c AI::Manager::GetKartAIController +8073897c AI::Manager::GetRealPlayerKartAIController +8073898c obj_checkIfSomething +80738994 AI::Manager::Init +80738a98 AI::Manager::Update +80738b9c AI::Manager::GetLocalPlayerCount +80738bac AI::Manager::GetEngineClass +80738bb4 AI::Manager::GetDifficulty +80738bbc 0x80738bbc +80738bf8 0x80738bf8 +80738cc8 AI::Manager::IsGPOrPrivateVS +80738cf0 AI::Manager::IsVS +80738d10 AI::Manager::IsTT +80738d38 AI::Manager::IsMissionTournament +80738d58 AI::Manager::IsOnline +80738d80 AI::Manager::IsBattle +80738dac AI::Manager::IsOfflineBattle +80738dcc AI::Manager::IsBallonBattle +80738de4 AI::Manager::IsCoinRunners +80738e00 AI::Manager::IsTT2 +80738e28 AI::Manager::IsSpecialItemMode +80738ed8 AI::Manager::IsTeamMode +80738eec 0x80738eec +80738ef4 AI::Manager::IsAwardsOrCredits +80738f18 AiHolder_getRealPlayerCountPerTeam +80738fb0 AI::Manager::GetRandomValue +80738fd8 AI::Manager::GetRandomFloat +80739008 AI::Manager::SetCCAndDifficulty +807390e8 0x807390e8 +80739194 0x80739194 +8073923c AiHolder_getBestPreviousScore +807392dc 0x807392dc +80739318 0x80739318 +807393a4 0x807393a4 +807393e8 0x807393e8 +8073954c 0x8073954c +807395b8 0x807395b8 +8073965c 0x8073965c +80739660 0x80739660 +80739670 0x80739670 +80739690 0x80739690 +807396d0 0x807396d0 +80739754 0x80739754 +807399f0 0x807399f0 +80739c50 0x80739c50 +80739ce0 0x80739ce0 +80739eec 0x80739eec +8073a000 0x8073a000 +8073a110 0x8073a110 +8073a19c 0x8073a19c +8073a1d4 AI::Params::__ct +8073a264 AI::Params::__dt +8073a2ec AI::Params::GetParamSpeed +8073a2f4 AI::Params::GetParamAction +8073a304 AI::Params::LoadParamFile +8073a314 AI::Params::Load +8073a5dc 0x8073a5dc +8073a638 0x8073a638 +8073a68c AI::Params::LoadActions +8073a764 AI::EnemyRouteController::__ct +8073ab08 AI::ENPTSettingsHolder::__dt +8073ab48 AI::EnemyRouteController::__dt +8073ac48 AI::EnemyRouteController::Init +8073acfc AI::EnemyRouteController::Update +8073ae5c 0x8073ae5c +8073ae9c 0x8073ae9c +8073aee0 0x8073aee0 +8073af00 0x8073af00 +8073af1c 0x8073af1c +8073af24 0x8073af24 +8073af2c 0x8073af2c +8073af50 0x8073af50 +8073aff4 0x8073aff4 +8073b0dc 0x8073b0dc +8073b0e4 0x8073b0e4 +8073b158 0x8073b158 +8073b1ac 0x8073b1ac +8073b1bc 0x8073b1bc +8073b294 0x8073b294 +8073b374 0x8073b374 +8073b3bc AI::EnemyRouteController::IsOutCurENPTBounds +8073b590 0x8073b590 +8073b6a8 0x8073b6a8 +8073b77c AI::EnemyRouteHolder::AdvanceToNextENPT +8073b8b8 0x8073b8b8 +8073b92c AI::EnemyRouteHolder::__ct +8073b974 AI::EnemyRouteHolder::__dt +8073b9b4 AI::EnemyRouteHolder::AddKartAIController +8073b9f8 0x8073b9f8 +8073b9fc 0x8073b9fc +8073ba00 0x8073ba00 +8073bbac 0x8073bbac +8073bbb8 AI::ENPTController::__ct +8073bc24 AI::ENPTController::__dt +8073bc64 AI::ENPTController::SetStartingENPT +8073bcb0 AI::ENPTController::Init +8073c024 AI::ENPTController::Update +8073c028 AI::ENPTController::GetPrevPrevPrevENPTPosition +8073c07c AI::ENPTController::GetPrevPrevENPTPosition +8073c0d0 AI::ENPTController::GetPrevENPTPosition +8073c124 AI::ENPTController::GetCurENPTPosition +8073c178 AI::ENPTController::GetNextENPTPosition +8073c1cc AI::ENPTController::GetCurPosition +8073c1e8 0x8073c1e8 +8073c314 0x8073c314 +8073c358 0x8073c358 +8073c3a8 AI::ENPTController::CalcNext +8073c6cc 0x8073c6cc +8073c85c 0x8073c85c +8073c894 0x8073c894 +8073c8b4 0x8073c8b4 +8073c8f0 0x8073c8f0 +8073c910 0x8073c910 +8073c930 0x8073c930 +8073c93c 0x8073c93c +8073c9e8 0x8073c9e8 +8073ca20 0x8073ca20 +8073cc08 0x8073cc08 +8073cd58 0x8073cd58 +8073cfa0 0x8073cfa0 +8073cff8 AI::ENPTController::CalcNextPosition +8073d124 0x8073d124 +8073d130 0x8073d130 +8073d238 0x8073d238 +8073d260 0x8073d260 +8073d2a4 0x8073d2a4 +8073d2e4 0x8073d2e4 +8073d688 0x8073d688 +8073d6c8 0x8073d6c8 +8073d6cc 0x8073d6cc +8073d6d8 0x8073d6d8 +8073d710 0x8073d710 +8073d748 0x8073d748 +8073d788 0x8073d788 +8073d7c8 0x8073d7c8 +8073d808 0x8073d808 +8073d814 0x8073d814 +8073d838 0x8073d838 +8073d968 0x8073d968 +8073d9d8 0x8073d9d8 +8073da48 0x8073da48 +8073dab8 0x8073dab8 +8073db20 0x8073db20 +8073db88 0x8073db88 +8073dc3c 0x8073dc3c +8073dcf4 0x8073dcf4 +8073de04 0x8073de04 +8073df14 0x8073df14 +8073df58 0x8073df58 +8073df98 0x8073df98 +8073dfd8 0x8073dfd8 +8073dfdc 0x8073dfdc +8073dfe8 0x8073dfe8 +8073e020 0x8073e020 +8073e058 0x8073e058 +8073e098 0x8073e098 +8073e0d8 0x8073e0d8 +8073e118 0x8073e118 +8073e150 0x8073e150 +8073e15c 0x8073e15c +8073e180 0x8073e180 +8073e1e8 0x8073e1e8 +8073e1f8 0x8073e1f8 +8073e250 AI::ENPTSettingsHolder::IsCutPoint +8073e264 AI::ENPTSettingsHolder::IsUseOffroadCutItem +8073e278 AI::ENPTSettingsHolder::MustWheelie +8073e28c AI::ENPTSettingsHolder::MustEndWheelie +8073e2a0 AI::ENPTSettingsHolder::IsSetting1Equal5 +8073e2b4 AI::ENPTSettingsHolder::MustEndDrift +8073e2c8 AI::ENPTSettingsHolder::IsDriftForbidden +8073e2dc AI::ENPTSettingsHolder::MustDrift +8073e2f0 AI::ENPTSettingsHolder::IsSetting3HighestBitSet +8073e2fc 0x8073e2fc +8073e318 AI::ENPTSettingsHolder::IsDriftAllowed +8073e34c 0x8073e34c +8073e360 0x8073e360 +8073e374 0x8073e374 +8073e388 0x8073e388 +8073e39c 0x8073e39c +8073e3a8 0x8073e3a8 +8073e3b4 0x8073e3b4 +8073e3c0 0x8073e3c0 +8073e400 0x8073e400 +8073e440 0x8073e440 +8073e45c AI::ParamActionCalculator::__ct +8073e480 AI::ParamActionCalculator::__dt +8073e4c0 AI::ParamActionCalculator::Init +8073e4f8 AI::ParamActionCalculator::CalcStartBoost +8073e614 AI::ParamActionCalculator::CalcGotDrift +8073e6d0 AI::ParamActionCalculator::CalcGotMT +8073e774 AI::ParamActionCalculator::CalcGotTrick +8073e7fc AI::ParamActionCalculator::CalcGotWheelie +8073e884 AI::ParamActionCalculator::CalcGotParamAction6 +8073e90c AI::ParamActionCalculator::CalcGotParamAction7 +8073e994 0x8073e994 +8073e9e8 0x8073e9e8 +8073ea2c 0x8073ea2c +8073ea6c 0x8073ea6c +8073eaa8 0x8073eaa8 +8073eb40 0x8073eb40 +8073eb60 0x8073eb60 +8073eb78 0x8073eb78 +8073ec80 0x8073ec80 +8073ecd4 0x8073ecd4 +8073ed10 0x8073ed10 +8073ed50 0x8073ed50 +8073ed80 0x8073ed80 +8073eda4 0x8073eda4 +8073edd8 0x8073edd8 +8073ee14 0x8073ee14 +8073eeb4 0x8073eeb4 +8073ef64 0x8073ef64 +8073ef98 0x8073ef98 +8073f078 0x8073f078 +8073f08c 0x8073f08c +8073f0c8 0x8073f0c8 +8073f0f4 0x8073f0f4 +8073f120 0x8073f120 +8073f1e4 0x8073f1e4 +8073f224 0x8073f224 +8073f264 0x8073f264 +8073f294 0x8073f294 +8073f2a0 0x8073f2a0 +8073f2ac 0x8073f2ac +8073f33c 0x8073f33c +8073f3f4 0x8073f3f4 +8073f71c 0x8073f71c +8073f820 0x8073f820 +8073fb24 0x8073fb24 +8073fb34 0x8073fb34 +8073fc70 0x8073fc70 +8073fd6c 0x8073fd6c +8073fd70 0x8073fd70 +8073fda4 0x8073fda4 +8073fde0 0x8073fde0 +8073fe20 0x8073fe20 +8073fe50 0x8073fe50 +8073fe5c 0x8073fe5c +8073fe68 0x8073fe68 +8073fe78 0x8073fe78 +80740020 0x80740020 +8074011c 0x8074011c +80740120 0x80740120 +80740154 0x80740154 +80740190 0x80740190 +807401d0 0x807401d0 +80740200 0x80740200 +807402fc 0x807402fc +80740300 0x80740300 +80740334 OS::GetCurrentContext +80740340 0x80740340 +8074034c 0x8074034c +80740350 0x80740350 +80740354 0x80740354 +8074035c 0x8074035c +80740364 0x80740364 +8074036c 0x8074036c +80740374 0x80740374 +8074037c 0x8074037c +80740380 0x80740380 +80740384 0x80740384 +80740388 0x80740388 +807409f4 0x807409f4 +80740a34 0x80740a34 +80740b24 0x80740b24 +80740bd4 0x80740bd4 +80740cc0 GameInfoManager_SetUserSelectedCupSidekick +80740ccc 0x80740ccc +80740e70 0x80740e70 +80740ee4 0x80740ee4 +80740eec 0x80740eec +80740ef4 0x80740ef4 +80740f04 0x80740f04 +80740f44 0x80740f44 +80740f4c 0x80740f4c +80740fec 0x80740fec +80741004 0x80741004 +8074107c 0x8074107c +80741358 0x80741358 +807416b8 0x807416b8 +80741778 0x80741778 +80741868 0x80741868 +80741938 0x80741938 +80741a04 0x80741a04 +80741b4c 0x80741b4c +80741bf0 0x80741bf0 +80741d50 0x80741d50 +80741e64 0x80741e64 +80741ec0 0x80741ec0 +80741ec4 0x80741ec4 +80741f04 0x80741f04 +80741fb0 0x80741fb0 +807420cc 0x807420cc +80742170 0x80742170 +8074217c 0x8074217c +8074222c 0x8074222c +80742278 0x80742278 +807422c4 0x807422c4 +80742334 0x80742334 +807424ec 0x807424ec +8074264c 0x8074264c +80742828 0x80742828 +807429b0 0x807429b0 +80742a50 0x80742a50 +80742a54 0x80742a54 +80742a94 0x80742a94 +80742aac 0x80742aac +80742ac4 0x80742ac4 +80742adc 0x80742adc +80742b3c 0x80742b3c +80742d98 0x80742d98 +80742de0 0x80742de0 +80742e10 0x80742e10 +80742e58 0x80742e58 +80742e84 0x80742e84 +80742ec4 0x80742ec4 +80742efc 0x80742efc +80742f48 0x80742f48 +80742f98 0x80742f98 +80742ff8 0x80742ff8 +80743004 0x80743004 +8074301c cGame_GetGameTime +80743028 0x80743028 +8074305c 0x8074305c +807432ac 0x807432ac +80743300 0x80743300 +80743340 0x80743340 +80743460 0x80743460 +8074348c 0x8074348c +807434ec 0x807434ec +80743588 0x80743588 +80743624 0x80743624 +80743800 0x80743800 +80743838 0x80743838 +80743878 0x80743878 +807438c4 0x807438c4 +807439d0 0x807439d0 +80743a04 0x80743a04 +80743a44 0x80743a44 +80743ae4 0x80743ae4 +80743c68 0x80743c68 +80743ca0 0x80743ca0 +80743ce0 0x80743ce0 +80743d2c 0x80743d2c +80743d94 0x80743d94 +80743d9c 0x80743d9c +80744098 0x80744098 +807440d8 0x807440d8 +80744160 0x80744160 +80744210 0x80744210 +80744288 0x80744288 +80744290 0x80744290 +807442b4 0x807442b4 +8074434c 0x8074434c +80744358 0x80744358 +80744418 0x80744418 +80744550 0x80744550 +807445e4 0x807445e4 +807445f8 0x807445f8 +807447d0 0x807447d0 +80744844 0x80744844 +80744cc4 0x80744cc4 +80744d2c 0x80744d2c +80744d64 0x80744d64 +80744d68 0x80744d68 +80744d88 0x80744d88 +80744dc8 0x80744dc8 +80744dd8 0x80744dd8 +80744e30 0x80744e30 +80744e78 0x80744e78 +80744ea8 0x80744ea8 +80744ef0 MotionController::__ct +80744f88 0x80744f88 +80744fc8 MotionController::__dt +80745050 MotionController::Init +80745250 MotionController::UpdateForNunchuck +80745450 MotionController::UpdateForCore +80745798 0x80745798 +80745924 0x80745924 +80745ab8 0x80745ab8 +80745b08 0x80745b08 +80745bd4 0x80745bd4 +80745dc8 0x80745dc8 +80745e28 0x80745e28 +80745fdc 0x80745fdc +80746168 0x80746168 +807462d0 0x807462d0 +807467c0 0x807467c0 +80746804 Objects::PoihanaBase::__ct +80746874 Objects::PoihanaBase::__dt +807468b4 Objects::PoihanaBase::OnStart +80746960 Objects::PoihanaBase::Update +80746974 Objects::PoihanaBase:GetTranslation +80746990 0x80746990 +807469ec 0x807469ec +80746a08 0x80746a08 +80746a70 0x80746a70 +80746b00 0x80746b00 +80746b50 0x80746b50 +80746b9c 0x80746b9c +80746c48 0x80746c48 +80746d44 0x80746d44 +80746df4 0x80746df4 +80746f98 UnkCollidableSub::__ct +80746fe0 UnkCollidableSub::__dt +80747020 UnkCollidableSub::Reset +80747040 UnkCollidableSub::Update +80747268 0x80747268 +80747284 UnkCollidableSub::vf_0x14 +807472ac Objects::PoihanaBase::SubChild::__ct +80747304 Objects::PoihanaBase::SubChild::__dt +80747344 Objects::PoihanaBase::SubChild::Reset +80747368 Objects::PoihanaBase::SubChild::Update +807475cc 0x807475cc +807477a4 Objects::Poihana::SubChild::vf_0x14 +807477c8 Objects::PoihanaBase::GetPropertiesBitfield +807477d0 Objects::PoihanaBase::__dt(thunk) +807477d8 Objects::Poihana::__ct +80747ee8 Objects::Poihana::Actions::__dt +80747f28 Objects::Poihana::__dt +80747fc4 Objects::Poihana::OnStart +807481dc Objects::Poihana::Update +80748240 0x80748240 +80748358 Objects::Poihana::LoadAnimations +80748404 0x80748404 +807489e4 Objects::Poihana::OnCollision +80748b70 Objects::Poihana::OnItemCollision +80748c7c 0x80748c7c +80748d30 0x80748d30 +80748e00 0x80748e00 +80748e74 0x80748e74 +80748e90 0x80748e90 +80748f18 Objects::Poihana::OnStartIdle +80748f90 Objects::Poihana::UpdateIdleAndAction1 +80749154 Objects::Poihana::OnStartChase +8074916c Objects::Poihana::UpdateChase +807495c0 0x807495c0 +807495dc Objects::Poihana::OnStartCatapult +80749770 Objects::Poihana::UpdateCatapult +807497ec Objects::Poihana::OnEndCatapult +807497f8 Objects::Poihana::OnStartCatapultNoMove +80749848 Objects::Poihana::UpdateCatapultNoMove +807498f8 Objects::Poihana::OnEndCatapultNoMove +80749904 Objects::Poihana::Topple +80749b10 Objects::Poihana::OnStartToppleNormal +80749b28 Objects::Poihana::OnStartToppleInverted +80749b44 Objects::Poihana::UpdateTopple +80749d8c Objects::Poihana::OnEndTopple +80749dc8 Objects::Poihana::OnStartToppleNoBury +80749f18 Objects::Poihana::UpdateToppleNoBury +8074a3a8 0x8074a3a8 +8074a3c4 Objects::Poihana::OnEndToppleNoBury +8074a3d0 Objects::Poihana::Actions::OnStart +8074a418 Objects::Poihana::Actions::Update +8074a448 Objects::Poihana::Actions::OnEnd +8074a490 Objects::Poihana::__dt(thunk) +8074a498 AI::Base::__ct +8074a5a4 AI::Base::UpdateActions +8074a620 AI::Base::SetInitialActions +8074a638 AI::Base::HasSameActions +8074a64c AI::Base::SetNextActions +8074a658 AI::Actions::OnActionStart +8074a6a0 AI::Actions::Update +8074a6d0 AI::Actions::OnActionEnd +8074a718 0x8074a718 +8074a764 0x8074a764 +8074a808 0x8074a808 +8074a9b8 0x8074a9b8 +8074aa88 0x8074aa88 +8074acd4 0x8074acd4 +8074ae60 0x8074ae60 +8074ae98 0x8074ae98 +8074af10 0x8074af10 +8074b014 0x8074b014 +8074b1a0 0x8074b1a0 +8074b238 0x8074b238 +8074b33c 0x8074b33c +8074b358 0x8074b358 +8074b35c 0x8074b35c +8074b4ac 0x8074b4ac +8074b594 0x8074b594 +8074b60c 0x8074b60c +8074b63c 0x8074b63c +8074b6b4 0x8074b6b4 +8074b720 0x8074b720 +8074b84c 0x8074b84c +8074b910 0x8074b910 +8074b920 0x8074b920 +8074b9b8 0x8074b9b8 +8074ba5c 0x8074ba5c +8074bb14 AwardCupModel::Disposer__dt +8074bc1c AwardCupModel::CreateInstance +8074bcec AwardCupModel::DestroyInstance +8074bda8 AwardCupModel::__ct +8074be4c AwardCupModel::__dt +8074bf14 AwardCupModel::Load +8074bf80 AwardCupModel::Load_switch +8074bf84 AwardCupModel::Load_caseD_0 +8074bfb8 AwardCupModel::Load_caseD_1 +8074bfec AwardCupModel::Load_caseD_2 +8074c020 AwardCupModel::Load_caseD_3 +8074c054 AwardCupModel::Load_caseD_4 +8074c088 AwardCupModel::Load_caseD_5 +8074c0bc AwardCupModel::Load_caseD_6 +8074c0f0 AwardCupModel::Load_caseD_7 +8074c124 AwardCupModel::Load_caseD_8 +8074c38c AwardCupModel::Prepare +8074c4bc AwardCupModel::Activate +8074c56c AwardCupModel::Update +8074c7f0 0x8074c7f0 +8074c958 0x8074c958 +8074c9fc 0x8074c9fc +8074caa8 0x8074caa8 +8074cbec 0x8074cbec +8074cc24 GlobeMgr::Disposer__dt +8074ccbc GlobeMgr::CreateInstance +8074cd38 GlobeMgr::DestroyInstance +8074cd6c EarthModel::__ct +8074d2d0 0x8074d2d0 +8074d334 EarthModel::__dt +8074d3b4 0x8074d3b4 +8074d5e4 0x8074d5e4 +8074d5e8 0x8074d5e8 +8074d5ec 0x8074d5ec +8074d5f0 0x8074d5f0 +8074d69c 0x8074d69c +8074d85c 0x8074d85c +8074d880 0x8074d880 +8074d998 0x8074d998 +8074da18 0x8074da18 +8074db40 0x8074db40 +8074dc6c 0x8074dc6c +8074dd98 0x8074dd98 +8074dec4 0x8074dec4 +8074dff0 0x8074dff0 +8074e11c 0x8074e11c +8074e248 0x8074e248 +8074e4f8 0x8074e4f8 +8074e874 GlobeMii::GetTranslation +8074e87c 0x8074e87c +8074e8cc 0x8074e8cc +8074e8ec 0x8074e8ec +8074e90c 0x8074e90c +8074e92c 0x8074e92c +8074e950 0x8074e950 +8074e970 0x8074e970 +8074ebc4 0x8074ebc4 +8074ede0 0x8074ede0 +8074f03c 0x8074f03c +8074f0ac 0x8074f0ac +8074f0ec 0x8074f0ec +8074f12c 0x8074f12c +8074f16c 0x8074f16c +8074f1b0 0x8074f1b0 +8074f1f0 0x8074f1f0 +8074f4a4 0x8074f4a4 +8074f4a8 GlobeMgr::__ct +8074f4f8 GlobeMgr::__dt +8074f5c0 GlobeMgr::Init +8074f684 0x8074f684 +8074f8a4 0x8074f8a4 +8074f960 0x8074f960 +8074f9b0 GlobeMgr::Update +8074fd34 0x8074fd34 +8074fd74 0x8074fd74 +8074fe58 0x8074fe58 +8074fe68 GlobeMgr::IsMiiEnabled +8074fe74 GlobeMgr::SetPosition +80750004 0x80750004 +80750008 0x80750008 +8075000c GlobeMgr::SetMii +80750020 GlobeMgr::DisplayMii +8075003c GlobeMgr::ResetGlobeMii +80750050 0x80750050 +80750118 GlobeMii::__ct +80750698 GlobeMii::Init +807507b0 GlobeMii::Update +80750874 GlobeMii::SetMii +80750b94 GlobeMii::IsFemaleMii +80750bac GlobeMii::DisplayMii +80750f28 GlobeMii::Reset +80750fa8 0x80750fa8 +80751034 0x80751034 +80751098 0x80751098 +807510d8 0x807510d8 +807510dc 0x807510dc +807510e0 0x807510e0 +807511b8 0x807511b8 +80751290 0x80751290 +80751298 0x80751298 +807512d8 0x807512d8 +80751318 0x80751318 +807513cc 0x807513cc +80751550 0x80751550 +80751924 0x80751924 +80751970 0x80751970 +80751ad8 0x80751ad8 +80751c2c 0x80751c2c +80751d70 0x80751d70 +80751e58 0x80751e58 +80752024 0x80752024 +80752090 0x80752090 +8075209c 0x8075209c +807520b0 0x807520b0 +80752110 0x80752110 +80752118 0x80752118 +80752120 0x80752120 +807521a0 0x807521a0 +807521e0 0x807521e0 +8075228c 0x8075228c +80752324 0x80752324 +80752398 0x80752398 +8075239c 0x8075239c +80752558 0x80752558 +80752610 0x80752610 +807526b4 0x807526b4 +8075272c 0x8075272c +807528d4 0x807528d4 +80752d0c 0x80752d0c +80752d80 0x80752d80 +80752d8c 0x80752d8c +80752d98 0x80752d98 +80752f54 0x80752f54 +80752fcc 0x80752fcc +80752fd0 0x80752fd0 +80753050 0x80753050 +80753068 0x80753068 +80753078 0x80753078 +807531a0 0x807531a0 +8075349c 0x8075349c +80753514 0x80753514 +80753518 0x80753518 +80753598 0x80753598 +8075359c 0x8075359c +807535a0 0x807535a0 +807535a4 0x807535a4 +807535a8 0x807535a8 +807535ac 0x807535ac +807535b0 0x807535b0 +807535b8 0x807535b8 +807535bc 0x807535bc +807535c0 0x807535c0 +807535c4 0x807535c4 +807535c8 0x807535c8 +807535d0 0x807535d0 +807535d8 0x807535d8 +80753628 0x80753628 +807536a0 0x807536a0 +807536a4 0x807536a4 +807536f4 0x807536f4 +8075376c 0x8075376c +80753770 0x80753770 +807538d0 0x807538d0 +80753fcc 0x80753fcc +8075405c 0x8075405c +80754068 0x80754068 +80754074 0x80754074 +80754140 0x80754140 +80754280 0x80754280 +8075428c 0x8075428c +80754298 0x80754298 +807542a4 0x807542a4 +807542b0 0x807542b0 +807542bc 0x807542bc +80754640 0x80754640 +8075477c 0x8075477c +80754830 0x80754830 +807548e0 0x807548e0 +8075499c 0x8075499c +80754a40 0x80754a40 +80754ae8 0x80754ae8 +80754f30 0x80754f30 +80755144 0x80755144 +807552c4 0x807552c4 +807552f8 0x807552f8 +8075560c 0x8075560c +80755734 0x80755734 +80755844 0x80755844 +807559cc 0x807559cc +80755be4 0x80755be4 +80755ea4 0x80755ea4 +80756078 0x80756078 +8075627c 0x8075627c +80756388 0x80756388 +80756438 0x80756438 +8075645c 0x8075645c +80756778 0x80756778 +8075682c 0x8075682c +80756b80 0x80756b80 +80756bf8 0x80756bf8 +80756c68 0x80756c68 +80756ca4 0x80756ca4 +80756cdc 0x80756cdc +80756dd0 0x80756dd0 +80756f44 BegomanManager::__ct +80756fb8 0x80756fb8 +80756fbc 0x80756fbc +80757424 0x80757424 +80757440 0x80757440 +80757474 0x80757474 +807574fc 0x807574fc +8075754c 0x8075754c +807577f4 0x807577f4 +8075780c 0x8075780c +807578d8 0x807578d8 +807579d4 0x807579d4 +80757ab0 0x80757ab0 +80757c3c 0x80757c3c +80757ce0 0x80757ce0 +80757ff0 0x80757ff0 +807580d4 0x807580d4 +807580dc 0x807580dc +807580e8 0x807580e8 +807580f0 0x807580f0 +807580f4 0x807580f4 +807580f8 0x807580f8 +807580fc 0x807580fc +80758100 0x80758100 +80758104 0x80758104 +80758108 0x80758108 +80758110 0x80758110 +80758114 0x80758114 +80758118 0x80758118 +8075811c 0x8075811c +80758120 0x80758120 +80758124 0x80758124 +80758128 0x80758128 +80758130 0x80758130 +80758170 0x80758170 +807581b0 0x807581b0 +807581f0 0x807581f0 +80758230 0x80758230 +80758238 0x80758238 +80758240 0x80758240 +80758248 0x80758248 +8075855c 0x8075855c +8075859c 0x8075859c +807585d4 0x807585d4 +807589d0 0x807589d0 +807589f4 0x807589f4 +80758d5c 0x80758d5c +8075903c 0x8075903c +80759044 0x80759044 +8075904c 0x8075904c +80759068 0x80759068 +80759424 0x80759424 +8075944c 0x8075944c +80759554 0x80759554 +80759a04 0x80759a04 +80759a38 0x80759a38 +80759b24 0x80759b24 +80759bd8 0x80759bd8 +80759c08 0x80759c08 +80759e90 0x80759e90 +80759ed0 0x80759ed0 +80759f70 0x80759f70 +8075a010 0x8075a010 +8075a134 0x8075a134 +8075a4ec cFielder_IsStriker +8075a4fc 0x8075a4fc +8075a628 0x8075a628 +8075a6f8 0x8075a6f8 +8075a7e4 0x8075a7e4 +8075a860 0x8075a860 +8075a8cc 0x8075a8cc +8075a950 0x8075a950 +8075aa3c 0x8075aa3c +8075ab90 0x8075ab90 +8075ac88 0x8075ac88 +8075acc8 0x8075acc8 +8075ad00 0x8075ad00 +8075adc0 0x8075adc0 +8075b2d8 0x8075b2d8 +8075b420 0x8075b420 +8075b604 0x8075b604 +8075b71c 0x8075b71c +8075b90c 0x8075b90c +8075b928 0x8075b928 +8075bac0 0x8075bac0 +8075bb88 0x8075bb88 +8075bcc4 0x8075bcc4 +8075bef4 0x8075bef4 +8075bf7c 0x8075bf7c +8075bfc4 0x8075bfc4 +8075c00c 0x8075c00c +8075c250 0x8075c250 +8075c2a0 0x8075c2a0 +8075c2c4 0x8075c2c4 +8075c3e8 0x8075c3e8 +8075c48c 0x8075c48c +8075c598 0x8075c598 +8075c66c 0x8075c66c +8075c67c 0x8075c67c +8075c6a0 0x8075c6a0 +8075c7a8 0x8075c7a8 +8075c7b0 0x8075c7b0 +8075c8d8 0x8075c8d8 +8075c9e4 0x8075c9e4 +8075cbf8 0x8075cbf8 +8075cef8 0x8075cef8 +8075cf90 0x8075cf90 +8075d03c 0x8075d03c +8075d044 0x8075d044 +8075d04c 0x8075d04c +8075d058 0x8075d058 +8075d060 0x8075d060 +8075d068 0x8075d068 +8075d074 0x8075d074 +8075d080 0x8075d080 +8075d08c 0x8075d08c +8075d098 0x8075d098 +8075d0d8 0x8075d0d8 +8075d118 0x8075d118 +8075d158 0x8075d158 +8075d190 0x8075d190 +8075d198 0x8075d198 +8075d1a0 0x8075d1a0 +8075d1a8 0x8075d1a8 +8075d20c 0x8075d20c +8075d308 0x8075d308 +8075d30c 0x8075d30c +8075d4ac 0x8075d4ac +8075d518 0x8075d518 +8075d6dc 0x8075d6dc +8075d7d8 0x8075d7d8 +8075d860 0x8075d860 +8075d8f8 0x8075d8f8 +8075d94c 0x8075d94c +8075dd54 0x8075dd54 +8075dda8 0x8075dda8 +8075ddb0 0x8075ddb0 +8075ddb8 0x8075ddb8 +8075ddf8 0x8075ddf8 +8075de70 0x8075de70 +8075deb0 0x8075deb0 +8075dff4 0x8075dff4 +8075dff8 0x8075dff8 +8075e100 0x8075e100 +8075e160 0x8075e160 +8075e168 obj_dossunc::__ct +8075e438 0x8075e438 +8075e4d4 0x8075e4d4 +8075e514 0x8075e514 +8075e888 0x8075e888 +8075e8c0 obj_dossun_active_update +8075ea60 0x8075ea60 +8075ea9c 0x8075ea9c +8075eacc 0x8075eacc +8075eb44 0x8075eb44 +8075eb8c 0x8075eb8c +8075ebf0 0x8075ebf0 +8075edd8 0x8075edd8 +8075f074 0x8075f074 +8075f1bc 0x8075f1bc +8075f2e8 0x8075f2e8 +8075f438 0x8075f438 +8075f4ec 0x8075f4ec +8075f4f8 obj_dossun_endFall +8075f50c 0x8075f50c +8075f574 0x8075f574 +8075f604 0x8075f604 +8075f784 0x8075f784 +8075f7f4 0x8075f7f4 +8075f8a8 0x8075f8a8 +8075f94c obj_dossun_update +8075fafc 0x8075fafc +8075fc58 0x8075fc58 +8075fca0 0x8075fca0 +8075fe8c 0x8075fe8c +8075ffd0 obj_dossun_make_active +807600b0 0x807600b0 +80760140 0x80760140 +8076018c 0x8076018c +80760240 0x80760240 +807602c8 0x807602c8 +80760384 0x80760384 +807603f8 0x807603f8 +80760a08 0x80760a08 +80760b3c 0x80760b3c +80760d34 0x80760d34 +80760dac 0x80760dac +80760db0 0x80760db0 +80760ff8 0x80760ff8 +807616c0 0x807616c0 +807617fc 0x807617fc +80761a18 0x80761a18 +80761b5c 0x80761b5c +80761c5c 0x80761c5c +80762558 0x80762558 +8076273c 0x8076273c +80762888 0x80762888 +80762b2c 0x80762b2c +80762f64 0x80762f64 +80762f84 0x80762f84 +80762fa8 0x80762fa8 +8076306c 0x8076306c +80763070 0x80763070 +8076307c 0x8076307c +807631cc 0x807631cc +80763280 0x80763280 +80763478 0x80763478 +80763518 0x80763518 +807635d8 0x807635d8 +807636c0 0x807636c0 +8076375c 0x8076375c +80763950 0x80763950 +80763964 0x80763964 +80763a0c 0x80763a0c +80763b04 0x80763b04 +80763b7c 0x80763b7c +80763c30 0x80763c30 +80763c70 0x80763c70 +80763c74 0x80763c74 +80763cb0 0x80763cb0 +80763d10 0x80763d10 +80763e08 0x80763e08 +80763f10 0x80763f10 +80764010 0x80764010 +80764070 0x80764070 +80764078 0x80764078 +80764080 0x80764080 +80764088 0x80764088 +8076408c 0x8076408c +80764090 0x80764090 +80764094 0x80764094 +80764098 0x80764098 +8076409c 0x8076409c +807640a4 0x807640a4 +807640a8 0x807640a8 +807640f8 0x807640f8 +80764170 0x80764170 +80764174 0x80764174 +807641b4 0x807641b4 +807641f4 0x807641f4 +80764234 0x80764234 +807642b4 0x807642b4 +807642f4 0x807642f4 +80764334 obj_Epropeller::__ct +80764428 0x80764428 +807644a0 obj_Epropeller::__dt +80764520 obj_Epropeller_0x0c +807646d0 0x807646d0 +807646d4 obj_Epropeller_update +807647fc 0x807647fc +80764918 0x80764918 +80764a14 obj_Epropeller_updateEffect +80764bc4 0x80764bc4 +80764c20 0x80764c20 +80764da0 0x80764da0 +80764da4 0x80764da4 +80764f4c 0x80764f4c +80764f9c 0x80764f9c +807650c0 0x807650c0 +8076522c 0x8076522c +80765234 0x80765234 +80765284 0x80765284 +807652fc 0x807652fc +80765300 0x80765300 +807653a4 0x807653a4 +8076541c 0x8076541c +8076549c 0x8076549c +807657a8 0x807657a8 +807657ac 0x807657ac +807657b0 0x807657b0 +80765964 0x80765964 +80765dc0 0x80765dc0 +80765e48 0x80765e48 +80765ed0 0x80765ed0 +80765f40 0x80765f40 +80766034 0x80766034 +80766074 0x80766074 +807660c0 0x807660c0 +807660c4 0x807660c4 +80766104 0x80766104 +80766144 0x80766144 +80766184 0x80766184 +807661c4 0x807661c4 +80766218 0x80766218 +80766220 0x80766220 +8076622c 0x8076622c +80766238 0x80766238 +80766310 0x80766310 +80766318 0x80766318 +8076631c 0x8076631c +80766324 0x80766324 +80766330 0x80766330 +8076633c 0x8076633c +80766348 0x80766348 +80766354 0x80766354 +80766360 0x80766360 +8076636c 0x8076636c +807663bc 0x807663bc +80766434 0x80766434 +80766438 0x80766438 +80766478 0x80766478 +807664b8 0x807664b8 +807664f8 0x807664f8 +807665b8 Objects::Karehayama::__ct +807665f4 Objects::Karehayama::__dt +8076664c Objects::Karehayama::OnStart +807666a4 Objects::Karehayama::LoadEffects +80766780 Objects::Karehayama::CreateCollisionEffectSoft +80766848 Objects::Karehayama::CreateCollisionEffect +807668b8 Objects::Karehayama::CreateExplosionEffect +807668bc Objects::Karehayama::Respawn +80766910 Objects::Karehayama::DropItem +807669b8 Objects::Karehayama::OnNormalCollision +80766ab4 Objects::Karehayama::OnImperviousCollision +80766be8 Objects::Karehayama::OnNormalItemCollision +80766cb4 Objects::Karehayama::OnImperviousItemCollision +80766d70 Objects::Karehayama::LoadShadow +80766e4c Object::ItemDropper::UpdateRespawn +80766e50 Object::ItemDropper::GetPropertiesBitfield +80766e58 Objects::Karehayama::LoadAnimations +80766eac Objects::Karehayama::vf_0x114 +80766eb4 Objects::Karehayama::OnWallCollision +80766eb8 Objects::Karehayama::GetBRRESName +80766f0c Objects::Karehayama::GetSubFileName +80766f60 0x80766f60 +807673dc 0x807673dc +80767454 0x80767454 +80767458 0x80767458 +80767470 0x80767470 +80767660 0x80767660 +80767a5c 0x80767a5c +80767a74 0x80767a74 +80767cbc 0x80767cbc +80767d04 0x80767d04 +80767d24 0x80767d24 +80767d28 0x80767d28 +80767d7c 0x80767d7c +80767d88 0x80767d88 +80767d94 0x80767d94 +80767d9c 0x80767d9c +80767da0 0x80767da0 +80767da4 0x80767da4 +80767da8 0x80767da8 +80767dac 0x80767dac +80767db4 0x80767db4 +80767dfc 0x80767dfc +80767e44 0x80767e44 +80767e4c 0x80767e4c +80767e9c 0x80767e9c +80767f14 0x80767f14 +80767f18 0x80767f18 +80767f98 0x80767f98 +80768018 0x80768018 +80768058 Objects::Hanabi::__ct +807680bc Objects::Hanabi::__dt +807680fc Objects::Hanabi::OnStart +80768150 0x80768150 +80768164 Objects::Hanabi::Update +80768284 0x80768284 +80768374 Objects::Hanabi::LoadClipInfo +80768378 Objects::Hanabi::LoadCollision +8076837c Objects::Hanabi::LoadAnimations +80768380 Objects::Hanabi::LoadModels +80768384 Objects::Hanabi::GetPropertiesBitfield +8076838c ObjVeniceGondola_construct +807683f0 ObjVeniceGondola_destruct +80768430 0x80768430 +80768578 0x80768578 +8076857c 0x8076857c +80768864 0x80768864 +807688ec 0x807688ec +80768974 0x80768974 +807689dc 0x807689dc +80768a18 0x80768a18 +80768a58 0x80768a58 +80768a98 0x80768a98 +80768b54 0x80768b54 +80768bf0 0x80768bf0 +80768bfc 0x80768bfc +80768c08 0x80768c08 +80768c10 0x80768c10 +80768c74 0x80768c74 +80768c7c 0x80768c7c +80768c88 0x80768c88 +80768c94 0x80768c94 +80768c9c 0x80768c9c +80768ca0 0x80768ca0 +80768d38 0x80768d38 +80768e00 0x80768e00 +80768e40 0x80768e40 +80768ea8 0x80768ea8 +80768eac 0x80768eac +80768fec 0x80768fec +80769004 0x80769004 +8076919c 0x8076919c +807691fc 0x807691fc +807695f0 0x807695f0 +80769690 0x80769690 +807697b4 0x807697b4 +80769868 0x80769868 +80769924 0x80769924 +807699a4 0x807699a4 +80769a1c 0x80769a1c +80769b74 0x80769b74 +80769bcc 0x80769bcc +80769bd8 0x80769bd8 +80769ca4 0x80769ca4 +80769e90 0x80769e90 +80769e94 0x80769e94 +80769f14 0x80769f14 +80769f8c 0x80769f8c +8076a040 0x8076a040 +8076a04c 0x8076a04c +8076a050 0x8076a050 +8076a418 0x8076a418 +8076a41c 0x8076a41c +8076a614 0x8076a614 +8076a6ec 0x8076a6ec +8076a8a4 0x8076a8a4 +8076a970 0x8076a970 +8076ab2c 0x8076ab2c +8076abc0 0x8076abc0 +8076affc 0x8076affc +8076b000 0x8076b000 +8076b078 0x8076b078 +8076b0f0 0x8076b0f0 +8076b0f4 0x8076b0f4 +8076b1b0 0x8076b1b0 +8076b200 0x8076b200 +8076b460 0x8076b460 +8076b6a4 0x8076b6a4 +8076b7c0 0x8076b7c0 +8076b860 0x8076b860 +8076b994 0x8076b994 +8076ba8c 0x8076ba8c +8076ba90 0x8076ba90 +8076ba94 0x8076ba94 +8076ba98 0x8076ba98 +8076ba9c 0x8076ba9c +8076baa4 0x8076baa4 +8076baa8 0x8076baa8 +8076baac 0x8076baac +8076bab0 0x8076bab0 +8076bab4 0x8076bab4 +8076babc 0x8076babc +8076bac4 0x8076bac4 +8076bb14 0x8076bb14 +8076bb8c 0x8076bb8c +8076bb90 0x8076bb90 +8076bbe0 0x8076bbe0 +8076bc58 0x8076bc58 +8076bc5c 0x8076bc5c +8076bcac 0x8076bcac +8076bd24 0x8076bd24 +8076bd28 0x8076bd28 +8076bde0 0x8076bde0 +8076bec4 0x8076bec4 +8076bec8 Objects::W_Itembox::__ct +8076c034 Objects::SubObjectArray::__dt +8076c0ac Objects::SubObjectArray::vf_0x18 +8076c0b0 Objects::W_Itembox::__dt +8076c130 Objects::W_Itembox::OnStart +8076c168 0x8076c168 +8076c174 Objects::W_Itembox::Update +8076c264 0x8076c264 +8076c334 Objects::W_Itembox::Box::__ct +8076c370 Objects::W_Itembox::Box::__dt +8076c3b0 Objects::W_Itembox::Box::OnStart +8076c3c0 0x8076c3c0 +8076c424 Objects::W_Itembox::Box::Update +8076c51c 0x8076c51c +8076c568 Objects::W_Itembox::Box::OnCollision +8076c5a0 Objects::W_Itembox::Box::OnItemCollision +8076c5a8 Objects::W_Itembox::UpdateModel +8076c5ac Objects::W_Itembox::LoadClipInfo +8076c5b0 Objects::W_Itembox::LoadCollision +8076c5b4 Objects::W_Itembox::LoadAnimations +8076c5b8 Objects::W_Itembox::LoadModels +8076c5bc Objects::W_Itembox::GetPropertiesBitfield +8076c5c4 Objects::W_Itembox::Box::GetSubFileName +8076c5d0 Objects::W_Itembox::Box::GetBRRESName +8076c5dc Objects::W_Itembox::Box::GetPropertiesBitfield +8076c5e4 Objects::SubObjectArray::CreateArray +8076c634 Objects::SubObjectArray::CreateArray(heap) +8076c6ac Objects::SubObjectArray::vf_0x14 +8076c6b0 Objects::W_Itemboxline::__ct +8076cacc Objects::SubObjectArray::__dt +8076cb44 Objects::SubObjectArray::__dt +8076cbbc Objects::SubObjectArray::vf_0x18 +8076cbc0 Objects::SubObjectArray::vf_0x18 +8076cbc4 Objects::W_Itemboxline::__dt +8076cc70 Objects::W_Itemboxline::OnStart +8076ccac 0x8076ccac +8076ccb8 Objects::W_Itemboxline::Update +8076ce94 0x8076ce94 +8076d050 Objects::W_Itemboxline::Box::GetID +8076d0b4 Objects::W_Itemboxline::Box::__dt +8076d0f4 Objects::W_Itemboxline::Box::OnStart +8076d104 0x8076d104 +8076d160 Objects::W_Itemboxline::Box::Update +8076d5b0 0x8076d5b0 +8076d728 Objects::W_Itemboxline::Box::OnCollision +8076d760 0x8076d760 +8076d7d0 Objects::W_Itemboxline::Block::__dt +8076d810 Objects::W_Itemboxline::Block::OnStart +8076d87c 0x8076d87c +8076d92c Objects::W_Itemboxline::Block::Update +8076da6c 0x8076da6c +8076db54 Objects::W_Itemboxline::Block::OnCollision +8076dc44 Objects::W_Itemboxline::Block::OnItemCollision +8076dd08 0x8076dd08 +8076de18 Objects::W_Itemboxline::Press::__ct +8076de84 Objects::W_Itemboxline::Press::__dt +8076dedc Objects::W_Itemboxline::Press::TryFall +8076df1c Objects::W_Itemboxline::Press::UpdateEffect +8076e014 Objects::W_Itemboxline::UpdateModel +8076e018 Objects::W_Itemboxline::LoadClipInfo +8076e01c Objects::W_Itemboxline::LoadCollision +8076e020 Objects::W_Itemboxline::LoadAnimations +8076e024 Objects::W_Itemboxline::LoadModels +8076e028 Objects::W_Itemboxline::GetPropertiesBitfield +8076e030 0x8076e030 +8076e038 0x8076e038 +8076e044 0x8076e044 +8076e050 Objects::W_Itemboxline::Box::GetPropertiesBitfield +8076e058 Objects::W_Itemboxline::Block::GetPropertiesBitfield +8076e060 Objects::W_Itemboxline::Block::GetBRRESName +8076e06c Objects::W_Itemboxline::Block::GetSubFileName +8076e078 Objects::Press::GetCollisionDiameter +8076e084 Objects::Press::GetShadowListIdx +8076e08c Objects::W_Itemboxline::Press::GetPropertiesBitfield +8076e094 Objects::W_Itemboxline::Press::GetID +8076e09c Objects::W_Itemboxline::Press::GetBRRESName +8076e0a8 Objects::W_Itemboxline::Press::GetSubFileName +8076e0b4 Objects::SubObjectArray::CreateArray +8076e104 Objects::SubObjectArray::CreateArray(heap) +8076e17c Objects::SubObjectArray::vf_0x14 +8076e180 Objects::SubObjectArray::CreateArray +8076e1d0 Objects::SubObjectArray::CreateArray(heap) +8076e248 Objects::SubObjectArray::vf_0x14 +8076e24c Objects::ItemDropper::__ct +8076e294 Objects::ItemDropper::__dt +8076e2d4 Objects::ItemDropper::OnStart +8076e384 Objects::ItemDropper::LoadEffects +8076e388 Objects::ItemDropper::Update +8076e3dc Objects::ItemDropper::RespawnImpl +8076e440 Objects::ItemDropper::Respawn +8076e450 Objects::ItemDropper::DropItem +8076e648 Objects::ItemDropper::CreateExplosionEffect +8076e718 Objects::ItemDropper::OnCollision +8076e840 Objects::ItemDropper::OnNormalCollision +8076e844 Objects::ItemDropper::OnImperviousCollision +8076e848 Objects::ItemDropper::OnItemCollision +8076e944 Objects::ItemDropper::OnNormalItemCollision +8076e948 Objects::ItemDropper::OnImperviousItemCollision +8076e94c Objects::DKRockGC::__ct +8076e9b0 Objects::DKRockGC::__dt +8076e9f0 Objects::DKRockGC::OnStart +8076ebf8 0x8076ebf8 +8076ebfc Objects::DKRockGC::Update +8076edd4 0x8076edd4 +8076eed4 0x8076eed4 +8076ef88 0x8076ef88 +8076f0cc 0x8076f0cc +8076f3fc 0x8076f3fc +8076f62c 0x8076f62c +8076f6d4 Objects::DKRockGC::OnCollision +8076f864 Objects::DKRockGC::OnItemCollision +8076f8f8 Objects::DKRockGC::UpdateShadow +8076f9d8 Objects::DKRockGC::GetCollisionTranslation +8076f9e0 Objects::DKRockGC::GetShadowListIdx +8076f9e8 Objects::DKRockGC::GetPropertiesBitfield +8076f9f0 Objects::KoopaBall::__ct +8076fa3c Objects::KoopaBall::OnStart +8076fe08 0x8076fe08 +8076fe18 0x8076fe18 +8076ff90 0x8076ff90 +807700d0 0x807700d0 +80770148 Objects::KoopaBall::Update +807705b8 0x807705b8 +807708b4 0x807708b4 +80770990 0x80770990 +80770b88 0x80770b88 +80770c90 0x80770c90 +80770de0 0x80770de0 +80770f3c 0x80770f3c +8077100c 0x8077100c +80771054 0x80771054 +807711bc 0x807711bc +80771238 0x80771238 +80771260 Objects::KoopaBall::OnCollision +80771490 Objects::KoopaBall::UpdateShadow +807715cc Objects::KoopaBall::GetCollisionTranslation +807715d4 Objects::KoopaBall::GetPropertiesBitfield +807715dc Objects::KoopaBall::__dt +8077161c 0x8077161c +807716c0 0x807716c0 +80771758 0x80771758 +807717a8 0x807717a8 +80771988 0x80771988 +80771ab4 0x80771ab4 +80771b70 0x80771b70 +80771b9c 0x80771b9c +80771cbc 0x80771cbc +80771d20 0x80771d20 +80771d28 0x80771d28 +80771d30 0x80771d30 +80771d70 0x80771d70 +80771db0 0x80771db0 +80771dc8 0x80771dc8 +80772188 0x80772188 +807722e4 0x807722e4 +807722e8 0x807722e8 +80772328 0x80772328 +80772368 0x80772368 +807726f8 0x807726f8 +80772700 0x80772700 +80772740 Objects::MiiObj::__ct +80772780 Objects::MiiObj::__dt +807727ec Objects::MiiObj::OnStart +807727f8 Objects::MiiObj::LoadModels +80772d2c Objects::MiiObj::GetPropertiesBitfield +80772d34 Objects::MiiPoster::__ct +80772d74 Objects::MiiPoster::__dt +80772d80 Objects::MiiPoster::OnStart +80772f54 Objects::MiiPoster::LoadModels +80772f5c Objects::MiiPoster::GetPropertiesBitfield +80772f9c Objects::MiiKanban::__ct +80772fdc Objects::MiiKanban::LoadModels +80773274 Objects::MiiKanban::OnStart +80773280 Objects::MiiKanban::GetPropertiesBitfield +80773288 Objects::MiiKanban::__dt +807732c8 ObjMonteA_construct +8077336c 0x8077336c +80773418 0x80773418 +807736b0 0x807736b0 +80773758 0x80773758 +80773874 0x80773874 +80773964 0x80773964 +80773a08 0x80773a08 +80773a10 0x80773a10 +80773a50 0x80773a50 +80773dbc 0x80773dbc +80773dc0 0x80773dc0 +8077406c 0x8077406c +807740f0 0x807740f0 +80774288 0x80774288 +807742ec 0x807742ec +8077431c 0x8077431c +80774524 0x80774524 +8077458c 0x8077458c +80774698 0x80774698 +80774774 0x80774774 +80774a20 0x80774a20 +80774ac4 0x80774ac4 +80774ad0 0x80774ad0 +80774b58 0x80774b58 +80774b60 0x80774b60 +80774b68 0x80774b68 +80774ba8 0x80774ba8 +80774be8 0x80774be8 +80774c80 0x80774c80 +80774c88 0x80774c88 +80774c90 0x80774c90 +80774cdc Objects::Penguin::__dt +80774d1c Objects::Penguin::OnStart +80774dc4 0x80774dc4 +80774dd0 Objects::Penguin::Update +80774e0c Objects::Penguin::UpdateWithRot +80774e70 Objects::Penguin::UpdateNoRot +80774ef8 Objects::Penguin::vf_0x104 +80774fbc Objects::Penguin::UpdateMtxNoRot +80775188 Objects::Penguin::UpdateMtxWithRot +80775210 0x80775210 +80775298 Objects::Penguin::UpdatePosition +807752c4 Objects::Penguin::OnCollision +8077534c Objects::Penguin::OnItemCollision +80775398 Objects::Penguin::SpinOut +807754cc Objects::Penguin_s::__ct +80775630 Objects::PenguinUnkObj::LoadAnimations +807756dc Objects::Penguin_s::__dt +8077571c Objects::Penguin_s::OnStart +807757f4 0x807757f4 +80775804 Objects::Penguin_s::Update +807759e8 Objects::Penguin_s::UpdateWithRot +80775a3c 0x80775a3c +80775b04 0x80775b04 +80775cdc 0x80775cdc +80775d54 Objects::Penguin_s::UpdateNoRot +80775f0c 0x80775f0c +8077615c Objects::Penguin_s::vf_0x104 +807761e8 0x807761e8 +80776200 0x80776200 +807762c4 0x807762c4 +80776348 0x80776348 +807763fc Objects::Penguin_s::SpinOut +80776538 Objects::Penguin_s::UpdateModelMatrix +807766b8 0x807766b8 +807766f8 Objects::Penguin_m::__ct +8077679c Objects::Penguin_l::__ct +80776848 Objects::Penguin_l::OnStart +807768f0 Objects::Penguin_l::UpdateModelMatrix +807768f4 0x807768f4 +80776934 Objects::Penguin::LoadAnimations +80776988 Objects::Penguin::vf_0xec +80776990 Objects::Penguin::GetPropertiesBitfield +80776998 Objects::Penguin_l::DoCalcShadowMtx +807769a0 0x807769a0 +807769f4 0x807769f4 +807769fc 0x807769fc +80776a00 0x80776a00 +80776a08 Objects::Penguin_s::LoadAnimations +80776ab4 Objects::Penguin_s::vf_0xec +80776abc Objects::PenguinUnkObj::vf_0xec +80776ac4 Objects::PenguinUnkObj::Update +80776ac8 Objects::PenguinUnkObj::GetScnObjDrawOptionsIdx +80776ad0 Objects::PenguinUnkObj::__dt +80776b10 Objects::Penguin_m::_dt +80776b50 0x80776b50 +80776b90 Objects::Penguin_l::__dt +80776bd0 Objects::Press::__ct +80776c68 Objects::Press::OnStart +80776ca8 0x80776ca8 +80776ed8 0x80776ed8 +80776ef8 Objects::Press::Update +807770fc Objects::Press::TryFall +807771c0 0x807771c0 +807771fc 0x807771fc +8077722c 0x8077722c +8077731c 0x8077731c +8077737c Objects::Press::UpdateColliding +80777564 Objects::Press::UpdateEffect +80777634 0x80777634 +807776ec 0x807776ec +807776f8 0x807776f8 +807777ac 0x807777ac +807777b8 0x807777b8 +807777d4 0x807777d4 +80777884 0x80777884 +80777940 Objects::Press::OnCollision +80777a78 Objects::Press::LoadCollision +80777d50 Objects::Press::LoadAnimations +80777e54 Objects::Press::GetPropertiesBitfield +80777e5c Objects::Dokan_sfc::__ct +80777e9c Objects::Dokan_sfc::OnStart +80777f34 Objects::Dokan_sfc::Update +80777fb8 0x80777fb8 +80778028 0x80778028 +8077820c 0x8077820c +80778278 Objects::Dokan_sfc::OnCollision +80778330 Objects::Dokan_sfc::OnItemCollision +807783bc Objects::Dokan_sfc::UpdateCollision +80778514 Objects::Dokan_sfc::UpdateShadow +807785c8 Objects::Dokan_sfc::LoadAnimations +80778648 Objects::Dokan_sfc::vf_0xec +80778650 Objects::Dokan_sfc::GetPropertiesBitfield +80778658 Objects::Dokan_sfc::__dt +80778698 0x80778698 +807786d8 0x807786d8 +807787dc 0x807787dc +807787e0 0x807787e0 +80778888 0x80778888 +807789fc 0x807789fc +80778a6c 0x80778a6c +80778c10 0x80778c10 +80778c98 0x80778c98 +80778d20 0x80778d20 +80778d88 0x80778d88 +807790d4 0x807790d4 +807793c8 0x807793c8 +807794d4 0x807794d4 +80779558 0x80779558 +80779560 0x80779560 +80779568 0x80779568 +807795a8 0x807795a8 +80779814 0x80779814 +80779854 0x80779854 +807799c8 nlListContainer__ct +807799d8 0x807799d8 +80779c64 0x80779c64 +80779d40 0x80779d40 +80779f24 0x80779f24 +8077a0e4 0x8077a0e4 +8077a204 0x8077a204 +8077a328 0x8077a328 +8077a34c 0x8077a34c +8077a3cc 0x8077a3cc +8077a8b4 0x8077a8b4 +8077a9c4 0x8077a9c4 +8077aa00 0x8077aa00 +8077aa40 0x8077aa40 +8077aabc 0x8077aabc +8077ac28 0x8077ac28 +8077b084 0x8077b084 +8077b0ec 0x8077b0ec +8077b204 0x8077b204 +8077b24c 0x8077b24c +8077b28c 0x8077b28c +8077b2d4 0x8077b2d4 +8077b314 0x8077b314 +8077b39c 0x8077b39c +8077b3a4 0x8077b3a4 +8077b3ac 0x8077b3ac +8077b3b0 0x8077b3b0 +8077b3bc 0x8077b3bc +8077b3c8 0x8077b3c8 +8077b3d4 0x8077b3d4 +8077b3e0 0x8077b3e0 +8077b3ec 0x8077b3ec +8077b5b0 0x8077b5b0 +8077b628 0x8077b628 +8077b62c 0x8077b62c +8077b630 0x8077b630 +8077b634 0x8077b634 +8077b83c 0x8077b83c +8077b88c 0x8077b88c +8077b958 0x8077b958 +8077b95c 0x8077b95c +8077b960 0x8077b960 +8077b9b0 0x8077b9b0 +8077b9f0 0x8077b9f0 +8077bb6c 0x8077bb6c +8077bb70 0x8077bb70 +8077bbe8 0x8077bbe8 +8077bbec 0x8077bbec +8077bc4c 0x8077bc4c +8077be58 0x8077be58 +8077be5c 0x8077be5c +8077bf60 0x8077bf60 +8077c1c0 0x8077c1c0 +8077c220 0x8077c220 +8077c2e4 0x8077c2e4 +8077c338 0x8077c338 +8077c340 0x8077c340 +8077c348 0x8077c348 +8077c34c 0x8077c34c +8077c350 0x8077c350 +8077c354 0x8077c354 +8077c358 0x8077c358 +8077c35c 0x8077c35c +8077c360 0x8077c360 +8077c368 0x8077c368 +8077c3b8 0x8077c3b8 +8077c430 0x8077c430 +8077c434 0x8077c434 +8077c4b4 0x8077c4b4 +8077c4f4 0x8077c4f4 +8077c534 Objects::Sin_ItemBox::__ct +8077c570 Objects::Sin_ItemBox::__dt +8077c5b0 Objects::Sin_ItemBox::OnStart +8077c690 Objects::Sin_ItemBox::Update +8077c7d4 0x8077c7d4 +8077c8e0 Objects::Sin_ItemBox::GetPropertiesBitfield +8077c8e8 obj_inseki::__ct +8077c9b8 0x8077c9b8 +8077c9f8 0x8077c9f8 +8077ca40 obj_inseki_update +8077cb48 0x8077cb48 +8077cb50 0x8077cb50 +8077cbb4 0x8077cbb4 +8077cbf4 0x8077cbf4 +8077ccb0 0x8077ccb0 +8077ccd8 0x8077ccd8 +8077ce3c 0x8077ce3c +8077cea0 0x8077cea0 +8077cfac 0x8077cfac +8077d01c 0x8077d01c +8077d030 0x8077d030 +8077d034 0x8077d034 +8077d038 0x8077d038 +8077d03c 0x8077d03c +8077d044 Objects::Fall::__ct +8077d37c Objects::Fall::__dt +8077d3bc Objects::Fall::OnStart +8077d3c0 Objects::Fall::Update +8077d4a4 0x8077d4a4 +8077d588 Objects::Fall::GetPropertiesBitfield +8077d590 Objects::W_Woodbox::__ct +8077d710 Objects::SubObjectArray::__dt +8077d788 Objects::SubObjectArray::vf_0x18 +8077d78c Objects::W_Woodbox::__dt +8077d80c Objects::W_Woodbox::OnStart +8077d844 0x8077d844 +8077d850 Objects::W_Woodbox::Update +8077d914 0x8077d914 +8077d9b8 Objects::W_Woodbox::Box::__ct +8077d9f4 Objects::W_Woodbox::Box::__dt +8077da50 Objects::W_Woodbox::Box::OnStart +8077dab0 Objects::W_Woodbox::Box::RespawnImpl +8077db08 Objects::W_Woodbox::Box::Update +8077dbd8 0x8077dbd8 +8077dc50 Objects::Woodbox::__ct +8077dc8c Objects::Woodbox::__dt +8077dce4 Objects::Woodbox::OnStart +8077dd24 Objects::Woodbox::LoadEffects +8077dd70 Objects::Woodbox::DropItem +8077ddbc Objects::Woodbox::Respawn +8077de1c Objects::Woodbox::UpdateRespawn +8077de4c Objects::Woodbox::UpdateRespawnImpl +8077df94 Objects::Woodbox::OnNormalCollision +8077e02c Objects::Woodbox::OnImperviousCollision +8077e0d8 Objects::Woodbox::OnNormalItemCollision +8077e174 Objects::Woodbox::OnImperviousItemCollision +8077e224 Objects::Woodbox::UpdateCollision +8077e334 Objects::W_Woodbox::UpdateModel +8077e338 Objects::W_Woodbox::LoadClipInfo +8077e33c Objects::W_Woodbox::LoadCollision +8077e340 Objects::W_Woodbox::LoadAnimations +8077e344 Objects::W_Woodbox::LoadModels +8077e348 Objects::W_Woodbox::GetPropertiesBitfield +8077e350 Objects::Woodbox::InitEntity +8077e3dc Objects::Woodbox::GetBRRESName +8077e3e8 Objects::Woodbox::GetSubFileName +8077e410 Objects::W_Woodbox::Box::GetPropertiesBitfield +8077e418 Objects::Woodbox::GetPropertiesBitfield +8077e420 Objects::SubObjectArray::CreateArray +8077e470 Objects::SubObjectArray::CreateArray(Heap) +8077e4e8 Objects::SubObjectArray::vf_0x14 +8077e4ec MiiRenderMgr::Disposer__dt +8077e5f0 MiiRenderMgr::CreateInstance +8077e67c MiiRenderMgr::DestroyInstance +8077e734 MiiRenderMgr::__ct +8077e794 0x8077e794 +8077e7d4 MiiRenderMgr::__dt +8077e898 MiiRenderMgr::Init2 +8077ebdc MiiRenderMgr::Init +8077ed50 MiiRenderMgr::CreateTextures +8077ee98 0x8077ee98 +8077ef34 MiiRenderMgr::SetPercentages +8077ef40 MiiRenderMgr::InitMenuModels +8077f2a8 0x8077f2a8 +8077f76c MiiRenderMgr::InitRaceModels +8077fa28 0x8077fa28 +8077fa88 0x8077fa88 +8077fc3c 0x8077fc3c +8077fd80 0x8077fd80 +8078010c 0x8078010c +80780124 0x80780124 +8078024c 0x8078024c +8078031c 0x8078031c +807803f4 0x807803f4 +8078053c 0x8078053c +80780578 MiiRenderMgr::InitLights +80780794 0x80780794 +807808fc MiiRenderMgr::AddMii +80780ae0 MiiRenderMgr::CreateMiisAndRender +80780bf0 MiiRenderMgr::CreateAndRenderFromMiis +80780d00 MiiRenderMgr::CreateAndDraw +80781234 0x80781234 +807815d8 0x807815d8 +80781680 MiiRenderMgr::SetMiiForModel +8078176c MiiRenderMgr::UpdateScreenFromTexture +80781924 0x80781924 +807819c8 MiiRenderMgr::RequestAddMii +80781a50 MiiRenderMgr::ProcessTopAddRequest +80781b04 MiiRenderMgr::DeleteMii +80781b94 MiiRenderMgr::ProcessAllAddRequests +80781c48 0x80781c48 +80781cd4 0x80781cd4 +80781e70 MiiRenderMgr::CalcWorldCB::ExecCallbackB +80781f1c MiiRenderMgr::CalcWorldCB::__dt +80781f5c 0x80781f5c +80782034 MiiRenderMgr::CalcWorldCB::ExecCallbackB(thunk) +8078203c MiiRenderMgr::CalcWorldCB::__dt +80782044 0x80782044 +80782054 0x80782054 +80782094 0x80782094 +80782098 0x80782098 +80782174 0x80782174 +80782280 0x80782280 +80782344 0x80782344 +807823e0 0x807823e0 +807824bc 0x807824bc +807825e0 Object::GetRaceinfoRandom +80782614 0x80782614 +807826bc 0x807826bc +80782764 0x80782764 +807827bc 0x807827bc +80782830 0x80782830 +807828c0 0x807828c0 +807829e0 RaceEndTallies::Disposer__dt +80782b0c RaceEndTallies::CreateInstance +80782bb4 RaceEndTallies::DestroyInstance +80782c68 RaceEndTallies::__dt +80782d0c RaceEndTallies::__ct +80782d88 RaceEndTallies::Init +80782f10 RaceEndTallies::Init_switch +80782f14 RaceEndTallies::Init_caseD_0 +80782f20 RaceEndTallies::Init_caseD_3 +80782f28 RaceEndTallies::Init_caseD_4 +80783074 RaceEndTallies::UpdateLicenseTallies +80783380 RaceEndTallies::Reset +807833c4 RaceEndTallies::SetVSBattleBool +8078341c RaceEndTallies::SetTotalDistance +80783434 RaceEndTallies::SetTotalDistanceVS +80783490 RaceEndTallies::SetCharacterAndKart +80783514 RaceEndTallies::SetCourseId +8078354c 0x8078354c +80783558 0x80783558 +80783560 0x80783560 +80783564 RaceEndTallies::SetWheelBool +8078364c RaceEndTallies::SetItemsTricksCounts +80783668 0x80783668 +807836bc 0x807836bc +80783714 0x80783714 +807838bc 0x807838bc +807839cc 0x807839cc +80783c34 0x80783c34 +80783cac 0x80783cac +80783d24 0x80783d24 +80783d28 0x80783d28 +80783d2c 0x80783d2c +80784028 0x80784028 +807842c4 0x807842c4 +80784600 0x80784600 +80784790 0x80784790 +80784828 0x80784828 +807848c0 0x807848c0 +80784944 0x80784944 +807849b8 0x807849b8 +80784a08 0x80784a08 +80784a80 0x80784a80 +80784a84 0x80784a84 +80784ad4 0x80784ad4 +80784b4c 0x80784b4c +80784b50 EntityManager::__dt +80784c48 EntityManager::CreateInstance +80784c98 EntityManager::DestroyInstance +80784d4c EntityManager::__ct +80784f44 0x80784f44 +80784fe8 0x80784fe8 +8078501c EntityManager::Update +807853f8 EntityManager::GetNextKartPlayer +80785460 EntityManager::GetNextObj +807854c8 EntityManager::GetNextObjectCollidable +80785530 EntityManager::GetNextObjectKCL +80785598 EntityManager::UpdateIndexes +807856bc EntityManager::InsertKartPlayer +807856d0 EntityManager::InsertItemEntity +807856e4 EntityManager::InsertObjectCollidable +8078578c EntityManager::InsertObjectKCL +807857a0 EntityManager::InsertEntity +80785be4 EntityManager::RemoveEntity +80785de0 EntityManager::PrepareFromEntity +80785f2c EntityManager::FindEntitiesCloseToEntity +80786180 EntityManager::PrepareFromSphere +807862cc EntityManager::FindEntitiesCloseToSphere +80786428 0x80786428 +807864cc EntityManager::IsPrepared +8078653c Entity::__ct +80786560 Entity::__dt +807865a0 Entity::Init +807865d8 Entity::MakeDynamic +807865e8 Entity::Resize +80786604 AreaMasker_ +80786614 EntityManager::Prepare +8078662c ClipInfoMgr::GetArea8And9GroupIDs +807866e8 ClipInfoMgr::UpdateScreenInfo +8078692c ClipInfoMgr::NormalizeVector +807869ac ClipInfoMgr::Disposer__dt +80786ad8 ClipInfoMgr::CreateInstance +80786ba4 ClipInfoMgr::DestroyInstance +80786c58 ClipInfoMgr::__ct +80786cf8 ClipScreenInfo::__ct +80786cfc ClipScreenInfo::__dt +80786d3c ClipInfoMgr::__dt +80786de0 ClipInfoMgr::Update +80787124 ClipInfoMgr::Insert +807871f4 0x807871f4 +8078720c ClipInfoMgr::CalcAreaType8Refs +80787244 ClipInfo::__ct +80787250 ClipInfo::__dt +80787290 ClipInfo::Init +80787370 0x80787370 +80787384 0x80787384 +807873bc 0x807873bc +807873f0 AwardsMgr::Disposer__dt +8078751c AwardsMgr::CreateInstance +8078764c AwardsMgr::DestroyInstance +80787700 AwardsMgr::__ct +80787804 AwardsMgr::__dt +807878a8 AwardsMgr::Init +80788674 AwardsMgr::LoadStand +807889ac AwardsMgr::LoadPlayers +80789200 0x80789200 +80789648 0x80789648 +80789840 0x80789840 +80789844 AwardsMgr::SetParams +80789904 0x80789904 +80789928 0x80789928 +80789d94 0x80789d94 +80789dd4 0x80789dd4 +80789f70 0x80789f70 +8078a14c 0x8078a14c +8078a324 0x8078a324 +8078a4f0 0x8078a4f0 +8078a940 0x8078a940 +8078abac 0x8078abac +8078ac3c IKParams::__ct +8078ae18 IKParams::Load +8078bfcc DriverMgr::Disposer__dt +8078c054 DriverMgr::CreateInstance +8078c0a4 DriverMgr::DestroyInstance +8078c0c8 DriverMgr::__ct +8078c490 DriverMgr::__dt +8078c5a4 0x8078c5a4 +8078c5b8 DriverMgr::SetController +8078c5c8 0x8078c5c8 +8078c610 0x8078c610 +8078c80c 0x8078c80c +8078c9e4 0x8078c9e4 +8078cab8 0x8078cab8 +8078cb2c 0x8078cb2c +8078cb38 0x8078cb38 +8078cc80 0x8078cc80 +8078cc88 0x8078cc88 +8078cdf0 0x8078cdf0 +8078ce54 DriverMgr::InitAwards +8078ce90 DriverMgr::Update +8078cfec 0x8078cfec +8078d054 0x8078d054 +8078d0fc 0x8078d0fc +8078d17c 0x8078d17c +8078d2d8 0x8078d2d8 +8078d420 0x8078d420 +8078d450 DriverMgr::ChangeFocusedPlayer +8078d460 0x8078d460 +8078d470 MHModelDirector::__ct +8078d4cc MHModelDirector::SetMatsTEVColors +8078d654 CourseMgr::CreateInstance +8078d790 CourseMgr::DestroyInstance +8078d81c CourseMgr::LoadModels +8078d9a8 0x8078d9a8 +8078dac0 0x8078dac0 +8078db54 CourseMgr::SetSoftWallInfo +8078db5c CourseMgr::UpdateKCL +8078dbf4 0x8078dbf4 +8078dd00 0x8078dd00 +8078de30 0x8078de30 +8078df58 0x8078df58 +8078df5c 0x8078df5c +8078e104 0x8078e104 +8078e16c 0x8078e16c +8078e314 0x8078e314 +8078e560 0x8078e560 +8078e7ac CourseMgr::IsCollidingNoTerrainInfoNoTriangleCheck +8078e98c CourseMgr::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +8078eb6c CourseMgr::IsColliding +8078edf0 CourseMgr::IsCollidingAddEntryNoTriangleCheck +8078f074 0x8078f074 +8078f21c 0x8078f21c +8078f3c4 0x8078f3c4 +8078f610 0x8078f610 +8078f85c CourseMgr::IsCollidingNoTerrainInfo +8078fa28 CourseMgr::IsCollidingAddEntryNoTerrainInfo +8078fbf4 0x8078fbf4 +8078fe64 CourseMgr::IsCollidingAddEntry +807900d4 0x807900d4 +8079012c _sinit_CourseMgr_cpp +8079013c MHModelDirector::__dt(thunk) +80790144 Item::LoadObjProperties +80790168 Item::InitAllObjProperties +80790488 Item::IsTT +80790494 Item::IsAwards +8079049c Item::GetDriverMgr +807904a8 Item::GetKMPObjectsCount +807904cc Item::GetGOBJHolder +807904d8 Item::GetKMPObjectId +807904e8 Item::ObjProperties::__ct(Copy) +80790624 Item::ObjProperties::ComputeCapacities +807908d8 0x807908d8 +8079094c 0x8079094c +807909c4 0x807909c4 +80790a3c 0x80790a3c +80790ab4 0x80790ab4 +80790b2c 0x80790b2c +80790ba0 0x80790ba0 +80790c14 0x80790c14 +80790cb0 0x80790cb0 +80790dcc Item::PlayerObj::__ct +80790e6c 0x80790e6c +80790eac Item::PlayerObj::Init +80790f7c Item::PlayerObj::UseItem +80791274 0x80791274 +80791334 0x80791334 +80791454 0x80791454 +80791464 0x80791464 +807914c8 Item::PlayerObj::UpdateParams +807917ac 0x807917ac +8079185c 0x8079185c +80791988 Item::PlayerObj::UpdateTetheredItems +80791b8c 0x80791b8c +80791c84 0x80791c84 +80792174 Item::PlayerObj::TrailPrepare +807922d4 Item::PlayerObj::TrailUpdate +80792634 0x80792634 +8079269c 0x8079269c +807927d0 0x807927d0 +80792848 Item::PlayerObj::TripleTrailPrepare +80792bd8 Item::PlayerObj::TripleTrailUpdate +80793570 0x80793570 +807935e0 0x807935e0 +8079385c Item::PlayerObj::SpinCalc +80793bc8 Item::PlayerObj::SpinPrepare +80793d00 Item::PlayerObj::SpinUpdate +807940d0 0x807940d0 +8079411c 0x8079411c +807941e4 0x807941e4 +80794218 0x80794218 +807942b0 0x807942b0 +80794388 0x80794388 +807944f4 Item::PlayerObj::CalcInitialObjSpeedAndDir +8079469c 0x8079469c +80794818 0x80794818 +80794948 0x80794948 +807949bc Item::PlayerObj::LoseItem +80794b44 0x80794b44 +80794c30 Item::PlayerObj::ComputeWheelPosRelativeToKart +80794cc8 0x80794cc8 +80794cd4 Item::PlayerObj::UpdateRemote +80794eb4 0x80794eb4 +807951cc 0x807951cc +807952ac 0x807952ac +8079530c 0x8079530c +80795334 Item::ObjHolder::__ct +80795338 Item::ObjHolder::Init +80795400 Item::ObjHolder::HideAll +80795470 Item::ObjHolder::Spawn +80795594 0x80795594 +807955d4 Item::ObjHolder::OnObjKillFinish +8079585c 0x8079585c +807959b4 Item::ObjHolder::SortObjs +80795adc Item::ObjHolder::Update +80795ff8 0x80795ff8 +80796014 0x80796014 +807960b4 0x807960b4 +8079619c Item::ObjHolder::UpdateModelPositions +80796228 Item::ObjHolder::OnFinishThrow +807962a4 0x807962a4 +8079630c Item::ObjHolder::ProcessRecvEVENT +807965dc Item::ObjHolder::ProcessRecvShootEVENT +807967ac Item::ObjHolder::ProcessRecvHitFreeEVENT +80796924 0x80796924 +80796a90 0x80796a90 +80796b18 Item::ObjHolder::GetTotalItemCount +80796b90 0x80796b90 +80796bb8 Item::Player::__ct +80796c08 0x80796c08 +80796c48 0x80796c48 +80796c88 0x80796c88 +80796cc8 Item::PlayerObj::__dt +80796d4c Item::Player::Init +80796efc 0x80796efc +80796f94 Item::Player::Update +80797850 0x80797850 +80797878 0x80797878 +807978b8 0x807978b8 +807978fc 0x807978fc +80797b48 0x80797b48 +80797bf0 0x80797bf0 +80797cb8 Item::Player::ActivateMushroom +80797cf0 Item::Player::ActivateStar +80797d20 Item::Player::ActivateMega +80797d50 Item::Player::ActivateBullet +80797d78 0x80797d78 +80797d7c 0x80797d7c +80797d94 0x80797d94 +80797e58 0x80797e58 +80797eb4 0x80797eb4 +80797f5c 0x80797f5c +80797f94 Item::Player::OnObjTetherEnd +80797ff8 0x80797ff8 +80798078 0x80798078 +8079809c Item::Player::LoseItemFromDmg +80798194 Item::Player::LoseTetheredItem +807981f8 0x807981f8 +807982a4 Item::Player::DecideItem +80798370 0x80798370 +80798378 0x80798378 +80798420 0x80798420 +80798428 Item::Player::HasTripleItem +807984ac 0x807984ac +80798578 Item::Player::GetHeldCount +807985f0 0x807985f0 +807985fc 0x807985fc +80798608 Item::Manager::Disposer__dt +807987a4 Item::Manager::CreateInstance +807987f4 Item::Manager::DestroyInstance +80798944 Item::Manager::__ct +80798b48 Item::ObjHolder::__dt +80798b88 Item::Player::__dt +80798c1c 0x80798c1c +80798c5c 0x80798c5c +80798c9c 0x80798c9c +80798cdc Item::Manager::__dt +80798e00 Item::Manager::Init +80798ebc Item::Manager::Update +8079900c Item::Manager::UpdateAllObjModelPos +80799064 Item::Manager::UpdateObjHolders +807990bc Item::Manager::UpdateTotalItemCountMinus30 +80799138 Item::Manager::UpdatePlayers +80799198 0x80799198 +80799254 Item::Manager::IsThereCapacityForItem +807992dc 0x807992dc +80799318 Item::Manager::CheckKartCollision +807994bc ItemManager::InitItemDirect +80799628 Item::Manager::CreateItemDirect +80799798 Item::Manager::GenerateItemDirect +80799904 Item::Manager::SpawnCloudForLocal +80799a24 Item::Manager::SpawnCloudForRemote +80799b04 0x80799b04 +80799be4 0x80799be4 +80799c60 Item::Manager::DoSomethingWithFIBObjTevColors +80799cc0 0x80799cc0 +80799cc8 Item::Manager::GetHeldCount +80799d3c 0x80799d3c +80799de4 Item::EVENTBuffer::Disposer__dt +80799f10 Item::EVENTBuffer::CreateInstance +8079a1d4 Item::EVENTBuffer::DestroyInstance +8079a288 0x8079a288 +8079a310 0x8079a310 +8079a32c 0x8079a32c +8079a39c Item::EVENTBuffer::GetPlayerIdFromBitfield +8079a3a4 Item::EVENTBuffer::FillOrExtractShootPos +8079a574 Item::EVENTBuffer::FillOrExtractPosDiff +8079a6e4 0x8079a6e4 +8079a978 0x8079a978 +8079a9a4 Item::EVENTBuffer::FillOrExtractBitfield +8079aa04 Item::EVENTBuffer::FillOrExtractTargetingShoot +8079aaac Item::EVENTBuffer::FillOrExtractBombShoot +8079ab18 Item::EVENTBuffer::FillOrExtractShoot +8079b400 Item::EVENTBuffer::UpdateSend +8079b53c Item::EVENTBuffer::UpdateReceive +8079b658 Item::EVENTBuffer::QueueSendEntry +8079b718 Item::EVENTBuffer::QueueReceivedEntry +8079b7e0 0x8079b7e0 +8079b88c Item::Obj::AddUseEVENTEntry +8079b950 Item::Obj::AddShootEVENTEntry +8079ba30 Item::Obj::AddHitFreeEVENTEntry +8079bb04 Item::Obj::AddHitDraggedEVENTEntry +8079bbc0 Item::Obj::AddTCLostPassEVENTEntry +8079bc8c Item::Obj::AddAction6EVENTEntry +8079bd50 Item::Obj::AddTCLostEndEVENTEntry +8079be30 Item::Obj::AddDropEVENTEntry +8079beec Item::Obj::GetHitFreeEntryPlayerIdAndType +8079bf04 0x8079bf04 +8079bf0c 0x8079bf0c +8079bf34 Item::EVENTBuffer::GetEntryBitfield +8079bf50 Item::EVENTBuffer::GetUSEPlayerId +8079bf58 0x8079bf58 +8079bf9c 0x8079bf9c +8079bfcc Item::Obj::SendOrExtractHitDraggedEVENT +8079c94c thunk_0x8079dee4 +8079ca48 Item::EVENTBuffer::__ct +8079cce0 Item::EVENTBuffer::__dt +8079cd84 0x8079cd84 +8079cd8c 0x8079cd8c +8079cdb0 0x8079cdb0 +8079cdb8 0x8079cdb8 +8079cdc0 0x8079cdc0 +8079cdc8 0x8079cdc8 +8079cdd0 0x8079cdd0 +8079cdd8 GetEVENTEntryDataLength +8079ce70 Item::Obj::InitSelf +8079ceb8 Item::Obj::CalcWorld::ExecCallbackB +8079cf28 Item::Obj::__ct +8079cf8c 0x8079cf8c +8079d068 Item::Obj::SpawnModel +8079d108 Item::Obj::PrepareLight +8079d2b0 0x8079d2b0 +8079d2cc 0x8079d2cc +8079d320 Item::Obj::SetInitialPosition +8079d328 Item::Obj::OnKill +8079d3d8 Item::Obj::OnTetherBreak +8079d3dc Item::Obj::OnFinishKill +8079d4a0 Item::Obj::ProcessRecvShootEVENT +8079d550 Item::Obj::vf_0x30 +8079d85c Item::Obj::vf_0x34 +8079d890 Item::Obj::Init +8079d96c Item::Obj::RemoveFromScn +8079d9f8 0x8079d9f8 +8079dbbc Item::Obj::Spawn +8079dc60 Item::Obj::Set +8079def0 Item::Obj::FinishKill +8079df60 0x8079df60 +8079e054 0x8079e054 +8079e0c4 0x8079e0c4 +8079e228 0x8079e228 +8079e2b0 0x8079e2b0 +8079e304 0x8079e304 +8079e388 0x8079e388 +8079e3b8 0x8079e3b8 +8079e420 0x8079e420 +8079e49c Item::Obj::RegisterEntity +8079e538 Item::Obj::UnregisterEntity +8079e54c 0x8079e54c +8079e658 Item::Obj::Update +8079ef20 0x8079ef20 +8079ef60 0x8079ef60 +8079efa0 0x8079efa0 +8079f2bc 0x8079f2bc +8079f3f0 0x8079f3f0 +8079f49c Item::Obj::TryDisappearDueToExcess +8079f518 0x8079f518 +8079f520 Item::Obj::CanDisappearFromDuration +8079f580 0x8079f580 +8079f5c8 Item::Obj::LoadGraphicsImplicitBRRESNoFunc +8079f610 Item::Obj::LoadGraphicsDefault +8079f648 Item::Obj::LoadGraphicsImplicitBRRES +8079f6ac Item::Obj::LoadGraphics +8079f9ec Item::Obj::LoadItemLight +8079fc3c Item::Obj::UpdateModelPosition +8079fc60 Item::Obj::UpdateModelPositionNoClip +8079fe24 Item::Obj::UpdateModelFromVecs +807a00d4 Item::Obj::UpdateShadow +807a0340 Item::Obj::UpdateModelFromQuat +807a0494 Item::Obj::OnObjCollision +807a06e0 0x807a06e0 +807a08c8 0x807a08c8 +807a0a08 0x807a0a08 +807a0b40 Item::Obj::CheckKartCollision +807a0cec 0x807a0cec +807a0ed0 0x807a0ed0 +807a0f58 Item::XZVecMag +807a0f68 Item::Obj::ProcessOtherCollision +807a1300 Item::Obj::CheckOtherObjsCollision +807a1544 0x807a1544 +807a18a0 0x807a18a0 +807a18bc 0x807a18bc +807a18dc 0x807a18dc +807a19b8 0x807a19b8 +807a1b64 0x807a1b64 +807a1bdc 0x807a1bdc +807a1c1c Item::Obj::UpdateWithClipping +807a2114 0x807a2114 +807a2454 0x807a2454 +807a24d4 0x807a24d4 +807a2548 0x807a2548 +807a256c 0x807a256c +807a2584 0x807a2584 +807a25a4 0x807a25a4 +807a25c4 0x807a25c4 +807a25e4 0x807a25e4 +807a25e8 0x807a25e8 +807a25f4 0x807a25f4 +807a2628 0x807a2628 +807a2730 0x807a2730 +807a276c 0x807a276c +807a27a8 0x807a27a8 +807a27e4 0x807a27e4 +807a282c Item::Obj::PrepareShootEventPacket +807a29dc Item::Obj::SendOrExtractShootEVENT +807a2a4c 0x807a2a4c +807a2ae0 0x807a2ae0 +807a2b38 0x807a2b38 +807a2bb0 0x807a2bb0 +807a2c1c 0x807a2c1c +807a2c84 0x807a2c84 +807a2cb4 0x807a2cb4 +807a2de8 0x807a2de8 +807a2dfc Item::Obj::OnPlayerCollision +807a2edc 0x807a2edc +807a2f4c 0x807a2f4c +807a2f50 Item::Obj::KillThunk +807a2f54 0x807a2f54 +807a2f58 0x807a2f58 +807a2f5c Item::ObjKouraGreen::UpdateThunk +807a2f60 Item::ObjKouraRed::UpdateThunk +807a2f64 Item::ObjKouraTogezo::UpdateThunk +807a2f68 Item::ObjBanana::UpdateThunk +807a2f6c Item::ObjBomb::UpdateThunk +807a2f70 Item::ObjFIB::UpdateThunk +807a2f74 Item::ObjKumo::UpdateThunk +807a2f78 0x807a2f78 +807a2f7c 0x807a2f7c +807a2f80 0x807a2f80 +807a2f84 0x807a2f84 +807a2f88 0x807a2f88 +807a2f8c 0x807a2f8c +807a2f90 0x807a2f90 +807a2f94 0x807a2f94 +807a2f98 0x807a2f98 +807a2f9c 0x807a2f9c +807a2fa0 0x807a2fa0 +807a2fa4 0x807a2fa4 +807a2fa8 0x807a2fa8 +807a2fac 0x807a2fac +807a2fb0 0x807a2fb0 +807a2fb4 0x807a2fb4 +807a2fb8 0x807a2fb8 +807a2fbc 0x807a2fbc +807a2fc0 0x807a2fc0 +807a2fe8 0x807a2fe8 +807a2ff0 0x807a2ff0 +807a2ff4 0x807a2ff4 +807a2ff8 0x807a2ff8 +807a3000 0x807a3000 +807a3040 Item::Obj::CalcWorldCB::__dt +807a3080 Item::Obj::CalcWorldCB::ExecCallbackB(thunk) +807a3088 Item::Obj::CalcWorldCB::__dt(thunk) +807a3090 Item::ObjBanana::CreateArray +807a310c 0x807a310c +807a314c 0x807a314c +807a318c 0x807a318c +807a31cc 0x807a31cc +807a320c 0x807a320c +807a324c Item::ObjBanana::SetInitialPosition +807a32ec 0x807a32ec +807a34e4 Item::ObjBanana::Update +807a3678 Item::ObjBanana::vf_0x30 +807a36dc Item::ObjBanana::InitSelf +807a375c Item::ObjBanana::SpawnModel +807a3760 Item::ObjBanana::OnKill +807a3830 Item::ObjBomb::CreateArray +807a39f0 0x807a39f0 +807a3a68 0x807a3a68 +807a3bc0 0x807a3bc0 +807a3c4c 0x807a3c4c +807a3da0 0x807a3da0 +807a3ebc Item::ObjBomb::__ct +807a4020 Item::ObjExplosion::__dt +807a4084 Item::ObjBomb::SetInitialPosition +807a41b4 0x807a41b4 +807a4348 Item::ObjBomb::Update +807a460c Item::ObjBomb::SendOrExtractShootEVENT +807a4678 Item::ObjBomb::vf_0x30 +807a46fc Item::ObjBomb::vf_0x34 +807a47b0 Item::ObjBomb::InitSelf +807a49ac Item::ObjBomb::UpdateModelPosition +807a504c Item::ObjBomb::UpdateModelPositionNoClip +807a508c 0x807a508c +807a513c 0x807a513c +807a51ec Item::ObjBomb::ToggleVisible +807a5230 Item::ObjBomb::SpawnModel +807a5368 Item::ObjBomb::PrepareLight +807a53b4 0x807a53b4 +807a53f4 0x807a53f4 +807a5510 0x807a5510 +807a55d8 Item::ObjBomb::OnKill +807a5764 Item::ObjBomb::OnTetherBreak +807a5808 Item::ObjBomb::OnFinishKill +807a5864 0x807a5864 +807a58b4 0x807a58b4 +807a58d8 Item::ObjBomb::__dt +807a5944 __sinit_ItemObjBomb_cpp +807a598c Item::ObjBomb::__dt(thunk) +807a5994 Item::Obj::KillObj +807a5b5c 0x807a5b5c +807a5bcc Item::Obj::KillFromOtherCollision +807a5c80 Item::Obj::KillFromPlayerCollision +807a5d6c Item::Obj::UpdateKill +807a5da4 0x807a5da4 +807a5f94 Item::ObjMiddle::__ct +807a5fe4 0x807a5fe4 +807a6064 0x807a6064 +807a6280 Item::Obj::DisappearDueToExcess +807a62fc 0x807a62fc +807a63f4 0x807a63f4 +807a6534 0x807a6534 +807a65d0 0x807a65d0 +807a65d8 0x807a65d8 +807a65e0 0x807a65e0 +807a6850 0x807a6850 +807a6918 0x807a6918 +807a69bc 0x807a69bc +807a6eb8 0x807a6eb8 +807a6f14 Item::ObjFIB::CreateArray +807a6fac Item::ObjFIB::SetInitialPosition +807a704c Item::ObjFIB::Update +807a70c8 Item::ObjFIB::vf_0x30 +807a712c Item::ObjFIB::InitSelf +807a73cc 0x807a73cc +807a73fc 0x807a73fc +807a7588 Item::ObjFIB::SpawnModel +807a7658 Item::ObjFIB::UpdateModelPosition +807a77a0 Item::ObjFIB::OnKill +807a77a4 Item::ObjGesso::CreateArray +807a7820 Item::Player::UseBlooper +807a79e4 Item::ObjGesso::InitSelf +807a7a00 0x807a7a00 +807a7a7c 0x807a7a7c +807a7acc Item::GessoScreen::__ct +807a7c60 Item::GessoScreen::__dt +807a7ca0 0x807a7ca0 +807a7d64 0x807a7d64 +807a7dbc Item::GessoScreen::UpdateModel +807a810c 0x807a810c +807a823c 0x807a823c +807a8278 0x807a8278 +807a82fc 0x807a82fc +807a83e4 0x807a83e4 +807a8570 Item::GessoMgr::CreateInstance +807a860c Item::GessoMgr::DestroyInstance +807a8644 Item::GessoMgr::Init +807a870c Item::GessoMgr::__ct +807a8794 Item::GessoMgr::DeployBlooper +807a891c Item::GessoMgr::Update +807a8d98 Item::GessoMgr::ApplyBlooper +807a90c4 __sinit_ItemObjGesso_cpp +807a90ec Item::ObjKiller::CreateArray +807a9168 Item::Player::UseBullet +807a91ac Item::ObjKiller::InitSelf +807a91c8 Item::ObjKiller::UpdateModelPosition +807a9304 __sinit_ItemObjKiller_cpp +807a932c Item::ObjKinoko::CreateArray +807a93a8 Item::Player::UseMushroom +807a93fc Item::ObjKinoko::InitSelf +807a9418 __sinit_ItemObjKinoko_cpp +807a9440 Item::ObjKinokoBig::CreateArray +807a94bc Item::Player::UseMegaMushroom +807a9510 Item::ObjKinokoBig::InitSelf +807a952c __sinit_ItemObjKinokoBig_cpp +807a9554 Item::ObjKinokoPowerful::CreateArray +807a95d0 Item::Player::UseGoldenMushroom +807a9618 Item::ObjKinokoPowerful::InitSelf +807a9634 __sinit_ItemObjKinokoPowerful_cpp +807a965c Item::ObjKouraRed::CreateArray +807a9824 Item::ObjKouraRed::__ct +807a99c4 0x807a99c4 +807a9a04 0x807a9a04 +807a9a88 0x807a9a88 +807a9b1c 0x807a9b1c +807a9bb4 0x807a9bb4 +807a9c18 0x807a9c18 +807a9c74 0x807a9c74 +807a9cf4 Item::ObjKouraRed::SetInitialPosition +807a9ee8 Item::ObjKouraRed::Update +807aa0c8 Item::ObjKouraRed::UpdateModelPosition +807aa168 Item::ObjKouraRed::UpdateModelPositionNoClip +807aa1f4 0x807aa1f4 +807aa234 0x807aa234 +807aa2ec 0x807aa2ec +807aa338 0x807aa338 +807aa3e4 0x807aa3e4 +807aa4c4 0x807aa4c4 +807aa4e4 0x807aa4e4 +807aa670 0x807aa670 +807aa690 0x807aa690 +807aa7ec 0x807aa7ec +807aa8a4 0x807aa8a4 +807aa9e8 0x807aa9e8 +807aa9f4 0x807aa9f4 +807aa9f8 Item::ObjKouraRed::InitSelf +807aaa78 Item::ObjKouraRed::SendOrExtractShootEVENT +807aab74 Item::ObjKouraRed::vf_0x30 +807aacc0 0x807aacc0 +807aadf4 Item::ObjKouraRed::OnKill +807aae7c Item::ObjKouraRed::OnFinishKill +807aaec0 Item::ObjKouraRed::SpawnModel +807aaf00 Item::ObjKouraRed::GetTargetedPlayerId +807aaf1c 0x807aaf1c +807aafd8 __sinit_ItemObjKouraRed_cpp +807ab044 0x807ab044 +807ab04c Item::ObjKouraTogezo::CreateArray +807ab280 Item::ObjKouraTogezo::__ct +807ab454 0x807ab454 +807ab4ec 0x807ab4ec +807ab550 0x807ab550 +807ab55c 0x807ab55c +807ab598 Item::ObjKouraTogezo::ToggleVisible +807ab5dc Item::ObjKouraTogezo::SpawnModel +807ab674 Item::ObjKouraTogezo::InitSelf +807ab814 Item::ObjKouraTogezo::CalcTargetedPlayerId +807abb08 Item::ObjKouraTogezo::Reset +807abc20 0x807abc20 +807abc60 0x807abc60 +807abca0 Item::ObjKouraTogezo::SetInitialPosition +807abe40 Item::ObjKouraTogezo::UpdateModelPosition +807ac058 Item::ObjKouraTogezo::UpdateModelPositionNoClip +807ac190 0x807ac190 +807ac488 0x807ac488 +807ac784 Item::ObjKouraTogezo::Update +807acc10 0x807acc10 +807acc58 Item::ObjKouraTogezo::UpdateRouteFlying +807ace50 Item::ObjKouraTogezo::807ad7e4 +807ace90 Item::ObjKouraTogezo::UpdateHomeIn +807acf80 0x807acf80 +807acfc4 Item::ObjKouraTogezo::UpdateDiveIn +807ad1c0 0x807ad1c0 +807ad274 0x807ad274 +807ad2c8 Item::ObjKouraTogezo::UpdateHover +807ad518 0x807ad518 +807ad580 0x807ad580 +807ad610 0x807ad610 +807ad7ec Item::ObjKouraTogezo::807ae180_ +807ad9b8 Item::ObjKouraTogezo::UpdateExplosion +807ada80 Item::ObjKouraTogezo::OnKill +807adbe0 Item::ObjKouraTogezo::OnFinishKill +807adc3c Item::ObjKouraTogezo::SendOrExtractShootEVENT +807add58 Item::ObjKouraTogezo::vf_0x30 +807adf14 0x807adf14 +807adf1c Item::ObjKouraTogezo::GetTargetedPlayerId +807adf54 0x807adf54 +807ae028 Item::ObjKouraGreen::__dt +807ae0e4 __sinit_ItemObjKouraTogezo_cpp +807ae150 Item::ObjKouraGreen::__dt(thunk) +807ae158 Item::ObjKouraGreen::CreateArray +807ae1d4 get_1 +807ae1e0 0x807ae1e0 +807ae1ec 0x807ae1ec +807ae1f8 0x807ae1f8 +807ae204 Item::ObjKouraGreen::SetInitialPosition +807ae2d0 Item::ObjKouraGreen::Update +807ae398 Item::ObjKouraGreen::UpdateModelPosition +807ae438 Item::ObjKouraGreen::UpdateModelPositionNoClip +807ae4c4 Item::ObjKouraGreen::SendOrExtractShootEVENT +807ae5a4 Item::ObjKouraGreen::vf_0x30 +807ae620 Item::ObjKouraGreen::InitSelf +807ae6a0 Item::ObjKouraGreen::OnKill +807ae728 Item::ObjKouraGreen::OnFinishKill +807ae76c Item::ObjKouraGreen::SpawnModel +807ae7ac Item::ObjKumo::CreateArray +807ae828 Item::Player::UseTC +807ae86c Item::ObjKumo::SpawnModel +807ae8a0 0x807ae8a0 +807aea08 Item::ObjKumo::UpdateModelPosition +807aeba0 Item::ObjKumo::InitSelf +807aec0c 0x807aec0c +807aedd8 Item::ObjKumo::Update +807afe2c 0x807afe2c +807aff60 0x807aff60 +807affcc Item::ObjKumo::OnFinishKill +807b005c 0x807b005c +807b01b8 0x807b01b8 +807b05d4 0x807b05d4 +807b0774 0x807b0774 +807b0878 0x807b0878 +807b0884 0x807b0884 +807b088c 0x807b088c +807b08a8 Item::ObjKumo::OnKill +807b0970 0x807b0970 +807b0cac 0x807b0cac +807b0f08 0x807b0f08 +807b0fbc 0x807b0fbc +807b1090 0x807b1090 +807b10b0 0x807b10b0 +807b10d8 0x807b10d8 +807b1100 0x807b1100 +807b111c Item::ObjPow::CreateArray +807b1198 Item::Player::UsePow +807b1210 Item::ObjPow::InitSelf +807b122c Item::PowMgr::CreateInstance +807b12d8 0x807b12d8 +807b12dc Item::PowMgr::DestroyInstance +807b1314 Item::PowMgr::Init +807b1384 Item::PowMgr::__ct +807b141c 0x807b141c +807b1420 Item::PowMgr::DeployPow +807b1558 Item::PowMgr::AnimateModel +807b1728 Item::PowMgr::CreateShockwave +807b1964 Item::PowMgr::Update +807b1ae0 0x807b1ae0 +807b1b5c 0x807b1b5c +807b1bac Item::PowScreen::__ct +807b1e68 0x807b1e68 +807b1ed4 0x807b1ed4 +807b1ef0 0x807b1ef0 +807b1f90 0x807b1f90 +807b1fec 0x807b1fec +807b2048 Item::PowScreen::UpdateModel +807b2280 0x807b2280 +807b23d0 0x807b23d0 +807b24fc Item::PowMgr::IsPowActive +807b2518 Item::PowMgr::GetFramesUntilPOWSmash +807b252c Item::PowMgr::GetPowUserPlayerId +807b253c __sinit_ItemObjPow_cpp +807b2564 0x807b2564 +807b2580 0x807b2580 +807b25c0 0x807b25c0 +807b2e88 0x807b2e88 +807b3218 0x807b3218 +807b32f8 0x807b32f8 +807b341c 0x807b341c +807b352c 0x807b352c +807b3558 Item::ObjKouraTogezoBase::ResetTargeting +807b3568 Item::ObjKouraTogezoBase::SpawnModel +807b35a8 0x807b35a8 +807b3648 0x807b3648 +807b3a48 0x807b3a48 +807b3a6c 0x807b3a6c +807b3a9c 0x807b3a9c +807b3c1c Item::ObjKouraTogezo::AcquireTarget +807b3e7c 0x807b3e7c +807b3ee4 0x807b3ee4 +807b3fb0 0x807b3fb0 +807b4150 0x807b4150 +807b4398 0x807b4398 +807b46d4 0x807b46d4 +807b4760 0x807b4760 +807b47e4 0x807b47e4 +807b4998 0x807b4998 +807b4a60 0x807b4a60 +807b4af0 0x807b4af0 +807b4b60 0x807b4b60 +807b570c 0x807b570c +807b57b4 0x807b57b4 +807b5838 0x807b5838 +807b5924 0x807b5924 +807b5b64 0x807b5b64 +807b5c78 0x807b5c78 +807b5d5c 0x807b5d5c +807b5e88 0x807b5e88 +807b5f7c Item::ObjThrowable::OnFinishThrow +807b6204 0x807b6204 +807b6268 KouraGreen_07b6bfc_ +807b65c0 0x807b65c0 +807b665c Item::ObjStar::CreateArray +807b66d8 Item::Player::UseStar +807b672c Item::ObjStar::InitSelf +807b6748 __sinit_ItemObjStar_cpp +807b6770 Item::ObjThrowable::SetInitialPositionImpl +807b6b40 0x807b6b40 +807b6bdc 0x807b6bdc +807b70b4 0x807b70b4 +807b7110 0x807b7110 +807b716c Item::ObjThunder::CreateArray +807b71e8 Item::Player::UseThunder +807b7270 Item::ObjThunder::InitSelf +807b728c Item::ObjThunder::ApplyToPlayers +807b73e0 __sinit_ItemObjThunder_cpp +807b7408 0x807b7408 +807b74c4 0x807b74c4 +807b74d8 0x807b74d8 +807b75c8 0x807b75c8 +807b767c 0x807b767c +807b774c 0x807b774c +807b7bb8 0x807b7bb8 +807b7c78 ItemPathManager_createInstance +807b7fe8 0x807b7fe8 +807b8050 0x807b8050 +807b8108 Player_UpdateItemPoint +807b859c Item::Point_update2 +807b8760 0x807b8760 +807b8850 0x807b8850 +807b9040 0x807b9040 +807b90a4 0x807b90a4 +807b9190 0x807b9190 +807b927c 0x807b927c +807b92dc 0x807b92dc +807b9440 Item::GetQuatFromMat +807b94bc 0x807b94bc +807b9530 0x807b9530 +807b95b4 Item::PlayerRoulette::__ct +807b95c0 0x807b95c0 +807b95ec Item::PlayerRoulette::Init +807b961c Item::PlayerRoulette::DecideItem +807b989c 0x807b989c +807b9944 Item::PlayerRoulette::OnRouletteEnd +807b99bc 0x807b99bc +807b99e8 Item::PlayerRoulette::Update +807b9bd8 0x807b9bd8 +807b9c28 0x807b9c28 +807b9c3c 0x807b9c3c +807b9c44 0x807b9c44 +807b9cbc Item::SlotData::Disposer__dt +807b9de8 Item::SlotData::CreateInstance +807b9e80 Item::SlotData::DestroyInstance +807b9f34 Item::SlotData::__ct +807b9fa0 Item::SlotData::__dt +807ba044 Item::SlotData::ProcessTable +807ba374 Item::SlotData::GetNextTable +807ba38c Item::SlotData::PostProcessVSTable +807ba4ec 0x807ba4ec +807ba540 Item::SlotData::RandomizeRouletteItem +807ba5b4 Item::SlotData::Init +807ba9e0 Item::SlotData::RouletteItems::__ct +807ba9ec Item::ItemSlotData::CanItemNotBeObtained +807baa98 Item::SlotData::DecideItem +807baf3c Item::SlotData::DecideRouletteItem +807bb028 Item::SlotData::ResetShockTimer +807bb034 Item::SlotData::ResetBlueShellTimer +807bb040 Item::SlotData::ResetBlooperTimer +807bb04c Item::SlotData::ResetPowTimer +807bb058 Item::SlotData::UpdateTimers +807bb100 Item::SlotData::GetBinary +807bb16c Item::SlotData::SetupBattleModeProbabilities +807bb3cc Item::SlotData::SetupOnlineVSProbabilities +807bb504 0x807bb504 +807bb564 Item::SlotData::SetupVSProbabilities +807bb66c Item::SlotData::SetupGPProbabilities +807bb764 Item::PlayerInventory::__ct +807bb768 0x807bb768 +807bb79c Item::PlayerInventory::Init +807bb7dc 0x807bb7dc +807bb924 0x807bb924 +807bb9bc Item::PlayerInventory::EjectItems +807bbc7c Item::PlayerInventory::LoseItemFromDmg +807bbd54 Item::PlayerInventory::Update +807bbe9c 0x807bbe9c +807bbf74 0x807bbf74 +807bbfac Item::PlayerInventory::SetItem +807bbfe8 Item::PlayerInventory::RemoveItems +807bc02c Item::PlayerInventory::ClearAll +807bc060 0x807bc060 +807bc11c 0x807bc11c +807bc13c 0x807bc13c +807bc14c Item::InitAllBehavior +807bc83c DriverMgr::SetParams +807bc87c DriverMgr::SetParams_switch +807bc880 DriverMgr::SetParams_caseD_2 +807bc89c DriverMgr::SetParams_caseD_3 +807bc8b8 DriverMgr::SetParams_caseD_7 +807bc8d4 DriverMgr::SetParams_caseD_9 +807bc8f0 DriverMgr::SetParams_caseD_0 +807bc908 DriverMgr::SetParams_caseD_1 +807bc9ac SomeTimers_update +807bc9e0 0x807bc9e0 +807bcc28 DriverMgr::IsPlayerComputer +807bcd50 0x807bcd50 +807bcd84 DriverMgr::GetRaceinfoRandom +807bcdd4 0x807bcdd4 +807bcdf8 0x807bcdf8 +807bce20 CollisionInfo::ObjInfo::Init +807bce44 CollisionInfo::ObjInfo::Set +807bce7c 0x807bce7c +807bcebc CollisionInfo::ObjInfo::AreItemsAllowedOnObj +807bced0 CollisionInfo::ObjInfo::SetDistanceCalcBit +807bcef8 CollisionInfo::ObjInfo::CalcInitialDistance +807bcf24 0x807bcf24 +807bcf40 0x807bcf40 +807bcf54 CollisionInfo::ObjInfo::Update +807bcf74 CollisionInfo::ObjInfo::UpdateWithRot +807bcf9c CollisionInfo::ObjInfo::Reset +807bcfc0 0x807bcfc0 +807bcfd8 KCLTypeHolder::FindClosestCollisionEntry +807bd054 0x807bd054 +807bd0e8 KCLTypeHolder::Reset +807bd108 KCLTypeHolder::ApplyFlagAndRegisterEntry +807bd154 0x807bd154 +807bd194 KCLTypeHolder::ReplaceBLIGHTIndex +807bd1c8 KCLTypeHolder::ReplaceKCLVariant +807bd1fc KCLTypeHolder::ReplaceWheelDepth +807bd230 KCLTypeHolder::ReplaceTrickableBit +807bd264 KCLTypeHolder::ReplaceRejectBit +807bd298 KCLTypeHolder::ReplaceSoftBit +807bd2c8 KCLController::__ct +807bd3e8 0x807bd3e8 +807bd428 KCLController::__dt +807bd468 0x807bd468 +807bd5c0 0x807bd5c0 +807bd69c KCLController::FindTrianglesList +807bd798 KCLController::FindTrianglesListAndProcessNewRadius +807bda30 0x807bda30 +807beb2c 0x807beb2c +807bf850 0x807bf850 +807bfef0 KCLController::IsCollidingImpl +807c056c KCLController::IsCollidingFromCurCopyPosition +807c0b80 KCLController::IsCollidingImplInfY +807c1178 0x807c1178 +807c1220 KCLController::GetTrianglesList +807c12f8 0x807c12f8 +807c1454 KCLController::GetTrianglesListReuse +807c15ec 0x807c15ec +807c1618 0x807c1618 +807c1860 0x807c1860 +807c1a7c KCLController::IsColliding +807c1aa8 0x807c1aa8 +807c1b2c KCLController::Update +807c1c38 0x807c1c38 +807c1c9c 0x807c1c9c +807c1ccc CollisionInfo::Init +807c1d18 0x807c1d18 +807c1e90 KCLManager::CreateInstance +807c1ef0 KCLManager::DestroyInstance +807c1f44 KCLManager::Load +807c1f94 0x807c1f94 +807c1fa8 KCLManager::Update +807c2050 0x807c2050 +807c2070 0x807c2070 +807c20cc 0x807c20cc +807c2244 KCLManager::IsCollidingFillInfoNoTerrainInfo +807c240c 0x807c240c +807c2584 KCLManager::IsCollidingFillInfoAddEntryNoTerrainInfo +807c274c 0x807c274c +807c28c4 KCLManager::IsCollidingFillInfo +807c2bc0 0x807c2bc0 +807c2d38 KCLManager::IsCollidingFillInfoAddEntry +807c3034 KCLManager::IsCollidingNoTerrainInfoNoTriangleCheck +807c31c8 KCLManager::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +807c335c KCLManager::IsColliding +807c34f0 KCLManager::IsCollidingAddEntryNoTriangleCheck +807c3684 0x807c3684 +807c3810 0x807c3810 +807c399c 0x807c399c +807c3b28 0x807c3b28 +807c3cb4 KCLManager::IsCollidingNoTerrainInfo +807c3e5c KCLManager::IsCollidingAddEntryNoTerrainInfo +807c4004 0x807c4004 +807c41ac KCLManager::IsCollidingAddEntry +807c4354 ObjectKCLController::__ct +807c43d8 ObjectKCLController::__dt +807c4434 ObjectKCLController::Update +807c44b8 0x807c44b8 +807c44e8 0x807c44e8 +807c4518 0x807c4518 +807c46d8 0x807c46d8 +807c4898 0x807c4898 +807c4a10 0x807c4a10 +807c4b88 ObjectKCLController::CalcCollisionNoTerrainInfoNoTriangleCheck +807c4d64 ObjectKCLController::CalcCollisionAddEntryNoTerrainInfoNoTriangleCheck +807c4f40 ObjectKCLController::CalcCollision +807c50d4 ObjectKCLController::CalcCollisionAddEntryNoTriangleCheck +807c5268 0x807c5268 +807c5440 0x807c5440 +807c5618 0x807c5618 +807c57a8 0x807c57a8 +807c5938 ObjectKCLController::CalcCollisionNoTerrainInfo +807c5b2c ObjectKCLController::CalcCollisionAddEntryNoTerrainInfo +807c5d20 0x807c5d20 +807c5ecc ObjectKCLController::CalcCollisionAddEntry +807c6078 0x807c6078 +807c6080 0x807c6080 +807c608c 0x807c608c +807c60a4 0x807c60a4 +807c60b0 0x807c60b0 +807c6104 0x807c6104 +807c6108 0x807c6108 +807c6144 0x807c6144 +807c61dc 0x807c61dc +807c6234 0x807c6234 +807c6270 0x807c6270 +807c6388 0x807c6388 +807c64d0 0x807c64d0 +807c6578 0x807c6578 +807c65a8 0x807c65a8 +807c66f8 DriverControllerBones::__ct +807c6720 0x807c6720 +807c6760 DriverControllerBones::__dt +807c67a0 DriverControllerBones::SetBoneName +807c67c4 DriverControllerBones::SetNode +807c6844 DriverMgr::InitiateDriverControllerBoneNames +807c69c4 0x807c69c4 +807c69d0 DriverController::__ct +807c6e50 0x807c6e50 +807c6e54 0x807c6e54 +807c6e94 DriverController::LoadModels +807c74e8 DriverController::LoadBones +807c7c90 0x807c7c90 +807c7dc4 DriverController::Load +807c8c98 0x807c8c98 +807c8eac 0x807c8eac +807c8eb0 0x807c8eb0 +807c9690 0x807c9690 +807c96d4 0x807c96d4 +807c9724 0x807c9724 +807c9d50 0x807c9d50 +807ca110 0x807ca110 +807ca1f8 0x807ca1f8 +807ca3d4 0x807ca3d4 +807ca4ec 0x807ca4ec +807ca4f8 0x807ca4f8 +807ca734 DriverController::Init +807ca79c DriverControllerBike::Init +807ca804 0x807ca804 +807ca9b8 0x807ca9b8 +807ca9cc DriverController::Update +807cab9c 0x807cab9c +807cb384 0x807cb384 +807cb38c 0x807cb38c +807cb390 0x807cb390 +807cb524 0x807cb524 +807cb684 PlayerModel_setAnimation +807cb7dc 0x807cb7dc +807cb7e0 0x807cb7e0 +807cc4e4 0x807cc4e4 +807cc4f4 0x807cc4f4 +807cc504 0x807cc504 +807cc514 0x807cc514 +807cc524 0x807cc524 +807cc534 0x807cc534 +807cc544 0x807cc544 +807cc554 0x807cc554 +807cc564 0x807cc564 +807cc574 0x807cc574 +807cc584 0x807cc584 +807cc594 0x807cc594 +807cc998 0x807cc998 +807cd0e0 0x807cd0e0 +807cd264 0x807cd264 +807cd28c 0x807cd28c +807cd310 0x807cd310 +807cd338 DriverControllerBike::__ct +807cd374 DriverController::__dt +807cd424 0x807cd424 +807cd580 0x807cd580 +807cd7fc 0x807cd7fc +807cd8dc 0x807cd8dc +807cd9f8 0x807cd9f8 +807cdc10 0x807cdc10 +807cdd3c 0x807cdd3c +807ce2b4 0x807ce2b4 +807ce340 0x807ce340 +807ceb7c 0x807ceb7c +807cef8c 0x807cef8c +807cefcc 0x807cefcc +807cf05c 0x807cf05c +807cfbc0 0x807cfbc0 +807cfdb0 0x807cfdb0 +807cfe5c 0x807cfe5c +807cff04 0x807cff04 +807cffa4 0x807cffa4 +807cffb8 0x807cffb8 +807d01c8 MiiDriverModel::UpdateParams +807d03d4 0x807d03d4 +807d04dc 0x807d04dc +807d05e4 0x807d05e4 +807d0b20 0x807d0b20 +807d0b70 0x807d0b70 +807d0d88 0x807d0d88 +807d0f58 0x807d0f58 +807d1034 0x807d1034 +807d10cc 0x807d10cc +807d1248 0x807d1248 +807d1264 0x807d1264 +807d1280 0x807d1280 +807d12ac 0x807d12ac +807d12c8 0x807d12c8 +807d12e4 0x807d12e4 +807d1300 0x807d1300 +807d131c 0x807d131c +807d1338 0x807d1338 +807d1354 0x807d1354 +807d1370 0x807d1370 +807d14a0 0x807d14a0 +807d15ec 0x807d15ec +807d1688 0x807d1688 +807d16a4 0x807d16a4 +807d16d0 0x807d16d0 +807d170c 0x807d170c +807d1728 0x807d1728 +807d174c 0x807d174c +807d1780 0x807d1780 +807d179c 0x807d179c +807d17b8 0x807d17b8 +807d17d4 0x807d17d4 +807d17f8 0x807d17f8 +807d1814 0x807d1814 +807d1830 0x807d1830 +807d1864 DriverController::CreateModelDirectors +807d1df0 0x807d1df0 +807d1e04 0x807d1e04 +807d1fac 0x807d1fac +807d2114 0x807d2114 +807d2198 0x807d2198 +807d21d4 0x807d21d4 +807d2220 0x807d2220 +807d2414 0x807d2414 +807d2448 0x807d2448 +807d2450 0x807d2450 +807d2458 0x807d2458 +807d24e4 0x807d24e4 +807d2570 0x807d2570 +807d2618 0x807d2618 +807d26c0 0x807d26c0 +807d2710 0x807d2710 +807d2760 0x807d2760 +807d276c 0x807d276c +807d27f4 0x807d27f4 +807d296c 0x807d296c +807d2970 0x807d2970 +807d2980 0x807d2980 +807d299c 0x807d299c +807d29f8 0x807d29f8 +807d2ac4 0x807d2ac4 +807d2e20 0x807d2e20 +807d2e3c 0x807d2e3c +807d2e88 0x807d2e88 +807d2ed4 0x807d2ed4 +807d2fd8 0x807d2fd8 +807d33c4 0x807d33c4 +807d34d4 0x807d34d4 +807d357c 0x807d357c +807d3590 0x807d3590 +807d35c4 DriverControllerBike::__dt +807d3678 0x807d3678 +807d3954 DriverLimbs::__ct +807d3c54 DriverCalcWorldCB::__dt +807d3c94 0x807d3c94 +807d3d10 0x807d3d10 +807d3d6c 0x807d3d6c +807d3f70 0x807d3f70 +807d3f98 0x807d3f98 +807d40ac 0x807d40ac +807d40b8 0x807d40b8 +807d410c 0x807d410c +807d4160 0x807d4160 +807d418c 0x807d418c +807d4374 0x807d4374 +807d4cec 0x807d4cec +807d4dcc DriverLimbs::ExecCallbackA +807d4fb0 0x807d4fb0 +807d5104 DriverLimbs::ExecCallbackB +807d51a4 0x807d51a4 +807d54fc 0x807d54fc +807d5a4c DriverLimbs::ExecCallbackC +807d5c28 0x807d5c28 +807d5eb0 0x807d5eb0 +807d6054 DriverLimbs::CalcLeftArm +807d6194 DriverLimbs::CalcRightArm +807d6318 DriverLimbs::CalcLeftLeg +807d64cc 0x807d64cc +807d6548 0x807d6548 +807d65c4 DriverLimbs::CalcRightLeg +807d6778 0x807d6778 +807d6ac4 0x807d6ac4 +807d6bf4 0x807d6bf4 +807d6d54 0x807d6d54 +807d6e40 0x807d6e40 +807d6ff8 0x807d6ff8 +807d7670 0x807d7670 +807d7950 0x807d7950 +807d7c70 0x807d7c70 +807d7cf4 0x807d7cf4 +807d7d78 0x807d7d78 +807d7dfc 0x807d7dfc +807d8060 0x807d8060 +807d849c 0x807d849c +807d85f4 0x807d85f4 +807d86a4 0x807d86a4 +807d8754 0x807d8754 +807d87a0 0x807d87a0 +807d8838 0x807d8838 +807d8cf4 0x807d8cf4 +807d8da0 0x807d8da0 +807d8da8 0x807d8da8 +807d8db8 DriverLimbs::ExecCallbackC(thunk) +807d8dc0 DriverLimbs::ExecCallbackB(thunk) +807d8dc8 DriverLimbs::ExecCallbackA(thunk) +807d8dd0 DriverLimbs::__dt(thunk) +807d8dd8 DriverController::GetBoneMatId +807d8e04 DriverCalcWorldCB::__ct +807d9058 DriverCalcWorldCB::ExecCallbackB +807d9178 DriverCalcWorldCB::ExecCallbackC +807d91ec DriverCalcWorldCB::ExecCallbackC(thunk) +807d91f4 DriverCalcWorldCB::ExecCallbackB(thunk) +807d91fc DriverCalcWorldCB::__dt(thunk) +807d9204 TicoModel::__ct +807d93d0 TicoModel::Update +807d9a78 0x807d9a78 +807d9be4 TicoModel::UpdateKartPosition +807d9c2c ToadetteHair::__ct(ResFile, ModelDirector) +807d9f60 ToadetteHair::__ct(DriverController) +807da2bc 0x807da2bc +807da370 0x807da370 +807da670 0x807da670 +807da674 0x807da674 +807da694 ToadetteHair::ToggleLock +807da6a8 ToadetteHair::CalcWorldCB::ExecCallbackC +807db290 ToadetteHair::__dt +807db2e8 ToadetteHair::CalcWorldCB::__dt +807db328 ToadetteHair::CalcWorldCB::ExecCallbackC(thunk) +807db330 ToadetteHair::CalcWorldCB::__dt(thunk) +807db338 0x807db338 +807db3ec MiiHeadsModel::__ct(Mii) +807db478 MiiHeadsModel::__ct(miiIdx, r9) +807db534 0x807db534 +807db5e8 0x807db5e8 +807db628 MiiHeadsModel::__ct(Mii, r9) +807db6b4 MiiHeadsModel::Init +807db918 0x807db918 +807db92c MiiHeadsModel::UpdateParams +807db944 0x807db944 +807db95c 0x807db95c +807dba54 MiiHeadsModel::SetExpression +807dbaa8 MiiHeadsModel::SetExpression_switch +807dbaac MiiHeadsModel::SetExpression_caseD_5 +807dbaf8 MiiHeadsModel::SetExpression_caseD_6 +807dbb44 MiiHeadsModel::SetExpression_caseD_7 +807dbb90 MiiHeadsModel::SetExpression_caseD_4 +807dbbdc MiiHeadsModel::SetExpression_caseD_2 +807dbc28 MiiHeadsModel::SetExpression_caseD_1 +807dbc74 MiiHeadsModel::SetExpression_caseD_0 +807dbcc0 MiiHeadsModel::SetExpression_caseD_3 +807dbd34 0x807dbd34 +807dbe50 0x807dbe50 +807dbecc MiiHeadsModel::__dt +807dbf24 0x807dbf24 +807dbf34 0x807dbf34 +807dbfbc 0x807dbfbc +807dc0ac 0x807dc0ac +807dc19c 0x807dc19c +807dc28c 0x807dc28c +807dc2cc 0x807dc2cc +807dc30c 0x807dc30c +807dc34c 0x807dc34c +807dc38c 0x807dc38c +807dc3cc 0x807dc3cc +807dc40c 0x807dc40c +807dc4e4 0x807dc4e4 +807dc5bc 0x807dc5bc +807dc694 0x807dc694 +807dc76c 0x807dc76c +807dc844 0x807dc844 +807dc91c 0x807dc91c +807dcc24 0x807dcc24 +807dcf2c 0x807dcf2c +807dd234 0x807dd234 +807dd53c 0x807dd53c +807dd844 0x807dd844 +807ddb4c 0x807ddb4c +807ddcac lim_sprintf +807ddd54 0x807ddd54 +807dde14 0x807dde14 +807dde8c 0x807dde8c +807ddec4 0x807ddec4 +807ddf24 0x807ddf24 +807ddfa0 0x807ddfa0 +807de190 0x807de190 +807de238 0x807de238 +807de380 PSMTXRotRad +807de4f8 0x807de4f8 +807de670 0x807de670 +807de7e8 0x807de7e8 +807de8cc 0x807de8cc +807dea30 0x807dea30 +807dea9c 0x807dea9c +807debd8 0x807debd8 +807decfc 0x807decfc +807dee20 0x807dee20 +807dee74 MinimapMgr::Disposer__dt +807def74 MinimapMgr::CreateInstance +807df070 MinimapMgr::DestroyInstance +807df13c MinimapMgr::__ct +807df20c 0x807df20c +807df210 MinimapMgr::Load +807df510 0x807df510 +807df550 MinimapMgr::__dt +807df610 MinimapMgr::TryDraw +807df694 MinimapMgr::Draw +807dfbe8 MinimapMgr::ApplyAREAType5 +807dff48 0x807dff48 +807dff4c 0x807dff4c +807dff50 MinimapMgr::Convert3DPosToPercent +807dffa8 CtrlMenuBattleCupSelectCup::GetClassName +807dffb4 CtrlMenuBattleCupSelectStage::GetClassName +807dffc4 CtrlMenuBattleCupSelectCup::Load +807e01bc CtrlMenuBattleCupSelectCup::OnInit +807e02fc CtrlMenuBattleCupSelectCup::OnCupButtonSelect +807e03cc CtrlMenuBattleCupSelectCup::OnCupButtonClick +807e042c CtrlMenuBattleCupSelectStage::Load +807e0550 CtrlMenuBattleCupSelectStage::UpdateStageList +807e063c CtrlMenuBattleCupSelectStage::InitSelf +807e0740 CtrlMenuBattleCupSelectStage::OnUpdate +807e08b4 CtrlMenuBattleCupSelectStage::GetRuntimeTypeInfo +807e08c0 CtrlMenuBattleCupSelectCup::GetRuntimeTypeInfo +807e08cc CtrlMenuBattleCup::_sinit_ +807e08e8 CtrlMenuBattleStageSelectCupSub::GetClassName +807e08f4 CtrlMenuBattleStageSelectCup::GetClassName +807e0904 CtrlMenuBattleStageSelectStage::GetClassName +807e0914 StageButton::GetClassName +807e0924 CtrlMenuBattleStageSelectCup::Load +807e0ab0 CtrlMenuBattleStageSelectCup::InitSelf +807e0bb4 CtrlMenuBattleStageSelectCupSub::SetRelativePosition +807e0c38 CtrlMenuBattleStageSelectCupSub::InitSelf +807e0cd4 CtrlMenuBattleStageSelectCupSub::OnUpdate +807e13e4 Pages::BattleStageSelect::GetManipulatorManager +807e13ec CtrlMenuBattleStageSelectStage::Load +807e153c CtrlMenuBattleStageSelectStage::InitSelf +807e1920 CtrlMenuBattleStageSelectStage::OnStageButtonClick +807e1978 CtrlMenuBattleStageSelectStage::OnStageButtonSelect +807e1b74 CtrlMenuBattleStageSelectStage::GetRuntimeTypeInfo +807e1b80 StageButton::GetRuntimeTypeInfo +807e1b8c CtrlMenuMovieButton::GetMovieCount +807e1b94 CtrlMenuBattleStageSelectCup::GetRuntimeTypeInfo +807e1ba0 CtrlMenuBattleStageSelectCupSub::GetRuntimeTypeInfo +807e1bac CtrlMenuBattleStage_cpp_sinit_ +807e1bd8 CtrlMenuMovieButton::OnUpdate(PushButton) +807e1be0 CtrlMenuMovieButton::InitSelf(PushButton) +807e1be8 CtrlMenuMovieButton::OnLoad(PushButton) +807e1bf0 StageButton::__dt(PushButton) +807e1bf8 StageButton::GetClassName(PushButton) +807e1c00 StageButton::GetRuntimeTypeInfo(PushButton) +807e1c08 CtrlMenuCharacterSelect::GetClassName +807e1c14 CtrlMenuCharacterSelect::Load +807e1e74 CtrlMenuCharacterSelect::ButtonDriver::__ct +807e1eb0 CtrlMenuCharacterSelect::ButtonDriver::__dt +807e1f08 CtrlMenuCharacterSelect::GetUnlockedStatus +807e1f94 CtrlMenuCharacterSelect::LoadButton +807e2384 CtrlMenuCharacterSelect::InitSelf +807e2718 CtrlMenuCharacterSelect::OnUpdate +807e2c1c CtrlMenuCharacterSelect::GetButtonDriver +807e2c68 CtrlMenuCharacterSelect::OnButtonClick +807e2d60 CtrlMenuCharacterSelect::OnButtonSelect +807e2e40 CtrlMenuCharacterSelect::OnButtonDeselect +807e2eec CtrlMenuCharacterSelect::OnMiiButtonClick +807e3038 CtrlMenuCharacterSelect::OnMiiButtonSelect +807e3118 CtrlMenuCharacterSelect::OnMiiButtonDeselect +807e31c4 CtrlMenuCharacterSelect::OnMultiplayerMiiSelected +807e3258 CtrlMenuCharacterSelect::GetUnlockedCharacterCountByWeight +807e3318 CtrlMenuCharacterSelect::GetCorrectButtonDriverId +807e346c CtrlMenuCharacterSelect::ButtonDriver::GetClassName +807e347c CtrlMenuCharacterSelect::ButtonDriver::InitSelf +807e3518 CtrlMenuCharacterSelect::ButtonDriver::SetPositionAnim +807e3568 CtrlMenuCharacterSelect::ButtonDriver::ResetButtonColours +807e379c CtrlMenuCharacterSelect::ButtonDriver::SetButtonColours +807e3a40 CtrlMenuCharacterSelect::GetRuntimeTypeInfo +807e3a4c CtrlMenuCharacterSelect::ButtonDriver::GetRuntimeTypeInfo +807e3a58 CtrlMenuCharacterSelect_cpp_sinit_ +807e3a7c CtrlMenuCourseSelectCupSub::GetClassName +807e3a88 CtrlMenuCourseSelectCup::GetClassName +807e3a98 CtrlMenuCourseSelectCourse::GetClassName +807e3aa8 CourseButton::GetClassName +807e3ab8 CtrlMenuCourseSelectCup::Load +807e3c2c CtrlMenuCourseSelectCup::InitSelf +807e3db0 CtrlMenuCourseSelectCupSub::SetRelativePosition +807e3e34 CtrlMenuCourseSelectCupSub::InitSelf +807e3ed0 CtrlMenuCourseSelectCupSub::OnUpdate +807e45e0 Pages::CourseSelect::GetManipulatorManager +807e45e8 CtrlMenuCourseSelectCourse::Load +807e4784 CtrlMenuCourseSelectCourse::InitSelf +807e4aa0 CtrlMenuCourseSelectCourse::OnCourseButtonClick +807e4af8 CtrlMenuCourseSelectCourse::OnCourseButtonSelect +807e4c64 CtrlMenuCourseSelectCourse::GetRuntimeTypeInfo +807e4c70 CourseButton::GetRuntimeTypeInfo +807e4c7c CtrlMenuCourseSelectCup::GetRuntimeTypeInfo +807e4c88 CtrlMenuCourseSelectCupSub::GetRuntimeTypeInfo +807e4c94 CtrlMenuCoursecpp_sinit_ +807e4cc0 CourseButton::__dt(PushButton) +807e4cc8 0x807e4cc8 +807e4cd0 CourseButton::GetRuntimeTypeInfo(PushButton) +807e4cd8 CtrlMenuCupSelectCup::GetClassName +807e4ce4 CtrlMenuCupSelectCourse::GetClassName +807e4cf4 CtrlMenuCupSelectCup::Load +807e4f00 CtrlMenuCupSelectCup::InitSelf +807e52c4 CtrlMenuCupSelectCup::OnCupButtonSelect +807e53d4 CtrlMenuCupSelectCup::OnCupButtonClick +807e5434 CtrlMenuCupSelectCup::IsCupUnlocked +807e5538 CtrlMenuCupSelectCourse::Load +807e565c CtrlMenuCupSelectCourse::UpdateTrackList +807e5748 CtrlMenuCupSelectCourse::InitSelf +807e584c CtrlMenuCupSelectCourse::OnUpdate +807e5a40 CtrlMenuCupSelectCourse::GetRuntimeTypeInfo +807e5a4c CtrlMenuCupSelectCup::GetRuntimeTypeInfo +807e5a58 CtrlMenuCupcpp_sinit_ +807e5a74 0x807e5a74 +807e5a80 0x807e5a80 +807e5a90 0x807e5a90 +807e5cd8 0x807e5cd8 +807e5e88 0x807e5e88 +807e5fa8 0x807e5fa8 +807e6008 0x807e6008 +807e6190 0x807e6190 +807e627c 0x807e627c +807e639c 0x807e639c +807e63a0 0x807e63a0 +807e63ac 0x807e63ac +807e63b8 0x807e63b8 +807e63d4 CtrlMenuMRStageSelectLevelSub::GetClassName +807e63e0 CtrlMenuMRStageSelectLevel::GetClassName +807e63f0 CtrlMenuMRStageSelectStage::GetClassName +807e6400 MRStageButton::GetClassName +807e6410 MissionStageSelectLevel::OnInit +807e65dc 0x807e65dc +807e66fc 0x807e66fc +807e6754 0x807e6754 +807e67b0 CtrlMenuMRStageSelectLevelSub::OnUpdate +807e6a0c 0x807e6a0c +807e6a14 MissionStageSelectStage::OnInit +807e6c48 0x807e6c48 +807e6e20 0x807e6e20 +807e6e78 0x807e6e78 +807e7024 0x807e7024 +807e7030 0x807e7030 +807e703c 0x807e703c +807e7048 CtrlMenuMRStageSelectLevelSub::GetRuntimeTypeInfo +807e7054 0x807e7054 +807e7080 0x807e7080 +807e7088 0x807e7088 +807e7090 0x807e7090 +807e7098 CtrlMenuMachineGraph::GetClassName +807e70a4 CtrlMenuMachineGraph::Load +807e73f4 MachineAbility::__ct +807e7430 MachineAbility::__dt +807e7488 CtrlMenuMachineGraph::OnUpdate +807e748c CtrlMenuMachineGraph::OnLoad +807e75b0 MachineAbility::InitSelf +807e7784 CtrlMenuMachineGraph::GetRuntimeTypeInfo +807e7790 CtrlMenuMachineGraph_cpp_sinit +807e77a4 CtrlMenuMovieHandler::Toggle +807e77f4 CtrlMenuMovieHandler::IsMirror +807e793c CtrlMenuMovieButton::GetPaneNames +807e7948 CtrlMenuMovieLayout::GetPaneNames +807e7954 CtrlMenuSingleTopMovieButton::GetPaneNames +807e7960 CtrlMenuMovieButton::GetClassName +807e796c CtrlMenuMovieButton::OnLoad +807e7b14 MovieScale::__ct +807e7b18 CtrlMenuMovieButton::InitSelf +807e7d04 CtrlMenuMovieButton::OnUpdate +807e7e08 CtrlMenuSingleTopMovieButton::GetClassName +807e7e18 CtrlMenuSingleTopMovieButton::OnLoad +807e7fc0 CtrlMenuSingleTopMovieButton::GetMovieCount +807e7fc8 CtrlMenuSingleTopMovieButton::InitSelf +807e81b4 CtrlMenuSingleTopMovieButton::OnUpdate +807e82b8 CtrlMenuMovieLayout::GetClassName +807e82c8 CtrlMenuMovieLayout::OnLoad +807e8470 CtrlMenuMovieLayout::GetMovieCount +807e8478 CtrlMenuMovieLayout::InitSelf +807e8664 CtrlMenuMovieLayout::OnUpdate +807e8768 CtrlMenuMovieLayout::GetRuntimeTypeInfo +807e8774 CtrlMenuSingleTopMovieButton::GetRuntimeTypeInfo +807e8780 CtrlMenuSingleTopMovieButton::__dt +807e87dc CtrlMenuMovieButton::GetRuntimeTypeInfo +807e87e8 CtrlMenuMovie_cpp_sinit_ +807e8810 CtrlMenuMovieButton::__dt(PushButton) +807e8818 CtrlMenuMovieButton::GetClassName(PushButton) +807e8820 CtrlMenuMovieButton::GetRuntimeTypeInfo(PushButton) +807e8828 CtrlMenuSingleTopMovieButton::OnUpdate(PushButton) +807e8830 CtrlMenuSingleTopMovieButton::InitSelf(PushButton) +807e8838 CtrlMenuSingleTopMovieButton::OnLoad(PushButton) +807e8840 CtrlMenuSingleTopMovieButton::__dt(PushButton) +807e8848 CtrlMenuSingleTopMovieButton::GetClassName(PushButton) +807e8850 CtrlMenuSingleTopMovieButton::GetRuntimeTypeInfo(PushButton) +807e8858 CtrlMenuMovieLayout::OnUpdate(LayoutUIControl) +807e8860 CtrlMenuMovieLayout::InitSelf(LayoutUIControl) +807e8868 CtrlMenuMovieLayout::__dt(LayoutUIControl) +807e8870 CtrlMenuMovieLayout::GetClassName(LayoutUIControl) +807e8878 CtrlMenuMovieLayout::GetRuntimeTypeInfo(LayoutUIControl) +807e8880 CtrlMenuBackButton::GetClassName +807e888c CtrlMenuDummyBack::GetClassName +807e889c CtrlMenuPageTitleText::GetClassName +807e88ac CtrlMenuInstructionText::GetClassName +807e88bc CtrlMenuObiTop::GetClassName +807e88cc CtrlMenuObiBottom::GetClassName +807e88dc CtrlMenuBackButton::OnUpdate +807e8a24 CtrlMenuBackButton::OnInit +807e8a7c CtrlMenuBackButton::SetPositionAnim +807e8ae8 CtrlMenuPageTitleTextText::Load +807e8c7c CtrlMenuBackButton::SetPlayerBitfield +807e8c8c CtrlMenuDummyBack::Load +807e8d90 CtrlMenuDummyBack::OnUpdate +807e8ee8 CtrlMenuPageTitleText::SetMessage +807e8f04 CtrlMenuPageTitleText::SetPositionAnim +807e8f70 CtrlMenuInstructionText::Load +807e9008 CtrlMenuInstructionText::SetPositionAnim +807e90a4 CtrlMenuInstructionText::SetMessage +807e90d4 CtrlMenuObiTop::SetPositionAnim +807e912c 0x807e912c +807e9184 0x807e9184 +807e91dc 0x807e91dc +807e91e8 CtrlMenuObiTop::__dt +807e9240 CtrlMenuObiTop::GetRuntimeTypeInfo +807e924c 0x807e924c +807e9258 CtrlMenuPageTitleText::GetRuntimeTypeInfo +807e9264 CtrlMenuDummyBack::GetRuntimeTypeInfo +807e9270 CtrlMenuBackButton::GetRuntimeTypeInfo +807e927c CtrlMenuText_cpp_sinit_ +807e92b0 CtrlMenuPressStart::GetClassName +807e92bc CtrlMenuPressStart::InitSelf +807e9338 CtrlMenuPressStart::OnUpdate +807e933c CtrlMenuPressStart::Load +807e93fc CtrlMenuPressStart::GetRuntimeTypeInfo +807e9408 CtrlMenuPressStart_cpp_sinit_ +807e941c CtrlMenuTeamConfirmTeam::GetClassName +807e942c CtrlMenuTeamConfirmTeam::Load +807e95c8 CtrlMenuTeamConfirmTeam::InitSelf +807e98ac CtrlMenuTeamConfirmTeam::GetRuntimeTypeInfo +807e98b8 CtrlMenuTeamConfirmTeam_cpp_sinit_ +807e98dc CtrlRace2DMap::GetClassName +807e98e8 CtrlRace2DMap::Load +807e9f08 CtrlRace2DMapCharacer::__ct +807e9f44 CtrlRaceBase::__dt +807e9f9c CtrlRace2DMapObject::__dt +807e9ff8 CtrlRace2DMapCharacter::__dt +807ea058 CtrlRace2DMapBossObj::__ct +807ea094 CtrlRace2DMapBossObj::__dt +807ea0f4 CtrlRace2DMapObject::SetMapPosition +807ea110 CtrlRace2DMapObject::SetMapRotation +807ea12c CtrlRace2DMap::InitSelf +807ea1a8 CtrlRace2DMap::OnUpdate +807ea1b8 zz_807eab4c +807ea288 CtrlRace2DMapObject::GetClassName +807ea298 CtrlRace2DMapObject::InitSelf +807ea2e8 CtrlRace2DMapObject::GetPaneName +807ea2f4 CtrlRace2DMapObject::OnUpdate +807ea368 CtrlRace2DMapObject::CalculatePosition +807ea45c CtrlRace2DMapCharacter::GetClassName +807ea46c CtrlRace2DMapCharacer::Load +807ea538 CtrlRace2DMapCharacter::InitSelf +807ea8bc CtrlRace2DMapCharacer::OnUpdate +807eaa38 CtrlRace2DMapCharacter::CalculatePosition +807eb064 CtrlRace2DMapBossObj::GetClassName +807eb074 CtrlRace2DMapBossObj::Load +807eb0cc CtrlRace2DMapBossObj::InitSelf +807eb3bc CtrlRace2DMapBossObj::OnUpdate +807eb4ac CtrlRaceBase::GetPane +807eb4b4 CtrlRace2DMapBossObj::GetPaneName +807eb4c0 CtrlRace2DMapBossObj::GetRuntimeTypeInfo +807eb4cc CtrlRace2DMapCharacter::GetPaneName +807eb4d8 CtrlRace2DMapCharacter::GetRuntimeTypeInfo +807eb4e4 CtrlRace2DMapObject::GetRuntimeTypeInfo +807eb4f0 CtrlRace2DMap::__dt +807eb54c CtrlRace2DMap::GetRuntimeTypeInfo +807eb558 CtrlRace2DMap_cpp_sinit_ +807eb580 CtrlRaceBase::GetClassName +807eb58c CtrlRaceBase::HudSlotColorEnable +807eb878 CtrlRaceBase::SetPanePosition +807eb978 CtrlRaceBase::setPausingPhase +807eba1c CtrlRaceBase::IsInactive +807eba30 CtrlRaceBase::HasStarted +807eba4c CtrlRaceBase::UpdatePausePosition +807ebd54 CtrlRaceBase::InitSelf +807ebe64 CtrlRaceBase::GetPlayerId +807ebf58 CtrlRaceBase::GetRuntimeTypeInfo +807ebf64 0x807ebf64 +807ebf78 CtrlRaceBattleAddPoint::GetClassName +807ebf84 CtrlRaceBattleAddPoint::Load +807ec018 CtrlRaceBattleAddPoint::InitSelf +807ec0f8 CtrlRaceBattleAddPoint::OnUpdate +807ec3f4 CtrlRaceBattlePoint::GetClassName +807ec404 CtrlRaceBattlePoint::SetPanePosition +807ec5c8 0x807ec5c8 +807ec618 CtrlRaceBattlePoint::SetPositionAnim +807ec704 CtrlRaceBattlePoint::Init +807ec7a0 CtrlRaceBattlePoint::OnUpdate +807ec85c CtrlRaceBattlePoint::Load +807ec8c4 CtrlRaceBattleTotalPoint::GetClassName +807ec8d4 CtrlRaceBattleTotalPoint::Init +807ec9d0 CtrlRaceBattleTotalPoint::OnUpdate +807ed054 CtrlRaceBattleTotalPoint::Load +807ed1f0 CtrlRaceBattleTotalPoint::__dt +807ed24c CtrlRaceBattleTotalPoint::GetRuntimeTypeInfo +807ed258 CtrlRaceBattlePoint::__dt +807ed2b4 CtrlRaceBattlePoint::GetRuntimeTypeInfo +807ed2c0 CtrlRaceBattleAddPoint::GetRuntimeTypeInfo +807ed2cc CtrlRaceBattleAddPoint::__dt +807ed328 CtrlRaceBattlePoint_cpp_sinit_ +807ed404 CtrlRaceBattleSetPoint::GetClassName +807ed410 CtrlRaceBattleSetPoint::Load +807ed524 CtrlRaceBattleSetPoint::InitSelf +807ed844 CtrlRaceBattleSetPoint::__dt +807ed89c CtrlRaceBattleSetPoint::GetRuntimeTypeInfo +807ed8a8 CtrlRaceBattleSetPoint_cpp_sinit_ +807ed8bc CtrlRaceCount::GetClassName +807ed8c8 CtrlRaceCount::Load +807ed978 CtrlRaceCount::Init +807ed9c4 CtrlRaceCount::OnUpdate +807eda08 CtrlRaceCount::IsFadingIn +807eda40 CtrlRaceCount::FadeIn +807eda78 CtrlRaceCount::__dt +807edad4 CtrlRaceCount::GetRuntimeTypeInfo +807edae0 CtrlRaceCount_cpp_sinit +807edaf4 CtrlRaceGhostDiffTime::GetClassName +807edb00 CtrlRaceGhostDiffTime::Init +807edbb4 CtrlRaceGhostDiffTime::OnUpdate +807ede2c CtrlRaceGhostDiffTime::AddTimers +807edecc CtrlRaceGhostDiffTime::SubtractTimers +807edf4c CtrlRaceGhostDiffTime::Load +807edffc CtrlRaceGhostDiffTime::__dt +807ee080 CtrlRaceGhostDiffTime::GetRuntimeTypeInfo +807ee08c CtrlRaceGhostDiffTime_cpp_sinit +807ee0a0 CtrlRaceItemWindow::GetClassName +807ee0ac CtrlRaceItemWindow::Init +807ee478 CtrlRaceItemWindow::IsInactive +807ee540 CtrlRaceItemWindow::HasStarted +807ee5d0 CtrlRaceItemWindow::OnUpdate +807eeb34 CtrlRaceItemWindow::Load +807eeb9c CtrlRaceItemWindow::AnimateItemIcon +807eeccc CtrlRaceItemWindow::__dt +807eed28 CtrlRaceItemWindow::GetRuntimeTypeInfo +807eed34 CtrlRaceItemWindow_cpp_sinit_ +807eed48 CtrlRaceLap::GetClassName +807eed54 CtrlRaceLap::Init +807eee7c CtrlRaceLap::OnUpdate +807eef3c CtrlRaceLap::Load +807eefe8 CtrlRaceLap::__dt +807ef044 CtrlRaceLap::GetRuntimeTypeInfo +807ef050 CtrlRaceLap_cpp_sinit_ +807ef060 CtrlRaceLive::getClassName +807ef06c CtrlRaceLive::initLayout +807ef0dc screenElement_setupPauseMovement +807ef0e0 0x807ef0e0 +807ef0e4 CtrlRaceLiveMessage::getClassName +807ef0f4 CtrlRaceLiveMessage::initLayout +807ef148 CtrlRaceLiveMessage::onInit +807ef1fc CtrlRaceLiveMessage::onUpdate +807ef28c CtrlRaceLiveMessage::__dt +807ef2e8 CtrlRaceLiveMessage::getInstance +807ef2f4 CtrlRaceLive::__dt +807ef350 0x807ef350 +807ef35c __sinit_CtrlRaceLive_cpp +807ef378 CtrlRaceNameBalloon:GetClassName +807ef384 CtrlRaceNameBalloon::Load +807ef534 CtrlRaceNameBalloon::InitSelf +807ef6b0 CtrlRaceNameBalloon::UpdateInfo +807efd54 CtrlRaceNameBalloon::OnUpdate +807f039c 0x807f039c +807f0540 0x807f0540 +807f0604 0x807f0604 +807f0700 CtrlRaceNameBalloon::UpdatePosition +807f0998 RaceBalloons::Update +807f11f8 0x807f11f8 +807f125c 0x807f125c +807f12a0 RaceBalloons::AddNameBalloon +807f12bc RaceBalloons::AddItemBalloon +807f12c4 RaceBalloons::__ct +807f13b0 RaceBalloons::Init +807f1410 0x807f1410 +807f1420 RaceBalloons::OnItemObjTargeting +807f1590 0x807f1590 +807f15ac CtrlRaceItemBalloon::GetClassName +807f15bc CtrlRaceItemBalloon::Load +807f1784 CtrlRaceItemBalloon::InitSelf +807f1928 CtrlRaceItemBalloon::OnUpdate +807f21e0 0x807f21e0 +807f22f0 0x807f22f0 +807f2b58 CtrlRaceItemBalloon::UpdateIcon +807f2cf8 CtrlRaceItemBalloon::UpdatePositionForPlayer +807f33d4 0x807f33d4 +807f3bbc 0x807f3bbc +807f3cec 0x807f3cec +807f3d2c 0x807f3d2c +807f3e28 CtrlRaceItemBalloon::__dt +807f3e80 CtrlRaceItemBalloon::GetRuntimeTypeInfo +807f3e8c CtrlRaceNameBalloon::__dt +807f3ee4 CtrlRaceNameBalloon::GetRuntimeTypeInfo +807f3ef0 0x807f3ef0 +807f3f5c CtrlRaceRankNum::GetClassName +807f3f68 CtrlRaceRankNum::Init +807f4074 CtrlRaceRankNum::OnUpdate +807f4220 CtrlRaceRankNum::Load +807f43ac CtrlRaceRankNum::IsInactive +807f444c CtrlRaceRankNum::__dt +807f44a8 CtrlRaceRankNum::GetRuntimeTypeInfo +807f44b4 CtrlRaceRankNum_cpp_sinit_ +807f44c8 CtrlRaceResult::GetClassName +807f44d4 CtrlRaceResult::Load +807f4638 0x807f4638 +807f4840 0x807f4840 +807f4960 CtrlRaceResult::FillName +807f4aac 0x807f4aac +807f4ab8 0x807f4ab8 +807f4d40 CtrlRaceResult::FillScore +807f4e08 0x807f4e08 +807f4fc8 CtrlRaceResult::FillFinishTime +807f50b8 CtrlRaceResult::Init +807f50bc CtrlRaceResult::OnUpdate +807f5390 CtrlRaceResult::807f5d24 +807f5498 0x807f5498 +807f558c CtrlRaceResult::GetBRCTRName +807f5608 CtrlRaceResult::CanEnd +807f5658 CtrlRaceResult::Fill +807f5afc CtrlRaceResult::__dt +807f5b54 CtrlRaceResult::GetRuntimeTypeInfo +807f5b60 CtrlRaceResult_cpp_sinit_ +807f5b7c CtrlRaceResultTeam::GetClassName +807f5b88 CtrlRaceResultTeam::Load +807f6050 CtrlRaceResultTeam::InitSelf +807f6624 CtrlRaceResultTeam::OnUpdate +807f6890 CtrlRaceResultTeam::IsResultAnimDone +807f6a2c CtrlRaceResultTeam::ComparePlayers +807f6ac4 CtrlResultAddPoint::GetClassName +807f6ad4 CtrlResultAddPoint::Load +807f6bfc CtrlResultAddPoint::InitSelf +807f6c50 CtrlResultAddPoint::OnUpdate +807f6c6c 0x807f6c6c +807f6cc0 CtrlResultAddPoint::GetRuntimeTypeInfo +807f6ccc CtrlRaceResultTeam::GetRuntimeTypeInfo +807f6cd8 CtrlResultAddPoint::__dt +807f6d34 CtrlRaceResultTeam_cpp_sinit_ +807f6d58 CtrlRaceScore::GetClassName +807f6d64 CtrlRaceScore::InitSelf +807f6eb8 CtrlRaceScore::OnUpdate +807f6f80 CtrlRaceScore::Load +807f6fdc CtrlRaceScore::SetMessage +807f71b4 CtrlRaceScore::__dt +807f7210 CtrlRaceScore::GetRuntimeTypeInfo +807f721c CtrlRaceScore_cpp_sinit_ +807f7230 CtrlRaceTime::GetClassName +807f723c CtrlRaceTime::__ct +807f72d8 CtrlRaceTime::InitSelf +807f74d0 CtrlRaceTime::GetPlayerMaxLap +807f74ec CtrlRaceTime::GetPlayerId +807f7520 CtrlRaceTime::GetRacedata +807f752c CtrlRaceTime::OnUpdate +807f78d8 CtrlRaceTime::GetParentPageId +807f78e0 CtrlRaceTime::GetParentPage +807f78ec CtrlRaceTime::IsPaused +807f78f4 CtrlRaceTime::GetCurSection +807f7904 CtrlRaceTime::GetSectionId +807f7918 CtrlRaceTime::FillTimerGlobal +807f7928 CtrlRaceTime::HasPlayerFinished +807f7948 CtrlRaceTime::FillLapSplitTimer +807f7960 CtrlRaceTime::IsBattle +807f798c CtrlRaceTime::CheckTimer +807f79cc CtrlRaceTime::IsTimerInvalid +807f79ec CtrlRaceTime::ResetTimer +807f7a10 CtrlRaceTime::IsOnlineVS +807f7a30 CtrlRaceTime::IsModeFlag4 +807f7a3c CtrlRaceTime::IsPlayerLast +807f7a5c CtrlRaceTime::FillFinishTimeTimer +807f7a98 CtrlRaceTime::Load +807f7b2c CtrlRaceTime::SetTimer +807f7dd4 CtrlRaceTime::SetPositionAnim +807f7eac CtrlRaceTime::DisableFlashingAnimation +807f7ee4 CtrlRaceTime::EnableFlashingAnimation +807f7f1c CtrlRaceTime::Func_0x5c +807f7f24 CtrlRaceTime::Func_0x58 +807f7f2c CtrlRaceTime::OnDefocus +807f7f54 CtrlRaceTime::OnFocus +807f7f78 CtrlRaceTime::__dt +807f7fd4 CtrlRaceTime::GetRuntimeTypeInfo +807f7fe0 CtrlRaceTime_cpp_sinit_ +807f7ff4 CtrlRaceWifiStartMessage::GetClassName +807f8000 CtrlRaceWifiStartMessage::Load +807f8210 CtrlRaceWifiStartMessage::HasStarted +807f8244 CtrlRaceWifiStartMessage::IsInactive +807f8254 CtrlRaceWifiStartMessage::SetPanePosition +807f82a0 CtrlRaceWifiStartMessage::OnUpdate +807f82b0 CtrlRaceWifiFinishMessage::GetClassName +807f82c0 CtrlRaceWifiFinishMessage::Load +807f8374 CtrlRaceWifiFinishMessage::HasStarted +807f83f4 CtrlRaceWifiFinishMessage::IsInactive +807f83fc CtrlRaceWifiFinishMessage::SetPanePosition +807f85f8 CtrlRaceWifiFinishMessage::OnUpdate +807f8608 CtrlRaceWaitSymbol::GetClassName +807f8618 CtrlRaceWaitSymbol::Load +807f86d4 CtrlRaceWaitSymbol::HasStarted +807f8708 CtrlRaceWaitSymbol::IsInactive +807f8718 CtrlRaceWaitSymbol::SetPanePosition +807f8764 CtrlRaceWaitSymbol::OnUpdate +807f8774 CtrlRaceWaitSymbol::GetPane +807f877c CtrlRaceWaitSymbol::__dt +807f87d8 CtrlRaceWaitSymbol::GetRuntimeTypeInfo +807f87e4 CtrlRaceWifiFinishMessage::GetPane +807f87ec CtrlRaceWifiFinishMessage::__dt +807f8848 CtrlRaceWifiFinishMessage::GetRuntimeTypeInfo +807f8854 CtrlRaceWifiStartMessage::GetPane +807f885c CtrlRaceWifiStartMessage::__dt +807f88b8 CtrlRaceWifiStartMessage::GetRuntimeTypeInfo +807f88c4 CtrlRaceWifi_cpp_sinit_ +807f88e4 GeoHitTableHolder::__ct +807f89b4 GeoHitTableHolder::__dt +807f89f4 Objects::Airblock::__ct +807f8a90 Objects::Airblock::__ct(Vec3s) +807f8b38 Objects::Airblock::OnStart +807f8be8 ObjectCollisionPolyhedra::GetRadius +807f8bf0 Objects::Airblock::LoadCollision +807f8d10 Objects::Airblock::UpdateCollision +807f8ddc Objects::Airblock::vf_0xb4 +807f8ea8 Objects::Airblock::GetCollisionDiameter +807f8ed0 Objects::Airblock::IsCollidingNoTerrainInfo +807f8ed4 Objects::Airblock::IsCollidingAddEntryNoTerrainInfo +807f8ed8 Objects::Airblock::vf_0xfc +807f8edc Objects::Airblock::IsCollidingAddEntry +807f8ee0 Objects::Airblock::IsCollidingNoTerrainInfoNoTriangleCheck(no radius) +807f8ef0 Objects::Airblock::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck(no radius) +807f8f00 Objects::Airblock::IsColliding(no radius) +807f8f10 Objects::Airblock::IsCollidingNoTriangleCheck(no radius) +807f8f20 Objects::Airblock::IsCollidingNoTerrainInfoNoTriangleCheck +807f8f24 Objects::Airblock::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +807f8f28 Objects::Airblock::IsColliding +807f8f2c Objects::Airblock::IsCollidingNoTriangleCheck +807f8f30 Objects::Airblock::vf_0xc0 +807f8f40 Objects::Airblock::vf_0xc4 +807f8f50 Objects::Airblock::vf_0xc8 +807f8f60 Objects::Airblock::vf_0xcc +807f8f70 Objects::Airblock::Update +807f8f74 Objects::Airblock::GetPropertiesBitfield +807f8f7c Objects::Airblock::__dt +807f8fbc Objects::Airblock::IsCollidingNoTerrainInfoImpl +807f9280 Objects::Airblock::IsCollidingAddEntryNoTerrainInfoImplImpl +807f9564 0x807f9564 +807f9b88 Objects::Airblock::IsCollidingAddEntryImpl +807fa1c4 Objects::Aurora::__ct +807fa230 Objects::Aurora::OnStart +807fa2f0 Objects::Aurora::Update +807fa57c 0x807fa57c +807fa668 0x807fa668 +807fa6cc 0x807fa6cc +807fa9a8 Objects::Aurora::CalcOtherEntityDistance +807faa08 Objects::Aurora::UpdateOtherEntityPosWithRot +807fab8c Objects::Aurora::vf_0x11c +807fab94 Objects::Aurora::vf_0x108 +807faba0 Objects::Aurora::AreItemsAllowed +807faba8 Objects::Aurora::IsCollidingNoTerrainInfo +807fabac Objects::Aurora::IsCollidingAddEntryNoTerrainInfo +807fabb0 Objects::Aurora::vf_0xfc +807fabb4 Objects::Aurora::IsCollidingAddEntry +807fabb8 Objects::Aurora::IsCollidingNoTerrainInfoNoTriangleCheck(no radius) +807fabc8 Objects::Aurora::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck(no radius) +807fabd8 Objects::Aurora::IsColliding(no radius) +807fabe8 Objects::Aurora::IsCollidingNoTriangleCheck(no radius) +807fabf8 Objects::Aurora::IsCollidingNoTerrainInfoNoTriangleCheck +807fabfc Objects::Aurora::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +807fac00 Objects::Aurora::IsColliding +807fac04 Objects::Aurora::IsCollidingNoTriangleCheck +807fac08 Objects::Aurora::vf_0xc0 +807fac18 Objects::Aurora::vf_0xc4 +807fac28 Objects::Aurora::vf_0xc8 +807fac38 Objects::Aurora::vf_0xc8 +807fac48 Objects::Aurora::GetCollisionDiameter +807fac5c Objects::Aurora::LoadAnimations +807face8 Objects::Aurora::vf_0xb4 +807facec Objects::Aurora::UpdateCollision +807facf0 Objects::Aurora::LoadCollision +807facf4 Objects::Aurora::GetPropertiesBitfield +807facfc Objects::Aurora::__dt +807fad3c Objects::Aurora::IsCollidingNoTerrainInfoImpl +807faf1c Objects::Aurora::IsCollidingAddEntryNoTerrainInfoImpl +807fb12c 0x807fb12c +807fb4d8 Objects::Aurora::IsCollidingAddEntryImpl +807fb8b4 0x807fb8b4 +807fb900 Objects::Belt::vf_0x120 +807fbbe4 Objects::BeltEasy::__ct +807fbc58 Objects::Belt::__dt +807fbc98 Objects::BeltEasy::vf_0x124 +807fbd34 Objects::BeltEasy::vf_0x128 +807fbdd0 Objects::BeltCrossing::__ct +807fbe44 Objects::BeltCrossing::vf_0x124 +807fbee0 Objects::BeltCrossing::vf_0x128 +807fbf78 Objects::BeltCurveA::__ct +807fc040 Objects::BeltCurveA::vf_0x124 +807fc310 Objects::BeltCurveA::vf_0x128 +807fc368 Objects::BeltCurveA::LoadModels +807fc454 Objects::BeltCurveA::LoadAnimations +807fc754 Objects::BeltCurveA::UpdateModelMatrix +807fc818 Objects::BeltCurveA::OnStart +807fc820 Objects::BeltCurveA::Update +807fc9f8 Objects::BeltCurveA::vf_0x12c +807fcc0c 0x807fcc0c +807fccd8 0x807fccd8 +807fcd10 Objects::Belt::vf_0x11c +807fcd18 Objects::Belt::UpdateOtherEntityPosWithRot +807fcd1c Objects::Belt::UpdateOtherEntityPos +807fcd20 Objects::Belt::CalcOtherEntityDistance +807fcd24 Objects::Belt::vf_0x108 +807fcd30 Objects::Belt::AreItemsAllowed +807fcd38 Objects::Belt::IsCollidingNoTerrainInfo +807fcd40 Objects::Belt::IsCollidingAddEntryNoTerrainInfo +807fcd48 Objects::Belt::vf_0xfc +807fcd50 Objects::Belt::IsCollidingAddEntry +807fcd60 Objects::Belt::IsCollidingNoTerrainInfoNoTriangleCheck(no radius) +807fcd68 Objects::Belt::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck(no radius) +807fcd70 Objects::Belt::IsColliding(no radius) +807fcd78 Objects::Belt::IsCollidingAddEntryNoTriangleCheck(no radius) +807fcd94 Objects::Belt::IsCollidingNoTerrainInfoNoTriangleCheck +807fcd9c Objects::Belt::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +807fcda4 Objects::Belt::IsColliding +807fcdac Objects::Belt::vf_0xc0 +807fcdbc 0x807fcdbc +807fcdc4 Objects::Belt::vf_0xc4 +807fcdcc Objects::Belt::vf_0xc8 +807fcdd4 Objects::Belt::vf_0xcc +807fcdf0 Objects::Belt::GetCollisionDiameter +807fcdfc Objects::Belt::vf_0xb4 +807fce00 Objects::Belt::UpdateCollision +807fce04 Objects::Belt::LoadCollision +807fce08 Objects::Belt::GetPropertiesBitfield +807fce10 Objects::BeltCurveA::SetObjInfoCalcBit +807fce20 Objects::BeltCurveA::GetScnObjDrawOptionsIdx +807fce28 Objects::BeltCurveA::__dt +807fce68 Objects::Belt::SetObjInfoCalcBit +807fce78 Objects::Belt::vf_0x12c +807fcecc Objects::Belt::LoadAnimations +807fcf0c Objects::BeltCrossing::GetScnObjDrawOptionsIdx +807fcf14 Objects::BeltCrossing::__dt +807fcf54 Objects::BeltEasy::GetScnObjDrawOptionsIdx +807fcf5c Objects::BeltEasy::__dt +807fcf9c Objects::Belt::GetScnObjDrawOptionsIdx +807fcfa4 0x807fcfa4 +807fd150 0x807fd150 +807fd2bc 0x807fd2bc +807fd4c8 0x807fd4c8 +807fd620 0x807fd620 +807fd648 0x807fd648 +807fd6a8 0x807fd6a8 +807fd938 0x807fd938 +807fd9d0 0x807fd9d0 +807fdb68 0x807fdb68 +807fdb98 0x807fdb98 +807fdba0 0x807fdba0 +807fdc54 0x807fdc54 +807fdc5c 0x807fdc5c +807fdc9c 0x807fdc9c +807fdcc4 Objects::Crane::__ct +807fde58 Objects::Crane::Update +807fe0c4 ObjectExternKCL::vf_0x11c +807fe0cc ObjectExternKCL::CalcOtherEntityDistance +807fe12c ObjectExternKCL::GetTransformationMatrix +807fe15c Objects::Crane::GetPeriod +807fe18c Objects::Crane::GetPropertiesBitfield +807fe194 Objects::Crane::__dt +807fe1d4 0x807fe1d4 +807fe29c 0x807fe29c +807fe3c8 0x807fe3c8 +807fe3ec 0x807fe3ec +807fe644 0x807fe644 +807fe7e8 0x807fe7e8 +807fec08 0x807fec08 +807feea8 0x807feea8 +807fef78 0x807fef78 +807fefec 0x807fefec +807feff8 0x807feff8 +807ff090 0x807ff090 +807ff098 0x807ff098 +807ff0a0 0x807ff0a0 +807ff0e0 0x807ff0e0 +807ff0ec 0x807ff0ec +807ff0f4 0x807ff0f4 +807ff100 0x807ff100 +807ff10c 0x807ff10c +807ff14c 0x807ff14c +807ff18c 0x807ff18c +807ff440 0x807ff440 +807ff76c 0x807ff76c +807ffe44 0x807ffe44 +807fff68 0x807fff68 +8080007c 0x8080007c +80800128 0x80800128 +80800628 0x80800628 +80800838 0x80800838 +80800b18 0x80800b18 +80800df8 0x80800df8 +80801064 0x80801064 +80801220 0x80801220 +80801e10 0x80801e10 +80802018 0x80802018 +808022dc 0x808022dc +808022e4 0x808022e4 +8080236c 0x8080236c +80802378 0x80802378 +80802384 0x80802384 +8080238c 0x8080238c +808023cc 0x808023cc +808023d4 0x808023d4 +808023d8 0x808023d8 +808023dc 0x808023dc +808023ec 0x808023ec +808023f0 0x808023f0 +808023fc 0x808023fc +80802404 0x80802404 +8080240c 0x8080240c +8080254c 0x8080254c +8080268c 0x8080268c +808027cc 0x808027cc +808027dc 0x808027dc +808028d0 0x808028d0 +808029c4 0x808029c4 +80802ab8 0x80802ab8 +80802bac 0x80802bac +80802cec 0x80802cec +80802e2c 0x80802e2c +80802f6c 0x80802f6c +80802f7c 0x80802f7c +80803070 0x80803070 +80803164 0x80803164 +80803258 0x80803258 +8080334c 0x8080334c +80803358 0x80803358 +8080335c 0x8080335c +80803364 0x80803364 +8080336c 0x8080336c +808033ac Objects::bblock::__ct +80803414 Objects::VolcanoPiece::__dt +80803454 Objects::bblock::LoadModels +808035d8 Objects::VolcanoPiece::GetSubFileName +808035e0 Objects::bblock::OnStart +80803638 Objects::bblock::UpdateModelMatrix +808036c0 Objects::bblock::LoadAnimations +80803774 Objects::bblock::LoadCollision +80803a2c Objects::bblock::GetBRRESName +80803a38 Objects::bblock::SetCollisionType +80803a84 Objects::bblock::Init_eAnm +80803b2c Objects::VolcanoPiece::UpdateKCL +80803c14 Objects::VolcanoPiece::SetCollisionType +80803c18 Objects::VolcanoPiece::IsCollidingNoTerrainInfo +80803d9c Objects::VolcanoPiece::IsCollidingAddEntryNoTerrainInfo +80803f20 Objects::VolcanoPiece::vf_0xfc +808040a4 Objects::VolcanoPiece::IsCollidingAddEntry +808040b4 Objects::VolcanoPiece::IsCollidingNoTerrainInfoNoTriangleCheck(no radius) +808041fc Objects::VolcanoPiece::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck(no radius) +80804344 Objects::VolcanoPiece::IsColliding(no radius) +8080448c Objects::VolcanoPiece::IsCollidingAddEntryNoTriangleCheck(no radius) +808045d4 Objects::VolcanoPiece::IsCollidingNoTerrainInfoNoTriangleCheck +80804758 Objects::VolcanoPiece::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +808048dc Objects::VolcanoPiece::IsColliding +80804a60 Objects::VolcanoPiece::IsCollidingAddEntryNoTriangleCheck +80804a70 Objects::VolcanoPiece::vf_0xc0 +80804bb8 Objects::VolcanoPiece::vf_0xc4 +80804d00 Objects::VolcanoPiece::vf_0xc8 +80804e48 Objects::VolcanoPiece::vf_0xcc +80804f90 Objects::VolcanoPiece::UpdateDiffPosVector +80804fc8 Objects::VolcanoPiece::GetTransformationMatrix +80804fe0 Objects::VolcanoPiece::GetPropertiesBitfield +80804fe8 Objects::bblock::UpdateModelScale +80805078 Objects::bblock::__dt +808050b8 Objects::DKturibashiGCc::__ct +80805144 Objects::DKturibashiGCc::OnStart +80805290 Objects::DKturibashiGCc::Update +808054d0 0x808054d0 +808055b0 0x808055b0 +80805740 Objects::DKturibashiGCc::UpdateOtherEntityPos +808058d4 Objects::DKturibashiGCc::UpdateOtherEntityPosWithRot +80805a98 Objects::DKturibashiGCc::vf_0x11c +80805aa0 Objects::DKturibashiGCc::vf_0x108 +80805aac Objects::DKturibashiGCc::AreItemsAllowed +80805ab4 Objects::DKturibashiGCc::IsCollidingAddEntryNoTerrainInfo +80805ab8 Objects::DKturibashiGCc::IsCollidingAddEntryNoTerrainInfo +80805abc Objects::DKturibashiGCc::vf_0xfc +80805ac0 Objects::DKturibashiGCc::IsCollidingAddEntry +80805ac4 Objects::DKturibashiGCc::IsCollidingNoTerrainInfo(no radius) +80805ad4 Objects::DKturibashiGCc::IsCollidingAddEntryNoTerrainInfo(no radius) +80805ae4 Objects::DKturibashiGCc::vf_0xec(no radius) +80805af4 Objects::DKturibashiGCc::IsCollidingAddEntry(no radius) +80805b04 Objects::DKturibashiGCc::IsCollidingNoTerrainInfoNoTriangleCheck +80805b08 Objects::DKturibashiGCc::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +80805b0c Objects::DKturibashiGCc::IsColliding +80805b10 Objects::DKturibashiGCc::IsCollidingNoTriangleCheck +80805b14 Objects::DKturibashiGCc::vf_0xc0 +80805b24 Objects::DKturibashiGCc::vf_0xc4 +80805b34 Objects::DKturibashiGCc::vf_0xc8 +80805b44 Objects::DKturibashiGCc::vf_0xcc +80805b54 Objects::DKturibashiGCc::GetCollisionDiameter +80805b68 Objects::DKturibashiGCc::LoadAnimations +80805b6c Objects::DKturibashiGCc::vf_0xb4 +80805b70 Objects::DKturibashiGCc::UpdateCollision +80805b74 0x80805b74 +80805b78 Objects::DKturibashiGCc::GetPropertiesBitfield +80805b80 Objects::DKturibashiGCc::__dt +80805bc0 0x80805bc0 +80805f0c 0x80805f0c +80806290 0x80806290 +8080677c Objects::DKturibashiGCc::IsCollidingImpl +80806c88 Objects::Kinoko::__ct +80806e58 Objects::Kinoko::OnStart +80806e98 Objects::Kinoko::Update +80806fbc Objects::Kinoko_ud::__ct +80807080 Objects::Kinoko::__dt +808070c0 Objects::Kinoko_ud::UpdateSpecific +808071e8 Objects::Kinoko_bend::__ct +80807304 Objects::Kinoko_bend::UpdateSpecific +808073f0 Objects::Kinoko::vf_0xb4 +808073f4 Objects::Kinoko::SetYScale +808073f8 Objects::Kinoko::GetSubFileName +80807418 Objects::Kinoko::GetPropertiesBitfield +80807420 Objects::Kinoko_bend::__dt +80807460 0x80807460 +80807464 Objects::Kinoko_ud::SetYScale +80807468 Objects::Kinoko_ud::GetSubFileName +80807488 Objects::Kinoko_ud::__dt +808074c8 Objects::Kinoko_kuki::vf_0xec +808074cc Objects::Kinoko_kuki::vf_0xf0 +808074d0 Objects::Kinoko_kuki::GetSubFileName +808074f0 Objects::Kinoko_kuki::UpdateModelScale +808074f4 Objects::Kinoko_kuki::GetPropertiesBitfield +808074fc Objects::Kinoko_kuki::__dt +8080753c ObjAmi_construct +808075ac 0x808075ac +80807660 0x80807660 +8080788c 0x8080788c +80807974 0x80807974 +80807be4 0x80807be4 +80807c28 0x80807c28 +80807c88 0x80807c88 +80807df0 0x80807df0 +80807df8 0x80807df8 +80807e04 0x80807e04 +80807e0c 0x80807e0c +80807e10 0x80807e10 +80807e14 0x80807e14 +80807e18 0x80807e18 +80807e1c 0x80807e1c +80807e2c 0x80807e2c +80807e3c 0x80807e3c +80807e4c 0x80807e4c +80807e5c 0x80807e5c +80807e60 0x80807e60 +80807e64 0x80807e64 +80807e68 0x80807e68 +80807e6c 0x80807e6c +80807e7c 0x80807e7c +80807e8c 0x80807e8c +80807e9c 0x80807e9c +80807eac 0x80807eac +80807eb8 0x80807eb8 +80807ebc 0x80807ebc +80807ec0 0x80807ec0 +80807ec4 0x80807ec4 +80807ecc 0x80807ecc +80807f0c 0x80807f0c +808080f8 0x808080f8 +80808314 0x80808314 +808086cc 0x808086cc +80808ab4 Objects::TownBridgeDS::__ct +80808c24 Objects::TownBridgeDS::LoadCollision +80808de0 Objects::TownBridgeDS::Update +80809348 0x80809348 +80809630 0x80809630 +80809688 0x80809688 +8080975c Objects::TownBridgeDS::CalcOtherEntityDistance +80809b18 Objects::TownBridgeDS::UpdateOtherEntityPosWithRot +80809f20 Objects::TownBridgeDS::vf_0x11c +80809f28 Objects::TownBridgeDS::vf_0x108 +80809f34 Objects::TownBridgeDS::AreItemsAllowed +80809f3c Objects::TownBridgeDS::GetPeriod +80809f48 Objects::TownBridgeDS::LoadAnimations +80809fd0 Objects::TownBridgeDS::GetTransformationMatrix +8080a344 Objects::TownBridgeDS::GetPropertiesBitfield +8080a34c Objects::TownBridgeDS::__dt +8080a38c 0x8080a38c +8080a744 obj_obakeblockSFC::__ct +8080a8b0 0x8080a8b0 +8080a984 0x8080a984 +8080abd0 0x8080abd0 +8080abe4 0x8080abe4 +8080b194 0x8080b194 +8080b2d0 0x8080b2d0 +8080b42c Object::GetCollisionDiameter +8080b438 0x8080b438 +8080b440 0x8080b440 +8080b444 0x8080b444 +8080b448 0x8080b448 +8080b44c 0x8080b44c +8080b450 0x8080b450 +8080b454 0x8080b454 +8080b458 0x8080b458 +8080b45c 0x8080b45c +8080b460 0x8080b460 +8080b470 0x8080b470 +8080b480 0x8080b480 +8080b490 0x8080b490 +8080b4a0 0x8080b4a0 +8080b4a4 0x8080b4a4 +8080b4a8 0x8080b4a8 +8080b4ac 0x8080b4ac +8080b4b0 0x8080b4b0 +8080b4c0 0x8080b4c0 +8080b4d0 0x8080b4d0 +8080b4e0 0x8080b4e0 +8080b4f0 0x8080b4f0 +8080b4fc 0x8080b4fc +8080b500 0x8080b500 +8080b504 0x8080b504 +8080b508 0x8080b508 +8080b510 0x8080b510 +8080b550 0x8080b550 +8080ba80 ObjectCollisionPolyhedra::SetRadius +8080ba88 0x8080ba88 +8080bfec 0x8080bfec +8080c798 0x8080c798 +8080cf68 0x8080cf68 +8080cfdc 0x8080cfdc +8080d014 0x8080d014 +8080d020 0x8080d020 +8080d02c 0x8080d02c +8080d038 0x8080d038 +8080d09c 0x8080d09c +8080d100 0x8080d100 +8080d174 0x8080d174 +8080d3e0 0x8080d3e0 +8080d53c obj_quicksand::__ct +8080d754 0x8080d754 +8080dcb8 0x8080dcb8 +8080e418 0x8080e418 +8080e6b8 0x8080e6b8 +8080e8a8 0x8080e8a8 +8080eeac 0x8080eeac +8080f4b0 0x8080f4b0 +8080f7b4 0x8080f7b4 +8080f7dc 0x8080f7dc +8080fbc4 0x8080fbc4 +8080fbcc 0x8080fbcc +8080fbd8 0x8080fbd8 +8080fbe0 0x8080fbe0 +8080fbe4 0x8080fbe4 +8080fbe8 0x8080fbe8 +8080fbec 0x8080fbec +8080fbf0 0x8080fbf0 +8080fc00 0x8080fc00 +8080fc10 0x8080fc10 +8080fc20 0x8080fc20 +8080fc30 0x8080fc30 +8080fc34 0x8080fc34 +8080fc38 0x8080fc38 +8080fc3c 0x8080fc3c +8080fc40 0x8080fc40 +8080fc50 0x8080fc50 +8080fc60 0x8080fc60 +8080fc70 0x8080fc70 +8080fc80 0x8080fc80 +8080fc94 0x8080fc94 +8080fcfc 0x8080fcfc +8080fd08 0x8080fd08 +8080fd14 0x8080fd14 +8080fd18 0x8080fd18 +8080fd1c 0x8080fd1c +8080fd20 0x8080fd20 +8080fd28 0x8080fd28 +8080fd68 0x8080fd68 +8080fd74 0x8080fd74 +8080fd80 0x8080fd80 +8080fd88 0x8080fd88 +8080fd90 0x8080fd90 +8080fdec 0x8080fdec +80810228 0x80810228 +80810690 0x80810690 +80810d8c 0x80810d8c +808114b4 0x808114b4 +808115f4 0x808115f4 +808117ec 0x808117ec +808117f4 0x808117f4 +80811968 0x80811968 +808119f0 0x808119f0 +80811ae8 0x80811ae8 +80811eb4 0x80811eb4 +80811ebc 0x80811ebc +808121ec 0x808121ec +808124b4 0x808124b4 +80812864 0x80812864 +80812c60 0x80812c60 +80812d58 0x80812d58 +80813150 0x80813150 +8081315c 0x8081315c +808131ec 0x808131ec +808131f8 0x808131f8 +80813200 0x80813200 +80813240 Objects::TwistedWay::__ct +808132ac Objects::TwistedWay::OnStart +80813368 Objects::TwistedWay::Update +808135ac 0x808135ac +8081368c 0x8081368c +8081379c 0x8081379c +808138dc 0x808138dc +80813a94 Objects::TwistedWay::CalcOtherEntityDistance +80813c44 Objects::TwistedWay::UpdateOtherEntityPosWithRot +80813e14 0x80813e14 +80813ea8 Objects::TwistedWay::vf_0x11c +80813eb0 Objects::TwistedWay::vf_0x108 +80813ebc Objects::TwistedWay::AreItemsAllowed +80813ec4 Objects::TwistedWay::IsCollidingNoTerrainInfo +80813ec8 Objects::TwistedWay::IsCollidingAddEntryNoTerrainInfo +80813ecc Objects::TwistedWay::vf_0xfc +80813ed0 Objects::TwistedWay::IsCollidingAddEntry +80813ed4 Objects::TwistedWay::IsCollidingNoTerrainInfoNoTriangleCheck(no radius) +80813ee4 Objects::TwistedWay::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck(no radius) +80813ef4 Objects::TwistedWay::IsColliding(no radius) +80813f04 Objects::TwistedWay::IsCollidingAddEntryNoTriangleCheck(no radius) +80813f14 Objects::TwistedWay::IsCollidingNoTerrainInfoNoTriangleCheck +80813f18 Objects::TwistedWay::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +80813f1c Objects::TwistedWay::IsColliding +80813f20 Objects::TwistedWay::IsCollidingAddEntryNoTriangleCheck +80813f24 Objects::TwistedWay::vf_0xc0 +80813f34 Objects::TwistedWay::vf_0xc4 +80813f44 Objects::TwistedWay::vf_0xc8 +80813f54 Objects::TwistedWay::vf_0xcc +80813f64 Objects::TwistedWay::GetCollisionDiameter +80813f6c Objects::TwistedWay::LoadAnimations +80813f70 Objects::TwistedWay::vf_0xb4 +80813f74 Objects::TwistedWay::UpdateCollision +80813f78 Objects::TwistedWay::LoadCollision +80813f7c Objects::TwistedWay::GetPropertiesBitfield +80813f84 Objects::TwistedWay::__dt +80813fc4 0x80813fc4 +80814514 0x80814514 +80814ab0 0x80814ab0 +808153d0 Objects::TwistedWay::IsCollidingImpl +80815d3c obj_venice_hasi::__ct +80815f18 0x80815f18 +8081604c 0x8081604c +80816150 0x80816150 +808165a4 0x808165a4 +80816808 0x80816808 +80816974 0x80816974 +80816a38 0x80816a38 +80816be4 0x80816be4 +80816d4c 0x80816d4c +80816f00 0x80816f00 +80816f08 0x80816f08 +80816f0c 0x80816f0c +80816f10 0x80816f10 +80816f1c 0x80816f1c +80816f24 0x80816f24 +80816f30 0x80816f30 +80816f40 0x80816f40 +80816f48 0x80816f48 +80816f50 0x80816f50 +80816f90 ObjSaku_construct +80817038 0x80817038 +808172cc 0x808172cc +8081740c 0x8081740c +80817414 0x80817414 +80817454 Objects::VolcanoPiece::__ct +808175d8 Objects::VolcanoPiece::LoadCollision +808179a0 Objects::VolcanoPiece::UpdateCollisionPosition +80817ce0 Objects::VolcanoPiece::SetYScale +80817e20 Objects::VolcanoPiece::GetTransformationMatrixImpl +80818638 0x80818638 +80818694 0x80818694 +80818780 0x80818780 +80818a68 Objects::VolcanoPiece::Init_eAnm +80818a6c Objects::VolcanoPiece::Update +80819014 Objects::VolcanoPiece::IsCollidingAddEntryNoTriangleCheckImpl +8081940c Objects::VolcanoPiece::IsCollidingImpl +80819804 Objects::VolcanoRock1::__ct +808199dc Objects::VolcanoRock1::Update +80819a80 Objects::VolcanoRock1::CalcTranslation +80819c3c Objects::VolcanoRock1::GetPeriod +80819c78 Objects::VolcanoRock1::GetTransformationMatrix +80819cd4 Objects::VolcanoRock1::GetSubFileName +80819cf4 Objects::VolcanoRock1::GetPropertiesBitfield +80819cfc Objects::VolcanoRock1::__dt +80819d3c ObjectKCL::__ct +80819d80 ObjectKCL::__ct(Vec3s, objId) +80819dc4 ObjectKCL::__ct(Vec3s, name) +80819e08 ObjectKCL::Init +80819ec8 ObjectKCL::RegisterEntity +80819f3c ObjectKCL::UpdateModel +80819fec ObjectExternKCL::__ct +8081a034 0x8081a034 +8081a07c 0x8081a07c +8081a0c4 ObjectExternKCL::LoadCollision +8081a1b8 ObjectExternKCL::InitCollision +8081a3d8 ObjectExternKCL::UpdateCollisionPosition +8081a594 ObjectExternKCL::SetYScale +8081a620 ObjectExternKCL::IsCollidingAddEntryNoTriangleCheckImpl +8081a7d8 ObjectExternKCL::IsCollidingImpl +8081a990 ObjectsKCLMgr::__ct +8081a9ec ObjectsKCLMgr::__dt +8081aa94 ObjectsKCLMgr::CreateInstance +8081ab1c ObjectsKCLMgr::DestroyInstance +8081ab6c ObjectsKCLMgr::Init +8081ac14 0x8081ac14 +8081ac84 ObjectsKCLMgr::Update +8081ad34 ObjectsKCLMgr::AddObject +8081ae38 ObjectsKCLMgr::UpdateKCL +8081aedc 0x8081aedc +8081afac 0x8081afac +8081b07c 0x8081b07c +8081b1c0 0x8081b1c0 +8081b304 ObjectsKCLMgr::IsCollidingNoTerrainInfoNoTriangleCheck +8081b3dc ObjectsKCLMgr::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +8081b4b4 ObjectsKCLMgr::IsColliding +8081b60c ObjectsKCLMgr::IsCollidingAddEntryNoTriangleCheck +8081b764 0x8081b764 +8081b854 0x8081b854 +8081b944 0x8081b944 +8081baa8 0x8081baa8 +8081bc0c ObjectsKCLMgr::IsCollidingNoTerrainInfo +8081bd20 ObjectsKCLMgr::IsCollidingAddEntryNoTerrainInfo +8081be34 0x8081be34 +8081bfc4 ObjectsKCLMgr::IsCollidingAddEntry +8081c154 0x8081c154 +8081c1dc GetKartWeightClass +8081c3a8 GetCharacterWeightClass +8081c51c 0x8081c51c +8081c560 CharacterIdToKartIdByIdx +8081c5dc 0x8081c5dc +8081c618 0x8081c618 +8081c620 IsKartUnlocked +8081c68c IsCharacterUnlocked +8081c694 0x8081c694 +8081c6c8 0x8081c6c8 +8081c6fc KartObjectCollision::Init +8081c764 KartObjectCollision::Init_switch +8081c768 KartObjectCollision::Init_case1 +8081c7d8 KartObjectCollision::Init_case0 +8081c824 KartObjectCollision::Init_case2 +8081c898 KartObjectCollision::Init_case3 +8081c908 KartObjectCollision::Init_case6 +8081c968 KartObjectCollision::Init_case9 +8081c9c4 KartObjectCollision::Init_casec +8081ca40 KartObjectCollision::Init_casef +8081ca9c KartObjectCollision::Init_case4 +8081cb1c KartObjectCollision::Init_case7 +8081cb90 KartObjectCollision::Init_casea +8081cbf8 KartObjectCollision::Init_cased +8081cc7c KartObjectCollision::Init_case10 +8081ccfc KartObjectCollision::Init_case5 +8081cd84 KartObjectCollision::Init_case8 +8081ce04 KartObjectCollision::Init_caseb +8081ce84 KartObjectCollision::Init_casee +8081cf08 KartObjectCollision::Init_case11 +8081cfa8 KartObjectCollision::Init_case12 +8081d004 KartObjectCollision::Init_case13 +8081d060 KartObjectCollision::Init_case14 +8081d0c0 KartObjectCollision::Init_case15 +8081d120 KartObjectCollision::Init_case18 +8081d180 KartObjectCollision::Init_case1b +8081d1dc KartObjectCollision::Init_case1e +8081d238 KartObjectCollision::Init_case21 +8081d298 KartObjectCollision::Init_case16 +8081d2f8 KartObjectCollision::Init_case19 +8081d354 KartObjectCollision::Init_case1c +8081d3b0 KartObjectCollision::Init_case1f +8081d410 KartObjectCollision::Init_case22 +8081d470 KartObjectCollision::Init_case17 +8081d4d0 KartObjectCollision::Init_case1a +8081d548 KartObjectCollision::Init_case1d +8081d5a8 KartObjectCollision::Init_case20 +8081d608 KartObjectCollision::Init_case23 +8081d738 KartObjectCollision::__ct +8081d750 KartObjectCollision::__dt +8081d7dc KartObjectCollision::Update +8081d8c0 ObjectCollisionPolyhedra::GetDefaultDiameter +8081d8c8 0x8081d8c8 +8081d8f0 MenuModelBRRESHandle::__ct +8081d908 MenuModelBRRESHandle::__dt +8081d948 0x8081d948 +8081d9c4 MenuModelBRRESHandle::BindDriverBRRES +8081dbb4 MenuModelBRRESHandle::BindKartBRRES +8081dcc4 MenuModelBRRESHandle::BindBackBRRES +8081ddb8 DriverModelAnmCalculator::__dt +8081ddf8 MenuModelBRRESHandle::LoadDriverModel +8081e130 MenuModelBRRESHandle::LinkDriverAnim +8081e42c MenuModelBRRESHandle::LoadKartModel +8081e580 MenuModelBRRESHandle::LoadBackModel +8081e648 MenuModelBRRESHandle::MdlExists +8081e658 ObjectCollidable::__ct(GOBJ) +8081e694 ObjectCollidable::::__ct(Vec3s, objId) +8081e6d0 ObjectCollidable::::__ct(Vec3s, name) +8081e70c ObjectCollidable::Init +8081e7dc ObjectCollidable::RegisterManagedObject +8081e7ec ObjectCollidable::RegisterEntity +8081e890 ObjectCollidable::LoadCollision +8081ebb4 ObjectCollidable::OnNormalCollision +8081ec44 ObjectCollidable::OnWallCollision +8081ecd8 ObjectCollidable::BeforeKartCollision +8081ede4 ObjectCollidable::BeforeItemCollision +8081ee34 ObjectCollidable::UpdateCollision +8081ee94 Object::__ct +8081f028 Object::__ct(Vec3s, objId) +8081f170 Object::__ct(Vec3s, name) +8081f2d4 Object::OnStart +8081f358 Object::LoadModels +8081f36c Object::LoadModels(r4) +8081f37c Object::LoadGraphics +8081f9cc Object::LoadSound +8081fb24 Object::LinkSound +8081fb68 Object::StartSoundLimited +8081fb88 Object::HoldSoundLimited +8081fba8 Object::StartNewSoundLimited +8081fbc8 Object::StartSound +8081fbe8 Object::HoldSound +8081fc08 Object::StopAllSound +8081fc28 Object::StopSound +8081fc48 Object::LoadShadow +8081fd98 Object::LoadAnimations +8081fee0 0x8081fee0 +8081ffec Object::LoadRoute +808200fc Object::LoadAnimationsByType +80820524 Object::LinkAnimations +808206dc Object::LoadClipInfo +80820cac Object::UpdateMatrix +80820d2c Object::ToggleVisible +80820da4 0x80820da4 +80820e1c 0x80820e1c +80820e24 Object::UpdateModel +80820f1c Object::CalcYAxisTransMtx +80820f7c 0x80820f7c +80820fe0 Object::UpdateShadow +80821108 Object::UpdateModelMatrix +808211d4 0x808211d4 +80821424 Object::vf_0x88 +80821444 Object::vf_0x8c +80821458 Object::DisableCollision +8082146c Object::EnableCollision +80821480 ObjectsMgr::CreateObject +80825fac 0x80825fac +808264f8 ObjectsMgr::CreateAllObjects +808270d4 Objects::Kinoko_nm::GetPeriod +808270e0 Objects::Kinoko_nm::GetSubFileName +80827100 Objects::Kinoko_nm::GetPropertiesBitfield +80827108 Objects::Kinoko_nm::__dt +80827148 0x80827148 +80827158 0x80827158 +80827238 0x80827238 +80827278 0x80827278 +80827280 0x80827280 +808272e4 0x808272e4 +80827324 0x80827324 +80827334 0x80827334 +80827374 0x80827374 +8082737c 0x8082737c +808273bc 0x808273bc +808273c4 0x808273c4 +80827404 0x80827404 +80827444 0x80827444 +80827484 0x80827484 +808274c4 0x808274c4 +808275e0 0x808275e0 +80827750 0x80827750 +808277c4 0x808277c4 +80827a78 0x80827a78 +80827a94 0x80827a94 +80827aac 0x80827aac +80827bd0 0x80827bd0 +80827bd4 0x80827bd4 +80827bdc 0x80827bdc +80827c1c Objects::Itembox::__ct +80827dd8 Objects::Itembox::__ct(position) +80827ecc Objects::Itembox::Update +80828324 Objects::Itembox::OnCollision +808285b0 Objects::F_Itembox::__ct +80828604 Objects::F_Itembox::OnStart +808286e0 Objects::F_Itembox::Update +80828874 Objects::S_Itembox::__ct +808288ec Objects::S_Itembox::OnStart +80828ac8 Objects::S_Itembox::Update +80828bf0 Objects::S_Itembox::__dt +80828c30 Objects::F_Itembox::__dt +80828c70 0x80828c70 +80828ca8 Objects::Heyho2::__ct +80828d64 Objects::Heyho2::OnStart +80828dd0 Objects::Heyho2::Lift::__ct +80828f48 Objects::Heyho2::Lift::OnStart +80829110 Objects::Heyho2::Lift::Update +80829304 Objects::Heyho2::Lift::UpdateModelMatrix +808293d4 Objects::Heyho2::Rider::__ct +80829540 Objects::Heyho2::Rider::OnStart +80829678 Objects::Heyho2::Rider::LoadAnimations +8082967c Objects::Heyho2::Rider::Update +808297a0 Objects::Heyho2::LoadRoute +808297a4 Objects::Heyho2::Update +808297a8 Objects::Heyho2::LoadModels +808297ac Objects::Heyho2::LoadAnimations +808297b0 Objects::Heyho2::GetPropertiesBitfield +808297b8 Objects::Heyho2::__dt +808297f8 Objects::Heyho2::Lift::GetBRRESName +80829804 Objects::Heyho2::Lift::GetSubFileName +80829824 Objects::Heyho2::Lift::GetPropertiesBitfield +8082982c Objects::Heyho2::Lift::vf_0xa8 +80829834 Objects::Heyho2::Lift::__dt +80829874 Objects::Heyho2::Rider::LoadRoute +80829878 Objects::Heyho2::Rider::vf_0xa8 +80829880 Objects::Heyho2::Rider::GetBRRESName +8082988c Objects::Heyho2::Rider::GetSubFileName +808298d8 Objects::Heyho2::Rider::GetPropertiesBitfield +808298e0 0x808298e0 +80829920 ObjectsMgr::Start +808299f8 ObjectsMgr::__ct +80829cc0 ObjectCollisionManager::__dt +80829d00 ObjectsMgr::__dt +80829df0 ObjectsMgr::CreateInstance +80829e90 ObjectsMgr::DestroyInstance +80829ef0 0x80829ef0 +80829f60 ObjectsMgr::Update +8082a12c 0x8082a12c +8082a170 ObjectsMgr::CheckCollision +8082a428 ObjectsMgr::HandleItemCollision +8082a658 0x8082a658 +8082a754 ObjectsMgr::AddObject +8082a900 0x8082a900 +8082aa0c ObjectsMgr::RegisterManagedObject +8082aa14 ObjectsMgr::GetManagedObject +8082aa24 ObjectsMgr::GetManagedObjectsCount +8082aa40 ObjectsMgr::GetPseaVeniceHeightDiff +8082aa58 ObjectsMgr::GetPseaVeniceHeight +8082aa6c ObjectsMgr::GetPseaVeniceHeightMinus260 +8082aa8c 0x8082aa8c +8082aa98 0x8082aa98 +8082ab4c ObjectCollisionManager::GetPlayerItemState +8082ab90 ObjectCollisionManager::Get_0x1c +8082ab98 0x8082ab98 +8082ab9c 0x8082ab9c +8082aba0 ObjectCollisionManager::GetPosition +8082aba8 GeoHitTableKartObjHolder::__dt +8082abe8 GeoHitTableKartHolder::__dt +8082ac28 GeoHitTableObjHolder::__dt +8082ac68 GeoHitTableItemHolder::__dt +8082aca8 Objects::MiiStatue::__ct +8082adb4 0x8082adb4 +8082ae54 0x8082ae54 +8082aef4 0x8082aef4 +8082af94 0x8082af94 +8082b084 Objects::MiiStatue::__dt +8082b14c Objects::MiiStatue::OnStart +8082b354 Objects::MiiStatue::Update +8082b478 Objects::MiiStatue::GetPropertiesBitfield +8082b480 0x8082b480 +8082b778 ObjFlowHolder::__ct +8082b7e4 ObjFlowHolder::GetObjIDByName +8082b860 ObjFlowHolder::__dt +8082b8a0 Objects::Psea::__ct +8082bca0 Objects::Psea::Update +8082bef0 Objects::Psea::LoadModels +8082bef4 Objects::Psea::GetPropertiesBitfield +8082befc Objects::Psea::__dt +8082bf3c Objects::Psea5spc::GetScnObjDrawOptionsIdx +8082bf44 Objects::Psea5spc::GetName +8082bf50 Objects::Psea5spc::GetSubFileName +8082bf5c Objects::Psea5spc::GetPropertiesBitfield +8082bf64 Objects::Psea5spc::__dt +8082bfa4 Objects::Psea4tex::GetScnObjDrawOptionsIdx +8082bfac Objects::Psea4tex::GetName +8082bfb8 Objects::Psea4tex::GetSubFileName +8082bfc4 Objects::Psea4tex::GetPropertiesBitfield +8082bfcc Objects::Psea4tex::__dt +8082c00c Objects::Psea3nami::GetScnObjDrawOptionsIdx +8082c014 Objects::Psea3nami::GetName +8082c020 Objects::Psea3nami::GetSubFileName +8082c02c Objects::Psea3nami::GetPropertiesBitfield +8082c034 Objects::Psea3nami::__dt +8082c074 Objects::Psea2dark::GetScnObjDrawOptionsIdx +8082c07c Objects::Psea2dark::GetName +8082c088 Objects::Psea2dark::GetSubFileName +8082c094 Objects::Psea2dark::GetPropertiesBitfield +8082c09c Objects::Psea2dark::__dt +8082c0dc Objects::Psea1sand::GetScnObjDrawOptionsIdx +8082c0e4 Objects::Psea1sand::GetName +8082c0f0 Objects::Psea1sand::GetSubFileName +8082c0fc Objects::Psea1sand::GetPropertiesBitfield +8082c104 Objects::Psea1sand::__dt +8082c144 Objects::Pylon01::_ct +8082c2d0 Objects::Pylon01::GetScnObjDrawOptionsIdx +8082c2e8 Objects::Pylon01::GetBRRESName +8082c320 Objects::Pylon01::LoadAnimations +8082c3cc Objects::Pylon01::OnStart +8082c6b0 Objects::Pylon01::Update +8082d258 Objects::Pylon01::OnCollision +8082d644 Objects::Pylon01::OnItemCollision +8082d76c 0x8082d76c +8082da5c 0x8082da5c +8082db60 Objects::Pylon01::OnWallCollision +8082db64 Objects::Pylon01::GetPropertiesBitfield +8082db6c Objects::Pylon01::__dt +8082dbac Objects::WLscreenGC::__ct +8082dc74 Objects::WLscreenGC::__dt +8082dd14 Objects::WLscreenGC::LoadModels +8082deb8 Objects::WLscreenGC::OnStart +8082debc Objects::WLscreenGC::Update +8082dec0 obj_venice_nami::__ct +8082e060 0x8082e060 +8082e254 0x8082e254 +8082e308 0x8082e308 +8082e5ec obj_venice_nami_update +8082e7b4 0x8082e7b4 +8082e984 0x8082e984 +8082ea18 0x8082ea18 +8082ea24 0x8082ea24 +8082ea2c 0x8082ea2c +8082ea34 0x8082ea34 +8082ea74 BackModelMgr::__ct +8082eb40 BackModelMgr::__dt +8082eb80 BackModelMgr::Start +8082ec64 BackModelMgr::Update +8082edec BackModelMgr::SetBackModel +8082eeb8 BackModelMgr::ToggleVisible +8082eecc MenuDriverModel::__ct +8082ef24 MenuVehicleDisplayModel::__dt +8082ef64 MenuDriverModel::Init +8082f0fc 0x8082f0fc +8082f1e4 MenuDriverModel::SwitchState +8082f578 MenuDriverModel::Update +8082f70c 0x8082f70c +8082f7a0 0x8082f7a0 +8082f7ec MenuDriverModelMgr::__ct +8082fd74 MenuDriverModel::__dt +8082fdb4 0x8082fdb4 +8082fe1c MenuDriverModel::Update +808300c8 MenuModel::ToggleVisible +808300ec MenuDriverModel::Draw +808302a8 MenuDriverModelMgr::TogglePlayerModel +808302d0 MenuDriverModelMgr::PrepareDriverOnKartAnms +8083036c MenuDriverModel::SetPlayerCharacter +808306b8 0x808306b8 +8083076c 0x8083076c +80830ab8 0x80830ab8 +80830ba0 0x80830ba0 +80830d90 0x80830d90 +80831160 0x80831160 +80831240 MenuDriverModelMgr::__dt +80831280 MenuModel::Update +80831284 MenuModel::Init +80831288 DriverModelAnmCalculator::Determine +8083138c DriverModelAnmCalculator::GetPrefix +80831488 0x80831488 +808314bc 0x808314bc +808314c4 0x808314c4 +8083151c 0x8083151c +80831574 0x80831574 +808315cc MenuKartModel::__ct +808315f0 MenuKartModel::__dt +80831630 MenuKartModel::Load +808318ac MenuKartModel::Init +80831dc8 MenuKartModel::Update +80832154 MenuKartModelMgr::__ct +80832328 0x80832328 +8083232c 0x8083232c +8083236c MenuKartModelMgr::Load +80832604 0x80832604 +80832678 MenuKartModelMgr::Update +80832830 MenuKartModelMgr::Draw +808328fc MenuKartModelMgr::SetKartModel +80832954 MenuKartModelMgr::Reset +80832a18 MenuKartModelMgr::ToggleVisible +80832ab0 0x80832ab0 +80832ae0 MenuKartModelMgr::GetMenuKartModel +80832b0c MenuKartModelMgr::__dt +80832b4c 0x80832b4c +80832b7c 0x80832b7c +80832ca4 GetCupNameMsgId +80832cd4 getTrackBmgId +80832d70 0x80832d70 +80832da0 getArenaBmgId +80832dd0 GetPositionBMGId +80832dd8 getOrangeOverlayBmgId +80832de0 0x80832de0 +80832e40 0x80832e40 +80832e44 0x80832e44 +80832e58 0x80832e58 +80832e88 GetMissionLevelNameMsgId +80832ea4 0x80832ea4 +80832eac ObjectCollisionCuboid::__ct +8083316c ObjectCollisionCuboid::SetPositionAndScale +80833558 ObjectCollisionCuboid::SetPositionAndScale(translation) +80833954 0x80833954 +8083395c ObjectCollisionCuboid::__dt +808339b4 ObjectCollision::ProcessCollision +80834620 0x80834620 +808346b8 0x808346b8 +80834750 0x80834750 +80834970 0x80834970 +80834cbc 0x80834cbc +80834e50 0x80834e50 +80834f38 0x80834f38 +80835010 0x80835010 +808350f8 0x808350f8 +808355a0 0x808355a0 +808356a0 0x808356a0 +808356d4 ObjectCollisionCylinder::__ct +808357f8 ObjectCollisionCylinder::Getposition +8083585c ObjectCollisionCylinder::SetPositionAndScale +808359a0 ObjectCollisionCylinder::SetPositionAndScale(translation) +80835afc 0x80835afc +80835b04 ObjectCollisionCylinder::GetRadius +80835b0c ObjectCollisionCylinder::__dt +80835b4c ObjectCollisionPolyhedra::__ct +80835c14 ObjectCollisionPolyhedra::__dt +80835c94 ObjectCollisionPolyhedra::GetPosition +80835d3c ObjectCollisionPolyhedra::SetPositionAndScale +80835e30 ObjectCollisionPolyhedra::SetPositionAndScale(translation) +80835f3c ObjectCollisionSphere::__ct +80835f8c ObjectCollisionSphere::GetPosition +80836004 ObjectCollisionSphere::SetPositionAndScale +808360bc ObjectCollisionSphere::SetPositionAndScale(translation) +808361c0 ObjectCollisionSphere::GetRadius +808361c8 ObjectCollisionSphere::__dt +80836208 Pages::Menu::OnInit +808367d0 Pages::Menu::CreateExternalControl +808367d8 Pages::Menu::SetButtonHandlers +808367dc Pages::Menu::OnActivate +8083694c Pages::Menu::GetTextInfo +80836954 Pages::Menu::OnControlsInitialized +80836b98 Pages::Menu::SelectButton +80836c58 Pages::Menu::OnExternalButtonSelect +80836c5c Pages::Menu::SelectExternObject +80836c88 Pages::Menu::LoadNextPageWithDelayById +80836d8c Pages::Menu::LoadNextPageById +80836e9c Pages::Menu::LoadPrevPageWithDelayById +80836fa0 Pages::Menu::LoadPrevPageById +808370b0 Pages::Menu::LoadPrevPageWithDelay +808371b8 Pages::Menu::LoadPrevPage +808372c8 Pages::Menu::ChangeSectionWithDelayById +80837388 Pages::Menu::AddPageLayer +808373b0 Pages::Menu::OnResume +808374ac Pages::Menu::ChangeSectionById +80837570 Pages::Menu::ForceChangeSectionWithDelayById +8083758c Pages::Menu::ForceChangeSectionById +808375ec Pages::Menu::LoadMessageBoxPageWithDelay +808377a8 Pages::Menu::LoadMessageBoxPage +8083796c Pages::Menu::LoadMessageBoxTransparentPageThenChangeSectionWithDelay +80837b38 Pages::Menu::LoadMessageBoxTransparentPageThenChangeSection +80837d0c Pages::Menu::LoadMessageBoxTransparentPage +80837e18 Pages::Menu::ChangePrevSection +80837e64 Pages::Menu::OnMoviesActivate +80837ef0 Pages::Menu::LoadMovies +80837f0c Pages::Menu::UnloadMovies +80837f20 Pages::Menu::IsMultiplayer +80837f5c Pages::Menu::AreAllPlayersActive +80838040 Pages::Menu::BeforeEntranceAnimations +808380dc Pages::Menu::GetNextPage +808380e4 Pages::Menu::BeforeExitAnimations +80838180 Pages::Menu::OnStartPress +80838184 MenuPage_cpp_sinit_ +80838198 Pages::MenuBG::GetPageById +808382a8 Pages::MenuBG::CreateControl +8083840c Pages::MenuBG::AfterControlUpdate +80838410 Pages::MenuBG::GetPlayerBifield +80838418 Pages::MenuBG::GetActivePlayerBitfield +80838420 Pages::MenuBG::GetManipulatorManager +80838428 Pages::MenuBG::BeforeEntranceAnimations +8083842c Pages::MenuBG::__ct +808384ac Pages::MenuBG::GetRuntimeTypeInfo +808384b8 MenuBGPage_cpp_sinit_ +808384cc Pages::BattleCupSelect::GetPageById +808385dc Pages::BattleCupSelect::OnInit +80838654 Pages::BattleCupSelect::CreateExternalControl +8083865c Pages::BattleCupSelect::CreateControl +808386f0 Pages::BattleCupSelect::OnActivate +80838a60 Pages::BattleCupSelect::AfterControlUpdate +80838bbc Pages::BattleCupSelect::UpdateText +80838bc8 Pages::BattleCupSelect::LoadNextPage +80838d00 Pages::BattleCupSelect::OnButtonClick +80838f70 Pages::BattleCupSelect::OnExternalButtonSelect +80838f74 Pages::BattleCupSelect::OnButtonDeselect +80838f78 Pages::BattleCupSelect::OnBackPress +808391e8 Pages::BattleCupSelect::OnResume +80839400 Pages::BattleCupSelect::OnDeactivate +80839404 Pages::BattleCupSelect::BeforeEntranceAnimations +80839460 Pages::BattleCupSelect::BeforeExitAnimations +808394bc Pages::BattleCupSelect::OnTimeout +808395b8 Pages::BattleCupSelect::GetPlayerBitfield +808395c0 Pages::BattleCupSelect::GetActivePlayerBitfield +808395c8 Pages::BattleCupSelect::SetButtonHandlers +80839624 Pages::BattleCupSelect::GetManipulatorManager +8083962c Pages::BattleCupSelect::__dt +80839720 Pages::BattleCupSelect::GetRuntimeTypeInfo +8083972c BattleCupSelectPage_sinit_ +80839740 Pages::BattleKartSelect::GetPageById +80839850 Pages::BattleKartSelect::OnInit +80839864 Pages::BattleKartSelect::CreateExternalControl +8083994c Pages::BattleKartSelect::SetButtonHandlers +808399a8 Pages::BattleKartSelect::CreateControl +80839ac4 Pages::BattleKartSelect::OnActivate +80839df8 Pages::BattleKartSelect::AfterControlUpdate +80839f84 Pages::BattleKartSelect::OnButtonClick +8083a110 Pages::BattleKartSelect::OnExternalButtonSelect +8083a1e4 Pages::BattleKartSelect::OnButtonDeselect +8083a1ec Pages::BattleKartSelect::OnBackPress +8083a2c0 Pages::BattleKartSelect::Func_8083ac54 +8083a3c0 Pages::BattleKartSelect::Func_8083ad54 +8083a5a8 Pages::BattleKartSelect::BeforeEntranceAnimations +8083a608 Pages::BattleKartSelect::BeforeExitAnimations +8083a668 Pages::BattleKartSelect::GetPlayerBitfield +8083a670 Pages::BattleKartSelect::GetLocalPlayerCount +8083a678 Pages::BattleKartSelect::GetManipulatorManager +8083a680 Pages::BattleKartSelect::__dt +8083a72c Pages::BattleKartSelect::GetRuntimeTypeInfo +8083a738 BattleKartSelectPagecpp_sinit_ +8083a74c Pages::BattleModeSelect::GetPageById +8083a85c Pages::BattleModeSelect::OnInit +8083a8b0 Pages::BattleModeSelect::GetManipulatorManager +8083a8b8 Pages::BattleModeSelect::CreateExternalControl +8083aa64 Pages::BattleModeSelect::CreateControl +8083aa6c Pages::BattleModeSelect::OnActivate +8083ae44 Pages::BattleModeSelect::OnActivate_switch +8083ae48 Pages::BattleModeSelect::OnActivate_case_0 +8083ae60 Pages::BattleModeSelect::OnActivate_case_1 +8083ae78 Pages::BattleModeSelect::OnActivate_case_2 +8083ae90 Pages::BattleModeSelect::OnActivate_case_3 +8083aea8 Pages::BattleModeSelect::OnActivate_case_4 +8083aec0 Pages::BattleModeSelect::OnActivate_case_5 +8083aed8 Pages::BattleModeSelect::OnActivate_case_6 +8083aef0 Pages::BattleModeSelect::OnActivate_case_7 +8083af38 Pages::BattleModeSelect::AfterControlUpdate +8083af3c Pages::BattleModeSelect::OnButtonClick +8083b018 Pages::BattleModeSelect::OnExternalButtonSelect +8083b050 Pages::BattleModeSelect::OnButtonDeselect +8083b054 Pages::BattleModeSelect::OnBackPress +8083b060 Pages::BattleModeSelect::OnDeactivate +8083b0ac Pages::BattleModeSelect::GetPlayerBitfield +8083b0b4 Pages::BattleModeSelect::GetActivePlayerBitfield +8083b0bc Pages::BattleModeSelect::SetButtonHandlers +8083b118 Pages::BattleModeSelect::__dt +8083b198 Pages::BattleModeSelect::GetRuntimeTypeInfo +8083b1a4 BattleModeSelectPage_cpp_sinit_ +8083b1b8 Pages::BattleSettings::GetPageById +8083b2c8 Pages::BattleSettings::OnInit +8083b5bc Pages::BattleSettings::CreateExternalControl +8083b64c Pages::BattleSettings::CreateControl +8083ba10 Pages::BattleSettings::OnActivate +8083bb70 Pages::BattleSettings::AfterControlUpdate +8083bb74 Pages::BattleSettings::OnButtonClick +8083bb78 Pages::BattleSettings::OnExternalButtonSelect +8083bba4 Pages::BattleSettings::OnButtonDeselect +8083bba8 Pages::BattleSettings::OnBackPress +8083bbec Pages::BattleSettings::OnRadioClick +8083bd58 Pages::BattleSettings::OnRadioChange +8083be38 Pages::BattleSettings::OnUpDownClick +8083bea4 Pages::BattleSettings::OnUpDownSelect +8083beb4 Pages::BattleSettings::OnUpDownChange +8083bf2c Pages::BattleSettings::OnTextChange +8083bfa8 Pages::BattleSettings::GetPlayerBitfield +8083bfb0 Pages::BattleSettings::GetActivePlayerBitfield +8083bfb8 Pages::BattleSettings::SetButtonHandlers +8083c014 Pages::BattleSettings::GetManipulatorManager +8083c01c Pages::BattleSettings::__dt +8083c0e4 Pages::BattleSettings::GetRuntimeTypeInfo +8083c0f0 Pages::BattleSettings::TriggerUpDown3APtmf +8083c120 Pages::BattleSettings::TriggerRadioPtmf +8083c150 Pages::BattleSettings::TriggerTextPtmf +8083c180 Pages::BattleSettings::TriggerUpDown2APtmf +8083c1b0 BattleSettingsPage_cpp_sinit_ +8083c1c4 Pages::BattleStageSelect::GetPageById +8083c2d4 Pages::BattleStageSelect::OnInit +8083c324 Pages::BattleStageSelect::CreateExternalControl +8083c32c Pages::BattleStageSelect::CreateControl +8083c3c0 Pages::BattleStageSelect::OnActivate +8083c514 Pages::BattleStageSelect::BeforeEntranceAnimations +8083c534 Pages::BattleStageSelect::AfterControlUpdate +8083c650 Pages::BattleStageSelect::UpdateBottomText +8083c654 Pages::BattleStageSelect::LoadNextPage +8083c788 Pages::BattleStageSelect::OnButtonClick +8083c7c0 Pages::BattleStageSelect::OnExternalButtonSelect +8083c7c4 Pages::BattleStageSelect::OnButtonDeselect +8083c7c8 Pages::BattleStageSelect::OnBackPress +8083c800 Pages::BattleStageSelect::BeforeExitAnimations +8083c85c Pages::BattleStageSelect::OnDeactivate +8083c860 Pages::BattleStageSelect::OnTimeout +8083c934 Pages::BattleStageSelect::GetPlayerBitfield +8083c93c Pages::BattleStageSelect::GetActivePlayerBitfield +8083c944 Pages::BattleStageSelect::SetButtonHandlers +8083c9a0 Pages::BattleStageSelect::__dt +8083ca8c Pages::BattleStageSelect::GetRuntimeTypeInfo +8083ca98 BattleStageSelectPage_cpp_sinit_ +8083caac CharaName::GetClassName +8083cab8 Pages::CharacterSelect::GetPageById +8083cbc8 Pages::CharacterSelect::OnInit +8083ceac CharaName::__ct +8083cee8 Pages::CharacterSelect::CreateExternalControl +8083cef0 Pages::CharacterSelect::CreateControl +8083d0e4 Pages::CharacterSelect::OnActivate +8083d420 Pages::CharacterSelect::GetManipulatorManager +8083d428 Pages::CharacterSelect::AfterControlUpdate +8083d614 Pages::CharacterSelect::OnButtonDriverClick +8083dc60 Pages::CharacterSelect::OnButtonDriverSelect +8083ddac Pages::CharacterSelect::OnButtonClick +8083df44 Pages::CharacterSelect::OnExternalButtonSelect +8083df90 Pages::CharacterSelect::OnButtonDeselect +8083df94 Pages::CharacterSelect::OnBackPress +8083e294 Pages::CharacterSelect::8083ec28 +8083e488 Pages::CharacterSelect::8083ee1c +8083e528 Pages::CharacterSelect::OnResume +8083e5a8 Pages::CharacterSelect::OnDispose +8083e5b8 Pages::CharacterSelect::BeforeEntranceAnimations +8083e660 Pages::CharacterSelect::BeforeExitAnimations +8083e708 CharaName::InitSelf +8083e8cc Pages::CharacterSelect::GetPlayerBitfield +8083e8d4 Pages::CharacterSelect::GetActivePlayerBitfield +8083e8dc Pages::CharacterSelect::SetButtonHandlers +8083e938 Pages::CharacterSelect::__dt +8083e9c8 Pages::CharacterSelect::GetRuntimeTypeInfo +8083e9d4 CharaName::GetRuntimeTypeInfo +8083e9e0 CharaSelectcpp_sinit_ +8083ea04 Pages::GPClassSelect::GetPageById +8083eb14 Pages::GPClassSelect::OnInit +8083ebe4 Pages::GPClassSelect::GetManipulatorManager +8083ebec Pages::GPClassSelect::CreateExternalControl +8083ee1c Pages::GPClassSelect::CreateControl +8083eea4 Pages::GPClassSelect::OnActivate +8083ef80 Pages::GPClassSelect::AfterControlUpdate +8083eff4 Pages::GPClassSelect::OnButtonClick +8083f198 Pages::GPClassSelect::OnExternalButtonSelect +8083f220 Pages::GPClassSelect::OnButtonDeselect +8083f224 Pages::GPClassSelect::OnBackPress +8083f230 Pages::GPClassSelect::OnDeactivate +8083f234 Pages::GPClassSelect::OnStartPress +8083f738 Pages::GPClassSelect::GetPlayerBitfield +8083f740 Pages::GPClassSelect::GetActivePlayerBitfield +8083f748 Pages::GPClassSelect::SetButtonHandlers +8083f7a4 Pages::GPClassSelect::__dt +8083f830 Pages::GPClassSelect::GetRuntimeTypeInfo +8083f83c GPClassSelectPage_cpp_sinit_ +8083f850 Pages::CourseSelect::GetPageById +8083f960 Pages::CourseSelect::OnInit +8083f9fc Pages::CourseSelect::CreateExternalControl +8083fa04 Pages::CourseSelect::CreateControl +8083fb0c Pages::CourseSelect::OnActivate +8083fc2c Pages::CourseSelect::BeforeEntranceAnimations +8083fc78 Pages::CourseSelect::AfterControlUpdate +8083fd94 Pages::CourseSelect::UpdateBottomText +8083fe9c Pages::CourseSelect::LoadNextPage +808400b0 Pages::CourseSelect::OnButtonClick +80840118 Pages::CourseSelect::OnExternalButtonSelect +8084011c Pages::CourseSelect::OnButtonDeselect +80840120 Pages::CourseSelect::OnBackPress +80840188 Pages::CourseSelect::BeforeExitAnimations +808401e4 Pages::CourseSelect::OnDeactivate +8084020c Pages::CourseSelect::OnTimeout +808402e0 Pages::CourseSelect::GetPlayerBitfield +808402e8 Pages::CourseSelect::GetActivePlayerBitfield +808402f0 Pages::CourseSelect::SetButtonHandlers +8084034c Pages::CourseSelect::__dt +80840438 Pages::CourseSelect::GetRuntimeTypeInfo +80840444 Pages::CourseSelect::_sinit_ +80840458 Pages::CupSelect::GetPageById +80840568 Pages::CupSelect::OnInit +8084066c Pages::CupSelect::CreateExternalControl +80840674 Pages::CupSelect::CreateControl +8084077c Pages::CupSelect::OnActivate +80840b1c Pages::CupSelect::GetManipulatorManager +80840b24 Pages::CupSelect::AfterControlUpdate +80840c80 Pages::CupSelect::UpdateText +80840db0 Pages::CupSelect::LoadNextPage +80840f54 Pages::CupSelect::OnButtonClick +808411b8 Pages::CupSelect::OnExternalButtonSelect +808411bc Pages::CupSelect::OnButtonDeselect +808411c0 Pages::CupSelect::OnBackPress +80841450 Pages::CupSelect::OnResume +80841664 Pages::CupSelect::OnDeactivate +8084168c Pages::CupSelect::BeforeEntranceAnimations +808416e8 Pages::CupSelect::BeforeExitAnimations +80841744 Pages::CupSelect::OnTimeout +80841840 Pages::CupSelect::GetPlayerBitfield +80841848 Pages::CupSelect::GetActivePlayerBitfield +80841850 Pages::CupSelect::SetButtonHandlers +808418ac Pages::CupSelect::__dt +808419a0 Pages::CupSelect::GetRuntimeTypeInfo +808419ac CupSelectPagecpp_sinit_ +808419c0 Pages::StartRace::GetPageById +80841ad0 Pages::StartRace::OnInit +80841ae8 Pages::StartRace::CreateExternalControl +80841c4c Pages::StartRace::GetActivePlayerBitfield +80841c54 Pages::StartRace::SetButtonHandlers +80841cb0 Pages::StartRace::CreateControl +80841f0c Pages::StartRace::OnActivate +80841f80 Pages::StartRace::AfterControlUpdate +80841fb4 Pages::StartRace::OnButtonClick +80842010 Pages::StartRace::OnExternalButtonSelect +80842014 Pages::StartRace::OnButtonDeselect +80842018 Pages::StartRace::OnBackPress +80842034 Pages::StartRace::GetPlayerBitfield +8084203c Pages::StartRace::GetManipulatorManager +80842044 Pages::StartRace::__dt +808420c4 Pages::StartRace::GetRuntimeTypeInfo +808420d0 StartRacePage_cpp_sinit_ +808420e4 0x808420e4 +808421f4 0x808421f4 +80842418 0x80842418 +808424bc 0x808424bc +8084252c 0x8084252c +80842618 0x80842618 +80842620 0x80842620 +80842624 0x80842624 +808429f0 0x808429f0 +80842a04 0x80842a04 +80842a08 0x80842a08 +80842cf0 0x80842cf0 +80842cf8 0x80842cf8 +80842d54 0x80842d54 +80842d5c 0x80842d5c +80842e00 0x80842e00 +80842e0c 0x80842e0c +80842e20 0x80842e20 +80842f30 0x80842f30 +80842f68 0x80842f68 +80842f70 0x80842f70 +80843004 0x80843004 +8084304c 0x8084304c +80843050 0x80843050 +8084305c 0x8084305c +808430b8 0x808430b8 +808430cc 0x808430cc +808430d0 0x808430d0 +808430d4 0x808430d4 +808430e0 0x808430e0 +8084312c 0x8084312c +80843180 0x80843180 +808431d4 0x808431d4 +808431dc 0x808431dc +808431e4 0x808431e4 +80843240 0x80843240 +80843248 0x80843248 +8084333c 0x8084333c +80843348 0x80843348 +8084335c 0x8084335c +8084346c 0x8084346c +808434dc 0x808434dc +80843568 0x80843568 +808435d8 0x808435d8 +808436bc 0x808436bc +808436c0 0x808436c0 +808437a4 0x808437a4 +808437dc 0x808437dc +808437e0 Pages::Menu::UnloadVideoSource +808437ec 0x808437ec +808437f0 0x808437f0 +808437f8 0x808437f8 +80843800 0x80843800 +8084385c 0x8084385c +80843864 0x80843864 +80843904 0x80843904 +80843910 0x80843910 +80843924 0x80843924 +80843a34 0x80843a34 +80843a48 0x80843a48 +80843a50 0x80843a50 +80843ae4 Pages::Menu::OnActivate +80843ae8 0x80843ae8 +80843b08 0x80843b08 +80843b0c 0x80843b0c +80843b10 0x80843b10 +80843b6c 0x80843b6c +80843bc8 0x80843bc8 +80843bcc 0x80843bcc +80843bd0 0x80843bd0 +80843c20 0x80843c20 +80843c74 0x80843c74 +80843cc0 0x80843cc0 +80843cc8 0x80843cc8 +80843cd0 0x80843cd0 +80843d2c 0x80843d2c +80843e18 0x80843e18 +80843e24 0x80843e24 +80843e38 Pages::KartSelect::GetPageById +80843f48 ButtonMachine::GetClassName +80843f54 Pages::KartSelect::GetVehicleID +80843fcc Pages::KartSelect::GetUnlockedVehiclesCountByWeightAndType +80844048 Pages::KartSelect::GetUnlockedVehiclesCountByWeight +80844128 Pages::KartSelect::GetMinUnlockedVehiclesCount +808443d4 Pages::KartSelect::OnInit +808447b4 Pages::KartSelect::CreateExternalControl +808447bc Pages::KartSelect::CreateControl +80844b20 Pages::KartSelect::SetButtonHandlers +80844b7c Pages::KartSelect::OnActivate +80846088 Pages::KartSelect::GetManipulatorManager +80846090 Pages::KartSelect::GetLocalPlayerCount +80846098 Pages::KartSelect::AfterControlUpdate +80846288 Pages::KartSelect::OnButtonClick +80846510 Pages::KartSelect::OnExternalButtonSelect +80846628 Pages::KartSelect::OnButtonSelect +8084662c Pages::KartSelect::OnBackPress +80846700 Pages::KartSelect::GetExternalControl +80846830 Pages::KartSelect::GetButtonMachineById +808469b0 Pages::KartSelect::InitButtonMachine +80846ac8 Pages::KartSelect::8084745c +80846bfc Pages::KartSelect::80847590 +80846c9c Pages::KartSelect::BeforeEntranceAnimations +80846cfc Pages::KartSelect::BeforeExitAnimations +80846d5c ButtonMachine::OnUpdate +80846e7c ButtonMachine::InitSelf +80846f60 zz_8478f4 +80847258 Pages::KartSelect::GetPlayerBitfield +80847260 Pages::KartSelect::__dt +808472fc Pages::KartSelect::GetRuntimeTypeInfo +80847308 ButtonMachine::GetRuntimeTypeInfo +80847314 ButtonMachine::__dt +8084736c KartSelect_cpp_sinit +80847390 Pages::MiiSelect::GetPageById +808474a0 MiiName::GetClassName +808474ac Pages::MiiSelect::OnINit +808476b0 Pages::MiiSelect::GetManipulatorManager +808476b8 Pages::MiiSelect::CreateExternalControl +80847838 Pages::MiiSelect::GetActivePlayerBitfield +80847840 Pages::MiiSelect::SetButtonHandlers +8084789c Pages::MiiSelect::CreateControl +80847bd4 Pages::MiiSelect::OnActivate +80847e54 Pages::MiiSelect::AfterControlUpdate +80847e58 Pages::MiiSelect::OnButtonClick +80848154 Pages::MiiSelect::OnExternalButtonSelect +808481c4 Pages::MiiSelect::OnButtonDeselect +808481cc Pages::MiiSelect::OnBackPress +80848240 Pages::MiiSelect::OnDeactivate +80848254 Pages::MiiSelect::OnRightArrowPress +808483ac Pages::MiiSelect::OnLeftArrowPress +808484b0 Pages::MiiSelect::OnTabButtonClick +80848600 Pages::MiiSelect::SetMiiIcons +808488a0 Pages::MiiSelect::GetCurTabMiiCount +808488f0 MiiName::InitSelf +80848ab4 Pages::MiiSelect::GetPlayerBitfield +80848abc Pages::MiiSelect::__dt +80848b64 Pages::MiiSelect::GetRuntimeTypeInfo +80848b70 MiiName::GetRuntimeTypeInfo +80848b7c Pages::MiiSelect::TriggerTabPtmf +80848bac Pages::MiiSelect::TriggerSheetPtmf +80848bdc MiiSelect_cpp_sinit_ +80848c00 Pages::MultiKartSelect::GetPageById +80848d10 Pages::MultiKartSelect::OnInit +80848fac Pages::MultiKartSelect::CreateExternalControl +80848fb4 Pages::MultiKartSelect::CreateControl +80849290 Pages::MultiKartSelect::OnActivate +808493ec Pages::MultiKartSelect::AfterControlUpdate +808494d0 Pages::MultiKartSelect::GetManipulatorManager +808494d8 Pages::MultiKartSelect::OnButtonClick +808495cc Pages::MultiKartSelect::OnExternalButtonSelect +808495d0 Pages::MultiKartSelect::OnButtonDeselect +808495d4 Pages::MultiKartSelect::OnBackPress +8084976c Pages::MultiKartSelect::OnUpDownClick +80849910 Pages::MultiKartSelect::OnUpDownChange +80849914 Pages::MultiKartSelect::OnTextChange +80849a64 Pages::MultiKartSelect::FillPossibleKarts +80849c30 0x80849c30 +80849cd4 Pages::MultiKartSelect::BeforeEntranceAnimations +80849d7c Pages::MultiKartSelect::BeforeExitAnimations +80849e24 Pages::MultiKartSelect::GetPlayerBitfield +80849e2c Pages::MultiKartSelect::GetActivePlayerBitfield +80849e34 Pages::MultiKartSelect::SetButtonHandlers +80849e90 Pages::MultiKartSelect::__dt +80849f70 Pages::MultiKartSelect::GetRuntimeTypeInfo +80849f7c TriggerPtmf +80849fac TriggerPtmf +80849fdc TriggerPtmf +8084a00c MultiKartSelectPage_cpp_sinit_ +8084a020 Pages::MultiDriftSelect::GetPageById +8084a130 Pages::MultiDriftSelect::OnInit +8084a5e8 Pages::MultiDriftSelect::GetManipulatorManager +8084a5f0 Pages::MultiDriftSelect::GetActivePlayerBitfield +8084a5f8 Pages::MultiDriftSelect::GetPlayerBitfield +8084a600 Pages::MultiDriftSelect::SetButtonHandlers +8084a65c Pages::MultiDriftSelect::OnControlsInitialized +8084a660 Pages::MultiDriftSelect::CreateExternalControl +8084a7bc Pages::MultiDriftSelect::CreateControl +8084a8ec Pages::MultiDriftSelect::OnActivate +8084a9f4 Pages::MultiDriftSelect::AfterControlUpdate +8084ab6c Pages::MultiDriftSelect::OnButtonClick +8084ae58 Pages::MultiDriftSelect::OnExternalButtonSelect +8084ae5c Pages::MultiDriftSelect::OnButtonDeselect +8084ae60 Pages::MultiDriftSelect::OnBackPress +8084af30 Pages::MultiDriftSelect::OnResume +8084aff0 Pages::MultiDriftSelect::__dt +8084b070 Pages::MultiDriftSelect::GetRuntimeTypeInfo +8084b07c MultiDriftSelectPage_cpp_sinit_ +8084b090 Pages::MultiTeamSelect::GetPageById +8084b1a0 Pages::MultiTeamSelect::OnInit +8084b668 Pages::MultiTeamSelect::GetManipulatorManager +8084b670 Pages::MultiTeamSelect::GetActivePlayerBitfield +8084b678 Pages::MultiTeamSelect::GetPlayerBifield +8084b680 Pages::MultiTeamSelect::SetButtonHandlers +8084b6dc Pages::MultiTeamSelect::OnControlsInitialized +8084b6e0 Pages::MultiTeamSelect::BeforeEntranceAnimations +8084b788 Pages::MultiTeamSelect::BeforeExitAnimations +8084b830 Pages::MultiTeamSelect::CreateExternalControl +8084b980 Pages::MultiTeamSelect::CreateControl +8084bab0 Pages::MultiTeamSelect::OnActivate +8084bd80 Pages::MultiTeamSelect::AfterControlUpdate +8084bd84 Pages::MultiTeamSelect::OnButtonClick +8084c288 Pages::MultiTeamSelect::OnExternalButtonSelect +8084c28c Pages::MultiTeamSelect::OnButtonDeselect +8084c290 Pages::MultiTeamSelect::OnBackPress +8084c39c Pages::MultiTeamSelect::OnResume +8084c488 Pages::MultiTeamSelect::AssignCPUTeams +8084c660 Pages::MultiTeamSelect::IsDifferentTeams +8084c6bc Pages::MultiTeamSelect::__dt +8084c73c Pages::MultiTeamSelect::GetRuntimeTypeInfo +8084c748 MultiTeamSelectPage_cpp_sinit_ +8084c75c Pages::MultiPlayer::GetPageById +8084c86c Pages::MultiPlayer::OnINit +8084c8cc Pages::MultiPlayer::CreateExternalControl +8084ca14 Pages::MultiPlayer::CreateControl +8084ca1c Pages::MultiPlayer::OnActivate +8084cb44 Pages::MultiPlayer::AfterControlUpdate +8084cb48 Pages::MultiPlayer::OnButtonClick +8084cd68 Pages::MultiPlayer::OnExternalButtonSelect +8084d1e8 Pages::MultiPlayer::OnButtonDeselect +8084d1ec Pages::MultiPlayer::OnBackPress +8084d240 Pages::MultiPlayer::OnDeactivate +8084d244 Pages::MultiPlayer::GetPlayerBifield +8084d24c Pages::MultiPlayer::GetActivePlayerBitfield +8084d254 Pages::MultiPlayer::SetButtonHandlers +8084d2b0 Pages::MultiPlayer::GetManipulatorManager +8084d2b8 Pages::MultiPlayer::__dt +8084d338 Pages::MultiPlayer::GetRuntimeTypeInfo +8084d344 MultiPlayerPage_cpp_sinit_ +8084d358 DriftSelectPage:GetPageById +8084d468 Pages::DriftSelect::OnInit +8084d54c Pages::DriftSelect::GetManipulatorManager +8084d554 Pages::DriftSelect::CreateExternalControl +8084d7a0 Pages::DriftSelect::CreateControl +8084d7a8 Pages::DriftSelect::OnActivate +8084d8c8 Pages::DriftSelect::AfterControlUpdate +8084d9f4 Pages::DriftSelect::OnButtonClick +8084dd28 Pages::DriftSelect::OnExternalButtonSelect +8084dd60 Pages::DriftSelect::OnButtonDeselect +8084dd64 Pages::DriftSelect::OnBackPress +8084dd70 Pages::DriftSelect::OnDeactivate +8084ddbc Pages::DriftSelect::GetPlayerBitfield +8084ddc4 Pages::DriftSelect::GetActivePlayerBitfield +8084ddcc Pages::DriftSelect::SetButtonHandlers +8084de28 Pages::DriftSelect::__dt +8084dea8 Pages::DriftSelect::GetRuntimeTypeInfo +8084deb4 DriftSelectPage_cpp_sinit_ +8084dec8 Pages::TopMenuOverlay::GetPageById +8084dfd8 Pages::TopMenuOverlay::CreateControl +8084e3b8 Pages::TopMenuOverlay::vf_0x98 +8084e3c0 Pages::TopMenuOverlay::GetPlayerBitfield +8084e3c8 Pages::TopMenuOverlay::GetActivePlayerBitfield +8084e3d0 Pages::TopMenuOverlay::GetManipulatorManager +8084e3d8 Pages::TopMenuOverlay::__dt +8084e458 Pages::TopMenuOverlay::GetRuntimeTypeInfo +8084e464 TopMenuOverlayPagecpp_sinit_ +8084e478 Pages::SinglePlayer::GetPageById +8084e588 Pages::SinglePlayer::OnInit +8084e628 Pages::SinglePlayer::GetManipulatorManager +8084e630 Pages::SinglePlayer::CreateExternalControl +8084e774 Pages::SinglePlayer::CreateControl +8084e77c Pages::SinglePlayer::OnActivate +8084e900 Pages::SinglePlayer::AfterControlUpdate +8084e904 Pages::SinglePlayer::OnButtonClick +8084ecf4 Pages::SinglePlayer::OnExternalButtonSelect +8084f1a0 Pages::SinglePlayer::OnButtonDeselect +8084f1a4 Pages::SinglePlayer::OnBackPress +8084f1f8 Pages::SinglePlayer::OnDeactivate +8084f1fc Pages::SinglePlayer::GetPlayerBitfield +8084f204 Pages::SinglePlayer::GetActivePlayerBitfield +8084f20c Pages::SinglePlayer::SetButtonHandlers +8084f268 Pages::SinglePlayer::__dt +8084f2e8 Pages::SinglePlayer::GetRuntimeTypeInfo +8084f2f4 SinglePlayerPage_cpp_sinit_ +8084f308 Pages::VSTeamsView::GetPageById +8084f418 Pages::VSTeamsView::OnInit +8084f41c Pages::VSTeamsView::CreateExternalControl +8084f4ac Pages::VSTeamsView::CreateControl +8084f514 Pages::VSTeamsView::OnActivate +8084f518 Pages::VSTeamsView::AfterControlUpdate +8084f51c Pages::VSTeamsView::OnButtonClick +8084f5ec Pages::VSTeamsView::OnExternalButtonSelect +8084f624 Pages::VSTeamsView::OnButtonDeselect +8084f628 Pages::VSTeamsView::OnBackPress +8084f634 Pages::VSTeamsView::AssignTeams +8084f80c Pages::VSTeamsView::GetPlayerBitfield +8084f814 Pages::VSTeamsView::GetActivePlayerBitfield +8084f81c Pages::VSTeamsView::SetButtonHandlers +8084f878 Pages::VSTeamsView::GetManipulatorManager +8084f880 Pages::VSTeamsView::__dt +8084f918 Pages::VSTeamsView::GetRuntimeTypeInfo +8084f924 VSTeamsViewPage_cpp_sinit_ +8084f938 Pages::MainMenu::GetPageById +8084fa48 Pages::MainMenu::OnInit +8084fb48 Pages::MainMenu::GetManipulatorManager +8084fb50 Pages::MainMenu::CreateExternalControl +8084fbec Pages::MainMenu::CreateControl +808503c0 Pages::MainMenu::SetButtonHandlers +8085041c Pages::MainMenu::OnActivate +80850774 Pages::MainMenu::AfterControlUpdate +80850778 Pages::MainMenu::OnButtonClick +80850b88 Pages::MainMenu::OnExternalButtonSelect +80850c0c Pages::MainMenu::OnButtonDeselect +80850d18 Pages::MainMenu::OnBackPress +80850d28 Pages::MainMenu::ResetSectionParamsAndRacedataScenario1 +808511f4 Pages::MainMenu::OnDeactivate +808511f8 Pages::MainMenu::ShowMessageBox +808512f0 Pages::MainMenu::GetPlayerBitfield +808512f8 Pages::MainMenu::GetActivePlayerBitfield +80851300 Pages::MainMenu::__dt +80851398 Pages::MainMenu::GetRuntimeTypeInfo +808513a4 MainMenuPage_cpp_sinit_ +808513b8 0x808513b8 +808514c8 0x808514c8 +808514d4 0x808514d4 +808514dc 0x808514dc +808515dc 0x808515dc +80851648 0x80851648 +8085164c 0x8085164c +80851660 0x80851660 +80851664 0x80851664 +80851668 Pages::Menu::UnloadVideoSource +80851674 0x80851674 +80851678 0x80851678 +80851680 0x80851680 +80851688 0x80851688 +808516e4 0x808516e4 +808516ec 0x808516ec +80851778 0x80851778 +80851784 0x80851784 +80851798 Pages::VSModeSelect::GetPageById +808518a8 Pages::VSModeSelect::OnInit +808518fc Pages::VSModeSelect::GetManipulatorManager +80851904 Pages::VSModeSelect::CreateExternalControl +80851ab4 Pages::VSModeSelect::CreateControl +80851abc Pages::VSModeSelect::OnActivate +80851f74 Pages::VSModeSelect::OnActivate_switch +80851f78 Pages::VSModeSelect::OnActivate_case_0 +80851f90 Pages::VSModeSelect::OnActivate_case_1 +80851fa8 Pages::VSModeSelect::OnActivate_case_2 +80851fc0 Pages::VSModeSelect::OnActivate_case_3 +80851fd8 Pages::VSModeSelect::OnActivate_case_4 +80851ff0 Pages::VSModeSelect::OnActivate_case_5 +80852008 Pages::VSModeSelect::OnActivate_case_6 +80852020 Pages::VSModeSelect::OnActivate_case_7 +80852068 Pages::VSModeSelect::AfterControlUpdate +8085206c Pages::VSModeSelect::OnButtonClick +8085214c Pages::VSModeSelect::OnExternalButtonSelect +80852184 Pages::VSModeSelect::OnButtonDeselect +80852188 Pages::VSModeSelect::OnBackPress +80852194 Pages::VSModeSelect::OnDeactivate +808521e0 Pages::VSModeSelect::GetPlayerBitfield +808521e8 Pages::VSModeSelect::GetActivePlayerBitfield +808521f0 Pages::VSModeSelect::SetButtonHandlers +8085224c Pages::VSModeSelect::__dt +808522cc Pages::VSModeSelect::GetRuntimeTypeInfo +808522d8 VSModeSelectPage_cpp_sinit_ +808522ec Pages::VSSettings::GetPageById +808523fc Pages::VSSettings::OnInit +80852694 Pages::VSSettings::CreateExternalControl +80852724 Pages::VSSettings::CreateControl +80852bb8 Pages::VSSettings::OnActivate +80852cbc Pages::VSSettings::AfterControlUpdate +80852cc0 Pages::VSSettings::OnButtonClick +80852cf0 Pages::VSSettings::OnExternalButtonSelect +80852d1c Pages::VSSettings::OnButtonDeselect +80852d20 Pages::VSSettings::OnBackPress +80852d80 Pages::VSSettings::OnRadioClick +80852f08 Pages::VSSettings::OnRadioChange +80852f88 Pages::VSSettings::OnUpDownClick +80852ff4 Pages::VSSettings::OnUpDownSelect +80853004 Pages::VSSettings::OnUpDownChange +8085307c Pages::VSSettings::OnTextChange +808530f8 Pages::VSSettings::OnDispose +80853108 Pages::VSSettings::GetPlayerBitfield +80853110 Pages::VSSettings::GetLocalPlayerCount +80853118 Pages::VSSettings::SetButtonHandlers +80853174 Pages::VSSettings::GetManipulatorManager +8085317c Pages::VSSettings::__dt +80853244 Pages::VSSettings::GetRuntimeTypeInfo +80853250 Pages::VSSettings::TriggerUpDown3APtmf +80853280 Pages::VSSettings::TriggerRadioPtmf +808532b0 Pages::VSSettings::TriggerTextPtmf +808532e0 Pages::VSSettings::TriggerUpDown2APtmf +80853310 VSSettingsPage_cpp_sinit_ +80853324 Pages::Unlock::GetPageById +80853434 0x80853434 +80853484 Pages::Unlock::OnInit +8085349c Pages::Unlock::CreateExternalControl +8085352c Pages::Unlock::CreateControl +80853770 Pages::Unlock::OnActivate +8085398c Pages::Unlock::AfterControlUpdate +80853ae8 Pages::Unlock::OnButtonClick +80853db4 Pages::Unlock::OnExternalButtonSelect +80853db8 Pages::Unlock::OnButtonDeselect +80853dbc Pages::Unlock::OnBackPress +80853dc0 Pages::Unlock::SetTitleBMG +80853e7c Pages::Unlock::PrepareControls +808540ec 0x808540ec +8085414c 0x8085414c +808541ac Pages::Unlock::SetModels +808542a8 Pages::Unlock::SetModels_switch +808542ac Pages::Unlock::SetModels_caseD_1b +808542b8 Pages::Unlock::SetModels_caseD_10 +808542c0 Pages::Unlock::SetModels_caseD_d +808542cc Pages::Unlock::SetModels_caseD_b +808542d8 Pages::Unlock::SetModels_caseD_e +808542e4 Pages::Unlock::SetModels_caseD_11 +808542f0 Pages::Unlock::SetModels_caseD_12 +80854344 0x80854344 +80854394 0x80854394 +808543d0 0x808543d0 +8085446c Pages::Unlock::SetMessageWindowMessage +80854610 0x80854610 +80854728 Pages::Unlock::GetPlayerBifield +80854730 Pages::Unlock::GetActivePlayerBitfield +80854738 Pages::Unlock::SetButtonHandlers +80854794 Pages::Unlock::GetManipulatorManager +8085479c Pages::Unlock::__dt +8085484c Pages::Unlock::GetRuntimeTypeInfo +80854858 UnlockPage_cpp_sinit_ +8085486c Pages::RaceIntro::OnInit +80854cb0 Pages::RaceIntro::__dt +80854d30 Pages::RaceIntro::GetRuntimeTypeInfo +80854d3c RaceIntroPage_cpp_sinit_ +80854d50 Pages::TTSplits::__ct +80854ec0 Pages::TTSplits::Unload +80854ed0 Pages::TTSplits::__dt +80854f90 Pages::TTSplits::OnInit +80855148 Pages::TTSplits::AfterControlUpdate +8085519c Pages::TTSplits::BeforeEntranceAnimations +808557d8 Pages::TTSplits::BeforeExitAnimations +80855848 Pages::TTSplits::GetNextPage +80855894 Pages::TTSplits::GetRuntimeTypeInfo +808558a0 Pages::TTSplits::TriggerAction +808558d0 Pages::TTSplits::_sinit_ +808558e4 Pages::RaceHUD::OnInit +80855cd0 Pages::RaceHUD::InitActions +80856018 Pages::RaceHUD::OnNextPlayerSwitch +80856020 Pages::RaceHUD::OnPrevPlayerSwitch +80856028 Pages::RaceHUD::OnPause +808561e0 Pages::RaceHUD::ChangeFocusedPlayer +80856338 Pages::RaceHUD::GetLocalPlayerCount +80856358 Pages::RaceHUD::BeforeControlUpdate +80856940 Pages::RaceHUD::HasPlayerRaceEnded +80856998 Pages::RaceHUD::HasRaceEndedReplay +80856a18 Pages::RaceHUD::HasRaceEnded +80856b24 Pages::RaceHUD::AfterControlUpdate +80857134 0x80857134 +80857174 Pages::RaceHUD::GetCtrlRaceBaseCount +8085732c Pages::RaceHUD::InitCtrlRaceBase +80857e94 CtrlRaceCount::__ct +80857ed0 RaceBalloons::__dt +80857f38 CtrlRaceNameBalloon::__ct +80857f88 CtrlRaceItemBalloon::__ct +80857fd8 Pages::TournamentHUD::GetEnabledCtrlRaceBases +80858084 Pages::RaceHUD::OnDeactivate +80858090 Pages::RaceHUD::OnDispose +808580a0 Pages::RaceHUD::ChangeSectionByReinit +808580bc Pages::RaceHUD::OnItemObjTargeting +80858150 Pages::RaceHUD::UpdateRaceBalloons +808581f4 Pages::TournamentHUD::GetCtrlRaceNameBalloonCount +808581fc Pages::TournamentHUD::GetPausePageId +80858204 Pages::TournamentHUD::__dt +80858270 Pages::TournamentHUD::GetRuntimeTypeInfo +8085827c Pages::RaceHUD::GetRuntimeTypeInfo +80858288 TriggerPtmf +808582b8 0x808582b8 +80858310 Pages::RaceMenu::__ct +808583cc Pages::RaceMenu::OnInit +80859098 Pages::RaceMenu::OnActivate +80859504 Pages::RaceMenu::AfterControlUpdate +8085959c Pages::RaceMenu::BeforeEntranceAnimations +808595a0 Pages::RaceMenu::BeforeExitAnimations +8085960c Pages::RaceMenu::OnDeactivate +80859610 Pages::RaceMenu::OnDispose +808596a8 0x808596a8 +80859704 Pages::RaceMenu::OnStartPress +80859760 Pages::RaceMenu::OnButtonClick +8085982c 0x8085982c +80859874 0x80859874 +80859904 0x80859904 +80859bec 0x80859bec +80859c4c 0x80859c4c +80859ce8 0x80859ce8 +80859d48 0x80859d48 +80859e78 0x80859e78 +8085a01c 0x8085a01c +8085a2c0 0x8085a2c0 +8085a690 0x8085a690 +8085a744 0x8085a744 +8085a7f8 0x8085a7f8 +8085aa28 0x8085aa28 +8085aad4 0x8085aad4 +8085ab28 0x8085ab28 +8085abd4 0x8085abd4 +8085ac54 0x8085ac54 +8085ad44 0x8085ad44 +8085ada8 0x8085ada8 +8085ae28 0x8085ae28 +8085ae88 0x8085ae88 +8085af34 0x8085af34 +8085af9c 0x8085af9c +8085b048 0x8085b048 +8085b0b0 0x8085b0b0 +8085b15c 0x8085b15c +8085b27c Pages::RaceMenu::IsFinalRace +8085b3c4 Pages::RaceMenu::GetRuntimeTypeInfo +8085b3d0 TriggerPtmf +8085b400 TriggerPtmf +8085b430 0x8085b430 +8085b4b0 Pages::Leaderboard::__ct +8085b600 Pages::Leaderboard::OnActivate +8085b6dc 0x8085b6dc +8085b730 Pages::Leaderboard::AfterControlUpdate +8085b7d8 0x8085b7d8 +8085b9fc Pages::Leaderboard::GetRuntimeTypeInfo +8085ba08 TriggerPtmf +8085ba38 0x8085ba38 +8085ba4c Pages::GPVSLeaderboardUpdate::OnInit +8085bb60 Pages::GPVSLeaderboardUpdate::GetRowCount +8085bb70 Pages::GPVSLeaderboardUpdate::CanEnd +8085bc0c Pages::GPVSLeaderboardUpdate::Func_0x6c +8085bec4 Pages::GPVSLeaderboardUpdate::FillRows +8085bfe0 Pages::GPVSLeaderboardUpdate::GetNextPage +8085c01c Pages::GPVSLeaderboardTotal::OnInit +8085c154 Pages::GPVSLeaderboardTotal::FillRows +8085c2ac Pages::GPVSLeaderboardTotal::GetNextPage +8085c2f0 Pages::GPVSLeaderboardTotal::ComparePlayers +8085c384 Pages::WWLeaderboardUpdate::OnInit +8085c4f8 Pages::WWLeaderboardUpdate::FillRows +8085cbc8 Pages::WWLeaderboardUpdate::GetNextPage +8085cbd0 Pages::TTLeaderboard::OnInit +8085cdf0 Pages::TTLeaderboard::GetRowCount +8085cdf8 Pages::TTLeaderboard::FillRows +8085d2b0 Pages::TTLeaderboard::GetNextPage +8085d4a0 0x8085d4a0 +8085da18 0x8085da18 +8085da20 0x8085da20 +8085da28 0x8085da28 +8085da98 0x8085da98 +8085daa4 Pages::TTLeaderboard::__dt +8085db24 Pages::TTLeaderboard::GetRuntimeTypeInfo +8085db30 Pages::WWLeaderboardUpdate::__dt +8085dba0 Pages::WWLeaderboardUpdate::GetRuntimeTypeInfo +8085dbac Pages::GPVSLeaderboardTotal::__dt +8085dc1c Pages::GPVSLeaderboardTotal::GetRuntimeTypeInfo +8085dc28 Pages::GPVSLeaderboardUpdate::__dt +8085dc98 Pages::GPVSLeaderboardUpdate::GetRuntimeTypeInfo +8085dca4 0x8085dca4 +8085dcb0 LeaderboardsPagescpp_sinit_ +8085dce0 Pages::TeamVSLeaderboardBase::OnInit +8085de0c Pages::TeamVSLeaderboardBase::AfterControlUpdate +8085de68 Pages::TeamVSLeaderboardBase::CanEnd +8085dec8 Pages::TeamVSLeaderboardBase::CalcTeamScoreDiff +8085e050 Pages::TeamVSLeaderboardTotal::FillRows +8085e0c0 Pages::BattleLeaderboardTotal::FillRows +8085e0d0 Pages::BattleLeaderboardUpdate::FillRows +8085e420 Pages::TeamVSLeaderboardTotal::GetNextPage +8085e450 Pages::BattleLeaderboardUpdate::GetNextPage +8085e480 Pages::BattleLeaderboardTotal::GetNextPage +8085e51c Pages::BattleLeaderboardTotal::__dt +8085e5a8 Pages::BattleLeaderboardTotal::GetRuntimeTypeInfo +8085e5b4 Pages::BattleLeaderboardUpdate::__dt +8085e640 Pages::BattleLeaderboardUpdate::GetRuntimeTypeInfo +8085e64c Pages::TeamVSLeaderboardTotal::__dt +8085e6d8 Pages::TeamVSLeaderboardTotal::GetRuntimeTypeInfo +8085e6e4 Pages::TeamVSLeaderboardBase::GetRuntimeTypeInfo +8085e6f0 TeamLeaderboard_cpp_sinit_ +8085e718 Pages::LicenseRecords::GetPageById +8085e828 Pages::LicenseRecords::OnInit +8085e8d0 Pages::LicenseRecords::CreateExternalControl +8085e97c Pages::LicenseRecords::CreateControl +8085eadc Pages::LicenseRecords::OnActivate +8085eb48 Pages::LicenseRecords::AfterControlUpdate +8085eb4c 0x8085eb4c +8085ec28 Pages::LicenseRecords::OnExternalButtonSelect +8085ec2c 0x8085ec2c +8085ec30 0x8085ec30 +8085ec58 0x8085ec58 +8085efa0 0x8085efa0 +8085f0dc 0x8085f0dc +8085f278 0x8085f278 +8085f390 0x8085f390 +8085f52c Pages::LicenseRecords::GetPlayerBitfield +8085f534 Pages::LicenseRecords::GetActivePlayerBitfield +8085f53c Pages::LicenseRecords::SetButtonHandlers +8085f598 Pages::LicenseRecords::GetManipulatorManager +8085f5a0 Pages::LicenseRecords::__dt +8085f620 Pages::LicenseRecords::GetRuntimeTypeInfo +8085f62c LicenseRecordsPagecpp_sinit_ +8085f640 RacePauseMgr::CreateInstance +8085f6a0 RacePauseMgr::__ct +8085f6b8 RacePauseMgr::DestroyInstance +8085f708 RacePauseMgr::__dt +8085f748 RacePauseMgr::RequestPause +8085f76c RacePauseMgr::RequestUnpause +8085f790 0x8085f790 +8085f7c4 0x8085f7c4 +8085f7cc 0x8085f7cc +8085f870 0x8085f870 +8085f8c0 0x8085f8c0 +8085f8c8 0x8085f8c8 +8085f8d0 0x8085f8d0 +8085f8e8 0x8085f8e8 +8085f91c 0x8085f91c +8085f924 0x8085f924 +8085f92c 0x8085f92c +8085f934 0x8085f934 +8085f93c 0x8085f93c +8085f944 0x8085f944 +8085f94c 0x8085f94c +8085f954 0x8085f954 +8085f95c 0x8085f95c +8085f964 0x8085f964 +8085f96c 0x8085f96c +8085f974 0x8085f974 +8085f97c 0x8085f97c +8085f984 0x8085f984 +8085f98c 0x8085f98c +8085f994 0x8085f994 +8085f99c 0x8085f99c +8085f9a4 0x8085f9a4 +8085f9ac 0x8085f9ac +8085f9b4 0x8085f9b4 +8085f9c4 0x8085f9c4 +8085f9f8 0x8085f9f8 +8085fa00 0x8085fa00 +8085fa08 0x8085fa08 +8085fa10 0x8085fa10 +8085fa20 0x8085fa20 +8085fa3c 0x8085fa3c +8085fa40 0x8085fa40 +8085fa48 0x8085fa48 +8085fa50 0x8085fa50 +8085fa58 0x8085fa58 +8085fa60 0x8085fa60 +8085fa68 0x8085fa68 +8085fa70 0x8085fa70 +8085fa78 0x8085fa78 +8085fa88 0x8085fa88 +8085fab4 0x8085fab4 +8085fabc 0x8085fabc +8085fadc 0x8085fadc +8085fae0 0x8085fae0 +8085faf0 IsOnlineSection +8085fb2c IsGhostRaceSection +8085fb4c IsTournamentSection +8085fb6c GetActiveRacedataPlayers +8085fc68 GetLocalPlayerCount +8085fc80 0x8085fc80 +8085fcf8 0x8085fcf8 +8085fd10 GetNextVSTrack +8085fd3c 0x8085fd3c +8085fd78 0x8085fd78 +8085fe98 0x8085fe98 +8085ff50 TimerToTextInfo +80860068 IsGameplaySection +80860094 0x80860094 +808600f8 IsBattle +80860138 GetCharacterIconPaneName +8086015c GetItemIconPaneName +808601c0 GetCupIconPaneName +808601f4 0x808601f4 +80860228 GetBattleCupIconPaneName +8086025c 0x8086025c +80860474 GetMapIconPaneName +80860598 0x80860598 +80860600 0x80860600 +80860604 0x80860604 +80860680 0x80860680 +808606e8 0x808606e8 +80860768 0x80860768 +808607d0 0x808607d0 +80860908 0x80860908 +8086097c 0x8086097c +808609d4 0x808609d4 +80860a1c 0x80860a1c +80860af4 0x80860af4 +80860b50 0x80860b50 +80860b90 0x80860b90 +80860c04 0x80860c04 +80860cec 0x80860cec +80860d60 0x80860d60 +80860dc8 0x80860dc8 +80860e10 0x80860e10 +80860f24 0x80860f24 +80860fa4 0x80860fa4 +80861088 0x80861088 +808610e4 0x808610e4 +80861124 0x80861124 +80861198 0x80861198 +80861210 0x80861210 +80861270 0x80861270 +808612bc 0x808612bc +80861394 0x80861394 +808613f0 0x808613f0 +80861438 0x80861438 +808614ac 0x808614ac +80861520 0x80861520 +80861594 0x80861594 +808615f0 0x808615f0 +80861638 0x80861638 +808616ac 0x808616ac +80861794 0x80861794 +80861808 0x80861808 +8086187c 0x8086187c +808618e4 0x808618e4 +80861924 0x80861924 +80861998 0x80861998 +80861a0c 0x80861a0c +80861af0 0x80861af0 +80861b64 0x80861b64 +80861bd8 0x80861bd8 +80861c34 0x80861c34 +80861c74 0x80861c74 +80861ce8 0x80861ce8 +80861d44 0x80861d44 +80861dc0 0x80861dc0 +80861e2c 0x80861e2c +80861eb8 0x80861eb8 +80861f10 0x80861f10 +80861ff4 0x80861ff4 +80862010 0x80862010 +80862014 0x80862014 +8086201c 0x8086201c +80862024 0x80862024 +8086202c 0x8086202c +80862034 0x80862034 +8086203c 0x8086203c +80862044 0x80862044 +8086204c 0x8086204c +80862054 0x80862054 +8086205c 0x8086205c +80862064 0x80862064 +8086206c 0x8086206c +80862074 0x80862074 +8086207c 0x8086207c +80862084 0x80862084 +8086208c 0x8086208c +80862094 0x80862094 +8086209c 0x8086209c +808620a4 0x808620a4 +808620ac 0x808620ac +808620b4 0x808620b4 +808620bc 0x808620bc +808620c4 0x808620c4 +808620cc 0x808620cc +808620d4 0x808620d4 +808620dc 0x808620dc +808620e4 0x808620e4 +808620ec 0x808620ec +808620f4 0x808620f4 +808620fc 0x808620fc +80862104 0x80862104 +8086210c 0x8086210c +80862114 0x80862114 +80862124 0x80862124 +80862140 0x80862140 +80862144 0x80862144 +8086214c 0x8086214c +80862154 0x80862154 +8086215c 0x8086215c +80862164 0x80862164 +8086216c 0x8086216c +80862174 0x80862174 +8086217c 0x8086217c +80862184 0x80862184 +8086218c 0x8086218c +80862194 0x80862194 +8086219c 0x8086219c +808621a4 0x808621a4 +808621ac 0x808621ac +808621b4 0x808621b4 +808621bc 0x808621bc +808621c4 0x808621c4 +808621cc 0x808621cc +808621d4 0x808621d4 +808621dc 0x808621dc +808621e4 0x808621e4 +808621ec 0x808621ec +808621f4 0x808621f4 +808621fc 0x808621fc +80862204 0x80862204 +8086220c 0x8086220c +80862214 0x80862214 +8086221c 0x8086221c +80862224 0x80862224 +8086222c 0x8086222c +80862234 0x80862234 +8086223c 0x8086223c +80862244 0x80862244 +8086224c 0x8086224c +80862254 0x80862254 +8086225c 0x8086225c +80862264 0x80862264 +8086226c 0x8086226c +80862274 0x80862274 +8086227c 0x8086227c +80862284 0x80862284 +8086228c 0x8086228c +80862294 0x80862294 +8086229c 0x8086229c +808622a4 0x808622a4 +808622ac 0x808622ac +808622b4 0x808622b4 +808622bc 0x808622bc +808622c4 0x808622c4 +808622cc 0x808622cc +808622d4 0x808622d4 +808622e4 0x808622e4 +80862308 0x80862308 +80862324 0x80862324 +80862328 0x80862328 +80862330 0x80862330 +80862338 0x80862338 +80862340 0x80862340 +80862348 0x80862348 +80862350 0x80862350 +80862358 0x80862358 +80862360 0x80862360 +80862368 0x80862368 +80862370 0x80862370 +80862378 0x80862378 +80862380 0x80862380 +80862388 0x80862388 +80862390 0x80862390 +808623a0 0x808623a0 +808623c4 0x808623c4 +808623e4 0x808623e4 +808623e8 0x808623e8 +808623f0 0x808623f0 +808623f8 0x808623f8 +80862400 0x80862400 +80862408 0x80862408 +80862410 0x80862410 +80862418 0x80862418 +80862420 0x80862420 +80862428 0x80862428 +80862430 0x80862430 +80862438 0x80862438 +80862440 0x80862440 +80862448 0x80862448 +80862450 0x80862450 +80862458 0x80862458 +80862460 0x80862460 +80862468 0x80862468 +80862470 0x80862470 +80862478 0x80862478 +80862480 0x80862480 +80862490 0x80862490 +808628a0 0x808628a0 +80862908 0x80862908 +80862930 0x80862930 +8086295c 0x8086295c +80862960 0x80862960 +8086296c 0x8086296c +80862978 0x80862978 +80862984 0x80862984 +80862990 0x80862990 +8086299c 0x8086299c +808629a8 0x808629a8 +808629b4 0x808629b4 +808629c4 0x808629c4 +808629c8 0x808629c8 +808629f0 0x808629f0 +80862a18 0x80862a18 +80862a38 0x80862a38 +80862a3c 0x80862a3c +80862a48 0x80862a48 +80862a54 0x80862a54 +80862a60 0x80862a60 +80862a6c 0x80862a6c +80862a78 0x80862a78 +80862a84 0x80862a84 +80862a90 0x80862a90 +80862a9c 0x80862a9c +80862aa8 0x80862aa8 +80862ab4 0x80862ab4 +80862ac0 0x80862ac0 +80862acc 0x80862acc +80862ad8 0x80862ad8 +80862ae4 0x80862ae4 +80862af0 0x80862af0 +80862afc 0x80862afc +80862b04 0x80862b04 +80862b08 0x80862b08 +80862b28 0x80862b28 +80862b2c 0x80862b2c +80862b38 0x80862b38 +80862b44 0x80862b44 +80862b50 0x80862b50 +80862b5c 0x80862b5c +80862b68 0x80862b68 +80862b74 0x80862b74 +80862b80 0x80862b80 +80862b8c 0x80862b8c +80862b98 0x80862b98 +80862ba4 0x80862ba4 +80862bb0 0x80862bb0 +80862bbc 0x80862bbc +80862bc8 0x80862bc8 +80862bd4 0x80862bd4 +80862be0 0x80862be0 +80862be8 0x80862be8 +80862bec 0x80862bec +80862c0c 0x80862c0c +80862c10 0x80862c10 +80862c1c 0x80862c1c +80862c28 0x80862c28 +80862c34 0x80862c34 +80862c40 0x80862c40 +80862c4c 0x80862c4c +80862c58 0x80862c58 +80862c64 0x80862c64 +80862c70 0x80862c70 +80862c7c 0x80862c7c +80862ca4 0x80862ca4 +80862ccc 0x80862ccc +80862cec 0x80862cec +80862cf0 0x80862cf0 +80862cfc 0x80862cfc +80862d08 0x80862d08 +80862d14 0x80862d14 +80862d20 0x80862d20 +80862d2c 0x80862d2c +80862d38 0x80862d38 +80862d44 0x80862d44 +80862d50 0x80862d50 +80862d5c 0x80862d5c +80862d68 0x80862d68 +80862d74 0x80862d74 +80862dc8 0x80862dc8 +80862e04 0x80862e04 +80862e08 0x80862e08 +80862e14 0x80862e14 +80862e20 0x80862e20 +80862e2c 0x80862e2c +80862e38 0x80862e38 +80862e44 0x80862e44 +80862e50 0x80862e50 +80862e5c 0x80862e5c +80862e94 0x80862e94 +80862e98 0x80862e98 +80862ec0 0x80862ec0 +80862ec4 0x80862ec4 +80862ed0 0x80862ed0 +80862edc 0x80862edc +80862ee8 0x80862ee8 +80862ef4 0x80862ef4 +80862f00 0x80862f00 +80862f0c 0x80862f0c +80862f18 0x80862f18 +80862f24 0x80862f24 +80862f30 0x80862f30 +80862f3c 0x80862f3c +80862f48 0x80862f48 +80862f50 0x80862f50 +80862f54 0x80862f54 +80862f94 Audio::CharacterActor::__ct +80863014 0x80863014 +80863054 Audio::RandomCharacterPicker::__dt +808630b0 Audio::RandomSoundPicker::__dt +80863108 Audio::CharacterActor::Link +80863524 0x80863524 +80863664 Audio::CharacterActor::Unlink +8086366c Audio::CharacterActor::Update +80863d30 Audio::CharacterActor::HoldSound +80863d5c Audio::CharacterActor::PlayCharacterSoundConditional +80863db4 Audio::CharacterActor::PlayCharacterSoundConditional_switch +80863db8 Audio::CharacterActor::PlayCharacterSoundConditional_case1a +80863e34 Audio::CharacterActor::PlayCharacterSoundConditional_case1b +80863ec0 Audio::CharacterActor::PlayCharacterSoundConditional_case16 +80863ee0 Audio::CharacterActor::PlayCharacterSoundConditional_case17 +80863f30 Audio::CharacterActor::PlayCharacterSoundConditional_caseb +80863f3c Audio::CharacterActor::PlayCharacterSoundConditional_casec +80863f58 Audio::CharacterActor::PlayCharacterSoundConditional_case10 +80863f80 Audio::CharacterActor::PlayCharacterSound +80864358 0x80864358 +808646bc 0x808646bc +808647a4 0x808647a4 +808649fc 0x808649fc +80864ab4 Audio::CharacterActor::PlayCharacterCollisionSound +80864aec 0x80864aec +80864af4 0x80864af4 +80864afc 0x80864afc +80864b04 0x80864b04 +80864b14 0x80864b14 +80864b84 0x80864b84 +80864ba0 0x80864ba0 +80864bec 0x80864bec +80864c20 0x80864c20 +80864c84 Audio::CharacterActor::StartSound +80864d30 0x80864d30 +80864d38 0x80864d38 +80864f2c 0x80864f2c +80864f84 0x80864f84 +80864fb0 0x80864fb0 +80864fd0 0x80864fd0 +80864ff0 Audio::CharacterActor::StopSound +80865084 0x80865084 +80865104 0x80865104 +80865240 0x80865240 +80865454 0x80865454 +80865570 0x80865570 +808655a4 0x808655a4 +808655bc 0x808655bc +808655d0 0x808655d0 +80865638 Jumbotron_StopPlaying +8086564c 0x8086564c +8086577c 0x8086577c +808657dc 0x808657dc +80865804 0x80865804 +80865898 0x80865898 +80865950 0x80865950 +80865978 0x80865978 +808659f4 Audio::CharacterActor::GetCharacterGroupId +80865a70 Audio::CharacterActor::GetCharacterCannonGroupId +80865b30 0x80865b30 +80865c94 0x80865c94 +80866188 0x80866188 +80866200 0x80866200 +80866274 Audio::CharacterActor::__dt +80866378 Audio::CharacterActor::__dt(thunk) +80866380 Audio::CharacterActor::StopSound(thunk) +80866388 Audio::CharacterActor::HoldSound(thunk) +80866390 Audio::CharacterActor::StartSound(thunk) +80866398 Audio::CharacterActor::Update(thunk) +808663a0 Audio::CharacterActor::Unlink(thunk) +808663a8 Audio::CharacterActor::Link(thunk) +808663b0 AudioRandomMgr::Disposer__dt +80866448 AudioRandomMgr::CreateInstance +808664d0 AudioRandomMgr::DestroyInstance +80866504 AudioRandomMgr::__dt +808665b8 AudioRandomMgr::RandInt +808665ec AudioRandomMgr::RandFloat +8086662c 0x8086662c +8086668c 0x8086668c +808666f8 Audio::RandomSoundPicker::__ct +8086673c 0x8086673c +808667cc 0x808667cc +80866800 0x80866800 +80866960 0x80866960 +80866a10 0x80866a10 +80866a6c 0x80866a6c +80866b38 0x80866b38 +80866bac 0x80866bac +80866bbc 0x80866bbc +80866bf0 0x80866bf0 +80866c58 0x80866c58 +80866d10 0x80866d10 +80866d44 0x80866d44 +80866d4c Audio::RandomCharacterPicker::__ct +80866d90 0x80866d90 +80866df4 0x80866df4 +80866dfc 0x80866dfc +80866ebc 0x80866ebc +80866f7c 0x80866f7c +8086703c 0x8086703c +808670fc 0x808670fc +808671a8 0x808671a8 +80867324 0x80867324 +80867448 0x80867448 +80867578 0x80867578 +80867670 0x80867670 +808676b0 0x808676b0 +808677e8 0x808677e8 +80867a4c 0x80867a4c +80867bc0 0x80867bc0 +80867bf8 0x80867bf8 +80867ca4 0x80867ca4 +80867de0 cAIPad__ct +80867dec 0x80867dec +80867e00 0x80867e00 +80867fe0 0x80867fe0 +80868048 0x80868048 +808680a8 0x808680a8 +80868128 0x80868128 +8086828c 0x8086828c +808683a8 0x808683a8 +808683c0 0x808683c0 +80868498 0x80868498 +80868588 0x80868588 +808685a0 0x808685a0 +80868690 0x80868690 +808686a4 0x808686a4 +808686c0 0x808686c0 +808686d8 0x808686d8 +808686f0 0x808686f0 +80868704 0x80868704 +80868714 cTeam_GetPlayer +80868724 0x80868724 +8086874c 0x8086874c +80868768 0x80868768 +80868784 0x80868784 +80868868 0x80868868 +80868934 0x80868934 +808689ac thunk_0x808691fc +808689b0 0x808689b0 +808689d0 0x808689d0 +808689e0 0x808689e0 +808689ec 0x808689ec +808689f8 0x808689f8 +80868a24 0x80868a24 +80868af4 0x80868af4 +80868cc8 0x80868cc8 +80868d64 0x80868d64 +80868e10 0x80868e10 +80868e28 0x80868e28 +80868eb0 0x80868eb0 +80868ef0 0x80868ef0 +80869004 0x80869004 +80869044 0x80869044 +80869198 0x80869198 +808692b4 0x808692b4 +8086938c 0x8086938c +80869460 0x80869460 +8086963c 0x8086963c +80869748 0x80869748 +808698c0 0x808698c0 +80869940 0x80869940 +80869984 0x80869984 +8086a058 0x8086a058 +8086a05c 0x8086a05c +8086a09c 0x8086a09c +8086a0a0 0x8086a0a0 +8086a0e0 0x8086a0e0 +8086a1d4 0x8086a1d4 +8086a214 0x8086a214 +8086a28c obj_casino_roulette::__ct +8086a354 obj_casino_roulette_generateBigassLongListOfFloatsForRotation +8086a59c 0x8086a59c +8086a860 obj_casino_roulette_spinVisually +8086a8e0 obj_casino_roulette_update +8086a9a8 obj_casino_roulette_spinEverythingElse +8086ad8c obj_casino_roulette_calculateSpin +8086aee4 obj_casino_roulette_spinPlayer +8086b118 obj_casino_roulette_initDushBoardAnimationSpeed? +8086b194 0x8086b194 +8086b1a0 0x8086b1a0 +8086b220 0x8086b220 +8086b228 0x8086b228 +8086b230 0x8086b230 +8086b240 0x8086b240 +8086b248 0x8086b248 +8086b288 Objects::WLwallGC::__ct +8086b450 Objects::WLwallGC::__dt +8086b4a0 Objects::WLwallGC::OnStart +8086b574 0x8086b574 +8086b59c Objects::WLwallGC::GetTransformationMatrix +8086b704 Objects::WLwallGC::CalcNextPosition +8086b774 Objects::WLwallGC::Update +8086b8ec Objects::WLwallGC::CalcOtherEntityDistance +8086b914 Objects::WLwallGC::UpdateOtherEntityPos +8086b994 Objects::WLwallGC::IsCollidingAddEntryNoTriangleCheckImpl +8086bc14 Objects::WLwallGC::IsCollidingImpl +8086bcac Objects::WLwallGC::GetPropertiesBitfield +8086bcb4 Objects::WLwallGC::GetPeriod +8086bcf0 Objects::WLwallGC::vf_0x11c +8086bcf8 0x8086bcf8 +8086bff4 0x8086bff4 +8086bff8 0x8086bff8 +8086c038 0x8086c038 +8086c0ac 0x8086c0ac +8086c138 0x8086c138 +8086c208 0x8086c208 +8086cefc 0x8086cefc +8086d500 0x8086d500 +8086d514 0x8086d514 +8086d534 0x8086d534 +8086d554 0x8086d554 +8086d55c 0x8086d55c +8086d6a0 0x8086d6a0 +8086d77c 0x8086d77c +8086d884 0x8086d884 +8086d888 0x8086d888 +8086d890 0x8086d890 +8086df7c 0x8086df7c +8086e048 0x8086e048 +8086e148 0x8086e148 +8086e2a8 0x8086e2a8 +8086e2c8 0x8086e2c8 +8086e4bc 0x8086e4bc +8086e5a0 0x8086e5a0 +8086e688 0x8086e688 +8086e808 0x8086e808 +8086e8a8 0x8086e8a8 +8086ea7c 0x8086ea7c +8086ed78 0x8086ed78 +8086ef58 0x8086ef58 +8087067c 0x8087067c +808706cc 0x808706cc +80870ae8 0x80870ae8 +80870cf0 0x80870cf0 +80870d04 0x80870d04 +80870f1c 0x80870f1c +80870f6c 0x80870f6c +80871160 0x80871160 +808711b0 0x808711b0 +8087121c 0x8087121c +80871874 0x80871874 +80871ec4 0x80871ec4 +80872138 0x80872138 +80872240 0x80872240 +8087224c 0x8087224c +80872254 0x80872254 +8087225c 0x8087225c +80872260 0x80872260 +80872264 0x80872264 +80872268 0x80872268 +8087226c 0x8087226c +80872274 0x80872274 +80872278 0x80872278 +80872280 0x80872280 +80872310 0x80872310 +80872320 0x80872320 +80872334 0x80872334 +80872e90 0x80872e90 +80872ebc 0x80872ebc +80872ec8 0x80872ec8 +8087301c 0x8087301c +80873024 0x80873024 +8087302c 0x8087302c +80873034 0x80873034 +8087303c 0x8087303c +80873060 0x80873060 +80873070 0x80873070 +80873074 0x80873074 +8087308c 0x8087308c +808730ac 0x808730ac +808731b4 0x808731b4 +80873360 0x80873360 +8087342c 0x8087342c +80873480 0x80873480 +80873498 0x80873498 +808735d8 0x808735d8 +80873844 0x80873844 +808738b0 0x808738b0 +8087396c 0x8087396c +80873a0c 0x80873a0c +80873bdc 0x80873bdc +80873de8 0x80873de8 +80873fbc 0x80873fbc +808740b0 0x808740b0 +808741a0 0x808741a0 +80874284 0x80874284 +808743e8 0x808743e8 +808743fc 0x808743fc +80874474 0x80874474 +80874ac0 0x80874ac0 +80874c30 0x80874c30 +80874ce8 0x80874ce8 +80874cf4 0x80874cf4 +80874dac GoalOverlay_SceneCreated +80874db8 0x80874db8 +80875118 0x80875118 +808753dc 0x808753dc +80875d5c 0x80875d5c +80875d7c 0x80875d7c +80875fd0 0x80875fd0 +80876a60 0x80876a60 +80876a74 0x80876a74 +80876be0 0x80876be0 +80876fe0 0x80876fe0 +8087724c 0x8087724c +8087783c 0x8087783c +80877990 0x80877990 +80877b00 0x80877b00 +80877f08 0x80877f08 +80878cc0 0x80878cc0 +80878d04 0x80878d04 +80878d8c 0x80878d8c +80879280 0x80879280 +8087940c 0x8087940c +808797a4 0x808797a4 +80879a18 0x80879a18 +80879b48 0x80879b48 +80879d78 0x80879d78 +80879d84 0x80879d84 +8087a660 0x8087a660 +8087a664 0x8087a664 +8087a804 0x8087a804 +8087a878 0x8087a878 +8087a890 0x8087a890 +8087a894 0x8087a894 +8087a958 0x8087a958 +8087a960 0x8087a960 +8087aa48 0x8087aa48 +8087aad8 0x8087aad8 +8087ab3c 0x8087ab3c +8087b08c 0x8087b08c +8087b090 0x8087b090 +8087b0d0 0x8087b0d0 +8087b138 0x8087b138 +8087b650 0x8087b650 +8087c170 0x8087c170 +8087c1b0 0x8087c1b0 +8087c1b8 0x8087c1b8 +8087c1f8 0x8087c1f8 +8087c200 0x8087c200 +8087c240 0x8087c240 +8087c248 0x8087c248 +8087c288 0x8087c288 +8087c2c8 0x8087c2c8 +8087c2d0 0x8087c2d0 +8087c310 0x8087c310 +8087c318 0x8087c318 +8087c358 0x8087c358 +8087c360 0x8087c360 +8087d250 0x8087d250 +8087d2b4 0x8087d2b4 +8087d318 0x8087d318 +8087d358 0x8087d358 +8087d3c4 0x8087d3c4 +8087d3cc 0x8087d3cc +8087d430 0x8087d430 +8087d49c 0x8087d49c +8087d508 0x8087d508 +8087d570 0x8087d570 +8087d5b0 0x8087d5b0 +8087d614 0x8087d614 +8087d61c 0x8087d61c +8087d65c 0x8087d65c +8087d6c0 0x8087d6c0 +8087d6c8 0x8087d6c8 +8087d708 0x8087d708 +8087d76c 0x8087d76c +8087d774 0x8087d774 +8087d7b4 0x8087d7b4 +8087d7e4 0x8087d7e4 +8087d824 0x8087d824 +8087d854 0x8087d854 +8087d894 0x8087d894 +8087d8c4 0x8087d8c4 +8087d904 0x8087d904 +8087d970 0x8087d970 +8087d978 0x8087d978 +8087d9b8 0x8087d9b8 +8087da1c 0x8087da1c +8087da24 0x8087da24 +8087da64 0x8087da64 +8087daa4 0x8087daa4 +8087dad4 0x8087dad4 +80880980 0x80880980 +808809e8 0x808809e8 +80880a50 0x80880a50 +80880ac8 0x80880ac8 +80880b30 0x80880b30 +80880b98 0x80880b98 +80880c10 0x80880c10 +80880c78 0x80880c78 +80880ce0 0x80880ce0 +80880d48 0x80880d48 +80880db0 0x80880db0 +80880e04 0x80880e04 +80880e58 0x80880e58 +80880eac 0x80880eac +80880f24 0x80880f24 +80880f8c 0x80880f8c +80880fe0 0x80880fe0 +80880ffc 0x80880ffc +80881000 0x80881000 +808821c4 0x808821c4 +80882254 0x80882254 +80882340 0x80882340 +808823cc 0x808823cc +80882720 0x80882720 +808828bc 0x808828bc +80882994 0x80882994 +80882a94 0x80882a94 +80882a98 0x80882a98 +80882aa0 0x80882aa0 +80882aa8 0x80882aa8 +80882ab0 0x80882ab0 +80882ab8 0x80882ab8 +80882e24 0x80882e24 +80882eb0 0x80882eb0 +80883204 0x80883204 +80885818 0x80885818 +80885940 0x80885940 +80885aa4 0x80885aa4 +80885ab8 0x80885ab8 +80885b40 0x80885b40 +80885b48 0x80885b48 +80885b50 0x80885b50 +80885be0 obj_cruiserR::__ct +80885e18 0x80885e18 +80885ea4 0x80885ea4 +808860fc 0x808860fc +8088611c 0x8088611c +808861c4 0x808861c4 +80886a3c 0x80886a3c +80887020 0x80887020 +80887034 0x80887034 +8088707c 0x8088707c +80887084 0x80887084 +8088708c 0x8088708c +808870c4 0x808870c4 +80887120 0x80887120 +80887170 0x80887170 +80887250 0x80887250 +80887380 0x80887380 +808873c8 0x808873c8 +808873d0 0x808873d0 +808873f0 0x808873f0 +808873f8 0x808873f8 +808874cc 0x808874cc +8088750c 0x8088750c +808875d8 0x808875d8 +808875f8 0x808875f8 +80887ad0 0x80887ad0 +80887c00 0x80887c00 +80887c0c 0x80887c0c +80887c18 0x80887c18 +80887c1c 0x80887c1c +80887c70 0x80887c70 +80887c74 0x80887c74 +80887c7c 0x80887c7c +80887c80 0x80887c80 +80887c84 0x80887c84 +80887c8c 0x80887c8c +80887e30 0x80887e30 +80887e70 0x80887e70 +80888138 0x80888138 +808881dc 0x808881dc +808887d8 0x808887d8 +8088891c 0x8088891c +80888960 0x80888960 +80888b20 0x80888b20 +80888b2c 0x80888b2c +80888b34 GetOneTimerLeadGroundContactAnims +80888b40 0x80888b40 +80888b44 0x80888b44 +80888c00 0x80888c00 +80888c08 0x80888c08 +80888c0c 0x80888c0c +80888c10 0x80888c10 +80888c18 0x80888c18 +80888db0 0x80888db0 +80888e0c 0x80888e0c +80888e5c 0x80888e5c +80889014 0x80889014 +80889900 0x80889900 +80889914 0x80889914 +8088995c 0x8088995c +80889964 0x80889964 +80889984 0x80889984 +8088998c 0x8088998c +80889a1c obj_Twanwan::__ct +80889ad8 obj_Twanwan::__dt +80889b28 obj_Twanwan_load +80889f10 0x80889f10 +80889fe4 0x80889fe4 +8088a170 0x8088a170 +8088aee8 obj_Twanwan_update +8088b1e8 0x8088b1e8 +8088b200 obj_Twanwan_draw_init +8088b238 0x8088b238 +8088b374 0x8088b374 +8088b3b8 0x8088b3b8 +8088b42c 0x8088b42c +8088b434 0x8088b434 +8088b46c 0x8088b46c +8088b4b4 0x8088b4b4 +8088b520 0x8088b520 +8088bb1c 0x8088bb1c +8088bb8c 0x8088bb8c +8088bb98 0x8088bb98 +8088bbf0 0x8088bbf0 +8088bc0c 0x8088bc0c +8088c1e0 0x8088c1e0 +8088c32c 0x8088c32c +8088c330 0x8088c330 +8088c370 0x8088c370 +8088c4c4 0x8088c4c4 +8088c4c8 0x8088c4c8 +8088c508 0x8088c508 +8088c65c 0x8088c65c +8088c660 0x8088c660 +8088c6a0 0x8088c6a0 +8088c76c 0x8088c76c +8088c838 0x8088c838 +8088c904 0x8088c904 +8088c990 0x8088c990 +8088ca1c 0x8088ca1c +8088caa4 0x8088caa4 +8088cf80 0x8088cf80 +8088d468 0x8088d468 +8088d944 0x8088d944 +8088da54 0x8088da54 +8088db68 0x8088db68 +8088dc78 0x8088dc78 +8088dcd8 0x8088dcd8 +8088dd38 0x8088dd38 +8088dd98 0x8088dd98 +8088ddec 0x8088ddec +8088de40 0x8088de40 +8088de94 0x8088de94 +8088e084 0x8088e084 +8088e274 0x8088e274 +8088e464 0x8088e464 +8088e4a4 0x8088e4a4 +8088e4e4 0x8088e4e4 +8088e524 0x8088e524 +8088e6a4 0x8088e6a4 +8088e828 0x8088e828 +8088e9a0 RelEndFuncLink::AddEntry +8088e9bc RelEndFuncLink::ExecFuncs +8088ea10 0x8088ea10 diff --git a/projects/mkwii-ntsc-j/data_addresses.txt b/projects/mkwii-ntsc-j/data_addresses.txt new file mode 100644 index 0000000..1143b4e --- /dev/null +++ b/projects/mkwii-ntsc-j/data_addresses.txt @@ -0,0 +1,150 @@ +# RMCJ01 addresses for the PAL (RMCP01) data globals named by the WiiCompiled runtime. +# Derived from projects/mkwii-ntsc-u/data_addresses.txt and confirmed against the RMCJ01 binaries. +# Format: +# PROVEN - the instruction at the ported reference site forms exactly this address, +# and the independent chunk-table port of the PAL address agrees. +# CALIBRATED - the reference site reproduces the known reference-disc address for this +# global, so its decode in this region is trusted even where the chunk +# table has no mapping. +# MATCHED - the reference site's instruction window, with the fields that legitimately +# differ between regions masked out, occurs exactly once in this region's +# code; the displacement was read from that instruction. Used where the +# chunk table is not instruction-exact inside a function. +# FIELD - uniquely matched PAL base and field instructions, with the base register +# preserved and the target's own displacement decoded (including REL relocations). +# RECORD - a verified table base, target indexing stride and matching immutable records. +# SECTION - a section boundary, taken from the region section table. +# CHUNK-ONLY - chunk-table port only; no reference site formed exactly this address. +# Small-data bases: RMCJ01 r13=0x8038C580 r2=0x8038E920. +# Totals: 115 confirmed, 16 chunk-only, 0 unresolved. +80344090 80343A10 PROVEN @80172D38 (calibrated on P@80172E18) forms 0x80343A10 (chunk port agrees) +80344094 80343A14 CHUNK-ONLY (no reference site confirmed it: no-reference-site) +80344098 80343A18 CHUNK-ONLY (no reference site confirmed it: no-reference-site) +803440A4 80343A24 CHUNK-ONLY (no reference site confirmed it: no-reference-site) +803440A8 80343A28 CHUNK-ONLY (no reference site confirmed it: no-reference-site) +803440AC 80343A2C CHUNK-ONLY (no reference site confirmed it: no-reference-site) +80344110 80343A90 CHUNK-ONLY (no reference site confirmed it: no-reference-site) +80344710 80344090 CHUNK-ONLY (no reference site confirmed it: no-reference-site) +803867D8 80386158 PROVEN @8016EA44 (calibrated on P@8016EB24) forms 0x80386158 (chunk port agrees) +803886C8 80388048 PROVEN @8016B794 (calibrated on P@8016B874) forms 0x80388048 (chunk port agrees) +80343230 80342BB0 PROVEN @801634E0 (calibrated on P@801635C0) forms 0x80342BB0 (chunk port agrees) +803434E0 80342E60 PROVEN @801648A0 (calibrated on P@80164980) forms 0x80342E60 (chunk port agrees) +80386664 80385FE4 PROVEN @80162B34 (calibrated on P@80162C14) forms 0x80385FE4 (chunk port agrees) +80386668 80385FE8 PROVEN @80162B78 (calibrated on P@80162C58) forms 0x80385FE8 (chunk port agrees) +80386670 80385FF0 PROVEN @801633B0 (calibrated on P@80163490) forms 0x80385FF0 (chunk port agrees) +8038667C 80385FFC PROVEN @80163018 (calibrated on P@801630F8) forms 0x80385FFC (chunk port agrees) +803866A8 80386028 PROVEN @801633A0 (calibrated on P@80163480) forms 0x80386028 (chunk port agrees) +803866F0 80386070 PROVEN @80162B2C (calibrated on P@80162C0C) forms 0x80386070 (chunk port agrees) +80386720 803860A0 PROVEN @80164908 (calibrated on P@801649E8) forms 0x803860A0 (chunk port agrees) +80386724 803860A4 PROVEN @80164890 (calibrated on P@80164970) forms 0x803860A4 (chunk port agrees) +80386725 803860A5 PROVEN @80164784 (calibrated on P@80164864) forms 0x803860A5 (chunk port agrees) +803866A0 80386020 PROVEN @8015E950 (calibrated on P@8015EA30) forms 0x80386020 (chunk port agrees) +80346D20 803466A0 PROVEN @8019E794 (calibrated on P@8019E874) forms 0x803466A0 (chunk port agrees) +80386848 803861C8 PROVEN @8019E0CC (calibrated on P@8019E1AC) forms 0x803861C8 (chunk port agrees) +80350864 803501E4 CHUNK-ONLY (no reference site confirmed it: 801B95EC forms 0x803501E0) +80350866 803501E6 CHUNK-ONLY (no reference site confirmed it: no-reference-site) +80350872 803501F2 CHUNK-ONLY (no reference site confirmed it: 801B96CC forms 0x803501E0) +8035087C 803501FC CHUNK-ONLY (no reference site confirmed it: no-reference-site) +80350890 80350210 CHUNK-ONLY (no reference site confirmed it: 801BA9F4 forms 0x803501E0) +80386B38 803864B8 PROVEN @801B93D8 (calibrated on P@801B94B8) forms 0x803864B8 (chunk port agrees) +80386BA8 80386528 PROVEN @801BAC0C (calibrated on P@801BACEC) forms 0x80386528 (chunk port agrees) +80386BE4 80386564 PROVEN @801B9928 (calibrated on P@801B9A08) forms 0x80386564 (chunk port agrees) +80386B44 803864C4 PROVEN @801B98C4 (calibrated on P@801B99A4) forms 0x803864C4 (chunk port agrees) +80386BB8 80386538 PROVEN @801B902C (calibrated on P@801B910C) forms 0x80386538 (chunk port agrees) +80386BB4 80386534 PROVEN @801B9070 (calibrated on P@801B9150) forms 0x80386534 (chunk port agrees) +80386BA0 80386520 PROVEN @801BAA44 (calibrated on P@801BAB24) forms 0x80386520 (chunk port agrees) +80386BC0 80386540 PROVEN @801B992C (calibrated on P@801B9A0C) forms 0x80386540 (chunk port agrees) +80386F60 803868E0 PROVEN @80008E74 (calibrated on P@80008F18) forms 0x803868E0 (chunk port agrees) +80244DE0 80244D00 SECTION .ctors start (from the region section table) +80244EA0 80244DC0 SECTION .dtors start (from the region section table) +8088F400 8088EA6C SECTION .ctors start (from the region section table) +8088F704 8088ED70 SECTION .dtors start (from the region section table) +80343740 803430C0 CHUNK-ONLY (no reference site confirmed it: no-reference-site) +803437C0 80343140 CHUNK-ONLY (no reference site confirmed it: 8016B794 forms 0x80388048) +80343DC0 80343740 PROVEN @8016D0EC (calibrated on P@8016D1CC) forms 0x80343740 (chunk port agrees) +80343DE4 80343764 PROVEN @8016D0D4 (calibrated on P@8016D1B4) forms 0x80343764 (chunk port agrees) +803867B0 80386130 PROVEN @8016D100 (calibrated on P@8016D1E0) forms 0x80386130 (chunk port agrees) +803867B1 80386131 PROVEN @8016D104 (calibrated on P@8016D1E4) forms 0x80386131 (chunk port agrees) +803867C0 80386140 PROVEN @8016D0DC (calibrated on P@8016D1BC) forms 0x80386140 (chunk port agrees) +803867C4 80386144 PROVEN @8016D0D0 (calibrated on P@8016D1B0) forms 0x80386144 (chunk port agrees) +803867D0 80386150 PROVEN @8016ED60 (calibrated on P@8016EE40) forms 0x80386150 (chunk port agrees) +803477B0 80347130 PROVEN @801A9970 (calibrated on P@801A9A50) forms 0x80347130 (chunk port agrees) +80386918 80386298 PROVEN @801A97A0 (calibrated on P@801A9880) forms 0x80386298 (chunk port agrees) +8038691C 8038629C PROVEN @801A96D8 (calibrated on P@801A97B8) forms 0x8038629C (chunk port agrees) +80386920 803862A0 PROVEN @801A96D0 (calibrated on P@801A97B0) forms 0x803862A0 (chunk port agrees) +803869E0 80386360 PROVEN @801B2350 (calibrated on P@801B2430) forms 0x80386360 (chunk port agrees) +80386000 80385980 PROVEN @8000A540 (calibrated on P@8000A5E4) forms 0x80385980 (chunk port agrees) +80386F14 80386894 PROVEN @8023E470 (calibrated on P@8023E550) forms 0x80386894 (chunk port agrees) +80386F20 803868A0 PROVEN @8023E624 (calibrated on P@8023E704) forms 0x803868A0 (chunk port agrees) +80386F24 803868A4 CHUNK-ONLY (no reference site confirmed it: 8023E624 forms 0x803868A0) +80388B80 80388500 PROVEN @8021B448 (calibrated on P@8021B528) forms 0x80388500 (chunk port agrees) +80388BA0 80388520 PROVEN @8021B4D8 (calibrated on P@8021B5B8) forms 0x80388520 (chunk port agrees) +80388BC0 80388540 PROVEN @8021B548 (calibrated on P@8021B628) forms 0x80388540 (chunk port agrees) +80388BE0 80388560 PROVEN @8021B540 (calibrated on P@8021B620) forms 0x80388560 (chunk port agrees) +802574A0 80256E40 FIELD base @8021B230 -> 0x80256E20; field @8021B298 word 389F0020 (unique PAL instruction matches; register r31 preserved) +802574E0 80256E80 FIELD base @8021B230 -> 0x80256E20; field @8021B2A8 word 389F0060 (unique PAL instruction matches; register r31 preserved) +80257520 80256EC0 FIELD base @8021B230 -> 0x80256E20; field @8021B434 word 389F00A0 (unique PAL instruction matches; register r31 preserved) +80257540 80256EE0 FIELD base @8021B230 -> 0x80256E20; field @8021B4C4 word 389F00C0 (unique PAL instruction matches; register r31 preserved) +802A3EE8 802A3888 CALIBRATED @8023E494 (calibrated on P@8023E574) forms 0x802A3888 (chunk port has no mapping) +802A3EF4 802A3894 RECORD table @8023E494 -> 0x802A3888; stride @8023E48C mulli r4,r0,12; both 12-byte records equal PAL +802A3F0C 802A38AC CALIBRATED @8023D250 (calibrated on P@8023D330) forms 0x802A38AC (chunk port has no mapping) +808B4C20 808B3D80 CALIBRATED @805651D0 (calibrated on P@80565850) forms 0x808B3D80 (chunk port has no mapping) +809C1830 809C0890 PROVEN @80564A9C (calibrated on P@8056511C) forms 0x809C0890 (chunk port agrees) +809C183C 809C089C FIELD base @80564BF0 -> 0x809C0890; field @80564C08 word 3865000C (unique PAL instruction matches; register r5 preserved) +809C2898 809C18F8 CALIBRATED @807164A0 (calibrated on P@80716E34) forms 0x809C18F8 (chunk port has no mapping) +8027F820 8027F1C0 CALIBRATED @80126920 (calibrated on P@80126A00) forms 0x8027F1C0 (chunk port has no mapping) +802F81A0 802F7B20 PROVEN @80126910 (calibrated on P@801269F0) forms 0x802F7B20 (chunk port agrees) +802F8200 802F7B80 PROVEN @801268E4 (calibrated on P@801269C4) forms 0x802F7B80 (chunk port agrees) +80386608 80385F88 PROVEN @8015D390 (calibrated on P@8015D470) forms 0x80385F88 (chunk port agrees) +80386610 80385F90 PROVEN @8015D4D0 (calibrated on P@8015D5B0) forms 0x80385F90 (chunk port agrees) +80386614 80385F94 PROVEN @8015D4CC (calibrated on P@8015D5AC) forms 0x80385F94 (chunk port agrees) +80386618 80385F98 PROVEN @8015D3F8 (calibrated on P@8015D4D8) forms 0x80385F98 (chunk port agrees) +8038661C 80385F9C PROVEN @8015D400 (calibrated on P@8015D4E0) forms 0x80385F9C (chunk port agrees) +80386620 80385FA0 PROVEN @8015D404 (calibrated on P@8015D4E4) forms 0x80385FA0 (chunk port agrees) +80386624 80385FA4 PROVEN @8015D3FC (calibrated on P@8015D4DC) forms 0x80385FA4 (chunk port agrees) +80388588 80387F08 PROVEN @8012B7DC (calibrated on P@8012B8BC) forms 0x80387F08 (chunk port agrees) +8038858C 80387F0C PROVEN @8012B7EC (calibrated on P@8012B8CC) forms 0x80387F0C (chunk port agrees) +80386448 80385DC8 PROVEN @80123FEC (calibrated on P@801240CC) forms 0x80385DC8 (chunk port agrees) +8038644C 80385DCC PROVEN @80124198 (calibrated on P@80124278) forms 0x80385DCC (chunk port agrees) +8038647C 80385DFC PROVEN @8012411C (calibrated on P@801241FC) forms 0x80385DFC (chunk port agrees) +80386480 80385E00 PROVEN @80123EC0 (calibrated on P@80123FA0) forms 0x80385E00 (chunk port agrees) +80347130 80346AB0 CHUNK-ONLY (no reference site confirmed it: 801A9E68 forms 0x80346A70) +80347498 80346E18 PROVEN @801A9560 (calibrated on P@801A9640) forms 0x80346E18 (chunk port agrees) +803478B0 80347230 PROVEN @801A9C60 (calibrated on P@801A9D40) forms 0x80347230 (chunk port agrees) +80385AA8 80385428 PROVEN @801A9EA0 (calibrated on P@801A9F80) forms 0x80385428 (chunk port agrees) +80385AE0 80385460 PROVEN @801A94EC (calibrated on P@801A95CC) forms 0x80385460 (chunk port agrees) +803868F8 80386278 PROVEN @801A6518 (calibrated on P@801A65F8) forms 0x80386278 (chunk port agrees) +80386298 80385C18 PROVEN @800BC390 (calibrated on P@800BC470) forms 0x80385C18 (chunk port agrees) +80336278 80335BF8 PROVEN @8013A220 (calibrated on P@8013A300) forms 0x80335BF8 (chunk port agrees) +809BEBA0 809BDC00 FIELD base @80550654 -> 0x809BDB60; field @8055067C word 801E00A0 (unique PAL instruction matches; register r30 preserved) +809BEBA4 809BDC04 FIELD base @80550654 -> 0x809BDB60; field @80550894 word 989E00A4 (unique PAL instruction matches; register r30 preserved) +809BEBA5 809BDC05 FIELD base @80550654 -> 0x809BDB60; field @8055088C word 989E00A5 (unique PAL instruction matches; register r30 preserved) +809BEBA6 809BDC06 FIELD base @80550654 -> 0x809BDB60; field @80550898 word 989E00A6 (unique PAL instruction matches; register r30 preserved) +809BEBA7 809BDC07 FIELD base @80550654 -> 0x809BDB60; field @8055079C word 981E00A7 (unique PAL instruction matches; register r30 preserved) +809BECF0 809BDD50 CALIBRATED @80550620 (calibrated on P@80550CA0) forms 0x809BDD50 (chunk port has no mapping) +8088FDB8 8088F418 CALIBRATED @805296A8 (calibrated on P@80529D28) forms 0x8088F418 (chunk port has no mapping) +80386934 803862B4 PROVEN @801AB7D0 (calibrated on P@801AB8B0) forms 0x803862B4 (chunk port agrees) +80386938 803862B8 PROVEN @801AB7C8 (calibrated on P@801AB8A8) forms 0x803862B8 (chunk port agrees) +8038693C 803862BC PROVEN @801AB7F0 (calibrated on P@801AB8D0) forms 0x803862BC (chunk port agrees) +80386940 803862C0 PROVEN @801AB6C0 (calibrated on P@801AB7A0) forms 0x803862C0 (chunk port agrees) +80386948 803862C8 PROVEN @801AB6A0 (calibrated on P@801AB780) forms 0x803862C8 (chunk port agrees) +80386770 803860F0 PROVEN @80169B04 (calibrated on P@80169BE4) forms 0x803860F0 (chunk port agrees) +80386774 803860F4 PROVEN @80169B34 (calibrated on P@80169C14) forms 0x803860F4 (chunk port agrees) +8038677C 803860FC PROVEN @80169B14 (calibrated on P@80169BF4) forms 0x803860FC (chunk port agrees) +80386780 80386100 PROVEN @80169B1C (calibrated on P@80169BFC) forms 0x80386100 (chunk port agrees) +80386784 80386104 PROVEN @80169BEC (calibrated on P@80169CCC) forms 0x80386104 (chunk port agrees) +803867EC 8038616C PROVEN @80192ED0 (calibrated on P@80192FB0) forms 0x8038616C (chunk port agrees) +803867F0 80386170 PROVEN @80192ECC (calibrated on P@80192FAC) forms 0x80386170 (chunk port agrees) +80385920 803852A0 PROVEN @80169B7C (calibrated on P@80169C5C) forms 0x803852A0 (chunk port agrees) +80385928 803852A8 PROVEN @80169B64 (calibrated on P@80169C44) forms 0x803852A8 (chunk port agrees) +803868A0 80386220 PROVEN @801A0500 (calibrated on P@801A05E0) forms 0x80386220 (chunk port agrees) +80386528 80385EA8 PROVEN @8012686C (calibrated on P@8012694C) forms 0x80385EA8 (chunk port agrees) +80386524 80385EA4 PROVEN @801267C4 (calibrated on P@801268A4) forms 0x80385EA4 (chunk port agrees) +80385800 80385180 PROVEN @80126934 (calibrated on P@80126A14) forms 0x80385180 (chunk port agrees) +80385802 80385182 PROVEN @8012693C (calibrated on P@80126A1C) forms 0x80385182 (chunk port agrees) +80385804 80385184 PROVEN @8012692C (calibrated on P@80126A0C) forms 0x80385184 (chunk port agrees) +80388DD0 80388750 PROVEN @8022D694 (calibrated on P@8022D774) forms 0x80388750 (chunk port agrees) +80388DE0 80388760 PROVEN @8022DDC8 (calibrated on P@8022DEA8) forms 0x80388760 (chunk port agrees) +80388DF4 80388774 PROVEN @8022E120 (calibrated on P@8022E200) forms 0x80388774 (chunk port agrees) +8029CEB0 8029C850 CALIBRATED @801B22E0 (calibrated on P@801B23C0) forms 0x8029C850 (chunk port has no mapping) +8029CEF8 8029C898 CALIBRATED @801B2408 (calibrated on P@801B24E8) forms 0x8029C898 (chunk port has no mapping) diff --git a/projects/mkwii-ntsc-j/recomp.yml b/projects/mkwii-ntsc-j/recomp.yml new file mode 100644 index 0000000..c3642f6 --- /dev/null +++ b/projects/mkwii-ntsc-j/recomp.yml @@ -0,0 +1,72 @@ +schema_version: 1 +workspace_root: ../.. + +# Mario Kart Wii NTSC-J (RMCJ01). The same translation surface as projects/mkwii/recomp.yml, with +# the facts that differ per region: the small-data bases the DOL's __init_registers installs, the +# StaticR.rel load address and the clean-input digests. The function map is the PAL map ported +# through the community region table and validated against these binaries. +project: + id: mkwii-rmcj01 + display_name: Mario Kart Wii NTSC-J + game_id: RMCJ01 + region: J + base_manifest_format: mkwii-recomp-base-manifest + base_manifest_stem: mkwii_base + +memory: + base: 0x80000000 + size: 0x01A00000 + sda_base: 0x8038C580 + sda2_base: 0x8038E920 + +inputs: + dol: + path: Assets/main.dol + sha256: 1b9621ef7c5d97dada103e50e5389730e67f3c2545dda592edd4b5843655af91 + + rel: + path: Assets/StaticR.rel + load_address: 0x8050FC60 + sha256: 88539012d357a1420724e51dc7e351192ce696da4b0045994895518a3fad6fae + +translation: + entry_points: + - 0x800060A4 + function_map: + path: projects/mkwii-ntsc-j/MAP.txt + allow_unsupported_instructions: false + +runtime: + native_registration_root: runtime/src + native_abi_directories: + - runtime/src/hle/gx + +output: + root: generated + functions: functions + runtime_config: RuntimeConfig.h + data_initializer: data_sections_init.cpp + base_manifest: ../build/base/mkwii_base_manifest.json + +# Code.pul carries a separate chunk for this region. The regional link base determines +# the branch bytes checked at startup; execution is remapped to module_guest_base. +profiles: + retro-rewind: + enabled: true + requires_game_id: RMCJ01 + requires_dol_sha256: 1b9621ef7c5d97dada103e50e5389730e67f3c2545dda592edd4b5843655af91 + code_pul: PulsarPacks/completed/RetroRewind/RetroRewind6/Binaries/Code.pul + mod_root: PulsarPacks/completed/RetroRewind/RetroRewind6 + region: J + module_guest_base: 0x81800000 + module_link_base: 0x80398C60 + output: build/mods/retro_rewind_full_cpp + enable_retro_wfc: true + retro_wfc_payload: https://rwfc.net/api/wfc/payload?g=RMCJD00 + retro_wfc_legacy_bootstrap_hook: 0x800ED608 + riivolution: + xml: xml/RetroRewind6.xml + options: + - section: Retro Rewind + option: Pack + choice: 1 diff --git a/projects/mkwii-ntsc-j/region_port.json b/projects/mkwii-ntsc-j/region_port.json new file mode 100644 index 0000000..d4f69f9 --- /dev/null +++ b/projects/mkwii-ntsc-j/region_port.json @@ -0,0 +1,591 @@ +{ + "source_region": "P", + "target_region": "J", + "attribution": "chunk table and section layouts vendored from the mkw-sp project (https://github.com/mkw-sp/mkw-sp, port.py)", + "license": "MIT. Copyright (c) 2021-2023 Pablo Stebler. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", + "port_rule": "if src_start <= a < src_end then a - src_start + dst_start", + "address_format": "hex strings", + "chunks": [ + [ + "0x80004000", + "0x80008024", + "0x80004000" + ], + [ + "0x800080E8", + "0x8000ADC0", + "0x80008044" + ], + [ + "0x8000AF08", + "0x80021BAC", + "0x8000AE2C" + ], + [ + "0x80021BAC", + "0x80244DE0", + "0x80021ACC" + ], + [ + "0x802A4080", + "0x8038917C", + "0x802A3A00" + ], + [ + "0x805103B4", + "0x805CC0A8", + "0x8050FD34" + ], + [ + "0x805CC1B4", + "0x805FA33C", + "0x805CBA90" + ], + [ + "0x805FA344", + "0x805FF6E8", + "0x805F9C20" + ], + [ + "0x805FFD70", + "0x806003E8", + "0x805FF528" + ], + [ + "0x80600C78", + "0x80620CB4", + "0x806003EC" + ], + [ + "0x80620D7C", + "0x80637A24", + "0x806204C8" + ], + [ + "0x80637A80", + "0x8063BCF8", + "0x8063716C" + ], + [ + "0x8063BE40", + "0x8088F400", + "0x8063B4AC" + ], + [ + "0x808913C0", + "0x808913C4", + "0x80890A10" + ], + [ + "0x80895238", + "0x808952B8", + "0x80894888" + ], + [ + "0x808AD3C4", + "0x808AD3C8", + "0x808AC524" + ], + [ + "0x808B3984", + "0x808B3988", + "0x808B2AE4" + ], + [ + "0x808B5B1C", + "0x808B5B20", + "0x808B4C7C" + ], + [ + "0x808B5C78", + "0x808B5C7C", + "0x808B4DD8" + ], + [ + "0x808BB034", + "0x808BB098", + "0x808BA184" + ], + [ + "0x808CB550", + "0x808CB554", + "0x808CA6A0" + ], + [ + "0x808D3698", + "0x808D369C", + "0x808D27E8" + ], + [ + "0x808D36CC", + "0x808D36D0", + "0x808D281C" + ], + [ + "0x808D36D4", + "0x808D36D8", + "0x808D2824" + ], + [ + "0x808D3744", + "0x808D3748", + "0x808D2894" + ], + [ + "0x808D374C", + "0x808D3750", + "0x808D289C" + ], + [ + "0x808D3E14", + "0x808D3E18", + "0x808D2F64" + ], + [ + "0x808DA070", + "0x808DA080", + "0x808D91C0" + ], + [ + "0x808DA318", + "0x808DA368", + "0x808D9468" + ], + [ + "0x809BD6E8", + "0x809BD74C", + "0x809BC748" + ], + [ + "0x809C1830", + "0x809C1834", + "0x809C0890" + ], + [ + "0x809C1874", + "0x809C1878", + "0x809C08D4" + ], + [ + "0x809C18F8", + "0x809C18FC", + "0x809C0958" + ], + [ + "0x809C1988", + "0x809C198C", + "0x809C09E8" + ], + [ + "0x809C19A0", + "0x809C19BC", + "0x809C0A00" + ], + [ + "0x809C1E38", + "0x809C1E3C", + "0x809C0E98" + ], + [ + "0x809C21D0", + "0x809C21D4", + "0x809C1230" + ], + [ + "0x809C21D8", + "0x809C21DC", + "0x809C1238" + ], + [ + "0x809C2328", + "0x809C232C", + "0x809C1388" + ], + [ + "0x809C27F0", + "0x809C27FC", + "0x809C1850" + ], + [ + "0x809C282C", + "0x809C2854", + "0x809C188C" + ], + [ + "0x809C28B8", + "0x809C28BC", + "0x809C1918" + ], + [ + "0x809C2BE8", + "0x809C2BEC", + "0x809C1C48" + ], + [ + "0x809C2EF0", + "0x809C2EF4", + "0x809C1F50" + ], + [ + "0x809C2F38", + "0x809C2F40", + "0x809C1F98" + ], + [ + "0x809C2F44", + "0x809C2F48", + "0x809C1FA4" + ], + [ + "0x809C3618", + "0x809C361C", + "0x809C2678" + ], + [ + "0x809C38B8", + "0x809C38BC", + "0x809C2918" + ], + [ + "0x809C4330", + "0x809C4334", + "0x809C3390" + ], + [ + "0x809C4680", + "0x809C4684", + "0x809C36E0" + ], + [ + "0x809C4740", + "0x809C474C", + "0x809C37A0" + ], + [ + "0x809C496C", + "0x809C4970", + "0x809C39CC" + ] + ], + "rel_load_address": { + "P": "0x805102E0", + "E": "0x8050BF60", + "J": "0x8050FC60" + }, + "dol_sections": { + "P": [ + { + "name": "init", + "start": "0x80004000", + "end": "0x80006460" + }, + { + "name": "extab", + "start": "0x80006460", + "end": "0x80006A20" + }, + { + "name": "extabindex", + "start": "0x80006A20", + "end": "0x800072C0" + }, + { + "name": "text", + "start": "0x800072C0", + "end": "0x80244DE0" + }, + { + "name": "ctors", + "start": "0x80244DE0", + "end": "0x80244EA0" + }, + { + "name": "dtors", + "start": "0x80244EA0", + "end": "0x80244EC0" + }, + { + "name": "rodata", + "start": "0x80244EC0", + "end": "0x80258580" + }, + { + "name": "data", + "start": "0x80258580", + "end": "0x802A4040" + }, + { + "name": "bss", + "start": "0x802A4080", + "end": "0x80384C00" + }, + { + "name": "sdata", + "start": "0x80384C00", + "end": "0x80385FC0" + }, + { + "name": "sbss", + "start": "0x80385FC0", + "end": "0x80386FA0" + }, + { + "name": "sdata2", + "start": "0x80386FA0", + "end": "0x80389140" + }, + { + "name": "sbss2", + "start": "0x80389140", + "end": "0x8038917C" + } + ], + "E": [ + { + "name": "init", + "start": "0x80004000", + "end": "0x80006460" + }, + { + "name": "extab", + "start": "0x80006460", + "end": "0x80006A20" + }, + { + "name": "extabindex", + "start": "0x80006A20", + "end": "0x800072C0" + }, + { + "name": "text", + "start": "0x800072C0", + "end": "0x80244D40" + }, + { + "name": "ctors", + "start": "0x80244D40", + "end": "0x80244E00" + }, + { + "name": "dtors", + "start": "0x80244E00", + "end": "0x80244E20" + }, + { + "name": "rodata", + "start": "0x80244E40", + "end": "0x80258260" + }, + { + "name": "data", + "start": "0x80258260", + "end": "0x8029FD00" + }, + { + "name": "bss", + "start": "0x8029FD00", + "end": "0x80380880" + }, + { + "name": "sdata", + "start": "0x80380880", + "end": "0x80381C40" + }, + { + "name": "sbss", + "start": "0x80381C40", + "end": "0x80382C20" + }, + { + "name": "sdata2", + "start": "0x80382C20", + "end": "0x80384DC0" + }, + { + "name": "sbss2", + "start": "0x80384DC0", + "end": "0x80384DFC" + } + ], + "J": [ + { + "name": "init", + "start": "0x80004000", + "end": "0x80006460" + }, + { + "name": "extab", + "start": "0x80006460", + "end": "0x80006A20" + }, + { + "name": "extabindex", + "start": "0x80006A20", + "end": "0x800072C0" + }, + { + "name": "text", + "start": "0x800072C0", + "end": "0x80244D00" + }, + { + "name": "ctors", + "start": "0x80244D00", + "end": "0x80244DC0" + }, + { + "name": "dtors", + "start": "0x80244DC0", + "end": "0x80244DE0" + }, + { + "name": "rodata", + "start": "0x80244E00", + "end": "0x80257F20" + }, + { + "name": "data", + "start": "0x80257F20", + "end": "0x802A39E0" + }, + { + "name": "bss", + "start": "0x802A3A00", + "end": "0x80384580" + }, + { + "name": "sdata", + "start": "0x80384580", + "end": "0x80385940" + }, + { + "name": "sbss", + "start": "0x80385940", + "end": "0x80386920" + }, + { + "name": "sdata2", + "start": "0x80386920", + "end": "0x80388AC0" + }, + { + "name": "sbss2", + "start": "0x80388AC0", + "end": "0x80388AFC" + } + ] + }, + "rel_sections": { + "P": [ + { + "name": "text", + "start": "0x805103B4", + "end": "0x8088F400" + }, + { + "name": "ctors", + "start": "0x8088F400", + "end": "0x8088F704" + }, + { + "name": "dtors", + "start": "0x8088F704", + "end": "0x8088F710" + }, + { + "name": "rodata", + "start": "0x8088F720", + "end": "0x808B2BD0" + }, + { + "name": "data", + "start": "0x808B2BD0", + "end": "0x808DD3D4" + }, + { + "name": "bss", + "start": "0x809BD6E0", + "end": "0x809C4F90" + } + ], + "E": [ + { + "name": "text", + "start": "0x8050C034", + "end": "0x8088AFD0" + }, + { + "name": "ctors", + "start": "0x8088AFD0", + "end": "0x8088B2D4" + }, + { + "name": "dtors", + "start": "0x8088B2D4", + "end": "0x8088B2E0" + }, + { + "name": "rodata", + "start": "0x8088B2E0", + "end": "0x808AE520" + }, + { + "name": "data", + "start": "0x808AE520", + "end": "0x808D8C7C" + }, + { + "name": "bss", + "start": "0x809B8F20", + "end": "0x809C07D0" + } + ], + "J": [ + { + "name": "text", + "start": "0x8050FD34", + "end": "0x8088EA6C" + }, + { + "name": "ctors", + "start": "0x8088EA6C", + "end": "0x8088ED70" + }, + { + "name": "dtors", + "start": "0x8088ED70", + "end": "0x8088ED7C" + }, + { + "name": "rodata", + "start": "0x8088ED80", + "end": "0x808B1D30" + }, + { + "name": "data", + "start": "0x808B1D30", + "end": "0x808DC524" + }, + { + "name": "bss", + "start": "0x809BC740", + "end": "0x809C3FF0" + } + ] + }, + "validated_against": { + "dol": { + "path": "main.dol", + "sha256": "1b9621ef7c5d97dada103e50e5389730e67f3c2545dda592edd4b5843655af91", + "entry": "0x800060A4" + }, + "rel": { + "path": "StaticR.rel", + "sha256": "88539012d357a1420724e51dc7e351192ce696da4b0045994895518a3fad6fae", + "module_id": 1, + "prolog": "0x80554C9C", + "epilog": "0x80554CE8", + "unresolved": "0x80554D30" + } + } +} diff --git a/projects/mkwii-ntsc-u/MAP.txt b/projects/mkwii-ntsc-u/MAP.txt new file mode 100644 index 0000000..27bebf6 --- /dev/null +++ b/projects/mkwii-ntsc-u/MAP.txt @@ -0,0 +1,29412 @@ +# NTSC-U (RMCE01) function map, ported from ../mkwii/MAP.txt (PAL RMCP01). +# Every entry was validated against the RMCE01 main.dol/StaticR.rel. +# Verdicts: PROVEN=12178, REFERENCED=12573, PLAUSIBLE=4500, IDENTITY=15, INTERPOLATED=0, ADDED=143 (binary-proven entries no PAL entry covers); entries=29409 +800018a8 0x800018a8 +80001d50 0x80001d50 +80001d6c 0x80001d6c +80001d90 0x80001d90 +80001dc0 0x80001dc0 +80001de8 0x80001de8 +80001dec 0x80001dec +80001e14 0x80001e14 +80001e30 0x80001e30 +80001f1c 0x80001f1c +80001f40 0x80001f40 +80001f54 0x80001f54 +80002440 0x80002440 +8000245c 0x8000245c +8000249c __TRKreset +80005f34 memcpy +80005f84 __fill_mem +80006038 memset +80006068 __check_pad3 +80006090 __set_debug_bba +8000609c __get_debug_bba +800060a4 __start +80006210 __init_registers +800062a0 __init_data +80006348 __init_hardware +8000636c __flush_cache +800063a0 0x800063a0 +800072c0 StrapScene::__ct +800073f0 RKScene::__dt +80007448 StrapScene::__dt +800074a4 StrapScene::LinkModule +800074d8 StrapScene::enter +800077c8 StrapScene::CheckInput +800079d0 StrapScene::calc +80007bc0 EGG::ColorFader::getStatus +80007bc8 StrapScene::draw +80007f2c StrapScene::exit +80007f34 EGG::Scene::outgoing_child_create +80007f38 EGG::Scene::incoming_child_destroy +80007f3c EGG::Scene::reinit +80007f40 EGG::Scene::exit +80007f44 EGG::Scene::enter +80007f48 EGG::Scene::draw +80007f4c EGG::Scene::calc +80007f50 getContentArcNameByIdx +80007f64 0x80007f64 +80007f7c DiscError::__ct +80007fac DiscError::__dt +80008004 setDiscReadErrorMessage +800080b4 0x800080b4 +800080b8 DiscInfoMessageData_printError +80008b90 nw4r::ut::Color::__dt +80008bd0 DiscCheckThread::create +80008c70 DiscCheckThread::__dt +80008cd8 DvdThread_main +80008de0 DiscCheckThread::halt +80008e34 DiscInfo_printError +80008e3c 0x80008e3c +80008e40 0x80008e40 +80008e44 RKSystem::GetStaticInstance +80008e50 RKSystem::WPADAlloc +80008e70 RKSystem::WPADFree +80008eb0 RKSystem::Main +80008f6c RKSystem::GetSystemHeap +80008f74 EGG::TSystem::Initialize +80009150 EGG::TSystem::InitRenderMode +80009154 RKSystem::Initialize +800094dc RKSystem::Run +800097d8 EGG::TSystem::GetDisplay +800097e0 EGG::TSystem::OnBeginFrame +800097e4 EGG::TSystem::OnEndFrame +800097e8 EGG::TSystem::GetSceneMgr +800097f0 EGG::TSystem::GetPerfView +80009804 RKSceneManager::ChangeSceneByCreatorAfterFadeOut +8000980c RKSceneManager::calcCurrentFader +80009944 RKSceneManager::calc +80009948 RKSceneManager::draw +8000994c RKSceneManager::drawCurrentFaderImpl +8000995c RKSceneManager::calcCurrentFaderImpl +8000996c EGG::TSystem::GetVideo +80009974 EGG::TSystem::GetSystemHeap +8000997c EGG::TSystem::GetXfbMgr +80009984 EGG::TSystem::GetAudioMgr +8000998c __sinit_\RKSystem_cpp +80009b00 EGG::Vector3f::__dt +80009b40 EGG::Vector2f::__dt +80009b80 ExpHeapGroup::SetHeapsGroupId +80009be4 ExpHeapGroup::CalculateGroupSizeRecords +80009c4c RKParameterFile::__ct +80009ca0 RKParameterFile::__dt +80009d2c RKParameterFile::AddParameter +80009d9c RKParameterFile::ReadParameterFile +80009eb8 RamStream::__dt +80009f10 RKParameterFile::vf_0x18 +80009f14 RKParameterFile::vf_0x14 +80009f18 RKParameterFile::vf_0x10 +80009f1c ModuleLinker::Disposer__dt +80009fb0 ModuleLinker::Create +8000a02c ModuleLinker::0x8000a06c +8000a030 ModuleLinker::0x8000a070 +8000a034 ModuleLinker::__dt +8000a148 ModuleLinker::Link +8000a3b8 ModuleLinker::CallModule +8000a400 ModuleLinker::Report +8000a510 RKSceneCreator::create +8000a568 RKSceneCreator::destroy +8000a590 SystemManager::create +8000a5e4 SystemManager::__dt +8000a648 SystemManager::__ct +8000a8b0 SystemManager::PrepareLaunch +8000ab48 SystemManager::LoadMapFile +8000ac10 SystemManager::Init +8000aed8 SystemManager::GetCountry +8000af4c SystemManager::GetLongitude +8000b000 SystemManager::GetLatitude +8000b0b4 SystemManager::Shutdown +8000b0e8 SystemManager::ReturnToMenu +8000b11c SystemManager::RestartGame +8000b154 0x8000b154 +8000b170 0x8000b170 +8000b18c SystemManager::SetSystemPowerCallbacks +8000b1cc SystemManager::HandlePowerState +8000b238 SystemManager::GetGameId +8000b240 SystemManager::GenerateGameId +8000b268 SystemManager::RipFromDiscAsync +8000b2d0 SystemManager::RipFromDiscImpl +8000b49c SystemManager::ProcessRipRequest +8000b528 SystemManager::RipFromDisc(heap) +8000b550 SystemManager::RipFromDisc(no heap) +8000b570 SystemManager::GetDisplayModeType +8000b5b4 SystemManager::StopAllControllerMotors +8000b610 Main +8000b614 _ftell +8000b6bc ftell +8000b6c0 _fseek +8000b884 fseek +8000b888 rewind +8000b8d0 atexit +8000b8d4 Block_link +8000ba24 SubBlock_merge_next +8000bacc deallocate_from_fixed_pools +8000bcb8 free +8000bde8 __close_all +8000be8c __flush_line_buffered_output_files +8000bf10 __flush_all +8000bf7c __ull2dec +8000c058 __timesdec +8000c2e0 __str2dec +8000c3cc __two_exp +8000c408 __two_exp_switch +8000c40c __two_exp_caseD_ffffffc0 +8000c420 __two_exp_caseD_ffffffcb +8000c438 __two_exp_caseD_ffffffe0 +8000c450 __two_exp_caseD_fffffff0 +8000c468 __two_exp_caseD_fffffff8 +8000c480 __two_exp_caseD_fffffff9 +8000c498 __two_exp_caseD_fffffffa +8000c4b0 __two_exp_caseD_fffffffb +8000c4c8 __two_exp_caseD_fffffffc +8000c4e0 __two_exp_caseD_fffffffd +8000c4f8 __two_exp_caseD_fffffffe +8000c510 __two_exp_caseD_ffffffff +8000c528 __two_exp_caseD_0 +8000c540 __two_exp_caseD_1 +8000c558 __two_exp_caseD_2 +8000c570 __two_exp_caseD_3 +8000c588 __two_exp_caseD_4 +8000c5a0 __two_exp_caseD_5 +8000c5b8 __two_exp_caseD_6 +8000c5d0 __two_exp_caseD_7 +8000c5e8 __two_exp_caseD_8 +8000c600 __two_exp_caseD_ffffffc1 +8000c738 __equals_dec +8000c81c __less_dec +8000c91c __minus_dec +8000ce38 __num2dec_internal +8000cf9c __num2dec +8000d13c __dec2num +8000d8d4 __prep_buffer +8000d8fc __load_buffer +8000d9f8 __flush_buffer +8000dab0 fread +8000dab4 __fread +8000ddf4 __fwrite +8000e0fc fclose +8000e1b8 fflush +8000e2ec __msl_strnicmp +8000e3a4 __fpclassifyf +8000e404 __signbitd +8000e41c __fpclassifyd +8000e498 mbtowc +8000e4b0 __mbtowc_noconv +8000e4fc __wctomb_noconv +8000e518 mbstowcs +8000e5d8 wcstombs +8000e690 memmove +8000e75c memchr +8000e788 __memrchr +8000e7b4 memcmp +8000e800 __copy_longs_aligned +8000e8bc __copy_longs_rev_aligned +8000e964 __copy_longs_unaligned +8000ea24 __copy_longs_rev_unaligned +8000ead0 __stdio_atexit +8000eae0 parse_format +8000ee70 parse_format_switch +8000ee74 parse_format_caseD_58 +8000eebc parse_format_caseD_46 +8000ef04 parse_format_caseD_41 +8000ef50 parse_format_caseD_47 +8000ef64 parse_format_caseD_45 +8000efb4 parse_format_caseD_70 +8000efd8 parse_format_caseD_63 +8000f010 parse_format_caseD_73 +8000f03c 0x8000f03c +8000f09c long2str +8000f2d4 longlong2str +8000f584 double2hex +8000f954 round_decimal +8000fa7c float2str +80010214 _pformatter +80010314 _pformatter_switch +80010318 _pformatter_caseD_64 +80010474 _pformatter_caseD_58 +800105d0 _pformatter_caseD_45 +80010640 _pformatter_caseD_41 +800106b0 _pformatter_caseD_73 +800107d4 _pformatter_caseD_6e +8001088c _pformatter_caseD_63 +800108ac _pformatter_caseD_25 +800108bc _pformatter_caseD_26 +80010ac0 __FileWrite +80010b18 __StringWrite +80010b84 printf +80010c50 vprintf +80010ccc vsnprintf +80010d54 vsprintf +80010dd8 snprintf +80010ecc sprintf +80010fa0 qsort +80011110 rand +80011130 srand +80011138 parse_format +8001140c parse_format_switch +80011410 parse_format_caseD_58 +80011428 parse_format_caseD_41 +80011470 parse_format_caseD_70 +80011484 parse_format_caseD_63 +800114b0 parse_format_caseD_73 +80011568 parse_format_caseD_5b +80011754 parse_format_caseD_42 +8001175c parse_format_caseD_6e +800117c0 __sformatter +80011a44 __sformatter_switch +80011a48 __sformatter_caseD_64 +80011a50 __sformatter_caseD_69 +80011b90 __sformatter_switch +80011b94 __sformatter_caseD_0 +80011b9c __sformatter_caseD_1 +80011ba4 __sformatter_caseD_2 +80011bac __sformatter_caseD_3 +80011bb4 __sformatter_caseD_4 +80011bc8 __sformatter_caseD_5 +80011bd0 __sformatter_caseD_6 +80011bd8 __sformatter_caseD_7 +80011bfc __sformatter_caseD_6f +80011c04 __sformatter_caseD_75 +80011c0c __sformatter_caseD_58 +80011d28 __sformatter_switch +80011d2c __sformatter_caseD_0 +80011d34 __sformatter_caseD_1 +80011d3c __sformatter_caseD_2 +80011d44 __sformatter_caseD_3 +80011d4c __sformatter_caseD_4 +80011d60 __sformatter_caseD_5 +80011d68 __sformatter_caseD_6 +80011d70 __sformatter_caseD_7 +80011d94 __sformatter_caseD_41 +80011e3c __sformatter_caseD_63 +80011fe8 __sformatter_caseD_25 +80012090 __sformatter_caseD_73 +80012134 __sformatter_caseD_5b +8001239c __sformatter_caseD_6e +8001240c __sformatter_caseD_26 +80012458 __StringRead +800124e0 sscanf +800125a8 raise +800125c0 strcpy +80012680 strncpy +800126c4 strcat +800126f0 strncat +8001273c strcmp +80012858 strncmp +80012898 strchr +800128c8 strcspn +8001296c strtok +80012a90 strstr +80012afc __strtold +80013e30 atof +80013e8c __strtoul +800142a0 __strtoull +80014748 strtoul +800147f0 strtol +800148dc atoi +800149a0 __write_console +80014a70 0x80014a70 +80014a78 fwide +80014af0 wmemcpy +80014af8 wmemchr +80014b20 parse_format +80014e70 parse_format_switch +80014e74 parse_format_caseD_58 +80014eb8 parse_format_caseD_46 +80014f04 parse_format_caseD_41 +80014f54 parse_format_caseD_47 +80014f68 parse_format_caseD_45 +80014fbc parse_format_caseD_70 +80014fe0 parse_format_caseD_63 +8001501c parse_format_caseD_73 +8001504c parse_format_caseD_6e +80015064 parse_format_caseD_42 +800150b0 long2str +800152f4 longlong2str +800155b0 double2hex +80015a08 round_decimal +80015b30 float2str +800162bc __wpformatter +800163cc __wpformatter_switch +800163d0 __wpformatter_caseD_64 +8001652c __wpformatter_caseD_58 +80016688 __wpformatter_caseD_45 +80016704 __wpformatter_caseD_41 +80016780 __wpformatter_caseD_73 +8001692c __wpformatter_caseD_6e +800169e4 __wpformatter_caseD_63 +80016a3c __wpformatter_caseD_25 +80016a4c __wpformatter_caseD_26 +80016c48 __wStringWrite +80016cb4 swprintf +80016dac vswprintf +80016e38 wcslen +80016e54 wcscpy +80016e70 wcsncpy +80016eb4 wcscmp +80016ee8 wcschr +80016f14 __ieee754_acos +800171e0 __ieee754_asin +80017478 __ieee754_atan2 +800176d0 __ieee754_fmod +80017a00 __ieee754_log +80017cb4 __ieee754_log10 +80017dc8 __ieee754_pow +800185dc __ieee754_rem_pio2 +80018960 __ieee754_sqrt +80018ba8 __kernel_cos +80018cb8 __kernel_rem_pio2 +8001a370 __kernel_sin +8001a430 __kernel_tan +8001a680 nan +8001a684 scalbn +8001a688 atan +8001a8b8 ceil +8001aa04 copysign +8001aa30 cos +8001aaf8 floor +8001ac48 frexp +8001acd0 ldexp +8001ae3c modf +8001af38 sin +8001b004 tan +8001b07c acos +8001b080 asin +8001b084 atan2 +8001b088 fmod +8001b08c log10 +8001b090 pow +8001b094 sqrt +8001b098 stricmp +8001b138 strncasecmp +8001b13c strcasecmp +8001b1dc CBGetBytesAvailableForRead +8001b1e4 CircleBufferInitialize +8001b208 CircleBufferWriteBytes +8001b310 CircleBufferReadBytes +8001b41c MWEnterCriticalSection +8001b44c MWExitCriticalSection +8001b454 gdev_cc_initialize +8001b490 0x8001b490 +8001b498 0x8001b498 +8001b4bc 0x8001b4bc +8001b4c4 gdev_cc_read +8001b578 gdev_cc_write +8001b5ec gdev_cc_pre_continue +8001b610 gdev_cc_post_stop +8001b634 gdev_cc_peek +8001b6a8 gdev_cc_initinterrupts +8001b6cc TRK_DispatchMessage +8001b710 TRK_DispatchMessage_switch +8001b714 TRK_DispatchMessage_caseD_1 +8001b724 TRK_DispatchMessage_caseD_2 +8001b734 TRK_DispatchMessage_caseD_3 +8001b744 TRK_DispatchMessage_caseD_7 +8001b754 TRK_DispatchMessage_caseD_10 +8001b764 TRK_DispatchMessage_caseD_11 +8001b774 TRK_DispatchMessage_caseD_12 +8001b784 TRK_DispatchMessage_caseD_13 +8001b794 TRK_DispatchMessage_caseD_18 +8001b7a4 TRK_DispatchMessage_caseD_19 +8001b7b4 TRK_DispatchMessage_caseD_1a +8001b7c4 TRK_DispatchMessage_caseD_17 +8001b7d0 TRK_DispatchMessage_caseD_0 +8001b7ec InitMetroTRK +8001b884 InitMetroTRK_BBA +8001b918 EnableMetroTRKInterrupts +8001b91c TRKTargetTranslate +8001b984 __TRK_copy_vectors +8001bab8 TRKInitializeTarget +8001bb00 __TRKreset +8001bb10 TRKLoadContext +8001bb98 TRKEXICallBack +8001bbd0 InitMetroTRKCommTable +8001bd08 TRKUARTInterruptHandler +8001bd0c TRK_InitializeIntDrivenUART +8001bd8c TRKPollUART +8001bda0 TRKReadUARTN +8001bddc TRK_WriteUARTN +8001be18 ReserveEXI2Port +8001be2c UnreserveEXI2Port +8001be40 0x8001be40 +8001be58 InitializeProgramEndTrap +8001beac TRK_flush_cache +8001bee4 TRK_main +8001bf20 TRK_NubMainLoop +8001c00c TRK_memcpy +8001c148 TRK_memset +8001c270 TRKSaveExtended1Block +8001c434 TRKRestoreExtended1Block +8001c598 TRK_MessageSend +8001c5fc TRK_InitializeMessageBuffers +8001c61c TRK_GetFreeBuffer +8001c6b8 TRKGetBuffer +8001c6dc TRK_ReleaseBuffer +8001c704 TRKResetBuffer +8001c72c TRK_SetBufferPosition +8001c75c TRK_AppendBuffer +8001c800 TRK_ReadBuffer +8001c890 TRKAppendBuffer1_ui32 +8001c960 TRKAppendBuffer1_ui64 +8001ca54 TRKAppendBuffer_ui8 +8001cab8 TRKAppendBuffer_ui32 +8001cba8 TRKReadBuffer1_ui64 +8001cc88 TRKReadBuffer_ui8 +8001cd20 TRKReadBuffer_ui32 +8001ce08 GetTRKConnected +8001ce10 TRK_DoConnect +8001ce80 TRKDoDisconnect +8001cf08 TRKDoReset +8001cf74 TRKDoOverride +8001cfe0 TRKDoReadMemory +8001d16c TRKDoReadMemory_switch +8001d170 TRKDoReadMemory_caseD_702 +8001d178 TRKDoReadMemory_caseD_700 +8001d180 TRKDoReadMemory_caseD_704 +8001d188 TRKDoReadMemory_caseD_705 +8001d190 TRKDoReadMemory_caseD_706 +8001d198 TRKDoReadMemory_caseD_701 +8001d214 TRKDoWriteMemory +8001d37c TRKDoWriteMemory_switch +8001d380 TRKDoWriteMemory_caseD_702 +8001d388 TRKDoWriteMemory_caseD_700 +8001d390 TRKDoWriteMemory_caseD_704 +8001d398 TRKDoWriteMemory_caseD_705 +8001d3a0 TRKDoWriteMemory_caseD_706 +8001d3a8 TRKDoWriteMemory_caseD_701 +8001d424 TRKDoReadRegisters +8001d620 TRKDoWriteRegisters +8001d8c0 TRKDoContinue +8001d984 TRKDoStep +8001dc08 TRKDoStop +8001dcc0 TRKDoSetOption +8001dd8c __read_console +8001ddf4 __TRK_write_console +8001de5c __read_file +8001de64 __access_file +8001de6c 0x8001de6c +8001df18 TRKDoNotifyStopped +8001dfa8 TRKInitializeEventQueue +8001dfcc TRKGetNextEvent +8001e058 TRKPostEvent +8001e124 TRKConstructEvent +8001e13c TRKDestructEvent +8001e144 TRK_InitializeNub +8001e1f0 TRK_TerminateNub +8001e214 TRK_board_display +8001e220 TRK_InitializeEndian +8001e294 TRKTestForPacket +8001e360 TRKGetInput +8001e38c TRKProcessInput +8001e3cc TRKInitializeSerialHandler +8001e3d4 TRKTerminateSerialHandler +8001e3dc TRK_strlen +8001e3f8 TRK_SuppAccessFile +8001e5ec TRK_RequestSend +8001e714 HandleOpenFileSupportRequest +8001e82c HandleCloseFileSupportRequest +8001e910 HandlePositionFileSupportRequest +8001ea1c TRKTargetContinue +8001ea50 SetUseSerialIO +8001ea58 GetUseSerialIO +8001ea60 __TRK_get_MSR +8001ea68 __TRK_set_MSR +8001ea70 TRKValidMemory32 +8001eb68 TRK_ppc_memcpy +8001ec34 TRKTargetAccessMemory +8001ed84 TRKTargetAccessDefault +8001ee7c TRKTargetAccessFP +8001efb8 TRKTargetAccessExtended1 +8001f11c TRKTargetAccessExtended2 +8001f4bc 0x8001f4bc +8001f574 TRKSwapAndGo +8001f68c TRKTargetInterrupt +8001f6e8 TRKTargetAddStopInfo +8001f81c TRKTargetAddExceptionInfo +8001f8b8 TRKTargetCheckStep +8001f9d4 TRKTargetSingleStep +8001fa58 TRKTargetStepOutOfRange +8001fac8 TRKTargetGetPC +8001fad8 TRKTargetSupportRequest +8001fccc TRKTargetStopped +8001fcdc TRKTargetSetStopped +8001fcec TRKTargetStop +8001fd04 TRKPPCAccessSPR +8001fde0 TRKPPCAccessPairedSingleRegister +8001fe88 ReadFPSCR +8001feac WriteFPSCR +8001fed0 TRKPPCAccessFPRegister +80020098 TRKPPCAccessSpecialReg +80020100 TRKTargetSetInputPendingPtr +80020110 GetThreadInfo +800201a0 TRKAccessFile +800201a8 0x800201a8 +800201b0 0x800201b0 +800201b8 0x800201b8 +800201c0 __sys_free +80020278 __register_fragment +800202ac __unregister_fragment +800202d4 __construct_new_array +800203d8 __partial_array_destructor::__dt +80020494 __construct_array +8002058c __destroy_array +80020604 __destroy_new_array +80020684 __init_cpp_exceptions +800206c0 __fini_cpp_exceptions +800206f4 strlen +80020710 __va_arg +800207d8 __register__global_object +800207f0 __destroy__global_chain +80020838 __register_atexit +80020884 __ptmf_test +800208b4 __ptmf_cmpr +800208f0 __ptmf_scall +80020918 __cvt_fp2unsigned +80020974 __save_fpr +80020998 _save_fpr_23 +800209ac _save_fpr_28 +800209c0 __restore_fpr +800209e4 _rest_fpr_23 +800209f8 _rest_fpr_28 +80020a0c _save_gpr_14 +80020a10 _save_gpr_15 +80020a14 _save_gpr_16 +80020a18 _save_gpr_17 +80020a1c _save_gpr_18 +80020a20 _save_gpr_19 +80020a24 _save_gpr_20 +80020a28 _save_gpr_21 +80020a2c _save_gpr_22 +80020a30 _save_gpr_23 +80020a34 _save_gpr_24 +80020a38 _save_gpr_25 +80020a3c _save_gpr_26 +80020a40 _save_gpr_27 +80020a58 _rest_gpr_14 +80020a5c _rest_gpr_15 +80020a60 _rest_gpr_16 +80020a64 _rest_gpr_17 +80020a68 _rest_gpr_18 +80020a6c _rest_gpr_19 +80020a70 _rest_gpr_20 +80020a74 _rest_gpr_21 +80020a78 _rest_gpr_22 +80020a7c _rest_gpr_23 +80020a80 _rest_gpr_24 +80020a84 _rest_gpr_25 +80020a88 _rest_gpr_26 +80020a8c _rest_gpr_27 +80020aa4 __div2u +80020b90 __div2i +80020cc8 __mod2u +80020dac __mod2i +80020eb8 __shl2i +80020edc __shr2u +80020f00 __cvt_ull_db +80020fa0 __cvt_dbl_ull +80021048 __DBMtrHandler +8002106c __DBIntrHandler +80021090 DBInitComm +800210ec DBInitInterrupts +80021140 DBQueryData +800211e4 DBRead +80021264 DBWrite +80021374 DBOpen +80021378 DBClose +8002137c __EXI2Imm +80021664 __DBEXIInit +80021720 __DBEXIReadReg +80021844 __DBEXIWriteReg +80021948 __DBEXIReadRam +80021a28 __DBEXIWriteRam +80021b10 nw4r::db::DirectPrint_Init +80021bd0 nw4r::db::DirectPrint_IsActive +80021c00 nw4r::db::DirectPrint_EraseXfb +80021d90 nw4r::db::DirectPrint_ChangeXfb +80021dd0 nw4r::db::DirectPrint_StoreCache +80021df0 nw4r::db::DirectPrint_DrawString +80021ee0 nw4r::db::DrawStringToXfb +80022040 nw4r::db::DrawStringLineToXfb +80022120 nw4r::db::DrawCharToXfb +800223e0 nw4r::db::DirectPrint_SetupFB +800225d0 nw4r::db::RemoveConsoleFromList_ +80022680 nw4r::db::Console_Create +80022830 nw4r::db::Console_Destroy +80022860 nw4r::db::DoDrawConsole_ +80022a10 nw4r::db::Console_DrawDirect +80022a90 nw4r::db::PrintToBuffer_ +80022e40 nw4r::db::Console_VFPrintf +80022f20 nw4r::db::Console_Printf +80023040 nw4r::db::Console_GetTotalLines +800230b0 nw4r::db::Exception_Init +800231a0 nw4r::db::ErrorHandler_ +800232e0 nw4r::db::RunThread_ +80023370 nw4r::db::DumpException_ +80023500 nw4r::db::Exception_Printf_ +800235e0 nw4r::db::PrintContext_ +800238e0 nw4r::db::ShowMainInfo_ +80023b20 nw4r::db::ShowGPRMap_ +80023bd0 nw4r::db::ShowFloat_ +80023fe0 nw4r::db::Exception_SetConsole +80024000 nw4r::db::Exception_SetUserCallback +80024020 nw4r::db::DbgPrintBase::GetInstance +80024030 nw4r::db::DbgPrintBase::Initialize +800240f0 nw4r::db::DbgPrintBase::Initialize +800241b0 nw4r::db::DbgPrintBase::SetFont +800241c0 nw4r::db::DbgPrintBase::GetFont +800241d0 nw4r::db::DbgPrintBase::SetTextColor +80024200 nw4r::db::DbgPrintBase::GetTextColor +80024230 nw4r::db::DbgPrintBase::SetFontSize +80024240 nw4r::db::DbgPrintBase::GetFontSize +80024250 nw4r::db::DbgPrintBase::SetVisible +80024260 nw4r::db::DbgPrintBase::IsVisible +80024270 nw4r::db::DbgPrintBase::Registerf +80024380 nw4r::db::DbgPrintBase::Registerf +800244a0 nw4r::db::DbgPrintBase::VRegisterf +80024570 nw4r::db::DbgPrintBase::Register +80024620 nw4r::db::DbgPrintBase::Registf +80024730 nw4r::db::DbgPrintBase::Registf +80024850 nw4r::db::DbgPrintBase::VRegistf +80024920 nw4r::db::DbgPrintBase::Reset +80024930 0x80024930 +800249d0 nw4r::db::DbgPrintBase::Flush +80024b70 nw4r::db::DbgPrintBase::Flush +80024c30 nw4r::db::DbgPrintBase::__ct +80024ca0 nw4r::db::DbgPrintBase::__dt +80024cf0 nw4r::db::DbgPrintBase::Unregister +80024d10 0x80024d10 +80024d50 nw4r::db::DbgPrintBase::SetBuffer +80024d80 nw4r::db::DbgPrintBase::ReleaseBuffer +80024de0 nw4r::db::DbgPrintBase::Operator.new +80024e30 nw4r::db::DbgPrintBase::GetInstance +80024e50 nw4r::db::DbgPrintBase::Initialize +80024f10 nw4r::db::DbgPrintBase::Initialize +80024fd0 nw4r::db::DbgPrintBase::SetFont +80024fe0 nw4r::db::DbgPrintBase::GetFont +80024ff0 nw4r::db::DbgPrintBase::SetTextColor +80025020 nw4r::db::DbgPrintBase::GetTextColor +80025050 nw4r::db::DbgPrintBase::SetFontSize +80025060 nw4r::db::DbgPrintBase::GetFontSize +80025070 nw4r::db::DbgPrintBase::SetVisible +80025080 nw4r::db::DbgPrintBase::IsVisible +80025090 nw4r::db::DbgPrintBase::Registerf +800251a0 nw4r::db::DbgPrintBase::Registerf +800252c0 nw4r::db::DbgPrintBase::VRegisterf +80025390 nw4r::db::DbgPrintBase::Register +80025440 nw4r::db::DbgPrintBase::Registf +80025550 nw4r::db::DbgPrintBase::Registf +80025670 nw4r::db::DbgPrintBase::VRegistf +80025740 nw4r::db::DbgPrintBase::Reset +80025750 0x80025750 +800257f0 nw4r::db::DbgPrintBase::Flush +80025990 nw4r::db::DbgPrintBase::Flush +80025a50 nw4r::db::DbgPrintBase::__ct +80025ac0 nw4r::db::DbgPrintBase::__dt +80025b10 nw4r::db::DbgPrintBase::Unregister +80025b30 0x80025b30 +80025b70 nw4r::db::DbgPrintBase::SetBuffer +80025ba0 nw4r::db::DbgPrintBase::ReleaseBuffer +80025c00 nw4r::db::DbgPrintBase::Operator.new +80025c50 nw4r::db::DbgPrintBase::Operator.delete +80025c60 nw4r::db::Assertion_Printf_ +80025d20 PrintExceptionTrace +80025dd0 nw4r::db::VPanic +80025f10 nw4r_db_Panic +80025fb0 nw4r::db::VWarning +80026160 nw4r::db::WarningAlarmFunc_ +80026180 nw4r::ef::DrawOrder::Draw +80026210 nw4r::ef::DrawOrder::Add +80026290 nw4r::ef::DrawOrder::Remove +800262a0 nw4r::ef::Effect::__ct +80026310 nw4r::ef::Effect::__dt +80026370 nw4r::ef::Effect::Initialize +800264b0 nw4r::ef::Effect::Closing +800264c0 0x800264c0 +800264d0 0x800264d0 +800265e0 nw4r::ef::Effect::CreateEmitter +800266e0 nw4r::ef::Effect::RetireEmitter +80026770 nw4r::ef::Effect::RetireEmitterAll +80026840 nw4r::ef::Effect::RetireParticleAll +800268d0 nw4r::ef::Effect::Calc +80026cc0 nw4r::ef::Effect::Draw +80026cf0 nw4r::ef::Effect::GetRootEmitter +80026d00 nw4r::ef::Effect::GetNumEmitter +80026d10 nw4r::ef::Effect::GetEmitter +80026d20 nw4r::ef::Effect::ForeachParticleManager +80026db0 nw4r::ef::Effect::ForeachEmitterFrom +80026e90 nw4r::ef::Effect::SetRootMtx +80026f00 nw4r::ef::Effect::CreateEmitter +80027000 nw4r::ef::EffectSystem::__dt +80027090 nw4r::ef::EffectSystem::GetInstance +800270a0 nw4r::ef::EffectSystem::Initialize +800271b0 nw4r::ef::ActivityList::__ct +80027200 nw4r::ef::EffectSystem::Closing +80027270 nw4r::ef::EffectSystem::CreateEffect(name) +800272e0 nw4r::ef::EffectSystem::CreateEffect(res) +80027410 nw4r::ef::EffectSystem::RetireEffectAll +80027500 nw4r::ef::EffectSystem::RetireEmitterAll +80027590 nw4r::ef::EffectSystem::RetireParticleAll +80027620 nw4r::ef::EffectSystem::Draw +800276b0 nw4r::ef::EffectSystem::SetProcessCamera +80027740 nw4r::ef::Swap +80027790 nw4r::ef::EffectSystem::SortEffect +80027910 nw4r::ef::EffectSystem::SortEffectOperatorZ +80027a10 __sinit_\ef_effectsystem_cpp +80027b40 nw4r::ef::Emitter::__ct +80027ba0 nw4r::ef::Emitter::__dt +80027be0 nw4r::ef::Emitter::RetireParticleAll +80027c70 nw4r::ef::Emitter::DestroyFunc +80027c80 0x80027c80 +80027d70 nw4r::ef::Emitter::Closing +80027e20 nw4r::ef::Emitter::RetireParticleManagerAll +80027ef0 nw4r::ef::Emitter::InitializeDatas +800281c0 nw4r::ef::Emitter::Initialize +80028330 nw4r::ef::Emitter::CreateEmitter +80028610 nw4r::ef::Emitter::CreateEmitterTmp +80028cf0 nw4r::ef::GetLODratio +80028df0 nw4r::ef::Emitter::Emission +80029240 nw4r::ef::Emitter::CalcEmitter +80029400 nw4r::ef::Emitter::CalcParticle +80029490 nw4r::ef::Emitter::CalcEmission +800295b0 nw4r::ef::Emitter::CalcBillboard +80029790 nw4r::ef::Emitter::RestructMatrix +800299c0 nw4r::ef::Emitter::CalcGlobalMtx +80029b10 nw4r::ef::Emitter::SetMtxDirty +80029c20 nw4r::ef::Emitter::GetNumParticleManager +80029c30 nw4r::ef::Emitter::GetParticleManager +80029c40 nw4r::ef::ForeachParticleManagerSub +80029c90 nw4r::ef::Emitter::ForeachParticleManager +80029d80 nw4r::ef::AnimCurveExecuteU8 +8002b060 nw4r::ef::AnimCurveExecuteF32 +8002c010 nw4r::ef::AnimCurveExecuteRotate +8002d0c0 nw4r::ef::AnimCurveExecuteTexture +8002d690 nw4r::ef::CreateChild +8002d800 nw4r::ef::AnimCurveExecuteChild +8002e5c0 nw4r::ef::AnimBakedExecuteU8 +8002e910 nw4r::ef::AnimBakedExecuteF32 +8002ec60 nw4r::ef::GetTypePositionSphere +8002ed80 nw4r::ef::GetTypePositionCube +8002ee60 nw4r::ef::GetTypePositionCylinder +8002ef30 nw4r::ef::GetTypePositionCircle +8002f040 nw4r::ef::GetTypePositionRectangle +8002f130 nw4r::ef::GetTypePositionPlane +8002f1e0 nw4r::ef::CrossCheckPlane +8002f680 nw4r::ef::CrossCheckRectangle +8002fc20 nw4r::ef::CrossCheckCircle +800301b0 nw4r::ef::CrossCheckSphere +800307f0 nw4r::ef::CrossCheckCylinder +80030fe0 nw4r::ef::CrossCheckCube +80031720 nw4r::ef::CrossCheck +80031b40 nw4r::ef::CalcPostField +800323a0 nw4r::ef::Particle::__ct +800323b0 nw4r::ef::Particle::__dt +800323f0 nw4r::ef::Particle::SendClosing +80032400 nw4r::ef::Particle::DestroyFunc +80032410 nw4r::ef::ParticleParameter::Initialize +80032730 nw4r::ef::Particle::Initialize +80033150 nw4r::ef::Particle::GetAlphaFlick +80033390 nw4r::ef::ParticleManager::__ct +800333f0 nw4r::ef::ParticleManager::SendClosing +80033400 nw4r::ef::ParticleManager::DestroyFunc +80033410 nw4r::ef::ParticleManager::Closing +800334a0 nw4r::ef::ParticleManager::RetireParticleAll +80033550 nw4r::ef::ParticleManager::Initialize +800336a0 nw4r::ef::ParticleManager::__dt +800336e0 nw4r::ef::ParticleManager::CreateParticle +80033810 nw4r::ef::ParticleManager::Calc +80034ee0 nw4r::ef::ParticleManager::Draw +800351c0 nw4r::ef::ParticleManager::CalcGlobalMtx +800352a0 nw4r::ef::ParticleManager::BeginCalc +80035310 nw4r::ef::ParticleManager::EndCalc +80035360 nw4r::ef::ParticleManager::BeginDraw +80035460 nw4r::ef::ParticleManager::EndDraw +80035470 nw4r::ef::ParticleManager::Draw_ModifyColor +80035890 __sinit_\ef_particlemanager_cpp +800358a0 nw4r::ef::Resource::GetInstance +800358b0 nw4r::ef::BreffRelocate +80035a20 nw4r::ef::BreffSearchName +80035ae0 nw4r::ef::BreffIndexOf +80035b80 nw4r::ef::BreftRelocate +80035c10 nw4r::ef::BreftSearchName +80035cd0 nw4r::ef::Resource::Add +80035d50 nw4r::ef::Resource::FindEmitter +80035e10 nw4r::ef::Resource::FindEmitter +80035ec0 nw4r::ef::Resource::AddTexture +80035f40 nw4r::ef::Resource::RelocateCurveTexture +80036060 nw4r::ef::Resource::RelocateCurveChild +80036160 nw4r::ef::Resource::RelocateCommand +800363a0 nw4r::ef::Resource::RemoveEffectProject +80036440 nw4r::ef::Resource::RemoveTextureProject +800364e0 __sinit_\ef_resource_cpp +80036530 nw4r::ef::UtlistToArray +800365c0 nw4r::ef::GetDirMtxY +800366d0 nw4r::ef::MtxGetRotationMtx +800367f0 nw4r::ef::MtxGetRotation +80036960 nw4r::ef::MtxGetTranslate +80036980 nw4r::ef::MtxGetScale +80036e60 nw4r::ef::Normalize +80036ed0 nw4r::ef::_PSSinCosRad +80036f50 nw4r::ef::PSSinCosRad +80036fd0 nw4r::ef::Rotation2VecY +80037120 nw4r::ef::PSMTX34RotXYZRad +800372a0 nw4r::ef::MTX34ScaleNonZero +80037320 nw4r::ef::MTX34ScaleNonZero +800373b0 nw4r::ef::MTX34ScaleInv +80037460 nw4r::ef::MTXColLen +800374c0 nw4r::ef::HandleBase::__ct +800374d0 nw4r::ef::HandleBase::Operator=(HandleBase) +800374f0 nw4r::ef::HandleBase::Operator=(LinkedObject) +80037520 nw4r::ef::HandleBase::IsValid +80037550 nw4r::ef::HandleBase::GetPtr +80037590 nw4r::ef::EmitterForm::CalcVelocity +80037a60 nw4r::ef::EmitterForm::CalcLife +80037b40 nw4r::ef::CreationQueue::__ct +80037b50 nw4r::ef::CreationQueue::AddParticleCreation +80037cd0 nw4r::ef::CreationQueue::AddEmitterCreation +80037e50 nw4r::ef::CreationQueue::Execute +80037f90 nw4r::ef::EmitFormBuilder::Create +80038010 __sinit_\ef_emform_cpp +80038070 nw4r::ef::EmitterFormPoint::Emission +800383c0 nw4r::ef::EmitterFormLine::Emission +80038700 nw4r::ef::EmitterFormDisc::Emission +80038c30 nw4r::ef::EmitterFormSphere::Emission +80039490 nw4r::ef::EmitterFormCylinder::EmissionSub +800398f0 nw4r::ef::EmitterFormCylinder::Emission +80039c40 nw4r::ef::EmitterFormTorus::Emission +8003a280 nw4r::ef::EmitterFormCube::EmissionSub +8003a5c0 nw4r::ef::EmitterFormCube::Emission +8003be90 nw4r::ef::DrawStrategyBuilder::Create +8003c010 nw4r::ef::DrawStrategyImpl::__ct +8003c320 nw4r::ef::DrawStrategyImpl::Initialize +8003c400 nw4r::ef::DrawStrategyImpl::_InitTev +8003c6f0 nw4r::ef::DrawStrategyImpl::_InitColor +8003cac0 nw4r::ef::DrawStrategyImpl::SetupGP +8003cf60 nw4r::ef::DrawStrategyImpl::_SetupTevReg +8003d790 nw4r::ef::DrawStrategyImpl::_SetupTexture +8003de00 nw4r::ef::DrawStrategyImpl::GetGetFirstDrawParticle +8003de20 nw4r::ef::DrawStrategyImpl::GetGetNextDrawParticle +8003de40 nw4r::ef::DrawStrategyImpl::GetFirstDrawParticle_EldersFirst +8003de70 nw4r::ef::DrawStrategyImpl::GetFirstDrawParticle_YoungersFirst +8003dec0 nw4r::ef::DrawStrategyImpl::GetNextDrawParticle_EldersFirst +8003def0 nw4r::ef::DrawStrategyImpl::GetNextDrawParticle_YoungersFirst +8003df20 nw4r::ef::DrawStrategyImpl::AheadContext::__ct +8003e140 nw4r::ef::DrawStrategyImpl::__dt +8003e180 __sinit_\ef_drawstrategyimpl_cpp +8003e210 nw4r::ef::DrawBillboardStrategy::__ct +8003e250 nw4r::ef::DrawBillboardStrategy::Draw +8003e290 nw4r::ef::DrawBillboardStrategy::DrawNormalBillboard +8003ed50 nw4r::ef::DrawBillboardStrategy::DrawYBillboard +8003f680 nw4r::ef::DrawBillboardStrategy::DrawDirectionalB +8003ff10 nw4r::ef::DrawBillboardStrategy::InitGraphics +8003ffe0 nw4r::ef::DrawBillboardStrategy::GetCalcAheadFunc +80040060 nw4r::ef::DrawStrategyImpl::CalcAhead_Speed +80040140 nw4r::ef::DrawStrategyImpl::CalcAhead_EmitterCent +80040200 nw4r::ef::DrawStrategyImpl::CalcAhead_EmitterDesi +80040220 nw4r::ef::DrawStrategyImpl::CalcAhead_Particle +80040340 nw4r::ef::DrawStrategyImpl::CalcAhead_ParticleBot +800405b0 nw4r::ef::DrawBillboardStrategy::__dt +800405f0 nw4r::ef::DrawDirectionalStrategy::DrawDirectiona +80040630 nw4r::ef::DrawQuad +80040770 nw4r::math::VEC3::__ct +80040780 nw4r::math::VEC3Transform +800407c0 0x800407c0 +800407d0 nw4r::ef::DrawQuad +80040970 nw4r::ef::DrawDirectionalStrategy::Draw +80040a80 nw4r::ef::EmitterResource::GetEmitterDrawSetting +80040a90 nw4r::ef::DrawDirectionalStrategy::DrawDirectiona +80041810 nw4r::math::MTX34::__ct +80041820 nw4r::ef::DrawInfo::GetViewMtxCooked +800419f0 nw4r::math::MTX34Mult +80041a30 nw4r::math::VEC3::Operator= +80041a50 nw4r::math::VEC3::__ct +80041a60 nw4r::ef::DrawStrategyImpl::Normalize +80041ad0 nw4r::math::VEC3Dot +80041af0 nw4r::ef::DrawStrategyImpl::GetYoungestParticle +80041b00 nw4r::ef::DrawStrategyImpl::GetElderParticle +80041b10 nw4r::ef::Particle::Draw_GetSizeX +80041b90 nw4r::ef::Particle::Draw_GetSizeY +80041c70 nw4r::ef::Particle::GetMoveDir +80041cc0 nw4r::math::FSqrt +80041d10 nw4r::ef::CalcRotate +80042080 nw4r::math::MTX34::__ct +800420d0 nw4r::ef::CalcLocalTransform +800422d0 nw4r::math::VEC3Cross +80042310 nw4r::ef::DrawDirectionalStrategy::DrawDirectiona +80042950 nw4r::ef::DrawDirectionalStrategy::InitGraphics +80042a10 nw4r::ef::DrawDirectionalStrategy::GetCalcAheadFu +80042aa0 nw4r::ef::DrawStrategyImpl::CalcAhead_NoDesign +80042ad0 nw4r::ef::DrawDirectionalStrategy::~DrawDirection +80042b10 nw4r::ef::DrawFreeStrategy::__ct +80042b50 nw4r::ef::DrawQuad +80042c90 nw4r::ef::DrawFreeStrategy::Draw +800435d0 nw4r::ef::DrawFreeStrategy::__dt +80043610 nw4r::ef::DrawLineStrategy::__ct +80043650 nw4r::ef::DrawLineStrategy::Draw +80043cd0 nw4r::ef::DrawLineStrategy::__dt +80043d10 nw4r::ef::DrawPointStrategy::__ct +80043d50 nw4r::ef::DrawPointStrategy::Draw +800441f0 nw4r::ef::DrawPointStrategy::__dt +80044230 nw4r::ef::DrawStripeStrategy::__ct +80044270 nw4r::ef::DrawStripeStrategy::DrawStripe +800445b0 nw4r::ef::DrawStrategyImpl::GetNumDrawParticle +800445c0 nw4r::ef::DrawStripeStrategy::GetStripeTexmapType +800445d0 nw4r::math::FInv +800445f0 nw4r::ef::DrawStripeStrategy::DrawParticle +80044a90 GXEnd +80044aa0 nw4r::ef::DrawStripeStrategy::CalcVertexTube +80044fa0 nw4r::ef::DrawStripeStrategy::DrawTubeSegment +80045380 nw4r::ef::DrawStripeStrategy::DrawStripeTube_Conn +80045640 nw4r::ef::DrawStripeStrategy::DrawStripeTube_Conn +80045980 nw4r::ef::DrawStripeStrategy::DrawStripeTube_Conn +80045d40 nw4r::ef::DrawStripeStrategy::DrawStripeTube +80045f30 nw4r::ef::DrawStripeStrategy::Draw +800467a0 nw4r::ef::DrawStripeStrategy::GetInitialPrevAxis +800468f0 nw4r::ef::DrawStripeStrategy::GetCalcAheadFunc +800469c0 nw4r::ef::DrawStripeStrategy::CalcAhead_Particle_ +80046ae0 nw4r::ef::DrawStripeStrategy::CalcAhead_ParticleB +80046d50 nw4r::ef::DrawStripeStrategy::CalcAhead_ParticleB +80047010 nw4r::ef::DrawStripeStrategy::CalcAhead_ParticleB +80047240 nw4r::ef::DrawStripeStrategy::__dt +80047280 nw4r::ef::DrawSmoothStripeStrategy::DrawSmoothStr +800472c0 nw4r::ef::DrawSmoothStripeStrategy::CalcVertex +800476b0 nw4r::ef::DrawSmoothStripeStrategy::CalcVertexTub +80047bb0 nw4r::ef::DrawSmoothStripeStrategy::DrawSection_B +80047e80 nw4r::math::VEC3::Operator+ +80047eb0 nw4r::ef::DrawSmoothStripeStrategy::DrawSectionEn +800480d0 nw4r::ef::DrawSmoothStripeStrategy::DrawSectionTu +80048b90 GXEnd +80048ba0 nw4r::ef::DrawSmoothStripeStrategy::DrawSmoothStr +80048ef0 nw4r::ef::DrawSmoothStripeStrategy::GetDrawOrder +80048f00 nw4r::ef::DrawSmoothStripeStrategy::GetStripeTexm +80048f10 nw4r::ef::DrawSmoothStripeStrategy::Vertex::Verte +80048f20 nw4r::ef::DrawSmoothStripeStrategy::DrawSmoothStr +80049340 nw4r::ef::DrawSmoothStripeStrategy::DrawSmoothStr +800497e0 nw4r::ef::DrawStrategyImpl::GetYoungestDrawPartic +80049830 nw4r::math::VEC3::Operator- +80049860 nw4r::math::VEC3::Operator+= +80049890 nw4r::ef::DrawSmoothStripeStrategy::Vertex::Verte +800498d0 nw4r::ef::DrawSmoothStripeStrategy::Vertex::Opera +80049910 nw4r::ef::DrawSmoothStripeStrategy::DrawSmoothStr +80049c10 nw4r::ef::DrawSmoothStripeStrategy::DrawSmoothStr +80049fc0 nw4r::ef::DrawSmoothStripeStrategy::DrawSmoothStr +8004a540 nw4r::ef::DrawSmoothStripeStrategy::DrawSmoothStr +8004a750 nw4r::ef::DrawSmoothStripeStrategy::Draw +8004b100 nw4r::ef::DrawSmoothStripeStrategy::GetInitialPre +8004b250 nw4r::ef::DrawSmoothStripeStrategy::GetCalcAheadF +8004b320 nw4r::ef::DrawSmoothStripeStrategy::CalcAhead_Par +8004b440 nw4r::ef::DrawSmoothStripeStrategy::CalcAhead_Par +8004b6b0 nw4r::ef::DrawSmoothStripeStrategy::CalcAhead_Par +8004b970 nw4r::ef::DrawSmoothStripeStrategy::CalcAhead_Par +8004bba0 nw4r::ef::DrawSmoothStripeStrategy::~DrawSmoothSt +8004bbe0 nw4r::ef::ResEmitter::GetEmitTrack +8004bc10 nw4r::ef::ResAnimCurve::SetStop +8004bc40 nw4r::g3d::ResName::Operator== +8004bc90 nw4r::g3d::detail::ResWriteBPCmd +8004bcc0 nw4r::g3d::detail::ResWriteBPCmd +8004bd20 nw4r::g3d::detail::ResWriteCPCmd +8004bd50 nw4r::g3d::detail::ResWriteXFCmd +8004bd90 nw4r::g3d::detail::ResWriteSSMask +8004bdf0 nw4r::g3d::ResDic::Get +8004bed0 nw4r::g3d::ResDic::Get +8004bfb0 ResDic_operator[] +8004c030 ResDic_operator[] +8004c0a0 nw4r::g3d::ResDic::GetIndex +8004c130 nw4r::g3d::ResDic::GetIndex +8004c1a0 nw4r::g3d::ResFile::GetResMdl(name) +8004c210 nw4r::g3d::ResFile::GetResMdl(idx) +8004c2b0 nw4r::g3d::ResFile::GetResMdl(u32 idx) +8004c350 nw4r::g3d::ResFile::GetResMdlNumEntries +8004c3c0 nw4r::g3d::ResFile::GetResPltt +8004c440 nw4r::g3d::ResFile::GetResTex +8004c4b0 nw4r::g3d::ResFile::GetResTex +8004c530 nw4r::g3d::ResFile::GetResTex(idx) +8004c5d0 nw4r::g3d::ResFile::GetResTex(u32 idx) +8004c670 nw4r::g3d::ResFile::GetResTexNumEntries +8004c6e0 nw4r::g3d::ResFile::GetResAnmChr(name) +8004c750 nw4r::g3d::ResFile::GetResAnmChr(ResName) +8004c7f0 nw4r::g3d::ResFile::GetResAnmChrNumEntries +8004c860 nw4r::g3d::ResFile::GetResAnmClr(name) +8004c8d0 nw4r::g3d::ResFile::GetResAnmClr(ResName) +8004c970 nw4r::g3d::ResFile::GetResAnmClrNumEntries +8004c9e0 nw4r::g3d::ResFile::GetResAnmTexPat(name) +8004ca50 nw4r::g3d::ResFile::GetResAnmTexPat(ResName) +8004caf0 nw4r::g3d::ResFile::GetResAnmTexPatNumEntries +8004cb60 nw4r::g3d::ResFile::GetResAnmTexSrt(name) +8004cbd0 nw4r::g3d::ResFile::GetResAnmTexSrt(ResName) +8004cc70 nw4r::g3d::ResFile::GetResAnmTexSrtNumEntries +8004cce0 nw4r::g3d::ResFile::GetResAnmShp(name) +8004cd50 nw4r::g3d::ResFile::GetResAnmShp(ResName) +8004cdf0 nw4r::g3d::ResFile::GetResAnmShpNumEntries +8004ce60 nw4r::g3d::ResFile::GetResAnmScn +8004ced0 nw4r::g3d::ResFile::HasResMdl +8004cf20 nw4r::g3d::ResFile::HasResAnmChr +8004cf70 nw4r::g3d::ResFile::HasResAnmVis +8004cfc0 nw4r::g3d::ResFile::HasResAnmClr +8004d010 nw4r::g3d::ResFile::HasResAnmTexPat +8004d060 nw4r::g3d::ResFile::HasResAnmTexSrt +8004d0b0 nw4r::g3d::ResFile::HasResAnmShp +8004d100 nw4r::g3d::ResFile::HasResAnmScn +8004d150 nw4r::g3d::ResFile::Bind +8004d390 nw4r::g3d::ResFile::Release +8004d590 nw4r::g3d::ResFile::Init +8004d860 nw4r::g3d::ResFile::CheckRevision +8004e1b0 nw4r::g3d::ResMdl::GetResByteCode +8004e200 nw4r::g3d::ResMdl::GetResNode(name) +8004e250 nw4r::g3d::ResMdl::GetResNode(ResName) +8004e2a0 nw4r::g3d::ResMdl::GetResNode(idx) +8004e300 nw4r::g3d::ResMdl::GetResNode(u32 idx) +8004e360 nw4r::g3d::ResMdl::GetResNodeNumEntries +8004e3a0 nw4r::g3d::ResMdl::GetResVtxPos +8004e3f0 nw4r::g3d::ResMdl::GetResVtxPos +8004e450 nw4r::g3d::ResMdl::GetResVtxPos +8004e4b0 nw4r::g3d::ResMdl::GetResVtxPosNumEntries +8004e4f0 nw4r::g3d::ResMdl::GetResVtxNrm +8004e540 nw4r::g3d::ResMdl::GetResVtxNrm +8004e5a0 nw4r::g3d::ResMdl::GetResVtxNrm +8004e600 nw4r::g3d::ResMdl::GetResVtxNrmNumEntries +8004e640 nw4r::g3d::ResMdl::GetResVtxClr +8004e690 nw4r::g3d::ResMdl::GetResVtxClr +8004e6f0 nw4r::g3d::ResMdl::GetResVtxClr +8004e750 nw4r::g3d::ResMdl::GetResVtxClrNumEntries +8004e790 nw4r::g3d::ResMdl::GetResVtxTexCoord +8004e7f0 nw4r::g3d::ResMdl::GetResVtxFurPos +8004e850 nw4r::g3d::ResMdl::GetResMat(name) +8004e8a0 nw4r::g3d::ResMdl::GetResMat(resname) +8004e8f0 nw4r::g3d::ResMdl::GetResMat(idx) +8004e950 nw4r::g3d::ResMdl::GetResMat(u32 idx) +8004e9b0 nw4r::g3d::ResMdl::GetResMatNumEntries +8004e9f0 nw4r::g3d::ResMdl::GetResShp +8004ea50 nw4r::g3d::ResMdl::GetResShp +8004eab0 nw4r::g3d::ResMdl::GetResShpNumEntries +8004eaf0 nw4r::g3d::ResMdl::GetResTexPlttInfoOffsetFromTexName +8004eb50 nw4r::g3d::ResMdl::GetResTexPlttInfoOffsetFromTexNameNumEntries +8004eb90 nw4r::g3d::ResMdl::Bind +8004eca0 nw4r::g3d::ResMdl::Release +8004ed90 nw4r::g3d::ResMdl::Init +8004f330 nw4r::g3d::ResShp::GetResVtxPos +8004f380 nw4r::g3d::ResShp::GetResVtxNrm +8004f3e0 nw4r::g3d::ResShp::GetResVtxClr +8004f450 nw4r::g3d::ResShp::GetResVtxFurPos +8004f4b0 nw4r::g3d::ResShp::Init +8004f840 nw4r::g3d::ResShp::CallPrePrimitiveDisplayList +8004f920 0x8004f920 +8004f990 nw4r::g3d::ResTev::GXSetTevSwapModeTable +8004fa40 nw4r::g3d::ResTev::GXSetTevSwapMode +8004faa0 nw4r::g3d::ResTev::GXSetTevAlphaIn +8004fb30 nw4r::g3d::ResTev::GXSetTevAlphaOp +8004fbe0 nw4r::g3d::ResTev::GXSetTevKColorSel +8004fc70 nw4r::g3d::ResTev::GXSetTevKAlphaSel +8004fd00 nw4r::g3d::ResTev::GXGetTevOrder +8004fdd0 nw4r::g3d::ResTev::GXSetTevOrder +8004fef0 nw4r::g3d::ResTev::GXGetTevColorOp +8004ffd0 nw4r::g3d::ResTev::GXSetTevColorIn +80050060 nw4r::g3d::ResTev::GXSetTevColorOp +80050110 nw4r::g3d::ResTev::GXGetIndTexOrder +800501b0 nw4r::g3d::ResTev::SetNumTevStages +800502a0 nw4r::g3d::ResTev::CallDisplayList +80050300 nw4r::g3d::ResTev::CopyTo +80050370 nw4r::g3d::ResTev::DCStore +80050390 nw4r::g3d::ResMat::GetParent +800503b0 nw4r::g3d::ResMatPix::DCStore +800503d0 nw4r::g3d::ResMatTevColor::DCStore +800503f0 nw4r::g3d::ResMatIndMtxAndScale::DCStore +80050410 nw4r::g3d::ResMatTexCoordGen::DCStore +80050430 0x80050430 +80050460 0x80050460 +80050490 nw4r::g3d::ResMatPix::CopyTo +800504d0 nw4r::g3d::ResMatTevColor::CopyTo +80050510 nw4r::g3d::ResMatIndMtxAndScale::CopyTo +80050550 nw4r::g3d::ResMatTexCoordGen::CopyTo +80050590 nw4r::g3d::ResTexObj::GetTexObj +800505c0 nw4r::g3d::ResTexObj::GetTexObj +800505f0 nw4r::g3d::ResTexObj::IsValidTexObj +80050630 SetTextureUsed +80050660 nw4r::g3d::ResTexObj::CopyTo +800506f0 nw4r::g3d::ResTlutObj::GetTlut +80050720 nw4r::g3d::ResTlutObj::GetTlut +80050750 nw4r::g3d::ResTlutObj::IsValidTlut +80050790 nw4r::g3d::ResTlutObj::CopyTo +80050820 nw4r::g3d::ResTexSrt::CopyTo +80050900 0x80050900 +80050980 0x80050980 +800509d0 0x800509d0 +80050a50 nw4r::g3d::ResGenMode::GXSetNumTexGens +80050a70 nw4r::g3d::ResGenMode::GXSetNumTexStages +80050a90 nw4r::g3d::ResGenMode::GXSetCullMode +80050ab0 nw4r::g3d::ResGenMode::CopyTo +80050af0 nw4r::g3d::ResMatMisc::GXGetZCompLoc +80050b10 nw4r::g3d::ResMatMisc::SetLightSetIdx +80050b40 nw4r::g3d::ResMatMisc::GetLightSetIdx +80050b60 nw4r::g3d::ResMatMisc::GetFogIdx +80050b80 nw4r::g3d::ResMatMisc::GetIndirectTexMtxCalcMetho +80050bd0 nw4r::g3d::ResMatMisc::CopyTo +80050c40 nw4r::g3d::ResMatFur::GetLyrRate +80050d00 nw4r::g3d::ResMatPix::GXSetZMode +80050d20 nw4r::g3d::ResMatPix::GXSetDstAlpha +80050d40 nw4r::g3d::ResMatTevColor::GXGetTevColor +80050e00 nw4r::g3d::ResMatTevColor::GXSetTevColor +80050ea0 nw4r::g3d::ResMatTevColor::GXGetTevKColor +80050f60 nw4r::g3d::ResMatTevColor::GXSetTevKColor +80050ff0 nw4r::g3d::ResMatIndMtxAndScale::CallDisplayList +80051030 nw4r::g3d::ResMatIndMtxAndScale::GXGetIndTexMtx +800512f0 nw4r::g3d::ResMatIndMtxAndScale::GXGetIndTexMtx +800514e0 nw4r::g3d::ResMatIndMtxAndScale::GXSetIndTexMtx +80051650 nw4r::g3d::ResMatChan::GXGetChanMatColor +80051690 nw4r::g3d::ResMatChan::GXGetChanCtrl +80051750 nw4r::g3d::ResMatChan::CopyTo +800517b0 nw4r::g3d::ResMatTexCoordGen::CallDisplayList +80051880 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2 +80051a30 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2 +80051a94 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_switch +80051a98 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_0 +80051aa4 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_1 +80051ab0 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_2 +80051abc nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_3 +80051ac8 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_13 +80051ad0 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_14 +80051ad8 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_4 +80051ae0 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_5 +80051ae8 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_6 +80051af0 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_7 +80051af8 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_8 +80051b00 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_9 +80051b08 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_a +80051b10 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_b +80051b18 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_c +80051b20 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_d +80051b28 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_e +80051b30 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_f +80051b38 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_10 +80051b40 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_11 +80051b48 nw4r::g3d::ResMatTexCoordGen::GXGetTexCoordGen2_caseD_12 +80051c30 nw4r::g3d::ResMat::Bind +80051d00 nw4r::g3d::ResMat::Release +80051da0 nw4r::g3d::ResMat::ForceBindTex +80051ff0 nw4r::g3d::ResMat::ReleaseTex +800520f0 nw4r::g3d::ResMat::Init +80052120 nw4r::g3d::ResMat::GetResTev +80052140 nw4r::g3d::ResMat::GetResMatFur +80052160 nw4r::g3d::ResTexPlttInfo::Bind +80052420 nw4r::g3d::ResVtxPos::SetArray +80052460 nw4r::g3d::ResVtxPos::GetArray +800524a0 nw4r::g3d::ResVtxPos::CopyTo +80052500 0x80052500 +80052540 0x80052540 +80052580 nw4r::g3d::ResVtxNrm::CopyTo +800525e0 0x800525e0 +80052620 nw4r::g3d::ResVtxClr::GetArray +80052660 nw4r::g3d::ResVtxClr::CopyTo +800526c0 0x800526c0 +80052700 0x80052700 +80052780 nw4r::g3d::ResVtxPos::DCStore +800527a0 nw4r::g3d::ResVtxNrm::DCStore +800527c0 nw4r::g3d::ResVtxClr::DCStore +800527e0 nw4r::g3d::ResVtxTexCoord::DCStore +80052800 nw4r::g3d::ResVtxFurVec::DCStore +80052820 nw4r::g3d::ResVtxFurPos::DCStore +80052840 0x80052840 +80052860 0x80052860 +80052890 nw4r::g3d::ResTex::GetTexObjParam +80052950 nw4r::g3d::ResTex::GetTexObjCIParam +80052a10 0x80052a10 +80052a40 nw4r::g3d::ResTex::Init +80052a50 nw4r::g3d::ResNode::PatchChrAnmResult +80052bf0 nw4r::g3d::ResNode::CalcChrAnmResult +80052d60 nw4r::g3d::ResNode::SetScale +80052e10 nw4r::g3d::ResNode::SetTranslate +80052ea0 nw4r::g3d::ResNode::SetRotate +80052f30 nw4r::g3d::detail::GetResKeyFrameAnmResult +80053070 nw4r::g3d::detail::GetResColorAnmResult +80053180 nw4r::g3d::ResAnmClr::GetAnmResult +800532f0 nw4r::g3d::@unnamed@g3d_resanmtexpat_cpp@::Search +800533b0 nw4r::g3d::ResAnmTexPat::GetAnmResult +80053530 nw4r::g3d::ResAnmTexPat::Bind +800536a0 nw4r::g3d::ResAnmTexPat::Release +80053840 0x80053840 +80053c60 0x80053c60 +80053f10 0x80053f10 +80054050 0x80054050 +800541d0 0x800541d0 +800543c0 0x800543c0 +80054e30 0x80054e30 +80055090 nw4r::g3d::ResAnmChr::GetAnmResult_ +800550b0 nw4r::g3d::ResAnmChr::GetAnmResult_T +80055140 nw4r::g3d::ResAnmChr::GetAnmResult_R +800551b0 nw4r::g3d::ResAnmChr::GetAnmResult_S +800551f0 nw4r::g3d::ResAnmChr::GetAnmResult_RT +800552a0 nw4r::g3d::ResAnmChr::GetAnmResult_SR +80055340 nw4r::g3d::ResAnmChr::GetAnmResult_ST +800553e0 nw4r::g3d::ResAnmChr::GetAnmResult_SRT +800554a0 nw4r::g3d::ResAnmChr::GetAnmResult +80055520 nw4r::g3d::ChrAnmResult::GetScale +80055560 nw4r::g3d::ChrAnmResult::GetRotTrans +80055610 nw4r::g3d::ChrAnmResult::SetRotTrans +800557a0 nw4r::g3d::ResLightSet::Bind +80055910 nw4r::g3d::ResAnmAmbLight::GetAnmResult +800559e0 0x800559e0 +80055dd0 0x80055dd0 +80055f30 nw4r::g3d::ResAnmCamera::GetAnmResult +80056240 nw4r::g3d::ResAnmScn::HasResAnmAmbLight +800562a0 nw4r::g3d::ResAnmScn::HasResAnmLight +80056300 nw4r::g3d::ResAnmScn::GetResLightSetNumEntries +80056380 nw4r::g3d::ResAnmScn::GetResAnmAmbLight(ResName) +80056410 nw4r::g3d::ResAnmScn::GetResAnmAmbLight(idx) +800564c0 nw4r::g3d::ResAnmScn::GetResAnmAmbLightNumEntries +80056540 nw4r::g3d::ResAnmScn::GetResAnmLight(ResName) +800565d0 nw4r::g3d::ResAnmScn::GetResAnmLight(idx) +80056680 nw4r::g3d::ResAnmScn::GetResAnmLightNumEntries +80056700 nw4r::g3d::ResAnmScn::GetResAnmFog +800567b0 nw4r::g3d::ResAnmScn::GetResAnmFogNumEntries +80056830 nw4r::g3d::ResAnmScn::GetResAnmCamera +800568e0 nw4r::g3d::ResAnmScn::GetResAnmCameraNumEntries +80056960 nw4r::g3d::ResAnmScn::GetResLightSetByRefNumber(u32) +800569b0 nw4r::g3d::ResAnmScn::GetResLightSetByRefNumber(int) +80056a00 nw4r::g3d::ResAnmScn::GetResAnmAmbLightByRefNumber +80056a50 nw4r::g3d::ResAnmScn::GetResAnmLightByRefNumber +80056aa0 nw4r::g3d::ResAnmScn::GetResAnmFogByRefNumber +80056af0 nw4r::g3d::ResAnmScn:GetResAnmCameraByRefNumber(u32) +80056b40 nw4r::g3d::ResAnmScn:GetResAnmCameraByRefNumber(int) +80056b90 nw4r::g3d::ResAnmScn::Bind +80056d00 0x80056d00 +80056e70 nw4r::g3d::ApplyVisAnmResult +80056f30 nw4r::g3d::ApplyVisAnmResult +80056fc0 0x80056fc0 +80056fe0 0x80056fe0 +80057020 0x80057020 +80057030 0x80057030 +80057040 0x80057040 +80057050 0x80057050 +80057090 0x80057090 +80057100 0x80057100 +800571f0 0x800571f0 +80057310 0x80057310 +80057370 0x80057370 +800573f0 0x800573f0 +80057480 0x80057480 +800574e0 0x800574e0 +80057570 0x80057570 +800575d0 0x800575d0 +800576d0 0x800576d0 +80057790 0x80057790 +80057810 0x80057810 +80057950 0x80057950 +80057a00 0x80057a00 +80057bf0 0x80057bf0 +80057cb0 0x80057cb0 +80057cc0 0x80057cc0 +80057d80 0x80057d80 +80057d90 0x80057d90 +80057e70 0x80057e70 +80057f70 0x80057f70 +80057ff0 0x80057ff0 +80058040 nw4r::g3d::ApplyClrAnmResult +80058500 0x80058500 +80058570 0x80058570 +800585c0 0x800585c0 +800585f0 0x800585f0 +80058600 0x80058600 +80058650 0x80058650 +800586d0 0x800586d0 +80058740 0x80058740 +80058770 0x80058770 +80058780 0x80058780 +800587f0 0x800587f0 +80058820 0x80058820 +80058830 0x80058830 +80058860 0x80058860 +80058870 0x80058870 +80058890 nw4r::g3d::AnmObjTexPat::Release +800588d0 nw4r::g3d::AnmObjTexPat::Attach +800588e0 nw4r::g3d::AnmObjTexPat::Detach +800588f0 nw4r::g3d::AnmObjTexPat::DetachAll +80058900 nw4r::g3d::AnmObjTexPat::__dt +80058940 nw4r::g3d::AnmObjTexPatNode::__dt +800589b0 nw4r::g3d::AnmObjTexPatNode::Attach +80058aa0 nw4r::g3d::AnmObjTexPatNode::Detach +80058bc0 nw4r::g3d::AnmObjTexPatNode::DetachAll +80058c20 nw4r::g3d::AnmObjTexPatNode::UpdateFrame +80058ca0 nw4r::g3d::AnmObjTexPatNode::SetFrame +80058d30 nw4r::g3d::AnmObjTexPatNode::GetFrame +80058d90 nw4r::g3d::AnmObjTexPatNode::SetUpdateRate +80058e20 nw4r::g3d::AnmObjTexPatNode::GetUpdateRate +80058e80 nw4r::g3d::AnmObjTexPatNode::Bind +80058f80 nw4r::g3d::AnmObjTexPatNode::Release +80059040 nw4r::g3d::AnmObjTexPatNode::G3dProc +800590c0 nw4r::g3d::AnmObjTexPatOverride::Construct +80059200 nw4r::g3d::AnmObjTexPatOverride::GetResult +800592c0 nw4r::g3d::AnmObjTexPatRes::Construct +800594b0 nw4r::g3d::AnmObjTexPatRes::SetFrame +80059570 nw4r::g3d::AnmObjTexPatRes::GetFrame +80059580 nw4r::g3d::AnmObjTexPatRes::SetUpdateRate +80059640 nw4r::g3d::AnmObjTexPatRes::GetUpdateRate +80059650 nw4r::g3d::AnmObjTexPatRes::UpdateFrame +80059730 nw4r::g3d::AnmObjTexPatRes::Bind +80059830 nw4r::g3d::AnmObjTexPatRes::GetResult +800598b0 nw4r::g3d::AnmObjTexPatRes::G3dProc +80059900 nw4r::g3d::ApplyTexPatAnmResult +80059b00 nw4r::g3d::AnmObjTexPatRes::IsDerivedFrom +80059b70 nw4r::g3d::AnmObjTexPat::IsDerivedFrom +80059bc0 nw4r::g3d::AnmObjTexPatRes::GetTypeName +80059bf0 nw4r::g3d::AnmObjTexPatRes::GetTypeObj +80059c00 nw4r::g3d::AnmObjTexPatRes::__dt +80059c50 nw4r::g3d::AnmObjTexPatOverride::IsDerivedFrom +80059cd0 nw4r::g3d::AnmObjTexPatNode::IsDerivedFrom +80059d40 nw4r::g3d::AnmObjTexPatOverride::GetTypeName +80059d70 nw4r::g3d::AnmObjTexPatOverride::GetTypeObj +80059d80 nw4r::g3d::AnmObjTexPatOverride::__dt +80059df0 nw4r::g3d::AnmObjTexPatNode::GetTypeName +80059e20 nw4r::g3d::AnmObjTexPatNode::GetTypeObj +80059e30 nw4r::g3d::AnmObjTexPat::GetTypeName +80059e60 nw4r::g3d::AnmObjTexPat::GetTypeObj +80059e70 0x80059e70 +80059e90 0x80059e90 +80059ed0 0x80059ed0 +80059ee0 0x80059ee0 +80059ef0 0x80059ef0 +80059f00 0x80059f00 +80059f40 0x80059f40 +80059fb0 0x80059fb0 +8005a0a0 0x8005a0a0 +8005a1c0 0x8005a1c0 +8005a220 0x8005a220 +8005a2a0 0x8005a2a0 +8005a330 0x8005a330 +8005a390 0x8005a390 +8005a420 0x8005a420 +8005a480 0x8005a480 +8005a580 0x8005a580 +8005a640 0x8005a640 +8005a6c0 0x8005a6c0 +8005a800 0x8005a800 +8005a8b0 0x8005a8b0 +8005aaa0 nw4r::g3d::AnmObjTexSrtRes::SetFrame +8005ab60 0x8005ab60 +8005ab70 0x8005ab70 +8005ac30 0x8005ac30 +8005ac40 0x8005ac40 +8005ad20 0x8005ad20 +8005ae20 0x8005ae20 +8005aea0 0x8005aea0 +8005aef0 0x8005aef0 +8005af90 0x8005af90 +8005b140 0x8005b140 +8005b1b0 0x8005b1b0 +8005b200 0x8005b200 +8005b230 0x8005b230 +8005b240 0x8005b240 +8005b290 0x8005b290 +8005b310 0x8005b310 +8005b380 0x8005b380 +8005b3b0 0x8005b3b0 +8005b3c0 0x8005b3c0 +8005b430 0x8005b430 +8005b460 0x8005b460 +8005b470 0x8005b470 +8005b4a0 0x8005b4a0 +8005b4b0 nw4r::g3d::AnmObjChr::Release +8005b4f0 nw4r::g3d::AnmObjChr::Attach +8005b500 nw4r::g3d::AnmObjChr::Attach +8005b510 nw4r::g3d::AnmObjChr::SetWeight +8005b520 nw4r::g3d::AnmObjChr::GetWeight +8005b530 nw4r::g3d::AnmObjChr::DetachAll +8005b540 nw4r::g3d::AnmObjChr::__dt +8005b580 nw4r::g3d::AnmObjChrNode::__dt +8005b5f0 nw4r::g3d::AnmObjChrNode::Attach +8005b6e0 nw4r::g3d::AnmObjChrNode::Detach +8005b800 nw4r::g3d::AnmObjChrNode::DetachAll +8005b860 nw4r::g3d::AnmObjChrNode::UpdateFrame +8005b8e0 nw4r::g3d::AnmObjChrNode::SetFrame +8005b970 nw4r::g3d::AnmObjChrNode::GetFrame +8005b9d0 nw4r::g3d::AnmObjChrNode::SetUpdateRate +8005ba60 0x8005ba60 +8005bac0 nw4r::g3d::AnmObjChrNode::Bind +8005bbc0 nw4r::g3d::AnmObjChrNode::Bind(BindOption) +8005bcd0 nw4r::g3d::AnmObjChrNode::Release +8005bd90 nw4r::g3d::AnmObjChrNode::Release(BindOption) +8005bee0 nw4r::g3d::AnmObjChrNode::G3dProc +8005bf60 nw4r::g3d::AnmObjChrBlend::Construct +8005c0e0 nw4r::g3d::AnmObjChrBlend::GetResult +8005c720 nw4r::g3d::AnmObjChrBlend::SetWeight +8005c730 nw4r::g3d::AnmObjChrBlend::GetWeight +8005c740 nw4r::g3d::AnmObjChrRes::Construct +8005c930 nw4r::g3d::AnmObjChrRes::SetFrame +8005c9f0 nw4r::g3d::AnmObjChrRes::GetFrame +8005ca00 nw4r::g3d::AnmObjChrRes::SetUpdateRate +8005cac0 nw4r::g3d::AnmObjChrRes::GetUpdateRate +8005cad0 nw4r::g3d::AnmObjChrRes::UpdateFrame +8005cbb0 nw4r::g3d::AnmObjChrRes::Bind +8005ccc0 nw4r::g3d::AnmObjChrRes::Bind(BindOption) +8005cec0 nw4r::g3d::AnmObjChrRes::Release(BindOption) +8005d090 nw4r::g3d::AnmObjChrRes::GetResult +8005d110 nw4r::g3d::AnmObjChrRes::G3dProc +8005d160 nw4r::g3d::AnmObjChrRes::IsDerivedFrom +8005d1d0 nw4r::g3d::AnmObjChr::IsDerivedFrom +8005d220 nw4r::g3d::AnmObjChrRes::GetTypeName +8005d250 nw4r::g3d::AnmObjChrRes::GetTypeObj +8005d260 nw4r::g3d::AnmObjChrRes::__dt +8005d2b0 nw4r::g3d::AnmObjChrBlend::IsDerivedFrom +8005d330 nw4r::g3d::AnmObjChrNode::IsDerivedFrom +8005d3a0 nw4r::g3d::AnmObjChrBlend::GetTypeName +8005d3d0 nw4r::g3d::AnmObjChrBlend::GetTypeObj +8005d3e0 nw4r::g3d::AnmObjChrBlend::__dt +8005d450 nw4r::g3d::AnmObjChrNode::GetTypeName +8005d480 nw4r::g3d::AnmObjChrNode::GetTypeObj +8005d490 nw4r::g3d::AnmObjChr::GetTypeName +8005d4c0 nw4r::g3d::AnmObjChr::GetTypeObj +8005d4d0 0x8005d4d0 +8005d4f0 0x8005d4f0 +8005d530 0x8005d530 +8005d540 0x8005d540 +8005d550 0x8005d550 +8005d560 0x8005d560 +8005d570 0x8005d570 +8005d580 0x8005d580 +8005d5c0 0x8005d5c0 +8005d630 0x8005d630 +8005d720 0x8005d720 +8005d840 0x8005d840 +8005d8a0 0x8005d8a0 +8005d920 0x8005d920 +8005d9b0 0x8005d9b0 +8005da10 0x8005da10 +8005daa0 0x8005daa0 +8005db00 0x8005db00 +8005dc00 0x8005dc00 +8005dcc0 0x8005dcc0 +8005dd40 0x8005dd40 +8005dec0 0x8005dec0 +8005e1d0 0x8005e1d0 +8005e1e0 0x8005e1e0 +8005e1f0 0x8005e1f0 +8005e430 0x8005e430 +8005e500 0x8005e500 +8005e510 0x8005e510 +8005e5d0 0x8005e5d0 +8005e5e0 0x8005e5e0 +8005e6d0 0x8005e6d0 +8005e890 0x8005e890 +8005e910 0x8005e910 +8005e960 0x8005e960 +8005e9d0 0x8005e9d0 +8005ea20 0x8005ea20 +8005ea50 0x8005ea50 +8005ea60 0x8005ea60 +8005eab0 0x8005eab0 +8005eb30 0x8005eb30 +8005eba0 0x8005eba0 +8005ebd0 0x8005ebd0 +8005ebe0 0x8005ebe0 +8005ec50 0x8005ec50 +8005ec80 0x8005ec80 +8005ec90 0x8005ec90 +8005ecc0 0x8005ecc0 +8005ecd0 0x8005ecd0 +8005ef50 nw4r::g3d::AnmScn::GetLightSetting +8005f280 0x8005f280 +8005f290 0x8005f290 +8005f2a0 0x8005f2a0 +8005f2e0 0x8005f2e0 +8005f2f0 0x8005f2f0 +8005f300 0x8005f300 +8005f310 0x8005f310 +8005f320 0x8005f320 +8005f330 0x8005f330 +8005f340 0x8005f340 +8005f350 0x8005f350 +8005f360 0x8005f360 +8005f370 0x8005f370 +8005f380 0x8005f380 +8005f390 nw4r::g3d::AnmScnRes::Construct +8005f530 nw4r::g3d::AnmScnRes::__ct +8005f640 0x8005f640 +8005f680 nw4r::g3d::AnmScnRes::SetFrame +8005f6e0 0x8005f6e0 +8005f6f0 0x8005f6f0 +8005f720 0x8005f720 +8005f730 0x8005f730 +8005f7b0 0x8005f7b0 +8005f800 0x8005f800 +8005f940 0x8005f940 +8005f9b0 0x8005f9b0 +8005fb40 nw4r::g3d::AnmScnRes::GetFog +8005fbf0 nw4r::g3d::AnmScnRes::GetCamera +8005fd50 0x8005fd50 +8005fdf0 0x8005fdf0 +8005fe80 0x8005fe80 +8005ff10 0x8005ff10 +8005ffa0 0x8005ffa0 +8005ffe0 0x8005ffe0 +80060030 0x80060030 +800601b0 0x800601b0 +80060200 0x80060200 +80060240 0x80060240 +80060270 0x80060270 +80060280 0x80060280 +800602b0 0x800602b0 +800602c0 nw4r::g3d::G3dObj::__dt +80060310 nw4r::g3d::G3dObj::Destroy +80060390 nw4r::g3d::G3dObj::DetachFromParent +800603f0 nw4r::g3d::G3dObj::IsDerivedFrom +80060410 nw4r::g3d::G3dObj::GetTypeName +80060440 nw4r::g3d::G3dObj::GetTypeObj +80060450 0x80060450 +80060460 nw4r::g3d::PlayPolicy_Loop +800604d0 nw4r::g3d::AnmObj::SetAnmFlag +80060500 nw4r::g3d::AnmObj::TestAnmFlag +80060520 nw4r::g3d::fifo::GDSetGenMode2 +800605a0 0x800605a0 +800605d0 Fifo_GDSetTexCoordScale2 +80060640 nw4r::g3d::fifo::GDSetIndTexMtx +800608e0 0x800608e0 +80060940 0x80060940 +800609c0 0x800609c0 +80060a40 nw4r::g3d::tmem::SetTMemLayout +80060b40 TexRegionCallback(_GXTexObj_* +80060c10 0x80060c10 +80060c40 setTexRegion_(TMemCachePlan) +80060da0 nw4r::g3d::detail::Copy32ByteBlocks +80060e80 nw4r::g3d::detail::ZeroMemory32ByteBlocks +80060f50 nw4r::g3d::detail::ZeroMemory16ByteBlocks +80060fe0 0x80060fe0 +800613c0 0x800613c0 +800614d0 0x800614d0 +80061910 nw4r::g3d::detail::ScnDependentMtxFunc::DefaultMa +80061920 nw4r::g3d::G3DState::IndTexMtxInfo::FifoSend +80061990 0x80061990 +800619d0 0x800619d0 +800619e0 0x800619e0 +80061ae0 0x80061ae0 +80061f10 nw4r::g3d::G3DState::CameraMtxState::CameraMtxSta +80061fb0 nw4r::g3d::G3DState::LoadResMatMisc +80062020 nw4r::g3d::G3DState::LoadResTexObj +80062290 nw4r::g3d::G3DState::LoadResTlutObj +800623e0 nw4r::g3d::G3DState::LoadResGenMode +800625b0 nw4r::g3d::G3DState::LoadResTev +800627c0 nw4r::g3d::G3DState::LoadResMatPix +80062870 nw4r::g3d::G3DState::LoadResMatTevColor +80062920 nw4r::g3d::G3DState::LoadResMatIndMtxAndScale +800629e0 nw4r::g3d::G3DState::LoadResMatIndMtxAndScale +80062bb0 nw4r::g3d::G3DState::LoadResMatChan +800632e0 nw4r::g3d::G3DState::LoadResMatTexCoordGen +80063370 nw4r::g3d::G3DState::LoadResTexSrt +80063620 0x80063620 +800637d0 0x800637d0 +80063b20 nw4r::g3d::G3DState::SetViewPosNrmMtxArray +80063bb0 0x80063bb0 +80063c80 nw4r::g3d::G3DState::SetScnDependentTexMtxFunc +80063cf0 nw4r::g3d::G3DState::GetScnDependentTexMtxFunc +80063d50 0x80063d50 +80063d90 0x80063d90 +80063da0 0x80063da0 +80063e40 nw4r::g3d::G3DState::LoadFog +80063f00 0x80063f00 +80063f10 0x80063f10 +80063f40 nw4r::g3d::G3DState::LoadLightSet +80063fa0 nw4r::g3d::G3DState::LoadLightSet +80064030 nw4r::g3d::G3DState::SetCameraProjMtx +800640e0 nw4r::g3d::G3DState::GetCameraMtxPtr +80064100 0x80064100 +80064170 nw4r::g3d::G3DState::GetCameraMtxPtr +800641a0 nw4r::g3d::G3DState::SetRenderModeObj +800643a0 nw4r::g3d::G3DState::GetRenderModeObj +800643b0 nw4r::g3d::G3DState::Invalidate +80064500 nw4r::g3d::G3DState::IndMtxOpStd::SetNrmMapMtx +80064660 nw4r::g3d::G3DState::IndMtxOpStd::Reset +800646b0 nw4r::g3d::G3DState::IndMtxOpStd::__cl +80064820 __sinit_g3d_state_cpp +80064a90 nw4r::g3d::detail::LoadMaterial +80064f30 0x80064f30 +800657e0 0x800657e0 +80065890 0x80065890 +80065960 0x80065960 +80065ba0 0x80065ba0 +80065e80 0x80065e80 +80066160 0x80066160 +800664e0 0x800664e0 +80066760 0x80066760 +80066a00 0x80066a00 +80066d30 0x80066d30 +800671d0 0x800671d0 +80067730 0x80067730 +800677c0 0x800677c0 +80067820 0x80067820 +80067830 nw4r::g3d::detail::workmem::GetMtxIDTemporary +80067840 0x80067840 +80067850 0x80067850 +80067860 0x80067860 +80067870 0x80067870 +80067880 nw4r::g3d::WorldMtxManip::SetScale +80067900 nw4r::g3d::CalcWorld +80067ed0 0x80067ed0 +800681b0 0x800681b0 +800686d0 0x800686d0 +800688a0 nw4r::g3d::DrawResMdlLoop(byteCode) +800689e0 nw4r::g3d::DrawResMdlLoop(byteCode, rep) +80068bb0 nw4r::g3d::DrawResMdlLoop(MdlZ) +80068cc0 nw4r::g3d::DrawResMdlLoop(MdlZ, rep) +80068e20 nw4r::g3d::SetUpMdlZ +80068f60 nw4r::g3d::DrawResMdlDirectly +80069190 0x80069190 +800691d0 0x800691d0 +80069240 0x80069240 +80069800 0x80069800 +80069dc0 0x80069dc0 +8006a020 nw4r::g3d::Camera::__ct +8006a030 nw4r::g3d::Camera::Init +8006a080 nw4r::g3d::Camera::Init +8006a1a0 nw4r::g3d::Camera::SetPosition +8006a1d0 nw4r::g3d::Camera::SetPosition +8006a210 nw4r::g3d::Camera::SetPosture +8006a430 nw4r::g3d::Camera::SetCameraMtxDirectly +8006a480 nw4r::g3d::Camera::SetPerspective +8006a4c0 nw4r::g3d::Camera::SetOrtho +8006a500 nw4r::g3d::Camera::SetProjectionMtxDirectly +8006a550 nw4r::g3d::Camera::SetScissor +8006a570 nw4r::g3d::Camera::SetScissorBoxOffset +8006a590 nw4r::g3d::Camera::SetViewport +8006a630 nw4r::g3d::Camera::SetViewportZRange +8006a650 nw4r::g3d::Camera::GetViewport +8006a6c0 nw4r::g3d::Camera::GetCameraMtx +8006a720 nw4r::g3d::Camera::GetProjectionMtx +8006a800 nw4r::g3d::Camera::GetProjectionTexMtx +8006a8d0 nw4r::g3d::Camera::GetEnvironmentTexMtx +8006a950 nw4r::g3d::Camera::GXSetViewport +8006a9e0 nw4r::g3d::Camera::GXSetProjection +8006aab0 nw4r::g3d::Camera::GXSetScissor +8006aae0 nw4r::g3d::Camera::GXSetScissorBoxOffset +8006ab00 0x8006ab00 +8006af20 0x8006af20 +8006b080 nw4r::g3d::detail::dcc::CalcWorldMtx_Basic +8006b1f0 0x8006b1f0 +8006b230 0x8006b230 +8006b2d0 0x8006b2d0 +8006b310 0x8006b310 +8006b3d0 0x8006b3d0 +8006b480 0x8006b480 +8006b4d0 0x8006b4d0 +8006b5b0 0x8006b5b0 +8006b630 0x8006b630 +8006b760 0x8006b760 +8006b790 0x8006b790 +8006b930 0x8006b930 +8006ba80 0x8006ba80 +8006bb10 0x8006bb10 +8006bcc0 0x8006bcc0 +8006bd60 nw4r::g3d::detail::dcc::CalcWorldMtx_Maya_SSC_App +8006bf00 0x8006bf00 +8006bf40 0x8006bf40 +8006bfd0 0x8006bfd0 +8006c010 0x8006c010 +8006c0b0 0x8006c0b0 +8006c180 0x8006c180 +8006c1d0 0x8006c1d0 +8006c2a0 0x8006c2a0 +8006c320 0x8006c320 +8006c430 0x8006c430 +8006c460 0x8006c460 +8006c5a0 0x8006c5a0 +8006c6d0 0x8006c6d0 +8006c760 0x8006c760 +8006c8c0 0x8006c8c0 +8006c960 nw4r::g3d::detail::dcc::CalcWorldMtx_Xsi +8006cb20 0x8006cb20 +8006cb70 0x8006cb70 +8006cc20 0x8006cc20 +8006cc60 0x8006cc60 +8006cd20 0x8006cd20 +8006cdf0 0x8006cdf0 +8006ce50 0x8006ce50 +8006cf20 0x8006cf20 +8006cfa0 0x8006cfa0 +8006d0d0 0x8006d0d0 +8006d100 0x8006d100 +8006d250 0x8006d250 +8006d390 0x8006d390 +8006d430 0x8006d430 +8006d5a0 0x8006d5a0 +8006d640 nw4r::g3d::ScnObj::CalcWorldMtx +8006d6f0 nw4r::g3d::ScnObj::CalcViewMtx +8006d710 nw4r::g3d::ScnObj::__ct +8006d800 nw4r::g3d::ScnObj::__dt +8006d880 nw4r::g3d::ScnObj::SetScnObjOption +8006d8a0 nw4r::g3d::ScnObj::SetScnObjOption_caseD_1 +8006d8c8 nw4r::g3d::ScnObj::SetScnObjOption_caseD_2 +8006d8f0 nw4r::g3d::ScnObj::SetScnObjOption_caseD_3 +8006d918 nw4r::g3d::ScnObj::SetScnObjOption_caseD_4 +8006d940 nw4r::g3d::ScnObj::SetScnObjOption_caseD_5 +8006d968 nw4r::g3d::ScnObj::SetScnObjOption_caseD_6 +8006d990 nw4r::g3d::ScnObj::SetScnObjOption_caseD_7 +8006d9b8 nw4r::g3d::ScnObj::SetScnObjOption_caseD_8 +8006d9e0 nw4r::g3d::ScnObj::SetScnObjOption_caseD_9 +8006da08 nw4r::g3d::ScnObj::SetScnObjOption_caseD_0 +8006da20 nw4r::g3d::ScnObj::GetScnObjOption +8006da50 nw4r::g3d::ScnObj::GetScnObjOption_caseD_1 +8006da60 nw4r::g3d::ScnObj::GetScnObjOption_caseD_2 +8006da70 nw4r::g3d::ScnObj::GetScnObjOption_caseD_3 +8006da80 nw4r::g3d::ScnObj::GetScnObjOption_caseD_4 +8006da90 nw4r::g3d::ScnObj::GetScnObjOption_caseD_5 +8006daa0 nw4r::g3d::ScnObj::GetScnObjOption_caseD_6 +8006dab0 nw4r::g3d::ScnObj::GetScnObjOption_caseD_7 +8006dac0 nw4r::g3d::ScnObj::GetScnObjOption_caseD_8 +8006dad0 nw4r::g3d::ScnObj::GetScnObjOption_caseD_9 +8006dae0 nw4r::g3d::ScnObj::GetScnObjOption_caseD_0 +8006daf0 nw4r::g3d::ScnObj::SetMtx +8006db80 nw4r::g3d::ScnObj::SetMtx +8006dbe0 nw4r::g3d::ScnObj::GetMtx +8006dc30 nw4r::g3d::ScnObj::GetValueForSortOpa +8006dc40 nw4r::g3d::ScnObj::GetValueForSortXlu +8006dc50 nw4r::g3d::ScnObj::SetPriorityDrawOpa +8006dc80 nw4r::g3d::ScnObj::SetPriorityDrawXlu +8006dcb0 nw4r::g3d::ScnObj::EnableScnObjCallbackTiming +8006dcf0 nw4r::g3d::ScnObj::EnableScnObjCallbackExecOp +8006dd10 nw4r::g3d::ScnObj::SetBoundingVolume +8006dda0 nw4r::g3d::ScnObj::GetBoundingVolume +8006de00 nw4r::g3d::ScnLeaf::ForEach +8006de40 nw4r::g3d::ScnLeaf::SetScnObjOption +8006de80 nw4r::g3d::ScnLeaf::GetScnObjOption +8006ded0 nw4r::g3d::ScnObj::CalcWorldMtx +8006dfd0 nw4r::g3d::ScnLeaf::GetScaleProperty +8006e010 nw4r::g3d::ScnLeaf::DefG3dProcScnLeaf +8006e2f0 nw4r::g3d::ScnGroup::Construct +8006e3b0 nw4r::g3d::ScnGroup::ForEach +8006e4f0 nw4r::g3d::ScnGroup::ScnGroup_G3DPROC_GATHER_SCNOBJ +8006e610 nw4r::g3d::ScnGroup::G3dProc +8006e650 nw4r::g3d::ScnGroup::DefG3dProcScnGroup +8006eac0 nw4r::g3d::ScnGroup::Insert +8006ec50 nw4r::g3d::ScnGroup::Remove(idx) +8006ed10 nw4r::g3d::ScnGroup::Remove(ScnObj) +8006eda0 nw4r::g3d::ScnGroup::__ct +8006ee10 nw4r::g3d::ScnGroup::__dt +8006eed0 nw4r::g3d::ScnGroup::IsDerivedFrom +8006ef20 nw4r::g3d::G3dObj::IsDerivedFrom +8006ef60 nw4r::g3d::ScnGroup::GetTypeNameStatic +8006ef90 nw4r::g3d::ScnGroup::GetTypeObjStatic +8006efa0 nw4r::g3d::ScnLeaf::IsDerivedFrom +8006eff0 nw4r::g3d::ScnLeaf::GetTypeNameStatic +8006f020 nw4r::g3d::ScnLeaf::GetTypeObjStatic +8006f030 nw4r::g3d::ScnLeaf::destruct +8006f0c0 nw4r::g3d::ScnObj::GetTypeNameStatic +8006f0f0 nw4r::g3d::ScnObj::GetTypeObjStatic +8006f100 nw4r::g3d::ScnRoot::Construct +8006f240 nw4r::g3d::ScnRoot::G3dProc +8006f2f0 nw4r::g3d::ScnRoot::GetCamera +8006f350 nw4r::g3d::ScnRoot::GetCurrentCamera +8006f390 nw4r::g3d::ScnRoot::SetCurrentCamera +8006f3a0 nw4r::g3d::ScnRoot::GetFog +8006f400 nw4r::g3d::ScnRoot::GetLightSet +8006f450 nw4r::g3d::ScnRoot::SetAnmScn +8006f4f0 nw4r::g3d::ScnRoot::UpdateFrame +8006f560 0x8006f560 +8006f790 nw4r::g3d::ScnRoot::CalcAnmScn +8006f920 nw4r::g3d::ScnRoot::CalcWorld +8006f970 nw4r::g3d::ScnRoot::CalcMaterial +8006f990 nw4r::g3d::ScnRoot::CalcVtx +8006f9b0 nw4r::g3d::ScnRoot::CalcView +8006fa30 nw4r::g3d::ScnRoot::GatherDrawScnObj +8006fb20 nw4r::g3d::ScnRoot::ZSort +8006fb80 nw4r::g3d::ScnRoot::DrawOpa +8006fc00 nw4r::g3d::ScnRoot::DrawXlu +8006fc80 nw4r::g3d::ScnRoot::ForceDrawMode +8006fcb0 nw4r::g3d::ScnRoot::__ct +8006fdb0 0x8006fdb0 +8006fe30 nw4r::g3d::ScnObjGather::Add +8006ff50 nw4r::g3d::ScnObjGather::ZSort +8006ffb0 0x8006ffb0 +8006fff0 0x8006fff0 +80070030 std::sort(void_(nw4r::g3d::ScnObj_** +800703b0 std::sort(void_(nw4r::g3d::ScnObj_** +80070730 std::__sort132(void_(nw4r::g3d::ScnObj_** +80070830 nw4r::g3d::ScnObjGather::Sort +80070890 nw4r::g3d::@unnamed@g3d_scnroot_cpp@::LessByGetVa +80070920 nw4r::g3d::@unnamed@g3d_scnroot_cpp@::LessByGetVa +800709b0 nw4r::g3d::ScnObjGather::Sort(CompFuncs) +80070a20 nw4r::g3d::ScnObjGather::DrawOpa +80070ab0 nw4r::g3d::ScnObjGather::DraxXlu +80070b40 nw4r::g3d::ScnObjGather::CheckScnObj +80070b50 nw4r::g3d::ScnObjGather::__ct +80070b80 nw4r::g3d::ScnObjGather::Clear +80070b90 nw4r::g3d::ScnObjGather::__dt +80070bd0 0x80070bd0 +80070c40 0x80070c40 +80070c70 0x80070c70 +80070c80 nw4r::g3d::ScnMdlSimple::Construct +80070e20 nw4r::g3d::ScnMdlSimple::ScnMdlSmpl_CalcPosture +80071080 nw4r::g3d::ScnMdlSimple::ScnMdlSmpl_G3DPROC_GATHER_SCNOBJ +800710c0 nw4r::g3d::ScnMdlSimple::ScnMdlSmpl_G3DPROC_CALC_ +80071410 nw4r::g3d::ScnMdlSimple::G3dProc +80071ca0 nw4r::g3d::ScnMdlSimple::SetScnObjOption +80071ce0 nw4r::g3d::ScnMdlSimple::GetScnObjOption +80071d20 nw4r::g3d::ScnMdlSimple::GetScnMtxPos +80071e60 nw4r::g3d::ScnMdlSimple::SetAnmObj +80072470 nw4r::g3d::ScnMdlSimple::RemoveAnmObj +800725f0 nw4r::g3d::ScnMdlSimple::RemoveAnmObj +800726d0 nw4r::g3d::ScnMdlSimple::GetAnmObj +80072730 nw4r::g3d::ScnMdlSimple::GetAnmObj +80072790 nw4r::g3d::ScnMdlSimple::UpdateFrame +80072850 nw4r::g3d::ScnMdlSimple::EnableScnMdlCallbackTiming +80072890 nw4r::g3d::ScnMdlSimple::DisableScnMdlCallbackTiming +800728d0 nw4r::g3d::ScnMdlSimple::GetViewPosMtxArray +80072900 nw4r::g3d::ScnMdlSimple::GetViewNrmMtxArray +80072940 nw4r::g3d::ScnMdlSimple::GetViewTexMtxArray +80072980 nw4r::g3d::ScnMdlSimple::GetByteCode +800729d0 0x800729d0 +80072bf0 nw4r::g3d::ScnMdlSimple::destruct +80072d10 nw4r::g3d::ScnMdlSimple::IsDerivedFrom +80072d80 nw4r::g3d::ScnMdlSimple::GetTypeNameStatic +80072db0 nw4r::g3d::ScnMdlSimple::GetTypeObj +80072dc0 nw4r::g3d::ScnMdl::CopiedMatAccess::GetResTexObj +80072e10 nw4r::g3d::ScnMdl::CopiedMatAccess::GetResMatTevColor +80072e60 nw4r::g3d::ScnMdl::CopiedMatAccess::GetResTexSrtEx +80072ec0 nw4r::g3d::ScnMdl::CopiedMatAccess::GetResMatMiscEx +80072f20 nw4r::g3d::ScnMdl::CopiedMatAccess::GetResMatTevColorEx +80072fa0 nw4r::g3d::ScnMdl::CopiedMatAccess::GetResTevEx +80073010 nw4r::g3d::ScnMdl::CopiedMatAccess::__ct +80073290 nw4r::g3d::ScnMdl::CopiedVisAccess::IsVisible +80073310 nw4r::g3d::ScnMdl::CopiedVisAccess::CopiedVisAcce +800733d0 nw4r::g3d::ScnMdl::Construct +80073f60 nw4r::g3d::ScnMdl::ScnMdl_G3DPROC_CALC_MAT +800746d0 nw4r::g3d::ScnMdl::G3dProc +80074b80 nw4r::g3d::ScnMdl::SetScnObjOption +80074bc0 nw4r::g3d::ScnMdl::GetScnObjOption +80074c00 nw4r::g3d::ScnMdl::InitBuffer +80074fa0 nw4r::g3d::ScnMdl::CleanMatBuffer +800752e0 nw4r::g3d::ScnMdl::SetAnmObj +80075450 nw4r::g3d::ScnMdl::RemoveAnmObj +80075650 nw4r::g3d::ScnMdl::RemoveAnmObj +800756a0 nw4r::g3d::ScnMdl::GetAnmObj +800756c0 nw4r::g3d::ScnMdl::GetAnmObj +800756e0 nw4r::g3d::ScnMdl::__dt +80075750 nw4r::g3d::ScnMdl::IsDerivedFrom +800757d0 nw4r::g3d::ScnMdl::GetTypeNameStatic +80075800 nw4r::g3d::ScnMdl::GetTypeObjStatic +80075810 0x80075810 +80075820 0x80075820 +80075950 nw4r::g3d::ScnObjGatherExScnMdl::DrawOpa +80075980 nw4r::g3d::ScnObjGatherExScnMdl::DrawXlu +800759b0 nw4r::g3d::ScnObjGatherExScnMdl::CheckScnObj +80075b30 nw4r::g3d::ScnObjGatherExScnMdl::GetResMdl +80075b40 nw4r::g3d::ScnObjGatherExScnMdl::DrawLoop +80075f30 nw4r::g3d::ScnObjGatherExScnMdl::HasEqualTarget +80075fc0 nw4r::g3d::ScnObjGatherExScnMdl::TypeID +80075fd0 nw4r::g3d::ScnGroupEx::Construct +80076130 nw4r::g3d::ScnGroupEx::SetResMdl +80076170 0x80076170 +800761b0 nw4r::g3d::ScnGroupEx::G3dProc +800764e0 nw4r::g3d::ScnGroupEx::__dt +80076520 nw4r::g3d::ScnObjGatherExScnMdl::SetResMdl +800765d0 nw4r::g3d::ScnObjGatherExScnMdl::__dt +80076610 0x80076610 +80076620 0x80076620 +80076630 0x80076630 +80076640 0x80076640 +80076650 0x80076650 +80076660 0x80076660 +80076670 nw4r::g3d::ScnGroupEx::IsDerivedFrom +800766e0 nw4r::g3d::ScnGroupEx::GetTypeName +80076710 nw4r::g3d::ScnGroupEx::GetTypeObj +80076720 nw4r::g3d::ScnMdl1Mat1Shp::Construct +80076840 nw4r::g3d::ScnMdl1Mat1Shp::G3dProc +80076b30 nw4r::g3d::ScnMdl1Mat1Shp::IsDerivedFrom +80076ba0 nw4r::g3d::ScnMdl1Mat1Shp::GetTypeName +80076bd0 nw4r::g3d::ScnMdl1Mat1Shp::GetTypeObj +80076be0 nw4r::g3d::ScnMdl1Mat1Shp::__dt +80076c20 nw4r::g3d::CalcMaterialDirectly +80077030 nw4r::g3d::G3dInit +80077120 nw4r::g3d::G3dReset +80077130 nw4r::g3d::ScnProc::Construct +80077240 nw4r::g3d::ScnProc::G3dProc +80077340 nw4r::g3d::ScnProc::IsDerivedFrom +800773b0 nw4r::g3d::ScnProc::GetTypeName +800773e0 nw4r::g3d::ScnProc::GetTypeObj +800773f0 nw4r::g3d::ScnProc::__dt +80077430 nw4r::g3d::Fog::__ct +80077440 nw4r::g3d::Fog::Init +800774b0 nw4r::g3d::Fog::CopyTo +80077510 nw4r::g3d::Fog::SetFogRangeAdjParam +80077530 nw4r::g3d::Fog::SetGP +800775c0 nw4r::g3d::LightObj::Clear +800775e0 nw4r::g3d::LightObj::InitLightColor +80077630 nw4r::g3d::LightObj::InitLightPos +80077670 nw4r::g3d::LightObj::InitLightDir +800776b0 nw4r::g3d::LightObj::InitLightSpot +800776f0 nw4r::g3d::LightObj::InitLightAttnA +80077730 nw4r::g3d::LightObj::InitLightDistAttn +80077770 nw4r::g3d::LightObj::InitLightAttnK +800777b0 nw4r::g3d::LightObj::InitSpecularDir +800777f0 nw4r::g3d::LightObj::InitLightShininess +80077850 nw4r::g3d::LightObj::GetLightPos +80077870 nw4r::g3d::LightObj::GetLightDir +80077890 nw4r::g3d::LightSetting::__ct +80077cd0 nw4r::g3d::LightSetting::Import +80077e70 nw4r::g3d::LightSetting::ApplyViewMtx +80077f90 nw4r::g3d::LightSet::SelectLightObj +80078000 nw4r::g3d::LightSet::SelectAmbLightObj +80078070 nw4r::g3d::CalcVtx +80078880 nw4r::lyt::LytInit +800788e0 nw4r::lyt::Pane::__ct +80078a20 nw4r::lyt::Pane::__dt +80078b60 nw4r::lyt::Pane::AppendChild +80078bb0 nw4r::lyt::Pane::GetPaneRect +80078c40 nw4r::lyt::Pane::GetVtxColor +80078c50 nw4r::lyt::Pane::SetVtxColor +80078c60 nw4r::lyt::Pane::GetColorElement +80078c90 nw4r::lyt::Pane::SetColorElement +80078cc0 nw4r::lyt::Pane::GetVtxColorElement +80078cd0 nw4r::lyt::Pane::SetVtxColorElement +80078ce0 nw4r::lyt::Pane::FindPaneByName +80078d90 nw4r::lyt::Pane::FindMaterialByName +80078e50 nw4r::lyt::Pane::CalculateMtx +80079150 nw4r::lyt::Pane::Draw +800791e0 nw4r::lyt::Pane::DrawSelf +800791f0 nw4r::lyt::Pane::Animate +80079280 nw4r::lyt::Pane::AnimateSelf +80079340 nw4r::lyt::Pane::BindAnimation +80079360 nw4r::lyt::Pane::UnbindAnimation +800793f0 nw4r::lyt::Pane::UnbindAllAnimation +80079410 nw4r::lyt::UnbindAnimationSelf +80079470 nw4r::lyt::Pane::AddAnimationLink +800794b0 nw4r::lyt::Pane::FindAnimationLinkSelf +800794c0 nw4r::lyt::Pane::FindAnimationLinkSelf +800794d0 nw4r::lyt::Pane::SetAnimationEnable +800795d0 nw4r::lyt::Pane::SetAnimationEnable +800796d0 nw4r::lyt::Pane::LoadMtx +80079730 nw4r::lyt::Pane::GetVtxPos +80079800 nw4r::lyt::Pane::GetMaterialNum +80079820 nw4r::lyt::Pane::GetMaterial +80079830 nw4r::lyt::Pane::GetMaterial +80079850 nw4r::lyt::Pane::GetRuntimeTypeInfo +80079860 0x80079860 +80079870 nw4r::lyt::Group::__ct +800798e0 nw4r::lyt::Group::__ct +80079a00 nw4r::lyt::Group::__dt +80079ab0 nw4r::lyt::Group::AppendPane +80079b40 nw4r::lyt::GroupContainer::__dt +80079c10 nw4r::lyt::GroupContainer::AppendGroup +80079c50 nw4r::lyt::GroupContainer::FindGroupByName +80079cd0 nw4r::lyt::SetTagProcessorImpl +80079e90 nw4r::lyt::IsIncludeAnimationGroupRef +80079f60 nw4r::lyt::Layout::__ct +80079fa0 nw4r::lyt::Layout::__dt +8007a0d0 nw4r::lyt::Layout::Build +8007a420 nw4r::lyt::Layout::CreateAnimTransform +8007a4a0 nw4r::lyt::Layout::CreateAnimTransform +8007a500 nw4r::lyt::Layout::CreateAnimTransform +8007a590 nw4r::lyt::Layout::BindAnimation +8007a5c0 nw4r::lyt::Layout::UnbindAnimation +8007a5f0 nw4r::lyt::Layout::UnbindAllAnimation +8007a610 nw4r::lyt::Layout::BindAnimationAuto +8007a8a0 nw4r::lyt::Layout::SetAnimationEnable +8007a8d0 nw4r::lyt::Layout::CalculateMtx +8007a8f0 nw4r::lyt::Layout::Draw +8007a910 nw4r::lyt::Layout::Animate +8007a930 nw4r::lyt::Layout::SetTagProcessor +8007aaf0 nw4r::lyt::Layout::BuildPaneObj +8007ace0 nw4r::ut::Color::__ct +8007acf0 nw4r::lyt::Picture::__ct +8007ae40 nw4r::lyt::Picture::__dt +8007af20 nw4r::lyt::Picture::Append +8007b0e0 nw4r::lyt::Picture::GetVtxColor +8007b110 nw4r::lyt::Picture::SetVtxColor +8007b140 nw4r::lyt::Picture::GetVtxColorElement +8007b160 nw4r::lyt::Picture::SetVtxColorElement +8007b180 nw4r::lyt::Picture::DrawSelf +8007b260 nw4r::lyt::Picture::GetRuntimeTypeInfo +8007b270 __sinit_\lyt_picture_cpp +8007b280 nw4r::lyt::TextBox::__ct +8007b570 nw4r::lyt::TextBox::__dt +8007b710 nw4r::lyt::TextBox::GetVtxColor +8007b740 nw4r::lyt::TextBox::SetVtxColor +8007b790 nw4r::lyt::TextBox::GetVtxColorElement +8007b7b0 nw4r::lyt::TextBox::SetVtxColorElement +8007b7d0 nw4r::lyt::TextBox::DrawSelf +8007beb0 0x8007beb0 +8007c290 0x8007c290 +8007c2d0 nw4r::lyt::TextBox::GetStringBufferLength +8007c300 nw4r::lyt::TextBox::AllocStringBuffer +8007c3d0 nw4r::lyt::TextBox::FreeStringBuffer +8007c420 nw4r::lyt::TextBox::SetString +8007c500 nw4r::lyt::TextBox::SetString +8007c5d0 nw4r::ut::Font__dt +8007c610 nw4r::lyt::TextBox::LoadMtx +8007c6a0 0x8007c6a0 +8007ca10 0x8007ca10 +8007cb70 nw4r::lyt::TextBox::GetRuntimeTypeInfo +8007cb80 0x8007cb80 +8007cb90 nw4r::lyt::Window::__ct +8007ce20 nw4r::lyt::Window::__dt +8007cf70 nw4r::lyt::Window::FindMaterialByName +8007d070 nw4r::lyt::Window::GetVtxColor +8007d0a0 nw4r::lyt::Window::SetVtxColor +8007d0d0 nw4r::lyt::Window::GetVtxColorElement +8007d0f0 nw4r::lyt::Window::SetVtxColorElement +8007d110 nw4r::lyt::Window::DrawSelf +8007d250 nw4r::lyt::Window::AnimateSelf +8007d2e0 nw4r::lyt::Window::UnbindAnimationSelf +8007d370 nw4r::lyt::Window::DrawContent +8007d480 nw4r::lyt::Window::DrawFrame +8007da60 nw4r::lyt::Window::DrawFrame4 +8007e1b0 nw4r::lyt::Window::DrawFrame8 +8007f000 nw4r::lyt::Window::GetFrameSize +8007f100 nw4r::lyt::Window:GetMaterialNum +8007f110 nw4r::lyt::Window::GetMaterial +8007f140 nw4r::lyt::Window::GetFrameMaterial +8007f170 nw4r::lyt::Window::GetContent +8007f180 0x8007f180 +8007f190 0x8007f190 +8007f1a0 Bounding_construct +8007f1e0 0x8007f1e0 +8007f240 0x8007f240 +8007f250 nw4r::lyt::Window::GetRuntimeTypeInfo +8007f260 __sinit_\lyt_bounding_cpp +8007f270 0x8007f270 +8007f380 0x8007f380 +8007f580 nw4r::math::VEC2::__as +8007f5a0 nw4r::ut::LinkList::__ct +8007f5c0 nw4r::lyt::Material::__ct +8007fc30 _GXColorS10::Operator= +8007fc60 nw4r::ut::Color::Operator= +8007fc70 nw4r::lyt::MaterialResourceNum::GetTexMapNum +8007fc80 nw4r::lyt::MaterialResourceNum::GetTexSRTNum +8007fc90 nw4r::lyt::MaterialResourceNum::GetCoordGenNum +8007fca0 nw4r::lyt::MaterialResourceNum::GetChanCtrlNum +8007fcb0 nw4r::lyt::MaterialResourceNum::GetMapColNum +8007fcc0 nw4r::lyt::MaterialResourceNum::HasTevSwapTable +8007fcd0 nw4r::lyt::MaterialResourceNum::HasAlphaCompare +8007fce0 nw4r::lyt::MaterialResourceNum::HasBlendMode +8007fcf0 nw4r::lyt::MaterialResourceNum::GetIndTexStageNum +8007fd00 nw4r::lyt::MaterialResourceNum::GetIndTexStageNum +8007fd10 0x8007fd10 +8007fd20 0x8007fd20 +8007fd40 nw4r::lyt::res::TexMap::GetWarpModeS +8007fd50 nw4r::lyt::res::TexMap::GetWarpModeT +8007fd60 0x8007fd60 +8007fd80 nw4r::lyt::res::TexMap::GetMinFilter +8007fda0 nw4r::lyt::res::TexMap::GetMagFilter +8007fdc0 0x8007fdc0 +8007fdf0 0x8007fdf0 +8007fe20 0x8007fe20 +8007fe50 nw4r::lyt::TevSwapMode::__as +8007fe60 nw4r::lyt::TexSRT::operator_= +8007fe90 0x8007fe90 +8007fec0 0x8007fec0 +8007ff70 0x8007ff70 +8007ffa0 0x8007ffa0 +8007ffd0 0x8007ffd0 +8007ffe0 0x8007ffe0 +8007fff0 nw4r::snd::DvdSoundArchive::OpenExtStream +80080000 0x80080000 +80080010 0x80080010 +80080020 0x80080020 +80080030 0x80080030 +80080040 nw4r::lyt::detail::ConvertOffsToPtr +80080050 nw4r::lyt::detail::ConvertOffsToPtr +80080060 0x80080060 +80080070 0x80080070 +80080080 0x80080080 +80080090 nw4r::lyt::detail::ConvertOffsToPtr::CalcCompletion +8050caa4 0x8050caa4 +8050cae4 0x8050cae4 +8050cbc0 0x8050cbc0 +8050cc9c KMP::Manager::CalcNextCPRecursive +8050d08c KMP::Manager::CalcNextCP +8050d98c KMP::Manager::ResetCKPTScannedState +8050da08 KMP::Manager::CalcExactFinishTime +8050da54 KMP::Holder::CalcExactFinishTime +8050dba8 Vec2::Operator- +8050dbcc Vec2::Operator+ +8050dbf0 KMP::CKPTSection::CalcDistanceFromCPRecursive +8050defc KMP::CKPTSection::CalcTotalDistance +8050e220 KMP::Manager::CreateInstance +8050e2a8 KMP::Manager::DestroyInstance +8050e2f8 KMP::Manager::__ct +8050e338 KMP::Manager::__dt +8050e378 KMP::Manager::Init +8050e79c KMP::Manager::GetRawKMP +8050e7b8 KMP::RawHolder::__ct +8050e7f8 KMP::Holder::GetType +8050e804 KMP::Manager::GetCAMECount +8050e820 KMP::RawHolder::GetVersion +8050e828 KMP::Holder::GetOpeningCamIdx +8050e838 KMP::Holder::SetId +8050e840 KMP::Manager::GetAREACount +8050e85c KMP::Manager::GetEENPTCount +8050e878 KMP::Manager::GetITPTCount +8050e894 KMP::Manager::GetJGPTCount +8050e8b0 KMP::Manager::GetKTPTCount +8050e8cc KMP::Holder::IsNarrowGrid +8050e8d8 KMP::Holder::GetFilterEffectColor +8050e8e4 KMP::Holder::HasFilterEffect +8050e8f0 KMP::Manager::ParseSTGI +8050ea10 KMP::Manager::ParseMSPT +8050eb30 KMP::Manager::ParseCNPT +8050ec50 KMP::Manager::ParseJGPT +8050ed70 KMP::Manager::ParseCAME +8050ee90 KMP::Manager::ParseAREA +8050ef24 KMP::Manager::ParsePOTI +8050f054 KMP::Manager::ParseGOBJ +8050f18c Vec3::__dt +8050f1cc KMP::Manager::ParseCKPT +8050f308 KMP::Manager::ParseCKPH +8050f668 KMP::Manager::ParseITPT +8050f788 KMP::Manager::ParseITPH +8050f8a4 KMP::Manager::ParseENPT +8050f9cc KMP::Manager::ParseENPH +8050fae8 KMP::Manager::ParseKTPT +8050fc68 KMP::AREASection::GetHolder +8050fc8c KMP::JGPTSection::GetHolder +8050fcb0 KMP::KTPTSection::GetHolder +8050fcd4 KMP::Manager::GetHolder +8050fd20 KMP::Holder::GetRoute +8050fd94 KMP::KTPTSection::GetBlock +8050fde4 KMP::KTPTSection::__ct +8050fef4 KMP::Holder::CalcCoordinates_0Indexed +80510320 0x80510320 +80510360 Vec3::Operator-(unary) +80510388 Vec3::RotateQuaternion +8051039c Vec3::MultiplyByScalar +805103c4 Vec3::Operator+ +805103f8 Vec3::Operator- +8051042c KMP::Holder::InitLinks +805106b0 KMP::Holder::CalcCoordinates +805106bc KMP::Manager::GetHolder +80510708 KMP::Manager::GetHolder +80510754 KMP::Manager::GetHolder +805107bc KMP::Manager::CalcExtremes +805108c8 KMP::Manager::GetHolder +80510914 KMP::Manager::GetHolder +8051097c KMP::CKPHSection::Init +80510ba0 KMP::CKPHSection::GetHolder +80510c24 KMP::Holder::Init +80510c6c KMP::Holder::CalcDepthRecursive +80510dd0 KMP::CKPTSection::Init +80511070 KMP::Holder__ct +8051116c KMP::LinkedCKPT::__ct +80511170 KMP::LinkedCKPT::__dt +805111b0 KMP::Holder::InitLinks +805115f8 KMP::Holder::InitType +805117b0 KMP::Manager::GetHolder +805117fc KMP::Manager::GetHolder +80511848 KMP::Manager::GetCKPHHolderByCT +805118c8 KMP::Manager::POTISection::__ct +80511990 KMP::Manager::GetHolder +805119dc KMP::AREASection::__ct +80511b18 KMP::AREASection::SortByPriority +80511bdc KMP::Holder::__ct +80511c3c KMP::Holder::IsPointInAREA +80511cc4 KMP::Holder::GetRouteId +80511cf4 KMP::Holder::GetRoute +80511dac KMP::HolderAREABox::__ct +80511f40 KMP::Holder::__dt +80511f80 KMP::HolderAREABox::IsPointInAREAShape +80512088 KMP::HolderAREACylinder::__ct +80512214 KMP::HolderAREACylinder::IsPointInAREAShape +805122f4 KMP::Manager::GetHolder +80512340 KMP::Manager::GetAREAHolderByPriority +80512394 KMP::Manager::FindAREA +805125ec KMP::Manager::GetMiniMapAREAParams +8051273c KMP::Manager::GetHolder +80512788 KMP::Manager::GetCAMEHolderFromAREAId +80512860 KMP::Holder::GetNext +805128d8 KMP::IsNonPrivateBattle +80512900 KMP::Holder::InitLinks +8051311c KMP::Manager::GetNextENPT +80513198 KMP::Manager::GetNextENPTCount +805131fc KMP::Manager::GetPrevENPT +80513278 KMP::Manager::GetPrevENPTCount +805132dc KMP::Manager::ToggleENPH +805133e4 KMP::Holder::ToggleENPHLink +80513870 KMP::Holder::AddPrevLink +805138c4 KMP::Holder::AddNextLink +80513918 KMP::Holder::AddLink +80513a14 KMP::Holder::InitLinks +80513d7c KMP::Manager::GetNextITPT +80513df4 KMP::Manager::GetNextITPTCount +80513e58 KMP::Manager::GetPrevITPT +80513ed0 KMP::Manager::GetPrevITPTCount +80513f34 KMP::Holder::__ct +80514088 KMP::Holder::InitLinks +805144ac KMP::Manager::GetHolder +805144f8 KMP::Holder::GetPosition +80514644 Vec3::MultiplyByScalar2 +8051466c KMP::Manager::GetHolder +805146b8 KMP::Manager::GetHolder +80514704 KMP::Manager::GetHolder +8051473c KMP::Holder::GetFilterEffectAlpha +80514768 KMP::AREASection::__dt +805147cc KMP::Holder::__dt +8051484c ArchiveFile::__ct +80514880 ArchiveFile::__dt +80514958 ArchiveFile::Mount +80514998 0x80514998 +8051499c ArchiveFile::Load +80514b30 ArchiveFile::LoadUncompressed +80514b48 ArchiveFile::MountFromRawArchive(void*) +80514bcc ArchiveFile::GetFileNewBuffer +80514c74 0x80514c74 +80514c7c ArchiveFile::Dump +80514d30 ArchiveFile::TryDump +80514dcc ArchiveFile::ClearAll +80514e54 0x80514e54 +80514e58 ArchiveFile::Unmount +80514efc ArchiveFile::ClearArchive +80514f54 ArchiveFile::ClearDump +80514fac ArchiveFile::GetFile +80515094 ArchiveFile::Decompress +80515130 ArchiveFile::SetDumpToDecompress +80515164 ArchiveFile::MountFromRawArchive(ArchiveFile*) +805151fc Friend::__dt +8051523c Friend::SetFriend +8051527c Friend::StoreToDest +80515290 Friend::AddFriend +8051530c 0x8051530c +805153f8 0x805153f8 +8051550c Friend::SetData +8051555c Friend::AddLoss +80515574 Friend::AddWin +8051558c 0x8051558c +805155d8 0x805155d8 +805156a8 0x805156a8 +805158c0 0x805158c0 +80515964 0x80515964 +80515b44 0x80515b44 +80515ba8 0x80515ba8 +80515bd8 0x80515bd8 +80515c08 KCLController::CanReuseLastTrianglesList +80515c84 0x80515c84 +80515cf0 0x80515cf0 +80515d00 0x80515d00 +80515d30 0x80515d30 +80515d38 0x80515d38 +80515d40 0x80515d40 +80515d6c GameScene::__ct +80515ef4 BaseScene::__dt +80515f4c GameScene::__dt +80515fa8 GameScene::FadeIn +8051600c GameScene::FadeOut +80516068 GameScene::FinalizeEnter +805165d8 GameScene::GetScreenCount +805165e0 GameScene::vf_0x58 +805165e4 GameScene::AddArchivesHolder +80516674 GameScene::UnmountArchives +805166e4 GameScene::enter +80516b10 GameScene::SetFramerate +80516b74 GameScene::ChangeScene +80516c18 0x80516c18 +80516c20 GameScene::FadeOutToReinit +80516c6c GameScene::CreateChildScene +80516c80 GameScene::Reset +80516d84 0x80516d84 +80516ddc GameScene::exit +80516f00 BaseScene::ResetRacedataScenarios +80516f0c 0x80516f0c +80516f28 0x80516f28 +80516f50 GameScene::vf_0x48 +80516f54 GameScene::calc +8051731c GameScene::isSpectating +80517324 GameScene::vf_0x2c +8051732c GameScene::vf_0x50 +80517334 0x80517334 +8051733c GameScene::reinit +8051745c GameScene::OnReinit +80517460 GameScene::isPaused +80517470 GameScene::CreateHeap +80517514 GameScene::DestroyHeap +8051755c GameScene::vf_0x5c +80517560 0x80517560 +80517804 GameScene::draw +805178c0 0x805178c0 +80517a5c GameScene::GetCurrent +80517a8c 0x80517a8c +80517b98 BaseScene::outgoing_child_create +80517b9c BaseScene::incoming_child_destroy +80517ba0 0x80517ba0 +80517ba4 0x80517ba4 +80517ba8 BaseScene::reinit +80517bac BaseScene::exit +80517bb0 BaseScene::enter +80517bb4 BaseScene::draw +80517bb8 BaseScene::calc +80517bbc 0x80517bbc +80517c14 RKG::ClearBuffer +80517c20 RKG::CheckHeader +80517cac RKGFile::CheckValidity +80517dc8 RKGFile::SetCRC32 +80517dfc GhostData::__ct +80517ec0 Timer::__dt +80517f00 Timer::__ct +80517f24 GhostData::__ct(RKG) +8051802c GhostData::Reset +805180b8 0x805180b8 +805180bc GhostData::ReadRKG +8051831c GhostData::Init +80518380 GhostData::FillHeader +80518598 GhostData::CreateRKGWithoutInputs +8051860c GhostData::CreateRKG +805186a8 GhostData::Fill +80518a08 Input::Controller::GetType +80518a10 0x80518a10 +80518a18 Input::ControllerHolder::GetInputsSize +80518a20 GhostGroup::__ct +80518b1c GhostData::__dt +80518b84 GhostGroup::__dt +80518bf0 GhostGroup::DisableGhostData +80518c10 GhostGroup::GetGhostData +80518c48 GhostGroup::ReadRKG +80518c6c RKG::CompressTo +80518d40 RKG::DecompressTo +80518f14 RKG::GetLength +80519060 HomeMenuMgr::CreateInstance +805190c0 HomeMenuMgr::DestroyInstance +80519110 HomeMenuMgr::__dt +80519174 HomeMenuMgr::LoadHBMArc +80519228 0x80519228 +8051922c HomeMenuMgr::__ct +80519420 HomeMenuMgr::ResetControllerData +805194a4 HomeMenuMgr::Open +80519580 HomeMenuMgr::Close +80519650 0x80519650 +805198fc HomeMenuMgr::UpdateControllerData +80519b04 HomeMenuMgr::UpdateLockParams +80519b4c 0x80519b4c +80519ca0 HomeMenuMgr::Calc +80519eec 0x80519eec +80519fac 0x80519fac +8051a100 0x8051a100 +8051a374 HomeMenuMgr::Draw +8051a3e8 Input::State::Reset +8051a428 Input::State::operator== +8051a490 Input::UIState::Reset +8051a4ec Input::State::SetStickXMirrorCheck +8051a574 Input::State::SetStickX +8051a5b4 Input::State::ConvertQuantised +8051a5ec Input::State::SetStickY +8051a62c Input::UIState::SetStickXMirrorCheck +8051a6b4 Input::UIState::SetStickY +8051a6f4 Input::State::SetControlMotionFlick +8051a734 Input::Controller::__ct +8051a820 Input::State::__dt +8051a860 Input::UIState::__dt +8051a8a0 Input::Controller::Update +8051ab98 Input::Controller::ResetSelf +8051ab9c Input::Controller::UpdateBatteryField +8051ac00 Input::Controller::GetRemainingBattery +8051ac08 Input::Controller::GetRuntimeTypeInfo +8051ac14 Input::WiiController::__ct +8051ad78 Input::Controller::__dt +8051adb8 Input::WiiController::Init +8051ae94 Input::Controller::Init +8051af08 Input::Controller::SetDriftType +8051af10 Input::WiiController::WPADInfoCallback +8051af40 Input::WiiController::UpdateBattery +8051af5c Input::WiiController::GetRemainingBattery +8051af9c Input::WiiController::UpdateStatesClassic +8051b608 Input::WiiController::UpdateStatesNunchuck +8051b76c Input::WiiController::UpdateStatesCore +8051b810 Input::WiiController::UpdateImpl +8051bb44 Input::WiiController::TogglePointer +8051bb5c Input::GCNController::__ct +8051bca4 Input::GCNController::Init +8051bd3c Input::GCNController::UpdateImpl +8051c288 Input::GCNController::HasRumble +8051c2bc Input::GhostController::__ct +8051c4b0 Input::GhostController::__dt +8051c524 Input::GhostController::Init +8051c5d8 Input::GhostController::HasRKGInputs +8051c5ec 0x8051c5ec +8051c6a4 0x8051c6a4 +8051c728 Input::GhostController::UpdateImpl +8051c8d8 Input::GhostDirectionStream::Read +8051ca40 Input::GhostDirectionStream::GetInputSize +8051ca48 Input::ControllerHolder::CreateRumbleController +8051cab8 Input::RealControllerHolder::SetDriftType +8051caf0 Input::ControllerHolder::__ct +8051cc9c Input::ControllerHolder::Init +8051cd24 Input::ControllerHolder::Update +8051d0e0 Input::RealControllerHolder::SetController +8051d160 Input::RealControllerHolder::StartGhostReading +8051d214 Input::RealControllerHolder::EndGhostWriting +8051d2f4 Input::RealControllerHolder::Update +8051d3d0 Input::RealControllerHolder::SetGhostController +8051d4bc Input::RealControllerHolder::PrepareForRace +8051d538 Input::AIControllerHolder::CopyCPUInputs +8051d5c0 Input::ControllerHolder::RequestRumble(3args) +8051d658 Input::ControllerHolder::RequestRumble(4args) +8051d910 Input::Controller::HasRumble +8051d918 0x8051d918 +8051d9d4 0x8051d9d4 +8051da5c Input::ControllerHolder::RequestRumbleByDuration +8051db18 Input::ControllerHolder::RequestRumbleByDurationNoFaderCheck +8051dba0 Input::ControllerHolder::StopAllRumble +8051dc04 Input::ControllerHolder::ActivateRumble +8051dc18 Input::Controller::ActivateRumble +8051dc1c Input::ControllerHolder::StopRumble +8051dc30 Input::ControllerHolder::StopCurrentRumble +8051dc34 Input::ControllerHolder::ResetSelfController +8051dc48 Input::RealControllerHolder::__ct +8051de40 Input::ControllerHolder::__dt +8051de80 Input::RealControllerHolder::__dt +8051dee4 Input::Manager::SetFSStickClamp +8051def0 Input::ControllerParams::Fill +8051e020 Input::Controller::GetChannel +8051e028 0x8051e028 +8051e098 0x8051e098 +8051e130 0x8051e130 +8051e214 0x8051e214 +8051e21c Input::Manager::ResetKPAD +8051e280 Input::ControllerHolder::CopyCPUInputs +8051e284 Input::RealControllerHolder::GetInputsSize +8051e28c Input::RealControllerHolder::GetRKGInputs +8051e294 Input::RealControllerHolder::Init +8051e328 Input::AIControllerHolder::__dt +8051e368 Input::AIController::__dt +8051e3a8 Input::Controller::IsPointerEnabled +8051e3b0 Input::Controller::TogglePointer +8051e3b4 Input::GhostController::SetDriftType +8051e3b8 Input::GhostController::GetType +8051e3c0 Input::Controller::Func_0x24 +8051e3cc Input::GCNController:ResetSelf +8051e3d8 Input::GCNController:StopRumble +8051e3e4 Input::GCNController:ActivateRumble +8051e3f0 Input::GCNController:GetChannel +8051e3f8 Input::GCNController:GetType +8051e400 Input::GCNController:__dt +8051e440 Input::WiiController::ResetSelf +8051e450 Input::WiiController::StopRumble +8051e45c Input::WiiController::ActivateRumble +8051e468 Input::WiiController::HasRumble +8051e480 Input::WiiController::IsPointerEnabled +8051e4b0 Input::WiiController::GetChannel +8051e4b8 Input::WiiController::GetType +8051e4c0 Input::WiiController::__dt +8051e500 Input::GhostDirectionStream::Write +8051e674 Input::GhostTrickStream::Write +8051e7e8 Input::GhostTrickStream::Read +8051e950 Input::GhostTrickStream::GetInputSize +8051e958 Input::GhostActionStream::Write +8051eacc Input::GhostActionStream::Read +8051ec34 Input::GhostActionStream::GetInputSize +8051ec3c Input_cpp_sinit_ +8051ec6c Input::Manager::SyncSimpleCallback +8051ecc8 Input::Manager::CreateInstance +8051ed18 Input::Manager::DestroyInstance +8051ed68 Input::Manager::__dt +8051ee3c Input::DummyController::__dt +8051ee7c Input::Manager::__ct +8051f02c Input::AIControllerHolder::__ct +8051f0ac Input::Manager::Init +8051f0b0 0x8051f0b0 +8051f138 Input::Manager::ResetIdleFrameCounter +8051f160 0x8051f160 +8051f21c Input::Manager::Prepare +8051f2b0 Input::Manager::ResetSelfWiiAndGCNControllers +8051f338 0x8051f338 +8051f374 Input::Manager::UpdateControllers +8051f47c Input::Manager::Update +8051f51c 0x8051f51c +8051f5e4 Input::Manager::ConvertType +8051f60c 0x8051f60c +8051f754 0x8051f754 +8051f89c 0x8051f89c +8051fa38 Input::Manager::ResetDummyController +8051fa48 Input::Manager::TrySetController +8051fc78 0x8051fc78 +8051fdf0 Input::Manager::ResetRealController +8051fe08 0x8051fe08 +8051fe64 Input::Manager::InitControllerHolders +8051ffc4 0x8051ffc4 +8052008c 0x8052008c +805200c8 Input::Manager::InitGhostController +805200e4 Input::Manager::PrepareRealControllerHolderForRace +805200f4 Input::Manager::EnableGhostReading +8052010c Input::Manager::StartGhostReading +80520158 Input::Manager::EndGhostWriting +80520168 Input::Manager::EndAllGhostWriting +805201b4 Input::Manager::CopyPADStatus +8052024c Input::Manager::InitRumble +805202a4 Input::Manager::ResetRumble +805202c0 0x805202c0 +80520314 Input::Manager::SyncWiimotes +80520370 0x80520370 +805203cc Input::Manager::EnableAllPointers +80520464 Input::Manager::ToggleAllPointers +805204d0 0x805204d0 +80520524 0x80520524 +8052053c Input::Manager::RequestRumbleByDuration +80520554 0x80520554 +805205dc 0x805205dc +805205e4 Input::AIController::UpdateImpl +80520634 Input::AIController::GetType +8052063c Input::DummyController::UpdateImpl +80520640 SITransferCommands +80520650 Input::GhostWriter::__ct +805207b8 Input::GhostWriter::__dt +80520834 Input::GhostWriter::Init +805208ac Input::GhostWriter::CopyToRKGInputsBuffer +8052095c Input::GhostWriter::IsInputsSumSmallEnough +80520a00 Input::GhostWriter::WriteFrame +80520b04 Input::GhostActionStream::WriteNewValue +80520b14 Input::GhostActionStream::IncrementDuration +80520b24 Input::GhostActionStream::IsNewInput +80520b48 Input::GhostActionStream::ReadValue +80520b50 Input::GhostActionStream::IsCurReadInputFinished +80520b6c Input::GhostDirectionStream::WriteNewValue +80520b7c Input::GhostDirectionStream::IncrementDuration +80520b8c Input::GhostDirectionStream::IsNewInput +80520bb0 Input::GhostDirectionStream::ReadValue +80520bb8 Input::GhostDirectionStream::IsCurReadInputFinished +80520bd4 Input::GhostTrickStream::WriteNewValue +80520be8 Input::GhostTrickStream::IncrementDuration +80520c00 Input::GhostTrickStream::IsNewInput +80520c28 Input::GhostTrickStream::ReadValue +80520c34 Input::GhostTrickStream::IsCurReadInputFinished +80520c54 Input::KRMMgr::Init +80520d90 Input::KRMMgr::__ct +80520e04 Input::Rumble::Init +80520e30 Input::Rumble::Request(KRMEntry) +80520e74 Input::Rumble::Request(float) +80520eb0 0x80520eb0 +80520ec0 Input::Rumble::Update +80521024 Input::RumbleController::__ct +80521094 Input::RumbleController::Init +80521148 Input::RumbleController::Stop +805211d8 Input::RumbleController::DeactivateRumble +80521298 Input::RumbleController::Update +80521500 Input::RumbleController::Request(KRMEntry) +80521600 Input::RumbleController::Request(float) +80521718 Input::RumbleController::GetFreeRumble +805217c4 Input::RumbleController::__dt +80521804 Input::Rumble::__dt +80521844 0x80521844 +80521914 0x80521914 +80521944 0x80521944 +8052198c 0x8052198c +805219ec 0x805219ec +80521b14 Mii::Init +80521b80 0x80521b80 +80521bac Mii::Load +80521f48 0x80521f48 +80521f8c 0x80521f8c +80521fec Mii::GetRFLArgs +805221c8 Mii::CreateScnRfl +80522340 0x80522340 +80522480 0x80522480 +80522588 0x80522588 +8052259c 0x8052259c +8052260c 0x8052260c +805226f0 MiiManager::Disposer__dt +80522788 MiiManager::CreateInstance +805227d8 0x805227d8 +8052280c MiiManager::__ct +805228c8 MiiManagerSub::__ct +805228e0 MiiManagerSub::__dt +80522920 MiiManager::Init +80522ce4 MiiManager::__dt +80522e24 MiiManager::CountOfficialMiis +80523024 0x80523024 +805230a0 MiiManager::GetMiddleDB3 +805230a8 0x805230a8 +80523118 Mii::ComputeRFLStoreData +80523178 Mii::IsMiiId +80523190 Mii::GetMiiId +8052326c MiiManager::GetStatus +8052328c MiiManager::IsOfficialOrDefaultMii +80523304 MiiManager::CreatePlayerMiiFromOfficial +80523698 MiiManager::CreateStoreMii(RFLCreateID) +805238ec MiiManager::CreateOfficialMii(RFLIdx) +80523a10 MiiManager::CreateOfficialMii(RFLCreateID) +80523b10 MiiManager::CreateDefaultMii(RFLIdx) +80523bf4 MiiManager::CreateDefaultMii(RFLCreateID) +80523cf8 MiiManager::CreateOfficialMii(IdxArray) +80523e1c MiiManager::AllowMiiDisplay +80523e3c MiiManager::CreateMiddleDBMii +80524124 MiiManager::CreateRandomMii +80524348 MiiManager::CreateMii(CreationParams) +80524a34 0x80524a34 +80524bc0 Mii::__dt +80524c00 MiiManager::CreateMiddleDB2Mii +80524ebc MiiManager::CreateMii(RFLStoreData) +80524fac MiiManager::CreateControllerMii +805250bc 0x805250bc +8052511c 0x8052511c +805251cc MiiManager::CreatePlayerMiiFromMiddleDB +805252bc MiiManager::PrepareRFLWiFiPacket +805252d4 MiiManager::RFLWiFiInfo2MiddleDB +80525324 MiiManager::RFLWiFiInfo2StoreData +80525370 MiiCreationParams::InitAndReset +80525390 MiiCreationParams::Init +805253b0 MiiCreationParams::Reset +805253e8 0x805253e8 +805253fc 0x805253fc +80525424 0x80525424 +80525488 0x80525488 +805254a8 0x805254a8 +805254c8 MiiCreationParams2::Init +80525504 MiiCreationParams2::Reset +80525530 0x80525530 +80525544 0x80525544 +8052556c 0x8052556c +805255d0 0x805255d0 +805255f0 0x805255f0 +80525610 0x80525610 +80525650 MovieManager::__ct +805256f4 MovieManager::__dt +80525770 MovieManager::IsMoviePlaying +80525798 MovieManager::DrawDone +805257cc MovieManager::Init +805257d4 MovieManager::Quit +805257d8 MovieManager::CheckForEnd +8052582c MovieManager::GetCurrentFrameNum +8052585c MovieManager::Prepare +805258f4 MovieManager::PrepareAsync +8052598c MovieManager::RequestPrepare +805259e8 MovieManager::Play +80525a30 MovieManager::PlayAsync +80525a78 MovieManager::RequestPlay +80525a90 MovieManager::Pause +80525ad0 MovieManager::PauseAsync +80525b10 MovieManager::RequestPause +80525b28 MovieManager::Close +80525b6c MovieManager::CloseAsync +80525bb0 MovieManager::RequestClose +80525bc8 MovieManager::SetVolume +80525bd4 MovieManager::GetVolume +80525bd8 MovieManager::FillCurTextureInfo +80525c24 ArchivesHolder::CreateByType +80525d54 CourseArchivesHolder::__ct +80525da8 CourseArchivesHolder::Reset +80525e34 UIArchivesHolder::__ct +80525e88 UIArchivesHolder::Reset +80525ef8 CommonArchivesHolder::__ct +80525f4c CommonArchivesHolder::Reset +80525fbc CourseArchivesHolder::__dt +80526014 UIArchivesHolder::__dt +8052606c CommonArchivesHolder::__dt +805260c4 ArchivesHolder::ArchiveHolder +805261d4 ArchivesHolder::Reset +80526268 ArchivesHolder::__dt +805262ec ArchivesHolder::GetFile +8052638c ArchivesHolder::HasArchives +805263f0 ArchivesHolder::FileExists +805264e0 ArchivesHolder::LoadArchives +80526614 ArchivesHolder::UnmountArchives +80526674 ArchivesHolder::LoadFromOther +805266f8 ArchivesHolder::DumpArchive +805267cc ArchivesHolder::ClearArchives +8052682c ArchivesHolder::GetTotalMountedArchivesSize +80526894 ArchivesHolder::GetFirstMountedArchive +8052690c ArchivesHolder::GetFirstMountedArchiveEnd +80526994 ArchivesHolder::GetLoadedArchivesCount +805269e8 NandUtils::SafeOpen +80526a64 NandUtils::SafeOpen_NandUtils::SafeOpen_switch +80526a68 NandUtils::SafeOpen_caseD_0 +80526a70 NandUtils::SafeOpen_caseD_-3 +80526a88 NandUtils::SafeOpen_caseD_-4 +80526a90 NandUtils::SafeOpen_caseD_-15 +80526a98 NandUtils::SafeOpen_caseD_-12 +80526aa0 NandUtils::SafeOpen_caseD_-14 +80526af0 NandUtils::Open +80526be4 NandUtils::SafeClose +80526cd0 NandUtils::Close +80526db4 NandUtils::Read +80526f84 NandUtils::GetLength +80527060 NandUtils::Write +80527210 NandUtils::Check +805272e0 NandUtils::CreateDir +805273d8 NandUtils::GetType +805274e8 NandUtils::Create +805275e0 NandUtils::Delete +805276cc NandUtils::SetStatus +805277c8 NandUtils::GetStatus +805278c4 NandUtils::FileExists +805278e8 NandMgr::Disposer_dt +80527980 NandMgr::CreateInstance +80527a24 NandMgr::DestroyInstance +80527a58 NandMgr::__ct +80527ad0 NandMgr::__dt +80527b84 NandMgr::Init +80527c3c NandMgr::ReadRKSYS +80527cf4 NandMgr::ReadFile +80527d98 NandMgr::CheckRKSYSLength +80527e5c NandMgr::WriteToRKSYS +80527fb4 NandMgr::WriteFile +80528078 0x80528078 +8052815c 0x8052815c +80528218 NandMgr::CreateRKSYS +80528370 NandMgr::DeleteRKSYS +8052869c NandMgr::GetBannerType +805286f8 0x805286f8 +80528830 0x80528830 +80528954 0x80528954 +805289e4 0x805289e4 +80528a84 0x80528a84 +80528b98 0x80528b98 +80528bf4 0x80528bf4 +80528ca4 0x80528ca4 +80528d4c 0x80528d4c +80528dfc RKSYS::Rating::AddPoints +80528e24 RacedataPlayer::__ct +80528ec8 RKSYS::Rating::__dt +80528f08 RacedataPlayer::RegisterPlayerParams +80528fa8 RacedataPlayer::ComputeGPRank +80529080 RacedataScenario::__ct +80529120 RacedataPlayer::__dt +80529160 RacedataScenario::BlueTeamHasMorePoints +805291d0 RacedataPlayer::GetTeam +805291d8 RacedataScenario::GetPlayer(const) +805291e8 RacedataPlayer::GetPlayerCount +805291f8 Racedata::Init +805298e4 RacedataPlayer::SetCharacterId +805298ec RacedataScenario::GetPlayer +805298fc RacedataPlayer::SetKartId +80529904 RacedataPlayer::SetPlayerType +8052990c Racedata::ResetScenarios +80529af8 RacedataPlayer::ResetScores +80529b10 RacedataPlayer::SetPrevFinishPos +80529b18 0x80529b18 +80529b20 0x80529b20 +80529c1c 0x80529c1c +80529c20 0x80529c20 +80529c24 0x80529c24 +80529c28 0x80529c28 +80529d28 0x80529d28 +80529e08 RacedataScenario::UpdatePoints +8052a1d0 RacedataScenario::GetGameType +8052a1d8 RacedataPlayer::GetPlayerType +8052a1e0 RacedataScenario::InitControllers +8052a3a8 RacedataScenario::InitGhostPlayer +8052a48c 0x8052a48c +8052a51c 0x8052a51c +8052a698 RacedataScenario::UpdateFromPrevRace +8052a9a0 RacedataScenario::InitScreens +8052ac40 RacedataScenario::ComputePlayerCounts +8052addc RacedataScenario::InitRng +8052aec4 RacedataScenario::InitCompetitionSettings +8052b048 RacedataScenario::Init +8052b310 Racedata::CreateInstance +8052b4a0 Racedata::DestroyInstance +8052b4f0 Racedata::__dt +8052b5ac RacedataScenario::__dt +8052b614 Racedata::__ct +8052b77c Racedata::InitRace +8052ba64 RacedataScenario::operator= +8052bd1c Racedata::InitAwards +8052c3c4 RacedataScenario::AreTeamsEnabled +8052c3d0 0x8052c3d0 +8052c3d8 RacedataPlayer::GetCharacterId +8052c3e0 RacedataPlayer::GetKartId +8052c3e8 RacedataPlayer::SetMii +8052c520 RacedataPlayer::GetMii +8052c528 Racedata::InitCredits +8052d19c Racedata::UpdatePrevFromCur +8052d29c RacedataScenario::RegisterParameters +8052d3d0 Racedata::GetHudSlotId +8052d3e4 Racedata::SetGhost +8052d428 Racedata::GetPlayerIdOfLocalPlayer +8052d438 Racedata::HandleRaceFinish? +8052d480 Racedata::LoadNextGPTrack +8052d4e8 Racedata::IsTTReplay +8052d528 Racedata::vf_0x18 +8052d52c Racedata::vf_0x14 +8052d530 Racedata::vf_0x10 +8052d534 0x8052d534 +8052d53c Raceinfo::CreateInstance +8052d58c Raceinfo::DestroyInstance +8052d5dc GMDataGP::__ct +8052d640 Raceinfo::CreateGMData +8052d680 Raceinfo::CreateGMData_Raceinfo::CreateGMData_switch +8052d684 Raceinfo::CreateGMData_case_0 +8052d6d8 Raceinfo::CreateGMData_case_1 +8052d700 Raceinfo::CreateGMData_case_4 +8052d70c Raceinfo::CreateGMData_case_3 +8052d780 Raceinfo::CreateGMData_case_7 +8052d898 Raceinfo::CreateGMData_case_9 +8052d8fc Raceinfo::CreateGMData_case_2 +8052d940 GMDataOnlineVSPlayer::__ct +8052d964 GMDataOnlineVSPlayer::__dt +8052d9a4 0x8052d9a4 +8052d9e4 0x8052d9e4 +8052da24 0x8052da24 +8052da64 0x8052da64 +8052daa4 0x8052daa4 +8052dae4 0x8052dae4 +8052db24 0x8052db24 +8052db64 0x8052db64 +8052dba4 Raceinfo::GetBattleDuration +8052dc58 Raceinfo::__ct +8052e1fc RaceTimerMgrBase::Reset +8052e298 RaceTimerMgrBase::__dt +8052e2f4 Raceinfo::__dt +8052e400 RaceinfoPlayer::__dt +8052e440 Raceinfo::Init +8052e544 GMData::Init +8052e548 Raceinfo::GetRemainingCountdownTime +8052e578 Raceinfo::ComputeDelfinoPierTideState +8052e66c Raceinfo::Update +8052eb58 RaceTimerMgrBase::Update +8052eb5c Raceinfo::GetLapCount +8052eb90 GMData::HandlePositionTracking +8052efb4 0x8052efb4 +8052f0a0 GMData::vf_0x20 +8052f0a4 0x8052f0a4 +8052f0ec GMData::vf_0x24 +8052f124 Raceinfo::EndPlayerRace +8052f23c Raceinfo::SetPlayerDisconnected +8052f28c 0x8052f28c +8052f390 RaceinfoPlayer::__ct +8052f64c 0x8052f64c +8052f7a0 RaceinfoPlayer::UpdateRealLocal +8052fb3c 0x8052fb3c +8052fcac RaceinfoPlayer::EndRace +8052fdec 0x8052fdec +8052fe70 RaceinfoPlayer::EndLap +80530130 RaceinfoPlayer::Vanish +80530174 RaceinfoPlayer::Disconnect +80530184 0x80530184 +80530224 0x80530224 +805302b0 RaceinfoPlayer::UpdateCheckPoint +805306c4 0x805306c4 +805307bc RaceinfoPlayer::Update +80530b50 0x80530b50 +80530b54 0x80530b54 +80530bd0 RaceinfoPlayer::CopyCPUInputs +80530be4 RaceinfoPlayer::FillTimerWithLapSplits +80530d1c RaceTimerMgr::Reset +80530dbc RaceTimerMgr::Update +80531158 Raceinfo::CloneTimer +805311cc GMDataTT::CanRaceEnd +805312a0 GMData::UpdateLocalPlayer +8053133c GMData::Update +805313ac GMData::GetJGPTHolder +805313e0 GMDataGP::CanRaceEnd +8053149c GMDataGP::Update +8053150c GMDataVS::CanRaceEnd +805316c0 Raceinfo::CanRaceEnd +805316d4 Raceinfo::GetJGPTHolder +805316e8 Raceinfo::IsAtLeastStage +80531700 0x80531700 +80531794 Raceinfo::GetInitialPhysicsValues +805317dc Raceinfo::GetInitialPhysicsValues::switch +805317e0 Raceinfo::GetInitialPhysicsValues::case_3 +80531908 Raceinfo::GetInitialPhysicsValues::case_b +8053193c Raceinfo::GetInitialPhysicsValues::case_c +8053194c Raceinfo::GetInitialPhysicsValues::case_2 +8053195c Raceinfo::GetInitialPhysicsValues::case_4 +805319f8 Raceinfo::GetInitialPhysicsValues::case_0 +80531a80 Raceinfo::GetKTPTHolder +80531acc Raceinfo::GetKTPTHolder_switch +80531ad0 Raceinfo::GetKTPTHolder_case_3 +80531bf0 Raceinfo::GetKTPTHolder_case_4 +80531c70 Raceinfo::GetKTPTHolder_case_b +80531c9c Raceinfo::GetKTPTHolder_case_c +80531ca4 Raceinfo::GetKTPTHolder_case_2 +80531cac Raceinfo::GetKTPTHolder_case_0 +80531ce0 Raceinfo::GetStartENPT +80531d7c Raceinfo::GetRawKRT +80531db0 RaceinfoPlayer::ComputeGPRank +8053213c 0x8053213c +80532648 0x80532648 +8053265c GMData::vf_0x28 +80532660 0x80532660 +805326a0 0x805326a0 +80532704 0x80532704 +8053276c 0x8053276c +80532774 0x80532774 +805327d8 0x805327d8 +80532840 0x80532840 +80532848 0x80532848 +805328ac 0x805328ac +80532914 0x80532914 +8053291c 0x8053291c +80532980 0x80532980 +805329e8 0x805329e8 +805329f0 0x805329f0 +80532a54 0x80532a54 +80532abc 0x80532abc +80532ac4 0x80532ac4 +80532b28 0x80532b28 +80532b90 0x80532b90 +80532b98 RaceTimerMgr::__dt +80532bf8 0x80532bf8 +80532ce8 Vec3::Cross +80532d34 0x80532d34 +80533038 Mtx34::GetColumnByIdx +8053305c 0x8053305c +8053310c 0x8053310c +8053314c 0x8053314c +8053318c 0x8053318c +80533450 0x80533450 +8053353c 0x8053353c +80533628 0x80533628 +8053365c 0x8053365c +805336d8 0x805336d8 +805337d4 KMGHolder::SetKMG +805337fc KMGHolder::ConvertArenaIdToIdx +805338d0 GMDataBattle::HandlePositionTracking +80533c28 GMDataBalloonBattle::OnItemCollision +80533e4c GMDataBalloonBattle::OnKartCollision +80534078 GMDataBalloonBattle::OnOOBCollision +80534198 0x80534198 +805342b8 0x805342b8 +8053436c 0x8053436c +80534408 GMDataOnlineBalloonBattle::GetKMGSeconds2 +80534410 GMDataOnlineBalloonBattle::GetKMGSeconds3 +80534418 0x80534418 +805344a4 GMDataBattle::Init +80534694 GMDataOnlineBalloonBattle::GetKMGSeconds1 +8053469c GMDataBattle::GetJGPTHolder +8053479c 0x8053479c +805348bc 0x805348bc +80534a2c GMDataBalloonBattle::Update +80534c28 GMDataBalloonBattle::CanRaceEnd +80534cdc GMDataCoinBattle::Update +80534f3c GMDataCoinBattle::CanRaceEnd +80534f48 GMDataCoinBattle::OnItemCollision +80534fe8 GMDataCoinBattle::OnKartCollision +805350a0 GMDataCoinBattle::OnOOBCollision +805350f4 GMDataOnlineBalloonBattle::Init +80535440 GMDataOnlineBalloonBattle::__ct +80535638 0x80535638 +80535678 0x80535678 +805356b8 0x805356b8 +805356f8 0x805356f8 +80535738 0x80535738 +80535778 0x80535778 +805357b8 0x805357b8 +805357f8 0x805357f8 +80535838 0x80535838 +80535878 0x80535878 +80535bd8 0x80535bd8 +80535c3c 0x80535c3c +80535c44 0x80535c44 +80535ca8 0x80535ca8 +80535cb0 0x80535cb0 +80535d20 0x80535d20 +80535d28 0x80535d28 +80535d8c 0x80535d8c +80535d94 0x80535d94 +80535df8 0x80535df8 +80535e00 0x80535e00 +80535e64 0x80535e64 +80535e6c 0x80535e6c +80535ed0 0x80535ed0 +80535ed8 0x80535ed8 +80536094 0x80536094 +805360b4 0x805360b4 +805360d4 0x805360d4 +80536560 0x80536560 +805365c8 0x805365c8 +80536630 0x80536630 +805366b0 0x805366b0 +80536718 0x80536718 +80536780 0x80536780 +805367e8 0x805367e8 +80536850 0x80536850 +80536884 0x80536884 +80536984 GMDataOnlineBalloonBattle::OnItemCollision +80536a3c GMDataOnlineBalloonBattle::OnKartCollision +80536af4 GMDataOnlineBalloonBattle::OnOOBCollision +80536ba0 GMDataOnlineBalloonBattle::vf_0x3c +80536bb0 0x80536bb0 +80536c5c GMDataOnlineBalloonBattle::OnObjectCollision +80536d08 0x80536d08 +80536d3c 0x80536d3c +80536dc8 0x80536dc8 +80536e44 0x80536e44 +80536f58 0x80536f58 +805370ac GMDataOnlineBalloonBattle::Update +80537214 GMDataOnlineBalloonBattle::Update_switch +80537218 GMDataOnlineBalloonBattle::Update_case_1 +8053722c GMDataOnlineBalloonBattle::Update_case_2 +8053723c GMDataOnlineBalloonBattle::Update_case_3 +80537250 GMDataOnlineBalloonBattle::Update_case_4 +805372d4 GMDataOnlineBalloonBattle::Update_case_5 +805372e4 GMDataOnlineBalloonBattle::Update_case_6 +80537328 GMDataOnlineBalloonBattle::Update_case_7 +80537330 GMDataOnlineBalloonBattle::Update_case_0 +80537334 GMDataOnlineBalloonBattle::Update_case_8 +80537fe4 0x80537fe4 +80538080 0x80538080 +805382c8 0x805382c8 +80538518 0x80538518 +80538658 0x80538658 +80538718 0x80538718 +80538858 GMDataOnlineBalloonBattle::vf_0x28 +805388e0 GMDataOnlineCoinBattle::Update +80538d00 0x80538d00 +80538d70 GMDataBattle::vf_0x3c +80538d74 GMDataCoinBattle::OnObjectCollision +80538d78 GMDataCoinBattle::GetKMGSeconds3 +80538d94 GMDataCoinBattle::GetKMGSeconds2 +80538db0 GMDataCoinBattle::GetKMGSeconds1 +80538dcc GMDataOnlineBalloonBattle::CanRaceEnd +80538dd4 GMDataBalloonBattle::GetKMGSeconds3 +80538df0 GMDataBalloonBattle::GetKMGSeconds2 +80538e0c GMDataBalloonBattle::GetKMGSeconds1 +80538e28 0x80538e28 +80538e2c 0x80538e2c +80538e30 0x80538e30 +80538e34 GMDataOnlineVS::Init +80538f40 0x80538f40 +80539144 0x80539144 +80539270 0x80539270 +80539680 0x80539680 +80539704 0x80539704 +8053982c 0x8053982c +80539914 0x80539914 +80539a98 0x80539a98 +80539c48 0x80539c48 +80539d68 GMDataOnlineVS::Update +80539f64 GMDataOnlineVS::HandlePositionTracking +8053a4d4 GMDataOnlineVS::CanRaceEnd +8053a5fc GMDataOnlineVS::vf_0x24 +8053a65c GMDataOnlineVS::UpdateLocalPlayers +8053a710 ArchiveMgr::CreateInstance +8053a760 ArchiveMgr::DestroyInstance +8053a7b0 ArchiveMgr::__ct +8053a92c AllkartArchivesLoader::__ct +8053a958 AllkartArchivesLoader::__dt +8053a998 0x8053a998 +8053a9d8 0x8053a9d8 +8053a9e0 ArchiveMgr::__dt +8053aafc ArchiveMgr::LoadArchiveAsync +8053ab64 ArchiveMgr::WaitForLoad +8053acb0 0x8053acb0 +8053acc0 0x8053acc0 +8053acd0 ArchiveMgr::LoadArchive(holder) +8053ad84 ArchiveMgr::LoadArchive(file) +8053ae58 ArchiveMgr::LoadArchive(holder, 2heaps) +8053af14 ArchiveMgr::LoadArchive(type) +8053b01c ArchiveMgr::LoadContentArchive +8053b144 ArchiveMgr::LoadUIArchive +8053b224 ArchiveMgr::LoadCourseArchive +8053b3dc ArchiveRoot_loadMissionTrack +8053b5d8 ArchiveMgr::LoadCompetitionArchives +8053b7c0 ArchiveMgr::LoadKartArchive(holder) +8053b900 ArchiveMgr::LoadKartArchive(playerId) +8053ba54 ArchiveMgr::LoadKartArchiveHolder2(playerId) +8053bba8 0x8053bba8 +8053bc98 ArchiveMgr::Unmount(source) +8053bca8 ArchiveMgr::Unmount(holder) +8053bcb0 ArchiveMgr::UnmountContentArchive +8053bcc0 ArchiveMgr::GetFile +8053bd3c ArchiveMgr::GetMenuKartBRRES +8053bde4 ArchiveMgr::GetKartBRRES +8053be8c ArchiveMgr::GetKartArchiveFile +8053befc ArchiveMgr::GetKartArchiveFileHolder2 +8053bf6c ArchiveMgr::GetBSP +8053c020 ArchiveMgr::GetContentFileNewBuffer +8053c078 ArchiveMgr::HasArchives +8053c088 ArchiveMgr::HasKartArchive +8053c098 ArchiveMgr::HasKartArchiveHolder2 +8053c0a8 ArchiveMgr::HasContentArchive +8053c0d8 ArchiveMgr::GetArchive +8053c160 ArchiveMgr::SetLayoutResources +8053c1fc ArchiveMgr::GetArchiveCount +8053c258 ArchiveMgr::GetUIArchiveCount +8053c268 ArchiveMgr::AttachUIAccessor +8053c33c ArchiveMgr::AttachLayoutResources +8053c45c ArchiveMgr::LoadCourseArchiveAsync +8053c470 ArchiveMgr::RequestLoadCourseArchiveAsync +8053c48c ArchiveMgr::GetKartArchivePostfix +8053c4b0 ArchiveMgr::GetKartArchivePrefix +8053c4d4 AsyncCourseArchiveLoader::__ct +8053c534 AsyncCourseArchiveLoader::Init +8053c588 AsyncCourseArchiveLoader::__dt +8053c61c AsyncCourseArchiveLoader::Load +8053c6dc AsyncCourseArchiveLoader::CopyToHolder +8053c6fc 0x8053c6fc +8053c70c ArchiveMgr::ExecuteTask +8053c780 ArchiveMgr::RequestTask +8053c7a4 ArchiveMgr::ProcessRequestsAndShutdown +8053c908 ArchiveMgr::LoadKartArchiveAsync +8053caf4 0x8053caf4 +8053ccd4 ArchiveMgr::RequestLoadKartArchives +8053cd90 ArchiveMgr::InitAllkartArchivesLoaders +8053ce80 ArchiveMgr::ResetAllkartArchivesLoaders +8053cf40 ArchiveMgr::GetAllKartLoaderHeap +8053cf50 ArchiveMgr::LoadEarthBrres(heap) +8053cfe8 ArchiveMgr::CreateEarthHeap +8053d048 ArchiveMgr::DestroyEarthHeap +8053d094 ArchiveMgr::LoadEarthBrresAsync +8053d158 ArchiveMgr::LoadEarthBrres +8053d218 ArchiveMgr::RequestLoadEarthBrres +8053d280 ArchiveMgr::LoadStaffGhostAsync +8053d32c 0x8053d32c +8053d33c RootScene::__ct +8053d46c RootScene::__dt +8053d4d4 RootScene::SetHeapsGroupId +8053d4dc RootScene::CreateArchiveMgr +8053d544 RootScene::CreateGroup1Instances +8053d5a4 RootScene::CreateAudioMgr +8053d620 RootScene::CreateScnMgrCreator +8053d664 RootScene::CreateRacedata +8053d6a8 RootScene::CreateEffectsMgr +8053d6f0 RootScene::CreateHomeMenuMgr +8053d738 RootScene::CreateRKNetInstances +8053d788 RootScene::CreateUIInstances +8053d7d0 0x8053d7d0 +8053d810 RootScene::CreateInstances +8053e378 RootScene::InitInstances +8053e590 0x8053e590 +8053e5d0 0x8053e5d0 +8053e5d4 RootScene::RequestRootScene +8053e640 0x8053e640 +8053e648 RootScene::enter +8053e748 RootScene::exit +8053e74c RootScene::calc +8053e750 RootScene::draw +8053e754 0x8053e754 +8053e7dc RKSYS::Mgr::Disposer__dt +8053e874 RKSYS::Mgr::CreateInstance +8053e9a0 RKSYS::Mgr::DestroyInstance +8053e9d4 RKSYS::Mgr::__ct +8053ead0 RKSYS::LicenseMgr::__ct +8053ed60 RKSYS::LicenseCup::__ct +8053ed84 Timer::__ct(bool) +8053edd4 Timer::SetActive +8053eddc RKSYS::LicenseCup::__dt +8053ee1c RKSYS::LicenseLdbEntry::__ct +8053ee40 RKSYS::LicenseLdbEntry::__dt +8053ee80 RKSYS::LicenseUnkTimer::__ct +8053eea4 RKSYS::LicenseUnkTimer::__dt +8053eee4 RKSYS::LicenseFriends::__dt +8053ef24 RKSYS::LicenseCompletion::__ct +8053ef48 RKSYS::LicenseCompletion::__dt +8053ef88 RKSYS::LicenseStaffGhostStatus::__ct +8053ef94 RKSYS::Rating::__ct +8053efac RKSYS::LicenseUnkTimer2::__ct +8053efd0 RKSYS::LicenseUnkTimer2::__dt +8053f010 RKSYS::LicenseMgr::SetInitialized +8053f01c RKSYS::LicenseMgr::__dt +8053f0d0 RKSYS::Mgr::__dt +8053f1ac 0x8053f1ac +8053f2e8 RKSYS::Mgr::RequestTask +8053f304 RKSYS::Mgr::LoadTask +8053f310 RKSYS::Mgr::LoadRKSYS +8053f4fc RKSYS::Mgr::Init +8053f520 RKSYS::Mgr::SaveCoreTask +8053f5a0 RKSYS::Mgr::SaveCoreImpl +8053f60c RKSYS::Mgr::SaveCore +8053f688 RKSYS::Mgr::WriteLicenses +8053f6f0 RKSYS::Mgr::WriteCoreAndRequestSaveCore +8053f79c RKSYS::LicenseMgr::SetCurLicense +8053f7d4 RKSYS::Mgr::CheckLicenseMagic +8053f804 RKSYS::Mgr::ReadLicense +805400a4 RKSYS::LicenseMgr::ReadMiiName +8054011c RKSYS::LicenseMgr::GetMiiName +80540120 RKSYS::LicenseMgr::ReadRFLCreateID +80540174 RKSYS::LicenseMgr::SetRFLCreateID +805401b8 RKSYS::LicenseMgr::ReadDWCAccUserData +8054025c RKSYS::LicenseMgr::SetDWCUserData +805402f4 RKSYS::LicenseMgr::ReadFriendData +80540318 RKSYS::LicenseMgr::GetFriends +80540320 RKSYS::LicenseMgr::ReadCup +805403f8 RKSYS::LicenseMgr::GetCup +80540410 RKSYS::LicenseMgr::ReadLdbEntry +805404c4 RKSYS::LicenseMgr::GetLdbEntry(SaveCourseId) +805404dc RKSYS::LicenseMgr::ReadUnkTimer +80540558 RKSYS::LicenseMgr::GetUnkTimer +80540568 RKSYS::LicenseMgr::ReadCompletion +8054059c RKSYS::LicenseMgr::SetCompletion +805405c4 RKSYS::LicenseMgr::ReadPBGhostBitfield +805405e0 RKSYS::LicenseMgr::SetPBGhostBitfield +805405ec RKSYS::LicenseMgr::ReadDLGhostBitfield +80540608 RKSYS::LicenseMgr::SetDLGhostBitfield +80540614 RKSYS::LicenseMgr::SetRKPDEA_2 +80540620 RKSYS::LicenseMgr::ReadRKPDEA_2 +80540648 RKSYS::LicenseMgr::ReadStaffGhostStatus +8054066c RKSYS::LicenseMgr::SetStaffGhostStatus +80540684 RKSYS::LicenseMgr::SetRKPD1BC_31 +80540690 RKSYS::LicenseMgr::ReadRKPD1BC_31 +805406ac RKSYS::LicenseMgr::GetRKPDVR +805406c8 RKSYS::LicenseMgr::SetVR +805406d8 RKSYS::LicenseMgr::GetRKPDBR +805406f4 RKSYS::LicenseMgr::SetBR +80540704 RKSYS::LicenseMgr::SetOfflineVSWins +80540724 RKSYS::LicenseMgr::ReadOfflineVSWins +8054073c RKSYS::LicenseMgr::SetOfflineVSLosses +8054075c RKSYS::LicenseMgr::ReadOfflineVSLosses +80540774 RKSYS::LicenseMgr::SetOfflineBattleWins +80540794 RKSYS::LicenseMgr::ReadOfflineBattleWins +805407ac RKSYS::LicenseMgr::SetOfflineBattleLosses +805407cc RKSYS::LicenseMgr::ReadOfflineBattleLosses +805407e4 RKSYS::LicenseMgr::SetWFCVSWins +80540804 RKSYS::LicenseMgr::ReadWFCVSWins +8054081c RKSYS::LicenseMgr::SetWFCVSLosses +8054083c RKSYS::LicenseMgr::ReadWFCVSLosses +80540854 RKSYS::LicenseMgr::SetWFCBattleWins +80540874 RKSYS::LicenseMgr::ReadWFCBattleWins +8054088c RKSYS::LicenseMgr::SetWFCBattleLosses +805408ac RKSYS::LicenseMgr::ReadWFCBattleLosses +805408c4 RKSYS::LicenseMgr::SetGhostRacesWins +805408e4 RKSYS::LicenseMgr::ReadGhostRacesWins +805408fc RKSYS::LicenseMgr::SetGhostRacesLosses +8054091c RKSYS::LicenseMgr::ReadGhostRacesLosses +80540934 RKSYS::LicenseMgr::SetTotalRacePlayed +80540954 RKSYS::LicenseMgr::ReadTotalRacePlayed +8054096c RKSYS::LicenseMgr::SetTotalBattlePlayed +8054098c RKSYS::LicenseMgr::ReadTotalBattlePlayed +805409a4 RKSYS::LicenseMgr::SetRacesOnWheel +805409c4 RKSYS::LicenseMgr::ReadRacesOnWheel +805409dc RKSYS::LicenseMgr::SetBattlesOnWheel +805409fc RKSYS::LicenseMgr::ReadBattlesOnWheel +80540a14 RKSYS::LicenseMgr::ReadDistanceTravelled +80540a2c RKSYS::LicenseMgr::SetDistanceTravelled +80540a68 RKSYS::LicenseMgr::SetGhostDataChallengesSent +80540a88 RKSYS::LicenseMgr::ReadGhostDataChallengesSent +80540aa0 RKSYS::LicenseMgr::SetGhostDataChallengesReceived +80540ac0 RKSYS::LicenseMgr::ReadGhostDataChallengesReceived +80540ad8 RKSYS::LicenseMgr::SetItemHitsDelivered +80540af8 RKSYS::LicenseMgr::ReadItemHitsDelivered +80540b10 RKSYS::LicenseMgr::SetItemHitsReceived +80540b30 RKSYS::LicenseMgr::ReadItemHitsReceived +80540b48 RKSYS::LicenseMgr::SetTricksPerformed +80540b68 RKSYS::LicenseMgr::ReadTricksPerformed +80540b80 RKSYS::LicenseMgr::SetTimes1stPlaceAchieved +80540ba0 RKSYS::LicenseMgr::ReadTimes1stPlaceAchieved +80540bb8 RKSYS::LicenseMgr::ReadDistancetravelledwhilein1stplace +80540bd0 RKSYS::LicenseMgr::SetDistancetravelledwhilein1stplace +80540c0c RKSYS::LicenseMgr::ReadDistancetravelledonVSRaces +80540c24 RKSYS::LicenseMgr::SetDistancetravelledonVSRaces +80540c60 RKSYS::LicenseMgr::SetCompetitionsEntered +80540c80 RKSYS::LicenseMgr::ReadCompetitionsEntered +80540c98 RKSYS::LicenseMgr::SetRacesOnCharacter +80540cc0 RKSYS::LicenseMgr::ReadRacesOnCharacter +80540ce0 RKSYS::LicenseMgr::SetRacesOnKart +80540d08 RKSYS::LicenseMgr::ReadRacesOnKart +80540d28 RKSYS::LicenseMgr::SetRacesOnTrack +80540d50 RKSYS::LicenseMgr::ReadRacesOnTrack +80540d70 RKSYS::LicenseMgr::SetRacesOnBattleArena +80540d98 RKSYS::LicenseMgr::ReadRacesOnBattleArena +80540db8 RKSYS::LicenseMgr::SetUnk55f0 +80540dd4 RKSYS::LicenseMgr::ReadUnk55f0 +80540e10 RKSYS::LicenseMgr::SetDefaultDrift +80540e1c RKSYS::LicenseMgr::ReadDefaultDrift +80540e38 RKSYS::LicenseMgr::Set CC +80540e4c RKSYS::LicenseMgr::ReadCC +80540e70 RKSYS::LicenseMgr::SetCPUDifficulty +80540e84 RKSYS::LicenseMgr::ReadCPUDifficulty +80540ea8 RKSYS::LicenseMgr::SetVehicleType +80540ebc RKSYS::LicenseMgr::ReadVehicleType +80540ee0 RKSYS::LicenseMgr::SetCourseChoice +80540ef4 RKSYS::LicenseMgr::ReadCourseChoice +80540f18 RKSYS::LicenseMgr::SetItemsType +80540f2c RKSYS::LicenseMgr::ReadItemsType +80540f50 RKSYS::LicenseMgr::SetTotalRaceCount +80540f64 RKSYS::LicenseMgr::ReadTotalRaceCount +80540f88 RKSYS::LicenseMgr::ReadUnkTimer2 +80540ff0 RKSYS::LicenseMgr::SetUnkTimer2 +80541030 RKSYS::LicenseMgr::ReadRKPD_1BC +80541090 RKSYS::LicenseMgr::SetRKPD_1BC +805410bc RKSYS::LicenseMgr::ReadRKPD_5680 +80541124 RKSYS::LicenseUnk5680::Set +80541178 RKSYS::LicenseMgr::SetRKPD_5680 +805411a0 RKSYS::LicenseMgr::ReadRKPD_5688 +805411f8 RKSYS::LicenseMgr::SetRKPD_5688 +80541208 RKSYS::LicenseMgr::ReadRKPD_568c +80541240 RKSYS::LicenseMgr::SetRKPD_568c +8054126c RKSYS::LicenseMgr::SetRKPD_568c_31 +80541278 RKSYS::LicenseMgr::ReadRKPD_5688_31 +80541294 RKSYS::LicenseMgr::WriteToRKPD +80541a78 RKSYS::LicenseMgr::IsInitialized +80541a84 RKSYS::LicenseMgr::WriteMiiName +80541aa0 RKSYS::LicenseMgr::GetMiiName +80541aa4 RKSYS::LicenseMgr::WriteRFLCreateID +80541af8 RKSYS::LicenseMgr::GetRFLCreateID +80541b00 RKSYS::LicenseMgr::WriteDWCAccUserData +80541b94 RKSYS::LicenseMgr::GetDWCAccUserData +80541ba0 RKSYS::LicenseMgr::WriteFriendData +80541bc0 RKSYS::LicenseMgr::GetFriends +80541bc8 RKSYS::LicenseMgr::WriteCup +80541bec RKSYS::LicenseMgr::GetCup +80541c04 RKSYS::LicenseMgr::WriteLdbEntry +80541d30 RKSYS::LicenseMgr::GetLdbEntry +80541d48 RKSYS::LicenseMgr::WriteUnkTimer +80541e38 RKSYS::LicenseMgr::GetUnkTimer +80541e48 RKSYS::LicenseMgr::WriteCompletion +80541e7c RKSYS::LicenseMgr::GetCompletion +80541e88 RKSYS::LicenseMgr::WritePBGhostBitfield +80541ea0 RKSYS::LicenseMgr::GetPBGhostBitfield +80541eac RKSYS::LicenseMgr::WriteDLGhostBitfield +80541ec4 RKSYS::LicenseMgr::GetDLGhostBitfield +80541ed0 RKSYS::LicenseMgr::WriteRKPD_EA_2 +80541ef0 RKSYS::LicenseMgr::GetRKPD_EA_2 +80541efc RKSYS::LicenseMgr::WriteRKPD1BC_31 +80541f1c RKSYS::LicenseMgr::GetRKPD1BC_31 +80541f28 RKSYS::LicenseMgr::WriteVR +80541f44 RKSYS::LicenseMgr::GetVR +80541f50 RKSYS::LicenseMgr::WriteBR +80541f6c RKSYS::LicenseMgr::GetBR +80541f78 RKSYS::LicenseMgr::WriteOfflineVSWins +80541f90 RKSYS::LicenseMgr::GetOfflineVSWins +80541f9c RKSYS::LicenseMgr::WriteOfflineVSLosses +80541fb4 RKSYS::LicenseMgr::GetOfflineVSLosses +80541fc0 RKSYS::LicenseMgr::WriteOfflineBattleWins +80541fd8 RKSYS::LicenseMgr::GetOfflineBattleWins +80541fe4 RKSYS::LicenseMgr::WriteOfflineBattleLosses +80541ffc RKSYS::LicenseMgr::GetOfflineBattleLosses +80542008 RKSYS::LicenseMgr::WriteWFCVSWins +80542020 RKSYS::LicenseMgr::GetWFCVSWins +8054202c RKSYS::LicenseMgr::WriteWFCVSLosses +80542044 RKSYS::LicenseMgr::GetWFCVSLosses +80542050 RKSYS::LicenseMgr::WriteWFCBattleWins +80542068 RKSYS::LicenseMgr::GetWFCBattleWins +80542074 RKSYS::LicenseMgr::WriteWFCBattleLosses +8054208c RKSYS::LicenseMgr::GetWFCBattleLosses +80542098 RKSYS::LicenseMgr::WriteGhostRacesWins +805420b0 RKSYS::LicenseMgr::GetGhostRacesWins +805420bc RKSYS::LicenseMgr::WriteGhostRacesLosses +805420d4 RKSYS::LicenseMgr::GetGhostRacesLosses +805420e0 RKSYS::LicenseMgr::WriteTotalRacePlayed +805420f8 RKSYS::LicenseMgr::GetTotalRacePlayed +80542118 RKSYS::LicenseMgr::WriteTotalBattlePlayed +80542130 RKSYS::LicenseMgr::WriteRacesOnWheel +80542150 RKSYS::LicenseMgr::GetTotalBattlePlayed +80542168 RKSYS::LicenseMgr::GetRacesOnWheel +80542188 RKSYS::LicenseMgr::WriteBattlesOnWheel +805421a0 RKSYS::LicenseMgr::GetBattlesOnWheel +805421c0 RKSYS::LicenseMgr::WriteDistanceTravelled +805421d8 RKSYS::LicenseMgr::GetDistanceTravelled +805421f8 RKSYS::LicenseMgr::WriteGhostDataChallengesSent +80542210 RKSYS::LicenseMgr::GetGhostDataChallengesSent +80542230 RKSYS::LicenseMgr::WriteGhostDataChallengesReceived +80542248 RKSYS::LicenseMgr::GetGhostDataChallengesReceived +80542268 RKSYS::LicenseMgr::WriteItemHitsDelivered +80542280 RKSYS::LicenseMgr::GetItemHitsDelivered +805422a0 RKSYS::LicenseMgr::WriteItemHitsReceived +805422b8 RKSYS::LicenseMgr::GetItemHitsReceived +805422d8 RKSYS::LicenseMgr::WriteTricksPerformed +805422f0 RKSYS::LicenseMgr::GetTricksPerformed +80542310 RKSYS::LicenseMgr::WriteTimes1stPlaceAchieved +80542328 RKSYS::LicenseMgr::GetTimes1stPlaceAchieved +80542348 RKSYS::LicenseMgr::WriteDistancetravelledwhilein1stplace +80542360 RKSYS::LicenseMgr::GetDistancetravelledwhilein1stplace +80542380 RKSYS::LicenseMgr::WriteDistancetravelledonVSRaces +80542398 RKSYS::LicenseMgr::GetDistancetravelledonVSRaces +805423b8 RKSYS::LicenseMgr::WriteCompetitionsEntered +805423d0 RKSYS::LicenseMgr::GetCompetitionsEntered +805423f4 RKSYS::LicenseMgr::WriteRacesOnCharacter +80542414 RKSYS::LicenseMgr::GetRacesOnCharacter +80542440 RKSYS::LicenseMgr::WriteRacesOnKart +80542460 RKSYS::LicenseMgr::GetRacesOnKart +8054248c RKSYS::LicenseMgr::WriteRacesOnTrack +805424ac RKSYS::LicenseMgr::GetRacesOnTrack +805424d8 RKSYS::LicenseMgr::WriteRacesOnBattleArena +805424f8 RKSYS::LicenseMgr::WriteUnk55f0 +80542528 RKSYS::LicenseMgr::GetUnk55f0 +80542544 RKSYS::LicenseMgr::WriteStaffGhostStatus +80542568 RKSYS::LicenseMgr::GetStaffGhostStatus +8054257c RKSYS::LicenseMgr::WriteDefaultDrift +8054259c RKSYS::LicenseMgr::GetDefaultDrift +805425a8 RKSYS::LicenseMgr::WriteCC +805425d0 RKSYS::LicenseMgr::GetCC +805425e4 RKSYS::LicenseMgr::WriteCPUDifficulty +8054260c RKSYS::LicenseMgr::GetCPUDifficulty +80542620 RKSYS::LicenseMgr::WriteVehicleType +80542648 RKSYS::LicenseMgr::GetVehicleType +8054265c RKSYS::LicenseMgr::WriteCourseChoice +80542684 RKSYS::LicenseMgr::GetCourseChoice +80542698 RKSYS::LicenseMgr::WriteItemsType +805426c0 RKSYS::LicenseMgr::GetItemsType +805426d4 RKSYS::LicenseMgr::WriteTotalRaceCount +805426fc RKSYS::LicenseMgr::GetTotalRaceCount +80542710 RKSYS::LicenseMgr::WriteUnkTimer2 +805427e0 RKSYS::LicenseMgr::GetUnkTimer2 +805427f4 RKSYS::LicenseMgr::GetRKPD_1BC +80542838 RKSYS::LicenseMgr::WriteRKPD_1BC +805428e0 RKSYS::LicenseMgr::GetRKPD_5680 +805428ec RKSYS::LicenseMgr::WriteRKPD_5680 +80542948 RKSYS::LicenseUnk5680::Get_0 +80542950 RKSYS::LicenseUnk5680::Get_7 +80542958 RKSYS::LicenseUnk5680::Get_11 +80542960 RKSYS::LicenseMgr::GetRKPD_5688 +80542970 RKSYS::LicenseMgr::WriteRKPD_5688 +805429cc RKSYS::LicenseMgr::WriteRKPD_568c +80542a04 RKSYS::LicenseMgr::GetRKPD_568c +80542a10 RKSYS::LicenseMgr::WriteRKPD_5688_31 +80542a30 RKSYS::LicenseMgr::GetRKPD_5688_31 +80542a3c RKSYS::LicenseMgr::WriteMagic +80542a5c RKSYS::LicenseUnk5680::__ct(copy) +80542a80 RKSYS::Mgr::EraseLicense +80542af4 RKSYS::Mgr::CreateLicense +80542bc4 0x80542bc4 +80542bc8 RKSYS::Reset +80542ce8 RKSYS::SetCRC +80542d24 RKSYS::IsCRCCorrect +80542d6c RKSYS::CheckMagicAndVersion +80542d9c RKSYS::CheckRegion +80542dc4 RKSYS::ResetRKPD +80542f18 RKSYS::CreateRKPD +80542fb8 RKSYS::ReadRKPDCup +8054307c RKSYS::ReadRKPDLdbEntry +8054311c RKSYS::ReadRKPDUnkTimer +80543184 RKSYS::ReadRKPDUnkTimer2 +80543310 RKSYS::WriteRKPDLdbEntry +80543428 RKSYS::WriteRKPDUnkTimer +80543504 RKSYS::WriteRKPDUnkTimer2 +805435c0 RKSYS::ResetRKGD +80543650 RKSYS::GetRKGDUnk8Idx +8054371c RKSYS::SetRKGDUnk8 +805438f4 RKSYS::LicenseMgr::GetLdbEntry(CourseId) +80543954 RKSYS::LicenseMgr::OverwriteAndStoreLdbEntry +80543a48 RKSYS::LicenseMgr::StoreLdbEntry +80543bb8 RKSYS::LicenseMgr::GetGhostPosition +80543ca8 RKSYS::LicenseMgr::GetBestRank +80543e74 RKSYS::LicenseMgr::GetFavouriteCharacter +80543f34 RKSYS::LicenseMgr::GetFavouriteKart +80544014 RKSYS::LicenseMgr::GetFavouriteTrack +80544134 RKSYS::LicenseMgr::GetFavouriteBattleArena +805441e4 RKSYS::LicenseMgr::GetWheelRacesPercentage +805442d4 RKSYS::LicenseMgr::GetInFirstPercentage +8054433c RKSYS::LicenseMgr::Copy5680To5688 +8054435c RKSYS::LicenseMgr::Generate5688Bitfield +80544394 RKSYS::LicenseCompletion::Reset +805443ac RKSYS::LicenseCompletion::GetOffsetAndRelativeBit +805443c0 RKSYS::LicenseCompletion::SetComplete +805443e8 RKSYS::LicenseCompletion::ResetComplete +80544410 RKSYS::LicenseCompletion::IsCompleted +80544440 RKSYS::Mgr::GetGhostOffset +80544480 RKSYS::Mgr::ReadGhostTask +805444d8 RKSYS::Mgr::ReadGhost +8054452c RKSYS::Mgr::ReadGhostAsync +80544708 RKSYS::Mgr::LoadGhostGroupTask +80544714 RKSYS::Mgr::LoadGhostGroup +80544870 RKSYS::Mgr::LoadGhostGroupAsync +805449a8 RKSYS::Mgr::WriteGhostTask +80544a5c RKSYS::Mgr::WriteGhost +80544b0c RKSYS::Mgr::SaveGhostAsync +80544d4c RKSYS::Mgr::EraseGhostTask +80544dec RKSYS::Mgr::EraseGhost +80544e88 RKSYS::Mgr::EraseGhostAsync +8054508c RKSYS::Mgr::GetValidLicensesCount +8054511c RKSYS::Mgr::GetCombinedLicenseCompletions +80545200 RKSYS::Mgr::ReplaceBinaryTask +8054520c RKSYS::Mgr::ReplaceBinary +8054532c RKSYS::Mgr::EraseBinary +8054547c RKSYS::Mgr::GetCountry +805454a4 RKSYS::Mgr::GetLongitude +805454cc RKSYS::Mgr::GetLatitude +805454f4 GameSceneCreator::CreateInstance +80545528 GameSceneCreator::create +805455ec GameSceneCreator::destroy +805455f0 LensFlare::QuadDrawer::__ct +80545874 0x80545874 +80545878 GameScreenEffectsMgr::GetRootScreenWidth +80545894 GameScreenEffectsMgr::GetRootScreenHeight +805458b4 LensFlare::QuadDrawer::Draw +80545a88 0x80545a88 +80545b58 LensFlare::Texture::__ct +80545c28 LensFlare::Texture::SetPosition +80545c6c LensFlare::Texture::CopyFromEFB +80545c98 0x80545c98 +80545dd4 LensFlare::__ct +80545fd8 0x80545fd8 +8054603c LensFlare::__dt +805460f0 LensFlare::OnFadeOutPrepareStart +80546130 LensFlare::FadeOutPrepareUpdate +80546288 LensFlare::OnFadeOutStart +8054628c LensFlare::FadeOutUpdate +80546334 LensFlare::OnNoTargetStart +80546384 LensFlare::NoTargetUpdate +805463e0 LensFlare::OnNormalStateStart +80546490 LensFlare::OnNormalStateUpdate +805465cc LensFlare::Update +805468d4 Vec2::MultiplyByScalar +805468f0 LensFlare::DrawQuads +80546958 LensFlare::CopyEFBToTexture +80546984 0x80546984 +8054698c 0x8054698c +80546a14 LensFlareMgr::__ct +80546e14 LensFlareMgr::__dt +80546ed8 LensFlareMgr::GetBRRESTexCount +80546ee0 LensFlareMgr::GetRawTexture +80546f5c LensFlareMgr::GetTextureWidth +80546fc4 LensFlareMgr::GetTextureHeight +8054702c LensFlareMgr::GetTextureName +805470a8 LensFlareMgr::GetTextureFormat +805470b8 LensFlareMgr::Update +80547124 LensFlareMgr::DrawTextures +80547274 LensFlareMgr::Draw +805472f8 LensFlareMgr::CopyEFBToTextures +805473b4 LensFlareMgr::AddLensFX +8054741c LensFlareMgr::EnableExternalLens +80547440 LensFlareMgr::GetTargetPosition +80547708 LensFlareMgr::GetScreenPosition +805478f0 0x805478f0 +8054791c 0x8054791c +80547954 FilterEffect::__ct +80547b74 0x80547b74 +80547bd8 FilterEffectMgr::SetColor +80547c00 FilterEffect::Update +80547cd4 0x80547cd4 +80547ce4 0x80547ce4 +80547cf0 0x80547cf0 +80547d8c 0x80547d8c +80547d90 0x80547d90 +80547de4 0x80547de4 +80547de8 0x80547de8 +80547e00 0x80547e00 +80547e10 0x80547e10 +80547e30 0x80547e30 +80547e34 0x80547e34 +80547e4c FilterEffect::Draw +80547f4c FilterEffectMgr::__ct +805481b8 FilterEffectMgr::__dt +80548270 FilterEffect:__dt +805482d8 FilterEffectMgr::Update +805483cc FilterEffectMgr::Draw +80548514 0x80548514 +80548538 0x80548538 +80548568 0x80548568 +80548708 CourseFilterEffect::__ct +805488e8 0x805488e8 +8054894c CourseFilterEffect::Update +80548a20 CourseFilterEffect::OnNoFilterStart +80548a30 CourseFilterEffect::OnWhiteFilterPrepareStart +80548a54 CourseFilterEffect::WhiteFilterPrepareUpdate +80548aa8 CourseFilterEffect::OnWhiteFilterStart +80548aac CourseFilterEffect::WhiteFilterUpdate +80548ac4 CourseFilterEffect::OnBlackFilterStart +80548ae4 CourseFilterEffect::BlackFilterUpdate +80548afc CourseFilterEffect::OnAlphaFadeoutStart +80548b00 CourseFilterEffect::AlphaFadeoutUpdate +80548b5c CourseFilterEffect::Draw +80548c5c CourseFilterEffectMgr::__ct +80548e8c CourseFilterEffectMgr::__dt +80548f44 CourseFilterEffect::__dt +80548fac CourseFilterEffectMgr::Update +805490a0 CourseFilterEffectMgr:Draw +805491d8 0x805491d8 +805491f0 0x805491f0 +80549390 CreditsBars::__ct +8054946c 0x8054946c +80549470 CreditsBars::Init +80549498 CreditsBars::Draw +80549618 GameScreenEffectsMgr::__ct +80549be4 GameScreenEffectsMgr::__dt +80549c74 GameScreenEffectsMgr::Update +80549e8c 0x80549e8c +80549ee0 GameScreenEffectsMgr::Draw +8054a268 GameScreenEffectsMgr::DrawCourseFilterEffects +8054a3a4 GameScreenEffectsMgr::CopyEFBToLensFlareTextures +8054a46c GameScreenEffectsMgr::AddLensFX +8054a4d4 GameScreenEffectsMgr::EnableExternalLensFlare +8054a4fc 0x8054a4fc +8054a524 0x8054a524 +8054a558 GameScreenEffectsMgr::RequestWhiteCourseFilter +8054a574 CreditsBars::__dt +8054a5b4 GameScreenEffects_cpp_sinit_ +8054a5f0 0x8054a5f0 +8054a790 0x8054a790 +8054a794 BitRotator::__ct +8054a7b4 BitRotator::Update +8054a7d8 GetTick +8054a7dc GetHour +8054a858 THP::CreateAudioDecodeThread +8054a928 THP::AudioDecodeThreadStart +8054a948 THP::AudioDecodeThreadCancel +8054a990 THP::AudioDecoder +8054a9b8 THP::AudioDecoderForOnMemory +8054aa64 THP::AudioDecode +8054ab50 THP::PopFreeAudioBuffer +8054ab84 THP::PushFreeAudioBuffer +8054ab98 THP::PopDecodedAudioBuffer +8054abdc THP::PushDecodedAudioBuffer +8054abf0 THP::PlayerInit +8054ad10 THP::PlayerQuit +8054ad68 THP::PlayerOpen +8054aff0 THP::PlayerClose +8054b044 THP::PlayerCalcNeedMemory +8054b0fc THP::PlayerSetBuffer +8054b33c THP::InitAllMessageQueue +8054b40c THP::PrepareReady +8054b420 THP::PlayerPrepare +8054b6a0 THP::PlayerPlay +8054b700 THP::PlayerStop +8054b7dc THP::PlayerPause +8054b818 THP::PlayerSkip +8054b9e8 THP::PlayControl +8054bcac THP::ProperTimingForGettingNextFrame +8054bdd8 THP::PlayerDrawCurrentFrame +8054bde0 THP::PlayerGetVideoInfo +8054be28 THP::PlayerGetAudioInfo +8054be70 THP::PlayerGetFrameRate +8054be98 THP::PlayerGetTotalFrame +8054bebc THP::PlayerGetState +8054becc THP::PlayerDrawDone +8054bf3c 0x8054bf3c +8054bfa8 THP::AudioMixCallback +8054c114 THP::MixAudio +8054c4e0 THP::PlayerSetVolume +8054c60c THP::PlayerGetVolume +8054c644 THP::CreateReadThread +8054c6e4 THP::ReadThreadStart +8054c704 THP::ReadThreadCancel +8054c74c THP::Reader +8054c83c THP::PopReadedBuffer +8054c870 THP::PopReadedBuffer2 +8054c884 THP::PopFreeReadBuffer +8054c8b8 THP::PushFreeReadBuffer +8054c8cc THP::PopReadedBuffer2 +8054c900 THP::PushReadedBuffer2 +8054c914 THP::CreateVideoDecodeThread +8054c9e8 THP::VideoDecodeThreadStart +8054ca08 THP::VideoDecodeThreadCancel +8054ca50 THP::VideoDecoder +8054cb1c THP::VideoDecoderOnMemory +8054cc4c THP::VideoDecode +8054cd98 THP::PopFreeTextureSet +8054cdcc THP::PushFreeTextureSet +8054cde0 THP::PopDecodedTextureSet +8054ce24 THP::PushDecodedTextureSet +8054ce38 courseIdToGhostIndex +8054cf1c GetCourseIdBySlot +8054cf40 0x8054cf40 +8054d0e0 0x8054d0e0 +8054d228 0x8054d228 +8054d3bc 0x8054d3bc +8054d60c 0x8054d60c +8054d734 0x8054d734 +8054d7a4 0x8054d7a4 +8054d7a8 0x8054d7a8 +8054d7b0 0x8054d7b0 +8054d7c8 0x8054d7c8 +8054d7d0 0x8054d7d0 +8054d830 0x8054d830 +8054d874 GlobeScene::__dt +8054d8cc GlobeScene::OnEnter +8054d998 GlobeScene::CreateAndInitInstances +8054da68 GlobeScene::OnEnterEnd +8054daa8 GlobeScene::OnExit +8054daf0 GlobeScene::OnCalc +8054db68 RaceScene::__ct +8054dbb4 RaceScene::__dt +8054dc30 RaceScene::OnEnter +8054e1e8 RaceScene::CreateAndInitInstances +8054e70c RaceScene::OnEnterEnd +8054e98c RaceScene::vf_0x58 +8054e990 RaceScene::OnExit +8054ea74 RaceScene::OnReinit +8054eab4 RaceScene::UpdateRaceInstances +8054ecf0 0x8054ecf0 +8054ed70 RaceScene::UpdateSomeInstances +8054edf4 RaceScene::isPaused +8054ee4c RaceScene::OnCalc +8054ef48 RaceScene::GetScreenCount +8054ef58 RaceScene::isSpectating +8054ef68 RaceScene::vf_0x48 +8054ef74 RaceScene::vf_0x50 +8054ef7c RaceScene::vf_0x58 +8054ef84 MenuScene::__ct +8054efc8 MenuScene::__dt +8054f020 MenuScene::OnEnter +8054f134 MenuScene::CreateAndInitInstances +8054f244 MenuScene::OnEnterEnd +8054f278 MenuScene::OnExit +8054f2a8 MenuScene::OnCalc +8054f2fc RelProlog +8054f348 RelEpilog +8054f390 RelUnresolvedSection +8054f444 Random::__ct +8054f4b0 Random::Reset +8054f4f4 Random::__ct(seed) +8054f518 Random::__dt +8054f558 Random::Next +8054f5ac Random::NextLimited +8054f608 Random::NextFloat +8054f688 Random::NextFloatLimited +8054f70c 0x8054f70c +8054f734 0x8054f734 +8054f800 ElineController::__ct +8054f878 0x8054f878 +8054f8ec 0x8054f8ec +8054f938 0x8054f938 +8054f9d4 ElineMgr::__ct +8054fd90 ElineMgr::GetController +8054fdf0 ElineMgr::Update +8054fed4 Raceinfo::RaceinfoGamemodeDataMissionTournament +8054ff10 Raceinfo::RaceinfoGamemodeDataMissionTournament_switch +8054ff14 Raceinfo::RaceinfoGamemodeDataMissionTournament_caseD_0 +8054ff40 Raceinfo::RaceinfoGamemodeDataMissionTournament_caseD_1 +8054ff6c Raceinfo::RaceinfoGamemodeDataMissionTournament_caseD_7 +8054ffa8 0x8054ffa8 +80550000 0x80550000 +80550004 0x80550004 +80550050 0x80550050 +80550054 0x80550054 +80550068 0x80550068 +80550070 0x80550070 +8055008c 0x8055008c +80550550 0x80550550 +80550570 0x80550570 +805506ec 0x805506ec +805507d4 0x805507d4 +805507f0 0x805507f0 +805507f8 0x805507f8 +80550808 0x80550808 +80550848 0x80550848 +80550888 0x80550888 +805508c8 IsVehicleTypeUnlocked +80550970 0x80550970 +80550980 GetCupType +805509e0 IsCupUnlocked +80550c74 IsCharacterUnlocked +80550ca8 IsCharacterUnlocked_switch +80550cac IsCharacterUnlocked_caseD_11 +80550d44 IsCharacterUnlocked_caseD_18 +80550dcc IsCharacterUnlocked_caseD_1a +80550e50 IsCharacterUnlocked_caseD_10 +80550e68 IsKartUnlocked +80550f40 0x80550f40 +80550f60 0x80550f60 +80551204 isFastStaffGhostUnlocked +805512e4 0x805512e4 +80551328 0x80551328 +80551380 0x80551380 +80551384 0x80551384 +80551388 0x80551388 +80551394 0x80551394 +805513a0 0x805513a0 +805513ac 0x805513ac +805513d0 ModelTransformator::__ct +805514dc ModelTransformator::AppendAnmHolder +805514e4 ModelTransformator::AppendAnmBlend +805514ec ModelTransformator::SetBlendWeightDecrement +80551510 ModelTransformator::GetBlendWeightDecrement +8055153c ModelTransformator::DecrementBlendWeight +8055156c ModelTransformator::DetachAllAnmFromBlend(type) +8055159c ModelTransformator::DetachAllAnmFromBlend(listIdx) +805515fc ModelTransformator::LinkAnimationByName +80552398 ModelTransformator::IsG3dObj +805523b4 AnmChrBlendHolder::__dt +805523f4 0x805523f4 +80552434 ModelTransformator::LinkAnimationByBRRESIdx +80552b90 ModelTransformator::LinkChrAnmToBone +80552d6c 0x80552d6c +80552e24 ModelTransformator::LinkEmptyAnm +80552eb4 ModelTransformator::GetAnmHolderByIdx +80552ebc ModelTransformator::GetAnmObjByIdx +80552ee4 ModelTransformator::AddAnmToScnMdlAndSetupBRASD +80552f70 ModelTransformator::AddAnmToScnMdl +80552f88 ModelTransformator::OverwriteAnm +80552fa8 ModelTransformator::RestoreAnm +80552fc0 ModelTransformator::GetAnmHolderByType +80552fd0 ModelTransformator::GetPrevAnmHolderByType +80552fe0 ModelTransformator::IsTypeActive +80552ffc ModelTransformator::IsTypeInPrev +80553018 ModelTransformator::GetAnmObjByType +8055302c ModelTransformator::DetachHolderFromParent +8055304c ModelTransformator::PlayAnmNoBlend +805531c8 0x805531c8 +805532d0 ModelTransformator::AddAnmBlendToScnMdl +80553304 ModelTransformator::PlayAnmWithBlend +805534b0 ModelTransformator::StopAnmType +80553558 ModelTransformator::UpdateBRASDAndBlend +805535d4 AnmHolder::GetFrame +805535e0 ModelTransformator::UpdateBlend +805537a0 AnmHolder::IsLooped +805537a8 AnmHolder::GetFrameCount +805537b4 0x805537b4 +80553838 ModelTransformator::Bind +80553890 ModelTransformator::UpdateActiveAnms +80553978 0x80553978 +80553a10 0x80553a10 +80553a50 0x80553a50 +80553b74 0x80553b74 +80553c30 ModelTransformator::vf_0x8 +80553c34 AnmHolder::SetUpdateRate +80553c38 AnmHolder::GetUpdateRate +80553c44 AnmHolder::UpdateRateAndSetFrame +80553c48 AnmHolder::SetFrame +80553c4c 0x80553c4c +80553c8c 0x80553c8c +80553cd4 0x80553cd4 +80553d24 0x80553d24 +80553f68 0x80553f68 +80554068 0x80554068 +805541b8 0x805541b8 +80554384 0x80554384 +80554414 AnmTexPatOverrideHolder::__dt +80554454 AnmTexPatOverrideHolder::SetWeight +8055449c AnmTexPatOverrideHolder::GetWeight +805544ec AnmTexPatOverrideHolder::AttachNew +80554730 AnmTexPatOverrideHolder::Attach +80554830 AnmTexPatOverrideHolder::DecrementWeight +80554980 AnmTexPatOverrideHolder::ShouldDetachFromParent +80554b4c AnmTexPatOverrideHolder::DetachAll +80554bdc 0x80554bdc +80554c1c 0x80554c1c +80554c64 0x80554c64 +80554cb4 0x80554cb4 +80554ef8 0x80554ef8 +80554ff8 0x80554ff8 +80555148 0x80555148 +80555314 0x80555314 +805553a4 0x805553a4 +805553e4 0x805553e4 +8055542c 0x8055542c +8055547c 0x8055547c +805556c0 0x805556c0 +805557c0 0x805557c0 +80555910 0x80555910 +80555adc 0x80555adc +80555b6c AnmChrBlendHolder::__dt +80555bac AnmChrBlendHolder::SetWeight +80555c5c AnmChrBlendHolder::GetWeight +80555cfc AnmChrBlendHolder::AttachNew +80555f40 AnmChrBlendHolder::Attach +80556040 AnmChrBlendHolder::DecrementWeight +80556190 AnmChrBlendHolder::ShouldDetachFromParent +8055635c AnmChrBlendHolder::DetachAll +805563ec 0x805563ec +80556400 0x80556400 +80556414 0x80556414 +80556480 0x80556480 +80556504 0x80556504 +80556568 0x80556568 +8055657c 0x8055657c +80556590 AnmTexPatHolder::GetFrame +805565a4 AnmTexPatHolder::SetFrame +805565b8 AnmTexPatHolder::UpdateRateAndSetFrame +80556624 AnmTexPatHolder::GetFrameCount +805566a8 AnmTexPatHolder::IsLooped +8055670c AnmTexPatHolder::GetUpdateRate +80556720 AnmTexPatHolder::SetUpdateRate +80556734 0x80556734 +80556748 0x80556748 +8055675c 0x8055675c +805567c8 0x805567c8 +8055684c 0x8055684c +805568b0 0x805568b0 +805568c4 0x805568c4 +805568d8 0x805568d8 +805568ec 0x805568ec +80556900 0x80556900 +8055696c 0x8055696c +805569f0 0x805569f0 +80556a54 0x80556a54 +80556a68 0x80556a68 +80556a7c AnmChrHolder::GetFrame +80556a90 AnmChrHolder::SetFrame +80556aa4 AnmChrHolder::UpdateRateAndSetFrame +80556b10 AnmChrHolder::GetFrameCount +80556b94 AnmChrHolder::IsLooped +80556bf8 AnmChrHolder::GetUpdateRate +80556c0c AnmChrHolder::SetUpdateRate +80556c20 0x80556c20 +80556c50 0x80556c50 +80556c70 0x80556c70 +80556cdc ModelDirector::SetScale +80556d30 0x80556d30 +80556da8 0x80556da8 +80556e14 0x80556e14 +80556e68 0x80556e68 +80556e78 0x80556e78 +80556ed8 0x80556ed8 +80556f18 ModelDirector::__ct(ClipInfo) +8055718c ModelDirector::__ct +805571d8 ModelDirector::__ct(ScnMgrIdx) +8055723c ModelDirector::__dt +8055727c ModelDirector::GetBRRES +80557298 ModelDirector::BindBRRES +80557324 ModelDirector::BindBRRESFallback +805573d4 ModelDirector::RipAndBindBRRES +80557478 ModelDirector::BindBRRESImpl +80557680 ModelDirector::BRRESExists +805576c4 ModelDirector::GetResMdl(string) +805576d4 ModelDirector::GetResMdl(idx) +805576e4 ModelDirector::MdlExists +8055771c ModelDirector::HasResMdl +80557720 ModelDirector::Init +80557980 ModelDirector::InitG3D +80557b54 ModelDirector::AppendToScnMgr +80557b90 ModelDirector::CreateScn +80557d68 ModelDirector::LoadWithAnm(name) +80557e50 ModelDirector::LoadWithAnm(idx) +80557f38 ModelDirector::LoadNoAnm(name) +80557f98 ModelDirector::LoadNoAnm(idx) +80557ff8 ModelDirector::LoadWithOption(name) +805580cc ModelDirector::LoadWithOption(idx) +805581a0 ModelDirector::LoadScnMdl1Mat1Shp +80558200 MiiHeadsModel::InitModel +80558474 0x80558474 +80558544 0x80558544 +805585bc 0x805585bc +80558670 ModelDirector::ToggleVisible +80558788 ModelDirector::EnableDraw +80558850 0x80558850 +8055888c ModelDirector::UpdateVisibility +80558960 ModelDirector::EnableScreen +80558978 ModelDirector::DisableScreen +80558990 ModelDirector::IsVisibleOnScreen +805589b0 ModelDirector::EnableScreen2 +805589c8 ModelDirector::IsVisibleOnScreen2 +805589e8 ModelDirector::SetScnMdlOptions +80558b04 0x80558b04 +80558b88 0x80558b88 +80558c10 0x80558c10 +80558cbc 0x80558cbc +80558d74 0x80558d74 +80558ebc ModelDirector::Update +80558f74 0x80558f74 +805590c8 ModelDirector::SetAllScnOptionsFromClipInfo +805591d4 ModelDirector::SetDisableDrawScnOptionsFromClipInfo +8055933c 0x8055933c +805594ac 0x805594ac +805595a0 0x805595a0 +80559670 ModelDirector::CreateTransformator +80559770 0x80559770 +80559880 0x80559880 +80559964 ModelDirector::SetAudioActor +80559a6c ModelDirector::LinkAnimation +80559c00 0x80559c00 +80559d74 0x80559d74 +80559ef4 ModelDirector::LinkEmptyAnm +8055a008 0x8055a008 +8055a760 ModelDirector::LinkAllAnimations +8055ae64 ModelDirector::PrepareAllAnms +8055aefc 0x8055aefc +8055af0c 0x8055af0c +8055af2c 0x8055af2c +8055af34 ModelDirector::SetLight +8055af44 ModelDirector::GetScnMgr +8055af7c ModelDirector::RemoveFromGroup +8055afcc ModelDirector::ToggleTransparent +8055b068 ModelDirector::ReplaceMatGXTexObj +8055b09c 0x8055b09c +8055b144 ModelDirector::UpdateDrawPriority +8055b188 0x8055b188 +8055b264 0x8055b264 +8055b328 0x8055b328 +8055b3d4 0x8055b3d4 +8055b458 ModelDirector::ChangeTransformator +8055b4c8 ModelDirector::GetScale +8055b514 ModelDirector::SetScale(float) +8055b550 ModelCalcBase::__ct +8055b55c 0x8055b55c +8055b63c 0x8055b63c +8055b710 ModelCalcCallback::GetBoneWorldMtx +8055b7e4 0x8055b7e4 +8055b8c4 0x8055b8c4 +8055b998 0x8055b998 +8055ba6c 0x8055ba6c +8055bab4 ModelCalcCallback::__ct +8055bb68 0x8055bb68 +8055bba8 ModelCalcCallback::ExecCallback_CALC_WORLD +8055bbcc ModelCalcCBBoneLinked::__ct +8055bc90 ModelCalcCallback::__dt +8055bcd0 ModelCalcCBBoneLinked::ExecWorldCBImpl +8055beac 0x8055beac +8055bf74 ModelCalcCBBoneLinked::__dt +8055bfb4 ModelCalcCallback::ExecCallback_CALC_XLU +8055bfb8 ModelCalcCallback::ExecCallback_CALC_OPA +8055bfbc ModelCalcCallback::ExecCallback_CALC_VIEW +8055bfc0 ModelCalcCallback::ExecCallback_CALC_MAT +8055bfc4 0x8055bfc4 +8055bfc8 0x8055bfc8 +8055c008 ModelCalcCallback::__dt(thunk) +8055c010 ModelCalcCBBoneLinked::__dt(thunk) +8055c018 ModelCalcCallback::ExecCallback_CALC_WORLD(thunk) +8055c020 0x8055c020 +8055c028 Light::__ct +8055c20c 0x8055c20c +8055c2c8 Light::Init +8055c47c 0x8055c47c +8055c624 0x8055c624 +8055c720 0x8055c720 +8055c77c Light::InitLightObject +8055c8b4 0x8055c8b4 +8055c910 0x8055c910 +8055c9a0 Light::Update +8055cc80 0x8055cc80 +8055cca4 LightMgrHolder::__ct +8055cd68 LightMgrHolder::805610e8 +8055ce8c LightMgrHolder::8056120c +8055cf68 LightMgrHolder::LoadBLIGHT +8055cf6c LightMgrHolder::805612ec +8055d00c 0x8055d00c +8055d018 LightMgrHolder::AcquireLight +8055d084 LightMgrHolder::moveFromAtoB +8055d0d0 LightMgrHolder::vf_0x10 +8055d1ec LightMgrHolder::Update +8055d270 LightMgrHolder::LoadBLMAP +8055d308 LightMgrHolderRace::__ct +8055d5c8 LightMgrHolder::__dt +8055d608 LightMgrHolderRace::LoadBLIGHT +8055d708 LightMgrHolder::LoadBLMAP +8055d798 LightMgrHolderMenu_construct +8055d868 LightMgrHolderMenu_loadBlight +8055d8c0 LightMgrHolderMenu_loadLightMap +8055d91c LightMgrHolderMiiBody_construct +8055d9ec LightMgrHolderMiiBody_loadBlight +8055da54 LightMgrHolderMiiBody_loadLightMap +8055dac0 LightMgrHolderMiiBody_destruct +8055db00 LightMgrHolderMenu_destruct +8055db40 LightMgrHolderRace::destruct +8055db80 Light::__dt +8055dbc0 ScnMgr::__ct +8055dce4 0x8055dce4 +8055dd3c ScnMgr::__dt +8055ddc4 ScnMgr::ResetRenderModeObj +8055de00 ScnMgr::InitImpl +8055dfd0 ScnMgr::LoadPostEffects +8055dfd4 ScnMgr::vf_0x28 +8055dfd8 ScnMgr::CreateAllGroups +8055e0c4 ScnMgr::CreateScnGroup +8055e0f0 ScnMgr::LoadLights +8055e14c ScnMgr::DrawLights +8055e19c 0x8055e19c +8055e1a0 ScnMgr::DoneDraw +8055e228 ScnMgr::DrawModelsImpl +8055e508 ScnMgr::UpdateScnRoot +8055e7b4 ScnMgr::UpdateCameras +8055e870 GameCamera::GetViewMatrix +8055e878 ScnMgr::RemoveShadowTextureMgr +8055e88c 0x8055e88c +8055e90c 0x8055e90c +8055e93c ScnMgr::InsertModelDirectorInScn +8055eb10 ScnMgr::SetModelDrawPriority +8055ebe0 ScnMgr::SetModelXluDrawPriority +8055ec00 0x8055ec00 +8055ece8 0x8055ece8 +8055ed6c 0x8055ed6c +8055ee2c 0x8055ee2c +8055eeec ScnMgr::SetAnmScn +8055f090 ScnMgr::SetRootAnmScn +8055f234 ScnMgr::AppendScnGroupExHolder +8055f244 ScnMgr::RemoveModelDirector +8055f24c ScnMgr::AppendScreenSpecificModelDirector +8055f254 ScnMgr::AppendMatModelDirector +8055f25c ScnMgr::RemoveMatModelDirector +8055f264 ScnMgr::SwitchScnRoot +8055f2f4 ScnMgr::UpdateVisibility +8055f35c 0x8055f35c +8055f474 0x8055f474 +8055f57c ScnMgr::CreateScnGroupEx +8055f6f8 ScnMgr::RearrangeDirectorGroups +8055f81c ScnMgr::80563b9c +8055f868 ScnMgr::80563be8 +8055f8b8 ScnMgr::80563c38 +8055f904 ScnGroupExHolder::__ct +8055f964 TextureHolder::__ct +8055fa30 TextureHolder::CopyFromEFB +8055fb68 TextureHolder::80563ee8 +8055fcf4 ScnMgr::UpdateModelDrawPriority +8055fd8c ScnMgr::RemoveGroup +8055fdc0 ScnMgr::InsertGroup +8055fdfc ScnMgr::GetScnGroup +8055fe58 TextureHolder::__dt +8055fe98 ScnMgr::vf_0x2c +8055fe9c ScnMgr::DrawModels +8055fea4 ScnMgr::CalcSelf +8055fea8 ScnMgr::vf_0xC +8055feac ScnMgr::Init +8055feb8 ScnGroupHolder::__dt +8055fef8 ScnGroupExHolder::__dt +8055ff38 Renderer::__ct +8055ff8c Renderer::__dt +8055fff8 RendererWithModels::__ct +8056004c RendererWithModels::__dt +805600c4 RendererWithModels::Calc +805600d8 RendererWithModels::Draw +80560128 RendererWithModels::DrawWithProjection +8056016c 0x8056016c +80560298 RendererMixed::__ct +805602ec RendererMixed::Draw +80560308 RendererMii::__ct +80560364 RendererMixed::__dt +805603e0 RendererMii::DrawModels +8056043c RendererMii::__dt +805604bc ScnMgr::InitScn +80560620 0x80560620 +80560668 0x80560668 +80560694 0x80560694 +8056075c ScnMgr::CalcAll +805607fc ScnMgr::Calc(idx) +805608c4 0x805608c4 +805608e4 ScnMgr::Draw(idx) +805609e0 ScnMgr::DrawMain +80560ab8 ScnMgr::DrawSecondary +80560c24 0x80560c24 +80560c3c Renderer::Remove(internal idx) +80560c74 ScnMgr::Unregister +80560cb0 ScnMgr::Reset +80560d30 ScnMgr::Finalize +80560d94 Renderer::Register(listIdx) +80560de4 Renderer::RegisterAndAppendScreen +80560ee8 Renderer::Register2ndList(NoAppend) +80560f2c Renderer::Remove(listIdx) +80560f44 Renderer::RemoveFrom1stList +80560f54 Renderer::RemoveFrom2ndList +80560f68 Renderer::Register(bool Append) +8056101c ScnMgr::Register +80561050 0x80561050 +805610bc 0x805610bc +80561114 0x80561114 +8056116c 0x8056116c +805612b0 ScnMgr::AcquireLight +805612c0 0x805612c0 +805612d4 0x805612d4 +805612e4 0x805612e4 +805612f4 0x805612f4 +80561344 0x80561344 +80561348 0x80561348 +805613ac 0x805613ac +80561424 0x80561424 +8056149c GameScreen::__ct +80561748 0x80561748 +80561788 0x80561788 +805617c8 0x805617c8 +80561808 0x80561808 +80561848 0x80561848 +80561938 0x80561938 +80561a20 GameScreen::SetAndLoadOrthoProj +80561b08 0x80561b08 +80561bf0 0x80561bf0 +80561ca0 GameScreen::SetAndLoadProjection +80561d50 0x80561d50 +80561e00 0x80561e00 +80561e68 GameScreen::SetProjection +80561ef8 0x80561ef8 +80561fb0 0x80561fb0 +80562038 0x80562038 +805620dc 0x805620dc +80562164 0x80562164 +80562204 0x80562204 +805622f0 0x805622f0 +80562330 0x80562330 +80562370 0x80562370 +805624a4 0x805624a4 +805625d8 0x805625d8 +80562838 GameScreen::Set16_9AspectRatio +805628a0 GameScreen::Set4_3AspectRatio +80562920 GameScreen::Init +80562a3c 0x80562a3c +80562ab8 GameScreen::CalcDimensions +80562bec GameScreen::GetAbsoluteToView +80562c40 GameScreen::GetViewToScreen +80562c44 GameScreen::GetAbsoluteToScreen +80562cc4 0x80562cc4 +80562d34 0x80562d34 +80562db0 GameScreen::__dt +80562df0 RendererGlobe::__ct +80562e2c RendererMenu::__dt +80562e8c 0x80562e8c +80562ee8 RendererGlobe::__dt +80562f4c Kart::Damage::__ct +80562fdc 0x80562fdc +8056301c Kart::Damage::Reset +80563030 Kart::Damage::Update +80563174 Kart::Damage::SetAffectedByPOW +8056317c Kart::Damage::SetPOWParams +805631a4 Kart::Damage::SetPOWParams(static) +805631cc Kart::Damage::ShouldReceivePOWDamage +805631f8 Kart::Damage::ResetPOWParams +80563214 Kart::Damage::UpdatePOWParams +8056325c Kart::Damage::SetDamage +805636d4 Kart::Damage::UpdateCurDamage +80563708 Kart::Damage::EndCurDamage +80563818 0x80563818 +805638e8 0x805638e8 +80563964 Kart::Damage::UpdateCurDamageSpeed +805639bc Kart::Damage::ApplySpinDamage +80563be8 Kart::Damage::ApplyBananaDamage +80563c34 Kart::Damage::ApplyGoombaDamage +80563c80 Kart::Damage::ApplyFireDamage +80563ccc Kart::Damage::ApplyShockDamage +80563cd8 Kart::Damage::ApplyZapperDamage +80563ce4 Kart::Damage::ApplyPOWDamage +80563e18 0x80563e18 +80563e84 Kart::Damage::UpdateSpinOutdamage +80563ffc Kart::Damage::OnSpinOutDamageEnd +80564038 Kart::Damage::UpdatePOWDamage +805641d8 Kart::Damage::vf_0x10 +805642a0 Kart::Damage::OnPOWDamageEnd +805642dc Kart::Damage::ApplyShellFIBDamage +8056435c Kart::Damage::OnShellFIBDamageEnd +80564398 Kart::Damage::ApplyStarDamage +80564414 Kart::Damage::ApplyKnockback +80564728 Kart::Damage::UpdateKnockbackDamage +805648c0 0x805648c0 +805648fc Kart::Damage::OnStarCarDamageEnd +80564938 Kart::Damage::ApplyChompDamage +805649b4 Kart::Damage::UpdateBigKnockbackDamage +80564be8 Kart::Damage::OnBigKnockbackDamageEnd +80564c24 Kart::Damage::ApplyCarDamage +80564ca4 Kart::Damage::ApplyBulletDamage +80564d20 Kart::Damage::ApplyLaunchDamage +80564f34 Kart::Damage::UpdateLaunchDamage +80565348 Kart::Damage::OnLaunchDamageEnd +8056534c 0x8056534c +805653f4 Kart::Damage::ApplyThwompDamage +80565498 Kart::Damage::ApplyMegaDamage +8056553c Kart::Damage::ApplySquishRespawnDamage +805655f8 Kart::Damage::ApplyCarSquishDamage +8056569c Kart::Damage::UpdateSquishDamage +80565750 Kart::Damage::OnSquishDamageEnd +80565768 Kart::Damage::ApplyDrivingDirKnockback +80565814 Kart::Damage::ApplySidewaysKnockback +805659cc 0x805659cc +80565a24 0x80565a24 +80565a7c 0x80565a7c +80565b1c 0x80565b1c +80565bac 0x80565bac +80565c30 0x80565c30 +80565ccc 0x80565ccc +80565de4 Kart::Damage::vf_0x14 +80565de8 0x80565de8 +80565e28 Kart::Damage::__dt +80565e68 0x80565e68 +80565ea8 KartDamageCpp_sinit_ +80565ee4 Kart::ModelsVisibility::__ct +80565f30 0x80565f30 +80565f70 Kart::ModelsVisibility::SetInvisible +80565f80 Kart::ModelsVisibility::SetModelsVisibility +805660f0 Kart::ModelsVisibility::UpdateModelsVisibility +80566200 Kart::ModelsVisibility::SetModelDraw +8056621c Kart::ModelsVisibility::__dt +8056625c Kart::MatTEVHandler::SetPartTEVSwapMode +8056626c Kart::MatTEVHandler::__ct +805662b0 Kart::MatTEVHandler::SetTexSwapModeAndSetTEVSwapModes +80566358 Kart::MatTEVHandler::SetTEVSwapModes +80566400 Kart::MatTEVHandler::SetModelTEVSwapMode(bool) +8056651c Kart::MatTEVHandler::SetModelTevColorOp +80566618 Kart::MatTEVHandler::SetTEVSwapModesNoTexModeUpdate +805666a8 Kart::MatTEVHandler::SetModelTEVSwapMode +805667ac Kart::MatTEVHandler::__dt +805667ec Kart::StarAnmMgr::LoadAnm +80566a58 Kart::StarAnmMgr::__ct +80566a9c Kart::StarAnmMgr::Activate +80566ac0 Kart::StarAnmMgr::Update +80566d5c Kart::StarAnmMgr::StartEnding +80566d70 Kart::StarAnmMgr::End +80566d7c Kart::StarAnmMgr::Reset +80566eb8 0x80566eb8 +80566fd0 Kart::StarAnmMgr::SetModelColorsImpl +805670d0 0x805670d0 +805671e0 Kart::StarAnmMgr::SetModelColors +805671e4 Kart::StarAnmMgr::__dt +80567224 0x80567224 +8056727c Kart::Part::__dt +805672bc Kart::Arm::LoadModel +805672d4 Kart::Arm::UpdateMatrix +80567544 Kart::Body::__ct +805675ac Kart::Body::LoadModel +805675c0 Kart::Body::CreateModelDirectors +80567608 Kart::Body::Init +80567664 Kart::Body::Reset +805676b0 Kart::Body::vf_0x58 +805676f4 0x805676f4 +80567738 0x80567738 +805677b4 Kart::Body::GetMatrix +80567814 Kart::Body::UpdateMatrix +805678b0 0x805678b0 +80567968 0x80567968 +80567a24 Kart::Body::vf_0x60 +80567aa0 0x80567aa0 +80567b00 0x80567b00 +80567b14 0x80567b14 +80567b74 0x80567b74 +80567b98 Kart::Body::Load2ndModel +80567bf8 0x80567bf8 +80567d0c 0x80567d0c +80567e24 0x80567e24 +80567e70 Kart::BodyKart::__ct +80567f34 Kart::Body::__dt +80567f74 Kart::BodyKart::SetDispParams +80567fb4 Kart::BodyKart::Load +80568048 Kart::BodyKart::UpdateMatrix +805682c8 Kart::BodyKart::vf_0xc +8056835c Kart::BodyKart::vf_0x64 +805683e0 Kart::BodyKart::vf_0x24 +80568430 Kart::BodyKart::ApplyStarColors +805684a8 Kart::BodyKart::vf_0x2c +80568520 Kart::BodyKart::vf_0x30 +80568598 Kart::BodyKart::UpdateModelDrawPriority +80568620 0x80568620 +80568660 Kart::BikeHandle::LoadModel +80568670 Kart::BikeHandle::UpdateMatrix +805687f0 0x805687f0 +80568830 Kart::BikeSwingArm::LoadModel +80568840 Kart::BikeSwingArm::UpdateMatrix +80568a08 Kart::BodyBike::__ct +80568aa0 Kart::BikeHandle::__dt +80568ae0 Kart::BikeSwingArm::__dt +80568b20 Kart::BodyBike::SetDispParams +80568b34 Kart::BodyBike::LoadModel +80568b48 Kart::BodyBike::Load +80568bbc Kart::BodyBike::vf_0x60 +80568c38 Kart::BodyBike::UpdateMatrix +80568f04 Kart::Body::GetMatrix +80569044 Kart::BodyBike::UpdateWheelMatrix +80569170 Kart::BodyBike::vf_0xC +805691e4 Kart::BodyBike::vf_0x64 +80569244 Kart::BodyBike::vf_0x24 +80569264 Kart::BodyBike::ApplyStarColors +805692b8 Kart::BodyBike::vf_0x2c +8056930c Kart::BodyBike::vf_0x30 +80569360 Kart::BodyBike::UpdateModelDrawPriority +805693c8 Kart::BodyQuacker::__ct +8056946c Kart::BodyBike::__dt +805694ac Kart::BodyQuacker::GetMatrix +8056950c Kart::BodyQuacker::UpdateMatrix +805695cc Kart::Body::SetHandleDistance +805695d4 Kart::Body::SetFloat_0x98 +805695dc Kart::BodyQuacker::__dt +8056961c Kart::Part::vf_0x24 +80569644 Kart::BodyKart::__dt +80569684 Kart::Arm::__dt +805696c4 0x805696c4 +805696cc 0x805696cc +805696d4 0x805696d4 +805696dc 0x805696dc +805696e4 0x805696e4 +805696ec 0x805696ec +805696f4 0x805696f4 +805696fc 0x805696fc +80569704 0x80569704 +8056970c 0x8056970c +80569714 0x80569714 +8056971c Kart::Collision::__ct +80569794 0x80569794 +805697d4 Kart::Collision::Reset +805698bc 0x805698bc +80569914 Kart::Collision::ProcessVehicleBodyCollision +80569a84 Kart::Collision::ProcessWheelCollision +80569ae0 Kart::Collision::ProcessMovingRoad +80569bb4 Kart::Collision::ProcessFloor +80569fd4 0x80569fd4 +8056a0a4 0x8056a0a4 +8056a334 0x8056a334 +8056a41c 0x8056a41c +8056a640 0x8056a640 +8056a6c0 Kart::Collision::ProcessTriggers +8056a8ec 0x8056a8ec +8056a9a0 Kart::Collision::CheckKartCollision +8056bed0 Kart::Movement::vf_0x30 +8056bed4 0x8056bed4 +8056bf58 0x8056bf58 +8056c3e4 0x8056c3e4 +8056c568 0x8056c568 +8056c588 0x8056c588 +8056c5ac 0x8056c5ac +8056c634 0x8056c634 +8056c720 0x8056c720 +8056c7a4 0x8056c7a4 +8056c7e4 Kart::Collision::CheckTriggersAndOOB +8056ca84 0x8056ca84 +8056ce0c 0x8056ce0c +8056ceb4 0x8056ceb4 +8056cf48 0x8056cf48 +8056d0c0 Kart::Collision::CheckObjectCollision +8056d6f4 0x8056d6f4 +8056d724 Object::GetId +8056d72c Kart::Collision::CheckItemCollision +8056dd44 0x8056dd44 +8056ddd0 Kart::Collision::UpdateCollisions +8056e0fc 0x8056e0fc +8056e284 Kart::Collision::InitHitboxes +8056e320 Kart::Collision::HandleNoopCollision +8056e328 Kart::Collision::HandleBananaCollision +8056e340 Kart::Collision::HandleShellCollision +8056e360 Kart::Collision::HandleBlueShellCollision +8056e378 Kart::Collision::HandleBombCollision +8056e390 Kart::Collision::HandleMushroomCollision +8056e3d4 Kart::Collision::HandleStarCollision +8056e40c Kart::Collision::HandleFibCollision +8056e574 0x8056e574 +8056e57c 0x8056e57c +8056e584 0x8056e584 +8056e58c 0x8056e58c +8056e594 0x8056e594 +8056e59c 0x8056e59c +8056e5a4 0x8056e5a4 +8056e614 0x8056e614 +8056e6c8 ObjectCollidable::GetCollision +8056e6d0 0x8056e6d0 +8056e6ec 0x8056e6ec +8056e75c 0x8056e75c +8056e764 0x8056e764 +8056e76c 0x8056e76c +8056e784 0x8056e784 +8056e78c 0x8056e78c +8056e794 0x8056e794 +8056e79c 0x8056e79c +8056e7ec 0x8056e7ec +8056e878 0x8056e878 +8056e904 0x8056e904 +8056e940 0x8056e940 +8056e968 0x8056e968 +8056e9d4 0x8056e9d4 +8056ebdc 0x8056ebdc +8056ecb0 Kart::Collision::ActivateOOB +8056f074 0x8056f074 +8056f084 Kart::Collision::UpdateRespawn +8056f1a0 Kart::Collision::__dt +8056f1e0 Kart::Trick::__ct +8056f244 Kart::Trick::__dt +8056f284 Kart::Trick::Reset +8056f2d4 Kart::Trick::UpdateNext +8056f408 0x8056f408 +8056f4ec 0x8056f4ec +8056f500 0x8056f500 +8056f518 Kart::Trick::TryStart +8056f684 Kart::Trick::Start +8056f7b4 0x8056f7b4 +8056f814 0x8056f814 +8056f8d8 0x8056f8d8 +8056f908 Kart::Trick::StartInner +8056f9cc 0x8056f9cc +8056fb80 Kart::Trick::Update +8056fbfc Kart::Trick::SetupProperties +8056fc98 Kart::Trick::UpdateRot +8056fdb4 0x8056fdb4 +8056fe20 0x8056fe20 +8056fe54 Kart::Trick::End +8056fee0 0x8056fee0 +8056fef4 Kart::TrickBike::Start +80570038 Kart::TrickBike::StartInner +80570130 Kart::TrickBike::UpdateRot +80570298 Kart::TrickBike::__ct +805702d8 Kart::BRRESHandle::__ct +805703f0 Kart::BRRESHandle::__dt +80570430 0x80570430 +805704ac 0x805704ac +80570528 Kart::BRRESHandle::LoadKartBRRES +8057062c Kart::BRRESHandle::LoadDriverBRRES +805706c8 0x805706c8 +80570784 0x80570784 +80570800 Kart::BRRESHandle::LoadBodyModel +805709bc 0x805709bc +80570a74 0x80570a74 +80570a8c Kart::BRRESHandle::LoadLeftBackWheelModel +80570b44 Kart::BRRESHandle::LoadLeftFrontWheelModel +80570bfc Kart::BRRESHandle::LoadRightBackWheelModel +80570cb4 Kart::BRRESHandle::LoadRightFrontWheelModel +80570d6c 0x80570d6c +80570e70 Kart::BRRESHandle::LoadArmModel +80571048 Kart::BRRESHandle::LoadDriverModels +805710b8 Kart::BRRESHandle::LoadBikeHandleModel +80571180 Kart::BRRESHandle::LoadBikeSwingArmModel +80571238 Kart::BRRESHandle::LoadBikeFrontWheelModel +805712f0 Kart::BRRESHandle::LoadBikeBackWheelModel +805713a8 Kart::BRRESHandle::LoadBikeSuspensionsModel +80571460 0x80571460 +80571518 Kart::BRRESHandle::LoadShadowModel +8057159c Kart::BRRESHandle::LoadKillerModels +8057169c 0x8057169c +80571740 0x80571740 +80571760 Kart::Movement::__ct +805718b8 Kart::Boost::__dt +805718f8 0x805718f8 +80571938 0x80571938 +80571978 0x80571978 +805719b8 Kart::Movement::CreateTrickZipper +80571a38 Kart::Movement::SetTurnParams +80571c70 Kart::Movement::Reset +80572078 Kart::Movement::Update +805730fc 0x805730fc +80573104 Kart::Movement::UpdateHopPhysics +80573148 Kart::Movement::Respawn +805731ec 0x805731ec +80573480 0x80573480 +80573544 0x80573544 +805736bc 0x805736bc +80573708 0x80573708 +80573780 Kart::Movement::SomethingWheelieBump +805738d8 0x805738d8 +805738dc Kart::Movement::UpdateDir +80574050 Kart::Movement::UpdateTurn +80574304 Kart::Movement::UpdateVehicleSpeed +805747c4 0x805747c4 +805748a4 Kart::Movement::ComputeWallCollisionSpeedFactor +80574a38 Kart::Movement::vf_0x68 +80574a3c 0x80574a3c +80574f18 0x80574f18 +80575004 Kart::Movement::GetAccelerationFromSpeed +80575138 Kart::Movement::ResetBulletSpeed +80575148 Kart::Movement::ResetMaxSpeed +80575158 Kart::Movement::UpdateAcceleration +80575b64 Kart::Movement::GetWheelieSoftSpeedLimitBonus +80575b70 Kart::Movement::UpdateOffroad +80575d84 0x80575d84 +80575e38 Kart::Movement::UpdateRotate +80576570 0x80576570 +805766a8 Kart::Movement::UpdateVehicleRotationVector +80576970 Kart::Movement::UpdateSSMTRotation +80576b34 Kart::Movement::UpdateUps +80577024 Kart::Movement::UpdateUpsWhileAirbone +805771b4 Kart::Movement::CheckIfCanHop +805771f8 Kart::Movement::Hop +805773dc Kart::Movement::CancelWheelie +805773e0 Kart::Movement::UpdateManualDrift +80577878 Kart::Movement::UpdateAutoDrift +80577ae4 0x80577ae4 +80577b90 Kart::Movement::StartManualDrift +80577dd4 0x80577dd4 +80577e90 0x80577e90 +80577f18 0x80577f18 +80577fa0 Kart::Movement::UpdateHopAndSlipdrift +80578138 0x80578138 +805781ec 0x805781ec +80578230 0x80578230 +80578254 0x80578254 +805783c4 0x805783c4 +805784bc 0x805784bc +805784d0 0x805784d0 +80578528 0x80578528 +805785ec Kart::Movement::UpdateMTCharge +8057877c Kart::Movement::GetMTMaxCharge +80578788 Kart::Movement::GetSMTMaxCharge +80578794 0x80578794 +805787c0 0x805787c0 +805787f8 0x805787f8 +8057882c 0x8057882c +8057896c 0x8057896c +80578b74 Kart::Movement::ActivateMushroom +80578dcc 0x80578dcc +80578f44 Kart::Movement::EndTrick +80579108 Kart::Movement::ActivateZipperBoost +80579308 0x80579308 +805794b4 Kart::Movement::TryStartJumpPad +80579858 0x80579858 +80579a04 Kart::Movement::ActivateStar +80579b8c 0x80579b8c +80579bd4 Kart::Movement::ApplyShock +80579cb8 0x80579cb8 +80579d88 0x80579d88 +80579de4 0x80579de4 +80579e40 0x80579e40 +80579f04 0x80579f04 +80579f14 Kart::Movement::ApplyShockEffect +8057a134 0x8057a134 +8057a220 0x8057a220 +8057a2b0 Kart::Movement::ActivateMega +8057a478 0x8057a478 +8057a55c 0x8057a55c +8057a6c4 0x8057a6c4 +8057a738 0x8057a738 +8057a7d0 0x8057a7d0 +8057a844 0x8057a844 +8057ab40 0x8057ab40 +8057ab84 0x8057ab84 +8057ada8 Kart::Movement::UpdateScale +8057aebc Kart::Movement::SetScale +8057aed8 0x8057aed8 +8057af14 0x8057af14 +8057afc0 Kart::Movement::CalcBlink +8057b108 0x8057b108 +8057b144 0x8057b144 +8057b1c0 0x8057b1c0 +8057b1c4 Kart::Movement::ActivateTC +8057b1dc Kart::Movement::DeactivateTC +8057b1f4 Kart::Movement::ApplyInk +8057b2b8 Kart::Movement::UpdateCharacterInk +8057b40c 0x8057b40c +8057b42c Kart::Movement::SomethingRespawnBoost +8057b8c8 Kart::Movement::ApplyStartBoost +8057ba14 0x8057ba14 +8057bb40 0x8057bb40 +8057bc24 0x8057bc24 +8057bc64 0x8057bc64 +8057bc8c 0x8057bc8c +8057bccc Kart::Movement::TryEndJumpPad +8057be30 Kart::Movement::UpdateBoost +8057bfa0 0x8057bfa0 +8057c068 0x8057c068 +8057c530 0x8057c530 +8057c550 0x8057c550 +8057c574 0x8057c574 +8057c5d0 0x8057c5d0 +8057c6d4 0x8057c6d4 +8057c6f4 0x8057c6f4 +8057c718 0x8057c718 +8057c738 Kart::Movement::ReleaseMT +8057ca18 0x8057ca18 +8057ca60 0x8057ca60 +8057ca80 Kart::Movement::CancelBoost +8057cbc0 0x8057cbc0 +8057cc28 Kart::Movement::vf_0x24 +8057cdf4 Kart::Movement::OnOOB +8057cf68 Kart::Movement::vf_0x2c +8057d320 0x8057d320 +8057d324 Kart::Movement::UpdateStickyRoad +8057d708 0x8057d708 +8057d820 Kart::Movement::SetInitialPhysicsValues +8057db10 Kart::Movement::DoRespawn +8057de24 0x8057de24 +8057df18 0x8057df18 +8057e104 thunk_0x8058473c +8057e108 thunk_0x8058473c +8057e10c 0x8057e10c +8057e168 Kart::Movement::EnterCannon +8057e534 Kart::Movement::UpdateCannon +8057eaa4 0x8057eaa4 +8057eb78 Kart::Movement::GetCannonPosAndDir +8057ed98 0x8057ed98 +8057f088 Kart::Movement::ActivateBullet +8057f1e0 0x8057f1e0 +8057f204 0x8057f204 +8057f23c 0x8057f23c +8057f27c 0x8057f27c +8057f2c4 0x8057f2c4 +8057f2d4 0x8057f2d4 +8057f898 0x8057f898 +8057ff58 Kart::Movement::UpdateFromPseaVenice +805801b8 Kart::Movement::UpdateDiving +805804f4 0x805804f4 +80580590 0x80580590 +8058066c 0x8058066c +80580784 Kart::Movement::UpdateSlipStream +80580c9c 0x80580c9c +80580d68 Kart::Movement::UpdateWheelie +80580d6c Kart::Movement::UpdateSpecialFloor +80581114 0x80581114 +80581180 0x80581180 +8058130c Kart::MovementBike::__ct +80581354 Kart::Movement::__dt +80581394 Kart::MovementBike::CreateTrickZipper +80581430 Kart::MovementBike::SetTurnParams +805814dc Kart::MovementBike::Reset +80581540 Kart::MovementBike::UpdateWheelie +80581544 Kart::MovementBike::UpdateVehicleRotationVector +80581b00 Kart::MovementBike::GetWheelieSoftSpeedLimitBonus +80581b2c Kart::MovementBike::StartWheelie +80581ba0 Kart::MovementBike::CancelWheelie2 +80581bd0 Kart::MovementBike::UpdateWheelie +80581f74 Kart::MovementBike::TryStartWheelie +8058203c 0x8058203c +80582064 Kart::MovementBike::UpdateMtCharge +8058212c Kart::MovementBike::vf_0x24 +8058230c Kart::MovementBike::CancelWheelie +80582334 Kart::MovementBike::OnOoB +80582488 Kart::MovementBike::vf_0x2c +80582504 Kart::Boost::__ct +80582550 Kart::Boost::Reset +8058258c Kart::Boost::Activate +805825f4 Kart::Boost::CancelAll +80582600 Kart::Boost::Update +8058279c Kart::MovementBike::vf_0x30 +805827ac Kart::MovementBike::vf_0x68 +805827bc Kart::MovementBike::CheckWheelie +80582800 Kart::Movement::GetStarDuration +8058280c 0x8058280c +80582838 0x80582838 +8058288c 0x8058288c +805828f4 0x805828f4 +8058299c 0x8058299c +805829e8 0x805829e8 +80582a0c 0x80582a0c +80582a30 0x80582a30 +80582a48 0x80582a48 +80582ae4 0x80582ae4 +80582bd8 0x80582bd8 +80582bdc Kart::MovementRealLocal::Hop +80582c1c Kart::MovementBikeRealLocal::Hop +80582c5c Kart::MovementBikeRealLocal::StartWheelie +80582cf0 Kart::MovementBikeRealLocal::CancelWheelie2 +80582d48 Kart::MovementRemote::CanHop +80582da8 Kart::MovementBikeRemote::CanHop +80582e08 Kart::MovementBikeRemote::TryStartWheelie +80582e94 Kart::Movement::vf_0x58 +80582e98 Kart::MovementBike::GetLeanRot +80582ea0 Kart::MovementBikeRemote::__dt +80582ee0 Kart::MovementBike::__dt +80582f20 Kart::Movement::CheckWheelie +80582f28 Kart::Movement::GetLeanRot +80582f34 Kart::MovementRemote::__dt +80582f74 Kart::MovementBikeRealLocal::__dt +80582fb4 Kart::MovementRealLocal::__dt +80582ff4 0x80582ff4 +8058300c 0x8058300c +80583020 0x80583020 +80583038 RacedataHandler_consstruct +805830c0 0x805830c0 +80583100 0x80583100 +80583140 0x80583140 +80583168 0x80583168 +80583740 0x80583740 +80583f50 0x80583f50 +80583f90 0x80583f90 +80583fd0 0x80583fd0 +80584010 0x80584010 +80584050 0x80584050 +80584090 0x80584090 +805840d0 0x805840d0 +80584110 0x80584110 +80584150 0x80584150 +80584190 0x80584190 +805841d0 0x805841d0 +80584210 0x80584210 +80584250 0x80584250 +80584290 0x80584290 +805842d0 0x805842d0 +80584310 0x80584310 +80584350 0x80584350 +80584390 0x80584390 +805843e4 0x805843e4 +80584438 0x80584438 +8058448c 0x8058448c +805844e0 0x805844e0 +80584534 0x80584534 +805845b4 0x805845b4 +805845bc 0x805845bc +80584624 0x80584624 +8058462c 0x8058462c +80584694 0x80584694 +8058469c 0x8058469c +80584704 0x80584704 +8058470c 0x8058470c +80584774 0x80584774 +8058477c 0x8058477c +805847e4 0x805847e4 +805847ec 0x805847ec +80584854 0x80584854 +8058485c 0x8058485c +805848c4 0x805848c4 +805848cc 0x805848cc +805848e8 0x805848e8 +80584904 0x80584904 +80584920 0x80584920 +80584974 RacedataHandler_processInputs +80584c70 0x80584c70 +80585084 0x80585084 +805851d4 0x805851d4 +805855bc Audio::KartActor::Reset +805855fc 0x805855fc +80585864 0x80585864 +80585868 0x80585868 +805858b8 0x805858b8 +80585bb4 0x80585bb4 +80585c6c 0x80585c6c +80585c9c 0x80585c9c +80585dc0 0x80585dc0 +80585df0 0x80585df0 +80585df8 0x80585df8 +80585e28 0x80585e28 +80585e30 0x80585e30 +80585e60 0x80585e60 +80585e68 0x80585e68 +80585e98 0x80585e98 +80585ea0 0x80585ea0 +80585ed0 0x80585ed0 +80585ed8 0x80585ed8 +80585f3c 0x80585f3c +80585fa0 0x80585fa0 +80586004 0x80586004 +80586068 0x80586068 +805860cc 0x805860cc +80586130 0x80586130 +80586194 0x80586194 +80586204 RacedataFactory_construct +80586250 0x80586250 +80586290 0x80586290 +80586294 0x80586294 +80586298 RacedataFactory_sendRacedataRecord +8058630c RacedataFactory_packRacedataRecord +80586ba8 RacedataFactoryFlags_construct +80586bf0 RacedataFactoryFlags_destroy +80586c30 0x80586c30 +80586c40 0x80586c40 +80586c58 0x80586c58 +80586c7c 0x80586c7c +80586cb8 0x80586cb8 +80586cf8 0x80586cf8 +80586cfc 0x80586cfc +80586d4c 0x80586d4c +80586e20 0x80586e20 +80586fb4 0x80586fb4 +80587084 0x80587084 +805870b4 0x805870b4 +805870e4 0x805870e4 +80587118 0x80587118 +8058713c 0x8058713c +80587160 0x80587160 +80587184 0x80587184 +80587208 0x80587208 +8058722c 0x8058722c +80587280 0x80587280 +805872bc 0x805872bc +8058730c 0x8058730c +80587330 0x80587330 +805873b8 0x805873b8 +805873e8 0x805873e8 +80587428 0x80587428 +80587434 0x80587434 +80587478 0x80587478 +805874bc 0x805874bc +80587500 0x80587500 +8058753c 0x8058753c +80587598 Kart::Player::__ct +8058768c 0x8058768c +805876cc Kart::Player::__dt +8058773c 0x8058773c +80587758 0x80587758 +805877f0 0x805877f0 +80587964 Kart::Player::InitSub +80587a08 Kart::Player::Init +80587dd4 Kart::Player::CreateBody +80587e24 0x80587e24 +80587f00 0x80587f00 +80587fa0 0x80587fa0 +80587fe0 Kart::Player::PrepateTiresAndSUspensions +8058816c 0x8058816c +805881e8 Kart::Player::InitWheels +805883e4 Kart::Wheel::__dt +80588424 0x80588424 +805884bc Kart::Player::CreateSound +80588504 0x80588504 +80588544 0x80588544 +80588624 Kart::Player::SetStartPosition +80588690 Kart::Player::UpdateKartSub +80588698 Kart::Player::Update2 +80588828 0x80588828 +805889d0 Kart::Wheel::vf_0x24 +805889e8 0x805889e8 +80588a3c Kart::PlayerBike::CreateBody +80588ac4 Kart::PlayerBike::InitWheels +80588c88 Kart::WheelFront::__dt +80588cc8 Kart::WheelBikeFront::__dt +80588d08 Kart::Suspensions::__dt +80588d48 Kart::PlayerBike::CreateSound +80588d90 Kart::Manager::SetupPlayer +80588ffc Kart::Player::CreateModel +8058908c Kart::PlayerBike::__dt +80589100 0x80589100 +8058916c 0x8058916c +805891ac 0x805891ac +805891ec Kart::Manager::Disposer__dt +80589284 Kart::Manager::CreateInstance +805892d4 Kart::Manager::DestroyInstance +80589308 Kart::Manager::__ct +805895b0 Kart::Manager::__dt +805896bc Kart::Manager::Init +805897c4 Kart::Manager::Update +805898dc Kart::Manager::GetKartPlayer +805898ec 0x805898ec +80589904 Kart::Link::InitList +80589914 Kart::Link::LinkKartList +80589968 Kart::Link::__ct +805899ac Kart::Link::SetPointersFromPlayer +805899e8 Kart::Link::GetKartPosition +80589a00 Kart::Player::GetPreviousPosition +80589a14 Kart::Link::SetKartPosition +80589a40 Kart::Link::GetMtx +80589a54 Kart::Link::GetKartBodyMtx +80589a64 Kart::Link::SetKartRotation +80589ab8 Kart::Link::GetWheelCount0 +80589ac8 Kart::Link::GetWheelCount1 +80589ad8 Kart::Link::GetWheelCountReciprocal +80589ae8 Kart::Link::GetWheelCountPlus1Reciprocal +80589af8 Kart::Link::GetWheelPosition +80589b14 Kart::Link::WheelHasFloorCollision +80589b2c Kart::Link::SetBody0x94 +80589b44 Kart::Link::SetBodyHandleDistance +80589b5c Kart::Link::SetStartBoost +80589b6c Kart::Link::GetWheelSpeed +80589b88 Kart::Link::GetPhysicsHolder +80589b98 Kart::Link::GetPhysicsHolder(const) +80589ba8 Kart::Link::GetPhysics +80589bbc Kart::Link::GetPhysics(const) +80589bd0 Kart::Link::GetControllerHolder +80589bf8 Kart::Link::ActivateRumble(3 args) +80589c54 Kart::Link::ActivateRumble(1 arg) +80589d4c Kart::Link::ActivateRumble(no arg) +80589e2c Kart::Link::IsLocal +80589e40 Kart::Link::IsCPU +80589e54 Kart::Link::IsGhost +80589e68 Kart::Link::IsMii +80589e78 Kart::Link::GetBody +80589e84 Kart::Link::GetBody(const) +80589e90 Kart::Link::GetSuspensions +80589ea4 Kart::Link::GetSuspensions(const) +80589eb8 Kart::Link::GetWheels +80589ecc Kart::Link::GetWheels(const) +80589ee0 Kart::Link::GetWheelPhysicsHolder +80589ef8 Kart::Link::GetWheelPhysicsHolder(const) +80589f10 Kart::Link::GetWheelPhysics +80589f28 Kart::Link::GetWheelPhysics(const) +80589f40 Kart::Link::GetSub +80589f4c Kart::Link::GetSub(const) +80589f58 Kart::Link::GetMovement +80589f64 Kart::Link::GetMovement(const) +80589f70 Kart::Link::GetKartActor +80589f7c Kart::Link::GetCharacterActor +80589f8c Kart::Link::PlayCharacterSound +80589f9c Kart::Link::GetObject +80589fa8 Kart::Link::GetShadow +80589fb4 Kart::Link::GetPhysicsHolderHitboxGroup +80589fc8 Kart::Link::GetPhysicsHolderHitboxGroup(const) +80589fdc Kart::Link::GetWheelPhysicsHitboxGroup +80589ff8 Kart::Link::GetVehicleBodyCollisionData +8058a010 Kart::Link::GetWheelCollisionData +8058a028 Kart::Link::GetCollision +8058a034 Kart::Link::GetCollision(const) +8058a040 Kart::Link::GetStatsAndBsp +8058a050 Kart::Link::GetStats +8058a064 Kart::Link::GetBsp +8058a078 Kart::Link::GetBspHitboxes +8058a090 Kart::Link::GetBspWheel +8058a0b0 Kart::Link::GetValues0x18 +8058a0c0 Kart::Link::GetKartDriverDispEntry +8058a0d0 Kart::Link::GetRotatingItemsParams +8058a0e8 Kart::Link::GetKartPartsDispEntry +8058a0f8 Kart::Link::GetBikePartsDispEntry +8058a108 Kart::Link::GetExhaustParticleSet2 +8058a134 Kart::Link::GetExhaustParticleSet +8058a168 Kart::Link::GetBalloonsPosition +8058a194 Kart::Link::GetDriverDispEntry +8058a1a4 Kart::Link::GetCameraVerticalDistance +8058a1d0 Kart::Link::GetBaseHopStickX +8058a1e0 Kart::Link::GetHopStickX +8058a1ec Kart::Link::GetType +8058a204 Kart::Link::GetStatsWheelCount +8058a21c Kart::Link::GetDriverController +8058a228 Kart::Link::GetTriggersCollisionRadius +8058a238 Kart::Link::GetPlayerIdx +8058a248 Kart::Link::IsBike +8058a258 Kart::Link::GetKartId +8058a268 Kart::Link::ToggleKartVisible +8058a278 Kart::Link::ToggleVisible +8058a420 Kart::Link::GetBodyMatCol0(copy) +8058a448 Kart::Link::GetBodyMatCol1(copy) +8058a470 Kart::Link::GetBodyMatCol2(copy) +8058a498 Kart::Link::GetBodyMatCol0 +8058a4ac Kart::Link::GetBodyMatCol1 +8058a4c0 Kart::Link::GetBodyMatCol2 +8058a4d4 Kart::Link::GetEngineSpeed +8058a4e4 Kart::Link::GetSpeed +8058a4fc Kart::Link::GetDamage +8058a508 Kart::Link::GetDamage(const) +8058a514 Kart::Link::80590d38 +8058a538 Kart::Link::SetDamageType +8058a564 Kart::Link::SetAffectedByPOW +8058a570 Kart::Link::80590d94 +8058a580 Kart::Link::GetCurDamageType +8058a590 Kart::Link::CancelBoost +8058a59c Kart::Link::GetSpeedRatioCapped +8058a5ac Kart::Link::GetSpeedRatio +8058a5bc Kart::Link::HasCamera +8058a5d4 Kart::Link::SetCamera +8058a5e0 Kart::Link::GetScreenIdx +8058a604 Kart::Link::UpdateCameraOnRespawn +8058a61c Kart::Link::UpdateCameraOnBoost +8058a634 Kart::Link::ResetCameraFov +8058a64c Kart::Link::UpdateCameraOnExplosion +8058a664 Kart::Link::80590e88 +8058a668 Kart::Link::80590e8c +8058a680 Kart::Link::80590ea4 +8058a6b4 Kart::Link::StopCloseCamera +8058a6d4 Kart::Link::SetCamera +8058a6f4 Kart::Link::StopCameraMovAndRotation +8058a714 Kart::Link::80590f38 +8058a734 Kart::Link::80590f58 +8058a74c Kart::Link::UpdateCameraOnOOBHit +8058a76c Kart::Link::ActivateStarAnm +8058a778 Kart::Link::80590f9c +8058a808 Kart::Link::UpdateStarAnm +8058a814 Kart::Link::StopStarAnm +8058a820 Kart::Link::80591044 +8058a82c Kart::Link::80591050 +8058a84c Kart::Link::GetStarAnm +8058a858 Kart::Link::GetStarColor +8058a868 Kart::Link::GetModelsVisibility +8058a874 Kart::Link::GetModelsVisibility +8058a880 Kart::Link::GetMatTEVHandler +8058a88c Kart::Link::GetBaseSpeed +8058a89c Kart::Link::GetAIController +8058a8a8 Kart::Link::GetBodyClosestFloorFlags +8058a8c0 Kart::Link::GetBodyClosestFloorSettings +8058a8d8 Kart::Link::IsWheelHittingWall +8058a914 Kart::Link::GetClosestFloorKCLFlags +8058a94c Kart::Link::GetClosestFloorKCLSettingss +8058a984 Kart::Link::GetBodyKCLIntensity +8058a99c Kart::Link::805911c0 +8058a9b4 Kart::Link::GetDriftState +8058a9c4 Kart::Link::GetMTCharge +8058a9d4 Kart::Link::GetSMTCharge +8058a9e4 Kart::Link::GetMTMaxCharge +8058a9f0 Kart::Link::GetSMTMaxCharge +8058a9fc Kart::Link::TranslateBody +8058aa40 Kart::Link::80591264 +8058aaf0 Kart::Link::IsRespawning +8058ab20 Kart::Link::80591344 +8058ab54 Kart::Link::80591378 +8058ab84 Kart::Link::805913a8 +8058abd8 Kart::Link::IsWaitingForBackwards +8058abf4 Kart::Link::GetBackwardsAllowCounter +8058ac04 Kart::Link::Get1stLight +8058ac10 Kart::Link::Get2ndLight +8058ac1c Kart::Link::GetRacedataFactory +8058ac28 Kart::Link::GetRacedataHandler +8058ac34 Kart::Link::GetRacedataFactoryFlags +8058ac44 Kart::Link::80591468 +8058ac54 Kart::Link::SetScale +8058ac98 Kart::Link::GetScale +8058aca8 Kart::Link::IsWheelieing +8058acc0 Kart::Link::GetStartBoostCharge +8058acd0 Kart::Link::805914f4 +8058acfc Kart::Link::GetEntity +8058ad08 Kart::Link::GetClipInfo +8058ad14 Kart::Link::CallOnAllPartsFunc +8058ade4 Kart::Link::AreKartModelsVisible +8058adf4 Kart::Link::GetKiller +8058ae00 Kart::Link::GetBillViewMtx +8058ae40 Kart::Link::ResetInertia +8058aee8 Kart::Link::8059170c +8058af60 Kart::Link::StartOobWipe +8058af7c Kart::Link::GetOobWipeState +8058af8c Kart::Link::805917b0 +8058af9c Kart::Link::805917c0 +8058afd0 Kart::Link::805917f4 +8058b004 Kart::Link::80591828 +8058b028 Kart::Link::8059184c +8058b074 Kart::Link::80591898 +8058b098 Kart::Link::IncrementItemsHitCount +8058b0bc Kart::Link::IncrementItemsCollisionCount +8058b0e0 Kart::Link::GetZipper +8058b0f0 Kart::Link::GetTrick +8058b100 Kart::Link::InitLights +8058b158 Kart::Link::SetLightObjIdx +8058b174 0x8058b174 +8058b1c4 0x8058b1c4 +8058b1d0 Kart::InitParamBinsFromCommon +8058b350 Kart::InitParamBinsFromRace +8058b478 Kart::ResetParamBins +8058b4c4 Kart::GetParamBinFromCommon +8058b4dc Kart::GetParamBinFromRace +8058b528 Kart::GetParamBin +8058b598 Kart::GetBSP +8058b5ac Kart::LoadKartAndDriverParamBinsFromCommon +8058b634 Kart::LoadKartParamBinFromCommon +8058b684 Kart::LoadDriverParamBinFromCommon +8058b6d4 Kart::LoadStatsParamFileFromCommon +8058b728 Kart::GetKartParamEntry +8058b73c Kart::GetDriverParamEntry +8058b780 Kart::ComputeStats +8058bbe8 Kart::LoadKartDriverDisp +8058bc74 Kart::GetKartDriverDispEntry +8058bca8 Kart::LoadKartPartsDisp +8058bd34 Kart::GetKartPartsDispEntry +8058bd70 Kart::LoadBikePartsDisp +8058bdfc Kart::GetBikePartsDispEntry +8058be3c Kart::SetMiiDispParam +8058be54 Kart::LoadMiiDisp +8058bea4 Kart::LoadMiiDispFromMiiBody +8058bef4 Kart::LoadCameraParam +8058bf38 Kart::LoadDriverDisp +8058bf88 Kart::GetMiiDispEntry +8058bf9c Kart::GetDriverDispEntry +8058bfb0 Kart::Link::GetCameraParamBin +8058c024 Kart::Part::__ct +8058c0b8 0x8058c0b8 +8058c0fc Kart::Part::CreateModelDirectors +8058c204 Kart::Part::LoadModel +8058c20c Kart::Part::Create2ndModelDirector +8058c330 Kart::Part::Load +8058c340 Kart::Part::UpdateMatrix +8058c3d4 0x8058c3d4 +8058c498 Kart::Part::vf_0xC +8058c4b8 Kart::Part::SetModelScale +8058c4e0 Kart::Part::SetModelMtx +8058c564 Kart::Part::ToggleModelVisible +8058c58c Kart::Part::vf_0x20 +8058c5c0 0x8058c5c0 +8058c5d4 Kart::Part::ApplyStarColors +8058c638 Kart::Part::vf_0x2c +8058c6bc Kart::Part::vf_0x30 +8058c728 Kart::Part::UpdateModelDrawPriority +8058c784 0x8058c784 +8058c79c Kart::Values::__ct +8058c868 0x8058c868 +8058c8c0 0x8058c8c0 +8058c900 0x8058c900 +8058c904 0x8058c904 +8058c914 0x8058c914 +8058caec 0x8058caec +8058cc38 0x8058cc38 +8058cf58 0x8058cf58 +8058cfb0 0x8058cfb0 +8058cff0 0x8058cff0 +8058d3fc 0x8058d3fc +8058d454 0x8058d454 +8058d494 0x8058d494 +8058d4e8 0x8058d4e8 +8058d4f8 0x8058d4f8 +8058d530 0x8058d530 +8058d598 0x8058d598 +8058d5e4 0x8058d5e4 +8058d5f4 0x8058d5f4 +8058d780 0x8058d780 +8058d870 0x8058d870 +8058d8b0 0x8058d8b0 +8058d910 0x8058d910 +8058d998 0x8058d998 +8058db90 Kart::Status::__ct +8058dd38 Kart::Status::Reset +8058dd70 Kart::Status::Init +8058de10 0x8058de10 +8058de20 0x8058de20 +8058dee0 0x8058dee0 +8058df28 Kart::Status::UpdateCollisionsAndMore +8058e058 Kart::Status::UpdateFromInput +8058e3b0 Kart::Status::UpdateCollisions +8058f0c8 0x8058f0c8 +8058f0cc 0x8058f0cc +8058f0f4 Kart::Status::UpdateStartBoostCharge +8058f1b0 Kart::Status::ComputeStartBoost +8058f2d4 Kart::Status::ApplyStartBoost +8058f438 0x8058f438 +8058f480 0x8058f480 +8058f490 0x8058f490 +8058f4a0 Kart::Status::__dt +8058f4e0 0x8058f4e0 +8058f524 Kart::Sub::Init +8058f754 Kart::Sub::InitParts +8058f8d8 0x8058f8d8 +8058f958 Kart::Sub::ResetPhysics +8058fbc0 0x8058fbc0 +8058fc30 Kart::Sub::SetPointers +8058fc5c Kart::Sub::Update +805904d8 Kart::Player::ApplyPhysics +80591018 Kart::Sub::UpdateTransforms +80591110 0x80591110 +805911c8 0x805911c8 +8059121c 0x8059121c +80591264 Kart::Sub::UpdateMovingRoad +80591528 Kart::Player::ApplyCollisionForce +805918b4 0x805918b4 +80591a68 Kart::Sub::InitEntity +80591b14 0x80591b14 +80591bb8 0x80591bb8 +80591bd0 0x80591bd0 +80591be8 0x80591be8 +80591e0c 0x80591e0c +80591f20 0x80591f20 +8059206c 0x8059206c +805922a4 Kart::Sub::__dt +805922e4 Kart::Suspensions::__ct +8059232c Kart::Suspensions::LoadModel +8059233c Kart::Suspensions::Init +805923b0 Kart::Suspensions::InitPhysicsHolder +805923b8 Kart::Suspensions::Reset +805923c0 0x805923c0 +805923c8 Kart::Suspensions::UpdateMatrix +805927c4 Kart::SuspensionsBike::LoadModel +805927d4 Kart::SuspensionsBike::UpdateMatrix +80592900 0x80592900 +80592910 0x80592910 +80592b68 0x80592b68 +80592ba8 Kart::SuspensionsBike::__dt +80592be8 WheelPhysics::__ct +80592c4c WheelPhysics::InitHitboxGroup +80592cb0 0x80592cb0 +80592ce4 WheelPhysics::Reset +80592d9c 0x80592d9c +80592e6c WheelPhysics::UpdateCollision +805932ac WheelPhysics::Realign +80593578 0x80593578 +8059359c 0x8059359c +80593688 WheelPhysics::HasFloorCollision +80593698 AnimatedModelExplodable_GetWorldMatrix +805936a4 WheelPhysics::GetCollisionData +805936b0 WheelPhysicsHolder::__ct +80593730 WheelPhysicsHolder::Reset +8059377c 0x8059377c +80593808 0x80593808 +80593a54 WheelPhysicsHolder::Update +80593cd4 Vec3::MultMtxByVec +80593d50 WheelPhysicsHolder::ApplySuspensions +805941a0 WheelPhysics::__dt +805941e0 0x805941e0 +80594220 Kart::Wheel::__ct +8059428c Kart::Wheel::Init +805942f0 Kart::Wheel::CreatePhysics +80594344 0x80594344 +8059434c Kart::Wheel::LoadModel +805943d0 Kart::WheelFront::LoadModel +805943f8 Kart::WheelFront::CreatePhysics +8059444c Kart::Wheel::UpdateMatrix +80594618 0x80594618 +805946a8 Kart::WheelFront::UpdateMatrix +80594814 Kart::WheelBikeFront::CreatePhysics +80594868 Kart::WheelBikeFront::LoadModel +80594878 Kart::WheelBikeFront::UpdateMatrix +805949d8 Kart::WheelBikeRear::CreatePhysics +80594a2c Kart::WheelBikeRear::LoadModel +80594a3c Kart::WheelBikeRear::UpdateMatrix +80594b94 0x80594b94 +80594d00 0x80594d00 +80594d40 Kart::WheelBikeRear::__dt +80594d80 0x80594d80 +80594dbc 0x80594dbc +80594dc0 0x80594dc0 +80594e70 0x80594e70 +80594ed4 0x80594ed4 +80594f2c 0x80594f2c +80594f84 RendererMenu::__ct +8059500c RendererMenu::Calc +80595044 RendererMenu::DrawModels +805957cc MenuModel::vf_0x18 +805957e4 RendererMenu::Draw +80595898 Kart::PhysicsHolder::Init +80595954 Kart::Physics::__dt +80595994 0x80595994 +805959d4 Kart::PhysicsHolder::__dt +80595a64 0x80595a64 +80595aa4 Kart::PhysicsHolder::Reset +80595c44 Kart::PhysicsHolder::Update +80595ee4 0x80595ee4 +80595f0c 0x80595f0c +80595f24 0x80595f24 +80595fe8 0x80595fe8 +805960ac 0x805960ac +80596170 0x80596170 +80596234 0x80596234 +8059632c 0x8059632c +805963ac 0x805963ac +80596428 0x80596428 +805964a8 0x805964a8 +80596594 0x80596594 +8059661c Kart::PhysicsHolder::UpdateMat +805966a0 0x805966a0 +805966ec Kart::PhysicsHolder::ResetQuaternions +8059675c 0x8059675c +8059677c Kart::PhysicsHolder::__ct +8059682c CameraLink::__ct +80596884 GameCamera::__ct +805969a0 CameraLink::__dt +805969e0 GameCamera::Update +805969fc CameraMgr::__ct +80596a0c CameraLink::InitCameraList +80596a2c CameraMgr::SetInstance +80596a44 CameraLink::Register +80596a54 0x80596a54 +80596ab8 CameraLink::UpdateAllCameras +80596b40 CameraMgr::Update +80596b44 CameraMgr::__dt +80596b84 GameCamera::__dt +80596bc4 GameCamera::vf_0xC +80596bc8 GameCamera::GetPosition +80596be4 GameCamera::GetViewMatrix(const) +80596bec GameCamera::Update(thunk) +80596bf4 GameCamera::vf_0xC(thunk) +80596bfc GameCamera::__dt(thunk) +80596c04 GameCamValues::Reset +80596cbc RaceCamera::CopyVec(2vecs) +80596cd8 RaceCamera::_ct +80596f74 0x80596f74 +80596f78 Vec3::__ct(no args) +80596f7c 0x80596f7c +80596fbc 0x80596fbc +80596ffc RaceCamera::Init +80597190 RaceCamera::GetCamParams +80597198 RaceCamera::Update +80597ad0 0x80597ad0 +80597ae8 RaceCamera::CopyVec(1vec) +80597b04 RaceCamera::CheckBitfield334 +80597b1c 0x80597b1c +80597b24 RaceCamera::NegateVec +80597b4c 0x80597b4c +80597bfc 0x80597bfc +80597c5c RaceCamera::SubtractVecs +80597c90 RaceCamera::AddVecs(3vecs) +80597cc4 0x80597cc4 +80597fa8 RaceCamera::LinearTransfo(2vecs) +80597fe8 RaceCamera::DotVec +80598018 RaceCamera::CheckKartStatusField1 +80598038 0x80598038 +805982dc RaceCamera::CheckKartStatusField0 +805982fc RaceCamera::IsAutomatic +80598310 RaceCamera::ClampFloat +80598344 RaceCamera::AcosDeg +80598430 0x80598430 +80598478 RaceCamera::UpdateCamValues +80598df4 RaceCamera::CrossVec +80598e40 RaceCamera::NormalizeAndGetNorm +80598e44 RaceCamera::CompareFloats +80598e64 PSMTXMultVec +80598e68 RaceCamera::ScaleVec(2vecs) +80598e90 0x80598e90 +80598e98 0x80598e98 +80598ea0 0x80598ea0 +80598ea8 0x80598ea8 +80598f58 0x80598f58 +80598f8c RaceCamera::SubtractVecsPS +80598fb0 RaceCamera::AddVecs(2vecs) +80598fe4 RaceCamera::ScaleVec(3vecs) +8059900c 0x8059900c +80599014 0x80599014 +80599054 0x80599054 +8059905c RaceCamera::GetVecMag +80599060 RaceCamera::NormalizeVecPS +80599098 0x80599098 +80599604 0x80599604 +8059976c 0x8059976c +805998f8 0x805998f8 +80599984 RaceCamera::OnRespawn +80599bac 0x80599bac +80599bd0 0x80599bd0 +80599ca4 RaceCamera::FlushPrevValues +80599cd8 0x80599cd8 +80599d84 RaceCamera::OnBoost +80599da4 RaceCamera::ResetAddedFov +80599db4 RaceCamera::OnExplosion +80599de8 0x80599de8 +80599dfc 0x80599dfc +8059a510 0x8059a510 +8059a794 0x8059a794 +8059acf8 0x8059acf8 +8059ad38 RaceCamera::vf_0x50 +8059b58c 0x8059b58c +8059b5c0 0x8059b5c0 +8059b5f0 0x8059b5f0 +8059b6a0 0x8059b6a0 +8059b784 0x8059b784 +8059b848 0x8059b848 +8059b8c0 0x8059b8c0 +8059ba80 0x8059ba80 +8059bb60 0x8059bb60 +8059bbcc 0x8059bbcc +8059bc10 0x8059bc10 +8059bc20 RaceCamera::GetViewMtx +8059bd94 0x8059bd94 +8059bdac 0x8059bdac +8059bdf8 0x8059bdf8 +8059be08 BCPInfo::Load +8059be7c 0x8059be7c +8059becc 0x8059becc +8059bf0c OpeningPan::Load +8059c068 OpeningPan::Init +8059c2a4 0x8059c2a4 +8059c320 OpeningPan::Calc +8059c530 0x8059c530 +8059c554 cPN_Feather_SetNodeWeight +8059c564 0x8059c564 +8059c574 FormationSet_GetFormationSpec +8059c584 0x8059c584 +8059c594 0x8059c594 +8059c698 0x8059c698 +8059c6f4 0x8059c6f4 +8059c7b8 0x8059c7b8 +8059c7e8 0x8059c7e8 +8059d314 RaceCameraMgr::Disposer__dt +8059d3ac RaceCameraMgr::CreateInstance +8059d3fc RaceCameraMgr::DestroyInstance +8059d430 RaceCameraMgr::__ct +8059dca4 RaceCameraMgr::__dt +8059dd5c 0x8059dd5c +8059df44 RaceCamera::__dt +8059df84 RaceCameraMgr::HasEveryOpeningPanEnded +8059dfd4 RaceCameraMgr::Update +8059e034 RaceCameraMgr::ApplyShaking +8059e27c 0x8059e27c +8059e3f8 0x8059e3f8 +8059e4a0 0x8059e4a0 +8059e4f8 0x8059e4f8 +8059e674 0x8059e674 +8059e6d0 0x8059e6d0 +8059e864 0x8059e864 +8059e8cc 0x8059e8cc +8059e938 0x8059e938 +8059e978 0x8059e978 +8059e9ac 0x8059e9ac +8059e9dc 0x8059e9dc +8059ea08 0x8059ea08 +8059eacc RaceCameraMgr::ChangeFocusedPlayer +8059eb2c 0x8059eb2c +8059eb6c OpeningPan::__dt +8059ebac RaceCamera::__dt(thunk) +8059ebb4 RaceCamera::Update(thunk) +8059ebbc RaceCamera::Init(thunk) +8059ebc4 0x8059ebc4 +8059ebcc AutoCameraMover::__ct +8059ec80 0x8059ec80 +8059ecf8 0x8059ecf8 +8059ed08 0x8059ed08 +8059ed18 0x8059ed18 +8059eea4 0x8059eea4 +8059eeac 0x8059eeac +8059ef24 0x8059ef24 +8059f108 0x8059f108 +8059f110 0x8059f110 +8059f1fc 0x8059f1fc +8059f6e0 0x8059f6e0 +8059f7b8 0x8059f7b8 +8059f868 0x8059f868 +8059f8b4 0x8059f8b4 +8059f910 0x8059f910 +8059f9cc 0x8059f9cc +8059fbb4 0x8059fbb4 +8059fc34 0x8059fc34 +8059fcd8 0x8059fcd8 +8059ff34 AutoCameraMoverRace::__ct +805a0544 0x805a0544 +805a0584 0x805a0584 +805a05c4 0x805a05c4 +805a0604 AutoCameraMoverRace::ResetActions +805a060c AutoCameraMoverRace::vf_0x10 +805a0b60 0x805a0b60 +805a0d20 0x805a0d20 +805a0d28 0x805a0d28 +805a0e2c 0x805a0e2c +805a0ed0 0x805a0ed0 +805a0ed4 0x805a0ed4 +805a0ee4 0x805a0ee4 +805a0ef4 0x805a0ef4 +805a0f04 0x805a0f04 +805a0f14 0x805a0f14 +805a0f24 0x805a0f24 +805a0f34 0x805a0f34 +805a0f64 AutoCameraMoverRace::OnAction0Start +805a0f68 AutoCameraMoverRace::OnAction0Update +805a104c AutoCameraMoverRace::OnAction1Start +805a1078 AutoCameraMoverRace::OnAction1Update +805a11b0 AutoCameraMoverRace::OnAction2Start +805a1288 AutoCameraMoverRace::OnAction2Update +805a13c0 AutoCameraMoverRace::OnRaceEndStart +805a141c AutoCameraMoverRace::OnRaceEndUpdate +805a153c AutoCameraMoverRace::OnAction4Start +805a15f8 AutoCameraMoverRace::OnAction4Update +805a1704 AutoCameraMoverRace::OnAction5Start +805a17dc AutoCameraMoverRace::OnAction5Update +805a1954 AutoCameraMoverRace::OnAction6Start +805a1ac4 AutoCameraMoverRace::OnAction6Update +805a1bb4 0x805a1bb4 +805a1ccc 0x805a1ccc +805a1eb4 0x805a1eb4 +805a1f24 0x805a1f24 +805a1ff4 0x805a1ff4 +805a2224 0x805a2224 +805a2248 0x805a2248 +805a22c0 DemoCamera_ct +805a24b8 0x805a24b8 +805a24f8 DemoCamera_init +805a264c 0x805a264c +805a2660 0x805a2660 +805a28b4 0x805a28b4 +805a2944 0x805a2944 +805a29bc 0x805a29bc +805a2ac0 0x805a2ac0 +805a2b7c 0x805a2b7c +805a2bd8 0x805a2bd8 +805a2d48 0x805a2d48 +805a2e30 0x805a2e30 +805a2e70 0x805a2e70 +805a2eb0 0x805a2eb0 +805a2ef8 0x805a2ef8 +805a2f28 0x805a2f28 +805a2f70 CamMove::OnStart +805a2fb8 CamMove::Update +805a2fe8 CamMove::OnEnd +805a3030 0x805a3030 +805a30c8 BFGHolder::__ct +805a31d0 BFGHolder::Update +805a3434 0x805a3434 +805a3494 0x805a3494 +805a3518 FogManager::__ct +805a3614 FogManager::Update +805a36cc 0x805a36cc +805a37e8 0x805a37e8 +805a380c FogManager::__dt +805a384c BFGHolder::__dt +805a388c 0x805a388c +805a39a8 0x805a39a8 +805a3ac4 VEC3_perpInPlane +805a3bb0 0x805a3bb0 +805a3c60 Vec3_projUnit +805a3ca8 VEC3_rejUnit +805a3cfc VEC3_projAndRej +805a3d64 0x805a3d64 +805a3d80 0x805a3d80 +805a3dec 0x805a3dec +805a3eec 0x805a3eec +805a3f9c GetPath +805a4044 0x805a4044 +805a40f8 0x805a40f8 +805a4120 0x805a4120 +805a41c8 0x805a41c8 +805a4220 0x805a4220 +805a4294 0x805a4294 +805a4300 0x805a4300 +805a4408 0x805a4408 +805a4448 ScnMgrCreator::Disposer__dt +805a44e0 ScnMgrCreator::CreateInstance +805a4564 0x805a4564 +805a45a4 ScnMgrCreator::DestroyInstance +805a45d8 ScnMgrCreator::__dt +805a4680 ScnMgrCreator::CreateScnMgr +805a484c ScnMgrCreator::CreateRace +805a4a20 0x805a4a20 +805a4ac0 ScnMgrCreator::CreateMenu +805a4b88 ScnMgrCreator::CreateGlobe +805a4c50 0x805a4c50 +805a4d20 0x805a4d20 +805a4d30 0x805a4d30 +805a4d70 0x805a4d70 +805a4dec 0x805a4dec +805a4ef8 0x805a4ef8 +805a4f60 0x805a4f60 +805a518c 0x805a518c +805a5374 0x805a5374 +805a556c 0x805a556c +805a5604 0x805a5604 +805a5c00 0x805a5c00 +805a5f18 0x805a5f18 +805a63d4 0x805a63d4 +805a63d8 ScnMgrRace::__ct +805a642c ScnMgrRace::__ct +805a6484 0x805a6484 +805a6524 ScnMgrRace::805b144c +805a6548 ScnMgrRace::SetModelXluDrawPriority +805a65b8 ScnMgrRace::LoadPostEffects +805a6af0 ScnMgrRace::LoadLights +805a6b4c ScnMgrRace::vf_0xC +805a6d50 ScnMgrRace::CalcSelf +805a6db0 ScnMgrRace::Draw +805a6e34 0x805a6e34 +805a7004 0x805a7004 +805a71e8 ScnMgrRace::UpdateCameras +805a7240 0x805a7240 +805a72c0 0x805a72c0 +805a731c 0x805a731c +805a7454 0x805a7454 +805a7628 0x805a7628 +805a7640 0x805a7640 +805a772c 0x805a772c +805a7818 0x805a7818 +805a8364 0x805a8364 +805a8408 0x805a8408 +805a8548 0x805a8548 +805a8624 0x805a8624 +805a8748 0x805a8748 +805a87bc 0x805a87bc +805a87c0 0x805a87c0 +805a8b30 0x805a8b30 +805a8b44 ScnProcShadows::Draw +805a8b50 ScnProcShadows2::Draw +805a8b5c 0x805a8b5c +805a8b68 0x805a8b68 +805a8b74 ScnProcEffects::Draw +805a8bac ScnProcCourseFilterEffect::Draw +805a8bcc ScnProcEffectsSelfItem::Draw +805a8bd8 ScnMgrRace::Init +805a8f80 ScnProcEffectsSelfItem::__dt +805a8fd8 ScnProcCourseFilterEffect::__dt +805a9030 ScnProcEffects::__dt +805a9088 0x805a9088 +805a90e0 0x805a90e0 +805a9138 ScnProcShadows2::__dt +805a9190 ScnProcShadows::__dt +805a91e8 RendererRaceUIScreen::__ct +805a922c RendererRaceUIScreen::__dt +805a9284 RendererRaceUIScreen::Draw +805a9314 RendererRaceUIOrtho::__ct +805a9358 RendererRaceUIOrtho::__dt +805a93b0 RendererRaceUIOrtho::Draw +805a93ec RendererRaceUIOrtho::Calc +805a93f0 RendererRaceUIScreen::Calc +805a93f4 RendererRaceModels::__ct +805a9440 RendererRaceModels::DrawModels +805a9494 RendererRaceModels::vf_0x1c +805a9560 RendererRaceModels::Draw +805a95e4 0x805a95e4 +805a975c RendererRaceModels::__dt +805a97b4 0x805a97b4 +805a97c0 0x805a97c0 +805a9984 0x805a9984 +805a9b08 0x805a9b08 +805a9b64 0x805a9b64 +805a9b70 0x805a9b70 +805a9bd0 Kart::Physics::__ct +805a9c2c Kart::Physics::Reset +805a9dfc Kart::Physics::ResetSpeed +805a9e98 Kart::Physics::Init(Reset Thunk) +805a9e9c Kart::Physics::Init +805a9f5c Kart::Physics::InitInertia +805aa00c Kart::Physics::CalcInvInertia +805aa01c 0x805aa01c +805aa1d0 0x805aa1d0 +805aa248 Kart::Physics::Update +805aac3c 0x805aac3c +805aac40 Kart::Physics::Stabilize +805aadc0 0x805aadc0 +805aaf18 0x805aaf18 +805ab01c 0x805ab01c +805ab050 0x805ab050 +805ab228 Kart::Physics::ApplyWheelSuspension +805ab374 0x805ab374 +805ab460 0x805ab460 +805ab494 0x805ab494 +805ab510 0x805ab510 +805ab520 Kart::PhysicsBike::Stabilize +805ab7bc Kart::PhysicsBike::__dt +805ab7fc Kart::Collision::UpdateCollisionsInner +805abb74 0x805abb74 +805abe20 Kart::Collision::ApplyBodyCollision +805ac024 Kart::Collision::UpdateWheelCollision +805ac334 0x805ac334 +805ac390 0x805ac390 +805ac9a8 0x805ac9a8 +805aca00 0x805aca00 +805ad020 Hitbox::Set +805ad05c Hitbox::Reset +805ad094 Hitbox::Update +805ad180 0x805ad180 +805ad230 0x805ad230 +805ad2a8 0x805ad2a8 +805ad2bc 0x805ad2bc +805ad2f4 CollisionData::__ct +805ad394 HitboxGroup::__ct +805ad408 HitboxGroup::Reset +805ad4b0 0x805ad4b0 +805ad4f8 0x805ad4f8 +805ad558 0x805ad558 +805ad598 HitboxGroup::__ct(hitboxes) +805ad780 0x805ad780 +805ad834 HitboxGroup::__ct(radius,position) +805ad914 HitboxGroup::UpdateBoundingRadius +805ada5c ShadowModelDirector::__ct(ClipInfo) +805adacc ShadowModelDirector::__ct +805adb20 ShadowModelDirector::__dt +805adb78 ShadowModelDirector::SetScnOptions +805adc7c ShadowModelsMgr::Disposer__dt +805add14 ShadowModelsMgr::CreateInstance +805addd4 ShadowModelsMgr::DestroyInstance +805ade08 ShadowModelsMgr::__ct +805ade9c ShadowModelsMgr::__dt +805adf38 ShadowModelsMgr::InsertModel +805adf40 ShadowModelsMgr::InsertModel2 +805adf48 ShadowModelsMgr::Draw +805ae018 ShadowModelsMgr::Draw2 +805ae0e8 Kart::ScaleAnmController::LoadAnimations +805ae218 Kart::ScaleAnmController::GetAnmScale +805ae270 Kart::ScaleAnmController::GetPressUpAnmScale +805ae2c0 Kart::ScaleAnmController::__ct +805ae40c 0x805ae40c +805ae44c 0x805ae44c +805ae48c Kart::ScaleAnmController::Reset +805ae530 Kart::ScaleAnmController::RequestScaleChange +805ae5dc 0x805ae5dc +805ae610 0x805ae610 +805ae648 0x805ae648 +805ae6e4 Kart::ScaleAnmController::RequestEndScale +805ae794 Kart::ScaleAnmController::Update +805ae9d8 0x805ae9d8 +805aeb24 Kart::ScaleAnmController::__dt +805aeb64 KartScaleAnmController_cpp_sinit_ +805aebac Kart::ScaleAnmController::__ct +805aebb8 0x805aebb8 +805aebf0 0x805aebf0 +805aec90 0x805aec90 +805aec9c Kart::Zipper::__ct +805aecf8 Kart::Zipper::__dt +805aed38 0x805aed38 +805aed50 0x805aed50 +805aed98 0x805aed98 +805aee7c 0x805aee7c +805aeec8 Kart::Zipper::Update +805af804 Vec3::RotateQuaternionConjugate +805af818 0x805af818 +805af9e8 0x805af9e8 +805afc54 0x805afc54 +805afe70 0x805afe70 +805b042c Kart::Zipper::End +805b058c 0x805b058c +805b05e8 Kart::Killer::ModelCalc::ExecWorldCBImpl +805b0640 Kart::Killer::__ct +805b07a0 Kart::Killer::Activate +805b0c2c Kart::Killer::Update +805b0e74 Kart::Killer::Init +805b10a0 Kart::Killer::ToggleVisible +805b1100 cancelBullet +805b1284 0x805b1284 +805b1434 0x805b1434 +805b1780 0x805b1780 +805b1850 0x805b1850 +805b1870 0x805b1870 +805b193c 0x805b193c +805b1a9c 0x805b1a9c +805b1b3c 0x805b1b3c +805b1c48 Kart::Killer::UpdateDuration +805b1e0c 0x805b1e0c +805b1eec 0x805b1eec +805b1fac 0x805b1fac +805b206c 0x805b206c +805b20a8 Kart::Killer::UpdateUps +805b22a0 0x805b22a0 +805b22bc Kart::Killer::UpdateSettings +805b2434 Kart::Killer::UpdateGravity +805b2584 0x805b2584 +805b2640 0x805b2640 +805b28c8 0x805b28c8 +805b294c 0x805b294c +805b2964 0x805b2964 +805b2acc 0x805b2acc +805b2cc4 0x805b2cc4 +805b2e84 Kart::Killer::__dt +805b2ec4 Kart::Killer::ModelCalc::__dt +805b2f04 Kart::Killer::ModelCalc::__dt(thunk) +805b2f0c MenuModelMgr::Disposer__dt +805b2fa4 MenuModelMgr::CreateInstance +805b3034 MenuModelMgr::DestroyInstance +805b3068 MenuModelMgr::__ct +805b30cc MenuModelMgr::__dt +805b31e4 MenuModelMgr::Start +805b3238 MenuModelMgr::Init +805b3490 MenuModelMgr::Update +805b34e4 MenuModelMgr::Draw +805b3538 MenuModelMgr::ResetKartModels +805b3550 MenuModelMgr::RequestDriverModel +805b3568 MenuModelMgr::RequestKartModel +805b3580 MenuModelMgr::RequestBackModel +805b358c MenuModelMgr::TogglePlayerModel +805b35a4 0x805b35a4 +805b35bc MenuModelMgr::ToggleBackModel +805b35c4 MenuModelMgr::GetTexObj +805b35d8 0x805b35d8 +805b3600 0x805b3600 +805b361c MenuModelMgr::GetDriverTexture +805b362c MenuModelMgr::GetKartTexture +805b3684 0x805b3684 +805b3694 0x805b3694 +805b3754 ScnMgrMenu::__ct +805b37b0 ScnMgrMenu::__dt +805b3808 ScnMgrMenu::UpdateCameras +805b389c 0x805b389c +805b38ac ScnMgrMenu::LoadLights +805b3908 ScnMgrMenu::CreateScnGroup +805b3960 ScnMgrMenu::SetAnmScn +805b3974 ScnMgrMii::__ct +805b39cc ScnMgrMii::__dt +805b3a24 ScnMgrMii::LoadLights +805b3a8c 0x805b3a8c +805b3adc 0x805b3adc +805b3b1c 0x805b3b1c +805b3ca4 0x805b3ca4 +805b3ce8 0x805b3ce8 +805b3d28 0x805b3d28 +805b3d2c 0x805b3d2c +805b3e58 0x805b3e58 +805b3ef8 0x805b3ef8 +805b3fac 0x805b3fac +805b4050 0x805b4050 +805b40c4 0x805b40c4 +805b423c 0x805b423c +805b4308 0x805b4308 +805b43dc 0x805b43dc +805b45f4 0x805b45f4 +805b4758 0x805b4758 +805b47fc 0x805b47fc +805b4860 0x805b4860 +805b48b4 0x805b48b4 +805b48f4 0x805b48f4 +805b4934 0x805b4934 +805b4968 0x805b4968 +805b498c 0x805b498c +805b4a0c 0x805b4a0c +805b4a7c 0x805b4a7c +805b4b7c 0x805b4b7c +805b4c0c 0x805b4c0c +805b4c4c 0x805b4c4c +805b4c8c 0x805b4c8c +805b4c90 MatModelDirector::__ct +805b4cec MatModelDirector::__ct(scnMgrIdx) +805b4d48 MatModelDirector::__ct(ClipInfo) +805b4da4 MatModelDirector::__dt +805b4e0c MatModelDirector::AppendToScnMgr +805b4e50 MatModelDirector::SetMaterialNames +805b4e60 MatModelDirector::CopyMaterialsTevColors +805b4f48 MatModelDirector::ReplaceDefaultScnMdlTevColorDL +805b4f78 MatModelDirector::__dt(thunk) +805b4f80 Pages::ActionLess::__ct +805b4fc4 Pages::ActionLess::__dt +805b502c Pages::ActionLess::OnInit +805b5080 Pages::ActionLess::OnActivate +805b508c Pages::ActionLess::AfterControlUpdate +805b50c4 Pages::ActionLess::RequestEnd +805b50d0 Pages::AutoEndingTransparent::__ct +805b5138 Pages::AutoEndingTransparent::__dt +805b51cc Pages::AutoEndingTransparent::OnInit +805b52c0 Pages::AutoEndingTransparent::ResetText +805b52d0 Pages::AutoEndingTransparent::SetMessageWindowText +805b52d8 Pages::AutoEnding::__ct +805b5350 CtrlMenuPageTitleText::__dt +805b53a8 Pages::AutoEnding::__dt +805b5464 Pages::AutoEnding::OnInit +805b5600 Pages::AutoEnding::ResetText +805b5650 Pages::AutoEnding::SetTitleText +805b5658 Pages::AutoEnding::SetMessageWindowText +805b5660 Page::vf_0x5c +805b5664 Page::OnSectionChange +805b5668 Page::OnResume +805b566c Page::OnUpdate +805b5670 Page::BeforeControlUpdate +805b5674 Page::AfterExitAnimations +805b5678 Page::BeforeExitAnimations +805b567c Page::AfterEntranceAnimations +805b5680 Page::BeforeEntranceAnimations +805b5684 Page::OnDeactivate +805b5688 Page::OnDispose +805b568c Page::IsDVDEnabled +805b5694 Page::IsHomeMenuWorking +805b569c Page::Getpage +805b56a4 0x805b56a4 +805b56ac Pages::AutoEnding::GetRuntimeTypeInfo +805b56b8 Page::GetNextPage +805b56c0 Pages::AutoEndingTransparent::GetRuntimeTypeInfo +805b56cc Pages::ActionLess::GetRuntimeTypeInfo +805b56d8 ActionLessPage_cpp_sinit_ +805b56f8 PushButton::GetClassName +805b5704 PushButton::__ct +805b580c PushButton::__dt +805b5874 PushButton::Load +805b5a60 ManipulatorManager::GetRuntimeTypeInfo +805b5a6c PushButton::OnLoad +805b5a70 0x805b5a70 +805b5a7c PushButton::LoadWithAnims +805b5e24 PushButton::SetOnClickHandler +805b5e3c PushButton::SetOnSelectHandler +805b5e44 PushButton::SetOnDeSelectHandler +805b5e4c PushButton::SelectInitial +805b5ea0 PushButton::Select +805b5eb4 PushButton::SelectFocus +805b5f30 PushButton::SetPlayerBitfield +805b5f3c PushButton::Init +805b60f4 PushButton::Update +805b62a0 PushButton::IsSelected +805b62e4 PushButton::GetAnimationFrameSize +805b6358 PushButton::HandleSelect +805b6488 PushButton::OnSelect +805b648c PushButton::HandleDeselect +805b66b0 PushButton::OnDeselect +805b66b4 PushButton::HandleClick +805b6788 PushButton::OnClick +805b678c PushButton::SetSelectionSoundId +805b6794 PushButtonScaleFade::GetClassName +805b67a4 PushButtonScaleFade::__ct +805b68b8 PushButtonScaleFade::__dt +805b6924 PushButtonScaleFade::SetPositionAnim +805b695c UIControl::805bd2d8 +805b6960 UIControl::OnPlayAnimSound +805b6964 UIControl::OnUpdate +805b6968 0x805b6968 +805b696c PushButtonScaleFade::GetRuntimeTypeInfo +805b6978 PushButton::GetRuntimeTypeInfo +805b6984 0x805b6984 +805b69b4 0x805b69b4 +805b69d4 NotifyButton::GetClassName +805b69e0 NotifyButton::__ct +805b6a1c NotifyButton::__dt +805b6a74 NotifyButton::Load +805b6b30 NotifyButton::InitSelf +805b6c04 NotifyButton::OnUpdate +805b6f9c NotifyButton::OnClick +805b6fe0 NotifyButton::OnClick_switch +805b6fe4 NotifyButton::OnClick_caseD_0 +805b6fec NotifyButton::OnClick_caseD_1 +805b6ff4 NotifyButton::OnClick_caseD_2 +805b70fc NotifyButton::OnClick_caseD_3 +805b7104 NotifyButton::OnClick_caseD_5 +805b710c NotifyButton::OnClick_caseD_7 +805b7114 NotifyButton::OnClick_caseD_8 +805b711c NotifyButton::OnClick_caseD_9 +805b7124 NotifyButton::OnClick_caseD_a +805b7174 NotifyButton::OnClick_switch_805bfb90::CaseD_a +805b7198 0x805b7198 +805b71a0 0x805b71a0 +805b71a8 0x805b71a8 +805b71b0 0x805b71b0 +805b71b8 0x805b71b8 +805b71c0 0x805b71c0 +805b71c8 0x805b71c8 +805b71d0 0x805b71d0 +805b71d8 0x805b71d8 +805b71e0 0x805b71e0 +805b71e8 0x805b71e8 +805b71f8 NotifyButton::CheckStatusAvailabilities +805b7420 Page::GetRuntimeTypeInfo +805b742c NotifyButton::UpdateText +805b7468 NotifyButton::UpdateText_switch +805b746c NotifyButton::UpdateText_caseD_0 +805b7474 NotifyButton::UpdateText_caseD_1 +805b747c NotifyButton::UpdateText_caseD_2 +805b7484 NotifyButton::UpdateText_caseD_3 +805b748c NotifyButton::UpdateText_caseD_4 +805b7494 NotifyButton::UpdateText_caseD_5 +805b749c NotifyButton::UpdateText_caseD_6 +805b74a4 NotifyButton::UpdateText_caseD_7 +805b74ac NotifyButton::UpdateText_caseD_8 +805b74b4 NotifyButton::UpdateText_caseD_9 +805b74bc NotifyButton::UpdateText_caseD_a +805b7528 Pages::Channel::__ct +805b76d0 CtrlMenuBackButton::__dt +805b7728 CtrlMenuInstructionText::__dt +805b7780 Pages::Channel::__dt +805b7864 Pages::Channel::OnInit +805b7eec Pages::Channel::OnDispose +805b7ef0 Pages::Channel::OnActivate +805b7f48 Pages::Channel::OnButtonClick +805b81e0 Pages::Channel::OnButtonSelect +805b8288 Pages::Channel::OnButtonSelect_switch +805b828c Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_0 +805b8294 Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_1 +805b829c Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_2 +805b82a4 Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_3 +805b82ac Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_4 +805b82b4 Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_5 +805b82bc Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_6 +805b82c4 Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_7 +805b82cc Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_8 +805b82d4 Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_9 +805b82dc Pages::Channel::OnButtonSelect_switch_805c0c20::CaseD_a +805b82f8 Pages::Channel::OnBackPress +805b8330 Pages::ChannelGhostChoice::__ct +805b84a0 Pages::ChannelGhostChoice::__dt +805b8550 Pages::ChannelGhostChoice::OnInit +805b8868 Pages::ChannelGhostChoice::OnActivate +805b88c0 Pages::ChannelGhostChoice::OnButtonClick +805b89a8 Pages::ChannelGhostChoice::OnButtonSelect +805b89fc Pages::ChannelGhostChoice::OnBackPress +805b8a14 Pages::ChannelRankingChoice::__ct +805b8b84 Pages::ChannelRankingChoice::__dt +805b8c34 Pages::ChannelRankingChoice::OnInit +805b8ea4 Pages::ChannelRankingChoice::OnActivate +805b8ef4 Pages::ChannelRankingChoice::GetNextPage +805b8f0c Pages::ChannelRankingChoice::OnButtonClick +805b9138 Pages::ChannelRankingChoice::OnButtonSelect +805b918c Pages::ChannelRankingChoice::OnBackPress +805b919c 0x805b919c +805b91a0 Pages::ChannelRankingChoice::GetRuntimeTypeInfo +805b91ac Pages::ChannelGhostChoice::GetNextPage +805b91b4 Pages::ChannelGhostChoice::GetRuntimeTypeInfo +805b91c0 Pages::Channel::GetNextPage +805b91c8 Pages::Channel::GetRuntimeTypeInfo +805b91d4 NotifyButton::GetRuntimeTypeInfo +805b91e0 TriggerPtmf +805b9210 TriggerPtmf +805b9240 TriggerPtmf +805b9270 TriggerPtmf +805b92a0 TriggerPtmf +805b92d0 TriggerPtmf +805b9300 ChannelPage_cpp_sinit_ +805b932c Pages::Approve::__ct +805b9484 Pages::Approve::__dt +805b9524 Pages::Approve::OnInit +805b96f8 Pages::Approve::OnActivate +805b9784 Pages::Approve::OnDeactivate +805b9788 Pages::Approve::Reset +805b9814 Pages::Approve::SetTitleMessage +805b981c Pages::Approve::SetMessageWindowMessage +805b9824 Pages::Approve::SetApproveButtonMessage +805b982c Pages::Approve::OnClick +805b98a8 Pages::Approve::OnBackButtonClick +805b9924 Pages::Approve::OnBackPress +805b9990 Pages::Approve::BeforeEntranceAnimations +805b99ac 0x805b99ac +805b99c8 0x805b99c8 +805b99d0 Pages::Approve::GetRuntimeTypeInfo +805b99dc Pages::Approve::TriggerApprovePtmf +805b9a0c Pages::Approve::TriggerDisapprovePtmf +805b9a3c ApprovePage_cpp_sinit_ +805b9a50 ControlGroup::__ct +805b9a6c ControlGroup::__dt +805b9acc ControlGroup::Init(UIControl) +805b9c8c ControlGroup::Init(Page) +805b9e48 ControlGroup::SetControl +805b9e70 ControlGroup::805c2804 +805b9ed4 ControlGroup::InitControls +805b9f44 ControlGroup::Update +805b9fb4 ControlGroup::Draw +805ba0c8 ControlGroup::ResetControlsPosition +805ba12c ControlGroup::GetControl +805ba13c ControlGroup::DoAction +805ba284 ControlLoader::__ct +805ba28c ControlLoader::__dt +805ba2cc ControlLoader::Load +805ba4ec ControlLoader::LoadBRCTR +805ba5a0 ControlLoader::LoadAnimations +805ba884 ControlLoader::IsStringInArray +805ba91c ControlLoader::FindStringInArray +805ba994 ControlLoader::GetVariant +805baa14 ControlLoader::LoadVariant +805baadc ControlLoader::LoadMessages +805babbc ControlLoader::LoadPictures +805bac64 CountDown::__ct +805bac84 CountDown::__dt +805bacc4 Countdown::SetInitial +805bacdc Countdown::Update +805bad60 CountDownTimerControl::GetClassName +805bad6c CountDownTimerControl::__ct +805badb0 CountDownTimerControl::__dt +805bae08 CountDownTimerControl::Load +805bae94 CountDownTimerControl::InitSelf +805bb114 CountDownTimerControl::OnUpdate +805bb418 CountDownTimerControl::AnimateCurrentCountDown +805bb4c8 CountDownTimerControl::Reset +805bb578 0x805bb578 +805bb7e0 CountDownTimerControl::GetRuntimeTypeInfo +805bb7ec CountDown_cpp_sinit_ +805bb800 0x805bb800 +805bb884 0x805bb884 +805bb8ec 0x805bb8ec +805bb968 0x805bb968 +805bbb28 Page::EndExitState +805bbb2c 0x805bbb2c +805bbb30 0x805bbb30 +805bc1a8 0x805bc1a8 +805bc840 0x805bc840 +805bc878 0x805bc878 +805bca98 0x805bca98 +805bcb68 0x805bcb68 +805bcb6c 0x805bcb6c +805bcb74 0x805bcb74 +805bcb7c 0x805bcb7c +805bcb84 0x805bcb84 +805bcb8c 0x805bcb8c +805bcb94 0x805bcb94 +805bcb9c 0x805bcb9c +805bcba4 0x805bcba4 +805bcbac 0x805bcbac +805bcbb4 0x805bcbb4 +805bcc58 0x805bcc58 +805bccc8 0x805bccc8 +805bcf08 0x805bcf08 +805bcfe4 0x805bcfe4 +805bd2b8 0x805bd2b8 +805bd408 0x805bd408 +805bd448 0x805bd448 +805bd788 0x805bd788 +805bd874 0x805bd874 +805bd958 0x805bd958 +805bda38 0x805bda38 +805bdc04 0x805bdc04 +805bdf5c 0x805bdf5c +805be058 0x805be058 +805be0f0 0x805be0f0 +805be158 0x805be158 +805be168 0x805be168 +805be338 0x805be338 +805be3e8 0x805be3e8 +805be4e0 0x805be4e0 +805be5b4 0x805be5b4 +805be658 0x805be658 +805be7f8 0x805be7f8 +805be834 0x805be834 +805be83c 0x805be83c +805be880 0x805be880 +805be8c4 0x805be8c4 +805be8d0 0x805be8d0 +805be8d8 0x805be8d8 +805be8e4 0x805be8e4 +805be8ec 0x805be8ec +805be8f8 TriggerPtmf +805be928 TriggerPtmf +805be958 TriggerPtmf +805be988 TriggerPtmf +805be9b8 TriggerPtmf +805be9e8 __sinit_DownloadGhostList_cpp +805bea08 DpdPointerControl::GetClassName +805bea14 DpdPointerControl::DpadpointerControl +805bea58 DpdPointerControl::__dt +805beab0 DpdPointerControl::Load +805bedbc DpdPointerControl::InitSelf +805bef0c DpdPointerControl::OnUpdate +805bf584 Pages::DpdPointer::__ct +805bf5e8 Pages::DpdPointer::__dt +805bf65c Pages::DpdPointer::OnInit +805bf6e8 Pages::DpdPointer::OnActivate +805bf6f4 Pages::DpdPointer::BeforeControlUpdate +805bf75c Pages::DpdPointer::CheckForConditions +805bf764 Pages::System::AddPageLayer +805bf76c Pages::System::Func_0x20 +805bf770 Pages::System::ChangeSection +805bf774 Pages::System::IsVisible +805bf77c Pages::DpdPointer::GetClassName +805bf788 Pages::DpdPointer::GetRuntimeTypeInfo +805bf794 DpdPointerControl::GetRuntimeTypeInfo +805bf7a0 __sinit_DpdPointer_cpp +805bf7c4 Pages::Empty::__ct +805bf808 Pages::Empty::__dt +805bf870 Pages::Empty::OnInit +805bf8d8 Page::OnActivate +805bf8dc Pages::Empty::BeforeExitAnimations +805bf8e0 Pages::Empty::BeforeEntranceAnimations +805bf8e4 NumericEditBox::GetClassName +805bf8f0 NumericEditBox::__ct +805bfa48 NumericEditBox::__dt +805bfacc NumericEditBox::Load +805bff0c NumericEditBox::vf_0x3c +805bff10 NumericEditBox::SelectInitial +805bff64 NumericEditBox::Select +805bff84 NumericEditBox::RemoveAllDigits +805c0038 NumericEditBox::HasFullDigits +805c0078 NumericEditBox::HasUnusedDigit +805c00b8 NumericEditBox::ComputeSum +805c0118 NumericEditBox::AddDigit +805c02a0 NumericEditBox::RemoveDigit +805c0488 NumericEditBox::Init +805c058c NumericEditBox::Update +805c0738 NumericEditBox::HandleUpPress +805c0810 NumericEditBox::HandleDownPress +805c08c0 NumericEditBox::HandleClick +805c099c NumericEditBox::HandleRightPress +805c0a74 NumericEditBox::HandleLeftPress +805c0b30 NumericEditBox::EditLetter::GetClassName +805c0b40 NumericEditBox::EditLetter::__ct +805c0b7c NumericEditBox::EditLetter::__dt +805c0bd4 NumericEditBox::EditLetter::Load +805c0c5c NumericEditBox::EditLetter::Init +805c0cdc NumericEditBox::EditLetter::Update +805c0ce0 NumericEditBox::EditLetter::AddDigit +805c0d34 NumericEditBox::EditLetter::RemoveDigit +805c0d40 NumericEditBox::EditLetter::ToggleCursor +805c0d8c NumericEditBox::EditLetter::AnimateDigit +805c0dc4 0x805c0dc4 +805c0dc8 NumericEditBox::GetRuntimeTypeInfo +805c0dd4 NumericEditBox::EditLetter::GetRuntimeTypeInfo +805c0de0 TriggerPtmf +805c0e10 NumericEditBox_cpp_sinit_ +805c0e2c Text::Info::__ct +805c0f14 Text::PaneHandler::__ct +805c0f30 Text::PaneHandler::__dt +805c0fa0 Text::Mgr::CreateInstance +805c1048 Text::Mgr::DestroyInstance +805c10c4 Text::PaneHandler::Init +805c11e0 Text::PaneHandler::SetMessage +805c1918 Text::PaneHandler::SetMessage_switch +805c191c Text::PaneHandler::SetMessage_case0 +805c19ac Text::PaneHandler::SetMessage_case10 +805c1a14 Text::PaneHandler::SetMessage_case12 +805c1a64 Text::PaneHandler::SetMessage_case13 +805c1b10 Text::PaneHandler::SetMessage_case14 +805c1c7c Text::PaneHandler::SetMessage_case15 +805c1db8 Text::PaneHandler::SetMessage_case1 +805c22a4 ManipulatorHandler::CheckPlayerPointer +805c22ac Text::PaneHandler::ResetMessage +805c22e8 Text::PaneHandler::Draw +805c23b8 0x805c23b8 +805c23d4 0x805c23d4 +805c23f0 Text::PaneHandler::GetBMGInfo +805c24a4 0x805c24a4 +805c2548 Text::GlyphParams::__ct +805c254c Text::GlyphParams::__dt +805c258c Text::GlyphParams::SetCharacter +805c25f0 Text::GlyphUnicodeExternal::__ct +805c25f4 Text::GlyphUnicodeExternal::__dt +805c2634 Text::GlyphUnicodeExternal::SetCharacter +805c275c Text::GlyphDrawer::__dt +805c279c Text::GlyphDrawer::Init +805c2a78 Text::GlyphDrawer::Draw +805c2b60 Text::GlyphDrawer::DrawExternalUnicode +805c2cc4 Text::GlyphDrawer::SetupGXColors +805c2ecc Text::GlyphDrawer::SetupGXColors_switch +805c2ed0 Text::GlyphDrawer::SetupGXColors_caseD_1 +805c2ee8 Text::GlyphDrawer::SetupGXColors_caseD_10 +805c2f00 Text::GlyphDrawer::SetupGXColors_caseD_11 +805c2f1c Text::GlyphDrawer::SetupGXColors_caseD_12 +805c2f38 Text::GlyphDrawer::SetupGXColors_caseD_13 +805c2f54 Text::GlyphDrawer::SetupGXColors_caseD_14 +805c2f70 Text::GlyphDrawer::SetupGXColors_caseD_15 +805c2f8c Text::GlyphDrawer::SetupGXColors_caseD_16 +805c2fa8 Text::GlyphDrawer::SetupGXColors_caseD_17 +805c2fc0 Text::GlyphDrawer::SetupGXColors_caseD_20 +805c2fd8 Text::GlyphDrawer::SetupGXColors_caseD_21 +805c2ff4 Text::GlyphDrawer::SetupGXColors_caseD_30 +805c300c Text::GlyphDrawer::SetupGXColors_caseD_31 +805c3028 Text::GlyphDrawer::SetupGXColors_caseD_32 +805c3040 Text::GlyphDrawer::SetupGXColors_caseD_33 +805c3058 Text::GlyphDrawer::SetupGXColors_caseD_40 +805c3074 Text::GlyphDrawer::SetupGXColors_caseD_18 +805c30b8 Text::GlobalHandler::__ct +805c30c4 Text::GlobalHandler::__dt +805c3104 Text::GlobalHandler::SetPaneHandler +805c3454 0x805c3454 +805c3590 Text::GlobalHandler::SetCharacter +805c3804 Text::GlobalHandler::SetExternalUnicodeChar +805c3a64 0x805c3a64 +805c3afc 0x805c3afc +805c3b40 0x805c3b40 +805c3b54 Text::GlobalHandler::Calc +805c4170 0x805c4170 +805c41b4 Text::GlobalHandler::CalcMessageParams +805c4278 Text::GlobalHandler::GetGlyphParamsAndIncrement +805c42b0 Text::GlobalHandler::GetUnicodeGlyphParamsAndIncrement +805c42e8 Text::GlobalHandler::SetPaneHandlerAndPane +805c4414 Text::GameFont::__ct +805c4460 Text::GameFont::__dt +805c44d0 Text::GameFont::Load +805c4524 Text::GameFont::GetTextureByCode +805c4614 Text::GameFont::GetTextureByIdx +805c46f4 Text::GameFont::Init +805c47ec Text::FontMgr::__ct +805c480c Text::FontMgr::__dt +805c48a4 Text::FontMgr::CreateInstance +805c48f4 Text::FontMgr::DestroyInstance +805c4984 Text::FontMgr::Init +805c4c38 Text::FontMgr::InitFont +805c4ce4 Text::FontMgr::GetFont +805c4d68 FriendList::__ct +805c4ddc 0x805c4ddc +805c4e1c FriendListEntry::__ct +805c4e64 FriendListEntry::__dt +805c4ea4 0x805c4ea4 +805c4ee4 0x805c4ee4 +805c4f24 FriendList::__dt +805c4f88 FriendList::Init +805c5098 FriendList::SaveToRKSYS +805c5148 FriendList::Update +805c51ac 0x805c51ac +805c52bc 0x805c52bc +805c53a4 FriendList::GetFriendCount +805c5440 FriendList::AddFriend +805c55e4 FriendList::RemoveFriend +805c565c FriendList::GetFriendIdx +805c5758 FriendList::GetFriendEntry +805c5774 FriendList::GetFriend +805c57ac FriendList::GetFriendStatus +805c57e4 FriendList::IsFriendStatusLessThan25 +805c5830 FriendList::IsUpdated +805c584c FriendList::UpdateKeyController +805c5874 0x805c5874 +805c58c0 0x805c58c0 +805c58e8 0x805c58e8 +805c5934 FriendList::UpdateStatuses +805c5a28 FriendList::UpdateStatuses_switch +805c5a2c FriendList::UpdateStatuses_caseD_1 +805c5a34 FriendList::UpdateStatuses_caseD_2 +805c5a3c FriendList::UpdateStatuses_caseD_3 +805c5a44 FriendList::UpdateStatuses_caseD_5 +805c5a4c FriendList::UpdateStatuses_caseD_6 +805c5a54 FriendList::UpdateStatuses_caseD_7 +805c5a5c FriendList::UpdateStatuses_caseD_8 +805c5a64 FriendList::UpdateStatuses_caseD_9 +805c5a6c FriendList::UpdateStatuses_caseD_a +805c5a74 FriendList::UpdateStatuses_caseD_b +805c5ad8 FriendList::UpdateStatuses_caseD_4 +805c5ae4 FriendList::UpdateStatuses_caseD_c +805c5b3c FriendList::UpdateStatuses_caseD_d +805c5ba4 FriendList::UpdateStatuses_caseD_e +805c5bfc FriendList::UpdateStatuses_caseD_0 +805c5c28 FriendList::UpdateFriendData +805c5fec 0x805c5fec +805c5ff0 0x805c5ff0 +805c6018 0x805c6018 +805c601c 0x805c601c +805c603c 0x805c603c +805c6040 0x805c6040 +805c608c 0x805c608c +805c6090 0x805c6090 +805c60dc 0x805c60dc +805c60e0 FriendCodesController::Update +805c619c FriendCodesController::TrySaveMgrToRKSYS +805c6200 FriendCodesController::SaveMgrToRKSYS +805c6334 FriendCodesController::ResetMgrKeys +805c6344 FriendReceiver::TrySaveToRKSYS +805c63b8 FriendReceiver::TryReceiveData +805c65a0 FriendReceiver::SaveToRKSYS +805c6650 FriendReceiver::vf_0x10 +805c66e4 FriendButton::GetClassName +805c66f0 FriendButton::__ct +805c6734 FriendButton::__dt +805c678c FriendButton::Load +805c6864 FriendButton::SetMii +805c6a40 0x805c6a40 +805c6b38 FriendButton::InitSelf +805c6b3c FriendButton::OnUpdate +805c6f0c FriendButton::OnSelect +805c7004 FriendButton::OnDeselect +805c70ac Pages::FriendList::__ct +805c728c Pages::FriendList::__dt +805c7350 Pages::FriendList::OnInit +805c7714 Pages::FriendList::OnDispose +805c7718 Pages::FriendList::OnActivate +805c7938 Pages::FriendList::BeforeEntranceAnimations +805c7a40 Pages::FriendList::BeforeExitAnimations +805c7a54 Pages::FriendList::OnDeactivate +805c7af4 Pages::FriendList::AfterControlUpdate +805c7b70 Pages::FriendList::AddNewFriend +805c7bec Pages::FriendList::OnFriendButtonClick +805c7d34 Pages::FriendList::OnBackButtonClick +805c7dc8 Pages::FriendList::OnRightArrowPress +805c7ef8 Pages::FriendList::OnLeftArrowPress +805c7ff0 Pages::FriendList::OnBackPress +805c8070 Pages::FriendList::CompareFriendIndexes +805c8100 Pages::FriendList::FriendStatusToValue +805c8120 Pages::FriendList::FriendStatusToValue_switch +805c8124 Pages::FriendList::FriendStatusToValue_Case_fffffffe +805c812c Pages::FriendList::FriendStatusToValue_Case_ffffffff +805c8134 Pages::FriendList::FriendStatusToValue_Case_0 +805c813c Pages::FriendList::FriendStatusToValue_Case_1 +805c8144 Pages::FriendList::FriendStatusToValue_Case_2 +805c814c Pages::FriendList::FriendStatusToValue_Case_3 +805c8154 Pages::FriendList::FriendStatusToValue_Case_4 +805c815c Pages::FriendList::FriendStatusToValue_Case_5 +805c8164 Pages::FriendList::FriendStatusToValue_Case_6 +805c816c Pages::FriendList::FriendStatusToValue_Case_7 +805c8174 Pages::FriendList::FriendStatusToValue_Case_8 +805c817c Pages::FriendList::FriendStatusToValue_Case_9 +805c8184 Pages::FriendList::FriendStatusToValue_Case_a +805c818c Pages::FriendList::FriendStatusToValue_Case_b +805c8194 Pages::FriendList::FriendStatusToValue_Case_c +805c819c Pages::FriendList::FriendStatusToValue_Case_d +805c81a4 Pages::FriendList::FriendStatusToValue_Case_e +805c81ac Pages::FriendList::FriendStatusToValue_Case_f +805c81b4 Pages::FriendList::FriendStatusToValue_Case_10 +805c81bc Pages::FriendList::FriendStatusToValue_Case_11 +805c81c4 Pages::FriendList::FriendStatusToValue_Case_12 +805c81cc Pages::FriendList::FriendStatusToValue_Case_13 +805c81d4 Pages::FriendList::FriendStatusToValue_Case_14 +805c81dc Pages::FriendList::FriendStatusToValue_Case_15 +805c81e4 Pages::FriendList::FriendStatusToValue_Case_16 +805c81ec Pages::FriendList::FriendStatusToValue_Case_17 +805c81f4 Pages::FriendList::FriendStatusToValue_Case_18 +805c81fc Pages::FriendList::FriendStatusToValue_Case_19 +805c8204 Pages::FriendList::FriendStatusToValue_Case_1a +805c8214 Pages::FriendList::UpdatePageCounter +805c82dc Pages::FriendList::UpdateMiiGroup +805c83e4 JoinFriendButton::GetClassName +805c83f4 JoinFriendButton::__ct +805c8430 JoinFriendButton::__dt +805c8488 JoinFriendButton::__dt +805c8590 JoinFriendButton::SetStatus +805c86fc JoinFriendButton::OnUpdate +805c8740 Pages::FriendInfo::__ct +805c88f8 Pages::FriendInfo::__dt +805c89d8 Pages::FriendInfo::OnInit +805c8ee4 Pages::FriendInfo::OnActivate +805c900c Pages::FriendInfo::AfterControlUpdate +805c9274 Pages::FriendInfo::PlaySound +805c9354 Pages::FriendInfo::SetInfoText +805c9538 0x805c9538 +805c955c Pages::FriendInfo::OnJoinButtonClick +805c97f0 Pages::FriendInfo::OnRemoveButtonClick +805c9834 Pages::FriendInfo::OnBackButtonClick +805c9878 Pages::FriendInfo::OnBackPress +805c9890 Pages::FriendRemove::__ct +805c99e8 Pages::FriendRemove::__dt +805c9a88 Pages::FriendRemove::OnInit +805c9c24 Pages::FriendRemove::OnActivate +805c9cf4 Pages::FriendRemove::OnDeactivate +805c9dac Pages::FriendRemove::OnResume +805c9e80 Pages::FriendRemove::OnRemoveButtonClick +805ca074 Pages::FriendRemove::OnCancelAndBackButtonClick +805ca0d0 Pages::FriendRemove::OnBackPress +805ca0e8 Pages::FriendRemoving::__ct +805ca15c Pages::FriendRemoving::__dt +805ca1ec Pages::FriendRemoving::OnInit +805ca2e8 Pages::FriendRemoving::OnActivate +805ca3d8 Pages::FriendRemoving::BeforeExitAnimations +805ca53c Pages::FriendRemoving::AfterControlUpdate +805ca850 Pages::FriendJoinMgr::__ct +805ca894 Pages::FriendJoinMgr::__dt +805ca8fc Pages::FriendJoinMgr::OnInit +805ca968 Pages::FriendJoinMgr::OnActivate +805cac38 Pages::FriendJoinMgr::BeforeEntranceAnimations +805cac3c Pages::FriendJoinMgr::AfterEntranceAnimations +805cac4c Pages::FriendJoinMgr::BeforeExitAnimations +805cac50 Pages::FriendJoinMgr::GetNextPage +805cac58 Pages::FriendJoinMgr::GetRuntimeTypeInfo +805cac64 Pages::FriendRemoving::IsHomeMenuWorking +805cac6c Pages::FriendRemoving::GetNextPage +805cac74 Pages::FriendRemoving::GetRuntimeTypeInfo +805cac80 Pages::FriendRemove::GetNextPage +805cac88 Pages::FriendRemove::GetRuntimeTypeInfo +805cac94 Pages::FriendInfo::GetNextPage +805cac9c Pages::FriendInfo::GetRuntimeTypeInfo +805caca8 JoinFriendButton::GetRuntimeTypeInfo +805cacb4 Pages::FriendList::GetNextPage +805cacbc Pages::FriendList::GetRuntimeTypeInfo +805cacc8 FriendButton::GetRuntimeTypeInfo +805cacd4 TriggerPtmf +805cad04 TriggerPtmf +805cad34 TriggerPtmf +805cad64 TriggerPtmf +805cad94 TriggerPtmf +805cadc4 TriggerPtmf +805cadf4 TriggerPtmf +805cae24 FriendListPage_cpp_sinit_ +805cae5c Pages::GhostManager::__ct +805caedc Pages::GhostManager::__dt +805cafa8 Pages::GhostManager::OnInit +805cb220 Pages::GhostManager::OnActivate +805cb31c Pages::GhostManager::BeforeEntranceAnimations +805cb320 Pages::GhostManager::BeforeExitAnimations +805cb324 Pages::GhostManager::OnDeactivate +805cb328 Pages::GhostManager::AfterControlUpdate +805cb32c Pages::GhostManager::OnSectionChange +805cb3d4 Pages::GhostManager::RequestAllGhosts +805cb438 Pages::GhostManager::UpdateState +805cb470 Pages::GhostManager::UpdateState_switch +805cb474 Pages::GhostManager::UpdateState_case_1 +805cb584 Pages::GhostManager::UpdateState_case_2 +805cb5a8 Pages::GhostManager::UpdateState_case_3 +805cb5e0 Pages::GhostManager::UpdateState_case_4 +805cb618 Pages::GhostManager::UpdateState_case_5 +805cb650 Pages::GhostManager::UpdateState_case_6 +805cb680 Pages::GhostManager::UpdateState_case_7 +805cb6a4 Pages::GhostManager::UpdateState_case_9 +805cb6d0 Pages::GhostManager::UpdateState_case_a +805cb6fc Pages::GhostManager::UpdateState_case_b +805cb728 Pages::GhostManager::UpdateState_case_c +805cb74c Pages::GhostManager::UpdateState_case_d +805cb76c Pages::GhostManager::UpdateState_case_0 +805cb7e8 Pages::GhostManager::AreStaffGhostsLoading +805cb860 0x805cb860 +805cb96c Pages::GhostManager::PrepareRaceState +805cb9f0 Pages::GhostManager::PrepareReplayState +805cba24 0x805cba24 +805cba44 0x805cba44 +805cbab8 0x805cbab8 +805cbbbc Pages::GhostManager::RequestGhost +805cbd28 Pages::GhostManager::SetupGhostRace +805cbf80 Pages::GhostManager::SetupGhostReplay +805cc11c 0x805cc11c +805cc1f4 0x805cc1f4 +805cc2b0 GhostList::__ct +805cc2c0 GhostList::__dt +805cc300 GhostList::FillWithAllGhosts +805cc3bc GhostList::FillWithAllDLdGhosts +805cc424 GhostList::Init +805cc4ec GhostList::Reset +805cc4f8 GhostList::FillFromGroup +805cc640 GhostList::Sort +805cc654 GhostList::CompareEntries +805cc724 GhostList::GetHeader +805cc74c GhostList::CheckIsNew +805cc778 GhostList::AllAreGhostsNrw +805cc7ac GhostList::SetSectionParamsGhostValues +805cc834 GhostList::EraseEntry +805cc944 Pages::GhostManager::GetRuntimeTypeInfo +805cc950 GhostManagerPage_cpp_sinit_ +805cc964 GhostInfoControl::GetClassName +805cc970 GhostInfoControl::__ct +805cca00 GhostInfoControl::__dt +805cca68 GhostInfoControl::Load +805ccb88 GhostInfoControl::InitSelf +805ccb8c GhostInfoControl::OnUpdate +805ccb90 GhostInfoControl::UpdateInfo +805ccea4 0x805ccea4 +805ccf64 GhostInfoControl::UpdateInfoAnimate +805ccfc4 0x805ccfc4 +805cd014 0x805cd014 +805cd04c 0x805cd04c +805cd084 0x805cd084 +805cd0bc 0x805cd0bc +805cd0f4 0x805cd0f4 +805cd12c 0x805cd12c +805cd164 GhostInfoControl::GetRuntimeTypeInfo +805cd170 GhostInfoControl_cpp_sinit_ +805cd184 SectionParams::__ct +805cd21c SectionParams::__dt +805cd2a4 SectionParams::Reset +805cd448 SectionParams::ResetMiisGhostsAndSubs +805cd4d0 SectionParams::ResetBattleParams +805cd4e8 0x805cd4e8 +805cd510 SectionParams::RandomizeVSTracks +805cd690 SectionParams::SetVStracks +805cd8c4 SectionParams::IsCourseUnlockedInOneCC +805cd9d4 SectionParams::IsCupUnlockedInOneCC +805cda7c SectionParams::RandomizeBattleArenas +805cdb20 SectionParams::SetBattleArenas +805cdbfc SectionParams::CopyMiisToRacedata +805cddbc OnlineParams::ResetRaceNumberAndCC +805cddcc OnlineParams::Reset +805cdf5c OnlineParams::CalcRank +805cdf6c OnlineParams::SetRankBMG +805cdf90 0x805cdf90 +805cdfa4 0x805cdfa4 +805cdfbc 0x805cdfbc +805cdfe0 0x805cdfe0 +805cdfec TitleParams::__ct +805ce020 TitleParams::Reset +805ce120 TitleParams::ForceDemo +805ce12c 0x805ce12c +805ce170 0x805ce170 +805ce180 0x805ce180 +805ce18c SectionParams::TrackIdxToCourseId +805ce1c4 SectionParams::CourseIdToTrackIdx +805ce21c SectionParams::CourseIdToCupIdx +805ce298 SectionParams::ArenaIdToCupIdx +805ce2cc SectionParams::ResetLicenseParams +805ce450 Pages::Globe::__ct +805ce4e4 Pages::Globe::MessageWindow::__dt +805ce53c Pages::Globe::__dt +805ce5c0 Pages::Globe::OnInit +805ce7e0 Pages::Globe::OnActivate +805ce8e4 Pages::Globe::BeforeEntranceAnimations +805ce8e8 Pages::Globe::BeforeExitAnimations +805ce8ec Pages::Globe::AfterControlUpdate +805cf2d8 0x805cf2d8 +805cf478 0x805cf478 +805cf754 0x805cf754 +805cfa14 0x805cfa14 +805cfb28 0x805cfb28 +805cfc30 Pages::Globe::SetMessage +805d0004 0x805d0004 +805d0108 0x805d0108 +805d020c 0x805d020c +805d0310 0x805d0310 +805d045c 0x805d045c +805d05a8 0x805d05a8 +805d0690 0x805d0690 +805d0708 0x805d0708 +805d07d8 0x805d07d8 +805d0848 0x805d0848 +805d08dc 0x805d08dc +805d092c 0x805d092c +805d0968 Pages::Globe::GetFriendActivityBMG +805d0984 Pages::Globe::GetFriendActivityBMG_switch +805d0988 Pages::Globe::GetFriendActivityBMG_caseD_1 +805d0990 Pages::Globe::GetFriendActivityBMG_caseD_2 +805d0998 Pages::Globe::GetFriendActivityBMG_caseD_3 +805d09a0 Pages::Globe::GetFriendActivityBMG_caseD_4 +805d09a8 Pages::Globe::GetFriendActivityBMG_caseD_5 +805d09b0 Pages::Globe::GetFriendActivityBMG_caseD_6 +805d09b8 Pages::Globe::GetFriendActivityBMG_caseD_7 +805d09c0 Pages::Globe::GetFriendActivityBMG_caseD_8 +805d09c8 Pages::Globe::GetFriendActivityBMG_caseD_9 +805d09d0 Pages::Globe::GetFriendActivityBMG_caseD_a +805d09d8 Pages::Globe::GetFriendActivityBMG_caseD_b +805d09e0 Pages::Globe::GetFriendActivityBMG_caseD_c +805d09e8 Pages::Globe::GetFriendActivityBMG_caseD_d +805d09f0 Pages::Globe::GetFriendActivityBMG_caseD_e +805d09f8 Pages::Globe::GetFriendActivityBMG_caseD_f +805d0a00 Pages::Globe::GetFriendActivityBMG_caseD_10 +805d0a08 Pages::Globe::GetFriendActivityBMG_caseD_11 +805d0a10 Pages::Globe::GetFriendActivityBMG_caseD_12 +805d0a18 Pages::Globe::GetFriendActivityBMG_caseD_13 +805d0a20 Pages::Globe::GetFriendActivityBMG_caseD_14 +805d0a28 Pages::Globe::GetFriendActivityBMG_caseD_15 +805d0a30 Pages::Globe::GetFriendActivityBMG_caseD_16 +805d0a38 Pages::Globe::GetFriendActivityBMG_caseD_17 +805d0a40 Pages::Globe::GetFriendActivityBMG_caseD_18 +805d0a48 Pages::Globe::GetFriendActivityBMG_caseD_19 +805d0a50 Pages::Globe::GetFriendActivityBMG_caseD_1a +805d0a58 Pages::Globe::GetFriendActivityBMG_caseD_0 +805d0a60 Pages::Globe::MessageWindow::GetClassName +805d0a70 0x805d0a70 +805d0b54 Pages::Globe::MessageWindow::InitSelf +805d0bb8 0x805d0bb8 +805d0c54 0x805d0c54 +805d0d04 0x805d0d04 +805d0d38 Pages::Globe::GetRuntimeTypeInfo +805d0d44 Pages::Globe::MessageWindow::GetRuntimeTypeInfo +805d0d50 GlobePage_cpp_sinit_ +805d0d74 PaneManager::SearchForPane +805d0e0c PaneManager::GetParentPane +805d0e14 0x805d0e14 +805d1014 PaneManager::IsPaneAndParentsVisible +805d110c PaneManager::IsPaneVisible +805d1118 PaneManager::SetTextBoxMessage +805d1204 PaneManager::DoAction +805d1380 PaneManager::CheckForUserInfo +805d13c0 PaneManager::CheckForUserInfo2 +805d1400 PaneManager::GetNextUserInfo +805d1454 PaneManager::ConvertColorS10ToUT +805d1508 0x805d1508 +805d1530 PaneManagerHolder::__dt +805d15bc PaneManagerHolder::__ct +805d16a8 PicturePaneManager::__ct +805d16c4 TextPaneManager::__ct +805d16e0 MoviePaneManager::__ct +805d16fc 0x805d16fc +805d1700 PaneManagerHolder::InsertPicturePane +805d1750 PaneManagerHolder::InsertTextPane +805d17a0 PaneManagerHolder::InsertMoviePane +805d17f0 PaneManagerHolder::Draw +805d184c PicturePaneManager::Draw +805d1970 TextPaneManager::Draw +805d1a8c MoviePaneManager::Draw +805d1ba8 PaneManagerHolder::InsertManager +805d1bd8 Layout::__ct +805d1c20 Layout::__dt +805d1c7c Layout::GetPaneByName +805d1c94 Layout::CreateResourceAccessor +805d1e3c Layout::Build +805d1ebc MainLayout::__ct +805d1f44 MainLayout::__dt +805d2008 MainLayout::CreateResourceAccessor +805d21b0 MainLayout::Build +805d293c MainLayout::GetTextPaneHandlerByName +805d29b4 MainLayout::GetTextPaneHandlerByPane +805d29fc MainLayout::GetMoviePaneHandlerByName +805d2a74 MainLayout::GetMoviePaneHandlerByPane +805d2abc MainLayout::Animate +805d2ad0 MainLayout::Update +805d2b7c MainLayout::Draw +805d2be4 Text::PaneHandler::Initializer::Calc +805d2ce8 MoviePaneHander::Initializer::Calc +805d2dec PaneTypeCounter::Calc +805d301c PaneManager::Initializer::Calc +805d343c PictureLayout::__ct +805d34d4 PictureLayout::__dt +805d3534 PictureLayout::CreateResourceAccessor +805d36ec PictureLayout::Build +805d378c PictureLayout::SetPrevLayout +805d3794 PictureLayout::IsLinkedToLYT +805d3800 PictureLayoutList::__ct +805d380c PictureLayoutList::__dt +805d3894 PictureLayoutList::Attach +805d3ba0 LayoutResourceAccessorList::__ct +805d3bac LayoutResourceAccessorList::__dt +805d3c6c LayoutFont::__dt +805d3cac 0x805d3cac +805d3cec 0x805d3cec +805d3d2c LayoutResources::__dt +805d3da4 LayoutResourceLink::__dt +805d3de4 LayoutResourceAccessorList::Attach +805d3f80 LayoutResourceAccessor::Init +805d4084 LayoutResourceLink::__ct +805d4094 ManipulatorManager::__ct +805d40b8 ManipulatorManager::__dt +805d40f8 ManipulatorManager::Init +805d417c ManipulatorManager::UpdatePlayerBitfield2 +805d4184 ManipulatorManager::CheckActions +805d4188 ManipulatorManager::Activate +805d4214 ManipulatorManager::OnLoad +805d429c ManipulatorManager::Load +805d42b0 ManipulatorManager::OnReset +805d42c4 ManipulatorManager::Update +805d4338 ManipulatorManager::GetControllerHolder +805d4350 ButtonInfo::__ct +805d43fc ButtonInfo::__dt +805d443c ButtonInfo::Reset +805d444c ButtonInfo::Update +805d4664 ButtonInfo::Init +805d46e8 0x805d46e8 +805d476c PageManipulatorManager::__ct +805d4828 PageManipulatorManager::__dt +805d4890 PageManipulatorManager::Init +805d4968 PageManipulatorManager::CheckActions +805d4ad4 PageManipulatorManager::Activate +805d4bb4 PageManipulatorManager::OnReset +805d4c94 PageManipulatorManager::SetGlobalHandler +805d4cac ControlButtonInfo::__ct +805d4d74 ControlButtonInfo::__dt +805d4db4 ControlButtonInfo::Reset +805d4dc4 ControlButtonInfo::Update +805d4e84 ControlButtonInfo::Init +805d4f18 ControlButtonInfo::LockNonDirectionalActions +805d4f9c ControlButtonInfo::IsADirectionHeldForMultipleOf15 +805d5008 ControlButtonInfo::GetFramesOnCurControl +805d5024 ControlManipulator::__ct +805d5100 ControlManipulator::__dt +805d516c 0x805d516c +805d5174 ControlManipulator::Init +805d5224 ControlManipulator::SetAction +805d523c 0x805d523c +805d5240 ControlManipulator::SetEnabledHudSlots +805d5248 0x805d5248 +805d52f4 ControlManipulator::HasDirectionalHandler +805d536c ControlManipulator::TriggerAction +805d53c0 0x805d53c0 +805d5420 ControlManipulator::Load +805d556c ControlManipulator::Update +805d5908 ControlManipulator::GetHudColor +805d596c ControlManipulator::GetHudSlotIdColor +805d5a04 ControlManipulator::GetHudSlotIdColorSingle +805d5ab8 ControlBoundingBox::__ct +805d5af8 ControlBoundingBox::__dt +805d5b38 0x805d5b38 +805d5b40 0x805d5b40 +805d5b44 ControlBoundingBox::CalculateBounds +805d5dcc ControlBoundingBox::TriggerOnSelectHandler +805d5e1c ControlBoundingBox::TriggerOnDeselectHandler +805d5e6c 0x805d5e6c +805d5ed4 ControlsManipulatorManager::__ct +805d5fc4 ControlManipulatorHolder::__ct +805d60c0 ControlManipulatorHolder::__dt +805d6100 ControlsManipulatorManager::__dt +805d6174 ControlsManipulatorManager::Init +805d6264 ControlManipulator::CalcDistanceBothWrapping +805d6270 ControlsManipulatorManager::AddControlManipulator +805d62b0 ControlsManipulatorManager::SetGlobalHandler +805d62cc ControlsManipulatorManager::SetControlManipulator +805d62e0 ControlsManipulatorManager::SetDistanceFunc +805d6344 ControlManipulator::CalcDistanceVerticalWrappingOnly +805d6350 ControlManipulator::CalcDistanceNoWrapping +805d635c ControlsManipulatorManager::GetHolderList +805d63c0 ControlsManipulatorManager::CheckActions +805d70ec ControlsManipulatorManager::Activate +805d7220 ControlsManipulatorManager::OnLoad +805d7340 ControlsManipulatorManager::OnReset +805d7468 ControlsManipulatorManager::OnActivate +805d746c ControlsManipulatorManager::Update +805d7618 ControlsManipulatorManager::SetChildControlManipulator +805d762c ControlsManipulatorManager::InitHolders +805d7660 ControlsManipulatorManager::IsActionAllowed +805d7698 ControlsManipulatorManager::HasDirectionalGlobalHandler +805d7710 ControlsManipulatorManager::Func_805f21e4 +805d7798 ControlsManipulatorManager::Func_805f226c +805d7800 ControlsManipulatorManager::CheckPlayerPointer +805d78b0 ControlManipulator::CalcDistance +805d7978 ControlManipulator::CalcDistance_Switch +805d797c ControlManipulator::CalcDistance_Case_1 +805d7bd0 ControlManipulator::CalcDistance_Case_5 +805d7e58 ControlManipulator::CalcDistance_Case_0 +805d7e74 ControlManipulator::CalcDistanceLinear +805d8014 ControlManipulator::CalcDistanceLinear_Switch +805d8018 ControlManipulator::CalcDistanceLinear_case_1 +805d8068 ControlManipulator::CalcDistanceLinear_case_4 +805d80b8 ControlManipulator::CalcDistanceLinear_case_5 +805d8118 ControlManipulator::CalcDistanceLinear_case_6 +805d8178 ControlManipulator::CalcDistanceLinear_case_0 +805d8190 0x805d8190 +805d8200 ControlsManipulatorManager:IsWiimoteCursorEnabled +805d8208 ControlsManipulatorManager::GetRuntimeTypeInfo +805d8214 ManipulatorManager::IsPointerEnabled +805d821c ManipulatorManager::OnActivate +805d8220 ManipulatorManager::GetHolderList +805d8224 PageManipulatorManager::GetRuntimeTypeInfo +805d8230 0x805d8230 +805d8250 BMGHolder::__ct +805d826c BMGHolder::__dt +805d82ac BMGHolder::Load +805d831c BMGHolder::Init +805d83a4 BMGHolder::GetMsgId +805d840c BMGHolder::GetMessageById +805d8448 BMGHolder::GetFontIndex +805d8478 Pages::Click::__ct +805d84fc Pages::Click::__dt +805d8564 Pages::Click::OnInit +805d85d4 Pages::Click:::OnLoad +805d85f8 Pages::Click::AfterControlUpdate +805d865c Pages::Click::Reset +805d8670 Pages::Click::OnClick +805d86c8 Pages::MessageBoxTransparent::__ct +805d8770 Pages::MessageBoxTransparent::__dt +805d8804 Pages::MessageBoxTransparent::OnInit +805d8940 Pages::MessageBoxTransparent::Reset +805d8960 Pages::MessageBoxTransparent::SetMessageWindowText +805d8968 Pages::MessageBoxTransparent::BeforeEntranceAnimations +805d89ac Pages::MessageBox::AfterExitAnimations +805d89f0 Pages::MessageBoxTransparent::SetButtonImage +805d8a38 Pages::MessageBox::__ct +805d8af8 Pages::MessageBox::__dt +805d8b90 Pages::MessageBox::OnInit +805d8cdc Pages::MessageBox::Reset +805d8d3c Pages::MessageBox::SetTitleText +805d8d44 Pages::MessageBox::SetMessageWindowText +805d8d4c Pages::MessageBox::SetButtonImage +805d8d94 Pages::MessageBox::GetNextPage +805d8d9c Pages::MessageBox::GetRuntimeTypeInfo +805d8da8 Pages::MessageBoxTransparent::GetRuntimeTypeInfo +805d8db4 Pages::Click::GetRuntimeTypeInfo +805d8dc0 Pages::Click::TriggerPtmf +805d8df0 MessagePagecpp_sinit_ +805d8e10 MessageWindowControl::GetClassName +805d8e1c MessageWindowControl::__ct +805d8e58 MessageWindowControl::__dt +805d8eb0 MessageWindowControl::Load +805d8f2c MessageWindowControlScaleFade::GetClassName +805d8f3c MessageWindowControlScaleFade::__ct +805d8f78 MessageWindowControlScaleFade::__dt +805d8fd4 MessageWindowControlScaleFade::SetPositionAnim +805d900c 0x805d900c +805d901c SimpleMessageWindowControl::__ct +805d9058 SimpleMessageWindowControl::__dt +805d90b0 SimpleMessageWindowControl::Load +805d9164 SimpleMessageWindowControl::InitSelf +805d91c8 BlackBackControlForMessage::GetClassName +805d91d8 BlackBackControlForMessage::__ct +805d9214 BlackBackControlForMessage::__dt +805d926c BlackBackControlForMessage::Load +805d92e0 BlackBackControlForMessage::SetPositionAnim +805d9340 BusySymbol::GetClassName +805d9350 BusySymbol::__ct +805d938c BusySymbol::__dt +805d93e4 BusySymbol::Load +805d9478 BusySymbol::InitSelf +805d94b0 BusySymbol::SetPositionAnim +805d9510 BusySymbol::OnUpdate +805d952c BusySymbol::GetRuntimeTypeInfo +805d9538 BlackBackControlForMessage::GetRuntimeTypeInfo +805d9544 SimpleMessageWindowControl::GetRuntimeTypeInfo +805d9550 MessageWindowControlScaleFade::GetRuntimeTypeInfo +805d955c MessageWindowControl::GetRuntimeTypeInfo +805d9568 0x805d9568 +805d9594 MiiGroup::__ct +805d9634 MiiCreationParams2::__dt +805d9674 MiiGroup::__dt +805d9768 MiiGroup::Init +805d9a8c MiiGroup::Reset +805d9ae0 MiiGroup::ResetCreationParams +805d9b18 MiiGroup::AddMii +805d9c9c MiiGroup::LoadMiddleDB2Mii +805d9d2c MiiGroup::LoadMii(RFLStoreData) +805d9d94 MiiGroup::LoadOfficialMii +805d9dfc MiiGroup::LoadStoreMii +805d9e64 MiiGroup::LoadDefaultMii +805d9ecc 0x805d9ecc +805d9fd4 MiiGroup::ReplaceMiiByPlayerMii +805da04c MiiGroup::GetMii +805da05c 0x805da05c +805da080 MiiGroup::GetMiiTexObj +805da098 MiiGroup::HasAllMiiTexObjs +805da1a0 MiiGroup::DeleteMii +805da2c4 0x805da2c4 +805da310 MiiGroup::CopyMii +805da650 MiiGroup::CopyMiiToOtherGroup +805daaa8 0x805daaa8 +805dabe8 0x805dabe8 +805dac20 0x805dac20 +805dac58 0x805dac58 +805dac74 0x805dac74 +805dacd4 0x805dacd4 +805dacd8 MoviePaneHandler::__ct +805dad08 MoviePaneHandler::__dt +805dad48 MoviePaneHandler::Init +805dae54 MoviePaneHandler::Crop(Rect*) +805daf20 MoviePaneHandler::Crop(4floats) +805db018 MoviePaneHandler::Draw +805dc1f8 MoviePlayer::__ct +805dc248 MoviePlayer::__dt +805dc2a0 MoviePlayer::Init +805dc2a4 MoviePlayer::Quit +805dc334 MoviePlayer::Update +805dc560 MoviePlayer::Prepare +805dc7d4 0x805dc7d4 +805dc850 MoviePlayer::Close +805dc898 MoviePlayer::GetCurTHPTextureInfo +805dc8b4 MoviePlayer::IsPlaying +805dc8f0 MoviePlayer::Pause +805dc90c MoviePlayer::Play +805dc928 MoviePlayer::GetCurTextureIdx +805dc930 MoviePlayer::Reprepare +805dc97c 0x805dc97c +805dc9d0 PadControl::GetClassName +805dc9dc PadControl::__ct +805dca18 PadControl::__dt +805dca70 PadControl::Load +805dcb30 PadControl::InitSelf +805dcb9c PadControl::OnUpdate +805dcc74 PadControl::SetParams +805dcc84 PadControl::SetPadID +805dcc8c PadControl::RegisterPad +805dccc4 PadControl::UpdateFromParams +805dce1c 0x805dce1c +805dce2c 0x805dce2c +805dce68 0x805dce68 +805dcec4 0x805dcec4 +805dcef4 RecognizePadWindow::GetClassName +805dcf04 RecognizePadWindow::__ct +805dcf40 RecognizePadWindow::__dt +805dcf98 RecognizePadWindow::Load +805dd014 RecognizePadWindow::InitSelf +805dd018 RecognizePadWindow::OnUpdate +805dd01c RecognizePadWindow::SetPositionAnim +805dd054 RecognizePadWindow::GetRuntimeTypeInfo +805dd060 0x805dd060 +805dd06c PadControl::GetRuntimeTypeInfo +805dd078 PadControl_sinit_ +805dd09c Page::__ct +805dd124 Page::__dt +805dd180 Page::Init +805dd1f8 Page::OnInit +805dd1fc Page::Dispose +805dd20c Page::Activate +805dd328 Page::Deactivate +805dd368 Page::IncrementDuration +805dd384 Page::CheckActions +805dd444 Page::UpdateState +805dd664 Page::Exit +805dd864 Page::Enter +805dd9ec Page::UpdateControls +805dda58 Page::Update +805dda7c Page::Draw +805dda98 Page::ResetManipulatorManager +805ddaac 0x805ddaac +805ddab0 Page::Resume +805ddb48 Page::HandleSectionChange +805ddb6c Page::SetAnimDirection +805ddb7c Page::InitControlGroup +805ddb8c Page::AddControl +805ddb94 Page::SetManipulatorManager +805ddb9c Page::EndState +805ddba8 Page::EndStateAnimated +805ddbc4 Page::EndExitState +805ddbd0 Page::ChangeSectionBySceneChange +805ddc50 Page::ChangeSectionByReinit +805ddcd0 Page::AddPageLayer +805ddd7c Page::AnimateControls +805ddecc Page::ControlAnimator::Calc +805ddfec Pages::System::GetAnimDelay +805de040 Page::MaxAnimDelayGetter::Calc +805de080 Page::OnStateChangeAnimator::Calc +805de090 Page::StartEntrance +805de114 Page::EndEntrance +805de224 Page::StartExit +805de380 Page::EndExit +805de408 Page::80602ce8 +805de418 Page::PlaySound +805de42c 0x805de42c +805de440 Page::SetTransitionSound +805de44c Pages::System::__ct +805de4e0 Pages::System::__dt +805de574 Pages::System::Setup +805de60c Pages::System::CheckForConditions +805de614 SystemPagecpp_sinit_ +805de624 Pages::RegisteredPads::__ct +805de688 Pages::RegisteredPads::__dt +805de708 Pages::RegisteredPads::OnInit +805de7fc Pages::RegisteredPads::OnActivate +805de970 Pages::RegisteredPads::BeforeEntranceAnimations +805de974 Pages::RegisteredPads::AfterEntranceAnimations +805de978 Pages::RegisteredPads::AfterControlUpdate +805dea24 Pages::RegisteredPads::AfterExitAnimations +805dea28 Pages::RegisteredPads::GetNextPage +805dea70 Pages::RegisteredPads::Register +805dead8 ConnectController::GetClassName +805deae8 ConnectController::__ct +805deb24 ConnectController::__dt +805deb7c ConnectController::Load +805decf8 ConnectController::InitSelf +805dedb0 ConnectController::OnUpdate +805dee84 Pages::RegisterPad::__ct +805defb0 CtrlMenuDummyBack::__dt +805df008 Pages::RegisterPad::__dt +805df0c4 Pages::RegisterPad::OnInit +805df2b0 Pages::RegisterPad::OnActivate +805df2c4 Pages::RegisterPad::AfterControlUpdate +805df630 Pages::RegisterPad::GetNextPage +805df648 Pages::RegisterPad::IsDVDEnabled +805df690 Pages::RegisterPad::OnBackPress +805df6dc Pages::RegisterPad::OnStartPress +805df794 EasyPairingController::GetClassName +805df7a4 EasyPairingController::__ct +805df7e0 EasyPairingController::__dt +805df838 EasyPairingController::Load +805df9c8 EasyPairingController::InitSelf +805dfad8 EasyPairingController::OnUpdate +805dfc38 0x805dfc38 +805dfca4 Pages::PairWiimotes::__ct +805dfd58 Pages::PairWiimotes::__dt +805dfdfc Pages::PairWiimotes::OnInit +805e0060 Pages::PairWiimotes::OnActivate +805e00e0 Pages::PairWiimotes::AfterEntranceAnimations +805e00ec Pages::PairWiimotes::BeforeEntranceAnimations +805e00f8 Pages::PairWiimotes::BeforeExitAnimations +805e0104 Pages::PairWiimotes::OnDeactivate +805e01a8 Pages::PairWiimotes::AfterControlUpdate +805e0220 Pages::PairWiimotes::SyncWiimotes +805e03a4 Pages::PairWiimotes::OnBackAndStartPress +805e03f8 Pages::ConfirmPads::__ct +805e05c0 Pages::ConfirmPads::__dt +805e0670 Pages::ConfirmPads::OnInit +805e08b8 Pages::ConfirmPads::OnActivate +805e0904 Pages::ConfirmPads::OnDeactivate +805e0924 Pages::ConfirmPads::OnOkButtonClick +805e0980 Pages::ConfirmPads::OnChangeButtonClick +805e0a60 Pages::ConfirmPads::OnBackButtonClick +805e0b90 Pages::ConfirmPads::OnButtonSelect +805e0be4 Pages::ConfirmPads::OnBackPress +805e0cec Pages::ConfirmPads::GetNextPage +805e0cf4 Pages::ConfirmPads::GetRuntimeTypeInfo +805e0d00 Pages::PairWiimotes::GetRuntimeTypeInfo +805e0d0c EasyPairingController::GetRuntimeTypeInfo +805e0d18 Pages::RegisterPad::IsHomeMenuWorking +805e0d20 Pages::RegisterPad::GetRuntimeTypeInfo +805e0d2c ConnectController::GetRuntimeTypeInfo +805e0d38 Pages::RegisterPad::GetRuntimeTypeInfo +805e0d44 TriggerPtmf +805e0d74 TriggerPtmf +805e0da4 TriggerPtmf +805e0dd4 TriggerPtmf +805e0e04 RegisterPadPage_cpp_sinit_ +805e0e38 RadioButtonControl::GetClassName +805e0e44 RadioButtonControl::__ct +805e0fe8 RadioButtonControl::__dt +805e106c RadioButtonControl::Load +805e1470 RadioButtonControl::OnLoadingEnd +805e1474 RadioButtonControl::SetOnClickHandler +805e147c RadioButtonControl::SetOnSelectHandler +805e1484 RadioButtonControl::SetOnDeselectHandler +805e148c RadioButtonControl::SetOnChangeHandler +805e1494 RadioButtonControl::SelectInitialButton +805e151c 0x805e151c +805e153c 0x805e153c +805e15d4 0x805e15d4 +805e1644 RadioButtonControl::Init +805e1820 RadioButtonControl::Update +805e19f8 RadioButtonControl::HandleSelect +805e1b54 RadioButtonControl::HandleDeselect +805e1c88 RadioButtonControl::HandleButtonSelect +805e1d40 RadioButtonControl::HandleClick +805e1df4 RadioButtonControl::HandleRightPress +805e1eb0 RadioButtonControl::HandleLeftPress +805e1f68 RadioButtonControl::OptionButton::GetClassName +805e1f78 RadioButtonControl::OptionButton::__ct +805e1fb4 RadioButtonControl::OptionButton::__dt +805e200c RadioButtonControl::OptionButton::Load +805e20b4 RadioButtonControl::OptionButton::Init +805e2134 RadioButtonControl::OptionButton::Update +805e21f0 RadioButtonControl::OptionButton::GetParentControl +805e22f0 GetInstanceUnusedControl? +805e22fc GetInstanceUnusedControl? +805e2308 0x805e2308 +805e2368 RadioButtonControl::OptionButton::ToggleChose +805e24e4 0x805e24e4 +805e2544 RadioButtonControl::OptionButton::ToggleSelect +805e26a8 RadioButtonControl::OptionButton::SetBorderColours +805e275c RadioButtonControl::OptionButton::SetColor_BaseColours +805e2804 RadioButtonControl::Func_0x40 +805e2808 RadioButtonControl::GetRuntimeTypeInfo +805e2814 RadioButtonControl::OptionButton::GetRuntimeTypeInfo +805e2820 RadioButtonControl_cpp_sinit_ +805e2850 RadioButtonControl_cpp_sinit_ +805e286c RandomMatchingPlayer::GetClassName +805e2878 RandomMatchingPlayer::__ct +805e28ec RandomMatchingPlayer::__dt +805e2944 RandomMatchingPlayer::Load +805e2a88 RandomMatchingPlayer::InitSelf +805e2be0 RandomMatchingPlayer::OnUpdate +805e2e50 0x805e2e50 +805e2f8c 0x805e2f8c +805e3044 0x805e3044 +805e30dc 0x805e30dc +805e3260 0x805e3260 +805e3278 RandomMatchingPlayer::SetMii +805e3304 RandomMatchingPlayer::IsShowing +805e333c RandomMatchingPlayer::OnMiiShowing +805e33fc RandomMatchingPlayer::CalcAngle +805e344c 0x805e344c +805e34a8 MatchingMessageWindow::GetClassName +805e34b8 MatchingMessageWindow::__ct +805e34f4 MatchingMessageWindow::__dt +805e354c MatchingMessageWindow::Load +805e35b0 MatchingMessageWindow::InitSelf +805e3614 MatchingMessageWindow::OnUpdate +805e3618 MatchingMessageWindow::SetMessage +805e36d0 MatchingMessageWindow::Hide +805e3780 Pages::GlobeSearch::__ct +805e38b4 Pages::GlobeSearch::__dt +805e3988 Pages::GlobeSearch::OnInit +805e3bb4 Pages::GlobeSearch::OnActivate +805e4438 Pages::Menu::GetRuntimeTypeInfo +805e4444 Pages::GlobeSearch::BeforeEntranceAnimations +805e4448 Pages::GlobeSearch::BeforeExitAnimations +805e4498 Pages::GlobeSearch::BeforeControlUpdate +805e49ec Pages::GlobeSearch::AfterControlUpdate +805e515c Pages::GlobeSearch::OnResume +805e53e4 0x805e53e4 +805e5424 0x805e5424 +805e55b0 Pages::GlobeSearch::PrepareLiveView +805e5b38 0x805e5b38 +805e5d84 0x805e5d84 +805e5d9c Pages::GlobeSearch::GetNextPage +805e5da4 Pages::GlobeSearch::IsHomeMenuWorking +805e5dac Pages::GlobeSearch::GetRuntimeTypeInfo +805e5db8 MatchingMessageWindow::GetRuntimeTypeInfo +805e5dc4 RandomMatchingPlayer::GetRuntimeTypeInfo +805e5dd0 TriggerPtmf +805e5e00 TriggerPtmf +805e5e30 __sinit_RandomMatchingPage_cpp +805e5e58 RankingGraphControl::GetClassName +805e5e64 RankingGraphControl::__ct +805e5edc RankingGraphControl::__dt +805e5f7c RankingGraphControl::LoadAssets +805e6004 0x805e6004 +805e6028 RankingGraphControl::UpdateImpl +805e6738 0x805e6738 +805e67d4 0x805e67d4 +805e684c 0x805e684c +805e68c4 0x805e68c4 +805e690c 0x805e690c +805e695c 0x805e695c +805e69a4 RankingGraphControlTimeAttack::GetClassName +805e69b4 RankingGraphControlTimeAttack::__ct +805e6af8 RankingGraphControlTimeAttack::__dt +805e6c68 RankingGraphControlTimeAttack::Load +805e7054 0x805e7054 +805e7078 0x805e7078 +805e707c RankingGraphControlTimeAttack::GetWindow +805e70e8 0x805e70e8 +805e7228 RankingGraphControlTimeAttack::DisplayItems +805e7288 RankingGraphControlTimeAttack::DisableAllItems +805e73a8 RankingGraphControlTimeAttack:: DisplayItemsOnlineRankings +805e7e50 0x805e7e50 +805e7e90 RankingGraphControlTimeAttack:: DisplayItemsFriendsRankings +805e827c 0x805e827c +805e828c 0x805e828c +805e83ac 0x805e83ac +805e84e8 0x805e84e8 +805e8810 0x805e8810 +805e8834 0x805e8834 +805e8838 0x805e8838 +805e8884 0x805e8884 +805e88e4 0x805e88e4 +805e89c8 0x805e89c8 +805e9248 0x805e9248 +805e95e8 0x805e95e8 +805e95f4 RankingGraphControlTimeAttack::GetRuntimeTypeInfo +805e9600 RankingGraphControl::GetRuntimeTypeInfo +805e960c 0x805e960c +805e9630 0x805e9630 +805e969c 0x805e969c +805e9720 0x805e9720 +805e9848 0x805e9848 +805e9858 0x805e9858 +805e9894 0x805e9894 +805e98ec 0x805e98ec +805e9964 0x805e9964 +805e999c 0x805e999c +805e99a0 Pages::RankingGraph::__ct +805e9c3c Pages::RankingGraph::__dt +805e9d24 Pages::RankingGraph::OnInit +805ea1c4 Pages::RankingGraph::OnDispose +805ea278 Pages::RankingGraph::OnActivate +805ea43c 0x805ea43c +805ea538 Pages::RankingGraph::OnTAUpDownChange +805ea554 Pages::RankingGraph::OnTAUpDownClick +805ea5a0 Pages::RankingGraph::OnTATextChange +805ea624 Pages::RankingGraph::OnCompetitionUpDownChange +805ea640 Pages::RankingGraph::OnCompetitionTextChange +805ea76c Pages::RankingGraph::OnRankingTypeUpDownChange +805ea890 Pages::RankingGraph::OnRankingTypeTextChange +805ea8a0 Pages::RankingGraph::OnBackButtonClick +805ea8ec Pages::RankingGraph::OnBackPress +805ea90c Pages::RankingGraph::SetBottomText +805ea914 0x805ea914 +805eaa44 0x805eaa44 +805eab24 0x805eab24 +805eaba8 0x805eaba8 +805eabb8 0x805eabb8 +805eabc8 0x805eabc8 +805eacec Pages::RankingGraph::GetNextPage +805eacf4 Pages::RankingGraph::GetRuntimeTypeInfo +805ead00 0x805ead00 +805ead0c 0x805ead0c +805ead18 TriggerPtmf +805ead48 TriggerPtmf +805ead78 TriggerPtmf +805eada8 TriggerPtmf +805eadd8 TriggerPtmf +805eae08 0x805eae08 +805eae30 SectionPad::__ct +805eae40 SectionPad::__dt +805eae80 SectionPad::Init +805eaee4 SectionPad::Update +805eb2fc SectionPad::ResetPadsStatusAndSet0x54 +805eb31c SectionPad::GetCurrentID +805eb33c SectionPad::GetNewID +805eb35c SectionPad::GetControllerHolder +805eb390 SectionPad::HasAController +805eb3e4 SectionPad::SetDriftType +805eb404 SectionPad::IsDriftAuto +805eb434 0x805eb434 +805eb454 SectionPad::SetID +805eb46c 0x805eb46c +805eb568 0x805eb568 +805eb6b0 SectionPad::RequestPad +805eb788 SectionPad::ResetPad +805eb860 SectionPad::SetPadDisconnected +805eb874 SectionPad::DisconnectPad +805eb964 SectionPad::ResetPadsStatus +805eb980 SectionPad::GetFirstDeactivatedPad +805eba0c SectionPad::HasControllerChanged +805eba44 0x805eba44 +805ebc18 SectionPad::Has4WiimotePads +805ebc8c SectionPad::ResetAllPads +805ebcd8 SectionPad::EnablePointer +805ebd80 SectionPad::GetControllerHolderByIdx +805ebe04 SectionPad::CalculateID +805ebf70 SectionPad::GetType +805ebfc0 Pages::RecognizePad::__ct +805ec01c Pages::RecognizePad::__dt +805ec09c Pages::RecognizePad::OnInit +805ec184 Pages::RecognizePad::OnActivate +805ec24c Pages::RecognizePad::OnDeactivate +805ec2a8 Pages::RecognizePad::AfterControlUpdate +805ec348 Pages::RecognizePad::BeforeEntranceAnimations +805ec38c Pages::RecognizePad::AfterExitAnimations +805ec3d0 Pages::RecognizePad::CheckForConditions +805ec4dc Pages::RecognizePad::IsVisible +805ec500 Pages::RecognizePadMenu::__ct +805ec568 Pages::RecognizePadMenu::__dt +805ec5ec Pages::RecognizePadMenu::BeforeEntranceAnimations +805ec6e4 Pages::RecognizePadMenu::AfterEntranceAnimations +805ec730 Pages::RecognizePadMenu::BeforeExitAnimations +805ec744 Pages::RecognizePadMenu::AfterExitAnimations +805ec788 Pages::RecognizePadMenu::BeforeControlUpdate +805ec830 Pages::RecognizePadMenu::IsDVDEnabled +805ec844 0x805ec844 +805ec8ac 0x805ec8ac +805ec930 0x805ec930 +805eca04 0x805eca04 +805eca6c 0x805eca6c +805ecb58 0x805ecb58 +805ecba4 0x805ecba4 +805ecbb8 0x805ecbb8 +805ecbfc 0x805ecbfc +805ecce8 0x805ecce8 +805ecd04 0x805ecd04 +805ecd6c 0x805ecd6c +805ecdf0 0x805ecdf0 +805ecec4 0x805ecec4 +805ecfb0 0x805ecfb0 +805ecffc 0x805ecffc +805ed010 0x805ed010 +805ed054 0x805ed054 +805ed140 0x805ed140 +805ed15c 0x805ed15c +805ed168 0x805ed168 +805ed174 0x805ed174 +805ed180 0x805ed180 +805ed18c Pages::RecognizePadMenu::GetClassName +805ed198 Pages::RecognizePadMenu::GetRuntimeTypeInfo +805ed1a4 Pages::RecognizePad::GetRuntimeTypeInfo +805ed1b0 0x805ed1b0 +805ed1d8 Pages::RegisteringFriend::__ct +805ed24c Pages::RegisteringFriend::__dt +805ed2c4 Pages::RegisteringFriend::OnInit +805ed36c Pages::RegisteringFriend::OnActivate +805ed48c Pages::RegisteringFriend::BeforeEntranceAnimations +805ed490 Pages::RegisteringFriend::BeforeExitAnimations +805ed494 Pages::RegisteringFriend::AfterControlUpdate +805ed5ec Pages::RegisteringFriend::OnResume +805edc04 Pages::RegisteringFriend::GetNextPage +805edc60 Pages::RegisteringFriend::IsHomeMenuWorking +805edc7c Pages::RegisterFriend::__ct +805edeb4 Pages::RegisterFriend::__dt +805edf78 Pages::RegisterFriend::OnInit +805ee234 Pages::RegisterFriend::OnActivate +805ee2ac 0x805ee2ac +805ee304 0x805ee304 +805ee30c Pages::RegisterFriend::OnDigitClick +805ee378 Pages::RegisterFriend::OnBackSpaceClick +805ee3c4 Pages::RegisterFriend::OnOkButtonClick +805ee6b0 Pages::RegisterFriend::OnBackButtonClick +805ee6f4 Pages::RegisterFriend::OnOkButtonSelect +805ee730 Pages::RegisterFriend::OnOkButtonDeselect +805ee740 Pages::RegisterFriend::OnBackPress +805ee7c8 Pages::RegisterFriend::GetRuntimeTypeInfo +805ee7d4 Pages::xA5::GetRuntimeTypeInfo +805ee7e0 TriggerPtmf +805ee810 TriggerPtmf +805ee840 RegisterFriendPage_cpp_sinit_ +805ee85c Pages::CorruptSaveMgr::__ct +805ee8d8 Pages::CorruptSaveMgr::__dt +805ee940 Pages::CorruptSaveMgr::OnInit +805ee99c Pages::CorruptSaveMgr::OnActivate +805eeb28 Pages::CorruptSaveMgr::AfterControlUpdate +805eed60 Pages::CorruptSaveMgr::OnResume +805eeef8 Pages::CorruptSaveMgr::IsHomeMenuWorking +805eef10 Pages::CorruptSaveMgr::InitYesNoValues +805ef0b4 0x805ef0b4 +805ef1c0 Pages::CorruptSaveMgr::OnReturnToWiiMenuClick +805ef230 Pages::CannotSave::__ct +805ef2ac Pages::CannotSave::__dt +805ef314 Pages::CannotSave::OnInit +805ef370 Pages::CannotSave::OnActivate +805ef514 Pages::CannotSave::OnYesNoClick +805ef5b4 Pages::CorruptMemory::__ct +805ef600 Pages::CorruptMemory::__dt +805ef674 Pages::CorruptMemory::OnInit +805ef738 Pages::CorruptMemory::OnActivate +805ef7ac Pages::CorruptMiiData::__ct +805ef838 Pages::CorruptMiiData::__dt +805ef8b8 Pages::CorruptMiiData::OnInit +805ef9bc Pages::CorruptMiiData::OnActivate +805efa14 Pages::CorruptMiiData::OnButtonClick +805efa60 Pages::CorruptMiiData::IsHomeMenuWorking +805efa68 Pages::CorruptMiiData::GetRuntimeTypeInfo +805efa74 Pages::CorruptMemory::IsHomeMenuWorking +805efa7c Pages::CorruptMemory::GetRuntimeTypeInfo +805efa88 Pages::CannotSave::__dt +805efa90 Pages::CannotSave::GetRuntimeTypeInfo +805efa9c Pages::CorruptSaveMgr::GetRuntimeTypeInfo +805efaa8 TriggerPtmf +805efad8 TriggerPtmf +805efb08 TriggerPtmf +805efb38 CorruptPages_cpp_sinit_ +805efb5c RKSYSRequester::__ct +805efb90 0x805efb90 +805efc00 RKSYSRequester::__dt +805efc78 RKSYSRequester::Reset +805efcb4 RKSYSRequester::Update +805efdd0 RKSYSRequester::Init +805efef0 RKSYSRequester::Close +805eff24 RKSYSRequester::HandleRequest +805f0328 RKSYSRequester::HandleAllRequests +805f0448 RKSYSRequester::CheckRequests +805f04f0 RKSYSRequester::HasError +805f0504 0x805f0504 +805f0518 RKSYSRequester::RequestEraseAllGhosts +805f0530 RKSYSRequester::RequestSaveLicense +805f055c RKSYSRequester::NotifyNewLicenseContent +805f0580 RKSYSRequester::RequestSaveLicenseIfNewContent +805f05d0 RKSYSRequester::RequestSaveGhost +805f0978 RKSYSRequester::RequestSaveGhost_0x18 +805f0d1c RKSYSRequester::RequestEraseGhost +805f0d54 RKSYSRequester::RequestEraseGhostFromLicense +805f0d88 RKSYSRequester::RequestGetDLdGhost +805f0dc4 RKSYSRequester::RequestGetGhostFromLicense +805f0dfc RKSYSRequester::RequestGetGroupGhosts +805f0e2c RKSYSRequester::RequestGetGroupGhostsFromLicense +805f0e58 Section::__ct +805f0ed0 Section::__dt +805f0f4c Section::Init +805f11fc Section::Enter +805f1324 Section::Exit +805f14ec Section::UpdateSystemPages +805f1644 Section::Update +805f18b0 Section::Draw +805f1c2c Section::Pause +805f1c98 Section::Resume +805f1d54 Section::OnTransition +805f1db4 Section::CreateMoviePlayer +805f1e04 Section::CreateFriendList +805f1e54 Section::CreateAndInitPage +805f1ea0 Section::CreateSystemPage +805f1eec Section::AddPageLayer +805f1f4c Section::AddPageLayerAnimatedReturnTopLayer +805f1fb8 Section::IsPageTopLayer +805f1fec Section::GetTopLayerPage +805f2014 Section::IsHomeMenuWorking +805f20d4 Section::IsDVDEnabled +805f21a0 Section::ScheduleDisconnection +805f21b4 Section::UpdateLayers +805f2374 Section::AddPageLayerAnimated +805f23d4 Section::TopLayerPage +805f2434 Section::RemovePageLayers +805f24dc Section::CreatePageById +805f2504 Section::CreatePageById_switch +805f2508 Section::CreatePageById_case0 +805f2520 Section::CreatePageById_case1 +805f2538 Section::CreatePageById_case2 +805f2550 Section::CreatePageById_case3 +805f2568 Section::CreatePageById_case4 +805f2580 Section::CreatePageById_case5 +805f2598 Section::CreatePageById_case6 +805f25b0 Section::CreatePageById_case7 +805f25c8 Section::CreatePageById_case8 +805f25e0 Section::CreatePageById_case9 +805f25f8 Section::CreatePageById_casea +805f2610 Section::CreatePageById_caseb +805f2628 Section::CreatePageById_casec +805f2640 Section::CreatePageById_cased +805f2658 Section::CreatePageById_casee +805f2670 Section::CreatePageById_case10 +805f2688 Section::CreatePageById_case12 +805f26a0 Section::CreatePageById_case13 +805f26b8 Section::CreatePageById_case16 +805f26d0 Section::CreatePageById_case17 +805f26e8 Section::CreatePageById_case18 +805f2700 Section::CreatePageById_case19 +805f2718 Section::CreatePageById_case1a +805f2730 Section::CreatePageById_case1b +805f2748 Section::CreatePageById_case1c +805f2760 Section::CreatePageById_case1d +805f2778 Section::CreatePageById_case1e +805f2790 Section::CreatePageById_case1f +805f27a8 Section::CreatePageById_case20 +805f27c0 Section::CreatePageById_case21 +805f27d8 Section::CreatePageById_case22 +805f27f0 Section::CreatePageById_case23 +805f2808 Section::CreatePageById_case24 +805f2820 Section::CreatePageById_case25 +805f2838 Section::CreatePageById_case26 +805f2850 Section::CreatePageById_case27 +805f2868 Section::CreatePageById_case28 +805f2880 Section::CreatePageById_case29 +805f2898 Section::CreatePageById_case2a +805f28b0 Section::CreatePageById_case2b +805f28c8 Section::CreatePageById_case2c +805f28e0 Section::CreatePageById_case2d +805f28f8 Section::CreatePageById_case2e +805f2910 Section::CreatePageById_case2f +805f2928 Section::CreatePageById_case30 +805f2940 Section::CreatePageById_case31 +805f2958 Section::CreatePageById_case32 +805f2970 Section::CreatePageById_case33 +805f2988 Section::CreatePageById_case34 +805f29a0 Section::CreatePageById_case35 +805f29b8 Section::CreatePageById_case36 +805f29d0 Section::CreatePageById_case37 +805f29e8 Section::CreatePageById_case38 +805f2a00 Section::CreatePageById_case39 +805f2a18 Section::CreatePageById_case3a +805f2a30 Section::CreatePageById_case3b +805f2a48 Section::CreatePageById_case3c +805f2a60 Section::CreatePageById_case3d +805f2a78 Section::CreatePageById_case3e +805f2a90 Section::CreatePageById_case3f +805f2aa8 Section::CreatePageById_case40 +805f2ac0 Section::CreatePageById_case41 +805f2ad8 Section::CreatePageById_case42 +805f2af0 Section::CreatePageById_case43 +805f2b08 Section::CreatePageById_case44 +805f2b20 Section::CreatePageById_case45 +805f2b38 Section::CreatePageById_case46 +805f2b50 Section::CreatePageById_case47 +805f2b68 Section::CreatePageById_case48 +805f2b80 Section::CreatePageById_case49 +805f2b98 Section::CreatePageById_case4a +805f2bb0 Section::CreatePageById_case4b +805f2bc8 Section::CreatePageById_case4c +805f2be0 Section::CreatePageById_case4d +805f2bf8 Section::CreatePageById_case4e +805f2c10 Section::CreatePageById_case4f +805f2c28 Section::CreatePageById_case51 +805f2c40 Section::CreatePageById_case52 +805f2c58 Section::CreatePageById_case53 +805f2c70 Section::CreatePageById_case54 +805f2c88 Section::CreatePageById_case55 +805f2ca0 Section::CreatePageById_case56 +805f2cb8 Section::CreatePageById_case57 +805f2cd0 Section::CreatePageById_case58 +805f2ce8 Section::CreatePageById_case59 +805f2d00 Section::CreatePageById_case5a +805f2d18 Section::CreatePageById_case5b +805f2d30 Section::CreatePageById_case5c +805f2d48 Section::CreatePageById_case5d +805f2d60 Section::CreatePageById_case5e +805f2d78 Section::CreatePageById_case5f +805f2d90 Section::CreatePageById_case60 +805f2da8 Section::CreatePageById_case61 +805f2dc0 Section::CreatePageById_case62 +805f2dd8 Section::CreatePageById_case63 +805f2df0 Section::CreatePageById_case64 +805f2e08 Section::CreatePageById_case65 +805f2e20 Section::CreatePageById_case66 +805f2e38 Section::CreatePageById_case67 +805f2e50 Section::CreatePageById_case68 +805f2e68 Section::CreatePageById_case69 +805f2e80 Section::CreatePageById_case6a +805f2e98 Section::CreatePageById_case6b +805f2eb0 Section::CreatePageById_case6c +805f2ec8 Section::CreatePageById_case6d +805f2ee0 Section::CreatePageById_case6e +805f2ef8 Section::CreatePageById_case6f +805f2f10 Section::CreatePageById_case70 +805f2f28 Section::CreatePageById_case71 +805f2f40 Section::CreatePageById_case72 +805f2f58 Section::CreatePageById_case73 +805f2f70 Section::CreatePageById_case74 +805f2f88 Section::CreatePageById_case75 +805f2fa0 Section::CreatePageById_case76 +805f2fb8 Section::CreatePageById_case77 +805f2fd0 Section::CreatePageById_case78 +805f2fe8 Section::CreatePageById_case79 +805f3000 Section::CreatePageById_case7a +805f3018 Section::CreatePageById_case7b +805f3030 Section::CreatePageById_case7c +805f3048 Section::CreatePageById_case7d +805f3060 Section::CreatePageById_case7e +805f3078 Section::CreatePageById_case7f +805f3090 Section::CreatePageById_case80 +805f30a8 Section::CreatePageById_case81 +805f30c0 Section::CreatePageById_case82 +805f30d8 Section::CreatePageById_case83 +805f30f0 Section::CreatePageById_case84 +805f3108 Section::CreatePageById_case85 +805f3120 Section::CreatePageById_case86 +805f3138 Section::CreatePageById_case87 +805f3150 Section::CreatePageById_case88 +805f3168 Section::CreatePageById_case89 +805f3180 Section::CreatePageById_case8a +805f3198 Section::CreatePageById_case8b +805f31b0 Section::CreatePageById_case8c +805f31c8 Section::CreatePageById_case8d +805f31e0 Section::CreatePageById_case8e +805f31f8 Section::CreatePageById_case8f +805f3210 Section::CreatePageById_case90 +805f3228 Section::CreatePageById_case91 +805f3240 Section::CreatePageById_case92 +805f3258 Section::CreatePageById_case93 +805f3270 Section::CreatePageById_case94 +805f3288 Section::CreatePageById_case95 +805f32a0 Section::CreatePageById_case96 +805f32b8 Section::CreatePageById_case97 +805f32d0 Section::CreatePageById_case98 +805f32e8 Section::CreatePageById_case99 +805f3300 Section::CreatePageById_case9a +805f3318 Section::CreatePageById_case9b +805f3330 Section::CreatePageById_case9c +805f3348 Section::CreatePageById_case9d +805f3360 Section::CreatePageById_case9e +805f3378 Section::CreatePageById_case9f +805f3390 Section::CreatePageById_casea0 +805f33a8 Section::CreatePageById_casea1 +805f33c0 Section::CreatePageById_casea2 +805f33d8 Section::CreatePageById_casea3 +805f33f0 Section::CreatePageById_casea4 +805f3408 Section::CreatePageById_casea5 +805f3420 Section::CreatePageById_casea6 +805f3438 Section::CreatePageById_casea7 +805f3450 Section::CreatePageById_casea8 +805f3468 Section::CreatePageById_caseaa +805f3480 Section::CreatePageById_caseab +805f3498 Section::CreatePageById_caseac +805f34b0 Section::CreatePageById_casead +805f34c8 Section::CreatePageById_caseae +805f34e0 Section::CreatePageById_caseaf +805f34f8 Section::CreatePageById_caseb0 +805f3510 Section::CreatePageById_caseb1 +805f3528 Section::CreatePageById_caseb2 +805f3540 Section::CreatePageById_caseb3 +805f3558 Section::CreatePageById_caseb4 +805f3570 Section::CreatePageById_caseb5 +805f3588 Section::CreatePageById_caseb6 +805f35a0 Section::CreatePageById_caseb7 +805f35b8 Section::CreatePageById_caseb8 +805f35d0 Section::CreatePageById_caseb9 +805f35e8 Section::CreatePageById_caseba +805f3600 Section::CreatePageById_casebb +805f3618 Section::CreatePageById_casebc +805f3630 Section::CreatePageById_casebd +805f3648 Section::CreatePageById_casebe +805f3660 Section::CreatePageById_casebf +805f3678 Section::CreatePageById_casec0 +805f3690 Section::CreatePageById_casec1 +805f36a8 Section::CreatePageById_casec2 +805f36c0 Section::CreatePageById_casec3 +805f36d8 Section::CreatePageById_casec5 +805f36f0 Section::CreatePageById_casec6 +805f3708 Section::CreatePageById_casec7 +805f3720 Section::CreatePageById_casec8 +805f3738 Section::CreatePageById_casec9 +805f3750 Section::CreatePageById_caseca +805f3768 Section::CreatePageById_casecb +805f3780 Section::CreatePageById_casecc +805f3798 Section::CreatePageById_casecd +805f37b0 Section::CreatePageById_casece +805f37dc Pages::RaceIntro::__ct +805f3830 Pages::GPHUD::__ct +805f38b0 Pages::RaceHUD::__dt +805f3918 Pages::TTHUD::__ct +805f39c0 Pages::VSHUD::__ct +805f3a40 Pages::VSMultiHUD::__ct +805f3ac0 Pages::BattleHUD::__ct +805f3b40 Pages::BattleMultiHUD::__ct +805f3bc0 Pages::TournamentHUD::__ct +805f3c40 Pages::GPPause::__ct +805f3c84 Pages::RaceMenu::__dt +805f3cec Pages::VSPause::__ct +805f3d30 Pages::TTPause::__ct +805f3d74 Pages::BattlePause::__ct +805f3db8 0x805f3db8 +805f3dfc 0x805f3dfc +805f3e40 0x805f3e40 +805f3e84 0x805f3e84 +805f3ec8 Pages::GhostReplayPause::GhostReplayPausePage +805f3f0c Pages::GPEnd::__ct +805f3f50 Pages::TTEnd::__ct +805f3f94 Pages::VSRaceEnd::VSRaceEndPage +805f3fd8 Pages::BattleEnd::__ct +805f401c Pages::BattleFinalRaceEnd::__ct +805f4060 0x805f4060 +805f40a4 0x805f40a4 +805f40e8 0x805f40e8 +805f412c 0x805f412c +805f4170 Pages::TTFriendGhostEnd::__ct +805f41b4 0x805f41b4 +805f41f8 Pages::CheckRankings::__ct +805f423c Pages::QuitConfirmation::__ct +805f4280 Pages::TTLeaderboard::__ct +805f42e4 Pages::Leaderboard::__dt +805f434c 0x805f434c +805f43b8 Pages::GPVSLeaderboardUpdate::__ct +805f43f4 Pages::GPVSLeaderboardTotal::__ct +805f4430 Pages::WWLeaderboardUpdate::__ct +805f446c Pages::TeamVSLeaderboardTotal::__ct +805f44d4 CtrlRaceResultTeam::__ct +805f4538 CtrlRaceResultTeam::__dt +805f45ac Pages::TeamVSLeaderboardBase::__dt +805f4634 Pages::BattleLeaderboardUpdate::__ct +805f469c Pages::BattleLeaderboardTotal::__ct +805f4704 0x805f4704 +805f4740 Pages::GPReplayHUD::__ct +805f47c0 Pages::GhostRaceHUD::__ct +805f4840 Pages::GPReplayPause::__ct +805f4884 Pages::TTReplayPause::__ct +805f48c8 Pages::WifiVSHUD::__ct +805f4948 Pages::WifiVSMultiHUD::__ct +805f49c8 Pages::WiFiFriendVSHUD::__ct +805f4a48 Pages::WiFiFriendTeamVSHUD::__ct +805f4ac8 Pages::LiveViewHUD::__ct +805f4b48 Pages::LiveBattleViewHUD::__ct +805f4bc8 Pages::StartRace::__ct +805f4e7c Pages::Menu::__dt +805f4ee8 Pages::DriftSelect::OnStartPress +805f4eec Pages::MainMenu::__ct +805f51c4 Pages::MenuBG::__ct +805f5334 Pages::TopMenuOverlay::__ct +805f54a8 Pages::MiiSelect::__ct +805f578c MiiName::__dt +805f57e4 Pages::SinglePlayer::__ct +805f5a9c Pages::GPClassSelect::__ct +805f5d5c Pages::CharacterSelect::__ct +805f6154 CtrlMenuCharacterSelect::__dt +805f61ac Pages::KartSelect::__ct +805f6484 CtrlMenuMachineGraph::__ct +805f64c0 CtrlMenuMachineGraph::__dt +805f6518 Pages::DriftSelect::__ct +805f67d0 Pages::CupSelect::__ct +805f6b8c CtrlMenuMovieHandler::__dt +805f6bcc CtrlMenuMovieLayout::__dt +805f6c28 CtrlMenuCupSelectCup::__dt +805f6cb0 CtrlMenuCupSelectCourse::__dt +805f6d24 Pages::CourseSelect::__ct +805f70b8 CtrlMenuCourseSelectCupSub::__ct +805f70f4 CtrlMenuCourseSelectCupSub::__dt +805f714c CtrlMenuCourseSelectCup::__dt +805f71c0 CourseButton::__ct +805f7220 CtrlMenuMovieButton::__dt +805f727c CourseButton::__dt +805f72dc 0x805f72dc +805f735c Pages::VSModeSelect::__ct +805f7614 Pages::VSSettings::VSSetting +805f792c Pages::VSTeamsView::__ct +805f7c00 CtrlMenuTeamConfirmTeam::__ct +805f7c5c CtrlMenuTeamConfirmTeam::__dt +805f7cd0 Pages::BattleModeSelect::__ct +805f7f88 Pages::BattleKartSelect::__ct +805f8278 CharaName::__dt +805f82d0 Pages::BattleSettings::__ct +805f85e8 Pages::BattleCupSelect::__ct +805f89a4 CtrlMenuBattleCupSelectCup::__dt +805f8a2c CtrlMenuBattleCupSelectStage::__dt +805f8aa0 Pages::BattleStageSelect::__ct +805f8e34 0x805f8e34 +805f8e70 0x805f8e70 +805f8ec8 CtrlMenuBattleStageSelectCup::__dt +805f8f3c StageButton::__ct +805f8f9c StageButton::__dt +805f8ffc CtrlMenuBattleStageSelectStage::__ct +805f907c 0x805f907c +805f9438 0x805f9438 +805f94c0 0x805f94c0 +805f9534 0x805f9534 +805f98c8 0x805f98c8 +805f9904 0x805f9904 +805f995c 0x805f995c +805f99d0 0x805f99d0 +805f9a30 0x805f9a30 +805f9a90 0x805f9a90 +805f9b10 0x805f9b10 +805f9de8 0x805f9de8 +805fa0d4 0x805fa0d4 +805fa38c Pages::MultiPlayer::__ct +805fa640 Pages::MultiKartSelect::__ct +805fa974 MultiKartBox::__ct +805fa9b0 MultiKartBox::__dt +805faa08 Pages::MultiDriftSelect::__ct +805facbc Pages::MultiTeamSelect::__ct +805faf70 Pages::Unlock::__ct +805fb240 Pages::LicenseRecords::__ct +805fb4f0 Section::CreateSectionPages +805fb524 Section::CreateSectionPages_switch +805fb528 Section::CreateSectionPages_case6 +805fb534 Section::CreateSectionPages_case7 +805fb540 Section::CreateSectionPages_case8 +805fb54c Section::CreateSectionPages_case9 +805fb558 Section::CreateSectionPages_casea +805fb564 Section::CreateSectionPages_caseb +805fb570 Section::CreateSectionPages_casec +805fb57c Section::CreateSectionPages_cased +805fb588 Section::CreateSectionPages_casee +805fb594 Section::CreateSectionPages_casef +805fb5a0 Section::CreateSectionPages_case10 +805fb5c4 Section::CreateSectionPages_case11 +805fb5f4 Section::CreateSectionPages_case12 +805fb624 Section::CreateSectionPages_case13 +805fb648 Section::CreateSectionPages_case14 +805fb660 Section::CreateSectionPages_case15 +805fb678 Section::CreateSectionPages_case16 +805fb684 Section::CreateSectionPages_case17 +805fb690 Section::CreateSectionPages_case18 +805fb69c Section::CreateSectionPages_case19 +805fb6a8 Section::CreateSectionPages_case1a +805fb6b4 Section::CreateSectionPages_case1b +805fb6c0 Section::CreateSectionPages_case1c +805fb6cc Section::CreateSectionPages_case1d +805fb6d8 Section::CreateSectionPages_case1e +805fb72c Section::CreateSectionPages_case1f +805fb798 Section::CreateSectionPages_case20 +805fb7e0 Section::CreateSectionPages_case21 +805fb834 Section::CreateSectionPages_case22 +805fb888 Section::CreateSectionPages_case23 +805fb8dc Section::CreateSectionPages_case24 +805fb924 Section::CreateSectionPages_case25 +805fb978 Section::CreateSectionPages_case26 +805fb9cc Section::CreateSectionPages_case27 +805fba20 Section::CreateSectionPages_case28 +805fba74 Section::CreateSectionPages_case29 +805fbad4 Section::CreateSectionPages_case2a +805fbb34 Section::CreateSectionPages_case2b +805fbb94 Section::CreateSectionPages_case2c +805fbbd0 Section::CreateSectionPages_case2d +805fbc18 Section::CreateSectionPages_case2e +805fbc48 Section::CreateSectionPages_case2f +805fbc90 Section::CreateSectionPages_case30 +805fbd08 Section::CreateSectionPages_case31 +805fbd8c Section::CreateSectionPages_case32 +805fbdc8 Section::CreateSectionPages_case33 +805fbe04 Section::CreateSectionPages_case34 +805fbe40 Section::CreateSectionPages_case35 +805fbe58 Section::CreateSectionPages_case36 +805fbe70 Section::CreateSectionPages_case37 +805fbe88 Section::CreateSectionPages_case38 +805fbea0 Section::CreateSectionPages_case39 +805fbeac Section::CreateSectionPages_case3a +805fbeb8 Section::CreateSectionPages_case3b +805fbed0 Section::CreateSectionPages_case3c +805fbee8 Section::CreateSectionPages_case3d +805fbf24 Section::CreateSectionPages_case3e +805fbf60 Section::CreateSectionPages_case3f +805fbfe4 Section::CreateSectionPages_case40 +805fc068 Section::CreateSectionPages_case41 +805fc0ec Section::CreateSectionPages_case42 +805fc170 Section::CreateSectionPages_case43 +805fc1f4 Section::CreateSectionPages_case44 +805fc20c Section::CreateSectionPages_case45 +805fc254 Section::CreateSectionPages_case46 +805fc29c Section::CreateSectionPages_case47 +805fc344 Section::CreateSectionPages_case48 +805fc488 Section::CreateSectionPages_case49 +805fc5cc Section::CreateSectionPages_case4a +805fc710 Section::CreateSectionPages_case4b +805fc794 Section::CreateSectionPages_case4c +805fc818 Section::CreateSectionPages_case4d +805fc95c Section::CreateSectionPages_case4e +805fc9c8 Section::CreateSectionPages_case4f +805fca34 Section::CreateSectionPages_case50 +805fcaa0 Section::CreateSectionPages_case51 +805fcae8 Section::CreateSectionPages_case52 +805fcb30 Section::CreateSectionPages_case53 +805fcb78 Section::CreateSectionPages_case54 +805fccb0 Section::CreateSectionPages_case55 +805fce54 Section::CreateSectionPages_case56 +805fcff8 Section::CreateSectionPages_case57 +805fd19c Section::CreateSectionPages_case58 +805fd22c Section::CreateSectionPages_case59 +805fd2bc Section::CreateSectionPages_case5a +805fd31c Section::CreateSectionPages_case5b +805fd4c0 Section::CreateSectionPages_case5c +805fd664 Section::CreateSectionPages_case5d +805fd808 Section::CreateSectionPages_case5e +805fd898 Section::CreateSectionPages_case5f +805fd928 Section::CreateSectionPages_case60 +805fd9b8 Section::CreateSectionPages_case61 +805fda48 Section::CreateSectionPages_case62 +805fdad8 Section::CreateSectionPages_case63 +805fdb68 Section::CreateSectionPages_case64 +805fdbf8 Section::CreateSectionPages_case65 +805fdc88 Section::CreateSectionPages_case66 +805fdd18 Section::CreateSectionPages_case67 +805fdda8 Section::CreateSectionPages_case68 +805fde20 Section::CreateSectionPages_case69 +805fde98 Section::CreateSectionPages_case6a +805fdeec Section::CreateSectionPages_case6b +805fdf40 Section::CreateSectionPages_case6c +805fdfc4 Section::CreateSectionPages_case6d +805fe048 Section::CreateSectionPages_case6e +805fe0a8 Section::CreateSectionPages_case6f +805fe108 Section::CreateSectionPages_case70 +805fe174 Section::CreateSectionPages_case71 +805fe1e0 Section::CreateSectionPages_case72 +805fe24c Section::CreateSectionPages_case73 +805fe2b8 Section::CreateSectionPages_case74 +805fe324 Section::CreateSectionPages_case75 +805fe390 Section::CreateSectionPages_case76 +805fe3fc Section::CreateSectionPages_case77 +805fe468 Section::CreateSectionPages_case78 +805fe480 Section::CreateSectionPages_case79 +805fe498 Section::CreateSectionPages_case7a +805fe4ec Section::CreateSectionPages_case7b +805fe540 Section::CreateSectionPages_case7c +805fe594 Section::CreateSectionPages_case7d +805fe690 Section::CreateSectionPages_case7e +805fe75c Section::CreateSectionPages_case7f +805fe7e0 Section::CreateSectionPages_case80 +805fe8c4 Section::CreateSectionPages_case81 +805fe99c Section::CreateSectionPages_case82 +805fe9fc Section::CreateSectionPages_case83 +805feb88 Section::CreateSectionPages_case84 +805fed20 Section::CreateSectionPages_case85 +805fed98 Section::CreateSectionPages_case86 +805fee10 Section::CreateSectionPages_case87 +805fee94 Section::CreateSectionPages_case88 +805feeac Section::CreateSectionPages_case89 +805feec4 Section::CreateSectionPages_case8a +805fef18 Section::CreateSectionPages_case8b +805fef54 Section::CreateSectionPages_case8c +805ff014 Section::CreateSectionPages_case8d +805ff044 Section::CreateSectionPages_case8e +805ff068 Section::CreateSectionPages_case8f +805ff0d4 Section::CreateSectionPages_case90 +805ff104 Section::CreateSectionPages_case91 +805ff134 Section::CreateSectionPages_case92 +805ff164 Section::CreateSectionPages_case93 +805ff194 Section::CreateSectionPages_case94 +805ff1e0 Section::AddInitialLayers +805ff214 Section::AddInitialLayers_switch +805ff218 Section::AddInitialLayers_caseD_6 +805ff224 Section::AddInitialLayers_caseD_7 +805ff230 Section::AddInitialLayers_caseD_8 +805ff23c Section::AddInitialLayers_caseD_9 +805ff248 Section::AddInitialLayers_caseD_a +805ff254 Section::AddInitialLayers_caseD_b +805ff260 Section::AddInitialLayers_caseD_c +805ff26c Section::AddInitialLayers_caseD_d +805ff278 Section::AddInitialLayers_caseD_e +805ff284 Section::AddInitialLayers_caseD_f +805ff290 Section::AddInitialLayers_caseD_10 +805ff2a8 Section::AddInitialLayers_caseD_11 +805ff2c0 Section::AddInitialLayers_caseD_12 +805ff2d8 Section::AddInitialLayers_caseD_13 +805ff2f0 Section::AddInitialLayers_caseD_14 +805ff308 Section::AddInitialLayers_caseD_15 +805ff320 Section::AddInitialLayers_caseD_16 +805ff32c Section::AddInitialLayers_caseD_17 +805ff338 Section::AddInitialLayers_caseD_18 +805ff344 Section::AddInitialLayers_caseD_19 +805ff350 Section::AddInitialLayers_caseD_1a +805ff35c Section::AddInitialLayers_caseD_1b +805ff368 Section::AddInitialLayers_caseD_1c +805ff374 Section::AddInitialLayers_caseD_1d +805ff380 Section::AddInitialLayers_caseD_1e +805ff398 Section::AddInitialLayers_caseD_1f +805ff3bc Section::AddInitialLayers_caseD_20 +805ff3d4 Section::AddInitialLayers_caseD_21 +805ff3ec Section::AddInitialLayers_caseD_22 +805ff404 Section::AddInitialLayers_caseD_23 +805ff41c Section::AddInitialLayers_caseD_24 +805ff434 Section::AddInitialLayers_caseD_25 +805ff44c Section::AddInitialLayers_caseD_26 +805ff464 Section::AddInitialLayers_caseD_27 +805ff47c Section::AddInitialLayers_caseD_28 +805ff494 Section::AddInitialLayers_caseD_29 +805ff4ac Section::AddInitialLayers_caseD_2a +805ff4c4 Section::AddInitialLayers_caseD_2b +805ff4dc Section::AddInitialLayers_caseD_2c +805ff4f4 Section::AddInitialLayers_caseD_2d +805ff50c Section::AddInitialLayers_caseD_2e +805ff524 Section::AddInitialLayers_caseD_2f +805ff548 Section::AddInitialLayers_caseD_30 +805ff560 Section::AddInitialLayers_caseD_31 +805ff584 Section::AddInitialLayers_caseD_32 +805ff5a8 Section::AddInitialLayers_caseD_33 +805ff5cc Section::AddInitialLayers_caseD_34 +805ff5f0 Section::AddInitialLayers_caseD_35 +805ff5fc Section::AddInitialLayers_caseD_36 +805ff608 Section::AddInitialLayers_caseD_37 +805ff614 Section::AddInitialLayers_caseD_38 +805ff620 Section::AddInitialLayers_caseD_39 +805ff62c Section::AddInitialLayers_caseD_3a +805ff638 Section::AddInitialLayers_caseD_3b +805ff650 Section::AddInitialLayers_caseD_3c +805ff668 Section::AddInitialLayers_caseD_3d +805ff680 Section::AddInitialLayers_caseD_3e +805ff698 Section::AddInitialLayers_caseD_3f +805ff6c8 Section::AddInitialLayers_caseD_40 +805ff6f8 Section::AddInitialLayers_caseD_41 +805ff728 Section::AddInitialLayers_caseD_42 +805ff758 Section::AddInitialLayers_caseD_43 +805ff788 Section::AddInitialLayers_caseD_44 +805ff7a0 Section::AddInitialLayers_caseD_45 +805ff7c4 Section::AddInitialLayers_caseD_46 +805ff7e8 Section::AddInitialLayers_caseD_47 +805ff80c Section::AddInitialLayers_caseD_48 +805ff848 Section::AddInitialLayers_caseD_49 +805ff884 Section::AddInitialLayers_caseD_4a +805ff8c0 Section::AddInitialLayers_caseD_4b +805ff8fc Section::AddInitialLayers_caseD_4c +805ff938 Section::AddInitialLayers_caseD_4d +805ff968 Section::AddInitialLayers_caseD_4e +805ff9a4 Section::AddInitialLayers_caseD_4f +805ff9e0 Section::AddInitialLayers_caseD_50 +805ffa1c Section::AddInitialLayers_caseD_51 +805ffa4c Section::AddInitialLayers_caseD_52 +805ffa7c Section::AddInitialLayers_caseD_53 +805ffaac Section::AddInitialLayers_caseD_54 +805ffadc Section::AddInitialLayers_caseD_55 +805ffb24 Section::AddInitialLayers_caseD_56 +805ffb6c Section::AddInitialLayers_caseD_57 +805ffbb4 Section::AddInitialLayers_caseD_58 +805ffbf0 Section::AddInitialLayers_caseD_59 +805ffc2c Section::AddInitialLayers_caseD_5a +805ffc44 Section::AddInitialLayers_caseD_5b +805ffc8c Section::AddInitialLayers_caseD_5c +805ffcd4 Section::AddInitialLayers_caseD_5d +805ffd1c Section::AddInitialLayers_caseD_5e +805ffd58 Section::AddInitialLayers_caseD_5f +805ffd94 Section::AddInitialLayers_caseD_60 +805ffdd0 Section::AddInitialLayers_caseD_61 +805ffe0c Section::AddInitialLayers_caseD_62 +805ffe48 Section::AddInitialLayers_caseD_63 +805ffe84 Section::AddInitialLayers_caseD_64 +805ffec0 Section::AddInitialLayers_caseD_65 +805ffefc Section::AddInitialLayers_caseD_66 +805fff38 Section::AddInitialLayers_caseD_67 +805fff74 Section::AddInitialLayers_caseD_68 +805fffa4 Section::AddInitialLayers_caseD_69 +805fffd4 Section::AddInitialLayers_caseD_6a +80600004 Section::AddInitialLayers_caseD_6b +80600034 Section::AddInitialLayers_caseD_6c +80600064 Section::AddInitialLayers_caseD_6d +80600094 Section::AddInitialLayers_caseD_6e +806000c4 Section::AddInitialLayers_caseD_6f +806000f4 Section::AddInitialLayers_caseD_70 +80600124 Section::AddInitialLayers_caseD_71 +80600154 Section::AddInitialLayers_caseD_72 +80600184 Section::AddInitialLayers_caseD_73 +806001b4 Section::AddInitialLayers_caseD_74 +806001e4 Section::AddInitialLayers_caseD_75 +80600214 Section::AddInitialLayers_caseD_76 +80600244 Section::AddInitialLayers_caseD_77 +80600274 Section::AddInitialLayers_caseD_78 +8060028c Section::AddInitialLayers_caseD_79 +806002a4 Section::AddInitialLayers_caseD_7a +806002bc Section::AddInitialLayers_caseD_7b +806002d4 Section::AddInitialLayers_caseD_7c +806002ec Section::AddInitialLayers_caseD_7d +80600334 Section::AddInitialLayers_caseD_7e +80600370 Section::AddInitialLayers_caseD_7f +80600394 Section::AddInitialLayers_caseD_80 +806003c4 Section::AddInitialLayers_caseD_81 +806003f4 Section::AddInitialLayers_caseD_82 +80600418 Section::AddInitialLayers_caseD_83 +80600460 Section::AddInitialLayers_caseD_84 +806004a8 Section::AddInitialLayers_caseD_85 +806004cc Section::AddInitialLayers_caseD_86 +806004f0 Section::AddInitialLayers_caseD_87 +80600514 Section::AddInitialLayers_caseD_88 +8060052c Section::AddInitialLayers_caseD_89 +80600544 Section::AddInitialLayers_caseD_8a +8060055c Section::AddInitialLayers_caseD_8b +80600574 Section::AddInitialLayers_caseD_8c +80600598 Section::AddInitialLayers_caseD_8d +806005bc Section::AddInitialLayers_caseD_8e +806005e0 Section::AddInitialLayers_caseD_8f +80600604 Section::AddInitialLayers_caseD_90 +80600634 Section::AddInitialLayers_caseD_91 +80600664 Section::AddInitialLayers_caseD_92 +80600694 Section::AddInitialLayers_caseD_93 +806006d4 Section::GetSceneId +80600880 Section::GetArchiveName +80600ba4 Section::HasBackModel +80600c44 Section::HasDriverController +80600d3c Section::GetPageName +80600d4c Section::GetSectionName +80600d5c 0x80600d5c +80600db4 Section::GetSoundId +80601044 Section::GetGroupId +806011cc 0x806011cc +80601300 Section::GetAudioStreamIdx +8060131c Section::GetAudioStreamIdx_switch +80601320 Section::GetAudioStreamIdx_caseD_0 +80601328 Section::GetAudioStreamIdx_caseD_1 +80601330 Section::GetAudioStreamIdx_caseD_2 +80601338 Section::GetAudioStreamIdx_caseD_5 +80601340 Section::GetAudioStreamIdx_caseD_6 +80601348 Section::GetAudioStreamIdx_caseD_10 +80601350 Section::GetAudioStreamIdx_caseD_4b +80601358 Section::GetAudioStreamIdx_caseD_4c +80601360 Section::GetAudioStreamIdx_caseD_4d +80601368 Section::GetAudioStreamIdx_caseD_4e +80601370 Section::GetAudioStreamIdx_caseD_57 +80601378 Section::GetAudioStreamIdx_caseD_58 +80601380 Section::GetAudioStreamIdx_caseD_5a +80601388 Section::GetAudioStreamIdx_caseD_5b +80601390 Section::GetAudioStreamIdx_caseD_5c +80601398 Section::GetAudioStreamIdx_caseD_5d +806013a0 Section::GetAudioStreamIdx_caseD_5e +806013a8 Section::GetAudioStreamIdx_caseD_5f +806013b0 Section::GetAudioStreamIdx_caseD_60 +806013b8 Section::GetAudioStreamIdx_caseD_65 +806013c0 Section::GetAudioStreamIdx_caseD_66 +806013c8 Section::GetAudioStreamIdx_caseD_69 +806013d0 Section::GetAudioStreamIdx_caseD_6b +806013d8 Section::GetAudioStreamIdx_caseD_6e +806013e0 Section::GetAudioStreamIdx_caseD_70 +806013e8 Section::GetAudioStreamIdx_caseD_72 +806013f0 Section::GetAudioStreamIdx_caseD_74 +806013f8 Section::GetAudioStreamIdx_caseD_75 +80601400 Section::GetAudioStreamIdx_caseD_76 +80601408 Section::GetAudioStreamIdx_caseD_77 +80601410 Section::GetAudioStreamIdx_caseD_78 +80601418 Section::GetAudioStreamIdx_caseD_7a +80601420 Section::GetAudioStreamIdx_caseD_7f +80601428 Section::GetAudioStreamIdx_caseD_80 +80601430 Section::GetAudioStreamIdx_caseD_81 +80601438 Section::GetAudioStreamIdx_caseD_84 +80601440 Section::GetAudioStreamIdx_caseD_85 +80601448 Section::GetAudioStreamIdx_caseD_8a +80601450 Section::GetAudioStreamIdx_caseD_8b +80601458 Section::GetAudioStreamIdx_caseD_8c +80601460 Section::GetAudioStreamIdx_caseD_8d +80601468 Section::GetAudioStreamIdx_caseD_8e +80601470 Section::GetAudioStreamIdx_caseD_8f +80601478 Section::GetAudioStreamIdx_caseD_90 +80601480 Section::GetAudioStreamIdx_caseD_93 +80601488 Section::GetAudioStreamIdx_caseD_95 +80601490 Section::GetAudioStreamIdx_caseD_96 +80601498 Section::GetAudioStreamIdx_caseD_98 +806014a0 Section::GetAudioStreamIdx_caseD_9a +806014a8 Section::GetAudioStreamIdx_caseD_9b +806014b0 Section::GetAudioStreamIdx_caseD_9c +806014b8 Section::GetAudioStreamIdx_caseD_9d +806014c0 Section::GetAudioStreamIdx_caseD_9f +806014c8 Section::GetAudioStreamIdx_caseD_a0 +806014d0 Section::GetAudioStreamIdx_caseD_a1 +806014d8 Section::GetAudioStreamIdx_caseD_a2 +806014e0 Section::GetAudioStreamIdx_caseD_a5 +806014e8 Section::GetAudioStreamIdx_caseD_a8 +806014f0 Section::GetAudioStreamIdx_caseD_b1 +806014f8 Section::GetAudioStreamIdx_caseD_b3 +80601500 Section::GetAudioStreamIdx_caseD_b4 +80601508 Section::GetAudioStreamIdx_caseD_b5 +80601510 Section::GetAudioStreamIdx_caseD_b6 +80601518 Section::GetAudioStreamIdx_caseD_b8 +80601520 Section::GetAudioStreamIdx_caseD_b9 +80601528 Section::GetAudioStreamIdx_caseD_bb +80601530 Section::GetAudioStreamIdx_caseD_c0 +80601538 Section::GetAudioStreamIdx_caseD_ca +80601540 Section::GetAudioStreamIdx_caseD_cc +80601548 Section::GetAudioStreamIdx_caseD_cd +80601558 Pages::RaceMenu::SetNextPage +80601560 Pages::RaceMenu::GetNextPage +80601568 0x80601568 +80601570 0x80601570 +80601578 0x80601578 +80601584 0x80601584 +80601590 0x80601590 +80601598 0x80601598 +80601604 0x80601604 +80601610 Pages::QuitConfirmation::GetMessageBMG +80601618 Pages::QuitConfirmation::IsPausePage +80601620 Pages::QuitConfirmation::GetButtonsBRCTRName +8060162c Pages::QuitConfirmation::GetVariantsIdxArray +80601638 Pages::QuitConfirmation::GetButtonCount +80601640 Pages::QuitConfirmation::__dt +806016ac Pages::QuitConfirmation::GetRuntimeTypeInfo +806016b8 Pages::CheckRankings::GetMessageBMG +806016c0 Pages::CheckRankings::IsPausePage +806016c8 Pages::CheckRankings::GetButtonsBRCTRName +806016d4 Pages::CheckRankings::GetVariantsIdxArray +806016e0 Pages::CheckRankings::GetButtonCount +806016e8 Pages::CheckRankings::__dt +80601754 Pages::CheckRankings::GetRuntimeTypeInfo +80601760 Pages::TTFriendGhostEnd::GetMessageBMG +80601768 Pages::TTFriendGhostEnd::IsPausePage +80601770 Pages::TTFriendGhostEnd::GetButtonsBRCTRName +8060177c Pages::TTFriendGhostEnd::GetVariantsIdxArray +80601788 Pages::TTFriendGhostEnd::GetButtonCount +80601790 Pages::TTFriendGhostEnd::__dt +806017fc Pages::TTFriendGhostEnd::GetRuntimeTypeInfo +80601808 0x80601808 +80601810 0x80601810 +80601818 0x80601818 +80601824 0x80601824 +80601830 0x80601830 +80601838 0x80601838 +806018a4 0x806018a4 +806018b0 0x806018b0 +806018b8 0x806018b8 +806018c0 0x806018c0 +806018cc 0x806018cc +806018d8 0x806018d8 +806018e0 0x806018e0 +8060194c 0x8060194c +80601958 0x80601958 +80601960 0x80601960 +80601968 0x80601968 +80601974 0x80601974 +80601980 0x80601980 +80601988 0x80601988 +806019f4 0x806019f4 +80601a00 0x80601a00 +80601a08 0x80601a08 +80601a10 0x80601a10 +80601a1c 0x80601a1c +80601a28 0x80601a28 +80601a30 0x80601a30 +80601a9c 0x80601a9c +80601aa8 Pages::BattleFinalRaceEnd::GetMessageBMG +80601ab0 Pages::BattleFinalRaceEnd::IsPausePage +80601ab8 Pages::BattleFinalRaceEnd::GetButtonsBRCTRName +80601ac4 Pages::BattleFinalRaceEnd::GetVariantsIdxArray +80601ad0 Pages::BattleFinalRaceEnd::GetButtonCount +80601ad8 Pages::BattleFinalRaceEnd::__dt +80601b44 Pages::BattleFinalRaceEnd::GetRuntimeTypeInfo +80601b50 Pages::BattleEnd::GetMessageBMG +80601b58 Pages::BattleEnd::IsPausePage +80601b60 Pages::BattleEnd::GetButtonsBRCTRName +80601b6c Pages::BattleEnd::GetVariantsIdxArray +80601b78 Pages::BattleEnd::GetButtonCount +80601b80 Pages::BattleEnd::__dt +80601bec Pages::BattleEnd::GetRuntimeTypeInfo +80601bf8 Pages::VSRaceEnd::GetMessageBMG +80601c00 Pages::VSRaceEnd::IsPausePage +80601c08 Pages::VSRaceEnd::GetButtonsBRCTRName +80601c40 Pages::VSRaceEnd::GetVariantsIdxArray +80601c4c Pages::VSRaceEnd::GetButtonCount +80601c7c Pages::VSRaceEnd::__dt +80601ce8 Pages::VSRaceEnd::GetRuntimeTypeInfo +80601cf4 Pages::GPEnd::GetMessageBMG +80601cfc Pages::GPEnd::IsPausePage +80601d04 Pages::GPEnd::GetButtonsBRCTRName +80601d3c Pages::GPEnd::GetVariantsIdxArray +80601d48 Pages::GPEnd::GetButtonCount +80601d78 Pages::GPEnd::__dt +80601de4 Pages::GPEnd::GetRuntimeTypeInfo +80601df0 Pages::TTEnd::GetMessageBMG +80601df8 Pages::TTEnd::IsPausePage +80601e00 Pages::TTEnd::GetButtonsBRCTRName +80601e0c Pages::TTEnd::GetVariantsIdxArray +80601e18 Pages::TTEnd::GetButtonCount +80601e20 Pages::TTEnd::__dt +80601e8c Pages::TTEnd::GetRuntimeTypeInfo +80601e98 0x80601e98 +80601ea0 0x80601ea0 +80601ea8 0x80601ea8 +80601eb4 0x80601eb4 +80601ec0 0x80601ec0 +80601ec8 0x80601ec8 +80601f34 0x80601f34 +80601f40 0x80601f40 +80601f48 0x80601f48 +80601f50 0x80601f50 +80601f5c 0x80601f5c +80601f68 0x80601f68 +80601f70 0x80601f70 +80601fdc 0x80601fdc +80601fe8 0x80601fe8 +80601ff0 0x80601ff0 +80601ff8 0x80601ff8 +80602004 0x80602004 +80602010 0x80602010 +80602018 0x80602018 +80602084 0x80602084 +80602090 Pages::GhostReplayPause::GetMessageBMG +80602098 Pages::GhostReplayPause::IsPausePage +806020a0 Pages::GhostReplayPause::GetButtonsBRCTRName +806020ac Pages::GhostReplayPause::GetVariantsIdxArray +806020b8 Pages::GhostReplayPause::GetButtonCount +806020c0 Pages::GhostReplayPause::__dt +8060212c Pages::GhostReplayPause::GetRuntimeTypeInfo +80602138 Pages::GPReplayPause::GetMessageBMG +80602140 Pages::GPReplayPause::IsPausePage +80602148 Pages::GPReplayPause::GetButtonsBRCTRName +80602180 Pages::GPReplayPause::GetVariantsIdxArray +8060218c Pages::GPReplayPause::GetButtonCount +806021bc Pages::GPReplayPause::__dt +80602228 Pages::GPReplayPause::GetRuntimeTypeInfo +80602234 Pages::TTReplayPause::GetMessageBMG +8060223c Pages::TTReplayPause::IsPausePage +80602244 Pages::TTReplayPause::GetButtonsBRCTRName +80602250 Pages::TTReplayPause::GetVariantsIdxArray +8060225c Pages::TTReplayPause::GetButtonCount +80602264 Pages::TTReplayPause::__dt +806022d0 Pages::TTReplayPause::GetRuntimeTypeInfo +806022dc 0x806022dc +806022e4 0x806022e4 +806022ec 0x806022ec +806022f8 0x806022f8 +80602304 0x80602304 +8060230c 0x8060230c +80602378 0x80602378 +80602384 Pages::BattlePause::GetMessageBMG +8060238c Pages::BattlePause::IsPausePage +80602394 Pages::BattlePause::GetButtonsBRCTRName +806023bc Pages::BattlePause::GetVariantsIdxArray +806023c8 Pages::BattlePause::GetButtonCount +806023d0 Pages::BattlePause::__dt +8060243c Pages::BattlePause::GetRuntimeTypeInfo +80602448 Pages::VSPause::GetMessageBMG +80602450 Pages::VSPause::IsPausePage +80602458 Pages::VSPause::GetButtonsBRCTRName +80602480 Pages::VSPause::GetVariantsIdxArray +8060248c Pages::VSPause::GetButtonCount +80602494 Pages::VSPause::__dt +80602500 Pages::VSPause::GetRuntimeTypeInfo +8060250c Pages::GPPause::GetMessageBMG +80602514 Pages::GPPause::IsPausePage +8060251c Pages::GPPause::GetButtonsBRCTRName +80602528 Pages::GPPause::GetVariantsIdxArray +80602534 Pages::GPPause::GetButtonCount +8060253c Pages::GPPause::__dt +806025a8 Pages::GPPause::GetRuntimeTypeInfo +806025b4 Pages::TTPause::GetMessageBMG +806025bc Pages::TTPause::IsPausePage +806025c4 Pages::TTPause::GetButtonsBRCTRName +806025d0 Pages::TTPause::GetVariantsIdxArray +806025dc Pages::TTPause::GetButtonCount +806025e4 Pages::TTPause::__dt +80602650 Pages::TTPause::GetRuntimeTypeInfo +8060265c Pages::RaceHUD::GetNextPage +80602664 Pages::LiveBattleViewHUD::GetCtrlRaceNameBalloonCount +8060266c Pages::LiveBattleViewHUD::GetEnabledCtrlRaceBases +80602674 Pages::LiveBattleViewHUD::GetPausePageId +8060267c Pages::LiveBattleViewHUD::__dt +806026e8 Pages::LiveBattleViewHUD::GetRuntimeTypeInfo +806026f4 Pages::LiveViewHUD::GetCtrlRaceNameBalloonCount +806026fc Pages::LiveViewHUD::GetEnabledCtrlRaceBases +80602704 Pages::LiveViewHUD::GetPausePageId +8060270c Pages::LiveViewHUD::__dt +80602778 Pages::LiveViewHUD::GetRuntimeTypeInfo +80602784 Pages::WiFiFriendTeamVSHUD::GetCtrlRaceNameBalloonCount +8060278c Pages::WiFiFriendTeamVSHUD::GetEnabledCtrlRaceBases +80602794 Pages::WiFiFriendTeamVSHUD::GetPausePageId +8060279c Pages::WiFiFriendTeamVSHUD::__dt +80602808 Pages::WiFiFriendVSHUD::GetRuntimeTypeInfo +80602814 Pages::WiFiFriendVSHUD::GetCtrlRaceNameBalloonCount +8060281c Pages::WiFiFriendVSHUD::GetEnabledCtrlRaceBases +80602824 Pages::WiFiFriendVSHUD::GetPausePageId +8060282c Pages::WiFiFriendVSHUD::__dt +80602898 Pages::WiFiFriendVSHUD::GetRuntimeTypeInfo +806028a4 Pages::WifiVSMultiHUD::GetCtrlRaceNameBalloonCount +806028ac Pages::WifiVSMultiHUD::GetEnabledCtrlRaceBases +806028b4 Pages::WifiVSMultiHUD::GetPausePageId +806028bc Pages::WifiVSMultiHUD::__dt +80602928 Pages::WifiVSMultiHUD::GetRuntimeTypeInfo +80602934 Pages::WifiVSHUD::GetCtrlRaceNameBalloonCount +8060293c Pages::WifiVSHUD::GetEnabledCtrlRaceBases +80602944 Pages::WifiVSHUD::GetPausePageId +8060294c Pages::WifiVSHUD::__dt +806029b8 Pages::WifiVSHUD::GetRuntimeTypeInfo +806029c4 Pages::BattleMultiHUD::GetCtrlRaceNameBalloonCount +806029cc Pages::BattleMultiHUD::GetEnabledCtrlRaceBases +806029d4 Pages::BattleMultiHUD::GetPausePageId +80602a0c Pages::BattleMultiHUD::__dt +80602a78 Pages::BattleMultiHUD::GetRuntimeTypeInfo +80602a84 Pages::BattleHUD::GetCtrlRaceNameBalloonCount +80602a8c Pages::BattleHUD::GetEnabledCtrlRaceBases +80602a94 Pages::BattleHUD::GetPausePageId +80602acc Pages::BattleHUD::__dt +80602b38 Pages::BattleHUD::GetRuntimeTypeInfo +80602b44 Pages::VSMultiHUD::GetCtrlRaceNameBalloonCount +80602b4c Pages::VSMultiHUD::GetEnabledCtrlRaceBases +80602b54 Pages::VSMultiHUD::GetPausePageId +80602b5c Pages::VSMultiHUD::__dt +80602bc8 Pages::VSMultiHUD::GetRuntimeTypeInfo +80602bd4 Pages::VSHUD::GetCtrlRaceNameBalloonCount +80602bdc Pages::VSHUD::GetEnabledCtrlRaceBases +80602be4 Pages::VSHUD::GetPausePageId +80602bec Pages::VSHUD::__dt +80602c58 Pages::VSHUD::GetRuntimeTypeInfo +80602c64 Pages::GPHUD::GetCtrlRaceNameBalloonCount +80602c6c Pages::GPHUD::GetEnabledCtrlRaceBases +80602c74 Pages::GPHUD::GetPausePageId +80602c7c Pages::GPHUD::__dt +80602ce8 Pages::GPHUD::GetRuntimeTypeInfo +80602cf4 Pages::TTHUD::GetCtrlRaceNameBalloonCount +80602cfc Pages::TTHUD::GetEnabledCtrlRaceBases +80602d04 Pages::TTHUD::GetPausePageId +80602d50 Pages::TTHUD::__dt +80602dbc Pages::TTHUD::GetRuntimeTypeInfo +80602dc8 Pages::GhostRaceHUD::GetCtrlRaceNameBalloonCount +80602dd0 Pages::GhostRaceHUD::GetEnabledCtrlRaceBases +80602dd8 Pages::GhostRaceHUD::GetPausePageId +80602e18 Pages::GhostRaceHUD::__dt +80602e84 Pages::GhostRaceHUD::GetRuntimeTypeInfo +80602e90 Pages::RaceHUD::GetCtrlRaceNameBalloonCount +80602e98 Pages::GPReplayHUD::GetEnabledCtrlRaceBases +80602ea0 Pages::GPReplayHUD::GetPausePageId +80602ea8 Pages::GPReplayHUD::__dt +80602f14 Pages::GPReplayHUD::GetRuntimeTypeInfo +80602f20 TriggerPtmf +80602f50 TriggerPtmf +80602f80 TriggerPtmf +80602fb0 TriggerPtmf +80602fe0 TriggerPtmf +80603010 TriggerPtmf +80603040 TriggerPtmf +80603070 TriggerPtmf +806030a0 TriggerPtmf +806030d0 TriggerPtmf +80603100 TriggerPtmf +80603130 TriggerPtmf +80603160 TriggerPtmf +80603190 TriggerPtmf +806031c0 TriggerPtmf +806031f0 TriggerPtmf +80603220 TriggerPtmf +80603250 TriggerPtmf +80603280 TriggerPtmf +806032b0 TriggerPtmf +806032e0 TriggerPtmf +80603310 TriggerPtmf +80603340 TriggerPtmf +80603370 TriggerPtmf +806033a0 TriggerPtmf +806033d0 TriggerPtmf +80603400 TriggerPtmf +80603430 TriggerPtmf +80603460 TriggerPtmf +80603490 TriggerPtmf +806034c0 TriggerPtmf +806034f0 TriggerPtmf +80603520 TriggerPtmf +80603550 TriggerPtmf +80603580 TriggerPtmf +806035b0 TriggerPtmf +806035e0 TriggerPtmf +80603610 TriggerPtmf +80603640 TriggerPtmf +80603670 TriggerPtmf +806036a0 TriggerPtmf +806036d0 TriggerPtmf +80603700 TriggerPtmf +80603730 TriggerPtmf +80603760 TriggerPtmf +80603790 TriggerPtmf +806037c0 TriggerPtmf +806037f0 TriggerPtmf +80603820 TriggerPtmf +80603850 TriggerPtmf +80603880 TriggerPtmf +806038b0 TriggerPtmf +806038e0 TriggerPtmf +80603910 TriggerPtmf +80603940 TriggerPtmf +80603970 TriggerPtmf +806039a0 TriggerPtmf +806039d0 TriggerPtmf +80603a00 TriggerPtmf +80603a30 TriggerPtmf +80603a60 TriggerPtmf +80603a90 TriggerPtmf +80603ac0 TriggerPtmf +80603af0 TriggerPtmf +80603b20 TriggerPtmf +80603b50 TriggerPtmf +80603b80 TriggerPtmf +80603bb0 SectionMgr::CreateSystemPages +80603ccc SectionMgr::GetSectionPriority +80603ddc SectionMgr::CreateInstance +80603e14 SectionMgr::DestroyInstance +80603e8c SectionMgr::__ct +80603f10 SectionMgr::__dt +80603f90 SectionMgr::Init +80604108 SectionMgr::GetBootSectionSceneId +80604124 SectionMgr::LoadSection +806041e8 SectionMgr::EnterSection +80604304 SectionMgr::ExitSection +80604620 0x80604620 +80604628 SectionMgr::RaceUpdate +80604674 SectionMgr::Update +806049a4 SectionMgr::MenuUpdate +806049f8 SectionMgr::UnkUpdate +80604b94 SectionMgr::Pause +80604b9c SectionMgr::Resume +80604ba4 SectionMgr::SetNextSection +80604c30 SectionMgr::RequestSceneChange +80604c94 SectionMgr::RequestSceneReinit +80604cd8 SectionMgr::HandleHomeAction +80604d74 SectionMgr::RequestGoToWiiMenu +80604ddc SectionMgr::RequestPowerOff +80604e44 SectionMgr::GetNextSectionArchiveName +80604e4c SectionMgr::NextSectionHasBackModel +80604e54 SectionMgr::NextSectionHasDriverController +80604e5c SectionMgr::UpdateStatusBitfield +80604f70 SectionMgr::UpdateDVDStatus +80605020 SheetSelectControl::GetClassName +8060502c SheetSelectControl::__ct +806051e4 SheetSelectControl::__dt +80605288 SheetSelectControl::Load +8060534c SheetSelectControl::Func_0x38 +80605350 SheetSelectControl::SetRightArrowHandler +80605358 SheetSelectControl::SetLeftArrowHandler +80605360 SheetSelectControl::SetEnabledHudSlots +806053cc SheetSelectControl::Toggle +80605450 SheetSelectControl::Init +806054b4 SheetSelectControl::Update +806054b8 SheetSelectControl::HandleRightArrowSelect +8060553c SheetSelectControl::AfterRightScroll +80605540 SheetSelectControl::HandleLeftArrowSelect +806055c4 SheetSelectControl::AfterLeftScroll +806055c8 SheetSelectControl::SheetSelectButton::GetClassName +806055d8 SheetSelectControl::SheetSelectButton::__ct +806056cc SheetSelectControl::SheetSelectButton::__dt +80605734 SheetSelectControl::SheetSelectButton::Load +80605960 SheetSelectControl::SheetSelectButton::Init +80605b4c SheetSelectControl::SheetSelectButton::Update +80605d94 SheetSelectControl::SheetSelectButton::SetEnabledHudSlots +80605db0 SheetSelectControl::SheetSelectButton::Toggle +80605dd4 SheetSelectControl::SheetSelectButton::GetParentControl +80605e70 SheetSelectControl::SheetSelectButton::HandleSelect +8060612c SheetSelectControl::SheetSelectButton::HandleDeselect +80606314 SheetSelectControl::SheetSelectButton::Select +806064ac SheetSelectControl::SheetSelectButton::SetPositionAnim +806065dc SheetSelectControl::GetArrowAnimationType +806065e4 SheetSelectControlScaleFade::GetClassName +806065f4 SheetSelectControlScaleFade::GetArrowAnimationType +806065fc 0x806065fc +806066a4 SheetSelectControlScaleFade::GetRuntimeTypeInfo +806066b0 SheetSelectControl::GetRuntimeTypeInfo +806066bc SheetSelectControl::SheetSelectButton::GetRuntimeTypeInfo +806066c8 SheetSelectControl::SheetSelectButton::TriggerPtmf +806066f8 SheetSelect_cpp_sinit_ +80606724 TabControl::GetClassName +80606730 TabControl::__ct +8060678c TabControl::__dt +80606804 TabControl::Load +80606980 TabControl::OnLoadingEnd +80606984 TabControl::SetOnClickHandler +8060698c TabControl::SetEnabledHudSlots +80606a08 TabControl::SelectInitial +80606aa8 TabControl::SelectButtonNoPtmf +80606b20 TabControl::Init +80606bf4 TabControl::Update +80606bf8 TabControl::SelectButton +80606c98 TabControl::OptionButton::GetClassName +80606ca8 TabControl::OptionButton::__ct +80606d9c TabControl::OptionButton::__dt +80606e04 TabControl::OptionButton::Load +80606fd0 TabControl::OptionButton::Init +8060717c TabControl::OptionButton::Update +80607328 TabControl::OptionButton::SetEnabledHudSlots +80607330 TabControl::OptionButton::GetParentControl +80607430 TabControl::OptionButton::SetInitialState +80607490 TabControl::OptionButton::ChangeButtonState +806075e8 TabControl::OptionButton::HandleSelect +806076dc TabControl::OptionButton::HandleDeselect +806078c4 TabControl::OptionButton::HandleClick +80607a80 TabControl::Func_0x40 +80607a84 TabControl::GetRuntimeTypeInfo +80607a90 TabControl::OptionButton::GetRuntimeTypeInfo +80607a9c TabControl::OptionButton::TriggerPtmf +80607acc TabControl_cpp_sinit_ +80607ae8 Pages::GhostSelectSupporting::__ct +80607b2c Pages::GhostSelectSupporting::__dt +80607b94 Pages::GhostSelectSupporting::OnInit +80607c00 Pages::GhostSelectSupporting::OnActivate +80607da4 Pages::GhostSelectSupporting::BeforeEntranceAnimations +80607da8 Pages::GhostSelectSupporting::BeforeExitAnimations +80607dac Pages::GhostSelectSupporting::AfterControlUpdate +80607ec0 Pages::GhostSelectSupporting::OnResume +80608028 Pages::GhostSelectSupporting::InitGhostList +8060824c Pages::GhostSelect::__ct +8060848c Pages::GhostSelect::__dt +80608568 Pages::GhostSelect::OnInit +80608830 Pages::GhostSelect::OnActivate +80608994 Pages::GhostSelect::BeforeEntranceAnimations +806089cc Pages::GhostSelect::OnResume +80608e04 Pages::GhostSelect::OnRightArrowPress +80608f04 Pages::GhostSelect::OnLeftArrowPress +80609000 Pages::GhostSelect::OnChallengeGhostPress +80609020 Pages::GhostSelect::OnWatchReplayPress +80609040 Pages::GhostSelect::OnSoloTTPress +80609060 0x80609060 +806090a4 Pages::GhostSelect::OnBackPress +806090bc 0x806090bc +80609118 Pages::GhostSelect::GetNextPage +80609120 Pages::GhostSelect::GetRuntimeTypeInfo +8060912c Pages::GhostSelectSupporting::GetNextPage +80609134 Pages::GhostSelectSupporting::GetRuntimeTypeInfo +80609140 TriggerPtmf +80609170 TriggerPtmf +806091a0 TriggerPtmf +806091d0 GhostSelectPage_cpp_sinit_ +806091ec TitleImage::GetClassName +806091f8 TitleImage::__ct +80609234 TitleImage::__dt +8060928c TitleImage::Load +8060932c TitleImage::InitSelf +80609364 0x80609364 +80609414 0x80609414 +8060944c 0x8060944c +806094fc 0x806094fc +80609534 TitleImage::ChangeImage +80609668 Pages::Title::__ct +806096ec CtrlMenuPressStart::__dt +80609744 Pages::Title::__dt +806097cc Pages::Title::OnInit +806099c0 Pages::Title::OnDispose +806099c4 Pages::Title::OnActivate +80609a44 Pages::Title::BeforeEntranceAnimations +80609af4 Pages::Title::AfterEntranceAnimations +80609b40 Pages::Title::BeforeExitAnimations +80609bf0 Pages::Title::AfterExitAnimations +80609c28 Pages::Title::AfterControlUpdate +80609d84 Pages::Title::OnResume +80609d90 Pages::Title::PrepareDemo +8060a174 Pages::BlurryTitle::__ct +8060a1c0 Pages::BlurryTitle::__dt +8060a234 Pages::BlurryTitle::OnInit +8060a2f8 Pages::BlurryTitle::OnActivate +8060a450 Pages::BlurryTitle::BeforeEntranceAnimations +8060a454 TitleMovieControl::GetClassName +8060a464 TitleMovieControl::__ct +8060a4a0 TitleMovieControl::__dt +8060a4f8 TitleMovieControl::Load +8060a598 TitleMovieControl::InitSelf +8060a5d0 TitleMovieControl::OnUpdate +8060a5d4 0x8060a5d4 +8060a684 0x8060a684 +8060a734 0x8060a734 +8060a768 Pages::TitleMovie::__ct +8060a7cc Pages::TitleMovie::__dt +8060a844 Pages::TitleMovie::OnInit +8060a958 0x8060a958 +8060aa24 Pages::TitleMovie::AfterExitAnimations +8060aa68 Pages::TitleMovie::OnDeactivate +8060aa7c Pages::TitleMovie::BeforeControlUpdate +8060abac Pages::TitleMovie::AfterControlUpdate +8060ac8c Pages::BlinkingPressA::__ct +8060acf0 Pages::BlinkingPressA::__dt +8060ad68 Pages::BlinkingPressA::OnInit +8060adf0 Pages::BlinkingPressA::OnActivate +8060ae48 Pages::BlinkingPressA::OnDeactivate +8060ae5c Pages::BlinkingPressA::AfterControlUpdate +8060af48 Pages::BlinkingPressA::GetRuntimeTypeInfo +8060af54 Pages::TitleMovie::GetRuntimeTypeInfo +8060af60 TitleMovieControl::GetRuntimeTypeInfo +8060af6c Pages::BlurryTitle::GetRuntimeTypeInfo +8060af78 Pages::Title::GetNextPage +8060af80 Pages::Title::GetRuntimeTypeInfo +8060af8c TitleImage::GetRuntimeTypeInfo +8060af98 Title_cpp_sinit_ +8060afcc UIAnimator::__ct +8060afe4 UIAnimator::__dt +8060b044 UIAnimator::SetLayout +8060b050 UIAnimator::Init +8060b0b4 UIAnimator::InitAnimationGroup +8060b11c Animation::__ct +8060b140 UIAnimator::AppendGroup +8060b230 UIAnimator::LoadNewAnimation +8060b2f4 UIAnimator::LoadAnimation +8060b39c UIAnimator::Update +8060b400 UIAnimator::GetAnimationGroupById +8060b410 UIAnimator::GetAnimationGroupById +8060b420 0x8060b420 +8060b424 AnimationGroup::__ct +8060b48c AnimationGroup::__dt +8060b4fc AnimationGroup::PlayAnimationAtFrame +8060b678 AnimationGroup::PlayAnimationAtPercent +8060b700 AnimationGroup::PlayAnimationAtFrameAndDisable +8060b734 AnimationGroup::PlayAnimationAtPercentAndDisable +8060b7c4 AnimationGroup::Update +8060b9bc 0x8060b9bc +8060ba4c UIControl::__ct +8060bb40 0x8060bb40 +8060bb80 UIControl::__dt +8060bbdc UIControl::8063cffc +8060bbe4 UIControl::Init +8060bc24 UIControl::Update +8060bc64 UIControl::Draw +8060bc98 UIControl::SetPosition +8060bcc0 UIControl::PlayAnimationSound +8060bd74 UIControl::SetPositionAnim +8060be48 UIControl::InitControlGroup +8060be58 UIControl::AddControl +8060be64 UIControl::GetAnimationDelay +8060bf78 UIControl::SetParentControlGroup +8060bf84 UIControl::SetSoundIds +8060bf90 UIControl::GetClassName +8060bfa0 0x8060bfa0 +8060bfac UIControl::PositionFromBasePosition +8060c130 UIControl::CalculatePosition +8060c1e8 UIControl::vf_0x30 +8060c228 UIControl::8063d648 +8060c32c UIControl::PlaySound +8060c344 UIControl::StopSound +8060c350 UIControl::HoldSound +8060c368 LayoutUIControl::GetClassName +8060c378 LayoutUIControl::__ct +8060c4a0 LayoutUIControl::__dt +8060c534 LayoutUIControl::LoadLayout +8060c5a0 LayoutUIControl::LoadPictureLayout +8060c5e0 LayoutUIControl::SetRootPane +8060c6a0 LayoutUIControl::Init +8060c6e0 LayoutUIControl::Update +8060c764 LayoutUIControl::Draw +8060c89c LayoutUIControl::SetTextBoxMessage +8060c994 LayoutUIControl::SetMessage +8060c9d4 LayoutUIControl::MessageRequester::Calc +8060cacc LayoutUIControl::ResetTextBoxMsg +8060cba8 LayoutUIControl::ResetMsg +8060cbe0 LayoutUIControl::MessageResetter::Calc +8060ccd0 LayoutUIControl::SetPicturePane +8060cf08 LayoutUIControl::PicturePaneExists +8060cfbc LayoutUIControl::SetMiiPane +8060d12c LayoutUIControl::SetPaneVisibility +8060d16c LayoutUIControl::CropMovie(Rect) +8060d1a4 LayoutUIControl::CropMovie(4floats) +8060d1fc LayoutUIControl::vf_0x30 +8060d244 LayoutUIControlScaleFade::GetClassName +8060d254 LayoutUIControlScaleFade::__ct +8060d388 LayoutUIControlScaleFade::__dt +8060d420 LayoutUIControlScaleFade::SetPositionAnim +8060d504 LayoutUIControlScaleFade::GetRuntimeTypeInfo +8060d510 LayoutUIControlcpp_sinit_ +8060d534 UpDownControl::GetClassName +8060d540 UpDownControl::__ct +8060d73c UpDownControl::__dt +8060d7bc UpDownControl::Load +8060dbfc UpDownControl::OnLoadingEnd +8060dc00 UpDownControl::SetOnChangeHandler +8060dc08 UpDownControl::SetOnClickHandler +8060dc10 UpDownControl::SetOnElementSelectHandler +8060dc18 UpDownControl::SetOnDeselectHandler +8060dc20 0x8060dc20 +8060dc8c 0x8060dc8c +8060dca0 UpDownControl::SelectInitial(count+initial) +8060dcc0 UpDownControl::SelectInitial(initial) +8060dcd8 0x8060dcd8 +8060dd40 UpDownControl::SetPlayerBitfield +8060dd4c UpDownControl::Init +8060de88 UpDownControl::Update +8060e274 UpDownControl::HandleSelect +8060e3a4 UpDownControl::HandleDeselect +8060e4a8 UpDownControl::HandleButtonSelect +8060e4c0 UpDownControl::HandleButtonDeselect +8060e4d8 UpDownControl::HandleClick +8060e744 UpDownControl::HandleRightPress +8060e870 UpDownControl::HandleLeftPress +8060e990 UpDownControl::UpDownButton::GetClassName +8060e9a0 UpDownControl::UpDownButton::__ct +8060e9dc UpDownControl::UpDownButton::__dt +8060ea34 UpDownControl::UpDownButton::Load +8060eaf8 UpDownControl::UpDownButton::Init +8060eb90 UpDownControl::UpDownButton::Update +8060ec7c UpDownControl::UpDownButton::GetParentControl +8060ed7c UpDownControl::UpDownButton::ToggleSelect +8060ef40 0x8060ef40 +8060efa4 0x8060efa4 +8060f0e8 0x8060f0e8 +8060f190 0x8060f190 +8060f198 0x8060f198 +8060f1a0 TextUpDownValueControl::GetClassName +8060f1b0 TextUpDownValueControl::__ct +8060f21c TextUpDownValueControl::__dt +8060f290 TextUpDownValueControl::Load +8060f3b4 TextUpDownValueControl::SetOnTextChangeHandler +8060f3bc TextUpDownValueControl::Init +8060f4dc TextUpDownValueControl::Update +8060f580 0x8060f580 +8060f680 TextUpDownValueControl::InitText +8060f748 TextUpDownValueControl::OnSelect +8060f8bc TextUpDownValueControl::SetMessage +8060f8ec TextUpDownValueControl::SetMessageAnimated +8060f9dc TextUpDownValueControl::OnClick +8060fa48 TextUpDownValueControl::IsOKStop +8060fae0 TextUpDownValueControl::Get3rdAnimStartFrame +8060fb54 TextUpDownValueControl::SetBorderColours +8060fc08 TextUpDownValueControl::SetColor_BaseColours +8060fcb0 TextUpDownValueControl::TextControl::GetClassName +8060fcc0 TextUpDownValueControl::TextControl::__ct +8060fcfc TextUpDownValueControl::TextControl::__dt +8060fd54 TextUpDownValueControl::TextControl::Load +8060fdc8 TextUpDownValueControl::TextControl::InitSelf +8060fe78 0x8060fe78 +8060fed8 TextUpDownValueControl::TextControl::ToggleState +8061003c UpDownControlOld::1 +8061004c UpDownControlOld::2 +80610204 UpDownControlOld::3 +8061026c UpDownControlOld::4 +806105b4 UpDownControlOld::5 +806105bc UpDownControlOld::6 +806106a0 UpDownControlOld::7 +8061086c UpDownControlOld::8 +80610880 0x80610880 +80610888 UpDownControlOld::9 +80610968 UpDownControlOld::10 +8061096c UpDownControlOld::11 +80610b6c UpDownControlOld::12 +80610b70 UpDownControlOld::13 +80610c50 UpDownControlOld::14 +80610e98 UpDownControlOld::15 +80610f50 UpDownControlOld::16 +80611004 UpDownControlOld::17 +80611154 UpDownControlOld::18 +8061120c UpDownControlOld::19 +80611210 UpDownControlOld::20 +806112c4 UpDownControlOld::21 +806112c8 TextUpDownControlOld::1 +806112d8 TextUpDownControlOld::2 +8061149c TextUpDownControlOld::3 +80611508 TextUpDownControlOld::4 +8061153c 0x8061153c +80611544 0x80611544 +8061154c 0x8061154c +80611550 0x80611550 +8061155c 0x8061155c +80611568 TextUpDownValueControl::GetTextControl +8061156c TextUpDownValueControl::GetRuntimeTypeInfo +80611578 TextUpDownValueControl::TextControl::GetRuntimeTypeInfo +80611584 UpDownControl::Func_0x40 +80611588 UpDownControl::GetRuntimeTypeInfo +80611594 UpDownControl::UpDownButton::GetRuntimeTypeInfo +806115a0 TriggerPtmf +806115d0 TriggerPtmf +80611600 UpDownControl_cpp_sinit_ +80611630 TextUpDownValueControl::SetColor_BaseColours(UpDownDisplayedText) +80611638 TextUpDownValueControl::SetBorderColours(UpDownDisplayedText) +80611640 TextUpDownValueControl::Get3rdAnimStartFrame(UpDownDisplayedText) +80611648 TextUpDownValueControl::Animate(UpDownDisplayedText) +80611650 TextUpDownValueControl::OnClick(UpDownDisplayedText) +80611658 TextUpDownValueControl::SetMessageAnimated(UpDownDisplayedText) +80611660 TextUpDownValueControl::SetMessage(UpDownDisplayedText) +80611668 TextUpDownValueControl::OnSelect(UpDownDisplayedText) +80611670 TextUpDownValueControl::InitText(UpDownDisplayedText) +80611678 TextUpDownValueControl::GetTextControl(UpDownDisplayedText) +80611680 VoteControl::GetClassName +8061168c VoteControl::__ct +806116c8 VoteControl::__dt +80611720 VoteControl::Load +806117cc VoteControl::InitSelf +80611880 VoteControl::OnUpdate +80611884 VoteControl::Fill +806119f4 VoteControl::AnimateSelect +80611a48 VoteControl::AnimateDeselect +80611a80 VoteControl::AnimateChose +80611adc VoteControl::AnimateFadeOut +80611b38 VoteControl::IsAnimationShow +80611b70 Pages::Vote::__ct +80611c9c Pages::Vote::__dt +80611d48 Pages::Vote::OnInit +80611de8 Pages::Vote::OnInit_switch +80611dec Pages::Vote::OnInit_case58 +80611df8 Pages::Vote::OnInit_case59 +80611e00 Pages::Vote::OnInit_case5a +80611fa8 Pages::Vote::OnDispose +80611fac Pages::Vote::BeforeEntranceAnimations +806123c8 Pages::Vote::BeforeControlUpdate +80612904 Pages::Vote::BeforeControlUpdate_switch +80612908 Pages::Vote::BeforeControlUpdate_case58 +80612910 Pages::Vote::BeforeControlUpdate_case59 +80612918 Pages::Vote::BeforeControlUpdate_case5e +80612920 Pages::Vote::BeforeControlUpdate_case5f +80612928 Pages::Vote::BeforeControlUpdate_case60 +80612930 Pages::Vote::BeforeControlUpdate_case61 +80612938 Pages::Vote::BeforeControlUpdate_case62 +80612940 Pages::Vote::BeforeControlUpdate_case63 +80612948 Pages::Vote::BeforeControlUpdate_case64 +80612950 Pages::Vote::BeforeControlUpdate_case65 +80612958 Pages::Vote::BeforeControlUpdate_case66 +80612960 Pages::Vote::BeforeControlUpdate_case67 +80612964 Pages::Vote::BeforeControlUpdate_caseDefault +80612a78 Pages::Vote::BeforeExitAnimations +80612af8 Pages::Vote::GetNextPage +80612b28 Pages::Vote::SetVotedCourseId +80612b58 Pages::Vote::SetCourseButtonId_switch +80612b5c Pages::Vote::SetCourseButtonId_case58 +80612b64 Pages::Vote::SetCourseButtonId_case59 +80612b68 Pages::Vote::SetCourseButtonId_case5a +80612b6c Pages::Vote::FillVoteControl +80612dc8 Pages::Vote::StartRoulette +80613010 Pages::Vote::FillVotesCounter +80613188 Pages::Vote::OnMessageBoxClick +8061322c Pages::Vote::GetRuntimeTypeInfo +80613238 VoteControl::GetRuntimeTypeInfo +80613244 TriggerPtmf +80613274 VotePage_cpp_sinit_ +80613298 0x80613298 +806132dc 0x806132dc +80613344 0x80613344 +806133a0 0x806133a0 +80613498 Page::EndExitState +8061349c 0x8061349c +806134a0 0x806134a0 +806135c8 0x806135c8 +806135d8 0x806135d8 +80613730 0x80613730 +806137d0 0x806137d0 +80613938 0x80613938 +80613a20 0x80613a20 +80613c58 0x80613c58 +80613cf0 0x80613cf0 +80613d58 0x80613d58 +80613f28 0x80613f28 +80613f34 0x80613f34 +80613f3c 0x80613f3c +80613f48 0x80613f48 +80613f78 0x80613f78 +80613fa8 0x80613fa8 +80613fc4 Pages::WFCConnect::__ct +80614040 Pages::WFCConnect::__dt +806140a8 Pages::WFCConnect::OnInit +80614114 Pages::WFCConnect::OnActivate +806145c4 Pages::WFCConnect::BeforeEntranceAnimations +806145c8 Pages::WFCConnect::AfterEntranceAnimations +806145e8 Pages::WFCConnect::BeforeExitAnimations +806145ec Pages::WFCConnect::AfterExitAnimations +806145f0 Pages::WFCConnect::OnDeactivate +806146a0 Pages::WFCConnect::AfterControlUpdate +80614cd8 Pages::WFCConnect::OnResume +806150b4 Pages::WFCConnect::GetNextPage +80615188 Pages::WFCConnect::IsHomeMenuWorking +806151cc Pages::WFCConnect::SetText +806154dc Pages::WFCConnect::GetTitleBMGId +806155a8 Pages::WFCConnect::OnDisconnect +806156bc Pages::WFCDataStatement::__ct +806157d4 Pages::WFCDataStatement::__dt +80615874 Pages::WFCDataStatement::OnInit +80615a10 Pages::WFCDataStatement::OnActivate +80615bb8 Pages::WFCDataStatement::SetType +80615bf4 Pages::WFCDataStatement::OnButtonClick +80615c70 Pages::WFCDataStatement::OnBackPress +80615c98 Pages::WFCAllowData::__ct +80615e00 Pages::WFCAllowData::__dt +80615eac Pages::WFCAllowData::OnInit +806160a4 Pages::WFCAllowData::OnActivate +80616214 Pages::WFCAllowData::OnResume +806162ec Pages::WFCAllowData::OnButtonClick +8061648c Pages::WFCAllowData::OnBackButtonClick +806164a4 Pages::WFCAllowData::OnBackPress +806165d8 Pages::WFCDisconnect::__ct +80616654 Pages::WFCDisconnect::__dt +806166bc Pages::WFCDisconnect::OnInit +80616718 Pages::WFCDisconnect::OnActivate +80616914 Pages::WFCDisconnect::BeforeEntranceAnimations +80616918 Pages::WFCDisconnect::BeforeExitAnimations +8061691c Pages::WFCDisconnect::OnDeactivate +806169cc Pages::WFCDisconnect::OnResume +806169dc Pages::WFCDisconnect::OnYesNoYesClick +80616abc Pages::WFCDisconnect::GetRuntimeTypeInfo +80616ac8 Pages::WFCAllowData::GetRuntimeTypeInfo +80616ad4 Pages::WFCDataStatement::GetRuntimeTypeInfo +80616ae0 Pages::WFCConnect::GetRuntimeTypeInfo +80616aec TriggerPtmf +80616b1c TriggerPtmf +80616b4c TriggerPtmf +80616b7c TriggerPtmf +80616bac TriggerPtmf +80616bdc TriggerPtmf +80616c0c TriggerPtmf +80616c3c WFCConnectPage_cpp_sinit_ +80616c60 Pages::DisconnectMgr::__ct +80616cac Pages::DisconnectMgr::__dt +80616d14 Pages::DisconnectMgr::OnInit +80616d80 Pages::DisconnectMgr::OnUpdate +80617178 Pages::DisconnectError::__ct +80617204 Pages::DisconnectError::__dt +80617284 Pages::DisconnectError::OnInit +80617380 Pages::DisconnectError::OnActivate +80617508 Pages::DisconnectError::AfterControlUpdate +80617550 Pages::DisconnectError::BeforeEntranceAnimations +8061755c Pages::DisconnectError::IsHomeMenuWorking +80617594 Pages::DisconnectError::GetErrorBMGId +806177c8 Pages::DisconnectError::OnClick +8061783c Pages::DisconnectError::GetRuntimeTypeInfo +80617848 Pages::DisconnectMgr::GetRuntimeTypeInfo +80617854 TriggerPtmf +80617884 DisconnectPage_cpp_sinit_ +806178a0 Pages::LiveViewWaiting::__ct +806178fc Pages::LiveViewWaiting::__dt +80617988 Pages::LiveViewWaiting::OnInit +80617a88 Pages::LiveViewWaiting::AfterControlUpdate +80617ac8 Pages::LiveViewWaiting::GetNextPage +80617b14 Pages::LiveViewWaiting::BeforeExitAnimations +80617b60 Pages::LiveViewWaiting::BeforeEntranceAnimations +80617bb8 Pages::LiveViewWaiting::AfterExitAnimations +80617bc4 Pages::LiveViewWaiting::GetRuntimeTypeInfo +80617bd0 LiveViewWaitingPage_cpp_sinit_ +80617be4 Pages::Approve2PWFC::__ct +80617c60 Pages::Approve2PWFC::__dt +80617cc8 Pages::Approve2PWFC::OnInit +80617d34 Pages::Approve2PWFC::OnActivate +80617e48 Pages::Approve2PWFC::BeforeEntranceAnimations +80617e4c Pages::Approve2PWFC::BeforeExitAnimations +80617e50 Pages::Approve2PWFC::OnResume +80617f10 Pages::Approve2PWFC::GetNextPage +80617f28 Pages::Approve2PWFC::OnApprove +80617fa0 FriendsStatusButton::GetClassName +80617fac FriendsStatusButton::__ct +80617fe8 FriendsStatusButton::__dt +80618040 FriendsStatusButton::Load +80618130 FriendsStatusButton::InitSelf +8061813c FriendsStatusButton::OnUpdate +806181ac FriendsStatusButton::OnSelect +806181b0 FriendsStatusButton::OnDeselect +806181b4 FriendsStatusButton::UpdateFriendStatus +8061832c Pages::WFCMainMenu::__ct +8061853c Pages::WFCMainMenu::__dt +806185fc Pages::WFCMainMenu::OnInit +8061897c Pages::WFCMainMenu::OnActivate +806189d4 Pages::WFCMainMenu::OnWorldwideButtonClick +80618ab0 Pages::WFCMainMenu::OnRegionalButtonClick +80618b8c Pages::WFCMainMenu::OnFriendsButtonClick +80618bd0 Pages::WFCMainMenu::OnBackButtonClick +80618c38 Pages::WFCMainMenu::OnButtonSelect +80618ca4 Pages::WFCMainMenu::OnBackPress +80618cc4 Pages::WFCModeSelect::__ct +80618e5c Pages::WFCModeSelect::__dt +80618f0c Pages::WFCModeSelect::OnInit +806191e4 Pages::WFCModeSelect::OnActivate +806192fc Pages::WFCModeSelect::OnModeButtonClick +80619404 Pages::WFCModeSelect::OnBackButtonClick +80619448 Pages::WFCModeSelect::OnModeButtonSelect +8061949c Pages::WFCModeSelect::OnBackPress +806194b4 Pages::WFCFriendsMenu::__ct +806196c4 Pages::WFCFriendsMenu::__dt +80619784 Pages::WFCFriendsMenu::OnInit +80619c04 Pages::WFCFriendsMenu::OnActivate +80619ce4 Pages::WFCFriendsMenu::OnDeactivate +80619d8c Pages::WFCFriendsMenu::OnRosterButtonClick +80619ed4 Pages::WFCFriendsMenu::OnRegisterButtonClick +8061a01c Pages::WFCFriendsMenu::OnCreateRoomClick +8061a1e0 Pages::WFCFriendsMenu::OnBackButtonClick +8061a28c Pages::WFCFriendsMenu::OnButtonSelect +8061a2f8 Pages::WFCFriendsMenu::OnBackPress +8061a34c Pages::WFCFriendsMenu::GetNextPage +8061a354 Pages::WFCFriendsMenu::GetRuntimeTypeInfo +8061a360 Pages::WFCModeSelect::GetNextPage +8061a368 Pages::WFCModeSelect::GetRuntimeTypeInfo +8061a374 Pages::WFCMainMenu::GetNextPage +8061a37c Pages::WFCMainMenu::GetRuntimeTypeInfo +8061a388 FriendsStatusButton::GetRuntimeTypeInfo +8061a394 Pages::Approve2PWFC::GetRuntimeTypeInfo +8061a3a0 TriggerPtmf +8061a3d0 TriggerPtmf +8061a400 TriggerPtmf +8061a430 TriggerPtmf +8061a460 TriggerPtmf +8061a490 TriggerPtmf +8061a4c0 TriggerPtmf +8061a4f0 WFCMainMenuPage__cpp__sinit +8061a520 Pages::WWRaceEndCountDown::__ct +8061a574 Pages::WWRaceEndCountDown::__dt +8061a5f4 Pages::WWRaceEndCountDown::OnInit +8061a680 Pages::WWRaceEndCountDown::OnActivate +8061a7ec Pages::WWRaceEndCountDown::BeforeControlUpdate +8061a838 FriendStatusButtonRaceAfter::GetClassName +8061a848 0x8061a848 +8061a854 FriendStatusButtonRaceAfter::__ct +8061a890 FriendStatusButtonRaceAfter::__dt +8061a8e8 FriendStatusButtonRaceAfter::8064dbfc +8061aa24 FriendStatusButtonRaceAfter::OnInit +8061aa28 FriendStatusButtonRaceAfter::OnUpdate +8061aa88 FriendStatusButtonRaceAfter::UpdateStatus +8061abd4 Pages::WWRaceEnd::__ct +8061ad00 Pages::WWRaceEnd::__dt +8061ad9c Pages::WWRaceEnd::OnInit +8061b0c4 Pages::WWRaceEnd::OnActivate +8061b1c8 Pages::WWRaceEnd::BeforeEntranceAnimations +8061b1dc Pages::WWRaceEnd::AfterControlUpdate +8061b37c Pages::WWRaceEnd::OnContinueRaceClick +8061b4f8 Pages::WWRaceEnd::OnFriendButtonClick +8061b5d8 Pages::WWRaceEnd::OnQuitClick +8061b6bc Pages::WWRaceEndQuit::__ct +8061b780 Pages::WWRaceEndQuit::__dt +8061b80c Pages::WWRaceEndQuit::OnInit +8061b9a0 Pages::WWRaceEndQuit::OnDispose +8061ba20 Pages::WWRaceEndQuit::OnActivate +8061bae4 Pages::WWRaceEndQuit::OnDeactivate +8061baf0 Pages::WWRaceEndQuit::AfterControlUpdate +8061bc90 Pages::WWRaceEndQuit::OnYesButtonClick +8061be10 Pages::WWRaceEndQuit::OnNoButtonClick +8061be54 Pages::WWRaceEndWait::__ct +8061bea0 Pages::WWRaceEndWait::__dt +8061bf14 Pages::WWRaceEndWait::OnInit +8061bf58 Pages::WWRaceEndWait::OnInit_switch +8061bf5c Pages::WWRaceEndWait::OnInit_case_68 +8061bf78 Pages::WWRaceEndWait::OnInit_case_69 +8061c00c Pages::WWRaceEndWait::OnActivate +8061c060 Pages::WWRaceEndWait::AfterControlUpdate +8061c110 Pages::WWRaceEndWait::AfterControlUpdate_switch +8061c114 Pages::WWRaceEndWait::AfterControlUpdate_case_68 +8061c11c Pages::WWRaceEndWait::AfterControlUpdate_case_69 +8061c124 Pages::WWRaceEndWait::AfterControlUpdate_case_6c +8061c12c Pages::WWRaceEndWait::AfterControlUpdate_case_6d +8061c2a4 Pages::WWRaceEndWait::AfterControlUpdate_switch2D +8061c2a8 Pages::WWRaceEndWait::AfterControlUpdate_case2_70 +8061c2b0 Pages::WWRaceEndWait::AfterControlUpdate_case2_71 +8061c2b8 Pages::WWRaceEndWait::AfterControlUpdate_case2_72 +8061c2c0 Pages::WWRaceEndWait::AfterControlUpdate_case2_73 +8061c2c8 Pages::WWRaceEndWait::AfterControlUpdate_case2_74 +8061c2d0 Pages::WWRaceEndWait::AfterControlUpdate_case2_75 +8061c2d8 Pages::WWRaceEndWait::AfterControlUpdate_case2_76 +8061c2e0 Pages::WWRaceEndWait::AfterControlUpdate_case2_77 +8061c348 0x8061c348 +8061c5cc 0x8061c5cc +8061c5d0 0x8061c5d0 +8061c628 0x8061c628 +8061c6c4 Pages::DisableHomeButton::__ct +8061c708 Pages::DisableHomeButton::__dt +8061c770 Pages::DisableHomeButton::OnInit +8061c7cc Pages::DisableHomeButton::IsHomeMenuWorking +8061c7d4 Pages::DisableHomeButton::GetRuntimeTypeInfo +8061c7e0 Pages::RaceEndWait::GetRuntimeTypeInfo +8061c7ec Pages::WWRaceEndQuit::GetNextPage +8061c7f4 Pages::WWRaceEndQuit::GetRuntimeTypeInfo +8061c800 Pages::WWRaceEnd::GetNextPage +8061c808 Pages::WWRaceEnd::GetRuntimeTypeInfo +8061c814 FriendStatusButtonRaceAfter::GetRuntimeTypeInfo +8061c820 Pages::WWRaceEndCountDown::GetNextPage +8061c828 Pages::WWRaceEndCountDown::GetRuntimeTypeInfo +8061c834 TriggerPtmf +8061c864 TriggerPtmf +8061c894 WWRaceSupportingPages_cpp_sinit_ +8061c8c8 Pages::SELECTStageMgr::__ct +8061c95c Pages::SELECTStageMgr::__dt +8061c9e8 Pages::SELECTStageMgr::OnInit +8061ca40 Pages::SELECTStageMgr::OnInit_switch +8061ca44 Pages::SELECTStageMgr::OnInit_case58 +8061ca50 Pages::SELECTStageMgr::OnInit_case60 +8061ca5c Pages::SELECTStageMgr::OnInit_case59 +8061ca68 Pages::SELECTStageMgr::OnInit_case62 +8061ca70 Pages::SELECTStageMgr::OnInit_case5a +8061cb1c Pages::SELECTStageMgr::OnDispose +8061cb20 Pages::SELECTStageMgr::OnActivate +8061cbf4 Pages::SELECTStageMgr::OnActivate_Pages::SELECTStageMgr::OnActivate_switch +8061cbf8 Pages::SELECTStageMgr::OnActivate_case58 +8061cc18 Pages::SELECTStageMgr::OnActivate_case59 +8061cc34 Pages::SELECTStageMgr::OnActivate_case5a +8061cd04 Pages::SELECTStageMgr::OnActivate_switch2 +8061cd08 Pages::SELECTStageMgr::OnActivate_2case58 +8061cec4 Pages::SELECTStageMgr::OnActivate_2case59 +8061cee4 Pages::SELECTStageMgr::OnActivate_2case5a +8061cf00 Pages::SELECTStageMgr::OnDeactivate +8061cf04 Pages::SELECTStageMgr::BeforeControlUpdate +8061cf60 Pages::SELECTStageMgr::AfterControlUpdate +8061d48c Pages::SELECTStageMgr::OnResume +8061d698 Pages::SELECTStageMgr::OnResume_Pages::SELECTStageMgr::OnResume_switch +8061d69c Pages::SELECTStageMgr::OnResume_case58 +8061d6a4 Pages::SELECTStageMgr::OnResume_case59 +8061d6a8 Pages::SELECTStageMgr::OnResume_case5a +8061d7e0 Pages::SELECTStageMgr::IsPublicBattle +8061d810 Pages::SELECTStageMgr::IsPublicBattle_switch +8061d814 Pages::SELECTStageMgr::IsPublicBattle_case58 +8061d81c Pages::SELECTStageMgr::IsPublicBattle_case59 +8061d824 Pages::SELECTStageMgr::IsPublicBattle_case5a +8061d82c Pages::SELECTStageMgr::GetEngineClass +8061d87c Pages::SELECTStageMgr::GetBattleType +8061d8cc Pages::SELECTStageMgr::GetInstructionBmgId +8061d8fc Pages::SELECTStageMgr::GetInstructionBmgId_switch +8061d900 Pages::SELECTStageMgr::GetInstructionBmgId_case58 +8061d970 Pages::SELECTStageMgr::GetInstructionBmgId_case59 +8061d9d0 Pages::SELECTStageMgr::GetInstructionBmgId_case60 +8061da40 Pages::SELECTStageMgr::GetInstructionBmgId_case61 +8061dab0 Pages::SELECTStageMgr::GetInstructionBmgId_case62 +8061dab8 Pages::SELECTStageMgr::GetInstructionBmgId_case63 +8061dac0 Pages::SELECTStageMgr::GetInstructionBmgId_case5a +8061dac8 Pages::SELECTStageMgr::GetPlayerId +8061db10 Pages::SELECTStageMgr::PrepareRace +8061dbd0 Pages::SELECTStageMgr::PrepareRace_switch +8061dbd4 Pages::SELECTStageMgr::PrepareRace_case58 +8061dbf4 Pages::SELECTStageMgr::PrepareRace_case60 +8061dc14 Pages::SELECTStageMgr::PrepareRace_case61 +8061dc34 Pages::SELECTStageMgr::PrepareRace_case59 +8061dc54 Pages::SELECTStageMgr::PrepareRace_case62 +8061dc70 Pages::SELECTStageMgr::PrepareRace_case5a +8061dca0 Pages::SELECTStageMgr::PrepareRace_case5a_switch +8061dca4 Pages::SELECTStageMgr::PrepareRace_2case58 +8061dd68 Pages::SELECTStageMgr::PrepareRace_2case59 +8061dde0 Pages::SELECTStageMgr::PrepareRace_2case62 +8061de0c Pages::SELECTStageMgr::PrepareRace_2case63 +8061de38 Pages::SELECTStageMgr::PrepareRace_2case5a +8061e2b8 Pages::SELECTStageMgr::UpdateOnlineParams +8061e49c Pages::SELECTStageMgr::OnDisconnect +8061e540 Pages::SELECTStageMgr::SetModeTypes +8061e584 Pages::SELECTStageMgr::SetModeTypes_switch +8061e588 Pages::SELECTStageMgr::SetModeTypes_case58 +8061e59c Pages::SELECTStageMgr::SetModeTypes_case59 +8061e5b0 Pages::SELECTStageMgr::SetModeTypes_case60 +8061e5ec Pages::SELECTStageMgr::SetModeTypes_case62 +8061e5f8 Pages::SELECTStageMgr::SetModeTypes_case63 +8061e600 Pages::SELECTStageMgr::SetModeTypes_loop +8061e770 0x8061e770 +8061e77c 0x8061e77c +8061e7bc 0x8061e7bc +8061e894 Pages::SELECTStageMgr::IsHomeMenuWorking +8061e89c Pages::SELECTStageMgr::GetRuntimeTypeInfo +8061e8a8 Pages::SELECTStageMgr::TriggerPtmf +8061e8d8 0x8061e8d8 +8061e8ec Pages::YesNo::__ct +8061e990 Pages::YesNo::__dt +8061ea1c Pages::YesNo::OnInit +8061eab0 Pages::YesNo::OnActivate +8061eb50 Pages::YesNo::AfterControlUpdate +8061eb8c Pages::YesNo::Reset +8061ebe8 Pages::YesNo::SetMessageBoxMsg +8061ebf0 Pages::YesNo::PrepareButton +8061ec64 Pages::YesNo::OnButtonClick +8061ecec Pages::YesNo::SelectInitialButton +8061ed60 Pages::YesNoPopUp::__ct +8061ee38 Pages::YesNoPopUp::__dt +8061eee8 Pages::YesNoPopUp::OnInit +8061f134 Pages::YesNoPopUp::BeforeEntranceAnimations +8061f178 Pages::YesNoPopUp::AfterExitAnimations +8061f1bc Pages::YesNoPopUp::Container::GetClassName +8061f1cc Pages::YesNoPopUp::Container::__ct +8061f208 Pages::YesNoPopUp::Container::__dt +8061f260 Pages::YesNoPopUp::Container::Load +8061f2d4 Pages::YesNoPopUp::Reset +8061f330 Pages::YesNoPopUp::Container::SetPositionAnim +8061f368 Pages::YesNoFull::__ct +8061f438 Pages::YesNoFull::__dt +8061f4dc Pages::YesNoFull::OnInit +8061f6bc Pages::YesNoFull::Reset +8061f728 Pages::YesNoFull::SetTitleMsg +8061f730 Pages::YesNoFull::BeforeEntranceAnimations +8061f74c Pages::YesNoFull::AfterExitAnimations +8061f768 Pages::YesNoFull::GetRuntimeTypeInfo +8061f774 Pages::YesNoPopUp::GetRuntimeTypeInfo +8061f780 Pages::YesNoPopUp::Container::GetRuntimeTypeInfo +8061f78c Pages::YesNo::GetRuntimeTypeInfo +8061f798 Pages::YesNo::TriggerPtmf +8061f7c8 YesNoPagecpp_sinit_ +8061f7f4 NdevArgsExtractor::__ct +8061f7f8 NdevArgsExtractor::__dt +8061f838 NdevArgsExtractor::ExtractAllArgs +80620580 NdevArgsExtractor::ExtractSection +80620678 NdevArgsExtractor::ExtractLicense +80620768 NdevArgsExtractor::ExtractPad +806208cc NdevArgsExtractor::ExtractGhostType +806209bc NdevArgsExtractor::ExtractCourseId +80620aac NdevArgsExtractor::ExtractGhostLicense +80620bd4 NdevArgsExtractor::ExtractFriendIdx +80620c8c NdevArgsExtractor::ExtractW +80620d80 NdevArgsExtractor::ExtractD +80620e80 NdevArgsExtractor::ExtractInt +80620f54 NdevArgsExtractor::ExtractU64 +80621034 Pages::AwardFade::GetPlayersVolumeMgr +80621040 Pages::AwardFade::__ct +806210c4 Pages::AwardFade::__dt +80621138 Pages::AwardFade::OnInit +80621258 Pages::AwardFade::OnActivate +806212a4 Pages::AwardFade::BeforeEntranceAnimations +806212a8 Pages::AwardFade::BeforeExitAnimations +806212ac Pages::AwardFade::AfterControlUpdate +806213f4 Pages::AwardFade::HandleClick +806214a0 AwardDemoCongratulations::GetClassName +806214b0 AwardDemoCongratulations::__ct +806214ec AwardDemoCongratulations::__dt +80621544 AwardDemoCongratulations::Load +8062161c AwardDemoCongratulations::InitSelf +80621654 0x80621654 +8062168c 0x8062168c +806216c4 AwardDemoResultItem::GetClassName +806216d4 AwardDemoResultItem::__ct +80621710 AwardDemoResultItem::__dt +80621768 AwardDemoResultItem::Load +80621914 AwardDemoResultItem::InitSelf +8062194c AwardDemoResultItem::SetValues +80621db8 Pages::AwardResults::__ct +80621e84 Pages::AwardResults::__dt +80621f2c Pages::AwardResults::OnInit +8062239c Pages::AwardResults::OnActivate +806223bc Pages::AwardResults::BeforeEntranceAnimations +806223dc Pages::AwardResults::AfterControlUpdate +806224b8 Pages::AwardResults::HandleClick +80622658 Pages::AwardResults::InitConfig +80622758 Pages::AwardResults::SetWinOrLose +8062291c 0x8062291c +806229a0 Pages::AwardResults::PrepareCongratulations +80622b40 Pages::AwardResults::PrepareResultItems +80622cac Pages::AwardResults::PrepareCup +80622d38 Pages::AwardResults::PrepareCup_switch +80622d3c Pages::AwardResults::PrepareCup_caseD_0 +80622d44 Pages::AwardResults::PrepareCup_caseD_1 +80622d4c Pages::AwardResults::PrepareCup_caseD_2 +80622d54 Pages::AwardResults::PrepareCup_caseD_3 +80622d5c Pages::AwardResults::PrepareCup_caseD_4 +80622d64 Pages::AwardResults::PrepareCup_caseD_5 +80622d6c Pages::AwardResults::PrepareCup_caseD_6 +80622d74 Pages::AwardResults::PrepareCup_caseD_7 +80622dcc Pages::AwardResults::InitRank +80623048 Pages::AwardResults::GetRuntimeTypeInfo +80623054 AwardDemoResultItem::GetRuntimeTypeInfo +80623060 AwardDemoCongratulations::GetRuntimeTypeInfo +8062306c 0x8062306c +80623074 Pages::AwardFade::GetRuntimeTypeInfo +80623080 TriggerPtmf +806230b0 TriggerPtmf +806230e0 AwardPages_cpp_sinit_ +8062310c Pages::AddMKChannel::__ct +80623294 Pages::AddMKChannel::__dt +80623340 Pages::AddMKChannel::OnInit +80623570 Pages::AddMKChannel::OnDispose +80623574 Pages::AddMKChannel::OnActivate +80623578 Pages::AddMKChannel::OnDeactivate +8062357c Pages::AddMKChannel::GetNextPage +80623594 Pages::AddMKChannel::OnAddButtonClick +806237b0 Pages::AddMKChannel::OnCancelButtonClick +8062383c Pages::AddMKChannel::OnBackButtonClick +80623878 Pages::AddMKChannel::OnBackPress +80623888 Pages::MKChannelExplanation::__ct +806239a0 Pages::MKChannelExplanation::__dt +80623a40 Pages::MKChannelExplanation::OnInit +80623bdc Pages::MKChannelExplanation::OnActivate +80623be8 Pages::MKChannelExplanation::GetNextPage +80623c20 Pages::MKChannelExplanation::OnButtonClick +80623ccc Pages::MKChannelExplanation::OnBackPress +80623d14 0x80623d14 +80623d20 0x80623d20 +80623d2c 0x80623d2c +80623d5c 0x80623d5c +80623d8c 0x80623d8c +80623dbc 0x80623dbc +80623dec 0x80623dec +80623e08 Pages::BatteryMgr::__ct +80623e4c Pages::BatteryMgr::__dt +80623eb4 Pages::BatteryMgr::OnInit +80623f10 Pages::BatteryMgr::OnActivate +80623f5c Pages::BatteryMgr::BeforeEntranceAnimations +80623f60 0x80623f60 +80623f64 Pages::BatteryMgr::BeforeExitAnimations +80623f68 Pages::BatteryMgr::AfterControlUpdate +80623ff0 Pages::LowBattery::__ct +80624084 Pages::LowBattery::__dt +80624110 Pages::LowBattery::OnInit +80624238 Pages::LowBattery::OnActivate +8062429c Pages::LowBattery::AfterControlUpdate +806242d4 Pages::LowBattery::OnClick +806242e8 Pages::LowBattery::BeforeEntranceAnimations +8062432c Pages::LowBattery::AfterExitAnimations +80624370 Pages::LowBattery::GetRuntimeTypeInfo +8062437c Pages::BatteryMgr::GetNextPage +80624384 Pages::BatteryMgr::GetRuntimeTypeInfo +80624390 TriggerPtmf +806243c0 LowBatteryPage_cpp_sinit_ +806243dc 0x806243dc +80624490 0x80624490 +806244f8 0x806244f8 +80624564 0x80624564 +8062495c Page::EndActivationState +80624960 0x80624960 +80624980 Page::EndExitState +80624984 0x80624984 +80624af4 0x80624af4 +80624ffc 0x80624ffc +80625200 0x80625200 +80625320 0x80625320 +80625340 0x80625340 +8062539c 0x8062539c +806253a4 0x806253a4 +806253b0 TriggerPtmf +806253e0 TriggerPtmf +80625410 0x80625410 +80625424 0x80625424 +80625430 0x80625430 +8062546c StaffRollControl::__dt +806254c4 StaffRollControl::Load +80625578 StaffRollControl::InitSelf +806255b0 StaffRollControl::AppearAnimated +806255e8 StaffRollControl::DisappearAnimated +80625620 Pages::StaffRoll::__ct +806256bc StaffRollText::__ct +80625718 StaffRollText::__dt +8062578c Pages::StaffRoll::__dt +8062580c Pages::StaffRoll::OnInit +80625d4c Pages::StaffRoll::OnActivate +80625d9c Pages::StaffRoll::BeforeEntranceAnimations +80625da0 Pages::StaffRoll::BeforeExitAnimations +80625da4 Pages::StaffRoll::AfterControlUpdate +80626120 Pages::StaffRoll::SetHasNotStarted +80626138 Pages::StaffRoll::OnClick +80626144 EndingMovieControl::GetClassName +80626154 EndingMovieControl::__ct +80626190 EndingMovieControl::__dt +806261e8 EndingMovieControl::Load +806262e0 EndingMovieControl::InitSelf +80626318 EndingMovieControl::FadeIn +80626350 EndingMovieControl::FadeOut +80626388 EndingMovieControl::IsCurrentAnimation1Or2 +806263d0 Pages::EndingMovie::__ct +8062646c Pages::EndingMovie::__dt +806264ec Pages::EndingMovie::OnInit +806266f0 0x806266f0 +8062675c Pages::EndingMovie::AfterEntranceAnimations +80626760 Pages::EndingMovie::AfterControlUpdate +80626890 Pages::EndingMovie::OnMovieActivate +8062695c Pages::CreditsCongrats::__ct +806269f0 Pages::CreditsCongrats::__dt +80626aa0 Pages::CreditsCongrats::OnInit +80626c8c Pages::CreditsCongrats::OnActivate +80626e08 Pages::CreditsCongrats::AfterControlUpdate +806271a8 Pages::CreditsCongrats::OnResumt +80627750 Pages::CreditsCongrats::OnClick +8062775c Pages::CreditsCongrats::Publish +8062788c Pages::CreditsCongrats::AfterPublish +8062798c Pages::CreditsCongrats::AfterPublishMsg +80627a8c Pages::CreditsCongrats::AfterDontPostTooMany +80627b8c Pages::CreditsCongrats::HandlePublishError +80627c5c Pages::CreditsCongrats::HandlePublishError_switch +80627c60 Pages::CreditsCongrats::HandlePublishError_caseD_1 +80627c68 Pages::CreditsCongrats::HandlePublishError_caseD_2 +80627c70 Pages::CreditsCongrats::HandlePublishError_caseD_3 +80627c78 Pages::CreditsCongrats::HandlePublishError_caseD_4 +80627c80 Pages::CreditsCongrats::HandlePublishError_caseD_5 +80627c88 Pages::CreditsCongrats::HandlePublishError_caseD_6 +80627c90 Pages::CreditsCongrats::HandlePublishError_caseD_8 +80627c98 Pages::CreditsCongrats::HandlePublishError_caseD_9 +80627ca0 Pages::CreditsCongrats::HandlePublishError_caseD_7 +80627cb4 Pages::CreditsCongrats::HandlePublishError_caseD_0 +80627d28 0x80627d28 +80627df4 Pages::CreditsCongrats::GetRuntimeTypeInfo +80627e00 Pages::EndingMovie::GetRuntimeTypeInfo +80627e0c EndingMovieControl::GetRuntimeTypeInfo +80627e18 Pages::StaffRoll::GetRuntimeTypeInfo +80627e24 StaffRollControl::GetRuntimeTypeInfo +80627e30 TriggerPtmf +80627e60 TriggerPtmf +80627e90 TriggerPtmf +80627ec0 Ending_cpp_sinit_ +80627ef0 HandleDisplayControl::GetClassName +80627efc HandleDisplayControl::__ct +80627f38 HandleDisplayControl::__dt +80627f90 HandleDisplayControl::Load +80628010 0x80628010 +80628074 HandleDisplayControl::InitSelf +80628120 Pages::WheelOnlyComp::__ct +8062818c Pages::WheelOnlyComp::__dt +80628210 Pages::WheelOnlyComp::OnInit +80628338 Pages::WheelOnlyComp::OnActivate +8062834c Pages::WheelOnlyComp::AfterEntranceAnimations +80628360 Pages::WheelOnlyComp::AfterControlUpdate +806284b0 Pages::WheelOnlyComp::GetRuntimeTypeInfo +806284bc HandleDisplayControl::GetRuntimeTypeInfo +806284c8 WheelOnlyComp_cpp_sinit_ +806284ec Pages::FriendRoom::__ct +806286d4 Pages::FriendRoom::__dt +80628780 Pages::FriendRoom::OnInit +806289b8 Pages::FriendRoom::OnActivate +80628a70 Pages::FriendRoom::OnDeactivate +80628a7c Pages::FriendRoom::AfterControlUpdate +8062920c Pages::FriendRoom::OnResume +806294b4 Pages::FriendRoom::SetStatus +806294bc 0x806294bc +806294f8 Pages::FriendRoom::OnMessagesButtonClick +806295e0 Pages::FriendRoom::OnStartButtonClick +806296c8 Pages::FriendRoom::OnAddFriendsButtonClick +806296d4 Pages::FriendRoom::OnBackButtonClick +80629814 Pages::FriendRoom::OnButtonSelect +80629880 Pages::FriendRoom::OnBackPress +806299c0 FriendMatchingPlayer::GetClassName +806299d0 FriendMatchingPlayer::__ct +80629a44 FriendMatchingPlayer::__dt +80629a9c FriendMatchingPlayer::Load +80629b88 FriendMatchingPlayer::InitSelf +80629c74 FriendMatchingPlayer::OnUpdate +80629df0 0x80629df0 +80629f08 0x80629f08 +80629f6c 0x80629f6c +8062a01c FriendMatchingPlayer::OnMessageSent +8062a0ac Pages::FriendRoomManager::__ct +8062a140 Pages::FriendRoomManager::__dt +8062a1e8 Pages::FriendRoomManager::OnInit +8062a324 Pages::FriendRoomManager::OnActivate +8062a494 Pages::FriendRoomManager::AfterEntranceAnimations +8062a59c Pages::FriendRoomManager::BeforeExitAnimations +8062a668 Pages::FriendRoomManager::OnDeactivate +8062a6b4 Pages::FriendRoomManager::AfterControlUpdate +8062b1c4 AvoidController_UseMinimumAvoidance +8062b1d4 0x8062b1d4 +8062b224 Pages::FriendRoomManager::GetMessageBmg +8062b318 Pages::FriendRoomManager::SetToSendPacket +8062b39c 0x8062b39c +8062b3a4 0x8062b3a4 +8062b3cc 0x8062b3cc +8062b3dc 0x8062b3dc +8062b3f0 0x8062b3f0 +8062b3f4 0x8062b3f4 +8062b434 0x8062b434 +8062b4ac 0x8062b4ac +8062b778 0x8062b778 +8062b7ec 0x8062b7ec +8062b894 0x8062b894 +8062b8bc 0x8062b8bc +8062b8cc 0x8062b8cc +8062bba8 0x8062bba8 +8062bc2c MessageSelectControl::GetClassName +8062bc3c MessageSelectControl::__ct +8062bc98 MessageSelectControl::__dt +8062bd0c MessageSelectControl::Load +8062be60 MessageSelectControl::InitSelf +8062be64 MessageSelectControl::OnUpdate +8062bf5c MessageSelectControl::SetPositionAnim +8062bf94 MessageSelectControl::Activate +8062c02c MessageSelectControl::Deactivate +8062c09c MessageSelectControl::ChangeToPage +8062c0fc MessageSelectControl::ChangeFromPage +8062c194 MessageSelectControl::IsActivated +8062c1cc MessageSelectControl::IsDeactivated +8062c200 MessageSelectControl::SetButtonBmg +8062c238 MessageSelectControl::SetOnClickHandler +8062c298 MessageSelectControl::SelectInitialButton +8062c2a8 MessageSelectControl::GetSelectedButtonId +8062c308 Pages::FriendRoomMessages::__ct +8062c550 Pages::FriendRoomMessages::__dt +8062c620 Pages::FriendRoomMessages::OnInit +8062c894 Pages::FriendRoomMessages::OnActivate +8062cc38 Pages::FriendRoomMessages::OnDeactivate +8062ccd4 Pages::FriendRoomMessages::BeforeControlUpdate +8062cd5c 0x8062cd5c +8062cfb8 Pages::FriendRoomMessages::End +8062cfd0 Pages::FriendRoomMessages::UpdateMessage +8062d18c Pages::FriendRoomMessages::OnMessageButtonClick +8062d294 Pages::FriendRoomMessages::OnModeButtonClick +8062d39c Pages::FriendRoomMessages::OnAddFriendsButtonClick +8062d5e4 Pages::FriendRoomMessages::OnRightArrowPress +8062d6f0 Pages::FriendRoomMessages::OnLeftArrowPress +8062d7f8 Pages::FriendRoomMessages::OnBackButtonClick +8062d834 Pages::FriendRoomMessages::OnBackPress +8062d84c Pages::FriendRoomWaiting::__ct +8062d8a8 Pages::FriendRoomWaiting::__dt +8062d934 Pages::FriendRoomWaiting::OnInit +8062dac8 Pages::FriendRoomWaiting::OnActivate +8062dc40 Pages::FriendRoomWaiting::OnDeactivate +8062dc50 Pages::FriendRoomWaiting::BeforeEntranceAnimations +8062dcdc Pages::FriendRoomWaiting::BeforeExitAnimations +8062dce0 Pages::FriendRoomWaiting::AfterControlUpdate +8062e1e4 Pages::FriendRoomWaiting::OnResume +8062e5a4 0x8062e5a4 +8062e5ac Pages::FriendRoomWaiting::StartRoom +8062ed54 0x8062ed54 +8062ed5c Pages::FriendRoomWaiting::IsHomeMenuWorking +8062ed64 Pages::FriendRoomWaiting::GetRuntimeTypeInfo +8062ed70 Pages::FriendRoomMessages::GetRuntimeTypeInfo +8062ed7c MessageSelectControl::GetRuntimeTypeInfo +8062ed88 Pages::FriendRoomManager::GetRuntimeTypeInfo +8062ed94 FriendMatchingPlayer::GetRuntimeTypeInfo +8062eda0 Pages::FriendRoom::GetRuntimeTypeInfo +8062edac TriggerPtmf +8062eddc TriggerPtmf +8062ee0c TriggerPtmf +8062ee3c TriggerPtmf +8062ee6c TriggerPtmf +8062ee9c TriggerPtmf +8062eecc FriendRoomPage_cpp_sinit_ +8062ef00 Pages::GhostRaceExplanation::__ct +8062f018 Pages::GhostRaceExplanation::__dt +8062f0b8 Pages::GhostRaceExplanation::OnInit +8062f234 Pages::GhostRaceExplanation::OnActivate +8062f3bc Pages::GhostRaceExplanation::GetNextPage +8062f40c Pages::GhostRaceExplanation::OnButtonClick +8062f498 Pages::GhostRaceExplanation::OnBackPress +8062f4e4 Pages::GhostRaceMgr::__ct +8062f568 Pages::GhostRaceMgr::__dt +8062f5d0 Pages::GhostRaceMgr::OnInit +8062f6e0 Pages::GhostRaceMgr::OnActivate +8062f800 Pages::GhostRaceMgr::BeforeEntranceAnimations +8062f804 Pages::GhostRaceMgr::BeforeExitAnimations +8062f808 Pages::GhostRaceMgr::AfterControlUpdate +8062fa50 Pages::GhostRaceMgr::OnResume +8062fe88 Pages::GhostRaceMgr::DownloadGhost +80630604 0x80630604 +80630714 0x80630714 +80630854 Pages::GhostRaceMgr::PrepareRace +80630a4c Pages::GhostRaceMgr::OnErrorBoxClick +80630a94 Pages::GhostRaceInfo::__ct +80630bac Pages::GhostRaceInfo::__dt +80630c4c Pages::GhostRaceInfo::OnInit +80630dc4 Pages::GhostRaceInfo::OnActivate +80630dd0 Pages::GhostRaceInfo::UpdateGhostInfo +80630e28 Pages::GhostRaceInfo::OnButtonClick +80630f54 Pages::GhostRaceInfo::OnBackPress +8063100c Pages::GhostRaceInfo::GetRuntimeTypeInfo +80631018 Pages::GhostRaceMgr::GetNextPage +80631020 Pages::GhostRaceMgr::GetRuntimeTypeInfo +8063102c Pages::GhostRaceExplanation::GetRuntimeTypeInfo +80631038 TriggerPtmf +80631068 TriggerPtmf +80631098 TriggerPtmf +806310c8 TriggerPtmf +806310f8 TriggerPtmf +80631128 GhostRacePage_cpp_sinit_ +80631148 0x80631148 +80631194 0x80631194 +806311fc 0x806311fc +80631268 0x80631268 +80631320 Page::EndActivationState +80631324 0x80631324 +806313d4 0x806313d4 +80631450 0x80631450 +80631818 0x80631818 +80631a38 0x80631a38 +80631a44 0x80631a44 +80631a58 0x80631a58 +80631a5c 0x80631a5c +80631a9c 0x80631a9c +80631af0 LicenseControl::GetClassName +80631afc LicenseButton::GetClassName +80631b0c Pages::LicenseSelect::__ct +80631d44 LicenseButton::__ct +80631d80 LicenseButton::__dt +80631dd8 Pages::LicenseSelect::__dt +80631e90 Pages::LicenseSelect::OnInit +8063216c Pages::LicenseSelect::SetControlMii +80632a4c Pages::LicenseSelect::OnActivate +80632a70 Pages::LicenseSelect::OnResume +80632a74 Pages::LicenseSelect::AfterControlUpdate +80632a78 Pages::LicenseSelect::OnLicenseButtonClick +80632e1c Pages::LicenseSelect::OnOptionsButtonClick +80632f64 Pages::LicenseSelect::OnBackButtonClick +80632fa8 Pages::LicenseSelect::OnBackPress +80632fc0 Pages::LicenseSelect::OnNewLicenseApprove +8063301c Pages::LicenseSelect::OnNewLicenseDisapprove +80633078 Pages::LicenseSelect::OnNewLicenseBack +80633084 Pages::LicenseChangeMii::__ct +806331e8 LicenseControl::__dt +80633240 Pages::LicenseChangeMii::__dt +806332e0 Pages::LicenseChangeMii::OnInit +8063354c Pages::LicenseChangeMii::OnActivate +806337c0 Pages::LicenseChangeMii::SetControlMii +806340a0 Pages::LicenseChangeMii::UpdateMiiGroup +806340b0 Pages::LicenseChangeMii::PrepareMessageBox +80634204 0x80634204 +806342c8 0x806342c8 +80634444 0x80634444 +806345ac Pages::LicenseChangeMii::OnClick +80634728 Pages::LicenseChangeMii::OnMiiApprove +80634734 Pages::LicenseChangeMii::OnMiiDisapprove +80634740 Pages::LicenseChangeMii::OnMessageBoxClick +806347c4 Pages::LicenseSettings::__ct +806349e4 Pages::LicenseSettings::__dt +80634abc Pages::LicenseSettings::OnInit +80634ed0 Pages::LicenseSettings::OnActivate +80634f28 Pages::LicenseSettings::OnRecordsButtonClick +80634f6c Pages::LicenseSettings::OnChangeMiiButtonClick +80634fb0 Pages::LicenseSettings::OnEraseLicenseButtonClick +80634ff4 Pages::LicenseSettings::OnBackPress +80635040 Pages::LicenseSettings::OnSelectButton +806350ac Pages::LicenseSettings::OnBackPress +806350cc Pages::LicenseErase::__ct +8063525c Pages::LicenseErase::__dt +80635308 Pages::LicenseErase::OnInit +80635510 Pages::LicenseErase::OnActivate +8063551c Pages::LicenseErase::OnResume +806356f4 Pages::LicenseErase::GetNextPage +8063570c Pages::LicenseErase::OnYesButtonClick +80635850 Pages::LicenseErase::OnNoButtonClick +806358a4 Pages::LicenseErase::OnBackPress +806358b4 Pages::LicenseErase::OnErasedLicense +806358fc Pages::LicenseErase::GetRuntimeTypeInfo +80635908 Pages::LicenseSettings::GetNextPage +80635910 Pages::LicenseSettings::GetRuntimeTypeInfo +8063591c Pages::LicenseChangeMii::GetNextPage +80635924 Pages::LicenseChangeMii::GetRuntimeTypeInfo +80635930 Pages::LicenseSelect::GetNextPage +80635938 Pages::LicenseSelect::GetRuntimeTypeInfo +80635944 LicenseButton::GetRuntimeTypeInfo +80635950 LicenseControl::GetRuntimeTypeInfo +8063595c LicenseUI_cpp_sinit_ +8063598c TriggerPtmf +806359bc TriggerPtmf +806359ec TriggerPtmf +80635a1c TriggerPtmf +80635a4c TriggerPtmf +80635a7c TriggerPtmf +80635aac TriggerPtmf +80635adc TriggerPtmf +80635b0c TriggerPtmf +80635b3c TriggerPtmf +80635b6c 0x80635b6c +80635ba8 MiiNameMsgPrinter::__ct +80635bd8 MiiNameMsgPrinter::__dt +80635c30 MiiNameMsgPrinter::Load +80635d50 MiiNameMsgPrinter::PrintMessage +80635e40 BackGroundModelControl::GetClassName +80635e4c BackGroundModelControl::__ct +80635e88 BackGroundModelControl::__dt +80635ee0 BackGroundModelControl::Load +80635fa0 BackGroundModelControl::RequestModel +80635fc0 BackGroundModelControl::InitSelf +80635fc4 BackGroundModelControl::OnUpdate +80636354 DriverModelControl::GetClassName +80636364 DriverModelControl::__ct +806363a0 DriverModelControl::__dt +806363f8 DriverModelControl::Load +80636588 DriverModelControl::SetAnimationType +806365b0 DriverModelControl::RequestModel +80636684 DriverModelControl::InitSelf +80636688 DriverModelControl::OnUpdate +80636900 DriverModelControl::SetPositionAnim +8063694c DriverModelControl::SetModelPositionOnAnim +80636ac8 VehicleModelControl::GetClassName +80636ad8 VehicleModelControl::__ct +80636b14 VehicleModelControl::__dt +80636b6c VehicleModelControl::Load +80636cb4 VehicleModelControl::SetAnimationType +80636ce0 VehicleModelControl::RequestNewModel +80636da8 VehicleModelControl::InitSelf +80636e14 VehicleModelControl::OnUpdate +806371c0 VehicleModelControl::SetPositionAnim +8063722c VehicleModelControl::SetModelPositionOnAnim +806373c0 NoteModelControl::GetClassName +806373d0 NoteModelControl::__ct +8063740c NoteModelControl::__dt +80637464 NoteModelControl::Load +806375bc NoteModelControl::SetAnimationType +806375dc NoteModelControl::InitSelf +80637714 NoteModelControl::OnUpdate +80637e18 NoteModelControl::SetPositionAnim +80637f68 NoteModelControl::SetModelPositionOnAnim +80638098 NoteModelControl::GetRuntimeTypeInfo +806380a4 VehicleModelControl::GetRuntimeTypeInfo +806380b0 DriverModelControl::GetRuntimeTypeInfo +806380bc BackGroundModelControl::GetRuntimeTypeInfo +806380c8 ModelControl_cpp_sinit_ +806380ec Pages::ModelRenderer::__ct +806382e4 Pages::ModelRenderer::__dt +8063834c Pages::ModelRenderer::OnInit +80638620 Pages::ModelRenderer::OnDispose +8063863c Pages::ModelRenderer::OnActivate +806387f0 Pages::ModelRenderer::BeforeEntranceAnimations +806387f4 Pages::ModelRenderer::BeforeExitAnimations +806387f8 Pages::ModelRenderer::BeforeControlUpdate +806387fc Pages::ModelRenderer::RequestCharacterModel +80638828 Pages::ModelRenderer::LoadKartModelsByCharacter +806388d4 0x806388d4 +80638a74 Pages::ModelRenderer::RequestKartModel +80638aa0 Pages::ModelRenderer::RequestBackgroundModel +80638ac8 0x80638ac8 +80638b4c Pages::ModelRenderer::SetBackgroundModelVisibility +80638b68 Pages::ModelRenderer::GetModelTexObj +80638b8c Pages::ModelRenderer::GetBackgroundModelTexObj +80638bb4 Pages::ModelRenderer::GetVariantType +80638db0 Pages::ModelRenderer::PrepareParams +80638e74 Pages::ModelRenderer::GetModelCount +80638f44 ModelRendererParams::Reset +80638f60 0x80638f60 +806390c0 ModelValuesHolder::GetValues +806390f8 Pages::ModelRenderer::GetRuntimeTypeInfo +80639104 ModelRendererPage_cpp_sinit_ +80639118 ModelRendererValuesHolder::Init +8063bc40 ModelRendererValues::SetValues +8063bc50 Pages::BackModel::__ct +8063bca4 Pages::BackModel::__dt +8063bd24 Pages::BackModel::OnInit +8063be40 Pages::BackModel::OnInit_switch +8063be44 Pages::BackModel::OnInit_case_60 +8063be54 Pages::BackModel::OnInit_case_49 +8063be64 Pages::BackModel::OnInit_case_4b +8063be74 Pages::BackModel::OnInit_case_4c +8063be80 Pages::BackModel::OnInit_case_4d +8063be94 Pages::BackModel::GetRuntimeTypeInfo +8063bea0 BackModelPage_cpp_sinit_ +8063beb4 Pages::Options::__ct +8063bfd4 Pages::Options::__dt +8063c080 Pages::Options::OnInit +8063c280 Pages::Options::OnDispose +8063c284 Pages::Options::OnActivate +8063c2a8 Pages::Options::OnButtonClick +8063c41c Pages::Options::OnBackPress +8063c444 Pages::WifiOptions::__ct +8063c574 Pages::WifiOptions::__dt +8063c638 Pages::WifiOptions::OnInit +8063c8d0 Pages::WifiOptions::OnActivate +8063c8f4 Pages::WifiOptions::OnButtonClick +8063caac Pages::WifiOptions::OnBackPress +8063cac4 Pages::OptionExplanation::__ct +8063cbdc Pages::OptionExplanation::__dt +8063cc7c Pages::OptionExplanation::OnInit +8063cdfc Pages::OptionExplanation::OnActivate +8063ce28 Pages::OptionExplanation::OnButtonClick +8063cf18 Pages::OptionExplanation::OnBackPress +8063cf94 Pages::OptionChoice::__ct +8063d0c4 Pages::OptionChoice::__dt +8063d170 Pages::OptionChoice::OnInit +8063d3f4 Pages::OptionChoice::OnActivate +8063d424 Pages::OptionChoice::OnResume +8063d4fc Pages::OptionChoice::SetTitleText +8063d508 Pages::OptionChoice::SetMessageWindowText +8063d514 Pages::OptionChoice::SetButtonText +8063d578 Pages::OptionChoice::SetInitialButton +8063d580 Pages::OptionChoice::OnButtonClick +8063d728 Pages::OptionChoice::OnBackPress +8063d740 Pages::RegionOptions::__ct +8063d898 Pages::RegionOptions::__dt +8063d938 Pages::RegionOptions::OnInit +8063dac4 Pages::RegionOptions::OnActivate +8063dad0 Pages::RegionOptions::GetNextPage +8063db30 Pages::RegionOptions::OnButtonClick +8063db7c Pages::RegionOptions::OnBackButtonClick +8063dc3c Pages::RegionOptions::OnBackPress +8063dcc4 Pages::MasterOptions::__ct +8063dd40 Pages::MasterOptions::__dt +8063dda8 Pages::MasterOptions::OnInit +8063de14 Pages::MasterOptions::OnActivate +8063de74 Pages::MasterOptions::BeforeEntranceAnimations +8063de78 Pages::MasterOptions::BeforeExitAnimations +8063de7c Pages::MasterOptions::AfterControlUpdate +8063e060 Pages::MasterOptions::OnResume +8063e09c Pages::MasterOptions::OnResume_switch +8063e0a0 Pages::MasterOptions::OnResume_case0 +8063e244 Pages::MasterOptions::OnResume_case1 +8063e2e4 Pages::MasterOptions::OnResume_case2 +8063e9d4 Pages::MasterOptions::OnResume_case4 +8063e9fc Pages::MasterOptions::OnResume_case5 +8063ea04 Pages::MasterOptions::OnResume_case7 +8063ea2c Pages::MasterOptions::OnResume_case8 +8063ea34 Pages::MasterOptions::OnResume_case9 +8063ea44 Pages::MasterOptions::OnResume_case3 +8063ea60 Pages::MasterOptions::SetNextPageType +8063eac4 Pages::MasterOptions::LoadOptionFirstExplanation +8063ec80 Pages::MasterOptions::LoadOptionNextExplanation +8063ed7c Pages::MasterOptions::LoadOptionChoice +8063f138 Pages::MasterOptions::LoadOptionWaitingNetwork +8063f268 Pages::MasterOptions::LoadOptionWaiting +8063f398 Pages::MasterOptions::LoadOptionChoiceSaved +8063f75c Pages::MasterOptions::LoadOptionChoiceSavedNetwork +8063f82c Pages::MasterOptions::LoadOptionChoiceSavedNetwork_switch +8063f830 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case1 +8063f838 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case2 +8063f840 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case3 +8063f848 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case4 +8063f850 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case5 +8063f858 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case6 +8063f860 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case8 +8063f868 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case9 +8063f870 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case7 +8063f898 Pages::MasterOptions::LoadOptionChoiceSavedNetwork_case0 +8063f924 Pages::MasterOptions::OnClick +8063f9b0 Pages::MasterOptions::GetNextPage +8063f9b8 Pages::MasterOptions::GetRuntimeTypeInfo +8063f9c4 Pages::RegionOptions::GetRuntimeTypeInfo +8063f9d0 Pages::OptionChoice::GetRuntimeTypeInfo +8063f9dc Pages::OptionExplanation::GetRuntimeTypeInfo +8063f9e8 Pages::WifiOptions::GetNextPage +8063f9f0 Pages::WifiOptions::GetRuntimeTypeInfo +8063f9fc Pages::Options::GetNextPage +8063fa04 Pages::Options::GetRuntimeTypeInfo +8063fa10 Pages::RegionOptions::TriggerPtmf +8063fa40 Pages::OptionChoice::TriggerPtmf +8063fa70 Pages::OptionExplanation::TriggerPtmf +8063faa0 Pages::WifiOptions::TriggerPtmf +8063fad0 Pages::Options::TriggerPtmf +8063fb00 Pages::MasterOptions::TriggerPtmf +8063fb30 Pages::RegionOptions::TriggerBackPtmf +8063fb60 Pages::OptionChoice::TriggerBackPtmf +8063fb90 Pages::OptionExplanation::TriggerBackPtmf +8063fbc0 Pages::WifiOptions::TriggerBackPtmf +8063fbf0 Pages::Options::TriggerBackPtmf +8063fc20 Optionscpp_sinit_ +8063fc4c RankingDetailItem_getTypeName +8063fc58 RankingDetailItem_ct +8063fc94 RankingDetailPage_dt +8063fcec 0x8063fcec +8063fe10 0x8063fe10 +8063fe48 0x8063fe48 +8063fff4 0x8063fff4 +80640258 RankingDetailPage_ct +80640380 0x80640380 +80640434 0x80640434 +806406d8 0x806406d8 +8064071c 0x8064071c +80640720 0x80640720 +80640828 0x80640828 +80640b0c 0x80640b0c +80640b30 0x80640b30 +80640b70 0x80640b70 +80640cbc 0x80640cbc +80641078 0x80641078 +806411fc 0x806411fc +80641238 0x80641238 +80641248 0x80641248 +806412ac 0x806412ac +806412d0 0x806412d0 +80641310 0x80641310 +80641378 0x80641378 +80641400 0x80641400 +806414b0 0x806414b0 +806415fc 0x806415fc +80641754 0x80641754 +80641a2c 0x80641a2c +80641a5c 0x80641a5c +80641a68 0x80641a68 +80641cc4 0x80641cc4 +806420dc 0x806420dc +8064248c 0x8064248c +806425a4 0x806425a4 +80642708 0x80642708 +80642714 0x80642714 +80642720 0x80642720 +8064272c TriggerPtmf +8064275c TriggerPtmf +8064278c 0x8064278c +806427b4 0x806427b4 +8064292c 0x8064292c +806429d4 0x806429d4 +80642bb4 0x80642bb4 +80642bc8 0x80642bc8 +80642bcc 0x80642bcc +80642ccc 0x80642ccc +80642d20 0x80642d20 +80642f14 0x80642f14 +80642f58 0x80642f58 +80642f70 0x80642f70 +80643140 0x80643140 +806431c4 0x806431c4 +8064322c 0x8064322c +80643298 0x80643298 +806432a8 0x806432a8 +806432b4 0x806432b4 +806432bc 0x806432bc +80643a84 0x80643a84 +80643abc 0x80643abc +80643ac0 0x80643ac0 +80643ac8 0x80643ac8 +80643c6c 0x80643c6c +80643d40 0x80643d40 +80643dec 0x80643dec +80643df4 0x80643df4 +80643ed8 0x80643ed8 +8064402c 0x8064402c +80644120 0x80644120 +80644370 0x80644370 +80644378 0x80644378 +80644380 0x80644380 +8064444c 0x8064444c +8064447c 0x8064447c +806459a0 0x806459a0 +80645a7c 0x80645a7c +80645b88 0x80645b88 +80645cb4 0x80645cb4 +80646288 0x80646288 +806466c0 0x806466c0 +806467c4 0x806467c4 +806468dc 0x806468dc +80646a9c 0x80646a9c +80646b6c 0x80646b6c +80646b70 0x80646b70 +80646b78 0x80646b78 +80646b80 0x80646b80 +80646b88 0x80646b88 +80646b90 0x80646b90 +80646b98 0x80646b98 +80646ba0 0x80646ba0 +80646ba8 0x80646ba8 +80646bb0 0x80646bb0 +80646c54 0x80646c54 +80646cc0 0x80646cc0 +80646cc8 0x80646cc8 +80646cd4 0x80646cd4 +80646ce0 TriggerPtmf +80646d10 TriggerPtmf +80646d40 TriggerPtmf +80646d70 0x80646d70 +80646d8c 0x80646d8c +80646edc RankingItem::GetClassName +80646ee8 0x80646ee8 +80646f38 RankingItem::__dt +80646f90 RankingItem::FinishLoad +8064716c RankingItem::OnUpdate +806475f8 0x806475f8 +8064760c RankingItem::Disable +80647620 RankingItem::Enable +80647634 RankingItem::Appear +80647738 RankingItem::MakeAccessible +8064773c RankingItem::Disappear +8064776c 0x8064776c +806477c8 0x806477c8 +806478f0 RankingItemSelectable::GetClassName +80647900 RankingItemSelectable::__ct +80647a14 RankingItemSelectable::__dt +80647a84 RankingItemSelectable::Load +80647ac8 RankingItemSelectable::Load_switch +80647acc RankingItemSelectable::Load_caseD_0 +80647adc RankingItemSelectable::Load_caseD_1 +80647aec RankingItemSelectable::Load_caseD_2 +80647afc RankingItemSelectable::Load_caseD_3 +80647b0c RankingItemSelectable::Load_caseD_4 +80647b1c RankingItemSelectable::Load_caseD_5 +80647b2c RankingItemSelectable::Load_caseD_6 +80647b3c RankingItemSelectable::Load_caseD_7 +80647ee4 RankingItemSelectable::InitSelf +80647f78 RankingItemSelectable::Disable +80647f94 RankingItemSelectable::Enable +806484ac RankingItemSelectable::MakeAccessible +806484c8 RankingItemSelectable::Disappear +80648500 RankingItemSelectable::vf_0x50 +8064851c RankingItemSelectable::vf_0x54 +80648534 RankingItemSelectable::vf_0x58 +8064854c RankingItemSelectable::vf_0x5c +80648568 RankingItemSelectable::vf_0x60 +80648834 RankingItemSelectable::vf_0x64 +80648838 RankedItemSelectable::OnSelect +80648e70 RankedItemSelectable::OnSelect_switch +80648e74 RankedItemSelectable::OnSelect_caseD_0 +80648e7c RankedItemSelectable::OnSelect_caseD_1 +80648e84 RankedItemSelectable::OnSelect_caseD_3 +80648eb0 RankedItemSelectable::OnSelect_caseD_5 +80648eb8 RankedItemSelectable::OnSelect_caseD_6 +80648ef4 RankedItemSelectable::OnSelect_caseD_7 +80649034 RankedItemSelectable::OnDeselect +80649198 RankedItemSelectable::OnClick +806493dc 0x806493dc +80649404 0x80649404 +80649408 0x80649408 +80649410 0x80649410 +80649418 0x80649418 +80649420 0x80649420 +80649428 0x80649428 +80649430 0x80649430 +80649438 0x80649438 +80649440 0x80649440 +80649464 RankingItemStranger::GetClassName +80649474 RankingItemStranger::__ct +806494d0 RankingItemStranger::__dt +8064952c RankingItemStranger::Load +806495c4 RankingItemStranger::Enable +806495f4 RankingItemStranger::vf_0x50 +80649610 RankingItemStranger::vf_0x54 +80649628 RankingItemStranger::vf_0x58 +80649640 RankingItemStranger::vf_0x5c +80649644 RankingItemStranger::vf_0x60 +80649648 RankingItemStranger::vf_0x64 +8064964c RankingRuler::GetClassName +8064965c RankingRuler::__ct +80649698 RankingRuler::__dt +806496f0 RankingRuler::Load +80649764 RankingRuler::InitSelf +80649770 0x80649770 +806498b4 0x806498b4 +80649960 0x80649960 +8064996c RankingWindow::GetClassName +8064997c RankingWindow::__ct +806499b8 RankingWindow::__dt +80649a10 0x80649a10 +80649b80 RankingWindow::InitSelf +80649b8c RankingWindow::OnUpdate +80649c0c 0x80649c0c +80649c18 0x80649c18 +80649e44 RankingWindow::GetRuntimeTypeInfo +80649e50 RankingRuler::GetRuntimeTypeInfo +80649e5c RankingItemStranger::GetRuntimeTypeInfo +80649e68 RankingItemSelectable::GetRuntimeTypeInfo +80649e74 RankingItem::GetRuntimeTypeInfo +80649e80 TriggerPtmf +80649eb0 0x80649eb0 +80649f04 0x80649f04 +80649f44 0x80649f44 +80649fa0 0x80649fa0 +80649fb0 0x80649fb0 +8064a198 GLMeshWriterCore_ColourPlat +8064a1b8 0x8064a1b8 +8064a204 0x8064a204 +8064a4a4 0x8064a4a4 +8064a4c0 0x8064a4c0 +8064a530 0x8064a530 +8064a784 0x8064a784 +8064a804 0x8064a804 +8064a874 0x8064a874 +8064a964 0x8064a964 +8064a9ac 0x8064a9ac +8064aa4c 0x8064aa4c +8064aaec 0x8064aaec +8064ab38 0x8064ab38 +8064ab98 0x8064ab98 +8064adc0 0x8064adc0 +8064b064 0x8064b064 +8064b0e8 0x8064b0e8 +8064b134 0x8064b134 +8064b194 0x8064b194 +8064b344 0x8064b344 +8064b3b4 0x8064b3b4 +8064b438 0x8064b438 +8064b4ac 0x8064b4ac +8064b52c 0x8064b52c +8064b6c4 Page::EndExitState +8064b6c8 0x8064b6c8 +8064b6cc 0x8064b6cc +8064bce8 0x8064bce8 +8064c000 0x8064c000 +8064c004 0x8064c004 +8064c00c 0x8064c00c +8064c014 0x8064c014 +8064c01c 0x8064c01c +8064c024 0x8064c024 +8064c02c 0x8064c02c +8064c034 0x8064c034 +8064c03c 0x8064c03c +8064c044 0x8064c044 +8064c10c 0x8064c10c +8064c1b4 0x8064c1b4 +8064c1c0 TriggerPtmf +8064c1f0 0x8064c1f0 +8064c204 Pages::ESRBNotice::__ct +8064c250 Pages::ESRBNotice::__dt +8064c2c4 Pages::ESRBNotice::OnInit +8064c368 Pages::ESRBNotice::AfterControlUpdate +8064c3d8 Pages::Suggest60Hz::__ct +8064c424 Pages::Suggest60Hz::__dt +8064c498 Pages::Suggest60Hz::OnInit +8064c540 Pages::Suggest60Hz::OnActivate +8064c58c Pages::Suggest60Hz::AfterControl +8064c644 Pages::Suggest60Hz::IsHomeMenuWorking +8064c64c Pages::Suggest60Hz::GetRuntimeTypeInfo +8064c658 Pages::ESRBNotice::IsHomeMenuWorking +8064c660 Pages::ESRBNotice::GetRuntimeTypeInfo +8064c66c NoticePages_cpp_sinit_ +8064c688 SystemBMGHolder::__ct +8064c6b8 SystemBMGHolder::__dt +8064c710 SystemBMGHolder::Init +8064c754 0x8064c754 +8064c78c 0x8064c78c +8064c798 0x8064c798 +8064c7d4 0x8064c7d4 +8064c82c 0x8064c82c +8064c8cc 0x8064c8cc +8064c904 0x8064c904 +8064c93c 0x8064c93c +8064c974 WifiAwardResultItem::GetClassName +8064c984 WifiAwardResultItem::__ct +8064c9c0 WifiAwardResultItem::__dt +8064ca18 WifiAwardResultItem::Load +8064cb90 WifiAwardResultItem::InitSelf +8064cbc8 0x8064cbc8 +8064cf70 Pages::WiFiVSResults::__ct +8064d034 Pages::WiFiVSResults::__dt +8064d0d0 Pages::WiFiVSResults::OnInit +8064d404 Pages::WiFiVSResults::OnActivate +8064d4f0 Pages::WiFiVSResults::BeforeEntranceAnimations +8064d504 Pages::WiFiVSResults::AfterEntranceAnimations +8064d55c Pages::WiFiVSResults::BeforeExitAnimations +8064d570 Pages::WiFiVSResults::AfterControlUpdate +8064d5a8 Pages::WiFiVSResults::OnClick +8064d5b4 0x8064d5b4 +8064d620 0x8064d620 +8064d748 0x8064d748 +8064d988 0x8064d988 +8064daf8 Pages::WiFiVSResults::GetNextPage +8064db00 Pages::WiFiVSResults::GetRuntimeTypeInfo +8064db0c WifiAwardResultItem::GetRuntimeTypeInfo +8064db18 0x8064db18 +8064db24 TriggerPtmf +8064db54 WiFiVSResults_cpp_sinit_ +8064db7c Pages::VR::__ct +8064dc68 Pages::VR::__dt +8064dd14 Pages::VR::OnInit +8064ddf8 Pages::VR::OnInit_switch +8064ddfc Pages::VR::OnInit_case58 +8064de10 Pages::VR::OnInit_case59 +8064de20 Pages::VR::OnInit_case5a +8064dfd4 Pages::VR::OnActivate +8064e090 Pages::VR::OnActivate_switch +8064e094 Pages::VR::OnActivate_case58 +8064e09c Pages::VR::OnActivate_case59 +8064e0a0 Pages::VR::OnActivate_case5a +8064e24c Pages::VR::AfterControlUpdate +8064e290 Pages::VR::FillVRControl +8064e5f4 Pages::VR::OnButtonClick +8064e630 Pages::VR::GetRuntimeTypeInfo +8064e63c TriggerPtmf +8064e66c CountDownTimerPage_cpp_sinit_ +8064e680 WipeControl::GetClassName +8064e68c WipeControl::__ct +8064e6c8 WipeControl::__dt +8064e720 WipeControl::Load +8064e7d4 WipeControl::InitSelf +8064e80c WipeControl::OnUpdate +8064e900 Pages::Wipe::__ct +8064e96c Pages::Wipe::__dt +8064e9f8 Pages::Wipe::OnInit +8064ed44 Pages::Wipe::GetRuntimeTypeInfo +8064ed50 WipeControl::GetRuntimeTypeInfo +8064ed5c WipePagecpp_sinit_ +8064ed80 RKNet::PacketMgr::CreateInstance +8064edfc RKNet::PacketMgr::DestroyInstance +8064ee50 RKNet::PacketMgr::Reset +8064f2a0 RKNet::PacketMgr::Update +8064f4d8 RKNet::PacketMgr::ExportRacedata +8064f634 RKNet::PacketMgr::GetRacedata +8064f780 RKNet::PacketMgr::ExportRH2 +8064f830 RKNet::PacketMgr::GetRH2 +8064f88c RKNet::PacketMgr::ClearSentRacedata +8064f8f0 RKNet::PacketMgr::ClearSentRH2 +8064f954 RKNet::PacketMgr::ProcessPlayerDC +8064f96c RKNet::PacketMgr::__ct +8064f9c4 0x8064f9c4 +8064fa04 0x8064fa04 +8064fa44 RKNet::PacketMgr::__dt +8064fa9c RKNet::PacketMgr::UpdateAsSpectator +8064fbb0 RKNet::PacketMgr::EveryoneIsConnected +8064fcc8 RKNet::PacketMgr::UpdateAsRacer +80650020 RKNet::PacketMgr::GetPlayerRH1Timer +806500e0 RKNet::PacketMgr::GetPlayerLagFrames +80650154 RKNet::PacketMgr::GetMaxRH1Timer +80650294 RKNet::PacketMgr::SetITEMItem +806502ac RKNet::PacketMgr::IsITEMItemNew +806502b8 RKNet::PacketMgr::GetITEMStoredItem +806502c4 RKNet::PacketMgr::AddEVENTEntry +806502d0 RKNet::PacketMgr::HasFreeEVENTEntries +80650388 RKNet::PacketMgr::GetEVENTFreeDataSpace +80650398 RKNet::PacketMgr::IsPlayerConnected +80650420 RKNet::PacketMgr::IsPlayerLocal +80650490 RKNet::PacketMgr::GetHudSlotId +806504fc RKNet::PacketMgr::UpdateRaceinfoConnectionStatus +806505ac 0x806505ac +80650678 RKNet::PacketMgr::ProcessLagFrames +80650880 RKNet::PacketMgr::CreateRH1AndExportRH1andUSERandRacedata +80650cdc RKNet::PacketMgr::CreateAndExportRH1andUSER +80651018 RKNet::PacketMgr::ProcessReceived +806512c4 RKNet::PacketMgr::UpdateAidsBitfield +806513b0 0x806513b0 +806513c4 0x806513c4 +806513d0 0x806513d0 +80651564 0x80651564 +80651568 0x80651568 +8065168c 0x8065168c +80651694 0x80651694 +8065169c RKNet::Controller::CreateInstance +80651724 RKNet::Controller::DestroyInstance +80651788 RKNet::Controller::Init +80651d20 RKNet::Controller::ScheduleShutdown +80651d2c RKNet::Controller::StartSearchWW +80651de8 RKNet::Controller::StartSearchRegion +80651ea4 RKNet::Controller::StartSearchBTWW +80651f60 RKNet::Controller::StartSearchBTRegional +8065201c RKNet::Controller::JoinFriend +8065214c 0x8065214c +8065227c RKNet::Controller::JoinRoom +80652350 RKNet::Controller::StartRoom +80652410 RKNet::Controller::ResetRH1andROOM +80652468 0x80652468 +80652480 0x80652480 +80652498 0x80652498 +8065252c RKNet::Controller::GetErrorParams +806525a8 RKNet::Controller::ResetErrorParams +80652604 RKNet::Controller::GetSubTickDiff +80652664 RKNet::Controller::UpdateServersAsyncAlt +806526bc RKNet::Controller::UpdateServersAsync +806526e4 RKNet::Controller::UpdateFriendsStatus +80652818 RKNet::Controller::SetFriendsAddedBack +806528e4 RKNet::Controller::SetFriendDeleted +80652914 RKNet::Controller::CanExchangeFriendData +806529bc RKNet::Controller::IsIdle +806529e8 0x806529e8 +80652a78 RKNet::Controller::IsConnectedToAnyone +80652ab8 RKNet::Controller::ClearSplitSendRACEPointers +80652b70 RKNet::Controller::SetConnectionStateToFailed +80652b7c RKNet::Controller::__ct +80652f54 RKNet::FriendManager::__dt +80652f94 RKNet::Controller::__dt +80653078 RKNet::Controller::MainNetworkLoop +8065307c RKNet::Controller::MainLoop +806535e8 RKNet::Controller::SendPacketsAndUpdateUSER +80653628 RKNet::Controller::CombineSplitSendPackets +806539a8 RKNet::Controller::TrySendNextRACEPacket +80653b5c RKNet::Controller::SendAidNextRACEPacket +80653c3c RKNet::Controller::GetSplitSendPacketsTotalSize +80653cb8 RKNet::Controller::SetConnectionState +80653cc0 RKNet::Controller::GetConnectionState +80653d44 RKNet::Controller::HandleError +80653ea4 RKNet::Controller::Alloc +80653f2c RKNet::Controller::Free +80653f90 RKNet::Controller::SOAlloc +80654010 RKNet::Controller::SOFree +80654078 RKNet::Controller::DWCAlloc +80654104 RKNet::Controller::DWCFree +8065416c RKNet::Controller::UserRecvCallback +8065418c RKNet::Controller::LoginCallback +80654290 RKNet::Controller::MatchedSCCallback +806542e0 RKNet::Controller::ConnectionAttemptCallback +8065439c RKNet::Controller::ConnectionClosedCallback +80654450 RKNet::Controller::UpdateServerCallback +80654474 RKNet::Controller::UpdateServerCallbackAlt +80654490 RKNet::Controller::FriendStatusChangeCallback +80654494 RKNet::Controller::BuddyFriendCallback +806544a0 RKNet::Controller::SetDWCRecvBuffers +80654508 RKNet::Controller::ProcessPlayerDisconnect +80654714 RKNet::Controller::ConnectToWFC +806548b4 RKNet::Controller::InitSubs +80654958 RKNet::Controller::UpdateSubsAndVR +80654af8 RKNet::Controller::ResetFriendArray +80654bbc RKNet::Controller::StartMatching +80654ce8 RKNet::Controller::ConnectToAnybodyAsync +80655130 RKNet::Controller::SetupGameServer +80655194 0x80655194 +806551f8 RKNet::Controller::ConnectToGameServerFromGroupId +8065543c 0x8065543c +806555b4 RKNet::Controller::CalcRACEPacketCRC32 +806555fc RKNet::Controller::ProcessRACEPacket +80655738 RKNet::Controller::UpdateAidsBelongingToPlayerIds +80655898 RKNet::Controller::ResetAidsBelongingToPlayerIds +806558d0 RKNet::Controller::GetLocalPlayerId +80655b1c RKNet::Controller::GetFriendsSearchType +80655c2c RKNet::Controller::UpdateStatusDatas +80655dc4 RKNet::PacketHolder::__ct +80655e24 RKNet::PacketHolder::__dt +80655e84 RKNet::PacketHolder::Clear +80655ec4 RKNet::PacketHolder::Copy +80655f04 RKNet::PacketHolder::Append +80655f54 RKNet::SplitRACEPointers::__ct +80655fec RKNet::SplitRACEPointers::__dt +80656070 RKNet::RatingRangeMaker::Init +80656158 RKNet::RatingRangeMaker::GetLowerRange +806561c4 RKNet::RatingRangeMaker::GetUpperRange +8065622c 0x8065622c +806562e0 RKNet::RatingRangeMaker::GetRatingGroup +8065644c RKNet::GPReverseBuddiesListCallback +806564ec RKNet::SetGPError +80656600 RKNet::ROOMHandler::CreateInstance +806566c4 RKNet::ROOMHandler::DestroyInstance +80656704 RKNet::ROOMHandler::Init +8065680c RKNet::ROOMHandler::Reset +80656890 RKNet::ROOMHandler::Update +806569e8 RKNet::ROOMHandler::SetAllToSendPackets +80656adc RKNet::ROOMHandler::GetRecvPacket +80656aec RKNet::ROOMHandler::SetToSendPacket +80656afc RKNet::ROOMHandler::__ct +80656b80 RKNet::ROOMHandler::__dt +80656bc0 RKNet::ROOMHandler::ExportROOMandUSER +80656d0c RKNet::ROOMHandler::ImportNewPackets +80656dd8 RKNet::ROOMHandler::ResetAllPackets +80656e58 RKNet::ROOMHandler::InitPacket +80656e64 RKNet::ROOMHandler::ClearToSendPacket +80656e78 RKNet::ROOMHandler::ClearRecvPacket +80656e8c RKNet::ROOMHandler::SetToSendPacket2 +80656e9c RKNet::ROOMHandler::SetRecvPacket +80656eac RKNet::ROOMHandler::GetToSendPacketPtr +80656ebc RKNet::ROOMHandler::GetRecvPacketPtr +80656ecc RKNet::EVENTHandler::CreateInstance +80656fe4 RKNet::EVENTHandler::DestroyInstance +80657024 RKNet::EVENTHandler::__ct +80657110 0x80657110 +80657114 RKNet::EVENTHandler::Update +80657164 RKNet::EVENTHandler::AddEntry +8065737c RKNet::EVENTHandler::Reset +80657470 RKNet::EVENTHandler::__dt +806574b0 RKNet::EVENTHandler::FreeExpiredSendEntries +80657578 RKNet::EVENTHandler::ExportSendEntries +806576c8 RKNet::EVENTHandler::ImportReceivedEntries +80657824 RKNet::EVENTHandler::ProcessReceivedEntries +80657a30 RKNet::EVENTHandler::ResetEntry +80657a5c RKNet::EVENTHandler::GetEventType +80657a94 RKNet::EVENTHandler::SetEntryItemAndActionFromType +80657aa8 RKNet::EVENTHandler::ProcessEntry +80657ad0 0x80657ad0 +80657bf0 0x80657bf0 +80657f10 0x80657f10 +80657f50 RKNet::SELECTHandler::CreateInstance +80658024 RKNet::SELECTHandler::DestroyInstance +80658068 RKNet::SELECTHandler::InitPackets +806583bc 0x806583bc +806583c0 RKNet::SELECTHandler::Update +806584f8 RKNet::SELECTHandler::GetWinningVoter +80658514 RKNet::SELECTHandler::GetWinningCourse +80658534 RKNet::SELECTHandler::GetOwnSelectId +80658550 RKNet::SELECTHandler::GetEngineClass +8065856c RKNet::SELECTHandler::GetBattleType +80658590 RKNet::SELECTHandler::GetOwnPlayerIdToAid +80658598 RKNet::SELECTHandler::GetCharacterId +806585e8 RKNet::SELECTHandler::GetKartId +80658638 RKNet::SELECTHandler::GetCourseVote +80658688 RKNet::SELECTHandler::GetPlayerData +806586d0 RKNet::SELECTHandler::GetStarRank +80658718 RKNet::SELECTHandler::GetTeam +80658750 RKNet::SELECTHandler::HasUnprocessedPackets +806587d4 RKNet::SELECTHandler::IsPrepared +80658814 RKNet::SELECTHandler::SetPlayerData +80658830 RKNet::SELECTHandler::__ct +806588b8 RKNet::SELECTHandler::__dt +80658978 RKNet::SELECTHandler::ResetSendPacket +80658ac4 RKNet::SELECTHandler::ResetReceivedPackets +80658bb8 RKNet::SELECTHandler::ResetPacket +80658c94 RKNet::SELECTHandler::ResetPlayerData +80658d00 RKNet::SELECTHandler::HandleReceivedPacketTimes +80658df0 RKNet::SELECTHandler::IsBattle +80658e04 RKNet::SELECTHandler::IsTrackDecided +80658e20 RKNet::SELECTHandler::EveryoneHasAccurateRaceSettings +80658e90 RKNet::SELECTHandler::EveryoneHasVoted +80658f00 RKNet::SELECTHandler::EveryoneHasAccurateAidPidMap +80658f74 RKNet::SELECTHandler::ClearRH1ReceivedBuffers +80658fe0 RKNet::SELECTHandler::PrepareAndExportSELECTandUSER +8065913c RKNet::SELECTHandler::ImportNewPackets +8065934c RKNet::SELECTHandler::PrepareAndExportPacket +80659574 RKNet::SELECTHandler::ProcessNewPacketVoting +806599f8 RKNet::SELECTHandler::DecideBattleTypeAndTeams +80659ad8 RKNet::SELECTHandler::GenerateOwnSELECTId +80659b20 RKNet::SELECTHandler::DecideEngineClass +80659dac RKNet::SELECTHandler::DecideTrack +8065a0f8 RKNet::SELECTHandler::AllocatePlayerIdsToAids +8065a2a0 RKNet::SELECTHandler::HasMatchingPlayerIdToAid +8065a354 RKNet::SELECTHandler::DecidePublicTeams +8065a64c RKNet::SELECTHandler::DecidePrivateTeams +8065a83c RKNet::FriendMgr::CreateInstance +8065a964 RKNet::FriendMgr::DestroyInstance +8065a9a4 RKNet::FriendMgr::ReadDataFromRKSYS +8065aaec RKNet::FriendMgr::Update +8065ac50 RKNet::FriendMgr::CreateAccUserData +8065ac58 RKNet::FriendMgr::CheckAccUserData +8065ac88 RKNet::FriendMgr::IsAccUserDataDirt +8065acb8 RKNet::FriendMgr::ClearAccUserDataDirtyFlag +8065acc0 RKNet::FriendMgr::CreateFriendCode +8065acec RKNet::FriendMgr::SetCodesForUnusedIdxs +8065adf4 RKNet::FriendMgr::IsAvailable +8065ae04 RKNet::FriendMgr::IsBuddyFriend +8065ae3c RKNet::FriendMgr::IsValidFriend +8065ae6c RKNet::FriendMgr::CheckFriendCode +8065aea4 RKNet::FriendMgr::GetFriendIdx +8065af1c RKNet::FriendMgr::GetFriendCodeLicenseIdx +8065afc0 RKNet::FriendMgr::GetLicenseFriendCode +8065afe8 RKNet::FriendMgr::GetFirstFreeFriendIdx +8065b048 RKNet::FriendMgr::__ct +8065b14c RKNet::RH1Handler::CreateInstance +8065b2e0 RKNet::RH1Handler::DestroyInstance +8065b324 RKNet::RH1Handler::Activate +8065b330 RKNet::RH1Handler::Reset +8065b47c RKNet::RH1Handler::Update +8065b7b4 RKNet::RH1Handler::Reset +8065b858 RKNet::RH1Handler::HasValidCourse +8065ba68 RKNet::RH1Handler::GetKart +8065ba80 RKNet::RH1Handler::GetCharacter +8065ba98 0x8065ba98 +8065bbf4 RKNet::RH1Handler::GetStarRank +8065bc08 RKNet::RH1Handler::GetValidCourse +8065bd70 0x8065bd70 +8065be78 RKNet::RH1Handler::GetPlayerCount +8065bfec RKNet::RH1Handler::GetSELECTId +8065c0e4 RKNet::RH1Handler::GetEngineClass +8065c1dc RKNet::RH1Handler::GetAidsBelongingToPlayer +8065c2d4 0x8065c2d4 +8065c444 RKNet::RH1Handler::__dt +8065c5a8 0x8065c5a8 +8065c6a0 0x8065c6a0 +8065c714 0x8065c714 +8065c85c RKNet::RH1Handler::ImportNewPackets +8065c9dc 0x8065c9dc +8065ca70 RKNet::RH1Handler::ExportDefaultPacket +8065cb28 RKNet::RH1Handler::ExportDefaultPacket2 +8065cbe0 0x8065cbe0 +8065cc44 0x8065cc44 +8065cc98 0x8065cc98 +8065cd74 RKNet::ITEMHandler::CreateInstance +8065cff0 RKNet::ITEMHandler::DestroyInstance +8065d030 RKNet::ITEMHandler::__ct +8065d26c 0x8065d26c +8065d270 RKNet::ITEMHandler::Update +8065d348 RKNet::ITEMHandler::SetItem +8065d3d4 RKNet::ITEMHandler::RemoveItem +8065d468 RKNet::ITEMHandler::OnRouletteEnd +8065d554 0x8065d554 +8065d6ec 0x8065d6ec +8065d8b4 0x8065d8b4 +8065da7c RKNet::ITEMHandler::GetModeRelatedInt +8065db48 0x8065db48 +8065dc4c RKNet::ITEMHandler::SetItemAndMode +8065dca8 0x8065dca8 +8065dd68 RKNet::ITEMHandler::SetDraggedItemAndMode +8065ddc4 0x8065ddc4 +8065dea4 RKNet::ITEMHandler::GetStoredItem +8065df38 RKNet::ITEMHandler::GetDraggedItem +8065dfec RKNet::ITEMHandler::GetStoredItemMode +8065e080 RKNet::ITEMHandler::GetDraggedItemMode +8065e134 RKNet::ITEMHandler::GetTimer +8065e1e4 RKNet::ITEMHandler::IsPlayerConnected +8065e1f0 RKNet::ITEMHandler::IsItemNew +8065e290 RKNet::ITEMHandler::IsDraggingItem +8065e36c RKNet::ITEMHandler::HasStartedDraggingItem +8065e678 0x8065e678 +8065e8b4 RKNet::ITEMHandler::__dt +8065e8f4 RKNet::ITEMHandler::ExportSendPackets +8065e9c4 RKNet::ITEMHandler::ImportNewPackets +8065ed28 RKNet::ITEMHandler::UpdateItemStatusAndSums +8065f2cc RKNet::ITEMHandler::AcknowledgeAid +8065f530 RKNet::ITEMHandler::UpdateLocalPlayersItems +8065f5c0 RKNet::ITEMHandler::UpdateStoredItem +8065f9fc RKNet::ITEMHandler::UpdateDraggedItem +8065fcf0 RKNet::ITEMHandler::UpdateLocalPlayers +80660364 RKNet::ItemHandler::GetStoredItemCount +80660654 0x80660654 +80660694 RKNet::USERHandler::CreateInstance +80660714 RKNet::USERHandler::DestroyInstance +80660768 RKNet::USERHandler::Prepare +80660860 RKNet::USERHandler::Reset +806608dc RKNet::USERHandler::Update +806609d8 RKNet::USERHandler::CopySendToPacketHolder +80660a1c RKNet::USERHandler::ProcessPlayerDisconnect +80660b08 0x80660b08 +80660b74 0x80660b74 +80660b84 0x80660b84 +80660ba4 0x80660ba4 +80660c3c 0x80660c3c +80660c9c RKNet::USERHandler::SetSendVR +80660ce0 RKNet::USERHandler::SetSendBR +80660d24 RKNet::USERHandler::__ct +80660d80 RKNet::USERHandler::__dt +80660dd8 RKNet::USERHandler::ImportNewPackets +80660ed4 0x80660ed4 +80660f28 RKNet::USERHandler::CreateSendPacket +806610b0 ServerMgr::__dt +806611f8 0x806611f8 +80661254 ServerMgr::DestroyInstance +80661350 ServerMgr::CreateInstance +806613b4 ServerMgr::__ct +8066154c 0x8066154c +80661570 0x80661570 +806615b0 0x806615b0 +80661618 0x80661618 +8066171c 0x8066171c +806617e8 0x806617e8 +806617fc 0x806617fc +80661840 ServerMgr::GetServerState +80661848 ServerMgr::GetState +80661850 0x80661850 +8066186c 0x8066186c +80661878 ServerMgr::GetError +80661880 ServerMgr::CountFriendsToInviteViaMsgBoard +80661994 0x80661994 +8066199c 0x8066199c +806619a4 0x806619a4 +80661b00 ServerMgr::Update +80661b40 ServerMgr::Update_switch +80661b44 ServerMgr::Update_caseD_1 +80661b68 ServerMgr::Update_caseD_8 +80661b70 ServerMgr::Update_caseD_16 +80661b78 ServerMgr::Update_caseD_9 +80661c90 ServerMgr::Update_caseD_3 +80661fbc ServerMgr::Update_caseD_0 +80661fd0 0x80661fd0 +806620f4 0x806620f4 +80662510 0x80662510 +80662550 0x80662550 +80662590 BundleSortProc +806625a0 0x806625a0 +806625a8 0x806625a8 +80662684 0x80662684 +80662688 0x80662688 +806626f8 0x806626f8 +806628ec 0x806628ec +806629b4 0x806629b4 +80662a74 0x80662a74 +80662c40 0x80662c40 +80662cdc 0x80662cdc +80663058 0x80663058 +80663310 0x80663310 +80663374 0x80663374 +806635c4 0x806635c4 +80663638 0x80663638 +80663848 0x80663848 +80663b6c 0x80663b6c +80663cb4 0x80663cb4 +80663d58 ServerMgr::GetRKG +80663e8c 0x80663e8c +806640e8 0x806640e8 +80664154 0x80664154 +8066455c 0x8066455c +80664650 0x80664650 +80664678 0x80664678 +80664908 0x80664908 +80664a18 ServerMgr::CheckNWC24Available +80664a24 0x80664a24 +80664b84 0x80664b84 +80664c2c 0x80664c2c +80664cbc 0x80664cbc +80664d58 0x80664d58 +80664dc4 ServerMgr::HasCourseNewFriendRecord +80664eb4 0x80664eb4 +80664f08 0x80664f08 +80665094 0x80665094 +80665110 0x80665110 +80665174 ServerMgr::GetCompetitionInfo +806652a0 0x806652a0 +806652f0 0x806652f0 +80665300 0x80665300 +806653cc ServerMgr::GetSpecialGhostInfo +806653e8 0x806653e8 +80665468 0x80665468 +80665bf8 0x80665bf8 +80665f04 0x80665f04 +80665fd0 0x80665fd0 +80666090 0x80666090 +8066636c 0x8066636c +80666458 0x80666458 +806665e4 0x806665e4 +80666630 0x80666630 +806668e4 0x806668e4 +806669fc 0x806669fc +80666bf8 0x80666bf8 +80666d4c 0x80666d4c +80666ef0 0x80666ef0 +806670e0 0x806670e0 +806671ac 0x806671ac +8066731c 0x8066731c +806673f8 0x806673f8 +806674c8 0x806674c8 +80667750 0x80667750 +80667800 0x80667800 +80667968 0x80667968 +80667a08 0x80667a08 +80667b60 0x80667b60 +80667d48 0x80667d48 +80667e2c 0x80667e2c +80668158 0x80668158 +806682e4 0x806682e4 +80668464 0x80668464 +806686a8 0x806686a8 +80668840 0x80668840 +80668ae4 0x80668ae4 +80668f48 0x80668f48 +806694a4 0x806694a4 +8066989c 0x8066989c +80669aa8 0x80669aa8 +80669bb0 0x80669bb0 +80669c2c 0x80669c2c +80669cdc 0x80669cdc +80669e24 0x80669e24 +80669ea8 0x80669ea8 +8066a00c 0x8066a00c +8066a0e4 0x8066a0e4 +8066a3e8 0x8066a3e8 +8066a518 ServerMgr::PublishMsgBoardAsync +8066a694 ServerMgr::PublishMsgBoard +8066a96c ServerMgr::InitCHJObj +8066abc0 0x8066abc0 +8066abd8 0x8066abd8 +8066abec ServerMgr::RequestMsgBoardPublish +8066ad3c 0x8066ad3c +8066aebc 0x8066aebc +8066af28 0x8066af28 +8066b0dc 0x8066b0dc +8066b29c 0x8066b29c +8066b3d8 0x8066b3d8 +8066b564 0x8066b564 +8066b6b0 0x8066b6b0 +8066b980 0x8066b980 +8066ba0c 0x8066ba0c +8066bab4 0x8066bab4 +8066bb64 0x8066bb64 +8066be04 0x8066be04 +8066c16c 0x8066c16c +8066c2dc 0x8066c2dc +8066c338 0x8066c338 +8066c488 0x8066c488 +8066c5d8 0x8066c5d8 +8066c728 0x8066c728 +8066c89c 0x8066c89c +8066c9f0 0x8066c9f0 +8066cb70 0x8066cb70 +8066cdb4 0x8066cdb4 +8066cef4 0x8066cef4 +8066d030 0x8066d030 +8066d0c8 0x8066d0c8 +8066d1f8 0x8066d1f8 +8066d2d4 0x8066d2d4 +8066d380 0x8066d380 +8066d3fc 0x8066d3fc +8066d468 0x8066d468 +8066d4d4 0x8066d4d4 +8066d524 0x8066d524 +8066d66c 0x8066d66c +8066d7a4 0x8066d7a4 +8066d918 0x8066d918 +8066d98c 0x8066d98c +8066d9c8 ServerMgr::CreateRKGFromRKG +8066dacc ServerMgr::CheckGhostDataValidity +8066dba0 0x8066dba0 +8066dc20 0x8066dc20 +8066dc28 0x8066dc28 +8066dce0 0x8066dce0 +8066dcf0 0x8066dcf0 +8066ddc8 0x8066ddc8 +8066dec0 0x8066dec0 +8066df28 0x8066df28 +8066df40 0x8066df40 +8066df64 0x8066df64 +8066df6c 0x8066df6c +8066dfc0 0x8066dfc0 +8066e0e4 0x8066e0e4 +8066e370 0x8066e370 +8066e41c 0x8066e41c +8066e6e4 0x8066e6e4 +8066e808 0x8066e808 +8066e96c 0x8066e96c +8066e978 0x8066e978 +8066e9cc 0x8066e9cc +8066ea20 0x8066ea20 +8066ea64 0x8066ea64 +8066ea6c 0x8066ea6c +8066eabc 0x8066eabc +8066eac4 0x8066eac4 +8066eae4 0x8066eae4 +8066eb24 0x8066eb24 +8066eb70 0x8066eb70 +8066ec80 0x8066ec80 +8066ecd8 0x8066ecd8 +8066ede4 0x8066ede4 +8066ef50 0x8066ef50 +8066f0fc 0x8066f0fc +8066f108 0x8066f108 +8066f1a0 0x8066f1a0 +8066f20c 0x8066f20c +8066f218 0x8066f218 +8066f22c 0x8066f22c +8066fa68 0x8066fa68 +8066fa94 0x8066fa94 +8066fab8 0x8066fab8 +8066fac4 0x8066fac4 +8066facc 0x8066facc +8066fad4 0x8066fad4 +8066fadc 0x8066fadc +8066fc1c 0x8066fc1c +8066fc64 0x8066fc64 +8066fce0 0x8066fce0 +8066fe80 0x8066fe80 +8066ff4c 0x8066ff4c +8066fff4 0x8066fff4 +8067011c 0x8067011c +806701a8 0x806701a8 +8067022c 0x8067022c +80670328 0x80670328 +80670400 0x80670400 +80670490 0x80670490 +80670584 0x80670584 +8067061c 0x8067061c +80670700 0x80670700 +80670800 0x80670800 +8067084c 0x8067084c +806708f8 0x806708f8 +80670a78 0x80670a78 +80670b34 0x80670b34 +80670bb4 0x80670bb4 +80670c20 0x80670c20 +80670c84 0x80670c84 +80670c98 0x80670c98 +80670d40 0x80670d40 +80670e28 0x80670e28 +80670ec4 0x80670ec4 +80670edc 0x80670edc +80670f08 0x80670f08 +80670f14 0x80670f14 +80670f1c 0x80670f1c +80670fdc 0x80670fdc +806710e8 0x806710e8 +806710ec 0x806710ec +80671250 0x80671250 +806712c4 0x806712c4 +80671348 0x80671348 +80671414 0x80671414 +80671730 0x80671730 +806717e8 0x806717e8 +80671868 0x80671868 +806718c0 0x806718c0 +80671908 0x80671908 +80671918 0x80671918 +80671af0 0x80671af0 +80671ca8 0x80671ca8 +80672030 0x80672030 +806721f4 0x806721f4 +8067247c 0x8067247c +80672640 0x80672640 +80672824 0x80672824 +80672a08 0x80672a08 +80672b14 0x80672b14 +80672d38 0x80672d38 +80672e44 0x80672e44 +80673188 0x80673188 +806732b0 0x806732b0 +80673350 0x80673350 +806734dc 0x806734dc +8067356c 0x8067356c +806735bc 0x806735bc +806735e8 0x806735e8 +80673600 0x80673600 +8067367c 0x8067367c +8067369c 0x8067369c +806736e0 0x806736e0 +80673748 0x80673748 +806737bc 0x806737bc +80673844 Page::EndExitState +80673848 0x80673848 +8067384c 0x8067384c +80673874 0x80673874 +8067388c 0x8067388c +80673c3c 0x80673c3c +80673d30 0x80673d30 +80673dcc 0x80673dcc +80673ed8 0x80673ed8 +80674058 0x80674058 +8067421c 0x8067421c +80674234 0x80674234 +8067429c 0x8067429c +806742e4 0x806742e4 +806742f0 0x806742f0 +806742fc 0x806742fc +80674308 0x80674308 +80674338 0x80674338 +80674368 0x80674368 +80674398 0x80674398 +806743b8 0x806743b8 +806744d0 0x806744d0 +80674570 0x80674570 +806746fc 0x806746fc +80674750 0x80674750 +80674768 0x80674768 +806747e4 0x806747e4 +80674804 0x80674804 +80674814 0x80674814 +80674870 0x80674870 +806748e4 0x806748e4 +80674a38 0x80674a38 +80674a3c 0x80674a3c +80674b34 0x80674b34 +80674bcc 0x80674bcc +80674c3c 0x80674c3c +80674c9c 0x80674c9c +80674d34 0x80674d34 +80674d6c 0x80674d6c +80674da0 0x80674da0 +80674e84 0x80674e84 +80674ee4 0x80674ee4 +80674ef4 0x80674ef4 +80675104 0x80675104 +806751e8 0x806751e8 +806754c0 0x806754c0 +80675698 0x80675698 +8067569c 0x8067569c +806756a0 0x806756a0 +80675804 0x80675804 +806758fc 0x806758fc +80675a08 0x80675a08 +80675b10 0x80675b10 +80675b4c 0x80675b4c +80675b5c 0x80675b5c +80675b74 0x80675b74 +80675bc0 0x80675bc0 +80675c34 0x80675c34 +80675cc8 0x80675cc8 +80675cd0 0x80675cd0 +80675e04 Page::EndExitState +80675e08 0x80675e08 +80675e0c 0x80675e0c +80676144 0x80676144 +80676148 0x80676148 +80676150 0x80676150 +80676158 0x80676158 +80676160 0x80676160 +80676168 0x80676168 +80676170 0x80676170 +80676178 0x80676178 +80676180 0x80676180 +80676228 0x80676228 +80676310 0x80676310 +80676318 0x80676318 +80676324 0x80676324 +80676330 0x80676330 +8067633c 0x8067633c +80676348 0x80676348 +80676378 0x80676378 +806763a8 0x806763a8 +806763d8 0x806763d8 +80676408 0x80676408 +80676438 0x80676438 +80676464 0x80676464 +80676470 0x80676470 +80676478 0x80676478 +80676480 0x80676480 +80676494 0x80676494 +80676674 0x80676674 +80676774 thunk_0x801de348 +80676778 0x80676778 +806767bc 0x806767bc +80676824 0x80676824 +806768ac 0x806768ac +806768b4 0x806768b4 +806769b8 Page::EndExitState +806769bc 0x806769bc +806769c0 0x806769c0 +80676ca4 0x80676ca4 +80676ca8 0x80676ca8 +80676cb0 0x80676cb0 +80676cb8 0x80676cb8 +80676cc0 0x80676cc0 +80676cc8 0x80676cc8 +80676cd0 0x80676cd0 +80676cd8 0x80676cd8 +80676ce0 0x80676ce0 +80676d88 0x80676d88 +80676e70 Effects::Mgr::GetRuntimeTypeInfo +80676e7c EffectsMgrcpp_sinit_ +80676e90 Effects::MGWhiteFog::__ct +80676f00 Effects::MGWhiteFog::__dt +80676f40 Effects::MGWhiteFog::Update +80676fc0 Effects::MGWhiteFog::UpdateEffect +8067702c Effects::MGWhiteFog::Kill +80677040 Effects::Mgr::CreateInstance +806770f8 Effects::Mgr::Init +80677468 Effects::Mgr::Reset +8067766c Effects::Sub9d8::__dt +806776ac Effects::Mgr::LoadRaceEffects +8067806c Effects::Mgr::CreatePlayerEffects +806780f8 Effects::Mgr::CreateEffects::Items +80678138 Effects::Mgr::LoadObjectEffect +8067855c 0x8067855c +806785c4 Effects::Mgr::InitRace +80678700 Effects::Mgr::Update +8067879c 0x8067879c +80678818 Effects::Mgr::CalcPlayerEffects +806789bc Effects::Mgr::UpdatePlayersVisibility +80678aec Effects::Mgr::Draw +8067926c 0x8067926c +80679484 0x80679484 +806795cc Object::GetClipInfo +806795d4 Effects::Mgr::UpdatePlayerFromWheelCollision +806795f0 Effects::Mgr::UpdatePlayerFromKartCollision +80679620 Effects::Mgr::GetMenuEffectByIdx +80679628 Effects::Mgr::CalcEffect1 +80679648 Effects::Mgr::DrawEffect1 +8067966c Effects::Mgr::DrawSelfItem +8067981c 0x8067981c +80679838 Effects::Mgr::IsEveryoneLookingForwards +80679894 Effects::Mgr::IsMTOrPlayer0xF4 +806798d0 0x806798d0 +8067998c Effects::Sub9d8::Update +80679c34 0x80679c34 +80679da8 0x80679da8 +80679de8 dGeomEnable +80679df8 0x80679df8 +80679efc ObjectCollidable::__dt +80679f3c Object::__dt +80679f7c Objects::FlamePoleEff::OnStart +80679f88 Objects::FlamePoleEff::Update +8067a140 0x8067a140 +8067a1e8 0x8067a1e8 +8067a264 0x8067a264 +8067a26c Objects::FlamePole::__ct +8067a664 Vec3::EulerFromMatrix +8067a674 ObjectExternKCL::__dt +8067a6b4 ObjectKCL::__dt +8067a6f4 0x8067a6f4 +8067a758 Objects::FlamePole::__dt +8067a80c Objects::FlamePole::OnStart +8067aae8 Objects::FlamePole::OnUpdate +8067adb8 Objects::FlamePole::UpdateModelMatrix +8067ae54 0x8067ae54 +8067ae68 0x8067ae68 +8067ae6c Objects::FlamePole::CalcOtherEntityDistance +8067affc 0x8067affc +8067b0b0 0x8067b0b0 +8067b0bc 0x8067b0bc +8067b164 0x8067b164 +8067b17c 0x8067b17c +8067b1c8 0x8067b1c8 +8067b224 0x8067b224 +8067b228 0x8067b228 +8067b22c 0x8067b22c +8067b230 0x8067b230 +8067b340 0x8067b340 +8067b3dc 0x8067b3dc +8067b3e0 0x8067b3e0 +8067b45c 0x8067b45c +8067b604 0x8067b604 +8067b730 Objects::FlamePole::GetTransformationMatrix +8067b7c8 0x8067b7c8 +8067b96c 0x8067b96c +8067b994 Objects::FlamePole::UpdateOtherEntityPosWithRot +8067ba00 Objects::FlamePole::IsCollidingNoTriangleCheckImpl +8067bd90 0x8067bd90 +8067c120 ObjectEffect::__dt +8067c178 Object::DoCalcShadowMtx +8067c180 Object::vf_0xa8 +8067c188 Object::IsLodDisabled +8067c190 Object::GetEntity +8067c198 Object::vf_0x84 +8067c1a0 Object::GetShadowListIdx +8067c1a8 Object::UpdateShadowScale +8067c1d4 Object::UpdateModelScale +8067c244 Object::GetShadowResName +8067c24c Object::GetLowResourceName +8067c254 Object::GetSubFileName +8067c2a8 Object::GetBRRESName +8067c2fc Object::GetName +8067c350 do_nothing_7d8 +8067c354 do_nothing_7dc +8067c358 ObjectKCL::GetScnObjDrawOptionsIdx +8067c360 ObjectExternKCL::UpdateKCL +8067c368 ObjectExternKCL::IsCollidingNoTerrainInfo +8067c464 ObjectExternKCL::HasCurrentCollision +8067c46c ObjectExternKCL::vf_0x13c +8067c474 ObjectExternKCL::IsCollidingAddEntryNoTerrainInfo +8067c570 ObjectExternKCL::HasCollision +8067c578 ObjectExternKCL::IsDriveable +8067c580 ObjectExternKCL::vf_0xfc +8067c67c ObjectExternKCL::IsCollidingAddEntry +8067c68c ObjectExternKCL::IsCollidingNoTerrainInfo(no radius) +8067c744 ObjectExternKCL::IsCollidingAddEntryNoTerrainInfo(no radius) +8067c7fc ObjectExternKCL::vf_0xec +8067c8b4 ObjectExternKCL::IsCollidingAddEntry(no radius) +8067c96c ObjectExternKCL::IsCollidingNoTerrainInfoNoTriangleCheck +8067ca68 ObjectExternKCL::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +8067cb64 ObjectExternKCL::IsColliding +8067cc60 ObjectExternKCL::IsCollidingAddEntryNoTriangleCheck +8067cc70 ObjectExternKCL::vf_0xc0 +8067cd28 ObjectExternKCL::vf_0xc4 +8067cde0 ObjectExternKCL::vf_0xc8 +8067ce98 ObjectExternKCL::vf_0xcc +8067cf50 ObjectExternKCL::UpdateOtherEntityPos +8067cfa4 ObjectExternKCL::SetObjInfoCalcBit +8067cfb4 ObjectExternKCL::GetPeriod +8067cfc0 ObjectExternKCL::GetPosition +8067cfc8 ObjectExternKCL::UpdateDiffPosVector +8067cff4 ObjectExternKCL::vf_0xb4 +8067d008 ObjectExternKCL::UpdateCollision +8067d01c Objects::FlamePole::vf__0x11c +8067d028 Objects::FlamePole::vf_0x108 +8067d034 Objects::FlamePole::AreItemsAllowed +8067d03c Objects::FlamePole::GetCollisionDiameter +8067d080 Objects::FlamePole::LoadAnimations +8067d100 0x8067d100 +8067d108 Objects::FlamePole::GetPropertiesBitfield +8067d110 Object::GetPosition +8067d118 ObjectCollidable::GetCollisionDiameter +8067d230 ObjectCollidable::GetSolidityCenter +8067d250 ObjectCollidable::InitEntity +8067d2ac ObjectCollidable::IsSolid +8067d2b4 ObjectCollidable::GetCollisionTranslation +8067d2c0 ObjectCollidable::CheckCollision +8067d314 ObjectCollidable::OnCollision +8067d31c ObjectCollidable::OnItemCollision +8067d324 ObjectCollidable::GetScnObjDrawOptionsIdx +8067d32c Objects::FlamePoleEff::LoadAnimations +8067d384 Objects::FlamePoleEff::vf_0xec +8067d38c Objects::FlamePoleEff::GetBRRESName +8067d398 Objects::FlamePoleEff::GetPropertiesBitfield +8067d3a0 Objects::FlamePoleEff::__dt +8067d3e0 Objects::FlamePole::__dt(thunk) +8067d3e8 0x8067d3e8 +8067d4c8 0x8067d4c8 +8067d99c 0x8067d99c +8067da10 0x8067da10 +8067dcd8 0x8067dcd8 +8067e2b4 0x8067e2b4 +8067e460 ObjectKCL::vf_0x111c +8067e468 ObjectKCL::vf_0x1118 +8067e46c ObjectKCL::UpdateOtherEntityPos +8067e470 ObjectKCL::SetObjInfoCalcBit +8067e474 ObjectKCL::CalcOtherEntityDistance +8067e478 ObjectKCL::vf_0x108 +8067e484 ObjectKCL::AreItemsAllowed +8067e48c ObjectKCL::UpdateKCL +8067e490 ObjectKCL::GetCollisionDiameter +8067e49c ObjectKCL::InitCollision +8067e4a0 0x8067e4a0 +8067e4a4 0x8067e4a4 +8067e4a8 0x8067e4a8 +8067e4ac 0x8067e4ac +8067e4b0 0x8067e4b0 +8067e4b8 0x8067e4b8 +8067e4c0 0x8067e4c0 +8067e4c8 0x8067e4c8 +8067e4d0 0x8067e4d0 +8067e4d4 0x8067e4d4 +8067e4d8 0x8067e4d8 +8067e4dc 0x8067e4dc +8067e4e0 0x8067e4e0 +8067e4e8 0x8067e4e8 +8067e4f0 0x8067e4f0 +8067e4f8 0x8067e4f8 +8067e500 0x8067e500 +8067e504 0x8067e504 +8067e508 0x8067e508 +8067e50c 0x8067e50c +8067e510 0x8067e510 +8067e518 0x8067e518 +8067e558 0x8067e558 +8067f334 0x8067f334 +80680110 0x80680110 +80680eec 0x80680eec +80681cc8 0x80681cc8 +806820e8 0x806820e8 +80682500 0x80682500 +80682804 0x80682804 +80682afc 0x80682afc +80682cf4 0x80682cf4 +80682d58 0x80682d58 +80682e18 0x80682e18 +80682f34 0x80682f34 +806832e0 0x806832e0 +806832e4 0x806832e4 +806832e8 0x806832e8 +806832ec 0x806832ec +80683338 0x80683338 +80683378 0x80683378 +8068351c 0x8068351c +80683544 0x80683544 +806835a4 0x806835a4 +80683838 0x80683838 +806838d0 ObjectExternKCL::UpdateOtherEntityPosWithRot +806838d4 ObjectExternKCL::vf_0x108 +806838e0 ObjectExternKCL::AreItemsAllowed +806838e8 ObjectExternKCL::GetCollisionDiameter +80683928 ObjectExternKCL::GetYScale +80683930 0x80683930 +80683938 0x80683938 +80683984 0x80683984 +8068398c 0x8068398c +80683994 0x80683994 +8068399c obj_gnd_sphere::__ct +80683b7c 0x80683b7c +80683c20 0x80683c20 +80683e14 0x80683e14 +80683e18 0x80683e18 +80684024 0x80684024 +80684064 0x80684064 +8068432c 0x8068432c +80684388 0x80684388 +80684770 0x80684770 +80684814 0x80684814 +80684924 0x80684924 +806849d8 0x806849d8 +80684a28 0x80684a28 +80684a78 0x80684a78 +80684ac8 0x80684ac8 +80684b18 0x80684b18 +80684b68 0x80684b68 +80684bb8 0x80684bb8 +80684c08 0x80684c08 +80684c58 0x80684c58 +80684ca8 0x80684ca8 +80684e78 0x80684e78 +806855f0 0x806855f0 +806856fc 0x806856fc +80685700 0x80685700 +80685704 0x80685704 +80685708 0x80685708 +8068570c 0x8068570c +80685714 0x80685714 +8068571c 0x8068571c +80685724 0x80685724 +8068572c 0x8068572c +80685730 0x80685730 +80685734 0x80685734 +80685738 0x80685738 +8068573c 0x8068573c +80685744 0x80685744 +8068574c 0x8068574c +80685754 0x80685754 +8068575c 0x8068575c +80685760 0x80685760 +80685764 0x80685764 +80685768 0x80685768 +8068576c 0x8068576c +80685774 0x80685774 +80685904 0x80685904 +80685954 0x80685954 +806859a4 0x806859a4 +806859f4 0x806859f4 +80685a44 0x80685a44 +80685a94 0x80685a94 +80685ae4 0x80685ae4 +80685b34 0x80685b34 +80685b84 0x80685b84 +80685bd4 0x80685bd4 +80685db4 0x80685db4 +80685f44 0x80685f44 +80685f94 0x80685f94 +80685fe4 0x80685fe4 +80686034 0x80686034 +80686084 0x80686084 +806860d4 0x806860d4 +80686124 0x80686124 +80686174 0x80686174 +806861c4 0x806861c4 +80686214 0x80686214 +80686400 0x80686400 +8068658c 0x8068658c +806865dc 0x806865dc +8068662c 0x8068662c +8068667c 0x8068667c +806866cc 0x806866cc +8068671c 0x8068671c +8068676c 0x8068676c +806867bc 0x806867bc +8068680c 0x8068680c +8068685c 0x8068685c +80686b60 0x80686b60 +80686cec 0x80686cec +80686d3c 0x80686d3c +80686d8c 0x80686d8c +80686ddc 0x80686ddc +80686e2c 0x80686e2c +80686e7c 0x80686e7c +80686ecc 0x80686ecc +80686f1c 0x80686f1c +80686f6c 0x80686f6c +80686fbc 0x80686fbc +806872c8 0x806872c8 +8068733c 0x8068733c +806874f4 0x806874f4 +806874fc obj_gnd_wave1::__ct +806876e0 0x806876e0 +80687784 0x80687784 +80687940 0x80687940 +80687944 obj_gnd_wave2::__ct +80687b5c 0x80687b5c +80687c00 0x80687c00 +80687da8 0x80687da8 +80687dac 0x80687dac +80687fdc 0x80687fdc +80688080 0x80688080 +8068854c 0x8068854c +80688550 0x80688550 +80688730 0x80688730 +806887d4 0x806887d4 +80688a50 0x80688a50 +80688a54 Effects::Items::__ct +80688dac Effects::Items::__dt +80688dec Effects::Items::Init +80688df8 0x80688df8 +80688dfc Effects::Items::CreateKouraTailGEffect +80688e50 Effects::Items::CreateKouraTailREffect +80688ea4 Effects::Items::CreateKouraTailBEffect +80688ef8 0x80688ef8 +80688f20 0x80688f20 +80688f48 0x80688f48 +80688f68 Effects::Items::FadeKouraTailGEffect +80688f94 Effects::Items::FadeKouraTailREffect +80688fc0 Effects::Items::FadeKouraTailBEffect +80688fec Effects::Items::KillKouraTailGEffect +80689018 Effects::Items::KillKouraTailREffect +80689044 Effects::Items::KillKouraTailBEffect +80689070 Effects::Items::CreateKouraBrkGEffect +806890e8 Effects::Items::CreateKouraBrkREffect +80689160 Effects::Items::CreateItemVanEffect +80689180 Effects::Items::CreateBombHeiEffect +806892c0 Effects::Items::CreateHaneKouraEffect +806892fc Effects::Items::CreateBombHeiSparkEffect +80689394 Effects::Items:KillBombHeiEffect +806893c0 Effects::Items::CreateBananaEffect +806894cc 0x806894cc +80689560 Effects::Items::CreateKaminariGumoPreEffect +80689650 Effects::Items::KillKaminariGumoPreEffect +8068966c Effects::Items::CreateKaminariGumoVanEffect +80689704 Effects::Items::UpdateKaminariGumoVanEffect +80689880 Effects::Items::CreateKouraTailEffect +80689b0c 0x80689b0c +80689b10 Effects::Player::__ct +8068a3a8 Effects::Player::GetRacedata +8068a3b4 Effects::Player::GetCourseId +8068a3bc Effects::Player::Color::__ct +8068a3c0 Effects::Player::Color::__dt +8068a400 Effects::Player::__dt +8068a520 Effects::Player::Init +8068a5d0 Effects::Player::Reset +8068abbc Effects::Player::LoadEffects +8068c2f4 Effects::Player::LoadEffects_switch +8068c2f8 Effects::Player::LoadEffects_case0 +8068c3c4 Effects::Player::LoadEffects_case1 +8068c490 Effects::Player::LoadEffects_case2 +8068c55c Effects::Player::LoadEffects_case3 +8068c628 Effects::Player::LoadEffects_case4 +8068c6f4 Effects::Player::LoadEffects_case5 +8068c7c0 Effects::Player::LoadEffects_case6 +8068c88c Effects::Player::LoadEffects_case7 +8068c958 Effects::Player::LoadEffects_case8 +8068ca24 Effects::Player::LoadEffects_case9 +8068caf0 Effects::Player::LoadEffects_casea +8068cbbc Effects::Player::LoadEffects_caseb +8068f8d0 Effects::Player::Toggle +8068f8fc Effects::Player::Update +8068fa0c Effects::Player::UpdateValues +80690234 0x80690234 +80690884 Effects::Player::UpdateItemEffect +8069117c 0x8069117c +806911e4 0x806911e4 +80691430 0x80691430 +8069146c Effects::Player::KillEffects +80691720 Effects::Player::UpdateNonItemEffects +80692868 0x80692868 +80692a94 0x80692a94 +80692b34 0x80692b34 +80692bb4 0x80692bb4 +80692cb0 0x80692cb0 +80692dac 0x80692dac +80692e6c 0x80692e6c +80692f2c 0x80692f2c +8069303c 0x8069303c +8069314c Effects::Player::CreateAndUpdateEffectsByIdx +80693300 Effects::Player::FollowFadeEffectsByIdx +806934f4 Effects::Player::CreateEffectsByIdx +80693568 Effects::Player::UpdateEffectsByIdx +806936a4 Effects::Player::KillEffectsByIdx +80693758 Effects::Player::UpdateCollisionEffects +806938b8 Effects::Player::UpdateCollisionEffects_caseD_0 +806938c8 Effects::Player::UpdateCollisionEffects_caseD_1 +806938d8 Effects::Player::UpdateCollisionEffects_caseD_2 +806938e8 Effects::Player::UpdateCollisionEffects_caseD_3 +806938f8 Effects::Player::UpdateCollisionEffects_caseD_4 +80693908 Effects::Player::UpdateCollisionEffects_caseD_5 +80693918 Effects::Player::UpdateCollisionEffects_caseD_6 +80693928 Effects::Player::UpdateCollisionEffects_caseD_7 +80693a50 Effects::Player::UpdateCollisionEffects_case2D_0 +80693a60 Effects::Player::UpdateCollisionEffects_case2D_1 +80693a70 Effects::Player::UpdateCollisionEffects_case2D_2 +80693a80 Effects::Player::UpdateCollisionEffects_case2D_3 +80693a90 Effects::Player::UpdateCollisionEffects_case2D_4 +80693aa0 Effects::Player::UpdateCollisionEffects_case2D_5 +80693ab0 Effects::Player::UpdateCollisionEffects_case2D_6 +80693ac0 Effects::Player::UpdateCollisionEffects_case2D_7 +80693b74 Effects::Player::UpdateVehicleEffects +80693ba0 Effects::Player::UpdateKartEffects +80694ae8 Effects::Player::UpdateBikeEffects +80695828 Effects::Player::UpdateJumpSmokeEffects +806962b0 0x806962b0 +8069648c 0x8069648c +8069676c 0x8069676c +806968b8 0x806968b8 +80696c8c 0x80696c8c +80696f0c Effects::Player::UpdateStartUpEffects +806972c0 Effects::Player::UpdateSlipStreamEffects +80697670 Effects::Player::UpdateGasSmokeEffects +80697bb8 0x80697bb8 +80697d34 0x80697d34 +80697e64 0x80697e64 +806981c0 0x806981c0 +80698308 0x80698308 +80698368 Effects::Player::UpdateWaterEffects +80698a90 0x80698a90 +80698c34 0x80698c34 +80698c98 Effects::Player::UpdateInBillEffects +806996b4 0x806996b4 +8069971c Effects::Player::UpdateThunderEffects +80699e7c 0x80699e7c +8069a08c 0x8069a08c +8069a424 Effects::Player::Create228Effect +8069a6d4 Effects::Player::Create25CEffect +8069af5c 0x8069af5c +8069af94 0x8069af94 +8069b208 0x8069b208 +8069b490 0x8069b490 +8069b868 Effects::Player::UpdateInkEffect +8069be5c 0x8069be5c +8069bee8 0x8069bee8 +8069bfa0 0x8069bfa0 +8069c6c4 0x8069c6c4 +8069cb54 Effects::Player::UpdateFromWheelCollision +8069ccd4 Effects::Player::UpdateFromWheelCollision_switch +8069ccd8 Effects::Player::UpdateFromWheelCollision_caseD_0 +8069ccf4 Effects::Player::UpdateFromWheelCollision_caseD_1 +8069cd10 Effects::Player::UpdateFromWheelCollision_caseD_4 +8069cd2c Effects::Player::UpdateFromWheelCollision_caseD_5 +8069cd48 Effects::Player::UpdateFromWheelCollision_caseD_3 +8069cd60 Effects::Player::UpdateFromWheelCollision_caseD_2 +8069cd74 Effects::Player::UpdateFromWheelCollision_caseD_6 +8069cd88 Effects::Player::UpdateFromWheelCollision_caseD_7 +8069d1d8 Effects::Player::UpdateFromKartCollision +8069d380 0x8069d380 +8069d398 0x8069d398 +8069d4b0 0x8069d4b0 +8069d550 Effects::Player::CreateAndUpdateEffectsByIdxVelocity +8069d6e0 Effects::Player::FollowFadeEffectsByIdxVelocity +8069d840 0x8069d840 +8069d894 0x8069d894 +8069d8e8 0x8069d8e8 +8069d9c4 0x8069d9c4 +8069da28 0x8069da28 +8069db50 0x8069db50 +8069dc2c 0x8069dc2c +8069dc90 0x8069dc90 +8069dd6c 0x8069dd6c +8069ddd0 0x8069ddd0 +8069dec0 0x8069dec0 +8069df9c 0x8069df9c +8069e000 0x8069e000 +8069e0f0 0x8069e0f0 +8069e164 0x8069e164 +8069e218 0x8069e218 +8069e2f8 0x8069e2f8 +8069e35c 0x8069e35c +8069e484 0x8069e484 +8069e564 0x8069e564 +8069e5c8 0x8069e5c8 +8069e6f0 0x8069e6f0 +8069e78c 0x8069e78c +8069e7a8 0x8069e7a8 +8069e85c 0x8069e85c +8069e97c 0x8069e97c +8069ea04 0x8069ea04 +8069ea98 0x8069ea98 +8069ecb0 0x8069ecb0 +8069ecfc 0x8069ecfc +8069ede4 0x8069ede4 +8069ef2c 0x8069ef2c +8069f01c 0x8069f01c +8069f144 0x8069f144 +8069f190 0x8069f190 +8069f240 0x8069f240 +8069f330 0x8069f330 +8069f394 0x8069f394 +8069f410 0x8069f410 +8069f45c 0x8069f45c +8069f4c0 0x8069f4c0 +8069f63c 0x8069f63c +8069f8c0 0x8069f8c0 +8069fb08 0x8069fb08 +8069fb98 0x8069fb98 +8069fc28 0x8069fc28 +8069fcc4 0x8069fcc4 +8069fdc0 0x8069fdc0 +8069fe90 0x8069fe90 +8069ff2c 0x8069ff2c +806a0028 0x806a0028 +806a00f8 0x806a00f8 +806a0194 0x806a0194 +806a0290 0x806a0290 +806a0360 0x806a0360 +806a03e8 0x806a03e8 +806a0498 0x806a0498 +806a0540 0x806a0540 +806a05f0 0x806a05f0 +806a0698 0x806a0698 +806a070c 0x806a070c +806a07b0 0x806a07b0 +806a0860 0x806a0860 +806a0924 0x806a0924 +806a09d4 0x806a09d4 +806a0a98 0x806a0a98 +806a0b48 0x806a0b48 +806a0c0c 0x806a0c0c +806a0cbc 0x806a0cbc +806a0d80 0x806a0d80 +806a0e50 0x806a0e50 +806a0ef4 0x806a0ef4 +806a1048 0x806a1048 +806a11d8 0x806a11d8 +806a14f4 0x806a14f4 +806a1578 0x806a1578 +806a1904 0x806a1904 +806a1928 0x806a1928 +806a19ac 0x806a19ac +806a1d28 0x806a1d28 +806a1dac 0x806a1dac +806a1e1c Vec3::DivideByScalar +806a1e50 0x806a1e50 +806a1eac 0x806a1eac +806a1fa0 0x806a1fa0 +806a2164 Effects::Player::CreateRKHitEffect +806a221c Effects::Player::OnBushCollision +806a235c 0x806a235c +806a2370 Effects::Player::CreateSpinEffect +806a25a4 0x806a25a4 +806a2650 0x806a2650 +806a27ac 0x806a27ac +806a2858 0x806a2858 +806a29b4 0x806a29b4 +806a2a60 0x806a2a60 +806a2bbc 0x806a2bbc +806a2c68 0x806a2c68 +806a2dc4 0x806a2dc4 +806a2e38 0x806a2e38 +806a2edc 0x806a2edc +806a2f50 0x806a2f50 +806a2ff4 0x806a2ff4 +806a30a0 0x806a30a0 +806a3144 0x806a3144 +806a31b8 0x806a31b8 +806a325c 0x806a325c +806a332c 0x806a332c +806a33d0 0x806a33d0 +806a356c 0x806a356c +806a365c 0x806a365c +806a36e0 0x806a36e0 +806a3780 0x806a3780 +806a3804 0x806a3804 +806a38a8 0x806a38a8 +806a394c 0x806a394c +806a3a1c 0x806a3a1c +806a3a80 0x806a3a80 +806a3af8 0x806a3af8 +806a3b18 0x806a3b18 +806a3bc4 0x806a3bc4 +806a3c68 0x806a3c68 +806a3ccc 0x806a3ccc +806a3d3c 0x806a3d3c +806a3de0 Effects::Player::CreateKartBrakeBackwardsEffects +806a3ef4 Effects::Player::KillKartBrakeBackwardsEffects +806a4014 0x806a4014 +806a405c 0x806a405c +806a4100 Effects::Player::CreateBikeBrakeBackwardsEffects +806a41f4 Effects::Player::KillBikeBrakeBackwardsEffects +806a42f4 0x806a42f4 +806a4394 0x806a4394 +806a4470 0x806a4470 +806a4510 0x806a4510 +806a4590 0x806a4590 +806a464c Effects::Player::CreateStarEffect +806a4828 Effects::Player::UpdateStarEffect +806a4aa4 Effects::Player::CreateRKKiller +806a4be8 Effects::Player::UpdateRKKiller +806a4e1c 0x806a4e1c +806a4ea0 0x806a4ea0 +806a4f20 0x806a4f20 +806a4fa4 0x806a4fa4 +806a50c8 0x806a50c8 +806a5168 0x806a5168 +806a5244 0x806a5244 +806a5444 0x806a5444 +806a56c0 0x806a56c0 +806a58c0 0x806a58c0 +806a5b3c 0x806a5b3c +806a5d40 0x806a5d40 +806a5dec 0x806a5dec +806a5eb4 0x806a5eb4 +806a6044 0x806a6044 +806a6080 0x806a6080 +806a60a8 Effects::Player::UpdatePowEffect +806a62fc Effects::Player::UpdatePow1Effect +806a6500 0x806a6500 +806a65a4 0x806a65a4 +806a6720 0x806a6720 +806a6770 0x806a6770 +806a685c 0x806a685c +806a6978 0x806a6978 +806a6a7c Effects::Player::UpdateNiseBoxBiriEffect +806a6c4c 0x806a6c4c +806a6d4c 0x806a6d4c +806a6e10 0x806a6e10 +806a6eb4 0x806a6eb4 +806a6fe0 0x806a6fe0 +806a7084 0x806a7084 +806a7184 0x806a7184 +806a7228 0x806a7228 +806a7418 Effects::Player::TriggerPochaEffect +806a766c 0x806a766c +806a7694 0x806a7694 +806a76d4 Effects::Player::CreatePochaEffect +806a78b4 0x806a78b4 +806a7a88 0x806a7a88 +806a7b20 0x806a7b20 +806a7c38 0x806a7c38 +806a7cb8 0x806a7cb8 +806a7d88 0x806a7d88 +806a7e30 0x806a7e30 +806a7f78 0x806a7f78 +806a8190 0x806a8190 +806a8214 0x806a8214 +806a82b4 0x806a82b4 +806a8388 0x806a8388 +806a849c 0x806a849c +806a867c 0x806a867c +806a8694 0x806a8694 +806a8b34 0x806a8b34 +806a8c00 0x806a8c00 +806a9090 0x806a9090 +806a915c 0x806a915c +806a95ec 0x806a95ec +806a96b8 0x806a96b8 +806a9844 0x806a9844 +806a9858 0x806a9858 +806a99d0 0x806a99d0 +806a99e4 0x806a99e4 +806a9a58 0x806a9a58 +806a9a6c Effects::Player::CreateSandEffect +806a9ee4 Effects::Player::Color::__ct(args) +806a9ef8 Effects::Player::Color::operator= +806a9f1c 0x806a9f1c +806aa104 Effects::Player::CreateGrassEffect +806aa464 0x806aa464 +806aa640 Effects::Player::CreateSnowDirtEffect +806aa934 0x806aa934 +806aab00 0x806aab00 +806aabb0 Effects::Player::CreateSnowRoadEffect +806ab048 0x806ab048 +806ab2e0 Effects::Player::CreateWaterEffect +806ab564 0x806ab564 +806ab77c Effects::Player::CreateMudEffect +806aba88 0x806aba88 +806abc10 Effects::Player::CreateFlowerEffect +806abeac 0x806abeac +806ac034 Effects::Player::CreateStoneEffect +806ac2cc 0x806ac2cc +806ac450 0x806ac450 +806ac72c 0x806ac72c +806ac97c 0x806ac97c +806acd28 0x806acd28 +806ad294 Effects::Player::SetOffroadColors +806ae124 0x806ae124 +806ae294 0x806ae294 +806ae2dc 0x806ae2dc +806ae3f8 0x806ae3f8 +806ae440 0x806ae440 +806ae4c4 0x806ae4c4 +806ae4dc 0x806ae4dc +806ae7d8 0x806ae7d8 +806ae924 0x806ae924 +806aee74 0x806aee74 +806aef58 0x806aef58 +806aefd4 0x806aefd4 +806af210 Effects::Player::SetGessoEffectsVisibility +806af344 Effects::Player::UpdateGessoEffectsVisibility +806af420 0x806af420 +806af478 Vector3_rotate +806af558 0x806af558 +806af63c 0x806af63c +806af6b8 0x806af6b8 +806af81c Vec3::CalcYAxisRotMtx +806af994 0x806af994 +806afae8 0x806afae8 +806afc80 0x806afc80 +806afd58 0x806afd58 +806afe40 0x806afe40 +806affec 0x806affec +806b0130 0x806b0130 +806b021c 0x806b021c +806b0270 0x806b0270 +806b02d4 0x806b02d4 +806b0ef8 0x806b0ef8 +806b10a8 0x806b10a8 +806b113c 0x806b113c +806b1520 -bx^2+ax +806b1584 CreateParabola +806b15a8 0x806b15a8 +806b15ac 0x806b15ac +806b15b0 0x806b15b0 +806b15b4 0x806b15b4 +806b15b8 0x806b15b8 +806b1640 Effects::Mgr::CreateOneTimeEffect(pos) +806b16a0 Effects::Mgr::CreateOneTimeEffect(mtx) +806b1700 Effects::Mgr::CreateOneTimeEffect(pos, scale) +806b177c Effects::Mgr::CreateOneTimeEffect(mtx, scale) +806b17f8 0x806b17f8 +806b17fc Objects::Basabasa::__ct +806b1994 0x806b1994 +806b19f8 Objects::Basabasa::OnStart +806b1ba0 Objects::Basabasa::vf_0x10 +806b1ba4 Objects::Basabasa::Update +806b1c78 0x806b1c78 +806b1e00 0x806b1e00 +806b20a4 0x806b20a4 +806b23ec Objects::Basabasa::OnCollision +806b2590 Objects::Basabasa::OnItemCollision +806b2a24 Objects::Basabasa::UpdateShadow +806b2c48 Objects::BasabasaMgr::__ct +806b2e6c Objects::BasabasaMgr::__dt +806b2eac Objects::BasabasaMgr::OnStart +806b3038 Objects::BasabasaMgr::vf_0x10 +806b303c Objects::BasabasaMgr::Update +806b3190 Objects::BasabasaMgr::LoadClipInfo +806b3194 Objects::BasabasaMgr::LoadCollision +806b3198 Objects::BasabasaMgr::LoadRoute +806b319c Objects::BasabasaMgr::LoadModels +806b31a0 Objects::BasabasaMgr::GetPropertiesBitfield +806b31a8 Objects::Basabasa::__dt +806b3214 0x806b3214 +806b321c Objects::Basabasa::LoadAnimations +806b3260 Objects::Basabasa::GetName +806b326c Objects::Basabasa::GetSubFileName +806b3278 Objects::Basabasa::GetPropertiesBitfield +806b3280 Objects::Basabasa::__dt(thunk) +806b3288 Objects::CarA::__ct +806b33e0 0x806b33e0 +806b3444 Objects::CarA::__dt +806b34bc Objects::CarA::LoadModels +806b36bc Objects::CarA::LoadCollision +806b373c Objects::CarA::UpdateCollision +806b3858 Objects::CarA::OnStart +806b39d8 Objects::CarA::OnCollision +806b3ba4 Objects::CarA::OnItemCollision +806b3e44 Objects::CarA::Update +806b4074 0x806b4074 +806b4100 0x806b4100 +806b4124 0x806b4124 +806b4268 Objects::CarA::UpdateRoute +806b43b0 0x806b43b0 +806b43bc 0x806b43bc +806b448c 0x806b448c +806b4520 0x806b4520 +806b4844 0x806b4844 +806b48b4 0x806b48b4 +806b49cc 0x806b49cc +806b4a54 0x806b4a54 +806b4a5c Objects::CarA::LoadAnimations +806b4abc Objects::CarA::GetPropertiesBitfield +806b4ac4 MiiCreationParams::__dt +806b4b04 Objects::CarA::__dt(thunk) +806b4b0c 0x806b4b0c +806b4bec 0x806b4bec +806b4c2c 0x806b4c2c +806b4c5c 0x806b4c5c +806b4cdc 0x806b4cdc +806b4de4 0x806b4de4 +806b4dec 0x806b4dec +806b4f44 0x806b4f44 +806b4fa0 0x806b4fa0 +806b5018 0x806b5018 +806b508c 0x806b508c +806b510c 0x806b510c +806b51ec 0x806b51ec +806b5218 0x806b5218 +806b56a0 0x806b56a0 +806b5704 0x806b5704 +806b5770 0x806b5770 +806b59d8 0x806b59d8 +806b5cbc 0x806b5cbc +806b5ef0 0x806b5ef0 +806b6250 0x806b6250 +806b6374 0x806b6374 +806b6764 0x806b6764 +806b6cbc 0x806b6cbc +806b6f0c 0x806b6f0c +806b6f10 0x806b6f10 +806b6f14 0x806b6f14 +806b7168 0x806b7168 +806b73b0 0x806b73b0 +806b73b4 0x806b73b4 +806b73b8 0x806b73b8 +806b75f4 0x806b75f4 +806b7660 0x806b7660 +806b76f8 0x806b76f8 +806b7814 0x806b7814 +806b7954 0x806b7954 +806b795c 0x806b795c +806b79ac 0x806b79ac +806b79b4 0x806b79b4 +806b79b8 0x806b79b8 +806b79bc 0x806b79bc +806b79c4 0x806b79c4 +806b79d0 0x806b79d0 +806b79dc 0x806b79dc +806b79e4 0x806b79e4 +806b7a24 0x806b7a24 +806b7a28 0x806b7a28 +806b7a30 0x806b7a30 +806b7a38 Objects::CowBase::__ct +806b7a9c Objects::CowBase::__dt +806b7adc 0x806b7adc +806b7c9c 0x806b7c9c +806b7e24 Objects::CowBase::OnCollision +806b7f68 Objects::CowBase::OnItemCollision +806b8138 0x806b8138 +806b8250 0x806b8250 +806b83f4 Objects::CowBase::vf_0xf0 +806b854c 0x806b854c +806b86a0 0x806b86a0 +806b871c 0x806b871c +806b8838 0x806b8838 +806b893c 0x806b893c +806b8a00 0x806b8a00 +806b8ac4 0x806b8ac4 +806b8b4c 0x806b8b4c +806b8bf8 Objects::CowLeader::__ct +806b8d0c 0x806b8d0c +806b8d70 Objects::CowLeader::__dt +806b8ddc Objects::CowLeader::OnStart +806b8f00 Objects::CowLeader::Update +806b9228 0x806b9228 +806b92b0 0x806b92b0 +806b9350 0x806b9350 +806b93c4 0x806b93c4 +806b9594 0x806b9594 +806b95e8 0x806b95e8 +806b9850 Objects::CowLeader::vf_0xf0 +806b98bc 0x806b98bc +806b98c0 Objects::CowVassal::__ct +806b9b08 0x806b9b08 +806b9b6c Objects::CowVassal::__dt +806b9bd8 Objects::CowVassal::OnStart +806b9d20 Objects::CowVassal::Update +806ba060 0x806ba060 +806ba0f8 0x806ba0f8 +806ba1a4 0x806ba1a4 +806ba30c 0x806ba30c +806ba4a8 0x806ba4a8 +806ba544 0x806ba544 +806ba6cc Objects::CowGroup::__ct +806bab64 Objects::CowGroup::__dt +806baba4 Objects::CowGroup::OnStart +806babdc Objects::CowGroup::Update +806bac8c 0x806bac8c +806baebc Objects::CowGroup::LoadClipInfo +806baec0 Objects::CowGroup::LoadCollision +806baec4 Objects::CowGroup::LoadRoute +806baec8 Objects::CowGroup::LoadModels +806baecc Objects::CowGroup::GetPropertiesBitfield +806baed4 Objects::CowBase::vf_0xec +806baedc Objects::CowBase::LoadAnimations +806baf98 Objects::CowVassal::LoadRoute +806baf9c Objects::CowVassal::GetPropertiesBitfield +806bafa4 Objects::CowLeader::GetPropertiesBitfield +806bafac Object::GetGetPropertiesBitfield +806bafc0 Object::Update +806bb030 Objects::CowLeader::__dt(thunk) +806bb038 Objects::CowVassal::__dt(thunk) +806bb040 Objects::Cannon::__ct +806bb174 Objects::Cannon::LoadAnimations +806bb2bc Objects::Cannon::__dt +806bb308 Objects::Cannon::OnStart +806bb3fc Objects::Cannon::Update +806bb938 Objects::Cannon::OnActivation +806bba20 Objects::Cannon::vf_0xec +806bba28 0x806bba28 +806bba30 Objects::Cannon::GetScnObjDrawOptionsIdx +806bba38 0x806bba38 +806bbb2c 0x806bbb2c +806bbb6c 0x806bbb6c +806bbbec 0x806bbbec +806bbc80 0x806bbc80 +806bbcf4 0x806bbcf4 +806bbcf8 0x806bbcf8 +806bbdcc 0x806bbdcc +806bbdd4 0x806bbdd4 +806bbe18 0x806bbe18 +806bbe58 0x806bbe58 +806bbecc 0x806bbecc +806bbed0 0x806bbed0 +806bbed4 0x806bbed4 +806bbedc 0x806bbedc +806bbf2c 0x806bbf2c +806bbf50 Objects::HanachanPart::LoadModels +806bbf88 Objects::HanachanPart::OnStart +806bc014 Objects::HanachanPart::vf_0x100 +806bc01c Objects::HanachanPart::Update +806bc0a0 Objects::HanachanPart::OnCollision +806bc24c Objects::HanachanPart::OnItemCollision +806bc470 0x806bc470 +806bc594 0x806bc594 +806bc648 0x806bc648 +806bc6c4 0x806bc6c4 +806bca80 0x806bca80 +806bcba4 0x806bcba4 +806bcbc4 0x806bcbc4 +806bccd8 0x806bccd8 +806bcd00 0x806bcd00 +806bce20 0x806bce20 +806bcf20 0x806bcf20 +806bd078 nw4r::g3d::ICalcWorldCallback::__dt +806bd0b8 Objects::BossHanachanHead::CalcWorldCB::ExecCallbackB +806bd174 0x806bd174 +806bd180 Objects::BossHanachanHead::__ct +806bd274 Objects::HanachanPart::__dt +806bd2b4 0x806bd2b4 +806bd598 Objects::BossHanachanHead::LoadCollision +806bd610 Objects::BossHanachanHead::OnStart +806bd6b8 Objects::BossHanachanHead::Update +806bd85c Objects::BossHanachanHead::UpdateCollision +806bd9e0 0x806bd9e0 +806bdb30 0x806bdb30 +806bdbc8 0x806bdbc8 +806bdbd8 Objects::HanachanBody::LoadAnimations +806bdc84 Objects::HanachanBody::OnStart +806bdd14 0x806bdd14 +806bde68 Objects::Hanachan::__ct +806be940 0x806be940 +806be9a4 Objects::Hanachan::__dt +806bea3c Objects::Hanachan::OnStart +806bec6c Objects::Hanachan::Update +806befc4 0x806befc4 +806befcc 0x806befcc +806bf144 0x806bf144 +806bf2d4 0x806bf2d4 +806bf3a4 0x806bf3a4 +806bf654 Objects::Hanachan::vf_0xC(parent) +806bf658 0x806bf658 +806bf688 0x806bf688 +806bf6fc 0x806bf6fc +806bf960 0x806bf960 +806bf968 0x806bf968 +806bf9f0 0x806bf9f0 +806bfad8 0x806bfad8 +806bfb38 0x806bfb38 +806bfcec 0x806bfcec +806bfdb8 0x806bfdb8 +806bfe98 0x806bfe98 +806bfedc 0x806bfedc +806bff68 0x806bff68 +806c00dc 0x806c00dc +806c02e0 0x806c02e0 +806c03a8 0x806c03a8 +806c03c4 0x806c03c4 +806c04b4 0x806c04b4 +806c05f4 0x806c05f4 +806c0738 0x806c0738 +806c0808 0x806c0808 +806c0994 0x806c0994 +806c099c 0x806c099c +806c0b70 0x806c0b70 +806c0d5c 0x806c0d5c +806c0dec 0x806c0dec +806c0fd0 0x806c0fd0 +806c1238 0x806c1238 +806c1254 0x806c1254 +806c12b4 0x806c12b4 +806c1324 0x806c1324 +806c1394 0x806c1394 +806c1404 0x806c1404 +806c1558 0x806c1558 +806c1658 0x806c1658 +806c1848 0x806c1848 +806c1898 0x806c1898 +806c1acc 0x806c1acc +806c1cf4 0x806c1cf4 +806c1df0 nw4r::g3d::ICalcWorldCallback::ExecCallbackC +806c1df4 nw4r::g3d::ICalcWorldCallback::ExecCallbackA +806c1df8 Objects::Hanachan::UpdateModel +806c1dfc Objects::Hanachan::LoadClipInfo +806c1e00 Objects::Hanachan::LoadCollision +806c1e04 Objects::Hanachan::LoadModels +806c1e08 Objects::Hanachan::GetPropertiesBitfield +806c1e10 Objects::HanachanPart::vf_0x104 +806c1e18 Objects::HanachanPart::vf_0x84 +806c1e20 Objects::HanachanPart::UpdateModelMatrix +806c1ed8 Objects::HanachanPart::LoadRoute +806c1edc Objects::HanachanPart::GetPropertiesBitfield +806c1ee4 Objects::HanachanBody::__dt +806c1f24 Objects::HanachanBody::vf_0xfc +806c1f2c Objects::HanachanBody::vf_0xf8 +806c1f34 Objects::HanachanBody::vf_0x108 +806c1f3c 0x806c1f3c +806c1f58 0x806c1f58 +806c1f78 0x806c1f78 +806c1f80 Objects::HanachanBody::GetShadowResName +806c1f8c Objects::HanachanBody::GetSubFileName +806c1f94 Objects::HanachanPart::GetSubFileName +806c1fa0 Objects::BossHanachanHead::__dt +806c1fe0 Objects::BossHanachanHead::vf_0xfc +806c1ffc Objects::BossHanachanHead::vf_0xf8 +806c2004 Objects::BossHanachanHead::vf_0xf4 +806c2050 Objects::BossHanachanHead::vf_0xf0 +806c20b0 Objects::BossHanachanHead::vf_0xec +806c2130 Objects::BossHanachanHead::UpdateShadow +806c21a4 Objects::BossHanachanHead::vf_0x108 +806c21ac Objects::BossHanachanHead::LoadAnimations +806c2234 Objects::BossHanachanHead::GetBRRESName +806c2240 nw4r::g3d::ICalcWorldCallback::ExecCallbackB +806c2244 Objects::BossHanachanHead::CalcWorldCB::__dt +806c2284 Objects::BossHanachanHead::CalcWorldCB::ExecCallbackB(thunk) +806c228c Objects::BossHanachanHead::CalcWorldCB::__dt(thunk) +806c2294 Objects::Hanachan::__dt(thunk) +806c229c Objects::Heyho::__ct +806c2534 0x806c2534 +806c2598 Objects::Heyho::__dt +806c2604 Objects::Heyho::OnStart +806c2868 Objects::Heyho::vf_0x10 +806c286c Objects::Heyho::Update +806c2a98 Objects::Heyho::OnCollision +806c2c0c Objects::Heyho::OnItemCollision +806c2e18 Objects::Heyho::UpdateShadow +806c2f40 0x806c2f40 +806c2f44 obj_heyho_move_update +806c3188 obj_heyho_beforeJump +806c31a0 obj_heyho_jump_update +806c3534 0x806c3534 +806c35ac 0x806c35ac +806c37bc 0x806c37bc +806c3824 0x806c3824 +806c3a24 0x806c3a24 +806c3a9c 0x806c3a9c +806c3b24 0x806c3b24 +806c3bb0 Objects::Heyho::LoadAnimations +806c3c40 Objects::Heyho::vf_0xc +806c3c48 Objects::Heyho::UpdateCollision +806c3d28 Objects::Heyho::GetPropertiesBitfield +806c3d38 Objects::HighwayManager::__ct +806c4418 Objects::HighwayManager::__dt +806c44ec 0x806c44ec +806c475c Objects::HighwayManager::OnStart +806c4878 0x806c4878 +806c488c Objects::HighwayManager::Update +806c4d7c 0x806c4d7c +806c50cc 0x806c50cc +806c528c 0x806c528c +806c544c 0x806c544c +806c578c 0x806c578c +806c5acc 0x806c5acc +806c5d60 0x806c5d60 +806c5ff4 0x806c5ff4 +806c6148 0x806c6148 +806c629c 0x806c629c +806c62e4 0x806c62e4 +806c632c 0x806c632c +806c6374 0x806c6374 +806c63bc 0x806c63bc +806c6404 0x806c6404 +806c644c 0x806c644c +806c6494 0x806c6494 +806c64dc 0x806c64dc +806c65f8 0x806c65f8 +806c6710 0x806c6710 +806c68ec 0x806c68ec +806c69d0 0x806c69d0 +806c6a1c 0x806c6a1c +806c6b30 0x806c6b30 +806c6cf4 0x806c6cf4 +806c6cfc Objects::K_truck_light::LoadAnimations +806c6d8c Objects::K_truck_light::LoadCollision +806c6d90 Objects::K_truck_light::LoadRoute +806c6d94 Objects::K_truck_light::GetSubFileName +806c6da0 Objects::K_truck_light::GetBRRESName +806c6dac Objects::K_truck_light::GetPropertiesBitfield +806c6db4 Objects::K_truck_light::GetID +806c6dbc Objects::K_truck_light::__dt +806c6dfc 0x806c6dfc +806c6e04 Objects::K_car_light::LoadAnimations +806c6e94 Objects::K_car_light::LoadCollision +806c6e98 Objects::K_car_light::LoadRoute +806c6e9c Objects::K_car_light::GetSubFileName +806c6ea8 Objects::K_car_light::GetBRRESName +806c6eb4 Objects::K_car_light::GetPropertiesBitfield +806c6ebc Objects::K_car_light::GetID +806c6ec4 Objects::K_car_light::__dt +806c6f04 0x806c6f04 +806c6f0c Objects::K_truck_tire::LoadAnimations +806c6f58 Objects::K_truck_tire::LoadCollision +806c6f5c Objects::K_truck_tire::LoadRoute +806c6f60 Objects::K_truck_tire::GetSubFileName +806c6f6c Objects::K_truck_tire::GetBRRESName +806c6f78 Objects::K_truck_tire::GetPropertiesBitfield +806c6f80 Objects::K_truck_tire::GetID +806c6f88 Objects::K_truck_tire::__dt +806c6fc8 0x806c6fc8 +806c6fd0 Objects::K_car_tire::LoadAnimations +806c701c Objects::K_car_tire::LoadCollision +806c7020 Objects::K_car_tire::LoadRoute +806c7024 Objects::K_car_tire::GetSubFileName +806c7030 Objects::K_car_tire::GetBRRESName +806c703c Objects::K_car_tire::GetPropertiesBitfield +806c7044 Objects::K_car_tire::GetID +806c704c Objects::K_car_tire::__dt +806c708c 0x806c708c +806c7090 0x806c7090 +806c7094 0x806c7094 +806c7098 0x806c7098 +806c709c 0x806c709c +806c70a4 Objects::HighwayCar::__ct +806c7a70 Objects::HighwayCar::GetBRRESName +806c7a78 0x806c7a78 +806c7adc Objects::HighwayCar::__dt +806c7b48 Objects::HighwayCar::LoadModels +806c7b80 Objects::HighwayCar::GetCollisionDiameter +806c7cd4 Objects::HighwayCar::OnStart +806c808c Objects::HighwayCar::Update +806c84e8 Objects::HighwayCar::OnCollision +806c8940 Objects::HighwayCar::OnItemCollision +806c8cb8 Objects::HighwayCar::LoadCollision +806c8db8 Objects::HighwayCar::UpdateCollision +806c8eb8 Objects::HighwayCar::GetSolidityCenter +806c8f24 0x806c8f24 +806c8f28 0x806c8f28 +806c8f2c 0x806c8f2c +806c8f30 0x806c8f30 +806c8fc8 0x806c8fc8 +806c8fcc 0x806c8fcc +806c9064 0x806c9064 +806c9118 0x806c9118 +806c943c 0x806c943c +806c9d1c 0x806c9d1c +806c9fa8 0x806c9fa8 +806ca1c0 0x806ca1c0 +806ca568 0x806ca568 +806ca5f0 0x806ca5f0 +806ca6c4 0x806ca6c4 +806ca760 0x806ca760 +806ca8a0 0x806ca8a0 +806ca9f8 0x806ca9f8 +806caad4 0x806caad4 +806cab4c 0x806cab4c +806cabc4 0x806cabc4 +806cabfc 0x806cabfc +806cad3c 0x806cad3c +806cae30 0x806cae30 +806caeec 0x806caeec +806caf5c 0x806caf5c +806cb120 0x806cb120 +806cb18c 0x806cb18c +806cb678 0x806cb678 +806cb74c 0x806cb74c +806cb820 Objects::HighwayCar::ProcessCollision +806cb8e8 Objects::HighwayCar::UpdateShadow +806cb95c Objects::HighwayCar::GetShadowResName +806cb964 Objects::HighwayCar::GetSubFileName +806cb96c Objects::HighwayCar::GetPropertiesBitfield +806cb974 0x806cb974 +806cb97c Objects::Kbomneji::LoadAnimations +806cb9c0 Objects::Kbomneji::LoadCollision +806cb9c4 Objects::Kbomneji::LoadRoute +806cb9c8 Objects::Kbomneji::GetSubFileName +806cb9d4 Objects::Kbomneji::GetPropertiesBitfield +806cb9dc Objects::Kbomneji::__dt +806cba1c 0x806cba1c +806cba24 Objects::K_bomb_tire00::LoadAnimations +806cba70 Objects::K_bomb_tire00::LoadCollision +806cba74 Objects::K_bomb_tire00::LoadRoute +806cba78 Objects::K_bomb_tire00::GetSubFileName +806cba84 Objects::K_bomb_tire00::GetPropertiesBitfield +806cba8c Objects::K_bomb_tire00::__dt +806cbacc Objects::HighwayCar::__dt(thunk) +806cbad4 Objects::Kuribo::__ct +806cbc8c 0x806cbc8c +806cbcf0 Objects::Kuribo::__dt +806cbd5c Objects::Kuribo::OnStart +806cbefc Objects::Kuribo::vf_0x10 +806cbf00 Objects::Kuribo::Update +806cc0b4 Objects::Kuribo::OnCollision +806cc3e8 Objects::Kuribo::OnItemCollision +806ccb6c Objects::Kuribo::OnRouteEnd +806ccb70 Objects::Kuribo::UpdateRouteEnd +806ccd44 Objects::Kuribo::OnCycleBegin +806ccd48 Objects::Kuribo::UpdateCycle +806ccdb0 0x806ccdb0 +806ccf30 0x806ccf30 +806cd0cc 0x806cd0cc +806cd0e0 0x806cd0e0 +806cd2c8 0x806cd2c8 +806cd328 0x806cd328 +806cd4a8 0x806cd4a8 +806cd5ec 0x806cd5ec +806cd698 0x806cd698 +806cd720 0x806cd720 +806cd72c 0x806cd72c +806cd928 0x806cd928 +806cd988 0x806cd988 +806cda78 0x806cda78 +806cdbc0 Objects::Kuribo::vf_0xC(ObjectCycleManager) +806cdbc8 Objects::Kuribo::LoadAnimations +806cdc18 0x806cdc18 +806cdc20 Objects::Kuribo::__dt(thunk) +806cdc28 Objects::Balloon::__ct +806cdd90 Objects::Balloon::__dt +806cddd0 Objects::Balloon::OnStart +806cdf2c Objects::Balloon::vf_0x10 +806cdf30 Objects::Balloon::Update +806ce120 0x806ce120 +806ce1a8 Objects::Balloon::UpdateShadow +806ce274 Objects::Balloon::GetShadowListIdx +806ce27c Objects::Balloon::GetPropertiesBitfield +806ce284 0x806ce284 +806ce2e8 0x806ce2e8 +806ce328 0x806ce328 +806ce3a4 0x806ce3a4 +806ce3d0 0x806ce3d0 +806ce3d4 Objects::TruckChimSmk::__ct +806ce5c8 Objects::TruckChimSmk::__dt +806ce608 Objects::TruckChimSmk::OnStart +806ce7a0 Objects::TruckChimSmk::Update +806cec88 Objects::TruckChimSmk::OnCollision +806cedec Objects::TruckChimSmk::OnItemCollision +806cee18 Objects::TruckChimSmk::UpdateCollision +806cef10 Objects::TruckChimSmk::vf_0x10 +806cef14 0x806cef14 +806cf004 Objects::TruckChimSmk::OnWallCollision +806cf008 Objects::TruckChimSmk::LoadAnimations +806cf054 0x806cf054 +806cf05c Objects::TruckChimSmk::GetPropertiesBitfield +806cf064 0x806cf064 +806cf0e4 0x806cf0e4 +806cf184 0x806cf184 +806cf1d4 0x806cf1d4 +806cf1ec 0x806cf1ec +806cf3a0 0x806cf3a0 +806cf3e0 0x806cf3e0 +806cf444 0x806cf444 +806cf4b0 0x806cf4b0 +806cf510 0x806cf510 +806cf734 0x806cf734 +806cf738 0x806cf738 +806cf9a0 0x806cf9a0 +806cfb84 0x806cfb84 +806cfe80 0x806cfe80 +806d0098 0x806d0098 +806d0140 0x806d0140 +806d0598 0x806d0598 +806d0620 0x806d0620 +806d06c0 0x806d06c0 +806d0b44 0x806d0b44 +806d0be4 0x806d0be4 +806d0be8 0x806d0be8 +806d0c90 0x806d0c90 +806d1120 0x806d1120 +806d1184 0x806d1184 +806d1270 0x806d1270 +806d12e0 0x806d12e0 +806d13b0 0x806d13b0 +806d13bc ObjTruckWagon_construct +806d153c 0x806d153c +806d157c 0x806d157c +806d16ec 0x806d16ec +806d16f0 0x806d16f0 +806d16f4 0x806d16f4 +806d17dc 0x806d17dc +806d182c 0x806d182c +806d1830 0x806d1830 +806d1834 0x806d1834 +806d1838 0x806d1838 +806d183c 0x806d183c +806d1844 0x806d1844 +806d184c 0x806d184c +806d18bc 0x806d18bc +806d18c4 0x806d18c4 +806d1954 obj_draw_shadow_init +806d1958 0x806d1958 +806d195c 0x806d195c +806d1968 0x806d1968 +806d1974 0x806d1974 +806d1a94 0x806d1a94 +806d1a9c 0x806d1a9c +806d1af4 0x806d1af4 +806d1b4c 0x806d1b4c +806d1b54 0x806d1b54 +806d1bb0 0x806d1bb0 +806d1bbc 0x806d1bbc +806d1bc8 0x806d1bc8 +806d1bcc 0x806d1bcc +806d1bd0 0x806d1bd0 +806d1bd8 0x806d1bd8 +806d1c18 0x806d1c18 +806d1c20 0x806d1c20 +806d1c24 0x806d1c24 +806d1c28 0x806d1c28 +806d1c34 0x806d1c34 +806d1c40 0x806d1c40 +806d1c44 0x806d1c44 +806d1c4c 0x806d1c4c +806d1c54 0x806d1c54 +806d1ecc 0x806d1ecc +806d1f30 0x806d1f30 +806d1f9c 0x806d1f9c +806d2040 0x806d2040 +806d20d0 0x806d20d0 +806d2158 0x806d2158 +806d2274 0x806d2274 +806d2284 0x806d2284 +806d2288 0x806d2288 +806d2384 0x806d2384 +806d25cc 0x806d25cc +806d2674 0x806d2674 +806d279c 0x806d279c +806d27a8 0x806d27a8 +806d2b9c 0x806d2b9c +806d2bdc 0x806d2bdc +806d2c70 0x806d2c70 +806d2db4 0x806d2db4 +806d2db8 0x806d2db8 +806d2dbc 0x806d2dbc +806d2dc0 0x806d2dc0 +806d2dc4 0x806d2dc4 +806d2dcc 0x806d2dcc +806d2dd4 0x806d2dd4 +806d2ddc Objects::Pile::OnStart +806d2e98 Objects::Pile::Update +806d2eac 0x806d2eac +806d2edc 0x806d2edc +806d3160 Objects::Wanwan_Chn::LoadCollision +806d31c4 Objects::Wanwan_Chn::Update +806d31d4 0x806d31d4 +806d31dc Objects::Wanwan_Chn::UpdateCollision +806d31e0 Objects::Wanwan::__ct +806d3a20 Objects::Wanwan_Chn::OnStart +806d3a44 0x806d3a44 +806d3aa8 Objects::Wanwan::__dt +806d3b54 Objects::Wanwan::vf_0x10 +806d3b58 Objects::Wanwan::OnStart +806d3ee8 Objects::Wanwan::Update +806d4228 Objects::Wanwan::OnCollision +806d4428 Objects::Wanwan::OnItemCollision +806d4680 0x806d4680 +806d4978 0x806d4978 +806d4a48 0x806d4a48 +806d4d2c 0x806d4d2c +806d4e98 0x806d4e98 +806d51c4 Objects::Wanwan::BeforeWanderB +806d5360 Objects::Wanwan::WanderBUpdate +806d56ec Objects::Wanwan::BeforeWanderA +806d57f4 Objects::Wanwan::WanderAUpdate +806d5b14 Objects::Wanwan::BeforeLookUp +806d5b38 Objects::Wanwan::LookUpUpdate +806d5c10 Objects::Wanwan::BeforeDigDown +806d5c54 Objects::Wanwan::DigDownUpdate +806d5d90 Objects::Wanwan::BeforeLookStraight +806d5d94 Objects::Wanwan::LookStraightUpdate +806d5e6c Objects::Wanwan::BeforeAttack +806d5f28 Objects::Wanwan::AttackUpdate +806d6380 Objects::Wanwan::BeforeRetreat +806d6450 Objects::Wanwan::RetreatUpdate +806d6550 0x806d6550 +806d65f4 0x806d65f4 +806d686c 0x806d686c +806d6908 0x806d6908 +806d69a0 0x806d69a0 +806d6b38 0x806d6b38 +806d6b60 0x806d6b60 +806d6df4 0x806d6df4 +806d6e98 vector3_lerp +806d6f20 0x806d6f20 +806d6fcc 0x806d6fcc +806d6fd0 0x806d6fd0 +806d72fc 0x806d72fc +806d7444 0x806d7444 +806d74dc 0x806d74dc +806d7784 0x806d7784 +806d7928 0x806d7928 +806d7a1c 0x806d7a1c +806d7f08 0x806d7f08 +806d8040 0x806d8040 +806d8420 Objects::Wanwan::UpdateModelMatrix +806d8424 Objects::Wanwan::LoadAnimations +806d8470 Objects::Wanwan::vf_0xC +806d8478 Objects::Wanwan::GetPropertiesBitfield +806d8480 Objects::Wanwan_Chn::GetCollisionDiameter +806d8498 Objects::Wanwan_Chn::GetName +806d84a4 Objects::Wanwan_Chn::GetSubFileName +806d84b0 Objects::Wanwan_Chn::GetPropertiesBitfield +806d84b8 Objects::Wanwan_Chn::__dt +806d84f8 Objects::Pile::GetName +806d8504 Objects::Pile::GetSubFileName +806d8510 Objects::Pile::GetBRRESName +806d851c Objects::Pile::GetPropertiesBitfield +806d8524 Objects::Pile::__dt +806d8564 Objects::Wanwan::__dt +806d856c Effects::Menus::__ct +806d86b8 Effects::Menus::__dt +806d8738 Effects::Menus::GetEffectByIdx +806d8748 Route::__ct(POTI) +806d88a0 RoutePoint::__ct +806d88a4 RoutePoint::__dt +806d88e4 Route::__ct(PointsArray) +806d89e4 Route::__dt +806d8a64 Route::FillNormals +806d8c00 Route::FillBLIGHTIndexes +806d8d2c Route::UpdatePoints +806d8eb4 Route::AddPoint +806d8ef4 Route::GetPointById +806d8f04 RouteController::__ct +806d8fa8 0x806d8fa8 +806d8ff0 RouteController::GetNormal +806d9058 RouteController::GetBLIGHTIndex +806d90b0 RouteController::GetTotalDistance +806d90f0 0x806d90f0 +806d9188 0x806d9188 +806d91cc 0x806d91cc +806d92e0 0x806d92e0 +806d92e8 RouteController::__dt +806d9328 RouteCurved::__ct(POTI) +806d946c RouteArc::__ct +806d9470 RouteArc::__ct +806d94b0 RouteCurved::__ct(PointsArray) +806d95d4 RouteCurved::__dt +806d9668 RouteCurved::Update +806d970c RouteCurved::UpdateTotalDistance +806d97b0 RouteCurved::Init +806da028 0x806da028 +806da1b4 0x806da1b4 +806da264 RouteCurved::Calc +806da318 0x806da318 +806da4d8 0x806da4d8 +806da5dc RouteCurvedController::__ct +806da6d0 RouteCurvedController::Init +806da884 RouteCurvedController::SetParams +806da940 RouteCurvedController::UpdateSpeed +806da998 RouteCurvedController::Update +806dac68 RouteCurvedController::vf_0x24 +806dad4c RouteCurvedController::vf_0x28 +806dae48 RouteCurvedController::GetDistanceToNextPoint +806dae84 RouteCurvedController::GetTotalPercent +806daea4 RouteCurvedController::GetTotalPercentNormalDir +806dafd0 RouteCurvedController::CalculateBezier +806db0fc RouteCurvedController::CalculateBezierCurve +806db200 RouteCurvedController::CalculateBezierDir +806db3f4 RouteController::IsAtRouteEnd +806db410 0x806db410 +806db5b0 0x806db5b0 +806db61c 0x806db61c +806db69c 0x806db69c +806db6e8 RouteCurvedController::GetSpeed +806db6f0 RouteCurvedController::__dt +806db730 RouteCurved::GetPercentFromOriginArrays +806db738 RouteCurved::GetPercent +806db740 RouteCurved::GetPointsPerArc +806db748 RouteCurved::GetArcArray +806db750 RouteCurved::GetSegmentArray +806db758 RouteCurved::GetTotalDistance +806db760 RouteStraight::__ct(POTI) +806db99c RouteSegment::__ct +806db9a0 RouteSegment::__dt +806db9e0 RouteStraight::__ct(PointsArray) +806dbb18 RouteStraight::__dt +806dbb70 RouteStraightController::__ct +806dbbfc RouteStraightController::SetParams +806dbc58 RouteStraightController::Init +806dbda0 RouteStraightController::UpdateSpeed +806dbdfc RouteStraightController::Update +806dc098 RouteStraightController::vf_0x24 +806dc1c8 RouteStraightController::vf_0x28 +806dc2b8 RouteStraightController::GetDistanceToNextPoint +806dc2ec 0x806dc2ec +806dc3a0 0x806dc3a0 +806dc3bc 0x806dc3bc +806dc5c0 0x806dc5c0 +806dc62c 0x806dc62c +806dc6ac 0x806dc6ac +806dc6f0 RouteStraightController::GetSpeed +806dc6f8 RouteStraightController::__dt +806dc738 RouteStraight::UpdateTotalDistance +806dc73c RouteStraight::Update +806dc740 RouteStraight::GetPercentFromOriginArrays +806dc748 RouteStraight::GetPercent +806dc754 RouteStraight::GetPointsPerArc +806dc75c RouteStraight::GetArcArray +806dc764 RouteStraight::GetSegmentArray +806dc76c RouteStraight::GetTotalDistance +806dc774 RouteHolder::CreateInstance +806dc7e8 RouteHolder::__ct +806dc7f8 RouteHolder::DestroyInstance +806dc844 RouteHolder::__dt +806dc884 RouteHolder::Init +806dcc04 RouteHolder::CreateRoute +806dcd74 RouteHolder::UpdateRoutePoints +806dce10 RouteHolder::AddRoutePoint +806dcea8 RouteHolder::GetRouteById +806dceb8 0x806dceb8 +806dcf00 0x806dcf00 +806dcf04 0x806dcf04 +806dcf40 0x806dcf40 +806dcfd0 0x806dcfd0 +806dd060 0x806dd060 +806dd0e8 0x806dd0e8 +806dd1a8 0x806dd1a8 +806dd268 0x806dd268 +806dd314 0x806dd314 +806dd3d8 0x806dd3d8 +806dd498 0x806dd498 +806dd624 0x806dd624 +806dd744 0x806dd744 +806dd7a4 0x806dd7a4 +806dd800 0x806dd800 +806dda04 0x806dda04 +806ddb64 0x806ddb64 +806ddcc0 0x806ddcc0 +806dde20 0x806dde20 +806ddfb8 0x806ddfb8 +806de074 0x806de074 +806de12c 0x806de12c +806de1e8 0x806de1e8 +806de1fc 0x806de1fc +806de21c 0x806de21c +806de23c 0x806de23c +806de4dc 0x806de4dc +806de6f0 0x806de6f0 +806de724 0x806de724 +806de7e4 0x806de7e4 +806deb58 0x806deb58 +806debe0 0x806debe0 +806ded94 Linked3DPoints::__ct +806defa0 Linked3DPoints::__dt +806df030 0x806df030 +806df11c 0x806df11c +806df1fc 0x806df1fc +806df860 0x806df860 +806dfa94 0x806dfa94 +806dfb24 0x806dfb24 +806dfcd8 0x806dfcd8 +806dfdd8 0x806dfdd8 +806dfea4 0x806dfea4 +806dff0c 0x806dff0c +806e0130 0x806e0130 +806e0194 0x806e0194 +806e01d8 0x806e01d8 +806e02c8 0x806e02c8 +806e030c 0x806e030c +806e0350 0x806e0350 +806e03ac 0x806e03ac +806e03dc 0x806e03dc +806e0454 0x806e0454 +806e0498 0x806e0498 +806e04c8 0x806e04c8 +806e052c 0x806e052c +806e055c 0x806e055c +806e0580 0x806e0580 +806e05a4 0x806e05a4 +806e05c8 0x806e05c8 +806e05ec 0x806e05ec +806e0610 0x806e0610 +806e0634 0x806e0634 +806e0658 aramGetFirstUserAddress +806e067c 0x806e067c +806e06b8 0x806e06b8 +806e0760 0x806e0760 +806e0764 0x806e0764 +806e0768 0x806e0768 +806e0b94 0x806e0b94 +806e103c 0x806e103c +806e10c8 0x806e10c8 +806e1164 0x806e1164 +806e11ec 0x806e11ec +806e13d8 0x806e13d8 +806e1480 0x806e1480 +806e16ac 0x806e16ac +806e1838 0x806e1838 +806e189c 0x806e189c +806e199c 0x806e199c +806e1a3c 0x806e1a3c +806e1a7c 0x806e1a7c +806e1afc 0x806e1afc +806e1df0 0x806e1df0 +806e1e70 0x806e1e70 +806e1edc 0x806e1edc +806e1f40 0x806e1f40 +806e20a8 0x806e20a8 +806e2118 0x806e2118 +806e2158 0x806e2158 +806e21c4 0x806e21c4 +806e21e4 0x806e21e4 +806e2344 0x806e2344 +806e2348 0x806e2348 +806e2350 0x806e2350 +806e2390 0x806e2390 +806e2398 0x806e2398 +806e23dc 0x806e23dc +806e2460 0x806e2460 +806e2468 0x806e2468 +806e24f8 0x806e24f8 +806e2538 0x806e2538 +806e25d0 0x806e25d0 +806e25d4 0x806e25d4 +806e26b4 0x806e26b4 +806e26f4 Objects::EffectSpawner::__ct +806e2748 Objects::EffectSpawner::OnStart +806e2758 Objects::EffectSpawner::OnCollision +806e28d8 Objects::EffectSpawner::Update +806e29cc Objects::EffectSpawner::__dt +806e2a0c Objects::EffectSpawner::OnItemCollision +806e2a38 Objects::EffectSpawner::OnWallCollision +806e2a3c Objects::EffectSpawner::GetPropertiesBitfield +806e2a44 Objects::LeafEffect::__ct +806e2b84 Objects::LeafEffect::OnCollision +806e2d3c Objects::LeafEffect::Update +806e2ec0 Objects::LeafEffect::__dt +806e2f00 Objects::FireSnake_ball::__ct +806e2f70 Objects::FireSnake_ball::OnStart +806e2fe8 Objects::FireSnake_ball::vf_0xec +806e3008 Objects::FireSnake_ball::ToggleVisible +806e300c Objects::FireSnake_ball::Update +806e3010 0x806e3010 +806e30b0 0x806e30b0 +806e3104 0x806e3104 +806e3118 Objects::FireSnake::__ct +806e346c Objects::MapObjProjectile::__dt +806e34ac Objects::FireSnake_ball::SetScale +806e34c8 0x806e34c8 +806e352c Objects::FireSnake::__dt +806e3598 Objects::FireSnake::OnStart +806e36cc Objects::FireSnake::Update +806e3a00 Objects::FireSnake::OnCollision +806e3a90 Objects::FireSnake::OnItemCollision +806e3b18 Objects::FireSnake::OnCycleEnd +806e3bcc Objects::FireSnake::OnCycleEnd2 +806e3bd0 Objects::FireSnake::OnCycleStart +806e3c70 Objects::FireSnake::OnCycleStart2 +806e3fb4 Objects::FireSnake::OnInitialGroundCollision +806e4078 Objects::FireSnake::vf_0x114 +806e41e8 Objects::FireSnake::vf_0x118 +806e4320 Objects::FireSnake::vf_0x11c +806e43b0 0x806e43b0 +806e4438 Objects::FireSnake::vf_0x120 +806e443c Objects::FireSnake::vf_0x124 +806e45a0 Objects::FireSnake::vf_0x128 +806e45ac Objects::FireSnake::vf_0x12c +806e45b0 Objects::FireSnake::vf_0xec +806e4718 0x806e4718 +806e4aec Objects::FireSnake_ball::GetEntity +806e4af4 Objects::FireSnake_ball::UpdateDrawInfo +806e4b50 Objects::FireSnake_ball::vf_0x8c +806e4b54 Objects::FireSnake_ball::vf_0xf8 +806e4be4 Objects::FireSnake::RequestShoot +806e4bf0 Objects::FireSnake::vf_0x130 +806e4bf8 Objects::FireSnake::LoadAnimations +806e4c44 Objects::FireSnake::GetPropertiesBitfield +806e4c4c Objects::FireSnake_eye::LoadCollision +806e4c50 Objects::FireSnake_eye::LoadRoute +806e4c54 Objects::FireSnake_eye::GetName +806e4c60 Objects::FireSnake_eye::GetSubFileName +806e4c6c Objects::FireSnake_eye::GetPropertiesBitfield +806e4c74 Objects::FireSnake_eye::__dt +806e4cb4 Objects::FireSnake_ball::__dt +806e4cf4 Objects::FireSnake_ball::vf_0xf0 +806e4cfc Objects::FireSnake_ball::LoadAnimations +806e4d48 Objects::FireSnake_ball::GetPropertiesBitfield +806e4d50 Objects::FireSnake::__dt(thunk) +806e4d58 Objects::FireSnake_v::__ct +806e4ea4 Objects::FireSnake_v::OnStart +806e4f3c Objects::FireSnake_v::Update +806e4f8c 0x806e4f8c +806e52d8 Objects::FireSnake_v::OnCycleEnd +806e52dc Objects::FireSnake_v::OnCycleEnd2 +806e52e0 Objects::FireSnake_v::OnCycleStart +806e53d8 Objects::FireSnake_v::OnCycleStart2 +806e559c Objects::FireSnake_v::OnInitialGroundCollision +806e55ac Objects::FireSnake_v::vf_0x114 +806e5730 Objects::FireSnake_v::__dt +806e5788 0x806e5788 +806e5790 obj_FlamePole_v::__ct +806e5b18 0x806e5b18 +806e5b7c 0x806e5b7c +806e5cb8 obj_FlamePole_v_update +806e5dd0 0x806e5dd0 +806e5e1c 0x806e5e1c +806e5e64 0x806e5e64 +806e5edc obj_FlamePole_v_raiseUpdate +806e5f6c obj_FlamePole_v_beforeShake +806e5f8c obj_FlamePole_v_calcShake +806e60a8 obj_FlamePole_v_dropUpdate +806e60d4 0x806e60d4 +806e6164 0x806e6164 +806e61b4 0x806e61b4 +806e61d0 0x806e61d0 +806e64a0 0x806e64a0 +806e650c 0x806e650c +806e6564 0x806e6564 +806e656c 0x806e656c +806e6578 0x806e6578 +806e6584 0x806e6584 +806e658c 0x806e658c +806e6594 0x806e6594 +806e6920 0x806e6920 +806e6924 0x806e6924 +806e6b80 0x806e6b80 +806e6bc0 Objects::HwanwanItembox::__ct +806e6c44 Objects::Itembox::__dt +806e6c84 0x806e6c84 +806e6cc4 Objects::HwanwanItembox::OnStart +806e6d40 Objects::HwanwanItembox::Update +806e6f24 Objects::HwanwanItembox::UpdateShadow +806e7024 Objects::Hwanwan::__ct +806e73ac Objects::Hwanwan::__dt +806e73ec 0x806e73ec +806e7794 Objects::Hwanwan::Update +806e789c Objects::Hwanwan::vf_0xec +806e7ab0 0x806e7ab0 +806e7e18 0x806e7e18 +806e7e6c 0x806e7e6c +806e7ee4 0x806e7ee4 +806e8078 0x806e8078 +806e83a0 0x806e83a0 +806e83bc 0x806e83bc +806e8444 0x806e8444 +806e85f4 0x806e85f4 +806e8670 0x806e8670 +806e8674 Objects::Hwanwan::LoadClipInfo +806e8678 Objects::Hwanwan::LoadCollision +806e867c Objects::Hwanwan::LoadModels +806e8680 Objects::Hwanwan::GetPropertiesBitfield +806e8688 Objects::Itembox::IsActive +806e869c Objects::Itembox::IsSolid +806e86a4 Objects::Itembox::OnNormalCollision +806e86a8 Objects::Itembox::UpdateModelScale +806e86ac Objects::Itembox::UpdateModelMatrix +806e86b0 Objects::Itembox::LoadShadow +806e86c4 Objects::Itembox::GetPropertiesBitfield +806e86cc Objects::HwanwanItembox::GetBRRESName +806e86d8 Objects::HwanwanItembox::GetSubFileName +806e86e4 Objects::HwanwanItembox::GetName +806e86f0 Objects::HwanwanItembox::GetID +806e8708 Objects::HwanwanItembox::__dt +806e8748 Objects::HwanwanItembox::LoadRoute +806e874c Objects::Itembox::UpdateShadow +806e8750 0x806e8750 +806e8754 Objects::OnStart +806e87a0 Objects::Hwanwan_Chn::ToggleVisible +806e87a4 Objects::Hwanwan_Chn::__dt +806e87e4 Objects::Hwanwan_Chn::LoadCollision +806e87e8 Objects::Hwanwan_Chn::LoadRoute +806e87ec Objects::Hwanwan_Chn::GetName +806e87f8 Objects::Hwanwan_Chn::GetSubFileName +806e8804 Objects::Hwanwan_Chn::GetPropertiesBitfield +806e880c 0x806e880c +806e89c0 0x806e89c0 +806e8ca4 0x806e8ca4 +806e8dd4 0x806e8dd4 +806e8e3c 0x806e8e3c +806e905c 0x806e905c +806e91e4 0x806e91e4 +806e9310 0x806e9310 +806e963c 0x806e963c +806e9640 0x806e9640 +806e969c 0x806e969c +806e9758 0x806e9758 +806e975c 0x806e975c +806e9760 0x806e9760 +806e9844 0x806e9844 +806e99b8 0x806e99b8 +806e9ae4 0x806e9ae4 +806e9cd0 0x806e9cd0 +806e9d18 0x806e9d18 +806e9d4c 0x806e9d4c +806e9dac 0x806e9dac +806e9ec4 0x806e9ec4 +806ea12c 0x806ea12c +806ea184 0x806ea184 +806ea18c 0x806ea18c +806ea194 0x806ea194 +806ea19c 0x806ea19c +806ea1a4 Objects::HeyHoBallGBA::__ct +806ea46c 0x806ea46c +806ea4d0 Objects::HeyHoBallGBA::OnStart +806ea660 Objects::HeyHoBallGBA::Update +806ea760 Objects::HeyHoBallGBA::OnCollision +806ea858 Objects::HeyHoBallGBA::OnItemCollision +806ea8e0 0x806ea8e0 +806ea8f4 0x806ea8f4 +806ea91c 0x806ea91c +806ea9b8 0x806ea9b8 +806eaaec 0x806eaaec +806eabb8 0x806eabb8 +806eac64 0x806eac64 +806eae04 0x806eae04 +806eaf84 Objects::HeyHoBallGBA::vf_0xec +806eb0a8 0x806eb0a8 +806eb1e8 0x806eb1e8 +806eb264 0x806eb264 +806eb3b8 0x806eb3b8 +806eb450 0x806eb450 +806eb488 0x806eb488 +806eb700 Objects::HeyHoBallGBA::__dt +806eb76c Objects::HeyHoBallGBA::RequestShoot +806eb778 0x806eb778 +806eb780 Objects::HeyHoBallGBA::LoadAnimations +806eb7cc Objects::HeyHoBallGBA::GetPropertiesBitfield +806eb7d4 0x806eb7d4 +806eb7dc Objects::HeyHoShipGBA::__ct +806eb878 Objects::MapObjShooter::__dt +806eb8b8 Objects::HeyHoShipGBA::OnStart +806eba7c Objects::HeyHoShipGBA::Update +806ebb84 Objects::HeyHoShipGBA::GetShootFromRoutePointID +806ebba4 0x806ebba4 +806ebbf0 0x806ebbf0 +806ebcb4 0x806ebcb4 +806ebf1c 0x806ebf1c +806ebfa4 0x806ebfa4 +806ec200 Objects::HeyHoShipGBA::__dt +806ec240 Objects::HeyHoShipGBA::GetPropertiesBitfield +806ec248 Objects::HeyHoShipManager::__ct +806ec3f4 Objects::HeyHoShipManager::__dt +806ec470 Objects::HeyHoShipManager::OnStart +806ec748 Objects::HeyHoShipManager::Update +806ec7cc 0x806ec7cc +806ec7d0 Objects::MapObjSniper::LoadClipInfo +806ec7d4 Objects::HighwayManager::LoadCollision +806ec7d8 Objects::HighwayManager::LoadRoute +806ec7dc Objects::HighwayManager::LoadModels +806ec7e0 Objects::HighwayManager::GetPropertiesBitfield +806ec7e8 0x806ec7e8 +806ec8c0 0x806ec8c0 +806eca0c 0x806eca0c +806eca4c 0x806eca4c +806eca50 0x806eca50 +806eca58 Objects::KoopaFigure64::__ct +806ecb88 Objects::KoopaFigure64::OnStart +806ecca0 Objects::KoopaFigure64::Update +806ed054 Objects::KoopaFigure64::UpdateForCPURace +806ed0fc Objects::KoopaFigure64::UpdateCollision +806ed258 Objects::KoopaFigure64::__dt +806ed298 Objects::KoopaFigure64::LoadCollision +806ed2ac Objects::KoopaFigure64::OnCollision +806ed2c8 Objects::MapObjSniper::__ct +806ed338 Objects::MapObjSniper::__dt +806ed378 Objects::MapObjSniper::OnStart +806ed488 Objects::MapObjSniper::Update +806ed4f4 0x806ed4f4 +806ed564 0x806ed564 +806ed5e4 0x806ed5e4 +806ed600 0x806ed600 +806ed604 0x806ed604 +806ed60c 0x806ed60c +806ed610 0x806ed610 +806ed614 0x806ed614 +806ed618 0x806ed618 +806ed61c Objects::SunDS::__ct +806ed748 0x806ed748 +806ed7ac Objects::SunDS::__dt +806ed818 Objects::SunDS::OnStart +806ed880 Objects::SunDS::Update +806eda0c 0x806eda0c +806eda28 0x806eda28 +806edc4c 0x806edc4c +806edc98 0x806edc98 +806edc9c 0x806edc9c +806edd28 0x806edd28 +806edd54 0x806edd54 +806eddac 0x806eddac +806edddc Objects::SunDS::GetShootFromRoutePointID +806ede0c 0x806ede0c +806ede14 Objects::SunDS::LoadAnimations +806ede58 Objects::SunDS::GetPropertiesBitfield +806ede60 Objects::SunDS::__dt(thunk) +806ede68 Objects::SunDSManager::__ct +806edfc4 Objects::SunDSManager::__dt +806ee040 0x806ee040 +806ee158 0x806ee158 +806ee1f4 0x806ee1f4 +806ee260 0x806ee260 +806ee384 Objects::TruckChimSmkW::__ct +806ee500 Objects::TruckChimSmkW::LoadModels +806ee514 Objects::TruckChimSmkW::LoadAnimations +806ee56c Objects::TruckChimSmkW::LoadCollision +806ee580 Objects::TruckChimSmkW::GetSolidityCenter +806ee618 Objects::TruckChimSmkW::OnStart +806ee6cc Objects::TruckChimSmkW::Update +806ee880 Objects::TruckChimSmkW::__dt +806ee8c0 Objects::TruckChimSmkW::GetScnObjDrawOptionsIdx +806ee8c8 0x806ee8c8 +806ee9c8 0x806ee9c8 +806eea04 0x806eea04 +806eec1c 0x806eec1c +806eec5c Objects::HwanwanBall::__ct +806eed6c 0x806eed6c +806eedd0 Objects::HwanwanBall::OnStart +806ef124 Objects::HwanwanBall::Update +806ef358 Objects::HwanwanBall::OnCollision +806ef418 Objects::HwanwanBall::OnItemCollision +806ef4b0 0x806ef4b0 +806ef4bc 0x806ef4bc +806ef68c 0x806ef68c +806ef690 0x806ef690 +806ef934 0x806ef934 +806ef9a8 0x806ef9a8 +806efd70 0x806efd70 +806efe30 0x806efe30 +806f0194 0x806f0194 +806f02f8 0x806f02f8 +806f0380 0x806f0380 +806f0754 0x806f0754 +806f0830 0x806f0830 +806f0b0c 0x806f0b0c +806f0cfc 0x806f0cfc +806f0f18 0x806f0f18 +806f1404 0x806f1404 +806f153c Objects::HwanwanBall::UpdateShadow +806f1638 0x806f1638 +806f16dc 0x806f16dc +806f179c 0x806f179c +806f192c 0x806f192c +806f19a8 0x806f19a8 +806f1af8 0x806f1af8 +806f1bcc 0x806f1bcc +806f1c94 0x806f1c94 +806f1d8c Objects::HwanwanBall::__dt +806f1df8 Objects::HwanwanBall::UpdateModelMatrix +806f1dfc Objects::HwanwanBall::LoadAnimations +806f1e4c Objects::HwanwanBall::vf_0xc +806f1e54 Objects::HwanwanBall::LoadRoute +806f1e58 Objects::HwanwanBall::GetSubFileName +806f1e64 Objects::HwanwanBall::GetPropertiesBitfield +806f1e74 0x806f1e74 +806f2024 0x806f2024 +806f2194 0x806f2194 +806f23b0 0x806f23b0 +806f24e4 Audio::Engine3D::Disposer__dt +806f257c Audio::Engine3D::CreateInstance +806f260c Audio::Engine3D::DestroyInstance +806f2640 Audio::Engine3D::SetCurSound +806f264c 0x806f264c +806f26d4 0x806f26d4 +806f2764 0x806f2764 +806f27e0 Audio::Engine3D::__ct +806f2844 0x806f2844 +806f2884 0x806f2884 +806f28c4 Audio::Engine3D::__dt +806f296c Audio::Engine3D::UpdateAmbientParam +806f3180 Audio::Engine3D::GetRequiredVoiceOutCount +806f3188 0x806f3188 +806f3210 Audio::SinglePlayer::CalcWaitTime +806f3498 Audio::SinglePlayer::Disposer__dt +806f3638 Audio::SinglePlayer::CreateInstance +806f36e0 Audio::SinglePlayer::DestroyInstance +806f385c Audio::SinglePlayer::__ct +806f38d8 Audio::Handle::__ct +806f38e4 Audio::Handle::__dt +806f3978 Audio::SinglePlayer::__dt +806f3aa8 Audio::SinglePlayer::Calc +806f3bc0 Audio::SinglePlayer::PlaySound +806f3ddc Audio::Manager::PrepareSound +806f3e10 Audio::SinglePlayer::PrepareSound +806f3f1c 0x806f3f1c +806f4078 Audio::SinglePlayer::PlayPreparedSound +806f40fc Audio::SinglePlayer::PreventActiveSoundStop +806f4108 Audio::SinglePlayer::StopSound +806f4180 Audio::SinglePlayer::StartSound +806f4380 Audio::SinglePlayer::SetupActiveHandle +806f444c Audio::SinglePlayer::SetupActiveHandle_switch +806f4450 Audio::SinglePlayer::SetupActiveHandle_caseD_83 +806f4480 Audio::SinglePlayer::SetupActiveHandle_caseD_91 +806f449c Audio::SinglePlayer::SetupActiveHandle_caseD_85 +806f44dc Audio::SinglePlayer::SetupActiveHandle_caseD_7b +806f4508 Audio::SinglePlayer::SetupActiveHandle_caseD_7d +806f4524 0x806f4524 +806f461c Audio::SinglePlayer::StartActiveSound +806f46dc Audio::SinglePlayer::GetFreeHandle +806f4768 0x806f4768 +806f476c Audio::SinglePlayer::GetFanfareLength +806f48f0 0x806f48f0 +806f4944 Audio::SinglePlayer::StopInactiveSounds +806f49d4 Audio::SinglePlayerValuesMgr::Disposer__dt +806f4b00 Audio::SinglePlayerValuesMgr::CreateInstance +806f4ba8 Audio::SinglePlayerValuesMgr::DestroyInstance +806f4c5c Audio::SinglePlayerValuesMgr::__dt +806f4d00 Audio::SinglePlayerValuesMgr::SetHandle +806f4d24 Audio::SinglePlayerValuesMgr::Calc +806f4e58 Audio::SinglePlayerValuesMgr::DetachHandle +806f4e64 Audio::SinglePlayerValuesMgr::UpdateTracks +806f4ebc Audio::SinglePlayerValuesMgr::SetVolume +806f4f00 0x806f4f00 +806f4fc4 Audio::StreamsMgr::Disposer_dt +806f50f0 Audio::StreamsMgr::CreateInstance +806f5198 Audio::StreamsMgr::DestroyInstance +806f524c Audio::StreamsMgr::__dt +806f52f0 Audio::StreamsMgr::PrepareStreams +806f5494 Audio::StreamsMgr::ChangeStreamVolume +806f54b8 Audio::StreamsMgr::Calc +806f5644 Audio::StreamsMgr::ResetVolume +806f569c Audio::SinglePlayer::PlayBGSound +806f5710 Audio::SinglePlayer::UpdateWaitTime +806f577c 0x806f577c +806f57d0 Audio::SinglePlayer::CalcTitlePageNext +806f5b4c Audio::StreamsMgr::ChangeMultipleStreamsVolume +806f5bc4 Audio::StreamsMgr::ChangeStream +806f5ef8 Audio::EngineMgr::Init +806f604c Audio::EngineMgr::Update +806f6394 Audio::EngineMgr::CalcSoundId +806f642c 0x806f642c +806f64dc Audio::EngineMgr::CalcAccelerating +806f65f0 Audio::EngineMgr::CalcBraking +806f66d8 Audio::EngineMgr::CalcPitch +806f67b8 Audio::RaceAmbienceMgr::Disposer__dt +806f6950 Audio::RaceAmbienceMgr::CreateInstance +806f69fc Audio::RaceAmbienceMgr::DestroyInstance +806f6b48 Audio::RaceAmbienceMgr::__ct +806f6bc8 0x806f6bc8 +806f6c08 Audio::RaceAmbienceMgr::__dt +806f6d28 Audio::RaceAmbienceMgr::Init +806f6d5c Audio::RaceAmbienceMgr::StopGlobalSound +806f6d74 Audio::RaceAmbienceMgr::Update +806f6eac Audio::RaceAmbienceMgr::StopGlobalSoundFadeOut +806f6ec8 Audio::RaceAmbienceMgr::PlayIntroAmbience +806f6f58 Audio::RaceAmbienceMgr::PlayIntroAmbience_switch +806f6f5c Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_1 +806f7000 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_2 +806f7028 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_3 +806f70fc Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_4 +806f71d8 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_5 +806f7294 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_6 +806f7310 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_7 +806f735c Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_3a +806f7384 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_a +806f7400 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_b +806f7474 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_c +806f74e4 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_d +806f7568 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_e +806f75b4 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_f +806f7638 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_10 +806f76c0 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_11 +806f76f8 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_12 +806f779c Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_13 +806f7854 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_14 +806f78f8 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_16 +806f7964 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_17 +806f79f8 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_19 +806f7a48 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_1a +806f7a74 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_1b +806f7ac4 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_1c +806f7b24 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_1d +806f7bc8 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_1e +806f7bf4 Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_1f +806f7c1c Audio::RaceAmbienceMgr::PlayIntroAmbience_caseD_0 +806f7c38 Audio::RaceAmbienceMgr::PlayGlobalSound +806f7e0c Audio::RaceAmbienceMgr::StopGlobalSound(soundId) +806f7e40 Audio::RaceAmbienceMgr::PlayAmbience +806f7f94 Audio::RaceAmbienceMgr::SetAmbienceVolume +806f8038 Audio::RaceAmbienceMgr::SetAllAmbiencesVolume +806f80d4 Audio::RaceAmbienceMgr::UpdateAmbiences +806f8144 Audio::RaceAmbienceMgr::UpdateVeniceAndRingMissionAmbiences +806f85f4 0x806f85f4 +806f86bc Audio::Ambience::__ct +806f8748 Audio::Ambience::__dt +806f87d4 Audio::Ambience::IsPlayingSoundId +806f8808 Audio::Ambience::PlayAmbience +806f886c Audio::Ambience::ResetVolume +806f8898 Audio::Ambience::SetVolume +806f88b0 Audio::Ambience::Update +806f8a78 0x806f8a78 +806f8b7c Audio::GameHeap::Disposer__dt +806f8cb4 Audio::GameHeap::CreateInstance +806f8d84 Audio::GameHeap::DestroyInstance +806f8ea0 Audio::GameHeap::__ct +806f8f44 Audio::GameHeapImpl::__dt +806f8fb0 Audio::GameHeap::__dt +806f9094 Audio::GameHeap::Initialize +806f90dc Audio::GameHeap::DestroySoundHeap +806f911c Audio::GameHeap::SetType +806f9138 0x806f9138 +806f9178 EGG::SoundHeapMgr::SaveState(using) +806f924c EGG::SoundHeapMgr::LoadState(using) +806f9330 EGG::SoundHeapMgr::GetCurrentLevel(using) +806f9384 0x806f9384 +806f93a8 Audio::ReverbMgr::Disposer__dt +806f94d4 Audio::ReverbMgr::CreateInstance +806f95c0 Audio::ReverbMgr::DestroyInstance +806f9674 Audio::ReverbMgr::__ct +806f9744 Audio::ReverbMgr::__dt +806f97e8 Audio::ReverbMgr::Disable +806f980c Audio::ReverbMgr::Clear +806f995c 0x806f995c +806f999c Audio::ReverbMgr::Prepare +806f9a34 Audio::ReverbMgr::Play +806f9aac Audio::ReverbMgr::Disable2 +806f9ad0 Audio::GroupBankRequester::Request::__ct +806f9bd4 0x806f9bd4 +806f9c14 Audio::Actor<4>::__dt +806f9c88 0x806f9c88 +806f9d10 0x806f9d10 +806f9d84 Audio::RaceActor::SetupBRASD +806f9db0 Audio::RaceActor::UpdateBRASDFrame +806f9e28 Audio::RaceActor::Update +806f9e70 Audio::Actor<4>::SetPosition +806f9e74 Audio::RaceActor::SetupSound +806f9ef0 ObjectSoundAnimNoHandle::__ct +806fa018 Audio::RaceActor::__dt +806fa0dc ObjectSoundAnimNoHandle::Update +806fa124 ObjectSoundAnimNoHandle::Link +806fa194 ObjectSoundAnimNoHandle::DisableConditional +806fa1dc Audio::RaceActor::DisableConditional +806fa1f8 ObjectSoundAnimNoHandle::UpdateUserParam3 +806fa218 Audio::RaceActor::UpdateUserParam3 +806fa238 ObjectSoundAnimNoHandle::StartSoundLimited +806fa3a8 Audio::RaceActor::StartSoundLimited +806fa504 ObjectSoundAnimNoHandle::HoldSoundLimited +806fa674 Audio::RaceAnimActor::__ct +806fa79c Audio::RaceAnimActor::StartSound +806fa7b0 Audio::RaceActor::StartSound +806fa824 0x806fa824 +806fa83c Audio::RaceActor::StartSound(StartInfo) +806fa8bc Audio::RaceAnimActor::HoldSound +806fa8d0 0x806fa8d0 +806fa944 0x806fa944 +806fa95c Audio::RaceActor::HoldSound +806fa9dc Audio::RaceAnimActor::StopSound +806fa9f0 Audio::RaceActor::StopSound +806fa9f4 Audio::RaceActor::HoldSound +806fa9fc Audio::RaceActor::StartSound +806faa04 Audio::RaceActor::StartNewSoundLimited +806fab44 Audio::RaceActor::HoldSoundLimited +806fad58 Audio::RaceActor::StopAllSound +806fadbc Audio::RaceActor::GetPosition +806fadc4 Audio::RaceActor::UpdateUserParam +806fadd8 Audio::RaceActor::UpdateUserParam2 +806fadf0 Audio::RaceActor::detail_UpdateAmbientArg +806fae54 Audio::Actor<4>::TryStartSound(u32) +806faee0 Audio::Actor<4>::TryStartSound(ul) +806faf6c Audio::Actor<4>::TryStartSound(str) +806fb02c Audio::Actor<4>::TryStopAndStartSound(u32) +806fb0c0 Audio::Actor<4>::TryStopAndStartSound(ul) +806fb154 Audio::Actor<4>::TryStopAndStartSound(str) +806fb210 Audio::Actor<4>::TryHoldSound(u32) +806fb2f8 Audio::Actor<4>::TryHoldSound(ul) +806fb3e0 Audio::Actor<4>::TryHoldSound(str) +806fb4fc Audio::Actor<4>::TryHoldSound(u32, handleId) +806fb564 Audio::Actor<4>::TryHoldSound(u3l, handleId) +806fb5cc Audio::Actor<4>::TryHoldSound(str, handleId) +806fb670 Audio::Actor<4>::TryPrepareSound(u32) +806fb6fc Audio::Actor<4>::TryPrepareSound(ul) +806fb788 Audio::Actor<4>::TryPrepareSound(str) +806fb848 Audio::Actor<4>::TryStopAndPrepareSound(u32) +806fb8dc Audio::Actor<4>::TryStopAndPrepareSound(ul) +806fb970 Audio::Actor<4>::TryStopAndPrepareSound(str) +806fba2c ObjectSoundAnimNoHandle::__dt +806fbaf4 Audio::RaceAnimActor::__dt +806fbbcc Audio::Actor::detail_UpdateAmbientArg +806fbbd4 0x806fbbd4 +806fbbdc 0x806fbbdc +806fbbe4 Audio::RaceActor::__dt +806fbbec ObjectSoundAnimNoHandle::__dt +806fbbf4 ObjectSoundAnimNoHandle::HoldSoundLimited +806fbbfc ObjectSoundAnimNoHandle::StartSoundLimited +806fbc04 ObjectSoundAnimNoHandle::UpdateUserParam3 +806fbc0c ObjectSoundAnimNoHandle::DisableConditional +806fbc14 ObjectSoundAnimNoHandle::Update +806fbc1c ObjectSoundAnimNoHandle::Link +806fbc24 Audio::RaceActor::detail_UpdateAmbientArg +806fbc2c 0x806fbc2c +806fbc34 Audio::RaceActor::UpdateBRASDFrame +806fbc3c Audio::RaceActor::SetupBRASD +806fbc44 Audio::RaceActor::HoldSound +806fbc4c Audio::RaceActor::HoldSound(StartInfo) +806fbc54 Audio::RaceActor::StartSound +806fbc5c Audio::RaceActor::StartSound(StartInfo) +806fbc64 Audio::RaceAnimActor::StopSound +806fbc6c Audio::RaceAnimActor::HoldSound +806fbc74 Audio::RaceAnimActor::StartSound +806fbc7c Audio::RaceActor::StartNewSoundLimited +806fbc84 Audio::RaceActor::StopAllSound +806fbc8c Audio::RaceActor::HoldSoundLimited +806fbc94 Audio::RaceActor::StartSoundLimited +806fbc9c Audio::RaceActor::UpdateUserParam3 +806fbca4 Audio::RaceActor::DisableCondition +806fbcac Audio::RaceActor::UpdateUserParam2 +806fbcb4 Audio::RaceActor::UpdateUserParam +806fbcbc Audio::RaceActor::Reset +806fbcc4 Audio::RaceActor::GetPosition +806fbccc Audio::RaceActor::Update +806fbcd4 Audio::LinkedRaceActor::__ct +806fbd28 Audio::LinkedRaceActor::__dt +806fbd70 Audio::LinkedRaceActor::Link +806fbe2c Audio::LinkedRaceActor::Unlink +806fbe84 0x806fbe84 +806fbea4 0x806fbea4 +806fbf40 Audio::LinkedRaceActor::CannotPlaySounds +806fbfc8 0x806fbfc8 +806fbfcc Audio::LinkedRaceActor::Toggle +806fc028 Audio::LinkedRaceActor::GetKartPosition +806fc030 Audio::LinkedRaceActor::GetObjectPosition +806fc03c Audio::LinkedRaceActor::SetSoundParams +806fc04c Audio::ObjectActorAnim::__ct +806fc0a0 0x806fc0a0 +806fc0e0 Audio::ObjectActorAnim::Link +806fc150 Audio::ObjectActorAnim::Unlink +806fc158 Audio::ObjectActorAnim::Update +806fc15c Audio::ObjectActorAnim::StartSoundLimited +806fc700 Audio::ObjectActorAnim::HoldSoundLimited +806fcb20 Audio::ObjectActorAnim::StartNewSoundLimited +806fcd28 Audio::ObjectActorAnim::StartSound +806fd124 Audio::ObjectActorAnim::SetupSound +806fd3c0 Audio::ObjectActorAnim::DisableConditional +806fd55c Audio::ObjectActorAnim::UpdateUserParam3 +806fd60c Audio::ObjectActorAnim::__dt +806fd6e8 Audio::ObjectActorAnim::__dt(thunk) +806fd6f0 Audio::ObjectActorAnim::StartSound(thunk) +806fd6f8 Audio::ObjectActorAnim::StartNewSoundLimited(thunk) +806fd700 Audio::ObjectActorAnim::HoldSoundLimited(thunk) +806fd708 Audio::ObjectActorAnim::StartSoundLimited(thunk) +806fd710 Audio::ObjectActorAnim::UpdateUserParam3(thunk) +806fd718 Audio::ObjectActorAnim::DisableConditional(thunk) +806fd720 Audio::ObjectActorAnim::Update(thunk) +806fd728 Audio::ObjectActorAnim::Unlink(thunk) +806fd730 Audio::ObjectActorAnim::Link(thunk) +806fd738 Audio::ItemActor::__ct +806fd7e0 0x806fd7e0 +806fd820 Audio::Actor<2>::__dt +806fd894 0x806fd894 +806fd91c Audio::ItemActor::Link +806fd924 Audio::ItemActor::Unlink +806fd92c Audio::ItemActor::Update +806fd944 Audio::Actor<2>::SetPosition +806fd948 Audio::ItemActor::DisableConditional +806fd964 0x806fd964 +806fd980 Audio::ItemActor::UpdateUserParam3 +806fd9a0 0x806fd9a0 +806fd9c0 Audio::ItemActor::StartSoundLimited +806fdbf0 0x806fdbf0 +806fdcfc Audio::ItemActor::HoldSoundLimited +806fde88 0x806fde88 +806fdff4 Audio::ItemActor::StartNewSoundLimited +806fe0f0 0x806fe0f0 +806fe1d8 0x806fe1d8 +806fe230 Audio::GessoActor::__ct +806fe2d8 0x806fe2d8 +806fe34c 0x806fe34c +806fe3d4 Audio::GessoActor::Link +806fe3dc Audio::GessoActor::Update +806fe3e0 0x806fe3e0 +806fe3f0 0x806fe3f0 +806fe3f4 Audio::GessoActor::StartSoundLimited +806fe4ec 0x806fe4ec +806fe5d0 Audio::GessoActor::SetupBRASD +806fe5d4 Audio::GessoActor::UpdateBRASDFrame +806fe5d8 Audio::ItemActor::SetupBRASD +806fe5dc Audio::ItemActor::UpdateBRASD +806fe5e0 Audio::GessoActor::StartNewSoundLimited +806fe69c Audio::GessoActor::HoldSoundLimited +806fe7b4 Audio::GessoActor::StopAllSound +806fe7c8 Audio::GessoActor::StartSound +806fe83c Audio::GessoActor::StartSound(StartInfo) +806fe8bc Audio::GessoActor::HoldSound +806fe930 Audio::GessoActor::HoldSound(StartInfo) +806fe9b0 Audio::GessoActor::Reset +806fe9f0 Audio::GessoActor::GetPosition +806fe9f8 Audio::GessoActor::UpdateUserParam +806fea0c Audio::GessoActor::UpdateUserParam2 +806fea24 Audio::GessoActor::DisableConditional +806fea40 Audio::GessoActor::UpdateUserPar +806fea60 Audio::GessoActor::detail_UpdateAmbientArg +806feac4 Audio::ItemActor::StopAllSound +806feb28 Audio::ItemActor::StartSound +806feb9c Audio::ItemActor::StartSound(StartInfo) +806fec1c Audio::ItemActor::HoldSound +806fec90 Audio::ItemActor::HoldSound(StartInfo) +806fed10 Audio::ItemActor::Reset +806fed50 Audio::ItemActor::GetPosition +806fed58 Audio::ItemActor::UpdateUserParam +806fed6c Audio::ItemActor::UpdateUserParam2 +806fed84 Audio::ItemActor::detail_UpdateAmbientArg +806fede8 0x806fede8 +806fee74 0x806fee74 +806fef00 0x806fef00 +806fefc0 0x806fefc0 +806ff054 0x806ff054 +806ff0e8 0x806ff0e8 +806ff1a4 0x806ff1a4 +806ff28c 0x806ff28c +806ff374 0x806ff374 +806ff490 0x806ff490 +806ff4f8 0x806ff4f8 +806ff560 0x806ff560 +806ff604 0x806ff604 +806ff690 0x806ff690 +806ff71c 0x806ff71c +806ff7dc 0x806ff7dc +806ff870 0x806ff870 +806ff904 0x806ff904 +806ff9c0 Audio::Actor<2>::TryStartSound(u32) +806ffa4c Audio::Actor<2>::TryStartSound(ul) +806ffad8 Audio::Actor<2>::TryStartSound(str) +806ffb98 Audio::Actor<2>::TryStopAndStartSound(u32) +806ffc2c Audio::Actor<2>::TryStopAndStartSound(ul) +806ffcc0 Audio::Actor<2>::TryStopAndStartSound(str) +806ffd7c Audio::Actor<2>::TryHoldSound(u32) +806ffe64 Audio::Actor<2>::TryHoldSound(ul) +806fff4c Audio::Actor<2>::TryHoldSound(str) +80700068 Audio::Actor<2>::TryHoldSound(u32, handleId) +807000d0 Audio::Actor<2>::TryHoldSound(ul, handleId) +80700138 Audio::Actor<2>::TryHoldSound(str, handleId) +807001dc Audio::Actor<2>::TryPrepareSound(u32) +80700268 Audio::Actor<2>::TryPrepareSound(ul) +807002f4 Audio::Actor<2>::TryPrepareSound(str) +807003b4 Audio::Actor<2>::TryStopAndPrepareSound(u32) +80700448 Audio::Actor<2>::TryStopAndPrepareSound(ul) +807004dc Audio::Actor<2>::TryStopAndPrepareSound(str) +80700598 Audio::ItemActor::__dt +80700624 Audio::GessoActor::__dt +807006b0 0x807006b0 +807006b8 0x807006b8 +807006c0 0x807006c0 +807006c8 0x807006c8 +807006d0 0x807006d0 +807006d8 0x807006d8 +807006e0 0x807006e0 +807006e8 Audio::ItemActor::detail_UpdateAmbientArg(thunk) +807006f0 Audio::ItemActor::__dt(thunk) +807006f8 Audio::ItemActor::UpdateBRASDFrame(thunk) +80700700 Audio::ItemActor::SetupBRASD(thunk) +80700708 Audio::ItemActor::HoldSound(thunk) +80700710 Audio::ItemActor::HoldSound(StartInfo)(thunk) +80700718 Audio::ItemActor::StartSound(thunk) +80700720 Audio::ItemActor::StartSound(StartInfo)(thunk) +80700728 Audio::ItemActor::StartNewSoundLimited(thunk) +80700730 Audio::ItemActor::StopAllSound(thunk) +80700738 Audio::ItemActor::HoldSoundLimited(thunk) +80700740 Audio::ItemActor::StartSoundLimited(thunk) +80700748 Audio::ItemActor::UpdateUserParam3(thunk) +80700750 Audio::ItemActor::DisableConditional(thunk) +80700758 Audio::ItemActor::UpdateUserParam2(thunk) +80700760 Audio::ItemActor::UpdateUserParam(thunk) +80700768 Audio::ItemActor::Reset(thunk) +80700770 Audio::ItemActor::GetPosition(thunk) +80700778 Audio::ItemActor::Update(thunk) +80700780 Audio::ItemActor::Unlink(thunk) +80700788 Audio::ItemActor::Link(thunk) +80700790 0x80700790 +80700798 0x80700798 +807007a0 0x807007a0 +807007a8 Audio::GessoActor::detail_UpdateAmbientArg(thunk) +807007b0 Audio::GessoActor::__dt(thunk) +807007b8 Audio::GessoActor::UpdateBRASDFrame(thunk) +807007c0 Audio::GessoActor::SetupBRASD(thunk) +807007c8 Audio::GessoActor::HoldSound(thunk) +807007d0 Audio::GessoActor::HoldSound(StartInfo)(thunk) +807007d8 Audio::GessoActor::StartSound(thunk) +807007e0 Audio::GessoActor::StartSound(StartInfo)(thunk) +807007e8 Audio::GessoActor::StartNewSoundLimited(thunk) +807007f0 Audio::GessoActor::StopAllSound(thunk) +807007f8 Audio::GessoActor::HoldSoundLimited(thunk) +80700800 Audio::GessoActor::StartSoundLimited(thunk) +80700808 Audio::GessoActor::UpdateUserParam3(thunk) +80700810 Audio::GessoActor::DisableConditional(thunk) +80700818 Audio::GessoActor::UpdateUserParam2(thunk) +80700820 Audio::GessoActor::UpdateUserParam(thunk) +80700828 Audio::GessoActor::Reset(thunk) +80700830 Audio::GessoActor::GetPosition(thunk) +80700838 Audio::GessoActor::Update(thunk) +80700840 Audio::GessoActor::Link(thunk) +80700848 0x80700848 +80700888 Audio::KartActor::__ct +807009bc Audio::SimpleRaceActor::__dt +80700a48 Audio::KartActor::__dt +80700b0c Audio::KartActor::SetActorType +80700b2c Audio::KartActor::DisableConditional +80700b70 Audio::KartActor::UpdateUserParam3 +80700b90 Audio::KartActor::Link +80700ca4 Audio::KartActor::Unlink +80700d2c Audio::KartActor::Update +807014a0 0x807014a0 +807015d8 Audio::KartActor::StopAllSound +80701698 Audio::KartActor::SetupSound +8070169c Audio::KartActor::HoldSoundLimited +80701934 Audio::KartActor::StartSoundLimited +8070217c Audio::KartActor::OutputSoundToWiimotes +807021a0 Audio::KartActor::ApplyKCLSoundTrigger +80702208 Audio::KartActor::PlayBoostSound +807023a4 Audio::KartActor::PlayRampSound +80702540 0x80702540 +807027ac Audio::KartActor::PlayCannonSound +80702808 Audio::KartActor::PlayHornSound +80702910 Audio::KartActor::StartSound +80702994 Audio::KartActor::HoldSound +80702a20 Audio::KartActor::PlayMTSounds +80702c6c Audio::KartActor::PlayRoadSound +80702e80 0x80702e80 +80702f34 0x80702f34 +80702fdc Audio::KartActor::StartNewSoundLimited +80703164 Audio::KartActor::OnObjectNormalCollision +80703300 Audio::KartActor::OnObjectWallCollision +80703454 Audio::KartActor::PlayObjectCollisionSounds +80704628 Audio::KartActor::PlayWallCollisionSound +807046f8 Audio::KartActor::PlayBushCollisionSound +80704758 0x80704758 +80704804 0x80704804 +8070482c 0x8070482c +807048ac Audio::KartActor::UpdateLapSounds +80704aec Audio::KartActor::UpdateKCLValues +80704e74 0x80704e74 +80704f38 Audio::KartActor::SetRoadState +80704f4c Audio::KartActor::GetDriftAndSSMTRoadSoundId +80704fb0 Audio::KartActor::GetDriftAndSSMTRoadSoundId_switch +80704fb4 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_16 +80704fc8 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_15 +80704fd4 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_13 +80704fe8 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_b +80704ffc Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_5 +80705010 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_4 +80705024 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_3 +80705038 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_2 +8070504c Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_1 +80705060 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_0 +80705070 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_17 +80705084 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_1d +80705094 Audio::KartActor::GetDriftAndSSMTRoadSoundId_caseD_10 +8070509c Audio::KartActor::GetLandingSoundId +807050dc Audio::KartActor::GetLandingSoundId_switch +807050e0 Audio::KartActor::GetLandingSoundId_caseD_16 +807050f4 Audio::KartActor::GetLandingSoundId_caseD_15 +80705100 Audio::KartActor::GetLandingSoundId_caseD_13 +80705114 Audio::KartActor::GetLandingSoundId_caseD_b +80705128 Audio::KartActor::GetLandingSoundId_caseD_5 +8070513c Audio::KartActor::GetLandingSoundId_caseD_4 +80705150 Audio::KartActor::GetLandingSoundId_caseD_3 +80705164 Audio::KartActor::GetLandingSoundId_caseD_2 +80705178 Audio::KartActor::GetLandingSoundId_caseD_1 +8070518c Audio::KartActor::GetLandingSoundId_caseD_0 +8070519c Audio::KartActor::GetLandingSoundId_caseD_17 +807051b0 Audio::KartActor::GetLandingSoundId_caseD_1d +807051c0 Audio::KartActor::GetLandingSoundId_caseD_10 +807051c8 Audio::KartActor::GetRoadSoundId +80705230 Audio::KartActor::GetRoadSoundId_caseD_16 +80705244 Audio::KartActor::GetRoadSoundId_caseD_15 +80705250 Audio::KartActor::GetRoadSoundId_caseD_13 +80705264 Audio::KartActor::GetRoadSoundId_caseD_b +80705278 Audio::KartActor::GetRoadSoundId_caseD_5 +8070528c Audio::KartActor::GetRoadSoundId_caseD_4 +807052a0 Audio::KartActor::GetRoadSoundId_caseD_3 +807052b4 Audio::KartActor::GetRoadSoundId_caseD_2 +807052c8 Audio::KartActor::GetRoadSoundId_caseD_1 +807052dc Audio::KartActor::GetRoadSoundId_caseD_0 +807052ec Audio::KartActor::GetRoadSoundId_caseD_17 +80705300 Audio::KartActor::GetRoadSoundId_caseD_1d +80705310 Audio::KartActor::GetRoadSoundId_caseD_10 +80705318 Audio::KartActor::GetBrakingSoundId +80705380 Audio::KartActor::GetBrakingSoundId_caseD_16 +80705394 Audio::KartActor::GetBrakingSoundId_caseD_15 +807053a0 Audio::KartActor::GetBrakingSoundId_caseD_13 +807053b4 Audio::KartActor::GetBrakingSoundId_caseD_b +807053c8 Audio::KartActor::GetBrakingSoundId_caseD_5 +807053dc Audio::KartActor::GetBrakingSoundId_caseD_4 +807053f0 Audio::KartActor::GetBrakingSoundId_caseD_3 +80705404 Audio::KartActor::GetBrakingSoundId_caseD_2 +80705418 Audio::KartActor::GetBrakingSoundId_caseD_1 +8070542c Audio::KartActor::GetBrakingSoundId_caseD_0 +8070543c Audio::KartActor::GetBrakingSoundId_caseD_17 +80705450 Audio::KartActor::GetBrakingSoundId_caseD_1d +80705460 Audio::KartActor::GetBrakingSoundId_caseD_10 +80705468 Audio::KartActor::SetNonLocalVolumeAndPriority +80705ac4 0x80705ac4 +80705bc0 Audio::KartActor::PlayEngineSound +80705db4 Audio::KartActor::SetPitch +80705ec4 0x80705ec4 +80705f0c 0x80705f0c +80705f40 Audio::KartActor::PlayOtherKartCollisionSound +80705fe4 0x80705fe4 +80706064 Audio::SimpleRaceActor::SetupBRASD +80706068 Audio::SimpleRaceActor::UpdateBRASDFrame +8070606c 0x8070606c +80706070 Audio::SimpleRaceActor::__dt(thunk) +80706078 Audio::KartActor::__dt(thunk) +80706080 Audio::SimpleRaceActor::UpdateBRASDFrame(thunk) +80706088 Audio::SimpleRaceActor::SetupBRASD(thunk) +80706090 Audio::KartActor::HoldSound(thunk) +80706098 Audio::KartActor::StartSound(thunk) +807060a0 Audio::KartActor::StartNewSoundLimited(thunk) +807060a8 Audio::KartActor::StopAllSound(thunk) +807060b0 Audio::KartActor::HoldSoundLimited(thunk) +807060b8 Audio::KartActor::StartSoundLimited(thunk) +807060c0 Audio::KartActor::UpdateUserParam3(thunk) +807060c8 Audio::KartActor::DisableConditional(thunk) +807060d0 Audio::KartActor::Update(thunk) +807060d8 Audio::KartActor::Unlink(thunk) +807060e0 Audio::KartActor::Link(thunk) +807060e8 Audio::ObjectActor::__ct +80706194 0x80706194 +807061d4 Audio::ObjectActor::__dt +80706264 Audio::ObjectActor::Update +8070638c Audio::ObjectActor::Unlink +80706394 Audio::ObjectActor::Link +80706404 0x80706404 +8070645c Audio::ObjectActor::StartNewSoundLimited +80706fd4 Audio::ObjectActor::HoldSoundLimited +807072e8 Audio::ObjectActor::StartSoundLimited +807074a4 0x807074a4 +807077e4 Audio::ObjectActor::DisableConditional +80707c4c Audio::ObjectActor::UpdateUserParam3 +80707cd0 Audio::ObjectActor::SetupSound +80707d88 0x80707d88 +80707dcc Audio::ObjectActor::__dt(thunk) +80707dd4 Audio::ObjectActor::StartNew(thunk) +80707ddc Audio::ObjectActor::HoldSoundLimited(thunk) +80707de4 Audio::ObjectActor::StartSoundLimited(thunk) +80707dec Audio::ObjectActor::UpdateUserParam3(thunk) +80707df4 Audio::ObjectActor::DisableConditional(thunk) +80707dfc Audio::ObjectActor::Update(thunk) +80707e04 Audio::ObjectActor::Unlink(thunk) +80707e0c Audio::ObjectActor::Link(thunk) +80707e14 Audio::ItemAlterationMgr::Disposer__dt +80707f64 Audio::ItemAlterationMgr::CreateInstance +80707fd8 0x80707fd8 +80708018 Audio::ItemAlterationMgr::DestroyInstance +8070811c Audio::ItemAlterationMgr::__dt +807081f4 Audio::ItemAlterationMgr::Init +8070824c Audio::ItemAlterationMgr::IsDemo +8070826c Audio::ItemAlterationMgr::Update +8070840c Audio::ItemAlterationMgr::ResetItemState +80708424 Audio::ItemAlterationMgr::UpdateStatus +807085d8 Audio::ItemAlterationMgr::SetAudioAlteration +80708750 Audio::ItemAlterationMgr::GetCourseSoundId +80708770 Audio::ItemAlterationMgr::CalcStatus2Values +8070880c Audio::ItemAlterationMgr::PlayStarMusic +80708864 Audio::ItemAlterationMgr::PlayMegaMusic +8070889c Audio::RaceMgr::Disposer__dt +80708a2c Audio::RaceMgr::CreateInstance +80708a7c Audio::RaceMgr::DestroyInstance +80708bc0 Audio::RaceMgr::ActorHolder::Compare +80708be4 Audio::RaceMgr::__ct +80708e04 0x80708e04 +80708e44 Audio::RaceMgr::__dt +80708f5c Audio::RaceMgr::Init +80709108 Audio::RaceMgr::Shutdown +807091fc Audio::RaceMgr::Calc +807095fc 0x807095fc +807096f4 Audio::RaceMgr::UpdatePlayerMatrix +80709858 0x80709858 +807098ec 0x807098ec +80709974 Audio::RaceMgr::StartRace +80709a00 Audio::RaceMgr::UpdateActors +80709a70 Audio::RaceMgr::UpdateLocalPlayerParams +80709bc4 Audio::RaceMgr::IsAPlayerSquishedOrSmall +80709c88 Audio::RaceMgr::IsAPlayerInStar +80709cfc Audio::RaceMgr::IsAPlayerInMega +80709d70 0x80709d70 +80709db8 0x80709db8 +80709ebc Audio::RaceMgr::SetNonTrackVolumes +80709f68 Audio::RaceMgr::SetEngineVolume +80709f70 Audio::RaceMgr::SetNonTrackAndEngineVolume +8070a020 Audio::RaceMgr::SetRaceState +8070a71c 0x8070a71c +8070a790 0x8070a790 +8070a794 0x8070a794 +8070a7a8 0x8070a7a8 +8070a7bc 0x8070a7bc +8070a7dc 0x8070a7dc +8070a8dc 0x8070a8dc +8070a8fc 0x8070a8fc +8070a9a8 0x8070a9a8 +8070aa04 0x8070aa04 +8070aa9c 0x8070aa9c +8070ab30 Audio::RaceMgr::CheckRaceState +8070b038 0x8070b038 +8070b0b4 Audio::RaceMgr::SortAndToggleActors +8070bcb0 Audio::RaceMgr::SetKartSound +8070bd04 0x8070bd04 +8070bd48 0x8070bd48 +8070bd50 0x8070bd50 +8070bdec 0x8070bdec +8070be2c 0x8070be2c +8070bf58 0x8070bf58 +8070bfc0 0x8070bfc0 +8070c074 0x8070c074 +8070c118 0x8070c118 +8070c120 0x8070c120 +8070c1dc Audio::RSARPlayer::OutputSoundToWiimotes +8070c2c0 0x8070c2c0 +8070c328 Audio::RSARPlayer::IsDemo +8070c344 0x8070c344 +8070c36c 0x8070c36c +8070c3ec Audio::RSARPlayer::CreateInstance +8070c610 Audio::RSARPlayer::DestroyInstance +8070c688 Audio::RSARPlayer::Close +8070c6e0 Audio::RSARPlayer::OnLoad +8070c6ec Audio::RSARPlayer::Stop +8070c748 Audio::RSARPlayer::HasFinishedLoadingGroups +8070c754 Audio::RSARPlayer::Calc +8070c8cc Audio::RSARPlayer::OnNewPageLayer +8070c8d0 Audio::MenuRSARPlayer::OnNewPageLayer +8070caf4 0x8070caf4 +8070cbec 0x8070cbec +8070cbf8 0x8070cbf8 +8070cc04 Audio::RSARPlayer::PlaySoundById +8070ccc8 Audio::RSARPlayer::HoldSoundById +8070cd2c 0x8070cd2c +8070ce98 0x8070ce98 +8070ced8 Audio::RSARPlayer::PlaySound +8070db40 Audio::RSARPlayer::StopSoundById +8070db80 Audio::RSARPlayer::HoldSound +8070dba4 0x8070dba4 +8070dc50 0x8070dc50 +8070de3c 0x8070de3c +8070dee4 0x8070dee4 +8070dfa8 0x8070dfa8 +8070dfcc Audio::RSARPlayer::PrepareReverb +8070dfd0 Audio::RSARPlayer::Reset +8070dff4 Audio::MenuRSARPlayer::__ct +8070e028 Audio::MenuRSARPlayer::Prepare +8070e0d8 Audio::MenuRSARPlayer::Close +8070e130 Audio::MenuRSARPlayer::OnLoad +8070e198 Audio::MenuRSARPlayer::Stop +8070e1f4 Audio::MenuRSARPlayer::PrepareReverb +8070e300 Audio::RaceRSARPlayer::__ct +8070e380 Audio::RaceRSARPlayer::OnLoad +8070e3c0 Audio::RaceRSARPlayer::Stop +8070e428 Audio::RaceRSARPlayer::Pause +8070e4bc Audio::RaceRSARPlayer::Resume +8070e54c Audio::RaceRSARPlayer::PlayEndRaceMenuButtonClickSound +8070e564 Audio::RaceRSARPlayer::SetFullVolume +8070e574 Audio::RaceRSARPlayer::HalveVolume +8070e584 Audio::RaceRSARPlayer::Prepare +8070e6cc Audio::RaceRSARPlayer::LoadCharacterGroups +8070e810 Audio::RaceRSARPlayer::PrepareReverb +8070e960 Audio::RaceRSARPlayer::Close +8070e9c8 Audio::RaceRSARPlayer::Calc +8070eb64 Audio::RaceRSARPlayer::PlaySound +8070ecd8 Audio::RaceRSARPlayer::HoldSound +8070ed14 Audio::TestRSARPlayer::__ct +8070ed48 Audio::TestRSARPlayer::Prepare +8070ed78 Audio::TestRSARPlayer::Close +8070edd0 Audio::TestRSARPlayer::OnDeactivate +8070eddc Audio::GlobeRSARPlayer::__ct +8070ee18 Audio::RSARPlayer::__dt +8070ee9c Audio::GlobeRSARPlayer::OnDeactivate +8070eee8 Audio::GlobeRSARPlayer::Prepare +8070ef7c Audio::GlobeRSARPlayer::Calc +8070f0f4 Audio::GlobeRSARPlayer::PrepareReverb +8070f200 Audio::GlobeRSARPlayer::Close +8070f258 0x8070f258 +8070f2c4 Audio::Manager::OpenBRSAR +8070f2f0 Audio::Manager::Disposer__dt +8070f388 Audio::Manager::CreateInstance +8070f46c Audio::Manager::DestroyInstance +8070f4a0 Audio::Manager::__ct +8070f560 Audio::Manager::__dt +8070f660 Audio::Manager::DestroyAudioInstances +8070f6ac Audio::Manager::Init +8070f7a8 Audio::Manager::InitSelf +8070f980 0x8070f980 +8070f9fc 0x8070f9fc +8070fa3c 0x8070fa3c +8070fa7c Audio::Manager::CreateAudioInstances +8070fafc Audio::Manager::LoadControlsGroup +8070fb98 Audio::Manager::Calc +8070fca0 Audio::Manager::StartSound +8070fce8 Audio::Manager::HoldSound +8070fd30 Audio::Manager::EnterHBM +8070fda8 Audio::Manager::ExitHBM +8070fe30 Audio::Manager::AudioUtilityCallback +8070fe48 Audio::Manager::Lock +8070fe54 Audio::Manager::Unlock +8070fe60 Audio::Manager::PauseOnDVDBusy +8070ff10 Audio::Manager::SetupMemoryArchive +8070ff20 0x8070ff20 +8070ffac Audio::Manager::HoldSound +8070ffe0 Audio::Manager::HoldSound(str) +80710050 Audio::Manager::PrepareSound +80710084 Audio::Manager::PrepareSound(str) +807100f4 Audio::Manager::StartSound +80710128 Audio::Manager::StartSound(str) +80710198 0x80710198 +807101b8 Audio::Manager::LoadState(thunk) +807101c0 Audio::Manager::HoldSound(thunk) +807101c8 Audio::Manager::StartSound(thunk) +807101d0 Audio::Manager::Calc(thunk) +807101d8 Audio::Manager::LoadGroup(thunk) +807101e0 Audio::Manager::LoadGroup(thunk) +807101e8 Audio::Manager::LoadGroup(thunk) +807101f0 Audio::Manager::CloseArchive(thunk) +807101f8 Audio::Manager::SetupMemoryArchive(thunk) +80710200 Audio::Manager::SetupMemoryArchive(thunk) +80710208 Audio::Manager::OpenMemoryArchive(thunk) +80710210 Audio::Manager::OpenNANDArchive(thunk) +80710218 Audio::Manager::OpenDVDArchive(thunk) +80710220 Audio::Manager::OpenArchive(thunk) +80710228 Audio::Manager::__dt(thunk) +80710230 Audio::Manager::WriteSeqVariable +807102b0 0x807102b0 +807102f0 Audio::Track::SetValue +80710314 Audio::Track::Calc +80710358 Audio::PitchModuler::_ct +8071036c Audio::PitchModuler::Update +807103e8 Audio::PitchModuler::GetNextLimit +8071041c Audio::SoundTriggerMgr::Disposer__dt +80710548 Audio::SoundTriggerMgr::CreateInstance +807105cc Audio::SoundTriggerMgr::DestroyInstance +80710680 Audio::SoundTriggerMgr::__ct +807106d8 Audio::SoundTriggerMgr::__dt +8071077c Audio::SoundTriggerMgr::Init +807107d4 Audio::SoundTriggerMgr::Init_switch +807107d8 Audio::SoundTriggerMgr::Init_caseD_3a +80710854 Audio::SoundTriggerMgr::Init_caseD_1 +807108d0 Audio::SoundTriggerMgr::Init_caseD_4 +8071094c Audio::SoundTriggerMgr::Init_caseD_0 +807109c8 Audio::SoundTriggerMgr::Init_caseD_5 +80710a44 Audio::SoundTriggerMgr::Init_caseD_6 +80710ac0 Audio::SoundTriggerMgr::Init_caseD_3 +80710b3c Audio::SoundTriggerMgr::Init_caseD_c +80710bb8 Audio::SoundTriggerMgr::Init_caseD_18 +80710c34 Audio::SoundTriggerMgr::Init_caseD_1a +80710cb0 Audio::SoundTriggerMgr::Init_caseD_1d +80710d2c Audio::SoundTriggerMgr::Init_caseD_10 +80710da8 Audio::SoundTriggerMgr::Init_caseD_13 +80710e24 Audio::SoundTriggerMgr::Init_caseD_14 +80710ea0 Audio::SoundTriggerMgr::Init_caseD_17 +80710f1c Audio::SoundTriggerMgr::Init_caseD_15 +80710f98 Audio::SoundTriggerMgr::Init_caseD_20 +80711010 Audio::SoundTriggerMgr::Init_caseD_2a +8071102c Audio::SoundTriggerMgr::IsAPlayerOnVariant +80711070 Audio::SoundTriggerMgr::Shutdown +8071107c Audio::SoundTriggerMgr::Update +807110b8 Audio::SoundTriggerMgr::IsPlayerAheadOfOtherLocal +80711178 Audio::SoundTriggerMgr::ApplyTrigger +807112d0 Audio::SoundTriggerMgr::ApplyTrigger_switch +807112d4 Audio::SoundTriggerMgr::ApplyTrigger_caseD_3a +80711428 Audio::SoundTriggerMgr::ApplyTrigger_caseD_2 +807116cc Audio::SoundTriggerMgr::ApplyTrigger_caseD_4 +807116ec Audio::SoundTriggerMgr::ApplyTrigger_switch +807116f0 Audio::SoundTriggerMgr::ApplyTrigger_caseD_0 +80711774 Audio::SoundTriggerMgr::ApplyTrigger_caseD_1 +80711820 Audio::SoundTriggerMgr::ApplyTrigger_caseD_2 +807118a4 Audio::SoundTriggerMgr::ApplyTrigger_caseD_3 +80711948 Audio::SoundTriggerMgr::ApplyTrigger_caseD_4 +807119f4 Audio::SoundTriggerMgr::ApplyTrigger_caseD_5 +80711b14 Audio::SoundTriggerMgr::ApplyTrigger_caseD_6 +80711b80 Audio::SoundTriggerMgr::ApplyTrigger_caseD_7 +80711c40 Audio::SoundTriggerMgr::ApplyTrigger_caseD_0 +80711cb0 Audio::SoundTriggerMgr::ApplyTrigger_caseD_5 +80711ee8 Audio::SoundTriggerMgr::ApplyTrigger_caseD_6 +8071203c Audio::SoundTriggerMgr::ApplyTrigger_caseD_7 +80712138 Audio::SoundTriggerMgr::ApplyTrigger_caseD_f +807123a8 Audio::SoundTriggerMgr::ApplyTrigger_caseD_9 +80712418 Audio::SoundTriggerMgr::ApplyTrigger_caseD_e +807125dc Audio::SoundTriggerMgr::ApplyTrigger_caseD_3 +80712670 Audio::SoundTriggerMgr::ApplyTrigger_caseD_a +8071287c Audio::SoundTriggerMgr::ApplyTrigger_caseD_b +80712940 Audio::SoundTriggerMgr::ApplyTrigger_caseD_c +80712960 Audio::SoundTriggerMgr::ApplyTrigger_switch2 +80712964 Audio::SoundTriggerMgr::ApplyTrigger_case2D_0 +807129c0 Audio::SoundTriggerMgr::ApplyTrigger_case2D_1 +80712a30 Audio::SoundTriggerMgr::ApplyTrigger_case2D_2 +80712a80 Audio::SoundTriggerMgr::ApplyTrigger_case2D_3 +80712ad0 Audio::SoundTriggerMgr::ApplyTrigger_case2D_4 +80712b20 Audio::SoundTriggerMgr::ApplyTrigger_case2D_5 +80712b3c Audio::SoundTriggerMgr::ApplyTrigger_case2D_6 +80712b58 Audio::SoundTriggerMgr::ApplyTrigger_case2D_7 +80712b90 Audio::SoundTriggerMgr::ApplyTrigger_case2D_d +80712d7c Audio::SoundTriggerMgr::ApplyTrigger_case2D_1e +80712de8 Audio::SoundTriggerMgr::ApplyTrigger_case2D_1f +80712e18 Audio::SoundTriggerMgr::ApplyTrigger_case2D_1b +80712fc0 Audio::SoundTriggerMgr::ApplyTrigger_case2D_1a +807130b8 Audio::SoundTriggerMgr::ApplyTrigger_case2D_1c +807132a0 Audio::SoundTriggerMgr::ApplyTrigger_case2D_1d +807133c4 Audio::SoundTriggerMgr::ApplyTrigger_case2D_12 +80713430 Audio::SoundTriggerMgr::ApplyTrigger_case2D_11 +807134a0 Audio::SoundTriggerMgr::ApplyTrigger_case2D_13 +807135b0 Audio::SoundTriggerMgr::ApplyTrigger_case2D_14 +807135e0 Audio::SoundTriggerMgr::ApplyTrigger_case2D_16 +80713610 Audio::SoundTriggerMgr::ApplyTrigger_case2D_17 +807138f0 Audio::SoundTriggerMgr::ApplyTrigger_case2D_23 +80713920 Audio::SoundTriggerMgr::ApplyTrigger_case2D_1 +8071393c SetTRKConnected +80713948 0x80713948 +80713994 0x80713994 +80713998 0x80713998 +8071399c 0x8071399c +807139a0 0x807139a0 +80713a88 Audio::ItemWarning::Init +80713adc Audio::ItemWarningMgr::PlayTargetedWarning +80713d08 Audio::ItemWarningMgr::PlayUntargetedWarning +80713f40 Audio::ItemWarningMgr::PlayWarningOnWiimote +80713fb8 Audio::ItemWarningMgr::Disposer__dt +80714148 Audio::ItemWarningMgr::CreateInstance +807141d0 Audio::ItemWarning::__dt +8071422c Audio::ItemWarningMgr::DestroyInstance +8071430c Audio::ItemWarningMgr::__dt +807143e8 Audio::ItemWarningMgr::Init +80714464 Audio::ItemWarningMgr::Shutdown +80714470 Audio::ItemWarningMgr::GetItemWarning +80714480 Audio::FileManager::__dt +807144c0 0x807144c0 +80714500 0x80714500 +80714540 Audio::FileManager::Init +8071466c 0x8071466c +80714738 0x80714738 +80714930 Audio::FileManager::LoadBank +80714a70 0x80714a70 +80714bb0 0x80714bb0 +80714c1c Audio::FileManager::IsBankLoaded +80714ca4 0x80714ca4 +80714d2c 0x80714d2c +80714f6c 0x80714f6c +80715018 Audio::FileManager::InvalidateWaveData +80715064 Audio::FileManager::InvalidateData +807150b0 Audio::FileManager::GetFileWaveDataAddress +807150d8 Audio::FileManager::GetFileAddress +80715100 Audio::FileManager::AudioFileManager +80715150 Audio::FileManager::__dt(thunk) +80715158 Audio::FileManager::InvalidateData(thunk) +80715160 Audio::FileManager::InvalidateWaveData(thunk) +80715168 Audio::FileManager::SetRequest +80715304 0x80715304 +80715344 Audio::FileManager::LoadGroupAsync +80715554 0x80715554 +8071564c Audio::GroupBankRequester::Disposer__dt +80715778 Audio::GroupBankRequester::CreateInstance +807158e0 Audio::GroupBankRequester::DestroyInstance +80715994 Audio::GroupBankRequester::__ct +80715ad0 Audio::GroupBankRequester::__dt +80715b74 Audio::GroupBankRequester::RequestLoad(id) +80715bac Audio::GroupBankRequester::RequestLoad(actorId) +80715c24 0x80715c24 +80715c44 Audio::GroupBankRequester::ProcessRequests +80715cd0 Audio::GroupBankRequester::LoadAsync +80715e54 Audio::GroupBankRequester::GroupBankLoader +80715e74 Audio::GroupBankRequester::ConstructRequests +80715e88 0x80715e88 +80715f44 0x80715f44 +80715f84 0x80715f84 +80716010 0x80716010 +807160f4 0x807160f4 +80716200 0x80716200 +80716208 0x80716208 +80716360 0x80716360 +8071639c 0x8071639c +807163a0 0x807163a0 +807163dc 0x807163dc +807163ec 0x807163ec +807163fc 0x807163fc +8071642c 0x8071642c +80716468 0x80716468 +80716488 0x80716488 +80716498 0x80716498 +807164b8 0x807164b8 +80716548 0x80716548 +8071654c 0x8071654c +80716550 0x80716550 +80716558 0x80716558 +80716560 0x80716560 +80716568 0x80716568 +80716570 0x80716570 +80716578 0x80716578 +80716580 0x80716580 +80716588 0x80716588 +80716590 0x80716590 +80716598 Audio::PlayersVolumeMgr::Disposer__dt +807166c4 Audio::PlayersVolumeMgr::CreateInstance +807167b8 Audio::PlayersVolumeMgr::DestroyInstance +8071686c Audio::PlayersVolumeMgr::__dt +80716910 0x80716910 +807169d8 0x807169d8 +80716a88 0x80716a88 +80716aa0 0x80716aa0 +80716ab8 Audio::PlayersVolumeMgr::Calc +80716b40 Audio::PlayersVolumeMgr::StopAllPlayersButTrackUI +80716ba0 Audio::PlayersVolumeMgr::MuteAllButTrackUI +80716c24 Audio::PlayersVolumeMgr::ResetAllButUI +80716c6c Audio::PlayersVolumeMgr::Reset +80716d18 Audio::PlayersVolumeMgr::PauseAllButTrackUI +80716d88 Audio::PlayersVolumeMgr::SetVolume +80716e74 0x80716e74 +80716f2c 0x80716f2c +80716f4c 0x80716f4c +80716f88 Audio::EchoMgr::Disposer__dt +807170b4 Audio::EchoMgr::CreateInstance +80717168 Audio::EchoMgr::DestroyInstance +8071721c Audio::EchoMgr::__ct +807172a4 Audio::EchoMgr::__dt +80717348 Audio::EchoMgr::Init +8071736c Audio::EchoMgr::Shutdown +80717370 Audio::EchoMgr::Update +8071740c Audio::EchoMgr::SetVolume +80717424 Audio::EchoMgr::SetEcho +8071743c MotionControllerSub::__ct +807178ec MotionControllerSub::__dt +807179ec 0x807179ec +80717c74 0x80717c74 +80717d14 0x80717d14 +80717d34 0x80717d34 +80717d58 0x80717d58 +80717dc0 0x80717dc0 +80717df4 0x80717df4 +80717e70 0x80717e70 +80717e7c 0x80717e7c +80717e98 0x80717e98 +80717eb4 0x80717eb4 +80717f00 0x80717f00 +80717f40 0x80717f40 +80717f6c 0x80717f6c +80717fa0 0x80717fa0 +80717fcc 0x80717fcc +807180f4 0x807180f4 +807181ec 0x807181ec +8071829c 0x8071829c +807182f4 0x807182f4 +80718354 0x80718354 +80718368 0x80718368 +807183c0 0x807183c0 +807183d4 0x807183d4 +807183e8 0x807183e8 +80718478 0x80718478 +807184d0 0x807184d0 +807184f8 0x807184f8 +80718538 0x80718538 +80718548 0x80718548 +807187a8 0x807187a8 +8071897c 0x8071897c +80718af0 0x80718af0 +80718ba0 0x80718ba0 +80718c04 0x80718c04 +80718c78 0x80718c78 +80718e30 0x80718e30 +80718e70 0x80718e70 +8071900c 0x8071900c +80719170 0x80719170 +807191fc 0x807191fc +80719270 0x80719270 +8071936c 0x8071936c +80719408 0x80719408 +80719430 0x80719430 +80719470 0x80719470 +8071952c 0x8071952c +80719538 0x80719538 +807195a4 0x807195a4 +80719610 0x80719610 +807196ac 0x807196ac +807196d8 0x807196d8 +8071970c 0x8071970c +80719770 0x80719770 +80719830 0x80719830 +80719864 0x80719864 +80719c4c 0x80719c4c +80719d8c 0x80719d8c +80719da8 Lakitu::Manager::Disposer__dt +80719e40 Lakitu::Manager::CreateInstance +80719ecc Lakitu::Manager::DestroyInstance +80719f00 Lakitu::Manager::__ct +80719f60 Lakitu::Manager::__dt +8071a050 Lakitu::Manager::CreatePlayers +8071a208 Lakitu::Manager::Init +8071a290 Lakitu::Manager::Update +8071a304 Lakitu::Manager::DoEnableRespawnAction +8071a37c Lakitu::Manager::ToggleVisible +8071a3fc 0x8071a3fc +8071a474 Lakitu::Manager::StartCountdownAnm +8071a4dc 0x8071a4dc +8071a554 Lakitu::Manager::GetCountdownStartFrame +8071a584 Lakitu::Movement::__ct +8071a650 0x8071a650 +8071a73c Lakitu::Movement::Reset +8071a894 0x8071a894 +8071a9f0 0x8071a9f0 +8071ab78 0x8071ab78 +8071aba8 Lakitu::Movement::SetBasePosition +8071abc4 0x8071abc4 +8071ac14 AI::CalcLinearTransfo +8071ac9c 0x8071ac9c +8071add4 0x8071add4 +8071aeec 0x8071aeec +8071afd4 Lakitu::Movement::Update +8071b5fc 0x8071b5fc +8071b818 0x8071b818 +8071b82c 0x8071b82c +8071b850 0x8071b850 +8071bbf4 Lakitu::Movement::UpdateRotation +8071bd80 0x8071bd80 +8071be8c Lakitu::Movement::UpdateExtMtx +8071c0bc 0x8071c0bc +8071c0d0 0x8071c0d0 +8071c198 0x8071c198 +8071c234 0x8071c234 +8071c2fc 0x8071c2fc +8071c31c 0x8071c31c +8071c470 0x8071c470 +8071c5f0 Lakitu::Movement::UpdateScale +8071c7dc 0x8071c7dc +8071c900 0x8071c900 +8071ca5c 0x8071ca5c +8071cb14 Lakitu::PlayerBase::__ct +8071cb5c Lakitu::PlayerBase::__dt +8071cbec Lakitu::PlayerBase::Init +8071cbf4 Lakitu::PlayerBase::Update +8071cc60 Lakitu::PlayerBase::ToggleModelsScreenVisibility +8071ccf8 Lakitu::PlayerBase::SetModelsVisibility +8071ce2c 0x8071ce2c +8071cf38 0x8071cf38 +8071d00c 0x8071d00c +8071d078 0x8071d078 +8071d0e4 Lakitu::Player::__ct +8071d7e4 AI::Base::__dt +8071d824 AI::Actions::__dt +8071d864 0x8071d864 +8071d8bc Lakitu::Action::__dt +8071d8fc Lakitu::Player::__dt +8071da34 0x8071da34 +8071da90 Lakitu::Player::CreateEnableActions +8071db58 0x8071db58 +8071dbcc 0x8071dbcc +8071dc24 0x8071dc24 +8071dcd0 Lakitu::Player::Init +8071dd94 Lakitu::Player::Update +8071df6c Lakitu::Player::GetPlayerIdx +8071df74 Lakitu::Player::StartRespawnAction +8071df8c Lakitu::Player::StartCountdownAction +8071dfdc Lakitu::Player::GetCountdownArmSwipeDuration +8071dfe8 0x8071dfe8 +8071e0d4 Lakitu::Player::LoadGraphics +8071ea24 0x8071ea24 +8071ea70 0x8071ea70 +8071eaa8 0x8071eaa8 +8071eb3c 0x8071eb3c +8071eca4 Lakitu::Player::MapToWorldSpace +8071eeb4 0x8071eeb4 +8071ef90 0x8071ef90 +8071f028 Lakitu::Player::OnStartIdle +8071f074 Lakitu::Player::UpdateIdle +8071f168 Lakitu::Player::OnStartCountdown +8071f2dc 0x8071f2dc +8071f37c Lakitu::Player::UpdateCountdown +8071f6c8 0x8071f6c8 +8071f76c 0x8071f76c +8071f7f0 Lakitu::Player::OnEndCountdown +8071f84c Lakitu::Player::OnStartLap +8071fa90 Lakitu::Player::UpdateLap +8071fe6c 0x8071fe6c +8071fec4 Lakitu::Player::OnStartRespawn +80720000 Lakitu::Player::UpdateRespawn +80720348 0x80720348 +80720364 Lakitu::Player::OnStartBackwards +80720450 Lakitu::Player::UpdateBackwards +80720b40 Lakitu::Player::OnEndBackwards +80720c30 Lakitu::Player::OnStartEnding +80720d40 Lakitu::Player::UpdateEnding +80720ff4 Lakitu::Player::OnEndEnding +80721070 Lakitu::Player::OnStartUnknown +80721090 Lakitu::Player::UpdateUnknown +80721178 AI::Base::OnStartDefaultAction +8072117c AI::Base::UpdateDefaultAction +80721180 Lakitu::Action::OnStart +807211c8 Lakitu::Action::Update +807211f8 Lakitu::Action::OnEnd +80721240 0x80721240 +807215b4 Lakitu::Player::__dt(thunk) +807215bc Lakitu::EnableLakituAction::__ct +807215dc Lakitu::EnableLakituAction::__dt +8072161c Lakitu::EnableLakituAction::ResetState +8072162c Lakitu::EnableLakituAction::HasActionHappened +80721648 Lakitu::EnableCountdownAction::__ct +80721668 Lakitu::EnableCountdownAction::__dt +807216a8 Lakitu::EnableCountdownAction::ResetState +807216b8 Lakitu::EnableCountdownAction::EnableAction +80721718 Lakitu::EnableDisplayLapAction::__ct +80721738 Lakitu::EnableDisplayLapAction::__dt +80721778 Lakitu::EnableDisplayLapAction::ResetState +807217a8 Lakitu::EnableDisplayLapAction::EnableAction +807217ec Lakitu::EnableBackwardsAction::__ct +8072180c Lakitu::EnableBackwardsAction::__dt +8072184c Lakitu::EnableBackwardsAction::ResetState +80721868 Lakitu::EnableBackwardsAction::EnableAction +807219a8 Lakitu::EnableRespawnAction::__ct +807219c8 Lakitu::EnableRespawnAction::__dt +80721a08 Lakitu::EnableRespawnAction::ResetState +80721a18 Lakitu::EnableRespawnAction::EnableAction +80721a1c Lakitu::EnableEndingAction::__ct +80721a3c Lakitu::EnableEndingAction::__dt +80721a7c Lakitu::EnableEndingAction::ResetState +80721a8c Lakitu::EnableEndingAction::EnableAction +80721adc 0x80721adc +80721afc 0x80721afc +80721b3c cGameSFX_Init +80721b4c 0x80721b4c +80721bac KartAIController::__ct +80721c58 KartAIController::__dt +80721ce0 KartAIController::Init +80721d88 KartAIController::Update +80721dd4 KartAIController::GetStick +80721e1c KartAIController::IsCPU +80721e60 KartAIController::IsRealLocal +80721ea0 0x80721ea0 +80721f08 thunk_0x80590664 +80721f0c KartAIController::IsGhost +80721f50 KartAIController::HaveSameTeam +80721f78 0x80721f78 +80721f80 0x80721f80 +80721f94 0x80721f94 +80721f9c 0x80721f9c +807220b8 KartAIController::IsOnTheGround +807220cc KartAIController::IsInTheAir +807220e0 0x807220e0 +807220f4 KartAIController::IsManuallyDrifting +80722108 KartAIController::IsHopping +8072211c KartAIController::IsAutomaticDrifting +80722130 KartAIController::IsInABill +80722144 0x80722144 +80722408 0x80722408 +80722448 0x80722448 +80722488 0x80722488 +807224a8 0x807224a8 +80722514 0x80722514 +8072251c 0x8072251c +8072265c 0x8072265c +80722738 0x80722738 +80722880 0x80722880 +8072288c 0x8072288c +807228b4 0x807228b4 +807228c0 0x807228c0 +8072297c 0x8072297c +80722984 0x80722984 +8072298c 0x8072298c +80722998 0x80722998 +80722ab0 0x80722ab0 +80722af8 0x80722af8 +80722b28 0x80722b28 +80722b70 0x80722b70 +80722b98 AI::CPUDriving::__ct +80722d14 AI::CPUDriving::__dt +80722ea4 0x80722ea4 +80722ee4 AI::CPUDriving::Init +80723018 AI::CPUDriving::InitEnemyRoute +807230a4 0x807230a4 +807230e4 0x807230e4 +807230ec 0x807230ec +807230f4 0x807230f4 +807230fc 0x807230fc +8072310c AI::CPUDriving::CalcStartBoost +8072316c 0x8072316c +80723170 ParamActionCalculator::GetStartBoost +80723178 0x80723178 +8072335c 0x8072335c +80723364 0x80723364 +8072336c 0x8072336c +8072344c 0x8072344c +80723470 0x80723470 +807234b0 0x807234b0 +807234c4 0x807234c4 +807234d8 0x807234d8 +8072353c 0x8072353c +80723550 0x80723550 +80723590 0x80723590 +8072359c 0x8072359c +80723640 0x80723640 +80723688 AI::CPUDriving::IsBattle +80723690 0x80723690 +80723694 0x80723694 +80723698 0x80723698 +8072369c 0x8072369c +807236a4 0x807236a4 +807236ac 0x807236ac +807236b0 0x807236b0 +807236ec 0x807236ec +80723e80 0x80723e80 +80723ec0 0x80723ec0 +80723fe0 0x80723fe0 +807241dc 0x807241dc +807241e0 0x807241e0 +80724258 0x80724258 +8072429c 0x8072429c +80724304 0x80724304 +807243fc 0x807243fc +8072441c 0x8072441c +80724484 0x80724484 +80724670 0x80724670 +80724678 0x80724678 +80724760 0x80724760 +80724768 0x80724768 +80724770 0x80724770 +80724778 0x80724778 +80724788 0x80724788 +807247cc 0x807247cc +8072492c 0x8072492c +80724b14 0x80724b14 +80724b30 0x80724b30 +80724c7c 0x80724c7c +80724da0 0x80724da0 +80724f74 0x80724f74 +80725150 0x80725150 +80725178 0x80725178 +80725258 0x80725258 +8072525c 0x8072525c +80725270 0x80725270 +8072527c 0x8072527c +8072535c 0x8072535c +8072537c 0x8072537c +807253bc 0x807253bc +807253fc 0x807253fc +80725554 0x80725554 +80725620 0x80725620 +80725628 0x80725628 +80725798 0x80725798 +80725818 0x80725818 +8072582c 0x8072582c +8072586c 0x8072586c +8072587c 0x8072587c +80725890 WorldLoader_GetStadiumTerrain +807258a4 0x807258a4 +807258b4 0x807258b4 +807258c8 0x807258c8 +80725908 0x80725908 +80725a7c 0x80725a7c +80725a84 0x80725a84 +80725a98 0x80725a98 +80725ad8 0x80725ad8 +80725ff0 0x80725ff0 +80726004 0x80726004 +80726044 0x80726044 +80726308 0x80726308 +8072633c 0x8072633c +8072637c 0x8072637c +807263d0 0x807263d0 +807263e0 0x807263e0 +807265fc 0x807265fc +807267e8 0x807267e8 +80726954 0x80726954 +80726a3c 0x80726a3c +80726af8 0x80726af8 +80726b2c 0x80726b2c +80726b6c 0x80726b6c +80726bc4 0x80726bc4 +80726bf8 0x80726bf8 +80726c38 0x80726c38 +80726c78 0x80726c78 +80726c7c 0x80726c7c +80726c84 0x80726c84 +80726c8c 0x80726c8c +80726c94 0x80726c94 +80726c9c 0x80726c9c +80726ca4 0x80726ca4 +80726cac 0x80726cac +80726cb4 0x80726cb4 +80726cb8 0x80726cb8 +80726cf8 0x80726cf8 +80726d00 0x80726d00 +80726d08 0x80726d08 +80726d10 0x80726d10 +80726d18 0x80726d18 +80726d20 0x80726d20 +80726d28 0x80726d28 +80726d70 0x80726d70 +80726da0 0x80726da0 +80726de8 AI::CPUDrivingRace::__ct +80726f74 AI::CPUDrivingAction::__dt +80726fb4 AI::CPUDrivingRace::__dt +80727070 AI::CPUDrivingRace::Init +80727160 AI::CPUDrivingRace::InitEnemyRoute +807272fc 0x807272fc +807273a8 0x807273a8 +807273dc AI::CPUDrivingRace::Update +807274d8 0x807274d8 +8072752c 0x8072752c +807276c8 0x807276c8 +807276cc 0x807276cc +807276d0 0x807276d0 +807276d8 0x807276d8 +807276e0 0x807276e0 +807276e8 0x807276e8 +80727730 0x80727730 +80727760 0x80727760 +807277a8 AI::Inputs::__ct +807277cc AI::Inputs::Reset +807277e4 AI::Inputs::AddInputs +807277f4 AI::Inputs::RemoveInputs +80727804 0x80727804 +8072780c AI::Player::__ct +807281a8 AI::PlayerActions::__dt +807281e8 AI::Player::__dt +80728350 AI::Player::Init +807284c0 AI::Player::Update +807284e4 AI::Player::vf_0x20 +80728574 0x80728574 +80728594 0x80728594 +80728638 0x80728638 +807286d8 AI::Player::OnStartPreRace +80728728 AI::Player::UpdatePreRace +807288b4 AI::Player::OnStartAI::CPUDriving +807288b8 AI::Player::UpdateAI::CPUDriving +80728ab4 AI::Player::OnStartRealPlayerDriving +80728ab8 AI::Player::UpdateRealPlayerDriving +80728bcc AI::Player::OnStartAction3 +80728bd0 AI::Player::UpdateAction3 +80728bd4 AI::Player::OnStartPostRaceDriving +80728c24 0x80728c24 +80728c28 AI::Player::UpdatePostRaceDriving +80728dcc AI::Player::OnStartPostBattleDriving +80728e1c AI::Player::UpdatePostBattleDriving +80728f3c AI::PlayerActions::OnStart +80728f84 AI::PlayerActions::Update +80728fb4 AI::PlayerActions::OnEnd +80728ffc AI::PlayerBike::__ct +80729080 AI::PlayerBike::__dt +807290d8 AI::PlayerBike::Init +807290dc AI::PlayerBike::Update +807290e0 AI::PlayerBike::vf_0x20 +807290e4 AI::PlayerBike::OnStartAction1 +807290e8 AI::PlayerBike::UpdateAction1 +807290ec AI::PlayerKart::__ct +80729144 AI::PlayerKart::__dt +8072919c AI::PlayerKart::Init +80729200 AI::PlayerKart::Update +80729204 AI::PlayerKart::vf_0x20 +80729208 AI::PlayerKart::OnStartAction1 +8072920c AI::PlayerKart::UpdateAction1 +80729210 0x80729210 +807298c4 0x807298c4 +80729904 0x80729904 +80729944 0x80729944 +80729964 0x80729964 +807299a8 0x807299a8 +807299ec 0x807299ec +807299f4 0x807299f4 +807299fc 0x807299fc +80729a04 0x80729a04 +80729a0c 0x80729a0c +80729a14 0x80729a14 +80729aa8 0x80729aa8 +80729b2c 0x80729b2c +80729b68 0x80729b68 +80729b94 0x80729b94 +80729ba8 0x80729ba8 +80729bc4 0x80729bc4 +80729bdc 0x80729bdc +80729bf8 0x80729bf8 +80729c60 0x80729c60 +80729c6c 0x80729c6c +80729ea0 0x80729ea0 +80729ea8 0x80729ea8 +80729eac 0x80729eac +80729f94 0x80729f94 +80729f98 0x80729f98 +8072a064 0x8072a064 +8072a068 0x8072a068 +8072a130 0x8072a130 +8072a134 0x8072a134 +8072a140 0x8072a140 +8072a23c 0x8072a23c +8072a248 0x8072a248 +8072a344 0x8072a344 +8072a348 0x8072a348 +8072a3d4 0x8072a3d4 +8072a3d8 0x8072a3d8 +8072a3dc 0x8072a3dc +8072a424 0x8072a424 +8072a464 0x8072a464 +8072a4bc 0x8072a4bc +8072a500 0x8072a500 +8072a50c 0x8072a50c +8072a600 0x8072a600 +8072a708 0x8072a708 +8072a894 0x8072a894 +8072a8a0 0x8072a8a0 +8072a8b8 0x8072a8b8 +8072a988 0x8072a988 +8072aa7c 0x8072aa7c +8072aabc 0x8072aabc +8072ac54 0x8072ac54 +8072ad2c 0x8072ad2c +8072af18 0x8072af18 +8072af28 0x8072af28 +8072af2c 0x8072af2c +8072b024 0x8072b024 +8072b06c 0x8072b06c +8072b09c 0x8072b09c +8072b0e4 0x8072b0e4 +8072b0f8 0x8072b0f8 +8072b138 0x8072b138 +8072b13c 0x8072b13c +8072b140 0x8072b140 +8072b190 0x8072b190 +8072b240 0x8072b240 +8072b254 0x8072b254 +8072b294 0x8072b294 +8072b298 0x8072b298 +8072b2a8 0x8072b2a8 +8072b2ac 0x8072b2ac +8072b3a4 0x8072b3a4 +8072b3b8 0x8072b3b8 +8072b3f8 0x8072b3f8 +8072b3fc 0x8072b3fc +8072b43c 0x8072b43c +8072b448 0x8072b448 +8072b56c 0x8072b56c +8072b674 0x8072b674 +8072b688 0x8072b688 +8072b6c8 0x8072b6c8 +8072b790 AI::Manager::Disposer__dt +8072b828 AI::Manager::CreateInstance +8072b878 AI::Manager::DestroyInstance +8072b8ac AI::Manager::__ct +8072ba84 AI::Manager::__dt +8072bc04 AI::Manager::AddKartAIController +8072bcd8 AI::Manager::GetKartAIController +8072bce8 AI::Manager::GetRealPlayerKartAIController +8072bcf8 obj_checkIfSomething +8072bd00 AI::Manager::Init +8072be04 AI::Manager::Update +8072bf08 AI::Manager::GetLocalPlayerCount +8072bf18 AI::Manager::GetEngineClass +8072bf20 AI::Manager::GetDifficulty +8072bf28 0x8072bf28 +8072bf64 0x8072bf64 +8072c034 AI::Manager::IsGPOrPrivateVS +8072c05c AI::Manager::IsVS +8072c07c AI::Manager::IsTT +8072c0a4 AI::Manager::IsMissionTournament +8072c0c4 AI::Manager::IsOnline +8072c0ec AI::Manager::IsBattle +8072c118 AI::Manager::IsOfflineBattle +8072c138 AI::Manager::IsBallonBattle +8072c150 AI::Manager::IsCoinRunners +8072c16c AI::Manager::IsTT2 +8072c194 AI::Manager::IsSpecialItemMode +8072c244 AI::Manager::IsTeamMode +8072c258 0x8072c258 +8072c260 AI::Manager::IsAwardsOrCredits +8072c284 AiHolder_getRealPlayerCountPerTeam +8072c31c AI::Manager::GetRandomValue +8072c344 AI::Manager::GetRandomFloat +8072c374 AI::Manager::SetCCAndDifficulty +8072c454 0x8072c454 +8072c500 0x8072c500 +8072c5a8 AiHolder_getBestPreviousScore +8072c648 0x8072c648 +8072c684 0x8072c684 +8072c710 0x8072c710 +8072c754 0x8072c754 +8072c8b8 0x8072c8b8 +8072c924 0x8072c924 +8072c9c8 0x8072c9c8 +8072c9cc 0x8072c9cc +8072c9dc 0x8072c9dc +8072c9fc 0x8072c9fc +8072ca3c 0x8072ca3c +8072cac0 0x8072cac0 +8072cd5c 0x8072cd5c +8072cfbc 0x8072cfbc +8072d04c 0x8072d04c +8072d258 0x8072d258 +8072d36c 0x8072d36c +8072d47c 0x8072d47c +8072d508 0x8072d508 +8072d540 AI::Params::__ct +8072d5d0 AI::Params::__dt +8072d658 AI::Params::GetParamSpeed +8072d660 AI::Params::GetParamAction +8072d670 AI::Params::LoadParamFile +8072d680 AI::Params::Load +8072d948 0x8072d948 +8072d9a4 0x8072d9a4 +8072d9f8 AI::Params::LoadActions +8072dad0 AI::EnemyRouteController::__ct +8072de74 AI::ENPTSettingsHolder::__dt +8072deb4 AI::EnemyRouteController::__dt +8072dfb4 AI::EnemyRouteController::Init +8072e068 AI::EnemyRouteController::Update +8072e1c8 0x8072e1c8 +8072e208 0x8072e208 +8072e24c 0x8072e24c +8072e26c 0x8072e26c +8072e288 0x8072e288 +8072e290 0x8072e290 +8072e298 0x8072e298 +8072e2bc 0x8072e2bc +8072e360 0x8072e360 +8072e448 0x8072e448 +8072e450 0x8072e450 +8072e4c4 0x8072e4c4 +8072e518 0x8072e518 +8072e528 0x8072e528 +8072e600 0x8072e600 +8072e6e0 0x8072e6e0 +8072e728 AI::EnemyRouteController::IsOutCurENPTBounds +8072e8fc 0x8072e8fc +8072ea14 0x8072ea14 +8072eae8 AI::EnemyRouteHolder::AdvanceToNextENPT +8072ec24 0x8072ec24 +8072ec98 AI::EnemyRouteHolder::__ct +8072ece0 AI::EnemyRouteHolder::__dt +8072ed20 AI::EnemyRouteHolder::AddKartAIController +8072ed64 0x8072ed64 +8072ed68 0x8072ed68 +8072ed6c 0x8072ed6c +8072ef18 0x8072ef18 +8072ef24 AI::ParamActionCalculator::__ct +8072ef48 AI::ParamActionCalculator::__dt +8072ef88 AI::ParamActionCalculator::Init +8072efc0 AI::ParamActionCalculator::CalcStartBoost +8072f0dc AI::ParamActionCalculator::CalcGotDrift +8072f198 AI::ParamActionCalculator::CalcGotMT +8072f23c AI::ParamActionCalculator::CalcGotTrick +8072f2c4 AI::ParamActionCalculator::CalcGotWheelie +8072f34c AI::ParamActionCalculator::CalcGotParamAction6 +8072f3d4 AI::ParamActionCalculator::CalcGotParamAction7 +8072f45c 0x8072f45c +8072f4b0 0x8072f4b0 +8072f4f4 0x8072f4f4 +8072f534 0x8072f534 +8072f570 0x8072f570 +8072f608 0x8072f608 +8072f628 0x8072f628 +8072f640 0x8072f640 +8072f748 0x8072f748 +8072f79c 0x8072f79c +8072f7d8 0x8072f7d8 +8072f818 0x8072f818 +8072f848 0x8072f848 +8072f86c 0x8072f86c +8072f8a0 0x8072f8a0 +8072f8dc 0x8072f8dc +8072f97c 0x8072f97c +8072fa2c 0x8072fa2c +8072fa60 0x8072fa60 +8072fb40 0x8072fb40 +8072fb54 0x8072fb54 +8072fb90 0x8072fb90 +8072fbbc 0x8072fbbc +8072fbe8 0x8072fbe8 +8072fcac 0x8072fcac +8072fcec 0x8072fcec +8072fd2c 0x8072fd2c +8072fd5c 0x8072fd5c +8072fd68 0x8072fd68 +8072fd74 0x8072fd74 +8072fe04 0x8072fe04 +8072febc 0x8072febc +807301e4 0x807301e4 +807302e8 0x807302e8 +807305ec 0x807305ec +807305fc 0x807305fc +80730738 0x80730738 +80730834 0x80730834 +80730838 0x80730838 +8073086c 0x8073086c +807308a8 0x807308a8 +807308e8 0x807308e8 +80730918 0x80730918 +80730924 0x80730924 +80730930 0x80730930 +80730940 0x80730940 +80730ae8 0x80730ae8 +80730be4 0x80730be4 +80730be8 0x80730be8 +80730c1c 0x80730c1c +80730c58 0x80730c58 +80730c98 0x80730c98 +80730cc8 0x80730cc8 +80730dc4 0x80730dc4 +80730dc8 0x80730dc8 +80730dfc OS::GetCurrentContext +80730e08 0x80730e08 +80730e14 0x80730e14 +80730e18 0x80730e18 +80730e1c 0x80730e1c +80730e24 0x80730e24 +80730e2c 0x80730e2c +80730e34 0x80730e34 +80730e3c 0x80730e3c +80730e44 0x80730e44 +80730e48 0x80730e48 +80730e4c 0x80730e4c +80730e50 0x80730e50 +807314bc 0x807314bc +807314fc 0x807314fc +807315ec 0x807315ec +8073169c 0x8073169c +80731788 GameInfoManager_SetUserSelectedCupSidekick +80731794 0x80731794 +80731938 0x80731938 +807319ac 0x807319ac +807319b4 0x807319b4 +807319bc 0x807319bc +807319cc 0x807319cc +80731a0c 0x80731a0c +80731a14 0x80731a14 +80731ab4 0x80731ab4 +80731acc 0x80731acc +80731b44 0x80731b44 +80731e20 0x80731e20 +80732180 0x80732180 +80732240 0x80732240 +80732330 0x80732330 +80732400 0x80732400 +807324cc 0x807324cc +80732614 0x80732614 +807326b8 0x807326b8 +80732818 0x80732818 +8073292c 0x8073292c +80732988 0x80732988 +8073298c 0x8073298c +807329cc 0x807329cc +80732a78 0x80732a78 +80732b94 0x80732b94 +80732c38 0x80732c38 +80732c44 0x80732c44 +80732cf4 0x80732cf4 +80732d40 0x80732d40 +80732d8c 0x80732d8c +80732dfc 0x80732dfc +80732fb4 0x80732fb4 +80733114 0x80733114 +807332f0 0x807332f0 +80733478 0x80733478 +80733518 0x80733518 +8073351c 0x8073351c +8073355c 0x8073355c +80733574 0x80733574 +8073358c 0x8073358c +807335a4 0x807335a4 +80733604 0x80733604 +80733860 0x80733860 +807338a8 0x807338a8 +807338d8 0x807338d8 +80733920 0x80733920 +8073394c 0x8073394c +8073398c 0x8073398c +807339c4 0x807339c4 +80733a10 0x80733a10 +80733a60 0x80733a60 +80733ac0 0x80733ac0 +80733acc 0x80733acc +80733ae4 cGame_GetGameTime +80733af0 0x80733af0 +80733b24 0x80733b24 +80733d74 0x80733d74 +80733dc8 0x80733dc8 +80733e08 0x80733e08 +80733f28 0x80733f28 +80733f54 0x80733f54 +80733fb4 0x80733fb4 +80734050 0x80734050 +807340ec 0x807340ec +807342c8 0x807342c8 +80734300 0x80734300 +80734340 0x80734340 +8073438c 0x8073438c +80734498 0x80734498 +807344cc 0x807344cc +8073450c 0x8073450c +807345ac 0x807345ac +80734730 0x80734730 +80734768 0x80734768 +807347a8 0x807347a8 +807347f4 0x807347f4 +8073485c 0x8073485c +80734864 0x80734864 +80734b60 0x80734b60 +80734ba0 0x80734ba0 +80734c28 0x80734c28 +80734cd8 0x80734cd8 +80734d50 0x80734d50 +80734d58 0x80734d58 +80734d7c 0x80734d7c +80734e14 0x80734e14 +80734e20 0x80734e20 +80734ee0 0x80734ee0 +80735018 0x80735018 +807350ac 0x807350ac +807350c0 0x807350c0 +80735298 0x80735298 +8073530c 0x8073530c +8073578c 0x8073578c +807357f4 0x807357f4 +8073582c 0x8073582c +80735830 0x80735830 +80735850 0x80735850 +80735890 0x80735890 +807358a0 0x807358a0 +807358f8 0x807358f8 +80735940 0x80735940 +80735970 0x80735970 +807359b8 MotionController::__ct +80735a50 0x80735a50 +80735a90 MotionController::__dt +80735b18 MotionController::Init +80735d18 MotionController::UpdateForNunchuck +80735f18 MotionController::UpdateForCore +80736260 0x80736260 +807363ec 0x807363ec +80736580 0x80736580 +807365d0 0x807365d0 +8073669c 0x8073669c +80736890 0x80736890 +807368f0 0x807368f0 +80736aa4 0x80736aa4 +80736c30 0x80736c30 +80736d98 0x80736d98 +80737288 0x80737288 +807372cc Objects::PoihanaBase::__ct +8073733c Objects::PoihanaBase::__dt +8073737c Objects::PoihanaBase::OnStart +80737428 Objects::PoihanaBase::Update +8073743c Objects::PoihanaBase:GetTranslation +80737458 0x80737458 +807374b4 0x807374b4 +807374d0 0x807374d0 +80737538 0x80737538 +807375c8 0x807375c8 +80737618 0x80737618 +80737664 0x80737664 +80737710 0x80737710 +8073780c 0x8073780c +807378bc 0x807378bc +80737a60 UnkCollidableSub::__ct +80737aa8 UnkCollidableSub::__dt +80737ae8 UnkCollidableSub::Reset +80737b08 UnkCollidableSub::Update +80737d30 0x80737d30 +80737d4c UnkCollidableSub::vf_0x14 +80737d74 Objects::PoihanaBase::SubChild::__ct +80737dcc Objects::PoihanaBase::SubChild::__dt +80737e0c Objects::PoihanaBase::SubChild::Reset +80737e30 Objects::PoihanaBase::SubChild::Update +80738094 0x80738094 +8073826c Objects::Poihana::SubChild::vf_0x14 +80738290 Objects::PoihanaBase::GetPropertiesBitfield +80738298 Objects::PoihanaBase::__dt(thunk) +807382a0 Objects::Poihana::__ct +807389b0 Objects::Poihana::Actions::__dt +807389f0 Objects::Poihana::__dt +80738a8c Objects::Poihana::OnStart +80738ca4 Objects::Poihana::Update +80738d08 0x80738d08 +80738e20 Objects::Poihana::LoadAnimations +80738ecc 0x80738ecc +807394ac Objects::Poihana::OnCollision +80739638 Objects::Poihana::OnItemCollision +80739744 0x80739744 +807397f8 0x807397f8 +807398c8 0x807398c8 +8073993c 0x8073993c +80739958 0x80739958 +807399e0 Objects::Poihana::OnStartIdle +80739a58 Objects::Poihana::UpdateIdleAndAction1 +80739c1c Objects::Poihana::OnStartChase +80739c34 Objects::Poihana::UpdateChase +8073a088 0x8073a088 +8073a0a4 Objects::Poihana::OnStartCatapult +8073a238 Objects::Poihana::UpdateCatapult +8073a2b4 Objects::Poihana::OnEndCatapult +8073a2c0 Objects::Poihana::OnStartCatapultNoMove +8073a310 Objects::Poihana::UpdateCatapultNoMove +8073a3c0 Objects::Poihana::OnEndCatapultNoMove +8073a3cc Objects::Poihana::Topple +8073a5d8 Objects::Poihana::OnStartToppleNormal +8073a5f0 Objects::Poihana::OnStartToppleInverted +8073a60c Objects::Poihana::UpdateTopple +8073a854 Objects::Poihana::OnEndTopple +8073a890 Objects::Poihana::OnStartToppleNoBury +8073a9e0 Objects::Poihana::UpdateToppleNoBury +8073ae70 0x8073ae70 +8073ae8c Objects::Poihana::OnEndToppleNoBury +8073ae98 Objects::Poihana::Actions::OnStart +8073aee0 Objects::Poihana::Actions::Update +8073af10 Objects::Poihana::Actions::OnEnd +8073af58 Objects::Poihana::__dt(thunk) +8073af60 AI::Base::__ct +8073b06c AI::Base::UpdateActions +8073b0e8 AI::Base::SetInitialActions +8073b100 AI::Base::HasSameActions +8073b114 AI::Base::SetNextActions +8073b120 AI::Actions::OnActionStart +8073b168 AI::Actions::Update +8073b198 AI::Actions::OnActionEnd +8073b1e0 0x8073b1e0 +8073b22c 0x8073b22c +8073b2d0 0x8073b2d0 +8073b480 0x8073b480 +8073b550 0x8073b550 +8073b79c 0x8073b79c +8073b928 0x8073b928 +8073b960 0x8073b960 +8073b9d8 0x8073b9d8 +8073badc 0x8073badc +8073bc68 0x8073bc68 +8073bd00 0x8073bd00 +8073be04 0x8073be04 +8073be20 0x8073be20 +8073be24 0x8073be24 +8073bf74 0x8073bf74 +8073c05c 0x8073c05c +8073c0d4 0x8073c0d4 +8073c104 0x8073c104 +8073c17c 0x8073c17c +8073c1e8 0x8073c1e8 +8073c314 0x8073c314 +8073c3d8 0x8073c3d8 +8073c3e8 0x8073c3e8 +8073c480 0x8073c480 +8073c524 0x8073c524 +8073c5dc 0x8073c5dc +8073ca80 0x8073ca80 +8073cac0 0x8073cac0 +8073cb00 0x8073cb00 +8073cb40 0x8073cb40 +8073cbfc 0x8073cbfc +8073cc50 0x8073cc50 +8073cc58 0x8073cc58 +8073cd7c 0x8073cd7c +8073cec4 0x8073cec4 +8073cee0 0x8073cee0 +8073d060 0x8073d060 +8073d0ec 0x8073d0ec +8073d104 0x8073d104 +8073d32c 0x8073d32c +8073d3dc 0x8073d3dc +8073d44c 0x8073d44c +8073d458 0x8073d458 +8073d468 0x8073d468 +8073d538 0x8073d538 +8073d544 0x8073d544 +8073d554 0x8073d554 +8073d588 0x8073d588 +8073d61c 0x8073d61c +8073d724 0x8073d724 +8073d730 0x8073d730 +8073d778 0x8073d778 +8073d7a8 0x8073d7a8 +8073d7f0 0x8073d7f0 +8073db54 0x8073db54 +8073db94 0x8073db94 +8073dc40 0x8073dc40 +8073dd0c 0x8073dd0c +8073dd60 0x8073dd60 +8073dda8 0x8073dda8 +8073ddb8 0x8073ddb8 +8073de08 0x8073de08 +8073deec 0x8073deec +8073df5c 0x8073df5c +8073dfc8 0x8073dfc8 +8073e0f0 0x8073e0f0 +8073e274 0x8073e274 +8073e278 0x8073e278 +8073e2ec 0x8073e2ec +8073e2f0 0x8073e2f0 +8073e2f4 0x8073e2f4 +8073e3b4 0x8073e3b4 +8073e528 0x8073e528 +8073e620 0x8073e620 +8073e668 0x8073e668 +8073e698 0x8073e698 +8073e6e0 0x8073e6e0 +8073e80c 0x8073e80c +8073e8c4 0x8073e8c4 +8073e9f8 0x8073e9f8 +8073ea6c 0x8073ea6c +8073eaac 0x8073eaac +8073eaec 0x8073eaec +8073ebd0 0x8073ebd0 +8073eca8 0x8073eca8 +8073ed1c 0x8073ed1c +8073ede8 0x8073ede8 +8073ee80 0x8073ee80 +8073eec4 0x8073eec4 +8073efb4 0x8073efb4 +8073f160 0x8073f160 +8073f1dc 0x8073f1dc +8073f26c 0x8073f26c +8073f38c 0x8073f38c +8073f394 0x8073f394 +8073f674 0x8073f674 +8073f6b4 0x8073f6b4 +8073f70c 0x8073f70c +8073f7ac 0x8073f7ac +8073f824 0x8073f824 +8073f834 0x8073f834 +8073f858 0x8073f858 +8073f874 0x8073f874 +8073f89c 0x8073f89c +8073fa3c 0x8073fa3c +8073fa44 0x8073fa44 +8073fa4c 0x8073fa4c +8073fa54 0x8073fa54 +8073fa64 0x8073fa64 +8073fa68 0x8073fa68 +8073fa70 0x8073fa70 +8073fa78 0x8073fa78 +8073fa80 0x8073fa80 +8073fa88 0x8073fa88 +8073fa90 0x8073fa90 +8073fa98 0x8073fa98 +8073faa0 0x8073faa0 +8073faa4 0x8073faa4 +8073fae4 0x8073fae4 +8073fb2c 0x8073fb2c +8073fb5c 0x8073fb5c +8073fba4 0x8073fba4 +8073fda0 0x8073fda0 +8073fde0 0x8073fde0 +8073fe38 0x8073fe38 +8073ff48 0x8073ff48 +8073ffc4 0x8073ffc4 +8073ffec 0x8073ffec +80740088 0x80740088 +80740190 0x80740190 +80740260 0x80740260 +807403d0 0x807403d0 +807406dc 0x807406dc +807406ec 0x807406ec +807408ec 0x807408ec +80740918 0x80740918 +80740a18 0x80740a18 +80740af8 0x80740af8 +80740bc4 0x80740bc4 +80740ce4 0x80740ce4 +80740d24 0x80740d24 +80740d7c 0x80740d7c +80740dbc 0x80740dbc +80740e38 0x80740e38 +80740f40 0x80740f40 +8074105c 0x8074105c +8074106c 0x8074106c +807410e0 0x807410e0 +807410fc 0x807410fc +80741324 0x80741324 +8074132c 0x8074132c +80741334 0x80741334 +8074137c 0x8074137c +807413ac 0x807413ac +807413f4 0x807413f4 +8074143c 0x8074143c +8074146c 0x8074146c +807414b4 0x807414b4 +80741544 0x80741544 +80741564 0x80741564 +807415a4 0x807415a4 +807415dc 0x807415dc +807417a4 0x807417a4 +807417b8 0x807417b8 +807418a0 0x807418a0 +80741a08 0x80741a08 +80741a3c 0x80741a3c +80741a48 0x80741a48 +80741b4c 0x80741b4c +80741c08 0x80741c08 +80741cd4 0x80741cd4 +80741ea4 0x80741ea4 +8074213c 0x8074213c +80742180 0x80742180 +807421ac 0x807421ac +807421ec 0x807421ec +80742364 AI::Character::__ct +80742c34 AI::CharacterActions::__dt +80742c74 AI::Character::__dt +80742cf8 AI::Character::Init +80742ddc AI::Character::Update +80742e1c AI::Character::vf_0x20 +80742e9c AI::Character::StartDriving +80742ef4 0x80742ef4 +80742fa4 0x80742fa4 +80742fe0 0x80742fe0 +80742fe4 0x80742fe4 +80742fec 0x80742fec +80742ff0 0x80742ff0 +80742ff8 0x80742ff8 +80743000 0x80743000 +80743004 0x80743004 +80743010 0x80743010 +8074306c 0x8074306c +807430a8 0x807430a8 +80743100 0x80743100 +80743180 AI::Character::ArePlayersClose +80743268 0x80743268 +807433d8 AI::Character::vf_0x8c +80743500 0x80743500 +807435e8 0x807435e8 +807436bc AI::Character::vf_0x94 +80743740 AI::Character::OnStartAction0 +8074374c AI::Character::UpdateAction0 +807437a8 AI::Character::OnStartAction1 +807437ac AI::Character::UpdateAction1 +807438e0 AI::Character::OnStartAction2 +807438e4 AI::Character::UpdateAction2 +80743a28 AI::Character::OnEndAction2 +80743a64 AI::Character::OnStartAction3 +80743a70 AI::Character::UpdateAction3 +80743bc4 AI::Character::OnStartAction4 +80743d00 AI::Character::UpdateAction4 +80743dc4 AI::Character::OnEndAction4 +80743e00 AI::Character::OnStartAction5 +80743e14 AI::Character::UpdateAction5 +8074401c AI::Character::OnEndAction5 +80744058 AI::Character::OnStartAction6 +807441b4 AI::Character::UpdateAction6 +807442a4 AI::Character::OnEndAction6 +807442e0 AI::Character::OnStartAction7 +807442f0 AI::Character::UpdateAction7 +80744350 AI::Character::OnEndAction7 +8074438c AI::Character::OnStartLookAhead +807443c8 AI::Character::UpdateLookAhead +807443cc AI::Character::OnStartLookAtCamera +807443d8 AI::Character::UpdateLookAtCamera +8074464c 0x8074464c +8074466c 0x8074466c +807446ac 0x807446ac +807446b8 0x807446b8 +807448e8 0x807448e8 +80744bc0 0x80744bc0 +80744f74 AI::CharacterBattle::__ct +80744fb0 AI::CharacterBattle::__dt +80745008 AI::CharacterBattle::Init +80745040 AI::CharacterBattle::OnStartAction1 +80745044 AI::CharacterBattle::UpdateAction1 +80745080 AI::CharacterAwards::__ct +807450bc AI::CharacterAwards::__dt +80745114 AI::CharacterAwards::Init +8074514c AI::CharacterAwards::OnStartAction1 +80745150 AI::CharacterAwards::UpdateAction1 +8074518c 0x8074518c +807451c8 0x807451c8 +80745220 0x80745220 +80745264 0x80745264 +8074537c 0x8074537c +80745464 0x80745464 +80745468 0x80745468 +807454e0 0x807454e0 +807455c0 0x807455c0 +807456d0 0x807456d0 +8074570c AI::CharacterAwards::vf_0x94 +80745714 AI::CharacterActions::OnStart +8074575c AI::CharacterActions::Update +8074578c AI::CharacterActions::OnEnd +807457d4 AI::ENPTController::__ct +80745840 AI::ENPTController::__dt +80745880 AI::ENPTController::SetStartingENPT +807458cc AI::ENPTController::Init +80745c40 AI::ENPTController::Update +80745c44 AI::ENPTController::GetPrevPrevPrevENPTPosition +80745c98 AI::ENPTController::GetPrevPrevENPTPosition +80745cec AI::ENPTController::GetPrevENPTPosition +80745d40 AI::ENPTController::GetCurENPTPosition +80745d94 AI::ENPTController::GetNextENPTPosition +80745de8 AI::ENPTController::GetCurPosition +80745e04 0x80745e04 +80745f30 0x80745f30 +80745f74 0x80745f74 +80745fc4 AI::ENPTController::CalcNext +807462e8 0x807462e8 +80746478 0x80746478 +807464b0 0x807464b0 +807464d0 0x807464d0 +8074650c 0x8074650c +8074652c 0x8074652c +8074654c 0x8074654c +80746558 0x80746558 +80746604 0x80746604 +8074663c 0x8074663c +80746824 0x80746824 +80746974 0x80746974 +80746bbc 0x80746bbc +80746c14 AI::ENPTController::CalcNextPosition +80746d40 0x80746d40 +80746d4c 0x80746d4c +80746e54 0x80746e54 +80746e7c 0x80746e7c +80746ec0 0x80746ec0 +80746f00 0x80746f00 +807472a4 0x807472a4 +807472e4 0x807472e4 +807472e8 0x807472e8 +807472f4 0x807472f4 +8074732c 0x8074732c +80747364 0x80747364 +807473a4 0x807473a4 +807473e4 0x807473e4 +80747424 0x80747424 +80747430 0x80747430 +80747454 0x80747454 +80747584 0x80747584 +807475f4 0x807475f4 +80747664 0x80747664 +807476d4 0x807476d4 +8074773c 0x8074773c +807477a4 0x807477a4 +80747858 0x80747858 +80747910 0x80747910 +80747a20 0x80747a20 +80747b30 0x80747b30 +80747b74 0x80747b74 +80747bb4 0x80747bb4 +80747bf4 0x80747bf4 +80747bf8 0x80747bf8 +80747c04 0x80747c04 +80747c3c 0x80747c3c +80747c74 0x80747c74 +80747cb4 0x80747cb4 +80747cf4 0x80747cf4 +80747d34 0x80747d34 +80747d6c 0x80747d6c +80747d78 0x80747d78 +80747d9c 0x80747d9c +80747e04 0x80747e04 +80747e14 0x80747e14 +80747e6c AI::ENPTSettingsHolder::IsCutPoint +80747e80 AI::ENPTSettingsHolder::IsUseOffroadCutItem +80747e94 AI::ENPTSettingsHolder::MustWheelie +80747ea8 AI::ENPTSettingsHolder::MustEndWheelie +80747ebc AI::ENPTSettingsHolder::IsSetting1Equal5 +80747ed0 AI::ENPTSettingsHolder::MustEndDrift +80747ee4 AI::ENPTSettingsHolder::IsDriftForbidden +80747ef8 AI::ENPTSettingsHolder::MustDrift +80747f0c AI::ENPTSettingsHolder::IsSetting3HighestBitSet +80747f18 0x80747f18 +80747f34 AI::ENPTSettingsHolder::IsDriftAllowed +80747f68 0x80747f68 +80747f7c 0x80747f7c +80747f90 0x80747f90 +80747fa4 0x80747fa4 +80747fb8 0x80747fb8 +80747fc4 0x80747fc4 +80747fd0 0x80747fd0 +80747fdc 0x80747fdc +8074801c 0x8074801c +8074805c 0x8074805c +80748078 GlobeMgr::Disposer__dt +80748110 GlobeMgr::CreateInstance +8074818c GlobeMgr::DestroyInstance +807481c0 EarthModel::__ct +80748724 0x80748724 +80748788 EarthModel::__dt +80748808 0x80748808 +80748a38 0x80748a38 +80748a3c 0x80748a3c +80748a40 0x80748a40 +80748a44 0x80748a44 +80748af0 0x80748af0 +80748cb0 0x80748cb0 +80748cd4 0x80748cd4 +80748dec 0x80748dec +80748e6c 0x80748e6c +80748f94 0x80748f94 +807490c0 0x807490c0 +807491ec 0x807491ec +80749318 0x80749318 +80749444 0x80749444 +80749570 0x80749570 +8074969c 0x8074969c +8074994c 0x8074994c +80749cc8 GlobeMii::GetTranslation +80749cd0 0x80749cd0 +80749d20 0x80749d20 +80749d40 0x80749d40 +80749d60 0x80749d60 +80749d80 0x80749d80 +80749da4 0x80749da4 +80749dc4 0x80749dc4 +8074a018 0x8074a018 +8074a234 0x8074a234 +8074a490 0x8074a490 +8074a500 0x8074a500 +8074a540 0x8074a540 +8074a580 0x8074a580 +8074a5c0 0x8074a5c0 +8074a604 0x8074a604 +8074a644 0x8074a644 +8074a8f8 0x8074a8f8 +8074a8fc GlobeMgr::__ct +8074a94c GlobeMgr::__dt +8074aa14 GlobeMgr::Init +8074aad8 0x8074aad8 +8074acf8 0x8074acf8 +8074adb4 0x8074adb4 +8074ae04 GlobeMgr::Update +8074b188 0x8074b188 +8074b1c8 0x8074b1c8 +8074b2ac 0x8074b2ac +8074b2bc GlobeMgr::IsMiiEnabled +8074b2c8 GlobeMgr::SetPosition +8074b458 0x8074b458 +8074b45c 0x8074b45c +8074b460 GlobeMgr::SetMii +8074b474 GlobeMgr::DisplayMii +8074b490 GlobeMgr::ResetGlobeMii +8074b4a4 0x8074b4a4 +8074b56c GlobeMii::__ct +8074baec GlobeMii::Init +8074bc04 GlobeMii::Update +8074bcc8 GlobeMii::SetMii +8074bfe8 GlobeMii::IsFemaleMii +8074c000 GlobeMii::DisplayMii +8074c37c GlobeMii::Reset +8074c3fc 0x8074c3fc +8074c488 0x8074c488 +8074c5e8 0x8074c5e8 +8074cce4 0x8074cce4 +8074cd74 0x8074cd74 +8074cd80 0x8074cd80 +8074cd8c 0x8074cd8c +8074ce58 0x8074ce58 +8074cf98 0x8074cf98 +8074cfa4 0x8074cfa4 +8074cfb0 0x8074cfb0 +8074cfbc 0x8074cfbc +8074cfc8 0x8074cfc8 +8074cfd4 0x8074cfd4 +8074d358 0x8074d358 +8074d494 0x8074d494 +8074d548 0x8074d548 +8074d5f8 0x8074d5f8 +8074d6b4 0x8074d6b4 +8074d758 0x8074d758 +8074d800 0x8074d800 +8074dc48 0x8074dc48 +8074de5c 0x8074de5c +8074dfdc 0x8074dfdc +8074e010 0x8074e010 +8074e324 0x8074e324 +8074e44c 0x8074e44c +8074e55c 0x8074e55c +8074e6e4 0x8074e6e4 +8074e8fc 0x8074e8fc +8074ebbc 0x8074ebbc +8074ed90 0x8074ed90 +8074ef94 0x8074ef94 +8074f0a0 0x8074f0a0 +8074f150 0x8074f150 +8074f174 0x8074f174 +8074f490 0x8074f490 +8074f544 0x8074f544 +8074f898 0x8074f898 +8074f910 0x8074f910 +8074f980 0x8074f980 +8074f9bc 0x8074f9bc +8074f9f4 0x8074f9f4 +8074fae8 0x8074fae8 +8074fc5c BegomanManager::__ct +8074fcd0 0x8074fcd0 +8074fcd4 0x8074fcd4 +8075013c 0x8075013c +80750158 0x80750158 +8075018c 0x8075018c +80750214 0x80750214 +80750264 0x80750264 +8075050c 0x8075050c +80750524 0x80750524 +807505f0 0x807505f0 +807506ec 0x807506ec +807507c8 0x807507c8 +80750954 0x80750954 +807509f8 0x807509f8 +80750d08 0x80750d08 +80750dec 0x80750dec +80750df4 0x80750df4 +80750e00 0x80750e00 +80750e08 0x80750e08 +80750e0c 0x80750e0c +80750e10 0x80750e10 +80750e14 0x80750e14 +80750e18 0x80750e18 +80750e1c 0x80750e1c +80750e20 0x80750e20 +80750e28 0x80750e28 +80750e2c 0x80750e2c +80750e30 0x80750e30 +80750e34 0x80750e34 +80750e38 0x80750e38 +80750e3c 0x80750e3c +80750e40 0x80750e40 +80750e48 0x80750e48 +80750e88 0x80750e88 +80750ec8 0x80750ec8 +80750f08 0x80750f08 +80750f48 0x80750f48 +80750f50 0x80750f50 +80750f58 0x80750f58 +80750f60 0x80750f60 +80750fc4 0x80750fc4 +807510c0 0x807510c0 +807510c4 0x807510c4 +80751264 0x80751264 +807512d0 0x807512d0 +80751494 0x80751494 +80751590 0x80751590 +80751618 0x80751618 +807516b0 0x807516b0 +80751704 0x80751704 +80751b0c 0x80751b0c +80751b60 0x80751b60 +80751b68 0x80751b68 +80751b70 0x80751b70 +80751bb0 obj_dossunc::__ct +80751e80 0x80751e80 +80751f1c 0x80751f1c +80751f5c 0x80751f5c +807522d0 0x807522d0 +80752308 obj_dossun_active_update +807524a8 0x807524a8 +807524e4 0x807524e4 +80752514 0x80752514 +8075258c 0x8075258c +807525d4 0x807525d4 +80752638 0x80752638 +80752820 0x80752820 +80752abc 0x80752abc +80752c04 0x80752c04 +80752d30 0x80752d30 +80752e80 0x80752e80 +80752f34 0x80752f34 +80752f40 obj_dossun_endFall +80752f54 0x80752f54 +80752fbc 0x80752fbc +8075304c 0x8075304c +807531cc 0x807531cc +8075323c 0x8075323c +807532f0 0x807532f0 +80753394 obj_dossun_update +80753544 0x80753544 +807536a0 0x807536a0 +807536e8 0x807536e8 +807538d4 0x807538d4 +80753a18 obj_dossun_make_active +80753af8 0x80753af8 +80753b88 0x80753b88 +80753bd4 0x80753bd4 +80753c88 0x80753c88 +80753d10 0x80753d10 +80753dcc 0x80753dcc +80753e40 0x80753e40 +80754450 0x80754450 +80754584 0x80754584 +8075477c 0x8075477c +807547f4 0x807547f4 +807547f8 0x807547f8 +80754a40 0x80754a40 +80755108 0x80755108 +80755244 0x80755244 +80755460 0x80755460 +807555a4 0x807555a4 +807556a4 0x807556a4 +80755fa0 0x80755fa0 +80756184 0x80756184 +807562d0 0x807562d0 +80756574 0x80756574 +807569ac 0x807569ac +807569cc 0x807569cc +807569f0 0x807569f0 +80756ab4 0x80756ab4 +80756ab8 0x80756ab8 +80756ac4 0x80756ac4 +80756c14 0x80756c14 +80756cc8 0x80756cc8 +80756ec0 0x80756ec0 +80756f60 0x80756f60 +80757020 0x80757020 +80757108 0x80757108 +807571a4 0x807571a4 +80757398 0x80757398 +807573ac 0x807573ac +80757454 0x80757454 +8075754c 0x8075754c +807575c4 0x807575c4 +80757678 0x80757678 +807576b8 0x807576b8 +807576bc 0x807576bc +807576f8 0x807576f8 +80757758 0x80757758 +80757850 0x80757850 +80757958 0x80757958 +80757a58 0x80757a58 +80757ab8 0x80757ab8 +80757ac0 0x80757ac0 +80757ac8 0x80757ac8 +80757ad0 0x80757ad0 +80757ad4 0x80757ad4 +80757ad8 0x80757ad8 +80757adc 0x80757adc +80757ae0 0x80757ae0 +80757ae4 0x80757ae4 +80757aec 0x80757aec +80757af0 0x80757af0 +80757b40 0x80757b40 +80757bb8 0x80757bb8 +80757bbc 0x80757bbc +80757bfc 0x80757bfc +80757c3c 0x80757c3c +80757c7c 0x80757c7c +80757cfc 0x80757cfc +80757d3c 0x80757d3c +80757d7c obj_Epropeller::__ct +80757e70 0x80757e70 +80757ee8 obj_Epropeller::__dt +80757f68 obj_Epropeller_0x0c +80758118 0x80758118 +8075811c obj_Epropeller_update +80758244 0x80758244 +80758360 0x80758360 +8075845c obj_Epropeller_updateEffect +8075860c 0x8075860c +80758668 0x80758668 +807587e8 0x807587e8 +807587ec 0x807587ec +80758994 0x80758994 +807589e4 0x807589e4 +80758b08 0x80758b08 +80758c74 0x80758c74 +80758c7c 0x80758c7c +80758ccc 0x80758ccc +80758d44 0x80758d44 +80758d48 0x80758d48 +807591c4 0x807591c4 +8075923c 0x8075923c +80759240 0x80759240 +80759258 0x80759258 +80759448 0x80759448 +80759844 0x80759844 +8075985c 0x8075985c +80759aa4 0x80759aa4 +80759aec 0x80759aec +80759b0c 0x80759b0c +80759b10 0x80759b10 +80759b64 0x80759b64 +80759b70 0x80759b70 +80759b7c 0x80759b7c +80759b84 0x80759b84 +80759b88 0x80759b88 +80759b8c 0x80759b8c +80759b90 0x80759b90 +80759b94 0x80759b94 +80759b9c 0x80759b9c +80759be4 0x80759be4 +80759c2c 0x80759c2c +80759c34 0x80759c34 +80759c84 0x80759c84 +80759cfc 0x80759cfc +80759d00 0x80759d00 +80759d80 0x80759d80 +80759e00 0x80759e00 +80759e40 Objects::Hanabi::__ct +80759ea4 Objects::Hanabi::__dt +80759ee4 Objects::Hanabi::OnStart +80759f38 0x80759f38 +80759f4c Objects::Hanabi::Update +8075a06c 0x8075a06c +8075a15c Objects::Hanabi::LoadClipInfo +8075a160 Objects::Hanabi::LoadCollision +8075a164 Objects::Hanabi::LoadAnimations +8075a168 Objects::Hanabi::LoadModels +8075a16c Objects::Hanabi::GetPropertiesBitfield +8075a174 Objects::W_Itembox::__ct +8075a2e0 Objects::SubObjectArray::__dt +8075a358 Objects::SubObjectArray::vf_0x18 +8075a35c Objects::W_Itembox::__dt +8075a3dc Objects::W_Itembox::OnStart +8075a414 0x8075a414 +8075a420 Objects::W_Itembox::Update +8075a510 0x8075a510 +8075a5e0 Objects::W_Itembox::Box::__ct +8075a61c Objects::W_Itembox::Box::__dt +8075a65c Objects::W_Itembox::Box::OnStart +8075a66c 0x8075a66c +8075a6d0 Objects::W_Itembox::Box::Update +8075a7c8 0x8075a7c8 +8075a814 Objects::W_Itembox::Box::OnCollision +8075a84c Objects::W_Itembox::Box::OnItemCollision +8075a854 Objects::W_Itembox::UpdateModel +8075a858 Objects::W_Itembox::LoadClipInfo +8075a85c Objects::W_Itembox::LoadCollision +8075a860 Objects::W_Itembox::LoadAnimations +8075a864 Objects::W_Itembox::LoadModels +8075a868 Objects::W_Itembox::GetPropertiesBitfield +8075a870 Objects::W_Itembox::Box::GetSubFileName +8075a87c Objects::W_Itembox::Box::GetBRRESName +8075a888 Objects::W_Itembox::Box::GetPropertiesBitfield +8075a890 Objects::SubObjectArray::CreateArray +8075a8e0 Objects::SubObjectArray::CreateArray(heap) +8075a958 Objects::SubObjectArray::vf_0x14 +8075a95c Objects::W_Itemboxline::__ct +8075ad78 Objects::SubObjectArray::__dt +8075adf0 Objects::SubObjectArray::__dt +8075ae68 Objects::SubObjectArray::vf_0x18 +8075ae6c Objects::SubObjectArray::vf_0x18 +8075ae70 Objects::W_Itemboxline::__dt +8075af1c Objects::W_Itemboxline::OnStart +8075af58 0x8075af58 +8075af64 Objects::W_Itemboxline::Update +8075b140 0x8075b140 +8075b2fc Objects::W_Itemboxline::Box::GetID +8075b360 Objects::W_Itemboxline::Box::__dt +8075b3a0 Objects::W_Itemboxline::Box::OnStart +8075b3b0 0x8075b3b0 +8075b40c Objects::W_Itemboxline::Box::Update +8075b85c 0x8075b85c +8075b9d4 Objects::W_Itemboxline::Box::OnCollision +8075ba0c 0x8075ba0c +8075ba7c Objects::W_Itemboxline::Block::__dt +8075babc Objects::W_Itemboxline::Block::OnStart +8075bb28 0x8075bb28 +8075bbd8 Objects::W_Itemboxline::Block::Update +8075bd18 0x8075bd18 +8075be00 Objects::W_Itemboxline::Block::OnCollision +8075bef0 Objects::W_Itemboxline::Block::OnItemCollision +8075bfb4 0x8075bfb4 +8075c0c4 Objects::W_Itemboxline::Press::__ct +8075c130 Objects::W_Itemboxline::Press::__dt +8075c188 Objects::W_Itemboxline::Press::TryFall +8075c1c8 Objects::W_Itemboxline::Press::UpdateEffect +8075c2c0 Objects::W_Itemboxline::UpdateModel +8075c2c4 Objects::W_Itemboxline::LoadClipInfo +8075c2c8 Objects::W_Itemboxline::LoadCollision +8075c2cc Objects::W_Itemboxline::LoadAnimations +8075c2d0 Objects::W_Itemboxline::LoadModels +8075c2d4 Objects::W_Itemboxline::GetPropertiesBitfield +8075c2dc 0x8075c2dc +8075c2e4 0x8075c2e4 +8075c2f0 0x8075c2f0 +8075c2fc Objects::W_Itemboxline::Box::GetPropertiesBitfield +8075c304 Objects::W_Itemboxline::Block::GetPropertiesBitfield +8075c30c Objects::W_Itemboxline::Block::GetBRRESName +8075c318 Objects::W_Itemboxline::Block::GetSubFileName +8075c324 Objects::Press::GetCollisionDiameter +8075c330 Objects::Press::GetShadowListIdx +8075c338 Objects::W_Itemboxline::Press::GetPropertiesBitfield +8075c340 Objects::W_Itemboxline::Press::GetID +8075c348 Objects::W_Itemboxline::Press::GetBRRESName +8075c354 Objects::W_Itemboxline::Press::GetSubFileName +8075c360 Objects::SubObjectArray::CreateArray +8075c3b0 Objects::SubObjectArray::CreateArray(heap) +8075c428 Objects::SubObjectArray::vf_0x14 +8075c42c Objects::SubObjectArray::CreateArray +8075c47c Objects::SubObjectArray::CreateArray(heap) +8075c4f4 Objects::ItemDropper::OnImperviousItemCollision +8075c4f8 Objects::DKRockGC::__ct +8075c55c Objects::DKRockGC::__dt +8075c59c Objects::DKRockGC::OnStart +8075c7a4 0x8075c7a4 +8075c7a8 Objects::DKRockGC::Update +8075c980 0x8075c980 +8075ca80 0x8075ca80 +8075cb34 0x8075cb34 +8075cc78 0x8075cc78 +8075cfa8 0x8075cfa8 +8075d1d8 0x8075d1d8 +8075d280 Objects::DKRockGC::OnCollision +8075d410 Objects::DKRockGC::OnItemCollision +8075d4a4 Objects::DKRockGC::UpdateShadow +8075d584 Objects::DKRockGC::GetCollisionTranslation +8075d58c Objects::DKRockGC::GetShadowListIdx +8075d594 Objects::DKRockGC::GetPropertiesBitfield +8075d59c Objects::KoopaBall::__ct +8075d5e8 Objects::KoopaBall::OnStart +8075d9b4 0x8075d9b4 +8075d9c4 0x8075d9c4 +8075db3c 0x8075db3c +8075dc7c 0x8075dc7c +8075dcf4 Objects::KoopaBall::Update +8075e164 0x8075e164 +8075e460 0x8075e460 +8075e53c 0x8075e53c +8075e734 0x8075e734 +8075e83c 0x8075e83c +8075e98c 0x8075e98c +8075eae8 0x8075eae8 +8075ebb8 0x8075ebb8 +8075ec00 0x8075ec00 +8075ed68 0x8075ed68 +8075ede4 0x8075ede4 +8075ee0c Objects::KoopaBall::OnCollision +8075f03c Objects::KoopaBall::UpdateShadow +8075f178 Objects::KoopaBall::GetCollisionTranslation +8075f180 Objects::KoopaBall::GetPropertiesBitfield +8075f188 Objects::KoopaBall::__dt +8075f1c8 0x8075f1c8 +8075f26c 0x8075f26c +8075f304 0x8075f304 +8075f354 0x8075f354 +8075f534 0x8075f534 +8075f660 0x8075f660 +8075f71c 0x8075f71c +8075f748 0x8075f748 +8075f868 0x8075f868 +8075f8cc 0x8075f8cc +8075f8d4 0x8075f8d4 +8075f8dc Objects::MiiKanban::__dt +8075f91c ObjMonteA_construct +8075f9c0 0x8075f9c0 +8075fa6c 0x8075fa6c +8075fd04 0x8075fd04 +8075fdac 0x8075fdac +8075fec8 0x8075fec8 +8075ffb8 0x8075ffb8 +8076005c 0x8076005c +807600c0 0x807600c0 +807600c8 0x807600c8 +807600d0 0x807600d0 +80760110 0x80760110 +80760150 0x80760150 +807604bc 0x807604bc +807604c0 0x807604c0 +8076076c 0x8076076c +807607f0 0x807607f0 +80760988 0x80760988 +807609ec 0x807609ec +80760a1c 0x80760a1c +80760c24 0x80760c24 +80760c8c 0x80760c8c +80760d98 0x80760d98 +80760e74 0x80760e74 +80761120 0x80761120 +807611c4 0x807611c4 +807611d0 0x807611d0 +80761258 0x80761258 +80761260 0x80761260 +80761268 0x80761268 +807612a8 0x807612a8 +807612e8 0x807612e8 +80761380 0x80761380 +80761388 0x80761388 +80761390 0x80761390 +807613dc Objects::Penguin::__dt +8076141c Objects::Penguin::OnStart +807614c4 0x807614c4 +807614d0 Objects::Penguin::Update +8076150c Objects::Penguin::UpdateWithRot +80761570 Objects::Penguin::UpdateNoRot +807615f8 Objects::Penguin::vf_0x104 +807616bc Objects::Penguin::UpdateMtxNoRot +80761888 Objects::Penguin::UpdateMtxWithRot +80761910 0x80761910 +80761998 Objects::Penguin::UpdatePosition +807619c4 Objects::Penguin::OnCollision +80761a4c Objects::Penguin::OnItemCollision +80761a98 Objects::Penguin::SpinOut +80761bcc Objects::Penguin_s::__ct +80761d30 Objects::PenguinUnkObj::LoadAnimations +80761ddc Objects::Penguin_s::__dt +80761e1c Objects::Penguin_s::OnStart +80761ef4 0x80761ef4 +80761f04 Objects::Penguin_s::Update +807620e8 Objects::Penguin_s::UpdateWithRot +8076213c 0x8076213c +80762204 0x80762204 +807623dc 0x807623dc +80762454 Objects::Penguin_s::UpdateNoRot +8076260c 0x8076260c +8076285c Objects::Penguin_s::vf_0x104 +807628e8 0x807628e8 +80762900 0x80762900 +807629c4 0x807629c4 +80762a48 0x80762a48 +80762afc Objects::Penguin_s::SpinOut +80762c38 Objects::Penguin_s::UpdateModelMatrix +80762db8 0x80762db8 +80762df8 Objects::Penguin_m::__ct +80762e9c Objects::Penguin_l::__ct +80762f48 Objects::Penguin_l::OnStart +80762ff0 Objects::Penguin_l::UpdateModelMatrix +80762ff4 0x80762ff4 +80763034 Objects::Penguin::LoadAnimations +80763088 Objects::Penguin::vf_0xec +80763090 Objects::Penguin::GetPropertiesBitfield +80763098 Objects::Penguin_l::DoCalcShadowMtx +807630a0 0x807630a0 +807630f4 0x807630f4 +807630fc 0x807630fc +80763100 0x80763100 +80763108 Objects::Penguin_s::LoadAnimations +807631b4 Objects::Penguin_s::vf_0xec +807631bc Objects::PenguinUnkObj::vf_0xec +807631c4 Objects::PenguinUnkObj::Update +807631c8 Objects::PenguinUnkObj::GetScnObjDrawOptionsIdx +807631d0 Objects::PenguinUnkObj::__dt +80763210 Objects::Penguin_m::_dt +80763250 0x80763250 +80763290 Objects::Penguin_l::__dt +807632d0 Objects::Press::__ct +80763368 Objects::Press::OnStart +807633a8 0x807633a8 +807635d8 0x807635d8 +807635f8 Objects::Press::Update +807637fc Objects::Press::TryFall +807638c0 0x807638c0 +807638fc 0x807638fc +8076392c 0x8076392c +80763a1c 0x80763a1c +80763a7c Objects::Press::UpdateColliding +80763c64 Objects::Press::UpdateEffect +80763d34 0x80763d34 +80763dec 0x80763dec +80763df8 0x80763df8 +80763eac 0x80763eac +80763eb8 0x80763eb8 +80763ed4 0x80763ed4 +80763f84 0x80763f84 +80764040 Objects::Press::OnCollision +80764178 Objects::Press::LoadCollision +80764450 Objects::Press::LoadAnimations +80764554 Objects::Press::GetPropertiesBitfield +8076455c 0x8076455c +8076459c 0x8076459c +807646a0 0x807646a0 +807646a4 0x807646a4 +8076474c 0x8076474c +807648c0 0x807648c0 +80764930 0x80764930 +80764ad4 0x80764ad4 +80764b5c 0x80764b5c +80764be4 0x80764be4 +80764c4c 0x80764c4c +80764f98 0x80764f98 +8076528c 0x8076528c +80765398 0x80765398 +8076541c 0x8076541c +80765424 0x80765424 +8076542c 0x8076542c +8076546c 0x8076546c +807656d8 0x807656d8 +80765718 0x80765718 +8076588c nlListContainer__ct +8076589c 0x8076589c +80765b28 0x80765b28 +80765c04 0x80765c04 +80765de8 0x80765de8 +80765fa8 0x80765fa8 +807660c8 0x807660c8 +807661ec 0x807661ec +80766210 0x80766210 +80766290 0x80766290 +80766778 0x80766778 +80766888 0x80766888 +807668c4 0x807668c4 +80766904 0x80766904 +80766980 0x80766980 +80766aec 0x80766aec +80766f48 0x80766f48 +80766fb0 0x80766fb0 +807670c8 0x807670c8 +80767110 0x80767110 +80767150 0x80767150 +80767198 0x80767198 +807671d8 0x807671d8 +80767260 0x80767260 +80767268 0x80767268 +80767270 0x80767270 +80767274 0x80767274 +80767280 0x80767280 +8076728c 0x8076728c +80767298 0x80767298 +807672a4 0x807672a4 +807672b0 0x807672b0 +80767474 0x80767474 +807674ec 0x807674ec +807674f0 0x807674f0 +807674f4 0x807674f4 +807674f8 0x807674f8 +80767700 0x80767700 +80767750 0x80767750 +8076781c 0x8076781c +80767820 0x80767820 +80767824 0x80767824 +80767874 0x80767874 +807678b4 0x807678b4 +80767a30 0x80767a30 +80767a34 0x80767a34 +80767aac 0x80767aac +80767ab0 0x80767ab0 +80767b10 0x80767b10 +80767d1c 0x80767d1c +80767d20 0x80767d20 +80767e24 0x80767e24 +80768084 0x80768084 +807680e4 0x807680e4 +807681a8 0x807681a8 +807681fc 0x807681fc +80768204 0x80768204 +8076820c 0x8076820c +80768210 0x80768210 +80768214 0x80768214 +80768218 0x80768218 +8076821c 0x8076821c +80768220 0x80768220 +80768224 0x80768224 +8076822c 0x8076822c +8076827c 0x8076827c +807682f4 0x807682f4 +807682f8 0x807682f8 +80768378 0x80768378 +807683b8 0x807683b8 +807683f8 Objects::W_Woodbox::__ct +80768578 Objects::SubObjectArray::__dt +807685f0 Objects::SubObjectArray::vf_0x18 +807685f4 Objects::W_Woodbox::__dt +80768674 Objects::W_Woodbox::OnStart +807686ac 0x807686ac +807686b8 Objects::W_Woodbox::Update +8076877c 0x8076877c +80768820 Objects::W_Woodbox::Box::__ct +8076885c Objects::W_Woodbox::Box::__dt +807688b8 Objects::W_Woodbox::Box::OnStart +80768918 Objects::W_Woodbox::Box::RespawnImpl +80768970 Objects::W_Woodbox::Box::Update +80768a40 0x80768a40 +80768ab8 Objects::Woodbox::__ct +80768af4 Objects::Woodbox::__dt +80768b4c Objects::Woodbox::OnStart +80768b8c Objects::Woodbox::LoadEffects +80768bd8 Objects::Woodbox::DropItem +80768c24 Objects::Woodbox::Respawn +80768c84 Objects::Woodbox::UpdateRespawn +80768cb4 Objects::Woodbox::UpdateRespawnImpl +80768dfc Objects::Woodbox::OnNormalCollision +80768e94 Objects::Woodbox::OnImperviousCollision +80768f40 Objects::Woodbox::OnNormalItemCollision +80768fdc Objects::Woodbox::OnImperviousItemCollision +8076908c Objects::Woodbox::UpdateCollision +8076919c Objects::W_Woodbox::UpdateModel +807691a0 Objects::W_Woodbox::LoadClipInfo +807691a4 Objects::W_Woodbox::LoadCollision +807691a8 Objects::W_Woodbox::LoadAnimations +807691ac Objects::W_Woodbox::LoadModels +807691b0 Objects::W_Woodbox::GetPropertiesBitfield +807691b8 Objects::Woodbox::InitEntity +80769244 Objects::Woodbox::GetBRRESName +80769250 Objects::Woodbox::GetSubFileName +80769278 Objects::W_Woodbox::Box::GetPropertiesBitfield +80769280 Objects::Woodbox::GetPropertiesBitfield +80769288 Objects::SubObjectArray::CreateArray +807692d8 Objects::SubObjectArray::CreateArray(Heap) +80769350 Objects::SubObjectArray::vf_0x14 +80769354 MiiRenderMgr::Disposer__dt +80769458 MiiRenderMgr::CreateInstance +807694e4 MiiRenderMgr::DestroyInstance +8076959c MiiRenderMgr::__ct +807695fc 0x807695fc +8076963c MiiRenderMgr::__dt +80769700 MiiRenderMgr::Init2 +80769a44 MiiRenderMgr::Init +80769bb8 MiiRenderMgr::CreateTextures +80769d00 0x80769d00 +80769d9c MiiRenderMgr::SetPercentages +80769da8 MiiRenderMgr::InitMenuModels +8076a110 0x8076a110 +8076a5d4 MiiRenderMgr::InitRaceModels +8076a890 0x8076a890 +8076a8f0 0x8076a8f0 +8076aaa4 0x8076aaa4 +8076abe8 0x8076abe8 +8076af74 0x8076af74 +8076af8c 0x8076af8c +8076b0b4 0x8076b0b4 +8076b184 0x8076b184 +8076b25c 0x8076b25c +8076b3a4 0x8076b3a4 +8076b3e0 MiiRenderMgr::InitLights +8076b5fc 0x8076b5fc +8076b764 MiiRenderMgr::AddMii +8076b948 MiiRenderMgr::CreateMiisAndRender +8076ba58 MiiRenderMgr::CreateAndRenderFromMiis +8076bb68 MiiRenderMgr::CreateAndDraw +8076c09c 0x8076c09c +8076c440 0x8076c440 +8076c4e8 MiiRenderMgr::SetMiiForModel +8076c5d4 MiiRenderMgr::UpdateScreenFromTexture +8076c78c 0x8076c78c +8076c830 MiiRenderMgr::RequestAddMii +8076c8b8 MiiRenderMgr::ProcessTopAddRequest +8076c96c MiiRenderMgr::DeleteMii +8076c9fc MiiRenderMgr::ProcessAllAddRequests +8076cab0 0x8076cab0 +8076cb3c 0x8076cb3c +8076ccd8 MiiRenderMgr::CalcWorldCB::ExecCallbackB +8076cd84 MiiRenderMgr::CalcWorldCB::__dt +8076cdc4 0x8076cdc4 +8076ce9c MiiRenderMgr::CalcWorldCB::ExecCallbackB(thunk) +8076cea4 MiiRenderMgr::CalcWorldCB::__dt +8076ceac AwardCupModel::Disposer__dt +8076cfb4 AwardCupModel::CreateInstance +8076d084 AwardCupModel::DestroyInstance +8076d140 AwardCupModel::__ct +8076d1e4 AwardCupModel::__dt +8076d2ac AwardCupModel::Load +8076d318 AwardCupModel::Load_switch +8076d31c AwardCupModel::Load_caseD_0 +8076d350 AwardCupModel::Load_caseD_1 +8076d384 AwardCupModel::Load_caseD_2 +8076d3b8 AwardCupModel::Load_caseD_3 +8076d3ec AwardCupModel::Load_caseD_4 +8076d420 AwardCupModel::Load_caseD_5 +8076d454 AwardCupModel::Load_caseD_6 +8076d488 AwardCupModel::Load_caseD_7 +8076d4bc AwardCupModel::Load_caseD_8 +8076d724 AwardCupModel::Prepare +8076d854 AwardCupModel::Activate +8076d904 AwardCupModel::Update +8076db88 0x8076db88 +8076dcf0 0x8076dcf0 +8076dd94 0x8076dd94 +8076de40 0x8076de40 +8076df84 0x8076df84 +8076dfbc 0x8076dfbc +8076e020 0x8076e020 +8076e060 0x8076e060 +8076e064 0x8076e064 +8076e068 0x8076e068 +8076e140 0x8076e140 +8076e218 0x8076e218 +8076e220 0x8076e220 +8076e260 0x8076e260 +8076e2a0 0x8076e2a0 +8076e354 0x8076e354 +8076e4d8 0x8076e4d8 +8076e8ac 0x8076e8ac +8076e8f8 0x8076e8f8 +8076ea60 0x8076ea60 +8076ebb4 0x8076ebb4 +8076ecf8 0x8076ecf8 +8076ede0 0x8076ede0 +8076efac 0x8076efac +8076f018 0x8076f018 +8076f024 0x8076f024 +8076f038 0x8076f038 +8076f098 0x8076f098 +8076f0a0 0x8076f0a0 +8076f0a8 0x8076f0a8 +8076f128 0x8076f128 +8076f168 0x8076f168 +8076f214 0x8076f214 +8076f2ac 0x8076f2ac +8076f320 0x8076f320 +8076f324 0x8076f324 +8076f4e0 0x8076f4e0 +8076f598 0x8076f598 +8076f63c 0x8076f63c +8076f6b4 0x8076f6b4 +8076f85c 0x8076f85c +8076fc94 0x8076fc94 +8076fd08 0x8076fd08 +8076fd14 0x8076fd14 +8076fd20 0x8076fd20 +8076fedc 0x8076fedc +8076ff54 0x8076ff54 +8076ff58 0x8076ff58 +8076ffd8 0x8076ffd8 +8076fff0 0x8076fff0 +80770000 0x80770000 +80770128 0x80770128 +80770424 0x80770424 +8077049c 0x8077049c +807704a0 0x807704a0 +80770520 0x80770520 +80770524 0x80770524 +80770528 0x80770528 +8077052c 0x8077052c +80770530 0x80770530 +80770534 0x80770534 +80770538 0x80770538 +80770540 0x80770540 +80770544 0x80770544 +80770548 0x80770548 +8077054c 0x8077054c +80770550 0x80770550 +80770558 0x80770558 +80770560 0x80770560 +807705b0 0x807705b0 +80770628 0x80770628 +8077062c 0x8077062c +8077067c 0x8077067c +807706f4 0x807706f4 +807706f8 0x807706f8 +80770a0c 0x80770a0c +80770a4c 0x80770a4c +80770a84 0x80770a84 +80770e80 0x80770e80 +80770ea4 0x80770ea4 +8077120c 0x8077120c +807714ec 0x807714ec +807714f4 0x807714f4 +807714fc 0x807714fc +80771518 0x80771518 +807718d4 0x807718d4 +807718fc 0x807718fc +80771a04 0x80771a04 +80771eb4 0x80771eb4 +80771ee8 0x80771ee8 +80771fd4 0x80771fd4 +80772088 0x80772088 +807720b8 0x807720b8 +80772340 0x80772340 +80772380 0x80772380 +80772420 0x80772420 +807724c0 0x807724c0 +807725e4 0x807725e4 +8077299c cFielder_IsStriker +807729ac 0x807729ac +80772ad8 0x80772ad8 +80772ba8 0x80772ba8 +80772c94 0x80772c94 +80772d10 0x80772d10 +80772d7c 0x80772d7c +80772e00 0x80772e00 +80772eec 0x80772eec +80773040 0x80773040 +80773138 0x80773138 +80773178 0x80773178 +807731b0 0x807731b0 +80773270 0x80773270 +80773788 0x80773788 +807738d0 0x807738d0 +80773ab4 0x80773ab4 +80773bcc 0x80773bcc +80773dbc 0x80773dbc +80773dd8 0x80773dd8 +80773f70 0x80773f70 +80774038 0x80774038 +80774174 0x80774174 +807743a4 0x807743a4 +8077442c 0x8077442c +80774474 0x80774474 +807744bc 0x807744bc +80774700 0x80774700 +80774750 0x80774750 +80774774 0x80774774 +80774898 0x80774898 +8077493c 0x8077493c +80774a48 0x80774a48 +80774b1c 0x80774b1c +80774b2c 0x80774b2c +80774b50 0x80774b50 +80774c58 0x80774c58 +80774c60 0x80774c60 +80774d88 0x80774d88 +80774e94 0x80774e94 +807750a8 0x807750a8 +807753a8 0x807753a8 +80775440 0x80775440 +807754ec 0x807754ec +807754f4 0x807754f4 +807754fc 0x807754fc +80775508 0x80775508 +80775510 0x80775510 +80775518 0x80775518 +80775524 0x80775524 +80775530 0x80775530 +8077553c 0x8077553c +80775548 0x80775548 +80775588 0x80775588 +807755c8 0x807755c8 +80775608 0x80775608 +80775640 0x80775640 +80775648 0x80775648 +80775650 0x80775650 +80775658 0x80775658 +807756d0 0x807756d0 +80775710 0x80775710 +80775854 0x80775854 +80775858 0x80775858 +80775960 0x80775960 +807759c0 0x807759c0 +807759c8 0x807759c8 +80775a6c 0x80775a6c +80775ae4 0x80775ae4 +80775b64 0x80775b64 +80775e70 0x80775e70 +80775e74 0x80775e74 +80775e78 0x80775e78 +8077602c 0x8077602c +80776488 0x80776488 +80776510 0x80776510 +80776598 0x80776598 +80776608 0x80776608 +807766fc 0x807766fc +8077673c 0x8077673c +80776788 0x80776788 +8077678c 0x8077678c +807767cc 0x807767cc +8077680c 0x8077680c +8077684c 0x8077684c +8077688c 0x8077688c +807768e0 0x807768e0 +807768e8 0x807768e8 +807768f4 0x807768f4 +80776900 0x80776900 +807769d8 0x807769d8 +807769e0 0x807769e0 +807769e4 0x807769e4 +807769ec 0x807769ec +807769f8 0x807769f8 +80776a04 0x80776a04 +80776a10 0x80776a10 +80776a1c 0x80776a1c +80776a28 0x80776a28 +80776a34 0x80776a34 +80776a84 0x80776a84 +80776afc 0x80776afc +80776b00 0x80776b00 +80776b40 0x80776b40 +80776b80 0x80776b80 +80776bc0 0x80776bc0 +80776c80 Objects::Karehayama::__ct +80776cbc Objects::Karehayama::__dt +80776d14 Objects::Karehayama::OnStart +80776d6c Objects::Karehayama::LoadEffects +80776e48 Objects::Karehayama::CreateCollisionEffectSoft +80776f10 Objects::Karehayama::CreateCollisionEffect +80776f80 Objects::Karehayama::CreateExplosionEffect +80776f84 Objects::Karehayama::Respawn +80776fd8 Objects::Karehayama::DropItem +80777080 Objects::Karehayama::OnNormalCollision +8077717c Objects::Karehayama::OnImperviousCollision +807772b0 Objects::Karehayama::OnNormalItemCollision +8077737c Objects::Karehayama::OnImperviousItemCollision +80777438 Objects::Karehayama::LoadShadow +80777514 Object::ItemDropper::UpdateRespawn +80777518 Object::ItemDropper::GetPropertiesBitfield +80777520 Objects::Karehayama::LoadAnimations +80777574 Objects::Karehayama::vf_0x114 +8077757c Objects::Karehayama::OnWallCollision +80777580 Objects::Karehayama::GetBRRESName +807775d4 Objects::Karehayama::GetSubFileName +80777628 ObjVeniceGondola_construct +8077768c ObjVeniceGondola_destruct +807776cc 0x807776cc +80777814 0x80777814 +80777818 0x80777818 +80777b00 0x80777b00 +80777b88 0x80777b88 +80777c10 0x80777c10 +80777c78 0x80777c78 +80777cb4 0x80777cb4 +80777cf4 0x80777cf4 +80777db0 0x80777db0 +80777e4c 0x80777e4c +80777e58 0x80777e58 +80777e64 0x80777e64 +80777e6c 0x80777e6c +80777e78 0x80777e78 +80777e84 0x80777e84 +80777e8c 0x80777e8c +80777e90 0x80777e90 +80777f28 0x80777f28 +80777ff0 0x80777ff0 +80778030 0x80778030 +80778098 0x80778098 +8077809c 0x8077809c +807781dc 0x807781dc +807781f4 0x807781f4 +8077838c 0x8077838c +807783ec 0x807783ec +807787e0 0x807787e0 +80778880 0x80778880 +807789a4 0x807789a4 +80778a58 0x80778a58 +80778b14 0x80778b14 +80778b94 0x80778b94 +80778c0c 0x80778c0c +80778d64 0x80778d64 +80778dbc 0x80778dbc +80778dc8 0x80778dc8 +80778e94 0x80778e94 +80779080 0x80779080 +80779084 0x80779084 +80779104 0x80779104 +8077917c 0x8077917c +80779230 0x80779230 +8077923c 0x8077923c +80779240 0x80779240 +80779608 0x80779608 +8077960c 0x8077960c +80779804 0x80779804 +807798dc 0x807798dc +80779a94 0x80779a94 +80779b60 0x80779b60 +80779d1c 0x80779d1c +80779db0 0x80779db0 +8077a1ec 0x8077a1ec +8077a1f0 0x8077a1f0 +8077a268 0x8077a268 +8077a2e0 0x8077a2e0 +8077a2e4 0x8077a2e4 +8077a3a0 0x8077a3a0 +8077a3f0 0x8077a3f0 +8077a650 0x8077a650 +8077a894 0x8077a894 +8077a9b0 0x8077a9b0 +8077aa50 0x8077aa50 +8077ab84 0x8077ab84 +8077ac7c 0x8077ac7c +8077ac80 0x8077ac80 +8077ac84 0x8077ac84 +8077ac88 0x8077ac88 +8077ac8c 0x8077ac8c +8077ac94 0x8077ac94 +8077ac98 0x8077ac98 +8077ac9c 0x8077ac9c +8077aca0 0x8077aca0 +8077aca4 0x8077aca4 +8077acac 0x8077acac +8077acb4 0x8077acb4 +8077ad04 0x8077ad04 +8077ad7c 0x8077ad7c +8077ad80 0x8077ad80 +8077add0 0x8077add0 +8077ae48 0x8077ae48 +8077ae4c 0x8077ae4c +8077ae9c 0x8077ae9c +8077af14 0x8077af14 +8077af18 0x8077af18 +8077afd0 0x8077afd0 +8077b0b4 0x8077b0b4 +8077b0b8 Objects::ItemDropper::__ct +8077b100 Objects::ItemDropper::__dt +8077b140 Objects::ItemDropper::OnStart +8077b1f0 Objects::ItemDropper::LoadEffects +8077b1f4 Objects::ItemDropper::Update +8077b248 Objects::ItemDropper::RespawnImpl +8077b2ac Objects::ItemDropper::Respawn +8077b2bc Objects::ItemDropper::DropItem +8077b4b4 Objects::ItemDropper::CreateExplosionEffect +8077b584 Objects::ItemDropper::OnCollision +8077b6ac Objects::ItemDropper::OnNormalCollision +8077b6b0 Objects::ItemDropper::OnImperviousCollision +8077b6b4 Objects::ItemDropper::OnItemCollision +8077b7b0 Objects::ItemDropper::OnNormalItemCollision +8077b7b4 0x8077b7b4 +8077b7b8 0x8077b7b8 +8077b7f8 0x8077b7f8 +8077b810 0x8077b810 +8077bbd0 0x8077bbd0 +8077bd2c 0x8077bd2c +8077bd30 0x8077bd30 +8077bd70 0x8077bd70 +8077bdb0 0x8077bdb0 +8077c140 0x8077c140 +8077c148 0x8077c148 +8077c188 Objects::MiiObj::__ct +8077c1c8 Objects::MiiObj::__dt +8077c234 Objects::MiiObj::OnStart +8077c240 Objects::MiiObj::LoadModels +8077c774 Objects::MiiObj::GetPropertiesBitfield +8077c77c Objects::MiiPoster::__ct +8077c7bc Objects::MiiPoster::__dt +8077c7c8 Objects::MiiPoster::OnStart +8077c99c Objects::MiiPoster::LoadModels +8077c9a4 Objects::MiiPoster::GetPropertiesBitfield +8077c9e4 Objects::MiiKanban::__ct +8077ca24 Objects::MiiKanban::LoadModels +8077ccbc Objects::MiiKanban::OnStart +8077ccc8 0x8077ccc8 +8077ccd0 0x8077ccd0 +8077cd10 Objects::Dokan_sfc::__ct +8077cd50 Objects::Dokan_sfc::OnStart +8077cde8 Objects::Dokan_sfc::Update +8077ce6c 0x8077ce6c +8077cedc 0x8077cedc +8077d0c0 0x8077d0c0 +8077d12c Objects::Dokan_sfc::OnCollision +8077d1e4 Objects::Dokan_sfc::OnItemCollision +8077d270 Objects::Dokan_sfc::UpdateCollision +8077d3c8 Objects::Dokan_sfc::UpdateShadow +8077d47c Objects::Dokan_sfc::LoadAnimations +8077d4fc Objects::Dokan_sfc::vf_0xec +8077d504 Objects::Dokan_sfc::GetPropertiesBitfield +8077d50c Objects::Dokan_sfc::__dt +8077d54c Objects::Sin_ItemBox::__ct +8077d588 Objects::Sin_ItemBox::__dt +8077d5c8 Objects::Sin_ItemBox::OnStart +8077d6a8 Objects::Sin_ItemBox::Update +8077d7ec 0x8077d7ec +8077d8f8 Objects::Sin_ItemBox::GetPropertiesBitfield +8077d900 obj_inseki::__ct +8077d9d0 0x8077d9d0 +8077da10 0x8077da10 +8077da58 obj_inseki_update +8077db60 0x8077db60 +8077db68 0x8077db68 +8077dbcc 0x8077dbcc +8077dc0c 0x8077dc0c +8077dcc8 0x8077dcc8 +8077dcf0 0x8077dcf0 +8077de54 0x8077de54 +8077deb8 0x8077deb8 +8077dfc4 0x8077dfc4 +8077e034 0x8077e034 +8077e048 0x8077e048 +8077e04c 0x8077e04c +8077e050 0x8077e050 +8077e054 0x8077e054 +8077e05c Objects::Fall::__ct +8077e394 Objects::Fall::__dt +8077e3d4 Objects::Fall::OnStart +8077e3d8 Objects::Fall::Update +8077e4bc 0x8077e4bc +8077e5a0 Objects::Fall::GetPropertiesBitfield +8077e5a8 0x8077e5a8 +8077e5b8 0x8077e5b8 +8077e5f8 0x8077e5f8 +8077e5fc 0x8077e5fc +8077e6d8 0x8077e6d8 +8077e7e4 0x8077e7e4 +8077e8a8 0x8077e8a8 +8077e944 0x8077e944 +8077ea20 0x8077ea20 +8077eb44 Object::GetRaceinfoRandom +8077eb78 0x8077eb78 +8077ec20 0x8077ec20 +8077ecc8 0x8077ecc8 +8077ed20 0x8077ed20 +8077ed94 0x8077ed94 +8077ee24 0x8077ee24 +8077ef44 RaceEndTallies::Disposer__dt +8077f070 RaceEndTallies::CreateInstance +8077f118 RaceEndTallies::DestroyInstance +8077f1cc RaceEndTallies::__dt +8077f270 RaceEndTallies::__ct +8077f2ec RaceEndTallies::Init +8077f474 RaceEndTallies::Init_switch +8077f478 RaceEndTallies::Init_caseD_0 +8077f484 RaceEndTallies::Init_caseD_3 +8077f48c RaceEndTallies::Init_caseD_4 +8077f5d8 RaceEndTallies::UpdateLicenseTallies +8077f8e4 RaceEndTallies::Reset +8077f928 RaceEndTallies::SetVSBattleBool +8077f980 RaceEndTallies::SetTotalDistance +8077f998 RaceEndTallies::SetTotalDistanceVS +8077f9f4 RaceEndTallies::SetCharacterAndKart +8077fa78 RaceEndTallies::SetCourseId +8077fab0 0x8077fab0 +8077fabc 0x8077fabc +8077fac4 0x8077fac4 +8077fac8 RaceEndTallies::SetWheelBool +8077fbb0 RaceEndTallies::SetItemsTricksCounts +8077fbcc 0x8077fbcc +8077fc20 0x8077fc20 +8077fc78 0x8077fc78 +8077fe20 0x8077fe20 +8077ff30 0x8077ff30 +80780198 0x80780198 +80780210 0x80780210 +80780288 0x80780288 +8078028c 0x8078028c +80780290 0x80780290 +8078058c 0x8078058c +80780828 0x80780828 +80780b64 0x80780b64 +80780cf4 0x80780cf4 +80780d8c 0x80780d8c +80780e24 0x80780e24 +80780ea8 0x80780ea8 +80780f1c 0x80780f1c +80780f6c 0x80780f6c +80780fe4 0x80780fe4 +80780fe8 0x80780fe8 +80781038 0x80781038 +807810b0 0x807810b0 +807810b4 EntityManager::__dt +807811ac EntityManager::CreateInstance +807811fc EntityManager::DestroyInstance +807812b0 EntityManager::__ct +807814a8 0x807814a8 +8078154c 0x8078154c +80781580 EntityManager::Update +8078195c EntityManager::GetNextKartPlayer +807819c4 EntityManager::GetNextObj +80781a2c EntityManager::GetNextObjectCollidable +80781a94 EntityManager::GetNextObjectKCL +80781afc EntityManager::UpdateIndexes +80781c20 EntityManager::InsertKartPlayer +80781c34 EntityManager::InsertItemEntity +80781c48 EntityManager::InsertObjectCollidable +80781cf0 EntityManager::InsertObjectKCL +80781d04 EntityManager::InsertEntity +80782148 EntityManager::RemoveEntity +80782344 EntityManager::PrepareFromEntity +80782490 EntityManager::FindEntitiesCloseToEntity +807826e4 EntityManager::PrepareFromSphere +80782830 EntityManager::FindEntitiesCloseToSphere +8078298c 0x8078298c +80782a30 EntityManager::IsPrepared +80782aa0 Entity::__ct +80782ac4 Entity::__dt +80782b04 Entity::Init +80782b3c Entity::MakeDynamic +80782b4c Entity::Resize +80782b68 AreaMasker_ +80782b78 EntityManager::Prepare +80782b90 ClipInfoMgr::GetArea8And9GroupIDs +80782c4c ClipInfoMgr::UpdateScreenInfo +80782e90 ClipInfoMgr::NormalizeVector +80782f10 ClipInfoMgr::Disposer__dt +8078303c ClipInfoMgr::CreateInstance +80783108 ClipInfoMgr::DestroyInstance +807831bc ClipInfoMgr::__ct +8078325c ClipScreenInfo::__ct +80783260 ClipScreenInfo::__dt +807832a0 ClipInfoMgr::__dt +80783344 ClipInfoMgr::Update +80783688 ClipInfoMgr::Insert +80783758 0x80783758 +80783770 ClipInfoMgr::CalcAreaType8Refs +807837a8 ClipInfo::__ct +807837b4 ClipInfo::__dt +807837f4 ClipInfo::Init +807838d4 0x807838d4 +807838e8 0x807838e8 +80783920 0x80783920 +80783954 DriverMgr::Disposer__dt +807839dc DriverMgr::CreateInstance +80783a2c DriverMgr::DestroyInstance +80783a50 DriverMgr::__ct +80783e18 DriverMgr::__dt +80783f2c 0x80783f2c +80783f40 DriverMgr::SetController +80783f50 0x80783f50 +80783f98 0x80783f98 +80784194 0x80784194 +8078436c 0x8078436c +80784440 0x80784440 +807844b4 0x807844b4 +807844c0 0x807844c0 +80784608 0x80784608 +80784610 0x80784610 +80784778 0x80784778 +807847dc DriverMgr::InitAwards +80784818 DriverMgr::Update +80784974 0x80784974 +807849dc 0x807849dc +80784a84 0x80784a84 +80784b04 0x80784b04 +80784c60 0x80784c60 +80784da8 0x80784da8 +80784dd8 DriverMgr::ChangeFocusedPlayer +80784de8 0x80784de8 +80784df8 MHModelDirector::__ct +80784e54 MHModelDirector::SetMatsTEVColors +80784fdc CourseMgr::CreateInstance +80785118 CourseMgr::DestroyInstance +807851a4 CourseMgr::LoadModels +80785330 0x80785330 +80785448 0x80785448 +807854dc CourseMgr::SetSoftWallInfo +807854e4 CourseMgr::UpdateKCL +8078557c 0x8078557c +80785688 0x80785688 +807857b8 0x807857b8 +807858e0 0x807858e0 +807858e4 0x807858e4 +80785a8c 0x80785a8c +80785af4 0x80785af4 +80785c9c 0x80785c9c +80785ee8 0x80785ee8 +80786134 CourseMgr::IsCollidingNoTerrainInfoNoTriangleCheck +80786314 CourseMgr::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +807864f4 CourseMgr::IsColliding +80786778 CourseMgr::IsCollidingAddEntryNoTriangleCheck +807869fc 0x807869fc +80786ba4 0x80786ba4 +80786d4c 0x80786d4c +80786f98 0x80786f98 +807871e4 CourseMgr::IsCollidingNoTerrainInfo +807873b0 CourseMgr::IsCollidingAddEntryNoTerrainInfo +8078757c 0x8078757c +807877ec CourseMgr::IsCollidingAddEntry +80787a5c 0x80787a5c +80787ab4 _sinit_CourseMgr_cpp +80787ac4 MHModelDirector::__dt(thunk) +80787acc Item::LoadObjProperties +80787af0 Item::InitAllObjProperties +80787e10 Item::IsTT +80787e1c Item::IsAwards +80787e24 Item::GetDriverMgr +80787e30 Item::GetKMPObjectsCount +80787e54 Item::GetGOBJHolder +80787e60 Item::GetKMPObjectId +80787e70 Item::ObjProperties::__ct(Copy) +80787fac Item::ObjProperties::ComputeCapacities +80788260 0x80788260 +807882d4 0x807882d4 +8078834c 0x8078834c +807883c4 0x807883c4 +8078843c 0x8078843c +807884b4 0x807884b4 +80788528 0x80788528 +8078859c 0x8078859c +80788638 0x80788638 +80788754 Item::PlayerObj::__ct +807887f4 0x807887f4 +80788834 Item::PlayerObj::Init +80788904 Item::PlayerObj::UseItem +80788bfc 0x80788bfc +80788cbc 0x80788cbc +80788ddc 0x80788ddc +80788dec 0x80788dec +80788e50 Item::PlayerObj::UpdateParams +80789134 0x80789134 +807891e4 0x807891e4 +80789310 Item::PlayerObj::UpdateTetheredItems +80789514 0x80789514 +8078960c 0x8078960c +80789afc Item::PlayerObj::TrailPrepare +80789c5c Item::PlayerObj::TrailUpdate +80789fbc 0x80789fbc +8078a024 0x8078a024 +8078a158 0x8078a158 +8078a1d0 Item::PlayerObj::TripleTrailPrepare +8078a560 Item::PlayerObj::TripleTrailUpdate +8078aef8 0x8078aef8 +8078af68 0x8078af68 +8078b1e4 Item::PlayerObj::SpinCalc +8078b550 Item::PlayerObj::SpinPrepare +8078b688 Item::PlayerObj::SpinUpdate +8078ba58 0x8078ba58 +8078baa4 0x8078baa4 +8078bb6c 0x8078bb6c +8078bba0 0x8078bba0 +8078bc38 0x8078bc38 +8078bd10 0x8078bd10 +8078be7c Item::PlayerObj::CalcInitialObjSpeedAndDir +8078c024 0x8078c024 +8078c1a0 0x8078c1a0 +8078c2d0 0x8078c2d0 +8078c344 Item::PlayerObj::LoseItem +8078c4cc 0x8078c4cc +8078c5b8 Item::PlayerObj::ComputeWheelPosRelativeToKart +8078c650 0x8078c650 +8078c65c Item::PlayerObj::UpdateRemote +8078c83c 0x8078c83c +8078cb54 0x8078cb54 +8078cc34 0x8078cc34 +8078cc94 0x8078cc94 +8078ccbc Item::ObjHolder::__ct +8078ccc0 Item::ObjHolder::Init +8078cd88 Item::ObjHolder::HideAll +8078cdf8 Item::ObjHolder::Spawn +8078cf1c 0x8078cf1c +8078cf5c Item::ObjHolder::OnObjKillFinish +8078d1e4 0x8078d1e4 +8078d33c Item::ObjHolder::SortObjs +8078d464 Item::ObjHolder::Update +8078d980 0x8078d980 +8078d99c 0x8078d99c +8078da3c 0x8078da3c +8078db24 Item::ObjHolder::UpdateModelPositions +8078dbb0 Item::ObjHolder::OnFinishThrow +8078dc2c 0x8078dc2c +8078dc94 Item::ObjHolder::ProcessRecvEVENT +8078df64 Item::ObjHolder::ProcessRecvShootEVENT +8078e134 Item::ObjHolder::ProcessRecvHitFreeEVENT +8078e2ac 0x8078e2ac +8078e418 0x8078e418 +8078e4a0 Item::ObjHolder::GetTotalItemCount +8078e518 0x8078e518 +8078e540 Item::Player::__ct +8078e590 0x8078e590 +8078e5d0 0x8078e5d0 +8078e610 0x8078e610 +8078e650 Item::PlayerObj::__dt +8078e6d4 Item::Player::Init +8078e884 0x8078e884 +8078e91c Item::Player::Update +8078f1d8 0x8078f1d8 +8078f200 0x8078f200 +8078f240 0x8078f240 +8078f284 0x8078f284 +8078f4d0 0x8078f4d0 +8078f578 0x8078f578 +8078f640 Item::Player::ActivateMushroom +8078f678 Item::Player::ActivateStar +8078f6a8 Item::Player::ActivateMega +8078f6d8 Item::Player::ActivateBullet +8078f700 0x8078f700 +8078f704 0x8078f704 +8078f71c 0x8078f71c +8078f7e0 0x8078f7e0 +8078f83c 0x8078f83c +8078f8e4 0x8078f8e4 +8078f91c Item::Player::OnObjTetherEnd +8078f980 0x8078f980 +8078fa00 0x8078fa00 +8078fa24 Item::Player::LoseItemFromDmg +8078fb1c Item::Player::LoseTetheredItem +8078fb80 0x8078fb80 +8078fc2c Item::Player::DecideItem +8078fcf8 0x8078fcf8 +8078fd00 0x8078fd00 +8078fda8 0x8078fda8 +8078fdb0 Item::Player::HasTripleItem +8078fe34 0x8078fe34 +8078ff00 Item::Player::GetHeldCount +8078ff78 0x8078ff78 +8078ff84 0x8078ff84 +8078ff90 Item::Manager::Disposer__dt +8079012c Item::Manager::CreateInstance +8079017c Item::Manager::DestroyInstance +807902cc Item::Manager::__ct +807904d0 Item::ObjHolder::__dt +80790510 Item::Player::__dt +807905a4 0x807905a4 +807905e4 0x807905e4 +80790624 0x80790624 +80790664 Item::Manager::__dt +80790788 Item::Manager::Init +80790844 Item::Manager::Update +80790994 Item::Manager::UpdateAllObjModelPos +807909ec Item::Manager::UpdateObjHolders +80790a44 Item::Manager::UpdateTotalItemCountMinus30 +80790ac0 Item::Manager::UpdatePlayers +80790b20 0x80790b20 +80790bdc Item::Manager::IsThereCapacityForItem +80790c64 0x80790c64 +80790ca0 Item::Manager::CheckKartCollision +80790e44 ItemManager::InitItemDirect +80790fb0 Item::Manager::CreateItemDirect +80791120 Item::Manager::GenerateItemDirect +8079128c Item::Manager::SpawnCloudForLocal +807913ac Item::Manager::SpawnCloudForRemote +8079148c 0x8079148c +8079156c 0x8079156c +807915e8 Item::Manager::DoSomethingWithFIBObjTevColors +80791648 0x80791648 +80791650 Item::Manager::GetHeldCount +807916c4 0x807916c4 +8079176c Item::EVENTBuffer::Disposer__dt +80791898 Item::EVENTBuffer::CreateInstance +80791b5c Item::EVENTBuffer::DestroyInstance +80791c10 0x80791c10 +80791c98 0x80791c98 +80791cb4 0x80791cb4 +80791d24 Item::EVENTBuffer::GetPlayerIdFromBitfield +80791d2c Item::EVENTBuffer::FillOrExtractShootPos +80791efc Item::EVENTBuffer::FillOrExtractPosDiff +8079206c 0x8079206c +80792300 0x80792300 +8079232c Item::EVENTBuffer::FillOrExtractBitfield +8079238c Item::EVENTBuffer::FillOrExtractTargetingShoot +80792434 Item::EVENTBuffer::FillOrExtractBombShoot +807924a0 Item::EVENTBuffer::FillOrExtractShoot +80792d88 Item::EVENTBuffer::UpdateSend +80792ec4 Item::EVENTBuffer::UpdateReceive +80792fe0 Item::EVENTBuffer::QueueSendEntry +807930a0 Item::EVENTBuffer::QueueReceivedEntry +80793168 0x80793168 +80793214 Item::Obj::AddUseEVENTEntry +807932d8 Item::Obj::AddShootEVENTEntry +807933b8 Item::Obj::AddHitFreeEVENTEntry +8079348c Item::Obj::AddHitDraggedEVENTEntry +80793548 Item::Obj::AddTCLostPassEVENTEntry +80793614 Item::Obj::AddAction6EVENTEntry +807936d8 Item::Obj::AddTCLostEndEVENTEntry +807937b8 Item::Obj::AddDropEVENTEntry +80793874 Item::Obj::GetHitFreeEntryPlayerIdAndType +8079388c 0x8079388c +80793894 0x80793894 +807938bc Item::EVENTBuffer::GetEntryBitfield +807938d8 Item::EVENTBuffer::GetUSEPlayerId +807938e0 0x807938e0 +80793924 0x80793924 +80793954 Item::Obj::SendOrExtractHitDraggedEVENT +807942d4 thunk_0x8079dee4 +807943d0 Item::EVENTBuffer::__ct +80794668 Item::EVENTBuffer::__dt +8079470c 0x8079470c +80794714 0x80794714 +80794738 0x80794738 +80794740 0x80794740 +80794748 0x80794748 +80794750 0x80794750 +80794758 0x80794758 +80794760 GetEVENTEntryDataLength +807947f8 Item::Obj::InitSelf +80794840 Item::Obj::CalcWorld::ExecCallbackB +807948b0 Item::Obj::__ct +80794914 0x80794914 +807949f0 Item::Obj::SpawnModel +80794a90 Item::Obj::PrepareLight +80794c38 0x80794c38 +80794c54 0x80794c54 +80794ca8 Item::Obj::SetInitialPosition +80794cb0 Item::Obj::OnKill +80794d60 Item::Obj::OnTetherBreak +80794d64 Item::Obj::OnFinishKill +80794e28 Item::Obj::ProcessRecvShootEVENT +80794ed8 Item::Obj::vf_0x30 +807951e4 Item::Obj::vf_0x34 +80795218 Item::Obj::Init +807952f4 Item::Obj::RemoveFromScn +80795380 0x80795380 +80795544 Item::Obj::Spawn +807955e8 Item::Obj::Set +80795878 Item::Obj::FinishKill +807958e8 0x807958e8 +807959dc 0x807959dc +80795a4c 0x80795a4c +80795bb0 0x80795bb0 +80795c38 0x80795c38 +80795c8c 0x80795c8c +80795d10 0x80795d10 +80795d40 0x80795d40 +80795da8 0x80795da8 +80795e24 Item::Obj::RegisterEntity +80795ec0 Item::Obj::UnregisterEntity +80795ed4 0x80795ed4 +80795fe0 Item::Obj::Update +807968a8 0x807968a8 +807968e8 0x807968e8 +80796928 0x80796928 +80796c44 0x80796c44 +80796d78 0x80796d78 +80796e24 Item::Obj::TryDisappearDueToExcess +80796ea0 0x80796ea0 +80796ea8 Item::Obj::CanDisappearFromDuration +80796f08 0x80796f08 +80796f50 Item::Obj::LoadGraphicsImplicitBRRESNoFunc +80796f98 Item::Obj::LoadGraphicsDefault +80796fd0 Item::Obj::LoadGraphicsImplicitBRRES +80797034 Item::Obj::LoadGraphics +80797374 Item::Obj::LoadItemLight +807975c4 Item::Obj::UpdateModelPosition +807975e8 Item::Obj::UpdateModelPositionNoClip +807977ac Item::Obj::UpdateModelFromVecs +80797a5c Item::Obj::UpdateShadow +80797cc8 Item::Obj::UpdateModelFromQuat +80797e1c Item::Obj::OnObjCollision +80798068 0x80798068 +80798250 0x80798250 +80798390 0x80798390 +807984c8 Item::Obj::CheckKartCollision +80798674 0x80798674 +80798858 0x80798858 +807988e0 Item::XZVecMag +807988f0 Item::Obj::ProcessOtherCollision +80798c88 Item::Obj::CheckOtherObjsCollision +80798ecc 0x80798ecc +80799228 0x80799228 +80799244 0x80799244 +80799264 0x80799264 +80799340 0x80799340 +807994ec 0x807994ec +80799564 0x80799564 +807995a4 Item::Obj::UpdateWithClipping +80799a9c 0x80799a9c +80799ddc 0x80799ddc +80799e5c 0x80799e5c +80799ed0 0x80799ed0 +80799ef4 0x80799ef4 +80799f0c 0x80799f0c +80799f2c 0x80799f2c +80799f4c 0x80799f4c +80799f6c 0x80799f6c +80799f70 0x80799f70 +80799f7c 0x80799f7c +80799fb0 0x80799fb0 +8079a0b8 0x8079a0b8 +8079a0f4 0x8079a0f4 +8079a130 0x8079a130 +8079a16c 0x8079a16c +8079a1b4 Item::Obj::PrepareShootEventPacket +8079a364 Item::Obj::SendOrExtractShootEVENT +8079a3d4 0x8079a3d4 +8079a468 0x8079a468 +8079a4c0 0x8079a4c0 +8079a538 0x8079a538 +8079a5a4 0x8079a5a4 +8079a60c 0x8079a60c +8079a63c 0x8079a63c +8079a770 0x8079a770 +8079a784 Item::Obj::OnPlayerCollision +8079a864 0x8079a864 +8079a8d4 0x8079a8d4 +8079a8d8 Item::Obj::KillThunk +8079a8dc 0x8079a8dc +8079a8e0 0x8079a8e0 +8079a8e4 Item::ObjKouraGreen::UpdateThunk +8079a8e8 Item::ObjKouraRed::UpdateThunk +8079a8ec Item::ObjKouraTogezo::UpdateThunk +8079a8f0 Item::ObjBanana::UpdateThunk +8079a8f4 Item::ObjBomb::UpdateThunk +8079a8f8 Item::ObjFIB::UpdateThunk +8079a8fc Item::ObjKumo::UpdateThunk +8079a900 0x8079a900 +8079a904 0x8079a904 +8079a908 0x8079a908 +8079a90c 0x8079a90c +8079a910 0x8079a910 +8079a914 0x8079a914 +8079a918 0x8079a918 +8079a91c 0x8079a91c +8079a920 0x8079a920 +8079a924 0x8079a924 +8079a928 0x8079a928 +8079a92c 0x8079a92c +8079a930 0x8079a930 +8079a934 0x8079a934 +8079a938 0x8079a938 +8079a93c 0x8079a93c +8079a940 0x8079a940 +8079a944 0x8079a944 +8079a948 0x8079a948 +8079a970 0x8079a970 +8079a978 0x8079a978 +8079a97c 0x8079a97c +8079a980 0x8079a980 +8079a988 0x8079a988 +8079a9c8 Item::Obj::CalcWorldCB::__dt +8079aa08 Item::Obj::CalcWorldCB::ExecCallbackB(thunk) +8079aa10 Item::Obj::CalcWorldCB::__dt(thunk) +8079aa18 Item::ObjBanana::CreateArray +8079aa94 0x8079aa94 +8079aad4 0x8079aad4 +8079ab14 0x8079ab14 +8079ab54 0x8079ab54 +8079ab94 0x8079ab94 +8079abd4 Item::ObjBanana::SetInitialPosition +8079ac74 0x8079ac74 +8079ae6c Item::ObjBanana::Update +8079b000 Item::ObjBanana::vf_0x30 +8079b064 Item::ObjBanana::InitSelf +8079b0e4 Item::ObjBanana::SpawnModel +8079b0e8 Item::ObjBanana::OnKill +8079b1b8 Item::ObjBomb::CreateArray +8079b378 0x8079b378 +8079b3f0 0x8079b3f0 +8079b548 0x8079b548 +8079b5d4 0x8079b5d4 +8079b728 0x8079b728 +8079b844 Item::ObjBomb::__ct +8079b9a8 Item::ObjExplosion::__dt +8079ba0c Item::ObjBomb::SetInitialPosition +8079bb3c 0x8079bb3c +8079bcd0 Item::ObjBomb::Update +8079bf94 Item::ObjBomb::SendOrExtractShootEVENT +8079c000 Item::ObjBomb::vf_0x30 +8079c084 Item::ObjBomb::vf_0x34 +8079c138 Item::ObjBomb::InitSelf +8079c334 Item::ObjBomb::UpdateModelPosition +8079c9d4 Item::ObjBomb::UpdateModelPositionNoClip +8079ca14 0x8079ca14 +8079cac4 0x8079cac4 +8079cb74 Item::ObjBomb::ToggleVisible +8079cbb8 Item::ObjBomb::SpawnModel +8079ccf0 Item::ObjBomb::PrepareLight +8079cd3c 0x8079cd3c +8079cd7c 0x8079cd7c +8079ce98 0x8079ce98 +8079cf60 Item::ObjBomb::OnKill +8079d0ec Item::ObjBomb::OnTetherBreak +8079d190 Item::ObjBomb::OnFinishKill +8079d1ec 0x8079d1ec +8079d23c 0x8079d23c +8079d260 Item::ObjBomb::__dt +8079d2cc __sinit_ItemObjBomb_cpp +8079d314 Item::ObjBomb::__dt(thunk) +8079d31c Item::Obj::KillObj +8079d4e4 0x8079d4e4 +8079d554 Item::Obj::KillFromOtherCollision +8079d608 Item::Obj::KillFromPlayerCollision +8079d6f4 Item::Obj::UpdateKill +8079d72c 0x8079d72c +8079d91c Item::ObjMiddle::__ct +8079d96c 0x8079d96c +8079d9ec 0x8079d9ec +8079dc08 Item::Obj::DisappearDueToExcess +8079dc84 0x8079dc84 +8079dd7c 0x8079dd7c +8079debc 0x8079debc +8079df58 0x8079df58 +8079df60 0x8079df60 +8079df68 0x8079df68 +8079e1d8 0x8079e1d8 +8079e2a0 0x8079e2a0 +8079e344 0x8079e344 +8079e840 0x8079e840 +8079e89c Item::ObjFIB::CreateArray +8079e934 Item::ObjFIB::SetInitialPosition +8079e9d4 Item::ObjFIB::Update +8079ea50 Item::ObjFIB::vf_0x30 +8079eab4 Item::ObjFIB::InitSelf +8079ed54 0x8079ed54 +8079ed84 0x8079ed84 +8079ef10 Item::ObjFIB::SpawnModel +8079efe0 Item::ObjFIB::UpdateModelPosition +8079f128 Item::ObjFIB::OnKill +8079f12c Item::ObjGesso::CreateArray +8079f1a8 0x8079f1a8 +8079f1fc 0x8079f1fc +8079f218 __sinit_ItemObjKinokoBig_cpp +8079f240 Item::ObjKinokoPowerful::CreateArray +8079f2bc Item::Player::UseGoldenMushroom +8079f304 Item::ObjKinokoPowerful::InitSelf +8079f320 __sinit_ItemObjKinokoPowerful_cpp +8079f348 Item::ObjKouraRed::CreateArray +8079f510 Item::ObjKouraRed::__ct +8079f6b0 0x8079f6b0 +8079f6f0 0x8079f6f0 +8079f774 0x8079f774 +8079f808 0x8079f808 +8079f8a0 0x8079f8a0 +8079f904 0x8079f904 +8079f960 0x8079f960 +8079f9e0 Item::ObjKouraRed::SetInitialPosition +8079fbd4 Item::ObjKouraRed::Update +8079fdb4 Item::ObjKouraRed::UpdateModelPosition +8079fe54 Item::ObjKouraRed::UpdateModelPositionNoClip +8079fee0 0x8079fee0 +8079ff20 0x8079ff20 +8079ffd8 0x8079ffd8 +807a0024 0x807a0024 +807a00d0 0x807a00d0 +807a01b0 0x807a01b0 +807a01d0 0x807a01d0 +807a035c 0x807a035c +807a037c 0x807a037c +807a04d8 0x807a04d8 +807a0590 0x807a0590 +807a06d4 0x807a06d4 +807a06e0 0x807a06e0 +807a06e4 Item::ObjKouraRed::InitSelf +807a0764 Item::ObjKouraRed::SendOrExtractShootEVENT +807a0860 Item::ObjKouraRed::vf_0x30 +807a09ac 0x807a09ac +807a0ae0 Item::ObjKouraRed::OnKill +807a0b68 Item::ObjKouraRed::OnFinishKill +807a0bac Item::ObjKouraRed::SpawnModel +807a0bec Item::ObjKouraRed::GetTargetedPlayerId +807a0c08 0x807a0c08 +807a0cc4 __sinit_ItemObjKouraRed_cpp +807a0d30 0x807a0d30 +807a0d38 Item::ObjKouraTogezo::CreateArray +807a0f6c Item::ObjKouraTogezo::__ct +807a1140 0x807a1140 +807a11d8 0x807a11d8 +807a123c 0x807a123c +807a1248 0x807a1248 +807a1284 Item::ObjKouraTogezo::ToggleVisible +807a12c8 Item::ObjKouraTogezo::SpawnModel +807a1360 Item::ObjKouraTogezo::InitSelf +807a1500 Item::ObjKouraTogezo::CalcTargetedPlayerId +807a17f4 Item::ObjKouraTogezo::Reset +807a190c 0x807a190c +807a194c 0x807a194c +807a198c Item::ObjKouraTogezo::SetInitialPosition +807a1b2c Item::ObjKouraTogezo::UpdateModelPosition +807a1d44 Item::ObjKouraTogezo::UpdateModelPositionNoClip +807a1e7c 0x807a1e7c +807a2174 0x807a2174 +807a2470 Item::ObjKouraTogezo::Update +807a28fc 0x807a28fc +807a2944 Item::ObjKouraTogezo::UpdateRouteFlying +807a2b3c Item::ObjKouraTogezo::807ad7e4 +807a2b7c Item::ObjKouraTogezo::UpdateHomeIn +807a2c6c 0x807a2c6c +807a2cb0 Item::ObjKouraTogezo::UpdateDiveIn +807a2eac 0x807a2eac +807a2f60 0x807a2f60 +807a2fb4 Item::ObjKouraTogezo::UpdateHover +807a3204 0x807a3204 +807a326c 0x807a326c +807a32fc 0x807a32fc +807a34d8 Item::ObjKouraTogezo::807ae180_ +807a36a4 Item::ObjKouraTogezo::UpdateExplosion +807a376c Item::ObjKouraTogezo::OnKill +807a38cc Item::ObjKouraTogezo::OnFinishKill +807a3928 Item::ObjKouraTogezo::SendOrExtractShootEVENT +807a3a44 Item::ObjKouraTogezo::vf_0x30 +807a3c00 0x807a3c00 +807a3c08 Item::ObjKouraTogezo::GetTargetedPlayerId +807a3c40 0x807a3c40 +807a3d14 Item::ObjKouraGreen::__dt +807a3dd0 __sinit_ItemObjKouraTogezo_cpp +807a3e3c Item::ObjKouraGreen::__dt(thunk) +807a3e44 Item::ObjKouraGreen::CreateArray +807a3ec0 get_1 +807a3ecc 0x807a3ecc +807a3ed8 0x807a3ed8 +807a3ee4 0x807a3ee4 +807a3ef0 Item::ObjKouraGreen::SetInitialPosition +807a3fbc Item::ObjKouraGreen::Update +807a4084 Item::ObjKouraGreen::UpdateModelPosition +807a4124 Item::ObjKouraGreen::UpdateModelPositionNoClip +807a41b0 Item::ObjKouraGreen::SendOrExtractShootEVENT +807a4290 Item::ObjKouraGreen::vf_0x30 +807a430c Item::ObjKouraGreen::InitSelf +807a438c Item::ObjKouraGreen::OnKill +807a4414 Item::ObjKouraGreen::OnFinishKill +807a4458 Item::ObjKouraGreen::SpawnModel +807a4498 0x807a4498 +807a44b4 0x807a44b4 +807a44f4 0x807a44f4 +807a4dbc 0x807a4dbc +807a514c 0x807a514c +807a522c 0x807a522c +807a5350 0x807a5350 +807a5460 0x807a5460 +807a548c Item::ObjKouraTogezoBase::ResetTargeting +807a549c Item::ObjKouraTogezoBase::SpawnModel +807a54dc 0x807a54dc +807a557c 0x807a557c +807a597c 0x807a597c +807a59a0 0x807a59a0 +807a59d0 0x807a59d0 +807a5b50 Item::ObjKouraTogezo::AcquireTarget +807a5db0 0x807a5db0 +807a5e18 0x807a5e18 +807a5ee4 0x807a5ee4 +807a6084 0x807a6084 +807a62cc 0x807a62cc +807a6608 0x807a6608 +807a6694 0x807a6694 +807a6718 0x807a6718 +807a68cc 0x807a68cc +807a6994 0x807a6994 +807a6a24 0x807a6a24 +807a6a94 0x807a6a94 +807a7640 0x807a7640 +807a76e8 0x807a76e8 +807a776c 0x807a776c +807a7858 0x807a7858 +807a7a98 0x807a7a98 +807a7bac 0x807a7bac +807a7c90 0x807a7c90 +807a7dbc 0x807a7dbc +807a7eb0 Item::ObjThrowable::OnFinishThrow +807a8138 0x807a8138 +807a819c KouraGreen_07b6bfc_ +807a84f4 0x807a84f4 +807a8590 Item::ObjStar::CreateArray +807a860c Item::Player::UseStar +807a8660 Item::ObjStar::InitSelf +807a867c __sinit_ItemObjStar_cpp +807a86a4 Item::ObjThrowable::SetInitialPositionImpl +807a8a74 0x807a8a74 +807a8b10 0x807a8b10 +807a8fe8 0x807a8fe8 +807a9044 0x807a9044 +807a90a0 Item::ObjThunder::CreateArray +807a911c Item::Player::UseThunder +807a91a4 Item::ObjThunder::InitSelf +807a91c0 Item::ObjThunder::ApplyToPlayers +807a9314 __sinit_ItemObjThunder_cpp +807a933c 0x807a933c +807a93f8 0x807a93f8 +807a940c 0x807a940c +807a94fc 0x807a94fc +807a95b0 0x807a95b0 +807a9680 0x807a9680 +807a9aec 0x807a9aec +807a9bac ItemPathManager_createInstance +807a9f1c 0x807a9f1c +807a9f84 0x807a9f84 +807aa03c Player_UpdateItemPoint +807aa4d0 Item::Point_update2 +807aa694 0x807aa694 +807aa784 0x807aa784 +807aaf74 0x807aaf74 +807aafd8 0x807aafd8 +807ab0c4 0x807ab0c4 +807ab1b0 0x807ab1b0 +807ab210 0x807ab210 +807ab374 Item::GetQuatFromMat +807ab3f0 0x807ab3f0 +807ab464 0x807ab464 +807ab4e8 Item::PlayerRoulette::__ct +807ab4f4 0x807ab4f4 +807ab520 Item::PlayerRoulette::Init +807ab550 Item::PlayerRoulette::DecideItem +807ab7d0 0x807ab7d0 +807ab878 Item::PlayerRoulette::OnRouletteEnd +807ab8f0 0x807ab8f0 +807ab91c Item::PlayerRoulette::Update +807abb0c 0x807abb0c +807abb5c 0x807abb5c +807abb70 0x807abb70 +807abb78 0x807abb78 +807abbf0 Item::SlotData::Disposer__dt +807abd1c Item::SlotData::CreateInstance +807abdb4 Item::SlotData::DestroyInstance +807abe68 Item::SlotData::__ct +807abed4 Item::SlotData::__dt +807abf78 Item::SlotData::ProcessTable +807ac2a8 Item::SlotData::GetNextTable +807ac2c0 Item::SlotData::PostProcessVSTable +807ac420 0x807ac420 +807ac474 Item::SlotData::RandomizeRouletteItem +807ac4e8 Item::SlotData::Init +807ac914 Item::SlotData::RouletteItems::__ct +807ac920 Item::ItemSlotData::CanItemNotBeObtained +807ac9cc Item::SlotData::DecideItem +807ace70 Item::SlotData::DecideRouletteItem +807acf5c Item::SlotData::ResetShockTimer +807acf68 Item::SlotData::ResetBlueShellTimer +807acf74 Item::SlotData::ResetBlooperTimer +807acf80 Item::SlotData::ResetPowTimer +807acf8c Item::SlotData::UpdateTimers +807ad034 Item::SlotData::GetBinary +807ad0a0 Item::SlotData::SetupBattleModeProbabilities +807ad300 Item::SlotData::SetupOnlineVSProbabilities +807ad438 0x807ad438 +807ad498 Item::SlotData::SetupVSProbabilities +807ad5a0 Item::SlotData::SetupGPProbabilities +807ad698 Item::PlayerInventory::__ct +807ad69c 0x807ad69c +807ad6d0 Item::PlayerInventory::Init +807ad710 0x807ad710 +807ad858 0x807ad858 +807ad8f0 Item::PlayerInventory::EjectItems +807adbb0 Item::PlayerInventory::LoseItemFromDmg +807adc88 Item::PlayerInventory::Update +807addd0 0x807addd0 +807adea8 0x807adea8 +807adee0 Item::PlayerInventory::SetItem +807adf1c Item::PlayerInventory::RemoveItems +807adf60 Item::PlayerInventory::ClearAll +807adf94 0x807adf94 +807ae050 0x807ae050 +807ae070 0x807ae070 +807ae080 Item::InitAllBehavior +807ae770 DriverMgr::SetParams +807ae7b0 DriverMgr::SetParams_switch +807ae7b4 DriverMgr::SetParams_caseD_2 +807ae7d0 DriverMgr::SetParams_caseD_3 +807ae7ec DriverMgr::SetParams_caseD_7 +807ae808 DriverMgr::SetParams_caseD_9 +807ae824 DriverMgr::SetParams_caseD_0 +807ae83c DriverMgr::SetParams_caseD_1 +807ae8e0 SomeTimers_update +807ae914 0x807ae914 +807aeb5c DriverMgr::IsPlayerComputer +807aec84 0x807aec84 +807aecb8 DriverMgr::GetRaceinfoRandom +807aed08 0x807aed08 +807aed2c 0x807aed2c +807aed54 CollisionInfo::ObjInfo::Init +807aed78 CollisionInfo::ObjInfo::Set +807aedb0 0x807aedb0 +807aedf0 CollisionInfo::ObjInfo::AreItemsAllowedOnObj +807aee04 CollisionInfo::ObjInfo::SetDistanceCalcBit +807aee2c CollisionInfo::ObjInfo::CalcInitialDistance +807aee58 0x807aee58 +807aee74 0x807aee74 +807aee88 CollisionInfo::ObjInfo::Update +807aeea8 CollisionInfo::ObjInfo::UpdateWithRot +807aeed0 CollisionInfo::ObjInfo::Reset +807aeef4 0x807aeef4 +807aef0c KCLTypeHolder::FindClosestCollisionEntry +807aef88 0x807aef88 +807af01c KCLTypeHolder::Reset +807af03c KCLTypeHolder::ApplyFlagAndRegisterEntry +807af088 0x807af088 +807af0c8 KCLTypeHolder::ReplaceBLIGHTIndex +807af0fc KCLTypeHolder::ReplaceKCLVariant +807af130 KCLTypeHolder::ReplaceWheelDepth +807af164 KCLTypeHolder::ReplaceTrickableBit +807af198 KCLTypeHolder::ReplaceRejectBit +807af1cc KCLTypeHolder::ReplaceSoftBit +807af1fc KCLController::__ct +807af31c 0x807af31c +807af35c KCLController::__dt +807af39c 0x807af39c +807af4f4 0x807af4f4 +807af5d0 KCLController::FindTrianglesList +807af6cc KCLController::FindTrianglesListAndProcessNewRadius +807af964 0x807af964 +807b0a60 0x807b0a60 +807b1784 0x807b1784 +807b1e24 KCLController::IsCollidingImpl +807b24a0 KCLController::IsCollidingFromCurCopyPosition +807b2ab4 KCLController::IsCollidingImplInfY +807b30ac 0x807b30ac +807b3154 KCLController::GetTrianglesList +807b322c 0x807b322c +807b3388 KCLController::GetTrianglesListReuse +807b3520 0x807b3520 +807b354c 0x807b354c +807b3794 0x807b3794 +807b39b0 KCLController::IsColliding +807b39dc 0x807b39dc +807b3a60 KCLController::Update +807b3b6c 0x807b3b6c +807b3bd0 0x807b3bd0 +807b3c00 CollisionInfo::Init +807b3c4c 0x807b3c4c +807b3dc4 KCLManager::CreateInstance +807b3e24 KCLManager::DestroyInstance +807b3e78 KCLManager::Load +807b3ec8 0x807b3ec8 +807b3edc KCLManager::Update +807b3f84 0x807b3f84 +807b3fa4 0x807b3fa4 +807b4000 0x807b4000 +807b4178 KCLManager::IsCollidingFillInfoNoTerrainInfo +807b4340 0x807b4340 +807b44b8 KCLManager::IsCollidingFillInfoAddEntryNoTerrainInfo +807b4680 0x807b4680 +807b47f8 KCLManager::IsCollidingFillInfo +807b4af4 0x807b4af4 +807b4c6c KCLManager::IsCollidingFillInfoAddEntry +807b4f68 KCLManager::IsCollidingNoTerrainInfoNoTriangleCheck +807b50fc KCLManager::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +807b5290 KCLManager::IsColliding +807b5424 KCLManager::IsCollidingAddEntryNoTriangleCheck +807b55b8 0x807b55b8 +807b5744 0x807b5744 +807b58d0 0x807b58d0 +807b5a5c 0x807b5a5c +807b5be8 KCLManager::IsCollidingNoTerrainInfo +807b5d90 KCLManager::IsCollidingAddEntryNoTerrainInfo +807b5f38 0x807b5f38 +807b60e0 KCLManager::IsCollidingAddEntry +807b6288 ObjectKCLController::__ct +807b630c ObjectKCLController::__dt +807b6368 ObjectKCLController::Update +807b63ec 0x807b63ec +807b641c 0x807b641c +807b644c 0x807b644c +807b660c 0x807b660c +807b67cc 0x807b67cc +807b6944 0x807b6944 +807b6abc ObjectKCLController::CalcCollisionNoTerrainInfoNoTriangleCheck +807b6c98 ObjectKCLController::CalcCollisionAddEntryNoTerrainInfoNoTriangleCheck +807b6e74 ObjectKCLController::CalcCollision +807b7008 ObjectKCLController::CalcCollisionAddEntryNoTriangleCheck +807b719c 0x807b719c +807b7374 0x807b7374 +807b754c 0x807b754c +807b76dc 0x807b76dc +807b786c ObjectKCLController::CalcCollisionNoTerrainInfo +807b7a60 ObjectKCLController::CalcCollisionAddEntryNoTerrainInfo +807b7c54 0x807b7c54 +807b7e00 ObjectKCLController::CalcCollisionAddEntry +807b7fac 0x807b7fac +807b7fb4 0x807b7fb4 +807b7fc0 0x807b7fc0 +807b7fd8 0x807b7fd8 +807b7fe4 0x807b7fe4 +807b8038 0x807b8038 +807b803c 0x807b803c +807b8078 0x807b8078 +807b8110 0x807b8110 +807b8168 0x807b8168 +807b81a4 0x807b81a4 +807b82bc 0x807b82bc +807b8404 0x807b8404 +807b84ac 0x807b84ac +807b84dc 0x807b84dc +807b862c DriverControllerBones::__ct +807b8654 0x807b8654 +807b8694 DriverControllerBones::__dt +807b86d4 DriverControllerBones::SetBoneName +807b86f8 DriverControllerBones::SetNode +807b8778 DriverMgr::InitiateDriverControllerBoneNames +807b88f8 0x807b88f8 +807b8904 DriverController::__ct +807b8d84 0x807b8d84 +807b8d88 0x807b8d88 +807b8dc8 DriverController::LoadModels +807b941c DriverController::LoadBones +807b9bc4 0x807b9bc4 +807b9cf8 DriverController::Load +807babcc 0x807babcc +807bade0 0x807bade0 +807bade4 0x807bade4 +807bb5c4 0x807bb5c4 +807bb608 0x807bb608 +807bb658 0x807bb658 +807bbc84 0x807bbc84 +807bc044 0x807bc044 +807bc12c 0x807bc12c +807bc308 0x807bc308 +807bc420 0x807bc420 +807bc42c 0x807bc42c +807bc668 DriverController::Init +807bc6d0 DriverControllerBike::Init +807bc738 0x807bc738 +807bc8ec 0x807bc8ec +807bc900 DriverController::Update +807bcad0 0x807bcad0 +807bd2b8 0x807bd2b8 +807bd2c0 0x807bd2c0 +807bd2c4 0x807bd2c4 +807bd458 0x807bd458 +807bd5b8 PlayerModel_setAnimation +807bd710 0x807bd710 +807bd714 0x807bd714 +807be418 0x807be418 +807be428 0x807be428 +807be438 0x807be438 +807be448 0x807be448 +807be458 0x807be458 +807be468 0x807be468 +807be478 0x807be478 +807be488 0x807be488 +807be498 0x807be498 +807be4a8 0x807be4a8 +807be4b8 0x807be4b8 +807be4c8 0x807be4c8 +807be8cc 0x807be8cc +807bf014 0x807bf014 +807bf198 0x807bf198 +807bf1c0 0x807bf1c0 +807bf244 0x807bf244 +807bf26c DriverControllerBike::__ct +807bf2a8 DriverController::__dt +807bf358 0x807bf358 +807bf4b4 0x807bf4b4 +807bf730 0x807bf730 +807bf810 0x807bf810 +807bf92c 0x807bf92c +807bfb44 0x807bfb44 +807bfc70 0x807bfc70 +807c01e8 0x807c01e8 +807c0274 0x807c0274 +807c0ab0 0x807c0ab0 +807c0ec0 0x807c0ec0 +807c0f00 0x807c0f00 +807c0f90 0x807c0f90 +807c1af4 0x807c1af4 +807c1ce4 0x807c1ce4 +807c1d90 0x807c1d90 +807c1e38 0x807c1e38 +807c1ed8 0x807c1ed8 +807c1eec 0x807c1eec +807c20fc MiiDriverModel::UpdateParams +807c2308 0x807c2308 +807c2410 0x807c2410 +807c2518 0x807c2518 +807c2a54 0x807c2a54 +807c2aa4 0x807c2aa4 +807c2cbc 0x807c2cbc +807c2e8c 0x807c2e8c +807c2f68 0x807c2f68 +807c3000 0x807c3000 +807c317c 0x807c317c +807c3198 0x807c3198 +807c31b4 0x807c31b4 +807c31e0 0x807c31e0 +807c31fc 0x807c31fc +807c3218 0x807c3218 +807c3234 0x807c3234 +807c3250 0x807c3250 +807c326c 0x807c326c +807c3288 0x807c3288 +807c32a4 0x807c32a4 +807c33d4 0x807c33d4 +807c3520 0x807c3520 +807c35bc 0x807c35bc +807c35d8 0x807c35d8 +807c3604 0x807c3604 +807c3640 0x807c3640 +807c365c 0x807c365c +807c3680 0x807c3680 +807c36b4 0x807c36b4 +807c36d0 0x807c36d0 +807c36ec 0x807c36ec +807c3708 0x807c3708 +807c372c 0x807c372c +807c3748 0x807c3748 +807c3764 0x807c3764 +807c3798 DriverController::CreateModelDirectors +807c3d24 0x807c3d24 +807c3d38 0x807c3d38 +807c3ee0 0x807c3ee0 +807c4048 0x807c4048 +807c40cc 0x807c40cc +807c4108 0x807c4108 +807c4154 0x807c4154 +807c4348 0x807c4348 +807c437c 0x807c437c +807c4384 0x807c4384 +807c438c 0x807c438c +807c4418 0x807c4418 +807c44a4 0x807c44a4 +807c454c 0x807c454c +807c45f4 0x807c45f4 +807c4644 0x807c4644 +807c4694 0x807c4694 +807c46a0 0x807c46a0 +807c4728 0x807c4728 +807c48a0 0x807c48a0 +807c48a4 0x807c48a4 +807c48b4 0x807c48b4 +807c48d0 0x807c48d0 +807c492c 0x807c492c +807c49f8 0x807c49f8 +807c4d54 0x807c4d54 +807c4d70 0x807c4d70 +807c4dbc 0x807c4dbc +807c4e08 0x807c4e08 +807c4f0c 0x807c4f0c +807c52f8 0x807c52f8 +807c5408 0x807c5408 +807c54b0 0x807c54b0 +807c54c4 0x807c54c4 +807c54f8 DriverControllerBike::__dt +807c55ac 0x807c55ac +807c5888 DriverLimbs::__ct +807c5b88 DriverCalcWorldCB::__dt +807c5bc8 0x807c5bc8 +807c5c44 0x807c5c44 +807c5ca0 0x807c5ca0 +807c5ea4 0x807c5ea4 +807c5ecc 0x807c5ecc +807c5fe0 0x807c5fe0 +807c5fec 0x807c5fec +807c6040 0x807c6040 +807c6094 0x807c6094 +807c60c0 0x807c60c0 +807c62a8 0x807c62a8 +807c6c20 0x807c6c20 +807c6d00 DriverLimbs::ExecCallbackA +807c6ee4 0x807c6ee4 +807c7038 DriverLimbs::ExecCallbackB +807c70d8 0x807c70d8 +807c7430 0x807c7430 +807c7980 DriverLimbs::ExecCallbackC +807c7b5c 0x807c7b5c +807c7de4 0x807c7de4 +807c7f88 DriverLimbs::CalcLeftArm +807c80c8 DriverLimbs::CalcRightArm +807c824c DriverLimbs::CalcLeftLeg +807c8400 0x807c8400 +807c847c 0x807c847c +807c84f8 DriverLimbs::CalcRightLeg +807c86ac 0x807c86ac +807c89f8 0x807c89f8 +807c8b28 0x807c8b28 +807c8c88 0x807c8c88 +807c8d74 0x807c8d74 +807c8f2c 0x807c8f2c +807c95a4 0x807c95a4 +807c9884 0x807c9884 +807c9ba4 0x807c9ba4 +807c9c28 0x807c9c28 +807c9cac 0x807c9cac +807c9d30 0x807c9d30 +807c9f94 0x807c9f94 +807ca3d0 0x807ca3d0 +807ca528 0x807ca528 +807ca5d8 0x807ca5d8 +807ca688 0x807ca688 +807ca6d4 0x807ca6d4 +807ca76c 0x807ca76c +807cac28 0x807cac28 +807cacd4 0x807cacd4 +807cacdc 0x807cacdc +807cacec DriverLimbs::ExecCallbackC(thunk) +807cacf4 DriverLimbs::ExecCallbackB(thunk) +807cacfc DriverLimbs::ExecCallbackA(thunk) +807cad04 DriverLimbs::__dt(thunk) +807cad0c TicoModel::__ct +807caed8 TicoModel::Update +807cb580 0x807cb580 +807cb6ec TicoModel::UpdateKartPosition +807cb734 0x807cb734 +807cb7e8 MiiHeadsModel::__ct(Mii) +807cb874 MiiHeadsModel::__ct(miiIdx, r9) +807cb930 0x807cb930 +807cb9e4 0x807cb9e4 +807cba24 MiiHeadsModel::__ct(Mii, r9) +807cbab0 MiiHeadsModel::Init +807cbd14 0x807cbd14 +807cbd28 MiiHeadsModel::UpdateParams +807cbd40 0x807cbd40 +807cbd58 0x807cbd58 +807cbe50 MiiHeadsModel::SetExpression +807cbea4 MiiHeadsModel::SetExpression_switch +807cbea8 MiiHeadsModel::SetExpression_caseD_5 +807cbef4 MiiHeadsModel::SetExpression_caseD_6 +807cbf40 MiiHeadsModel::SetExpression_caseD_7 +807cbf8c MiiHeadsModel::SetExpression_caseD_4 +807cbfd8 MiiHeadsModel::SetExpression_caseD_2 +807cc024 MiiHeadsModel::SetExpression_caseD_1 +807cc070 MiiHeadsModel::SetExpression_caseD_0 +807cc0bc MiiHeadsModel::SetExpression_caseD_3 +807cc130 0x807cc130 +807cc24c 0x807cc24c +807cc2c8 MiiHeadsModel::__dt +807cc320 0x807cc320 +807cc330 0x807cc330 +807cc420 0x807cc420 +807cc510 0x807cc510 +807cc600 0x807cc600 +807cc640 0x807cc640 +807cc680 0x807cc680 +807cc6c0 0x807cc6c0 +807cc700 0x807cc700 +807cc740 0x807cc740 +807cc780 0x807cc780 +807cc858 0x807cc858 +807cc930 0x807cc930 +807cca08 0x807cca08 +807ccae0 0x807ccae0 +807ccbb8 0x807ccbb8 +807ccc90 0x807ccc90 +807ccf98 0x807ccf98 +807cd2a0 0x807cd2a0 +807cd5a8 0x807cd5a8 +807cd8b0 0x807cd8b0 +807cdbb8 0x807cdbb8 +807cdec0 0x807cdec0 +807ce020 lim_sprintf +807ce0c8 0x807ce0c8 +807ce188 0x807ce188 +807ce200 0x807ce200 +807ce238 0x807ce238 +807ce298 0x807ce298 +807ce314 0x807ce314 +807ce504 0x807ce504 +807ce5ac 0x807ce5ac +807ce6f4 PSMTXRotRad +807ce86c 0x807ce86c +807ce9e4 0x807ce9e4 +807ceb5c 0x807ceb5c +807cec40 0x807cec40 +807ceda4 0x807ceda4 +807cee10 0x807cee10 +807cef4c 0x807cef4c +807cf070 0x807cf070 +807cf194 0x807cf194 +807cf1e8 MinimapMgr::Disposer__dt +807cf2e8 MinimapMgr::CreateInstance +807cf3e4 MinimapMgr::DestroyInstance +807cf4b0 MinimapMgr::__ct +807cf580 0x807cf580 +807cf584 MinimapMgr::Load +807cf884 0x807cf884 +807cf8c4 MinimapMgr::__dt +807cf984 MinimapMgr::TryDraw +807cfa08 MinimapMgr::Draw +807cff5c MinimapMgr::ApplyAREAType5 +807d02bc 0x807d02bc +807d02c0 0x807d02c0 +807d02c4 MinimapMgr::Convert3DPosToPercent +807d031c AwardsMgr::Disposer__dt +807d0448 AwardsMgr::CreateInstance +807d0578 AwardsMgr::DestroyInstance +807d062c AwardsMgr::__ct +807d0730 AwardsMgr::__dt +807d07d4 AwardsMgr::Init +807d15a0 AwardsMgr::LoadStand +807d18d8 AwardsMgr::LoadPlayers +807d212c 0x807d212c +807d2574 0x807d2574 +807d276c 0x807d276c +807d2770 AwardsMgr::SetParams +807d2830 0x807d2830 +807d2854 0x807d2854 +807d2cc0 0x807d2cc0 +807d2d00 0x807d2d00 +807d2e9c 0x807d2e9c +807d3078 0x807d3078 +807d3250 0x807d3250 +807d341c 0x807d341c +807d386c 0x807d386c +807d3ad8 0x807d3ad8 +807d3b68 IKParams::__ct +807d3d44 IKParams::Load +807d4ef8 0x807d4ef8 +807d4f74 Item::Player::UseBlooper +807d5138 Item::ObjGesso::InitSelf +807d5154 0x807d5154 +807d51d0 0x807d51d0 +807d5220 Item::GessoScreen::__ct +807d53b4 Item::GessoScreen::__dt +807d53f4 0x807d53f4 +807d54b8 0x807d54b8 +807d5510 Item::GessoScreen::UpdateModel +807d5860 0x807d5860 +807d5990 0x807d5990 +807d59cc 0x807d59cc +807d5a50 0x807d5a50 +807d5b38 0x807d5b38 +807d5cc4 Item::GessoMgr::CreateInstance +807d5d60 Item::GessoMgr::DestroyInstance +807d5d98 Item::GessoMgr::Init +807d5e60 Item::GessoMgr::__ct +807d5ee8 Item::GessoMgr::DeployBlooper +807d6070 Item::GessoMgr::Update +807d64ec Item::GessoMgr::ApplyBlooper +807d6818 __sinit_ItemObjGesso_cpp +807d6840 Item::ObjKiller::CreateArray +807d68bc Item::Player::UseBullet +807d6900 Item::ObjKiller::InitSelf +807d691c Item::ObjKiller::UpdateModelPosition +807d6a58 __sinit_ItemObjKiller_cpp +807d6a80 Item::ObjKinoko::CreateArray +807d6afc Item::Player::UseMushroom +807d6b50 0x807d6b50 +807d6b6c 0x807d6b6c +807d6b94 Item::ObjKumo::CreateArray +807d6c10 Item::Player::UseTC +807d6c54 Item::ObjKumo::SpawnModel +807d6c88 0x807d6c88 +807d6df0 Item::ObjKumo::UpdateModelPosition +807d6f88 Item::ObjKumo::InitSelf +807d6ff4 0x807d6ff4 +807d71c0 Item::ObjKumo::Update +807d8214 0x807d8214 +807d8348 0x807d8348 +807d83b4 Item::ObjKumo::OnFinishKill +807d8444 0x807d8444 +807d85a0 0x807d85a0 +807d89bc 0x807d89bc +807d8b5c 0x807d8b5c +807d8c60 0x807d8c60 +807d8c6c 0x807d8c6c +807d8c74 0x807d8c74 +807d8c90 Item::ObjKumo::OnKill +807d8d58 0x807d8d58 +807d9094 0x807d9094 +807d92f0 0x807d92f0 +807d93a4 0x807d93a4 +807d9478 0x807d9478 +807d9498 0x807d9498 +807d94c0 0x807d94c0 +807d94e8 0x807d94e8 +807d9504 Item::ObjPow::CreateArray +807d9580 Item::Player::UsePow +807d95f8 Item::ObjPow::InitSelf +807d9614 Item::PowMgr::CreateInstance +807d96c0 0x807d96c0 +807d96c4 Item::PowMgr::DestroyInstance +807d96fc Item::PowMgr::Init +807d976c Item::PowMgr::__ct +807d9804 0x807d9804 +807d9808 Item::PowMgr::DeployPow +807d9940 Item::PowMgr::AnimateModel +807d9b10 Item::PowMgr::CreateShockwave +807d9d4c Item::PowMgr::Update +807d9ec8 0x807d9ec8 +807d9f44 0x807d9f44 +807d9f94 Item::PowScreen::__ct +807da250 0x807da250 +807da2bc 0x807da2bc +807da2d8 0x807da2d8 +807da378 0x807da378 +807da3d4 0x807da3d4 +807da430 Item::PowScreen::UpdateModel +807da668 0x807da668 +807da7b8 0x807da7b8 +807da8e4 Item::PowMgr::IsPowActive +807da900 Item::PowMgr::GetFramesUntilPOWSmash +807da914 Item::PowMgr::GetPowUserPlayerId +807da924 __sinit_ItemObjPow_cpp +807da94c DriverController::GetBoneMatId +807da978 DriverCalcWorldCB::__ct +807dabcc DriverCalcWorldCB::ExecCallbackB +807dacec DriverCalcWorldCB::ExecCallbackC +807dad60 0x807dad60 +807dad68 0x807dad68 +807dad70 0x807dad70 +807dad78 ToadetteHair::__ct(ResFile, ModelDirector) +807db0ac ToadetteHair::__ct(DriverController) +807db408 0x807db408 +807db4bc 0x807db4bc +807db7bc 0x807db7bc +807db7c0 0x807db7c0 +807db7e0 ToadetteHair::ToggleLock +807db7f4 ToadetteHair::CalcWorldCB::ExecCallbackC +807dc3dc ToadetteHair::__dt +807dc434 ToadetteHair::CalcWorldCB::__dt +807dc474 ToadetteHair::CalcWorldCB::ExecCallbackC(thunk) +807dc47c ToadetteHair::CalcWorldCB::__dt(thunk) +807dc484 0x807dc484 +807dc50c CtrlMenuCharacterSelect::GetClassName +807dc518 CtrlMenuCharacterSelect::Load +807dc778 CtrlMenuCharacterSelect::ButtonDriver::__ct +807dc7b4 CtrlMenuCharacterSelect::ButtonDriver::__dt +807dc80c CtrlMenuCharacterSelect::GetUnlockedStatus +807dc898 CtrlMenuCharacterSelect::LoadButton +807dcc88 CtrlMenuCharacterSelect::InitSelf +807dd01c CtrlMenuCharacterSelect::OnUpdate +807dd520 CtrlMenuCharacterSelect::GetButtonDriver +807dd56c CtrlMenuCharacterSelect::OnButtonClick +807dd664 CtrlMenuCharacterSelect::OnButtonSelect +807dd744 CtrlMenuCharacterSelect::OnButtonDeselect +807dd7f0 CtrlMenuCharacterSelect::OnMiiButtonClick +807dd93c CtrlMenuCharacterSelect::OnMiiButtonSelect +807dda1c CtrlMenuCharacterSelect::OnMiiButtonDeselect +807ddac8 CtrlMenuCharacterSelect::OnMultiplayerMiiSelected +807ddb5c CtrlMenuCharacterSelect::GetUnlockedCharacterCountByWeight +807ddc1c CtrlMenuCharacterSelect::GetCorrectButtonDriverId +807ddd70 CtrlMenuCharacterSelect::ButtonDriver::GetClassName +807ddd80 CtrlMenuCharacterSelect::ButtonDriver::InitSelf +807dde1c CtrlMenuCharacterSelect::ButtonDriver::SetPositionAnim +807dde6c CtrlMenuCharacterSelect::ButtonDriver::ResetButtonColours +807de0a0 CtrlMenuCharacterSelect::ButtonDriver::SetButtonColours +807de344 CtrlMenuCharacterSelect::GetRuntimeTypeInfo +807de350 CtrlMenuCharacterSelect::ButtonDriver::GetRuntimeTypeInfo +807de35c CtrlMenuCharacterSelect_cpp_sinit_ +807de380 CtrlMenuCourseSelectCupSub::GetClassName +807de38c CtrlMenuCourseSelectCup::GetClassName +807de39c CtrlMenuCourseSelectCourse::GetClassName +807de3ac CourseButton::GetClassName +807de3bc CtrlMenuCourseSelectCup::Load +807de530 CtrlMenuCourseSelectCup::InitSelf +807de6b4 CtrlMenuCourseSelectCupSub::SetRelativePosition +807de738 CtrlMenuCourseSelectCupSub::InitSelf +807de7d4 CtrlMenuCourseSelectCupSub::OnUpdate +807deee4 Pages::CourseSelect::GetManipulatorManager +807deeec CtrlMenuCourseSelectCourse::Load +807df088 CtrlMenuCourseSelectCourse::InitSelf +807df3a4 CtrlMenuCourseSelectCourse::OnCourseButtonClick +807df3fc CtrlMenuCourseSelectCourse::OnCourseButtonSelect +807df568 CtrlMenuCourseSelectCourse::GetRuntimeTypeInfo +807df574 CourseButton::GetRuntimeTypeInfo +807df580 0x807df580 +807df588 0x807df588 +807df594 0x807df594 +807df5a0 0x807df5a0 +807df5cc 0x807df5cc +807df5d4 0x807df5d4 +807df5dc 0x807df5dc +807df5e4 CourseButton::__dt(PushButton) +807df5ec 0x807df5ec +807df5f4 CourseButton::GetRuntimeTypeInfo(PushButton) +807df5fc CtrlMenuCupSelectCup::GetClassName +807df608 CtrlMenuCupSelectCourse::GetClassName +807df618 CtrlMenuCupSelectCup::Load +807df824 CtrlMenuCupSelectCup::InitSelf +807dfbe8 CtrlMenuCupSelectCup::OnCupButtonSelect +807dfcf8 CtrlMenuCupSelectCup::OnCupButtonClick +807dfd58 CtrlMenuCupSelectCup::IsCupUnlocked +807dfe5c CtrlMenuCupSelectCourse::Load +807dff80 CtrlMenuCupSelectCourse::UpdateTrackList +807e006c CtrlMenuCupSelectCourse::InitSelf +807e0170 CtrlMenuCupSelectCourse::OnUpdate +807e0364 CtrlMenuCupSelectCourse::GetRuntimeTypeInfo +807e0370 CtrlMenuCupSelectCup::GetRuntimeTypeInfo +807e037c CtrlMenuCupcpp_sinit_ +807e0398 0x807e0398 +807e03a4 CtrlMenuPressStart::InitSelf +807e0420 CtrlMenuPressStart::OnUpdate +807e0424 CtrlMenuPressStart::Load +807e04e4 CtrlMenuPressStart::GetRuntimeTypeInfo +807e04f0 CtrlMenuPressStart_cpp_sinit_ +807e0504 CtrlMenuTeamConfirmTeam::GetClassName +807e0514 CtrlMenuTeamConfirmTeam::Load +807e06b0 CtrlMenuTeamConfirmTeam::InitSelf +807e0994 CtrlMenuTeamConfirmTeam::GetRuntimeTypeInfo +807e09a0 CtrlMenuTeamConfirmTeam_cpp_sinit_ +807e09c4 CtrlRace2DMap::GetClassName +807e09d0 CtrlRace2DMap::Load +807e0ff0 CtrlRace2DMapCharacer::__ct +807e102c CtrlRaceBase::__dt +807e1084 CtrlRace2DMapObject::__dt +807e10e0 CtrlRace2DMapCharacter::__dt +807e1140 CtrlRace2DMapBossObj::__ct +807e117c CtrlRace2DMapBossObj::__dt +807e11dc CtrlRace2DMapObject::SetMapPosition +807e11f8 CtrlRace2DMapObject::SetMapRotation +807e1214 CtrlRace2DMap::InitSelf +807e1290 CtrlRace2DMap::OnUpdate +807e12a0 zz_807eab4c +807e1370 CtrlRace2DMapObject::GetClassName +807e1380 CtrlRace2DMapObject::InitSelf +807e13d0 CtrlRace2DMapObject::GetPaneName +807e13dc CtrlRace2DMapObject::OnUpdate +807e1450 CtrlRace2DMapObject::CalculatePosition +807e1544 CtrlRace2DMapCharacter::GetClassName +807e1554 CtrlRace2DMapCharacer::Load +807e1620 CtrlRace2DMapCharacter::InitSelf +807e19a4 CtrlRace2DMapCharacer::OnUpdate +807e1b20 CtrlRace2DMapCharacter::CalculatePosition +807e214c CtrlRace2DMapBossObj::GetClassName +807e215c CtrlRace2DMapBossObj::Load +807e21b4 CtrlRace2DMapBossObj::InitSelf +807e24a4 CtrlRace2DMapBossObj::OnUpdate +807e2594 CtrlRaceBase::GetPane +807e259c CtrlRace2DMapBossObj::GetPaneName +807e25a8 CtrlRace2DMapBossObj::GetRuntimeTypeInfo +807e25b4 CtrlRace2DMapCharacter::GetPaneName +807e25c0 CtrlRace2DMapCharacter::GetRuntimeTypeInfo +807e25cc CtrlRace2DMapObject::GetRuntimeTypeInfo +807e25d8 CtrlRace2DMap::__dt +807e2634 CtrlRace2DMap::GetRuntimeTypeInfo +807e2640 CtrlRace2DMap_cpp_sinit_ +807e2668 CtrlRaceBase::GetClassName +807e2674 CtrlRaceBase::HudSlotColorEnable +807e2960 CtrlRaceBase::SetPanePosition +807e2a60 CtrlRaceBase::setPausingPhase +807e2b04 CtrlRaceBase::IsInactive +807e2b18 CtrlRaceBase::HasStarted +807e2b34 CtrlRaceBase::UpdatePausePosition +807e2e3c CtrlRaceBase::InitSelf +807e2f4c CtrlRaceBase::GetPlayerId +807e3040 CtrlRaceBase::GetRuntimeTypeInfo +807e304c 0x807e304c +807e3060 CtrlRaceBattleAddPoint::GetClassName +807e306c CtrlRaceBattleAddPoint::Load +807e3100 CtrlRaceBattleAddPoint::InitSelf +807e31e0 CtrlRaceBattleAddPoint::OnUpdate +807e34dc CtrlRaceBattlePoint::GetClassName +807e34ec CtrlRaceBattlePoint::SetPanePosition +807e36b0 0x807e36b0 +807e3700 CtrlRaceBattlePoint::SetPositionAnim +807e37ec CtrlRaceBattlePoint::Init +807e3888 CtrlRaceBattlePoint::OnUpdate +807e3944 CtrlRaceBattlePoint::Load +807e39ac CtrlRaceBattleTotalPoint::GetClassName +807e39bc CtrlRaceBattleTotalPoint::Init +807e3ab8 CtrlRaceBattleTotalPoint::OnUpdate +807e413c CtrlRaceBattleTotalPoint::Load +807e42d8 CtrlRaceBattleTotalPoint::__dt +807e4334 CtrlRaceBattleTotalPoint::GetRuntimeTypeInfo +807e4340 CtrlRaceBattlePoint::__dt +807e439c CtrlRaceBattlePoint::GetRuntimeTypeInfo +807e43a8 CtrlRaceBattleAddPoint::GetRuntimeTypeInfo +807e43b4 CtrlRaceBattleAddPoint::__dt +807e4410 CtrlRaceBattlePoint_cpp_sinit_ +807e44ec CtrlRaceCount::GetClassName +807e44f8 CtrlRaceCount::Load +807e45a8 CtrlRaceCount::Init +807e45f4 CtrlRaceCount::OnUpdate +807e4638 CtrlRaceCount::IsFadingIn +807e4670 CtrlRaceCount::FadeIn +807e46a8 CtrlRaceCount::__dt +807e4704 CtrlRaceGhostDiffTime::GetRuntimeTypeInfo +807e4710 CtrlRaceGhostDiffTime_cpp_sinit +807e4724 CtrlRaceItemWindow::GetClassName +807e4730 CtrlRaceItemWindow::Init +807e4afc CtrlRaceItemWindow::IsInactive +807e4bc4 CtrlRaceItemWindow::HasStarted +807e4c54 CtrlRaceItemWindow::OnUpdate +807e51b8 CtrlRaceItemWindow::Load +807e5220 CtrlRaceItemWindow::AnimateItemIcon +807e5350 CtrlRaceItemWindow::__dt +807e53ac CtrlRaceItemWindow::GetRuntimeTypeInfo +807e53b8 CtrlRaceItemWindow_cpp_sinit_ +807e53cc CtrlRaceLap::GetClassName +807e53d8 CtrlRaceLap::Init +807e5500 CtrlRaceLap::OnUpdate +807e55c0 CtrlRaceLap::Load +807e566c CtrlRaceLap::__dt +807e56c8 CtrlRaceLap::GetRuntimeTypeInfo +807e56d4 CtrlRaceLap_cpp_sinit_ +807e56e4 CtrlRaceNameBalloon:GetClassName +807e56f0 CtrlRaceNameBalloon::Load +807e58a0 CtrlRaceNameBalloon::InitSelf +807e5a1c CtrlRaceNameBalloon::UpdateInfo +807e60c0 CtrlRaceNameBalloon::OnUpdate +807e6708 0x807e6708 +807e68ac 0x807e68ac +807e6970 0x807e6970 +807e6a6c CtrlRaceNameBalloon::UpdatePosition +807e6d04 RaceBalloons::Update +807e7564 0x807e7564 +807e75c8 0x807e75c8 +807e760c RaceBalloons::AddNameBalloon +807e7628 RaceBalloons::AddItemBalloon +807e7630 RaceBalloons::__ct +807e771c RaceBalloons::Init +807e777c 0x807e777c +807e778c RaceBalloons::OnItemObjTargeting +807e78fc 0x807e78fc +807e7918 CtrlRaceItemBalloon::GetClassName +807e7928 CtrlRaceItemBalloon::Load +807e7af0 CtrlRaceItemBalloon::InitSelf +807e7c94 CtrlRaceItemBalloon::OnUpdate +807e854c 0x807e854c +807e865c 0x807e865c +807e8ec4 CtrlRaceItemBalloon::UpdateIcon +807e9064 CtrlRaceItemBalloon::UpdatePositionForPlayer +807e9740 0x807e9740 +807e9f28 0x807e9f28 +807ea058 0x807ea058 +807ea098 0x807ea098 +807ea194 CtrlRaceItemBalloon::__dt +807ea1ec CtrlRaceItemBalloon::GetRuntimeTypeInfo +807ea1f8 CtrlRaceNameBalloon::__dt +807ea250 CtrlRaceNameBalloon::GetRuntimeTypeInfo +807ea25c 0x807ea25c +807ea2c8 CtrlRaceRankNum::GetClassName +807ea2d4 CtrlRaceRankNum::Init +807ea3e0 CtrlRaceRankNum::OnUpdate +807ea58c CtrlRaceRankNum::Load +807ea718 CtrlRaceRankNum::IsInactive +807ea7b8 CtrlRaceRankNum::__dt +807ea814 CtrlRaceRankNum::GetRuntimeTypeInfo +807ea820 CtrlRaceRankNum_cpp_sinit_ +807ea834 CtrlRaceResult::GetClassName +807ea840 CtrlRaceResult::Load +807ea9a4 0x807ea9a4 +807eabac 0x807eabac +807eaccc CtrlRaceResult::FillName +807eae18 0x807eae18 +807eae24 0x807eae24 +807eb0ac CtrlRaceResult::FillScore +807eb174 0x807eb174 +807eb334 CtrlRaceResult::FillFinishTime +807eb424 CtrlRaceResult::Init +807eb428 CtrlRaceResult::OnUpdate +807eb6fc CtrlRaceResult::807f5d24 +807eb804 0x807eb804 +807eb8f8 CtrlRaceResult::GetBRCTRName +807eb974 CtrlRaceResult::CanEnd +807eb9c4 CtrlRaceResult::Fill +807ebe68 CtrlRaceResult::__dt +807ebec0 CtrlRaceResult::GetRuntimeTypeInfo +807ebecc CtrlRaceResult_cpp_sinit_ +807ebee8 CtrlRaceResultTeam::GetClassName +807ebef4 CtrlRaceResultTeam::Load +807ec3bc CtrlRaceResultTeam::InitSelf +807ec990 CtrlRaceResultTeam::OnUpdate +807ecbfc CtrlRaceResultTeam::IsResultAnimDone +807ecd98 CtrlRaceResultTeam::ComparePlayers +807ece30 CtrlResultAddPoint::GetClassName +807ece40 CtrlResultAddPoint::Load +807ecf68 CtrlResultAddPoint::InitSelf +807ecfbc CtrlResultAddPoint::OnUpdate +807ecfd8 0x807ecfd8 +807ed02c CtrlResultAddPoint::GetRuntimeTypeInfo +807ed038 CtrlRaceResultTeam::GetRuntimeTypeInfo +807ed044 CtrlResultAddPoint::__dt +807ed0a0 CtrlRaceResultTeam_cpp_sinit_ +807ed0c4 CtrlRaceTime::GetClassName +807ed0d0 CtrlRaceTime::__ct +807ed16c CtrlRaceTime::InitSelf +807ed364 CtrlRaceTime::GetPlayerMaxLap +807ed380 CtrlRaceTime::GetPlayerId +807ed3b4 CtrlRaceTime::GetRacedata +807ed3c0 CtrlRaceTime::OnUpdate +807ed76c CtrlRaceTime::GetParentPageId +807ed774 CtrlRaceTime::GetParentPage +807ed780 CtrlRaceTime::IsPaused +807ed788 CtrlRaceTime::GetCurSection +807ed798 CtrlRaceTime::GetSectionId +807ed7ac CtrlRaceTime::FillTimerGlobal +807ed7bc CtrlRaceTime::HasPlayerFinished +807ed7dc CtrlRaceTime::FillLapSplitTimer +807ed7f4 CtrlRaceTime::IsBattle +807ed820 CtrlRaceTime::CheckTimer +807ed860 CtrlRaceTime::IsTimerInvalid +807ed880 CtrlRaceTime::ResetTimer +807ed8a4 CtrlRaceTime::IsOnlineVS +807ed8c4 CtrlRaceTime::IsModeFlag4 +807ed8d0 CtrlRaceTime::IsPlayerLast +807ed8f0 CtrlRaceTime::FillFinishTimeTimer +807ed92c CtrlRaceTime::Load +807ed9c0 CtrlRaceTime::SetTimer +807edc68 CtrlRaceTime::SetPositionAnim +807edd40 CtrlRaceTime::DisableFlashingAnimation +807edd78 CtrlRaceTime::EnableFlashingAnimation +807eddb0 CtrlRaceTime::Func_0x5c +807eddb8 CtrlRaceTime::Func_0x58 +807eddc0 CtrlRaceTime::OnDefocus +807edde8 CtrlRaceTime::OnFocus +807ede0c 0x807ede0c +807ede68 0x807ede68 +807ede74 0x807ede74 +807ede88 0x807ede88 +807edf58 0x807edf58 +807edf98 Objects::Aurora::__ct +807ee004 Objects::Aurora::OnStart +807ee0c4 Objects::Aurora::Update +807ee350 0x807ee350 +807ee43c 0x807ee43c +807ee4a0 0x807ee4a0 +807ee77c Objects::Aurora::CalcOtherEntityDistance +807ee7dc Objects::Aurora::UpdateOtherEntityPosWithRot +807ee960 Objects::Aurora::vf_0x11c +807ee968 Objects::Aurora::vf_0x108 +807ee974 Objects::Aurora::AreItemsAllowed +807ee97c Objects::Aurora::IsCollidingNoTerrainInfo +807ee980 Objects::Aurora::IsCollidingAddEntryNoTerrainInfo +807ee984 Objects::Aurora::vf_0xfc +807ee988 Objects::Aurora::IsCollidingAddEntry +807ee98c Objects::Aurora::IsCollidingNoTerrainInfoNoTriangleCheck(no radius) +807ee99c Objects::Aurora::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck(no radius) +807ee9ac Objects::Aurora::IsColliding(no radius) +807ee9bc Objects::Aurora::IsCollidingNoTriangleCheck(no radius) +807ee9cc Objects::Aurora::IsCollidingNoTerrainInfoNoTriangleCheck +807ee9d0 Objects::Aurora::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +807ee9d4 Objects::Aurora::IsColliding +807ee9d8 Objects::Aurora::IsCollidingNoTriangleCheck +807ee9dc Objects::Aurora::vf_0xc0 +807ee9ec Objects::Aurora::vf_0xc4 +807ee9fc Objects::Aurora::vf_0xc8 +807eea0c Objects::Aurora::vf_0xc8 +807eea1c Objects::Aurora::GetCollisionDiameter +807eea30 Objects::Aurora::LoadAnimations +807eeabc Objects::Aurora::vf_0xb4 +807eeac0 Objects::Aurora::UpdateCollision +807eeac4 Objects::Aurora::LoadCollision +807eeac8 Objects::Aurora::GetPropertiesBitfield +807eead0 Objects::Aurora::__dt +807eeb10 Objects::Aurora::IsCollidingNoTerrainInfoImpl +807eecf0 Objects::Aurora::IsCollidingAddEntryNoTerrainInfoImpl +807eef00 0x807eef00 +807ef2ac Objects::Aurora::IsCollidingAddEntryImpl +807ef688 0x807ef688 +807ef6d4 Objects::Belt::vf_0x120 +807ef9b8 Objects::BeltEasy::__ct +807efa2c Objects::Belt::__dt +807efa6c Objects::BeltEasy::vf_0x124 +807efb08 Objects::BeltEasy::vf_0x128 +807efba4 Objects::BeltCrossing::__ct +807efc18 Objects::BeltCrossing::vf_0x124 +807efcb4 Objects::BeltCrossing::vf_0x128 +807efd4c Objects::BeltCurveA::__ct +807efe14 Objects::BeltCurveA::vf_0x124 +807f00e4 Objects::BeltCurveA::vf_0x128 +807f013c Objects::BeltCurveA::LoadModels +807f0228 Objects::BeltCurveA::LoadAnimations +807f0528 Objects::BeltCurveA::UpdateModelMatrix +807f05ec Objects::BeltCurveA::OnStart +807f05f4 Objects::BeltCurveA::Update +807f07cc Objects::BeltCurveA::vf_0x12c +807f09e0 0x807f09e0 +807f0aac 0x807f0aac +807f0ae4 Objects::Belt::vf_0x11c +807f0aec Objects::Belt::UpdateOtherEntityPosWithRot +807f0af0 Objects::Belt::UpdateOtherEntityPos +807f0af4 Objects::Belt::CalcOtherEntityDistance +807f0af8 Objects::Belt::vf_0x108 +807f0b04 Objects::Belt::AreItemsAllowed +807f0b0c Objects::Belt::IsCollidingNoTerrainInfo +807f0b14 Objects::Belt::IsCollidingAddEntryNoTerrainInfo +807f0b1c Objects::Belt::vf_0xfc +807f0b24 Objects::Belt::IsCollidingAddEntry +807f0b34 Objects::Belt::IsCollidingNoTerrainInfoNoTriangleCheck(no radius) +807f0b3c Objects::Belt::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck(no radius) +807f0b44 Objects::Belt::IsColliding(no radius) +807f0b4c Objects::Belt::IsCollidingAddEntryNoTriangleCheck(no radius) +807f0b68 Objects::Belt::IsCollidingNoTerrainInfoNoTriangleCheck +807f0b70 Objects::Belt::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +807f0b78 Objects::Belt::IsColliding +807f0b80 Objects::Belt::vf_0xc0 +807f0b90 0x807f0b90 +807f0b98 Objects::Belt::vf_0xc4 +807f0ba0 Objects::Belt::vf_0xc8 +807f0ba8 Objects::Belt::vf_0xcc +807f0bc4 Objects::Belt::GetCollisionDiameter +807f0bd0 Objects::Belt::vf_0xb4 +807f0bd4 Objects::Belt::UpdateCollision +807f0bd8 Objects::Belt::LoadCollision +807f0bdc Objects::Belt::GetPropertiesBitfield +807f0be4 Objects::BeltCurveA::SetObjInfoCalcBit +807f0bf4 Objects::BeltCurveA::GetScnObjDrawOptionsIdx +807f0bfc Objects::BeltCurveA::__dt +807f0c3c Objects::Belt::SetObjInfoCalcBit +807f0c4c Objects::Belt::vf_0x12c +807f0ca0 Objects::Belt::LoadAnimations +807f0ce0 Objects::BeltCrossing::GetScnObjDrawOptionsIdx +807f0ce8 Objects::BeltCrossing::__dt +807f0d28 Objects::BeltEasy::GetScnObjDrawOptionsIdx +807f0d30 Objects::BeltEasy::__dt +807f0d70 Objects::Belt::GetScnObjDrawOptionsIdx +807f0d78 0x807f0d78 +807f0f24 0x807f0f24 +807f1090 0x807f1090 +807f129c 0x807f129c +807f13f4 0x807f13f4 +807f141c 0x807f141c +807f147c 0x807f147c +807f170c 0x807f170c +807f17a4 0x807f17a4 +807f193c 0x807f193c +807f196c 0x807f196c +807f1974 0x807f1974 +807f1a28 0x807f1a28 +807f1a30 0x807f1a30 +807f1a70 0x807f1a70 +807f1a98 Objects::Crane::__ct +807f1c2c Objects::Crane::Update +807f1e98 ObjectExternKCL::vf_0x11c +807f1ea0 ObjectExternKCL::CalcOtherEntityDistance +807f1f00 ObjectExternKCL::GetTransformationMatrix +807f1f30 Objects::Crane::GetPeriod +807f1f60 Objects::Crane::GetPropertiesBitfield +807f1f68 Objects::Crane::__dt +807f1fa8 0x807f1fa8 +807f225c 0x807f225c +807f2588 0x807f2588 +807f2c60 0x807f2c60 +807f2d84 0x807f2d84 +807f2e98 0x807f2e98 +807f2f44 0x807f2f44 +807f3444 0x807f3444 +807f3654 0x807f3654 +807f3934 0x807f3934 +807f3c14 0x807f3c14 +807f3e80 0x807f3e80 +807f403c 0x807f403c +807f4c2c 0x807f4c2c +807f4e34 0x807f4e34 +807f50f8 0x807f50f8 +807f5100 0x807f5100 +807f5188 0x807f5188 +807f5194 0x807f5194 +807f51a0 0x807f51a0 +807f51a8 0x807f51a8 +807f51e8 0x807f51e8 +807f51f0 0x807f51f0 +807f51f4 0x807f51f4 +807f51f8 0x807f51f8 +807f5208 0x807f5208 +807f520c 0x807f520c +807f5218 0x807f5218 +807f5220 0x807f5220 +807f5228 0x807f5228 +807f5368 0x807f5368 +807f54a8 0x807f54a8 +807f55e8 0x807f55e8 +807f55f8 0x807f55f8 +807f56ec 0x807f56ec +807f57e0 0x807f57e0 +807f58d4 0x807f58d4 +807f59c8 0x807f59c8 +807f5b08 0x807f5b08 +807f5c48 0x807f5c48 +807f5d88 0x807f5d88 +807f5d98 0x807f5d98 +807f5e8c 0x807f5e8c +807f5f80 0x807f5f80 +807f6074 0x807f6074 +807f6168 0x807f6168 +807f6174 0x807f6174 +807f6178 0x807f6178 +807f6180 0x807f6180 +807f6188 0x807f6188 +807f61c8 Objects::bblock::__ct +807f6230 Objects::VolcanoPiece::__dt +807f6270 Objects::bblock::LoadModels +807f63f4 Objects::VolcanoPiece::GetSubFileName +807f63fc Objects::bblock::OnStart +807f6454 Objects::bblock::UpdateModelMatrix +807f64dc Objects::bblock::LoadAnimations +807f6590 Objects::bblock::LoadCollision +807f6848 Objects::bblock::GetBRRESName +807f6854 Objects::bblock::SetCollisionType +807f68a0 Objects::bblock::Init_eAnm +807f6948 Objects::VolcanoPiece::UpdateKCL +807f6a30 Objects::VolcanoPiece::SetCollisionType +807f6a34 Objects::VolcanoPiece::IsCollidingNoTerrainInfo +807f6bb8 Objects::VolcanoPiece::IsCollidingAddEntryNoTerrainInfo +807f6d3c Objects::VolcanoPiece::vf_0xfc +807f6ec0 Objects::VolcanoPiece::IsCollidingAddEntry +807f6ed0 Objects::VolcanoPiece::IsCollidingNoTerrainInfoNoTriangleCheck(no radius) +807f7018 Objects::VolcanoPiece::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck(no radius) +807f7160 Objects::VolcanoPiece::IsColliding(no radius) +807f72a8 Objects::VolcanoPiece::IsCollidingAddEntryNoTriangleCheck(no radius) +807f73f0 Objects::VolcanoPiece::IsCollidingNoTerrainInfoNoTriangleCheck +807f7574 Objects::VolcanoPiece::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +807f76f8 Objects::VolcanoPiece::IsColliding +807f787c Objects::VolcanoPiece::IsCollidingAddEntryNoTriangleCheck +807f788c Objects::VolcanoPiece::vf_0xc0 +807f79d4 Objects::VolcanoPiece::vf_0xc4 +807f7b1c Objects::VolcanoPiece::vf_0xc8 +807f7c64 Objects::VolcanoPiece::vf_0xcc +807f7dac Objects::VolcanoPiece::UpdateDiffPosVector +807f7de4 Objects::VolcanoPiece::GetTransformationMatrix +807f7dfc Objects::VolcanoPiece::GetPropertiesBitfield +807f7e04 Objects::bblock::UpdateModelScale +807f7e94 0x807f7e94 +807f7ed4 Objects::Kinoko::__ct +807f80a4 Objects::Kinoko::OnStart +807f80e4 Objects::Kinoko::Update +807f8208 Objects::Kinoko_ud::__ct +807f82cc Objects::Kinoko::__dt +807f830c Objects::Kinoko_ud::UpdateSpecific +807f8434 Objects::Kinoko_bend::__ct +807f8550 Objects::Kinoko_bend::UpdateSpecific +807f863c Objects::Kinoko::vf_0xb4 +807f8640 Objects::Kinoko::SetYScale +807f8644 Objects::Kinoko::GetSubFileName +807f8664 Objects::Kinoko::GetPropertiesBitfield +807f866c Objects::Kinoko_bend::__dt +807f86ac 0x807f86ac +807f86b0 Objects::Kinoko_ud::SetYScale +807f86b4 Objects::Kinoko_ud::GetSubFileName +807f86d4 Objects::Kinoko_ud::__dt +807f8714 Objects::Kinoko_kuki::vf_0xec +807f8718 Objects::Kinoko_kuki::vf_0xf0 +807f871c Objects::Kinoko_kuki::GetSubFileName +807f873c Objects::Kinoko_kuki::UpdateModelScale +807f8740 Objects::Kinoko_kuki::GetPropertiesBitfield +807f8748 Objects::Kinoko_kuki::__dt +807f8788 ObjAmi_construct +807f87f8 0x807f87f8 +807f88ac 0x807f88ac +807f8ad8 0x807f8ad8 +807f8bc0 0x807f8bc0 +807f8e30 0x807f8e30 +807f8e74 0x807f8e74 +807f8ed4 0x807f8ed4 +807f903c 0x807f903c +807f9044 0x807f9044 +807f9050 0x807f9050 +807f9058 0x807f9058 +807f905c 0x807f905c +807f9060 0x807f9060 +807f9064 0x807f9064 +807f9068 0x807f9068 +807f9078 0x807f9078 +807f9088 0x807f9088 +807f9098 0x807f9098 +807f90a8 0x807f90a8 +807f90ac 0x807f90ac +807f90b0 0x807f90b0 +807f90b4 0x807f90b4 +807f90b8 0x807f90b8 +807f90c8 0x807f90c8 +807f90d8 0x807f90d8 +807f90e8 0x807f90e8 +807f90f8 0x807f90f8 +807f9104 0x807f9104 +807f9108 0x807f9108 +807f910c 0x807f910c +807f9110 0x807f9110 +807f9118 0x807f9118 +807f9158 0x807f9158 +807f9344 0x807f9344 +807f9560 0x807f9560 +807f9918 0x807f9918 +807f9d00 0x807f9d00 +807fa0b8 obj_obakeblockSFC::__ct +807fa224 0x807fa224 +807fa2f8 0x807fa2f8 +807fa544 0x807fa544 +807fa558 0x807fa558 +807fab08 0x807fab08 +807fac44 0x807fac44 +807fada0 Object::GetCollisionDiameter +807fadac 0x807fadac +807fadb4 0x807fadb4 +807fadb8 0x807fadb8 +807fadbc 0x807fadbc +807fadc0 0x807fadc0 +807fadc4 0x807fadc4 +807fadc8 0x807fadc8 +807fadcc 0x807fadcc +807fadd0 0x807fadd0 +807fadd4 0x807fadd4 +807fade4 0x807fade4 +807fadf4 0x807fadf4 +807fae04 0x807fae04 +807fae14 0x807fae14 +807fae18 0x807fae18 +807fae1c 0x807fae1c +807fae20 0x807fae20 +807fae24 0x807fae24 +807fae34 0x807fae34 +807fae44 0x807fae44 +807fae54 0x807fae54 +807fae64 0x807fae64 +807fae70 0x807fae70 +807fae74 0x807fae74 +807fae78 0x807fae78 +807fae7c 0x807fae7c +807fae84 0x807fae84 +807faec4 0x807faec4 +807fb3f4 ObjectCollisionPolyhedra::SetRadius +807fb3fc 0x807fb3fc +807fb960 0x807fb960 +807fc10c 0x807fc10c +807fc8dc 0x807fc8dc +807fc950 0x807fc950 +807fc988 0x807fc988 +807fc994 0x807fc994 +807fc9a0 0x807fc9a0 +807fc9ac 0x807fc9ac +807fca10 0x807fca10 +807fca74 0x807fca74 +807fcae8 0x807fcae8 +807fcd54 0x807fcd54 +807fceb0 obj_quicksand::__ct +807fd0c8 0x807fd0c8 +807fd62c 0x807fd62c +807fdd8c 0x807fdd8c +807fe02c 0x807fe02c +807fe21c 0x807fe21c +807fe820 0x807fe820 +807fee24 0x807fee24 +807ff128 0x807ff128 +807ff150 0x807ff150 +807ff538 0x807ff538 +807ff540 0x807ff540 +807ff54c 0x807ff54c +807ff554 0x807ff554 +807ff558 0x807ff558 +807ff55c 0x807ff55c +807ff560 0x807ff560 +807ff564 0x807ff564 +807ff574 0x807ff574 +807ff584 0x807ff584 +807ff594 0x807ff594 +807ff5a4 0x807ff5a4 +807ff5a8 0x807ff5a8 +807ff5ac 0x807ff5ac +807ff5b0 0x807ff5b0 +807ff5b4 0x807ff5b4 +807ff5c4 0x807ff5c4 +807ff5d4 0x807ff5d4 +807ff5e4 0x807ff5e4 +807ff5f4 0x807ff5f4 +807ff608 0x807ff608 +807ff670 0x807ff670 +807ff67c 0x807ff67c +807ff688 0x807ff688 +807ff68c 0x807ff68c +807ff690 0x807ff690 +807ff694 0x807ff694 +807ff69c 0x807ff69c +807ff6dc 0x807ff6dc +807ff6e8 0x807ff6e8 +807ff6f4 0x807ff6f4 +807ff6fc 0x807ff6fc +807ff704 0x807ff704 +807ff760 0x807ff760 +807ffb9c 0x807ffb9c +80800004 0x80800004 +80800700 0x80800700 +80800e28 Objects::TwistedWay::__ct +80800e94 Objects::TwistedWay::OnStart +80800f50 Objects::TwistedWay::Update +80801194 0x80801194 +80801274 0x80801274 +80801384 0x80801384 +808014c4 0x808014c4 +8080167c Objects::TwistedWay::CalcOtherEntityDistance +8080182c Objects::TwistedWay::UpdateOtherEntityPosWithRot +808019fc 0x808019fc +80801a90 Objects::TwistedWay::vf_0x11c +80801a98 Objects::TwistedWay::vf_0x108 +80801aa4 Objects::TwistedWay::AreItemsAllowed +80801aac Objects::TwistedWay::IsCollidingNoTerrainInfo +80801ab0 Objects::TwistedWay::IsCollidingAddEntryNoTerrainInfo +80801ab4 Objects::TwistedWay::vf_0xfc +80801ab8 Objects::TwistedWay::IsCollidingAddEntry +80801abc Objects::TwistedWay::IsCollidingNoTerrainInfoNoTriangleCheck(no radius) +80801acc Objects::TwistedWay::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck(no radius) +80801adc Objects::TwistedWay::IsColliding(no radius) +80801aec Objects::TwistedWay::IsCollidingAddEntryNoTriangleCheck(no radius) +80801afc Objects::TwistedWay::IsCollidingNoTerrainInfoNoTriangleCheck +80801b00 Objects::TwistedWay::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +80801b04 Objects::TwistedWay::IsColliding +80801b08 Objects::TwistedWay::IsCollidingAddEntryNoTriangleCheck +80801b0c Objects::TwistedWay::vf_0xc0 +80801b1c Objects::TwistedWay::vf_0xc4 +80801b2c Objects::TwistedWay::vf_0xc8 +80801b3c Objects::TwistedWay::vf_0xcc +80801b4c Objects::TwistedWay::GetCollisionDiameter +80801b54 Objects::TwistedWay::LoadAnimations +80801b58 Objects::TwistedWay::vf_0xb4 +80801b5c Objects::TwistedWay::UpdateCollision +80801b60 Objects::TwistedWay::LoadCollision +80801b64 Objects::TwistedWay::GetPropertiesBitfield +80801b6c Objects::TwistedWay::__dt +80801bac 0x80801bac +808020fc 0x808020fc +80802698 0x80802698 +80802fb8 Objects::TwistedWay::IsCollidingImpl +80803924 obj_venice_hasi::__ct +80803b00 0x80803b00 +80803c34 0x80803c34 +80803d38 0x80803d38 +8080418c 0x8080418c +808043f0 0x808043f0 +8080455c 0x8080455c +80804620 0x80804620 +808047cc 0x808047cc +80804934 0x80804934 +80804ae8 0x80804ae8 +80804af0 0x80804af0 +80804af4 0x80804af4 +80804af8 0x80804af8 +80804b04 0x80804b04 +80804b0c 0x80804b0c +80804b18 0x80804b18 +80804b28 0x80804b28 +80804b30 0x80804b30 +80804b38 0x80804b38 +80804b78 ObjSaku_construct +80804c20 0x80804c20 +80804eb4 0x80804eb4 +80804ff4 0x80804ff4 +80804ffc 0x80804ffc +8080503c Objects::VolcanoPiece::__ct +808051c0 Objects::VolcanoPiece::LoadCollision +80805588 Objects::VolcanoPiece::UpdateCollisionPosition +808058c8 Objects::VolcanoPiece::SetYScale +80805a08 Objects::VolcanoPiece::GetTransformationMatrixImpl +80806220 0x80806220 +8080627c 0x8080627c +80806368 0x80806368 +80806650 Objects::VolcanoPiece::Init_eAnm +80806654 Objects::VolcanoPiece::Update +80806bfc Objects::VolcanoPiece::IsCollidingAddEntryNoTriangleCheckImpl +80806ff4 Objects::VolcanoPiece::IsCollidingImpl +808073ec Objects::VolcanoRock1::__ct +808075c4 Objects::VolcanoRock1::Update +80807668 Objects::VolcanoRock1::CalcTranslation +80807824 Objects::VolcanoRock1::GetPeriod +80807860 Objects::VolcanoRock1::GetTransformationMatrix +808078bc Objects::VolcanoRock1::GetSubFileName +808078dc Objects::VolcanoRock1::GetPropertiesBitfield +808078e4 Objects::VolcanoRock1::__dt +80807924 ObjectKCL::__ct +80807968 ObjectKCL::__ct(Vec3s, objId) +808079ac ObjectKCL::__ct(Vec3s, name) +808079f0 ObjectKCL::Init +80807ab0 ObjectKCL::RegisterEntity +80807b24 ObjectKCL::UpdateModel +80807bd4 ObjectExternKCL::__ct +80807c1c 0x80807c1c +80807c64 0x80807c64 +80807cac ObjectExternKCL::LoadCollision +80807da0 ObjectExternKCL::InitCollision +80807fc0 ObjectExternKCL::UpdateCollisionPosition +8080817c ObjectExternKCL::SetYScale +80808208 ObjectExternKCL::IsCollidingAddEntryNoTriangleCheckImpl +808083c0 ObjectExternKCL::IsCollidingImpl +80808578 ObjectsKCLMgr::__ct +808085d4 ObjectsKCLMgr::__dt +8080867c ObjectsKCLMgr::CreateInstance +80808704 ObjectsKCLMgr::DestroyInstance +80808754 ObjectsKCLMgr::Init +808087fc 0x808087fc +8080886c ObjectsKCLMgr::Update +8080891c ObjectsKCLMgr::AddObject +80808a20 ObjectsKCLMgr::UpdateKCL +80808ac4 0x80808ac4 +80808b94 0x80808b94 +80808c64 0x80808c64 +80808da8 0x80808da8 +80808eec ObjectsKCLMgr::IsCollidingNoTerrainInfoNoTriangleCheck +80808fc4 ObjectsKCLMgr::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +8080909c ObjectsKCLMgr::IsColliding +808091f4 ObjectsKCLMgr::IsCollidingAddEntryNoTriangleCheck +8080934c 0x8080934c +8080943c 0x8080943c +8080952c 0x8080952c +80809690 0x80809690 +808097f4 ObjectsKCLMgr::IsCollidingNoTerrainInfo +80809908 ObjectsKCLMgr::IsCollidingAddEntryNoTerrainInfo +80809a1c 0x80809a1c +80809bac ObjectsKCLMgr::IsCollidingAddEntry +80809d3c 0x80809d3c +80809dc4 GetKartWeightClass +80809f90 GetCharacterWeightClass +8080a104 0x8080a104 +8080a148 CharacterIdToKartIdByIdx +8080a1c4 0x8080a1c4 +8080a200 0x8080a200 +8080a208 IsKartUnlocked +8080a274 IsCharacterUnlocked +8080a27c 0x8080a27c +8080a2b0 0x8080a2b0 +8080a2e4 KartObjectCollision::Init +8080a34c KartObjectCollision::Init_switch +8080a350 KartObjectCollision::Init_case1 +8080a3c0 KartObjectCollision::Init_case0 +8080a40c KartObjectCollision::Init_case2 +8080a480 KartObjectCollision::Init_case3 +8080a4f0 KartObjectCollision::Init_case6 +8080a550 KartObjectCollision::Init_case9 +8080a5ac KartObjectCollision::Init_casec +8080a628 KartObjectCollision::Init_casef +8080a684 KartObjectCollision::Init_case4 +8080a704 KartObjectCollision::Init_case7 +8080a778 KartObjectCollision::Init_casea +8080a7e0 KartObjectCollision::Init_cased +8080a864 KartObjectCollision::Init_case10 +8080a8e4 KartObjectCollision::Init_case5 +8080a96c KartObjectCollision::Init_case8 +8080a9ec KartObjectCollision::Init_caseb +8080aa6c KartObjectCollision::Init_casee +8080aaf0 KartObjectCollision::Init_case11 +8080ab90 KartObjectCollision::Init_case12 +8080abec KartObjectCollision::Init_case13 +8080ac48 KartObjectCollision::Init_case14 +8080aca8 KartObjectCollision::Init_case15 +8080ad08 KartObjectCollision::Init_case18 +8080ad68 KartObjectCollision::Init_case1b +8080adc4 KartObjectCollision::Init_case1e +8080ae20 KartObjectCollision::Init_case21 +8080ae80 KartObjectCollision::Init_case16 +8080aee0 KartObjectCollision::Init_case19 +8080af3c KartObjectCollision::Init_case1c +8080af98 KartObjectCollision::Init_case1f +8080aff8 KartObjectCollision::Init_case22 +8080b058 KartObjectCollision::Init_case17 +8080b0b8 KartObjectCollision::Init_case1a +8080b130 KartObjectCollision::Init_case1d +8080b190 KartObjectCollision::Init_case20 +8080b1f0 KartObjectCollision::Init_case23 +8080b320 KartObjectCollision::__ct +8080b338 KartObjectCollision::__dt +8080b3c4 KartObjectCollision::Update +8080b4a8 ObjectCollisionPolyhedra::GetDefaultDiameter +8080b4b0 0x8080b4b0 +8080b4d8 ObjectCollidable::__ct(GOBJ) +8080b514 ObjectCollidable::::__ct(Vec3s, objId) +8080b550 ObjectCollidable::::__ct(Vec3s, name) +8080b58c ObjectCollidable::Init +8080b65c ObjectCollidable::RegisterManagedObject +8080b66c ObjectCollidable::RegisterEntity +8080b710 ObjectCollidable::LoadCollision +8080ba34 ObjectCollidable::OnNormalCollision +8080bac4 ObjectCollidable::OnWallCollision +8080bb58 ObjectCollidable::BeforeKartCollision +8080bc64 ObjectCollidable::BeforeItemCollision +8080bcb4 ObjectCollidable::UpdateCollision +8080bd14 Object::__ct +8080bea8 Object::__ct(Vec3s, objId) +8080bff0 Object::__ct(Vec3s, name) +8080c154 Object::OnStart +8080c1d8 Object::LoadModels +8080c1ec Object::LoadModels(r4) +8080c1fc Object::LoadGraphics +8080c84c Object::LoadSound +8080c9a4 Object::LinkSound +8080c9e8 Object::StartSoundLimited +8080ca08 Object::HoldSoundLimited +8080ca28 Object::StartNewSoundLimited +8080ca48 Object::StartSound +8080ca68 Object::HoldSound +8080ca88 Object::StopAllSound +8080caa8 Object::StopSound +8080cac8 Object::LoadShadow +8080cc18 Object::LoadAnimations +8080cd60 0x8080cd60 +8080ce6c Object::LoadRoute +8080cf7c Object::LoadAnimationsByType +8080d3a4 Object::LinkAnimations +8080d55c Object::LoadClipInfo +8080db2c Object::UpdateMatrix +8080dbac Object::ToggleVisible +8080dc24 0x8080dc24 +8080dc9c 0x8080dc9c +8080dca4 Object::UpdateModel +8080dd9c Object::CalcYAxisTransMtx +8080ddfc 0x8080ddfc +8080de60 Object::UpdateShadow +8080df88 Object::UpdateModelMatrix +8080e054 0x8080e054 +8080e2a4 Object::vf_0x88 +8080e2c4 Object::vf_0x8c +8080e2d8 Object::DisableCollision +8080e2ec Object::EnableCollision +8080e300 ObjectsMgr::CreateObject +80812e2c 0x80812e2c +80813378 ObjectsMgr::CreateAllObjects +80813f54 Objects::Kinoko_nm::GetPeriod +80813f60 Objects::Kinoko_nm::GetSubFileName +80813f80 Objects::Kinoko_nm::GetPropertiesBitfield +80813f88 Objects::Kinoko_nm::__dt +80813fc8 0x80813fc8 +80813fd8 0x80813fd8 +808140b8 0x808140b8 +808140f8 0x808140f8 +80814100 0x80814100 +80814164 0x80814164 +808141a4 0x808141a4 +808141b4 0x808141b4 +808141f4 0x808141f4 +808141fc 0x808141fc +8081423c 0x8081423c +80814244 0x80814244 +80814284 0x80814284 +808142c4 0x808142c4 +80814304 0x80814304 +80814344 0x80814344 +80814460 0x80814460 +808145d0 0x808145d0 +80814644 0x80814644 +808148f8 0x808148f8 +80814914 0x80814914 +8081492c 0x8081492c +80814a50 0x80814a50 +80814a54 0x80814a54 +80814a5c 0x80814a5c +80814a9c Objects::Itembox::__ct +80814c58 Objects::Itembox::__ct(position) +80814d4c Objects::Itembox::Update +808151a4 Objects::Itembox::OnCollision +80815430 Objects::F_Itembox::__ct +80815484 Objects::F_Itembox::OnStart +80815560 Objects::F_Itembox::Update +808156f4 Objects::S_Itembox::__ct +8081576c Objects::S_Itembox::OnStart +80815948 Objects::S_Itembox::Update +80815a70 Objects::S_Itembox::__dt +80815ab0 Objects::F_Itembox::__dt +80815af0 0x80815af0 +80815b28 Objects::Heyho2::__ct +80815be4 Objects::Heyho2::OnStart +80815c50 Objects::Heyho2::Lift::__ct +80815dc8 Objects::Heyho2::Lift::OnStart +80815f90 Objects::Heyho2::Lift::Update +80816184 Objects::Heyho2::Lift::UpdateModelMatrix +80816254 Objects::Heyho2::Rider::__ct +808163c0 Objects::Heyho2::Rider::OnStart +808164f8 Objects::Heyho2::Rider::LoadAnimations +808164fc Objects::Heyho2::Rider::Update +80816620 Objects::Heyho2::LoadRoute +80816624 Objects::Heyho2::Update +80816628 Objects::Heyho2::LoadModels +8081662c Objects::Heyho2::LoadAnimations +80816630 Objects::Heyho2::GetPropertiesBitfield +80816638 Objects::Heyho2::__dt +80816678 Objects::Heyho2::Lift::GetBRRESName +80816684 Objects::Heyho2::Lift::GetSubFileName +808166a4 Objects::Heyho2::Lift::GetPropertiesBitfield +808166ac Objects::Heyho2::Lift::vf_0xa8 +808166b4 Objects::Heyho2::Lift::__dt +808166f4 Objects::Heyho2::Rider::LoadRoute +808166f8 Objects::Heyho2::Rider::vf_0xa8 +80816700 Objects::Heyho2::Rider::GetBRRESName +8081670c Objects::Heyho2::Rider::GetSubFileName +80816758 Objects::Heyho2::Rider::GetPropertiesBitfield +80816760 0x80816760 +808167a0 ObjectsMgr::Start +80816878 ObjectsMgr::__ct +80816b40 ObjectCollisionManager::__dt +80816b80 ObjectsMgr::__dt +80816c70 ObjectsMgr::CreateInstance +80816d10 ObjectsMgr::DestroyInstance +80816d70 0x80816d70 +80816de0 ObjectsMgr::Update +80816fac 0x80816fac +80816ff0 ObjectsMgr::CheckCollision +808172a8 ObjectsMgr::HandleItemCollision +808174d8 0x808174d8 +808175d4 ObjectsMgr::AddObject +80817780 0x80817780 +8081788c ObjectsMgr::RegisterManagedObject +80817894 ObjectsMgr::GetManagedObject +808178a4 ObjectsMgr::GetManagedObjectsCount +808178c0 ObjectsMgr::GetPseaVeniceHeightDiff +808178d8 ObjectsMgr::GetPseaVeniceHeight +808178ec ObjectsMgr::GetPseaVeniceHeightMinus260 +8081790c 0x8081790c +80817918 0x80817918 +808179cc ObjectCollisionManager::GetPlayerItemState +80817a10 ObjectCollisionManager::Get_0x1c +80817a18 0x80817a18 +80817a1c 0x80817a1c +80817a20 ObjectCollisionManager::GetPosition +80817a28 GeoHitTableKartObjHolder::__dt +80817a68 GeoHitTableKartHolder::__dt +80817aa8 GeoHitTableObjHolder::__dt +80817ae8 GeoHitTableItemHolder::__dt +80817b28 Objects::MiiStatue::__ct +80817c34 0x80817c34 +80817cd4 0x80817cd4 +80817d74 0x80817d74 +80817e14 0x80817e14 +80817f04 Objects::MiiStatue::__dt +80817fcc Objects::MiiStatue::OnStart +808181d4 Objects::MiiStatue::Update +808182f8 Objects::MiiStatue::GetPropertiesBitfield +80818300 0x80818300 +808185f8 ObjFlowHolder::__ct +80818664 ObjFlowHolder::GetObjIDByName +808186e0 ObjFlowHolder::__dt +80818720 Objects::Psea::__ct +80818b20 Objects::Psea::Update +80818d70 Objects::Psea::LoadModels +80818d74 Objects::Psea::GetPropertiesBitfield +80818d7c Objects::Psea::__dt +80818dbc Objects::Psea5spc::GetScnObjDrawOptionsIdx +80818dc4 Objects::Psea5spc::GetName +80818dd0 Objects::Psea5spc::GetSubFileName +80818ddc Objects::Psea5spc::GetPropertiesBitfield +80818de4 Objects::Psea5spc::__dt +80818e24 Objects::Psea4tex::GetScnObjDrawOptionsIdx +80818e2c Objects::Psea4tex::GetName +80818e38 Objects::Psea4tex::GetSubFileName +80818e44 Objects::Psea4tex::GetPropertiesBitfield +80818e4c Objects::Psea4tex::__dt +80818e8c Objects::Psea3nami::GetScnObjDrawOptionsIdx +80818e94 Objects::Psea3nami::GetName +80818ea0 Objects::Psea3nami::GetSubFileName +80818eac Objects::Psea3nami::GetPropertiesBitfield +80818eb4 Objects::Psea3nami::__dt +80818ef4 Objects::Psea2dark::GetScnObjDrawOptionsIdx +80818efc Objects::Psea2dark::GetName +80818f08 Objects::Psea2dark::GetSubFileName +80818f14 Objects::Psea2dark::GetPropertiesBitfield +80818f1c Objects::Psea2dark::__dt +80818f5c Objects::Psea1sand::GetScnObjDrawOptionsIdx +80818f64 Objects::Psea1sand::GetName +80818f70 Objects::Psea1sand::GetSubFileName +80818f7c Objects::Psea1sand::GetPropertiesBitfield +80818f84 Objects::Psea1sand::__dt +80818fc4 Objects::Pylon01::_ct +80819150 Objects::Pylon01::GetScnObjDrawOptionsIdx +80819168 Objects::Pylon01::GetBRRESName +808191a0 Objects::Pylon01::LoadAnimations +8081924c Objects::Pylon01::OnStart +80819530 Objects::Pylon01::Update +8081a0d8 Objects::Pylon01::OnCollision +8081a4c4 Objects::Pylon01::OnItemCollision +8081a5ec 0x8081a5ec +8081a8dc 0x8081a8dc +8081a9e0 Objects::Pylon01::OnWallCollision +8081a9e4 Objects::Pylon01::GetPropertiesBitfield +8081a9ec Objects::Pylon01::__dt +8081aa2c obj_venice_nami::__ct +8081abcc 0x8081abcc +8081adc0 0x8081adc0 +8081ae74 0x8081ae74 +8081b158 obj_venice_nami_update +8081b320 0x8081b320 +8081b4f0 0x8081b4f0 +8081b584 0x8081b584 +8081b590 0x8081b590 +8081b598 0x8081b598 +8081b5a0 0x8081b5a0 +8081b5e0 0x8081b5e0 +8081b610 0x8081b610 +8081b738 GetCupNameMsgId +8081b768 getTrackBmgId +8081b804 0x8081b804 +8081b834 getArenaBmgId +8081b864 GetPositionBMGId +8081b86c getOrangeOverlayBmgId +8081b874 0x8081b874 +8081b8d4 0x8081b8d4 +8081b8d8 0x8081b8d8 +8081b8ec 0x8081b8ec +8081b91c GetMissionLevelNameMsgId +8081b938 0x8081b938 +8081b940 ObjectCollisionCuboid::__ct +8081bc00 0x8081bc00 +8081bc08 ObjectCollisionCuboid::SetPositionAndScale +8081bff4 ObjectCollisionCuboid::SetPositionAndScale(translation) +8081c3f0 0x8081c3f0 +8081c3f8 ObjectCollisionCuboid::__dt +8081c450 ObjectCollision::ProcessCollision +8081d0bc 0x8081d0bc +8081d154 0x8081d154 +8081d1ec 0x8081d1ec +8081d40c 0x8081d40c +8081d758 0x8081d758 +8081d8ec 0x8081d8ec +8081d9d4 0x8081d9d4 +8081daac 0x8081daac +8081db94 0x8081db94 +8081e03c 0x8081e03c +8081e13c 0x8081e13c +8081e170 ObjectCollisionCylinder::__ct +8081e294 ObjectCollisionCylinder::Getposition +8081e2f8 ObjectCollisionCylinder::SetPositionAndScale +8081e43c ObjectCollisionCylinder::SetPositionAndScale(translation) +8081e598 0x8081e598 +8081e5a0 ObjectCollisionCylinder::GetRadius +8081e5a8 ObjectCollisionCylinder::__dt +8081e5e8 ObjectCollisionPolyhedra::__ct +8081e6b0 ObjectCollisionPolyhedra::__dt +8081e730 ObjectCollisionPolyhedra::GetPosition +8081e7d8 ObjectCollisionPolyhedra::SetPositionAndScale +8081e8cc ObjectCollisionPolyhedra::SetPositionAndScale(translation) +8081e9d8 ObjectCollisionSphere::__ct +8081ea28 ObjectCollisionSphere::GetPosition +8081eaa0 ObjectCollisionSphere::SetPositionAndScale +8081eb58 ObjectCollisionSphere::SetPositionAndScale(translation) +8081ec5c ObjectCollisionSphere::GetRadius +8081ec64 ObjectCollisionSphere::__dt +8081eca4 Pages::Menu::OnInit +8081f26c Pages::Menu::CreateExternalControl +8081f274 Pages::Menu::SetButtonHandlers +8081f278 Pages::Menu::OnActivate +8081f3e8 Pages::Menu::GetTextInfo +8081f3f0 Pages::Menu::OnControlsInitialized +8081f634 Pages::Menu::SelectButton +8081f6f4 Pages::Menu::OnExternalButtonSelect +8081f6f8 Pages::Menu::SelectExternObject +8081f724 Pages::Menu::LoadNextPageWithDelayById +8081f828 Pages::Menu::LoadNextPageById +8081f938 Pages::Menu::LoadPrevPageWithDelayById +8081fa3c Pages::Menu::LoadPrevPageById +8081fb4c Pages::Menu::LoadPrevPageWithDelay +8081fc54 Pages::Menu::LoadPrevPage +8081fd64 Pages::Menu::ChangeSectionWithDelayById +8081fe24 Pages::Menu::AddPageLayer +8081fe4c Pages::Menu::OnResume +8081ff48 Pages::Menu::ChangeSectionById +8082000c Pages::Menu::ForceChangeSectionWithDelayById +80820028 Pages::Menu::ForceChangeSectionById +80820088 Pages::Menu::LoadMessageBoxPageWithDelay +80820244 Pages::Menu::LoadMessageBoxPage +80820408 Pages::Menu::LoadMessageBoxTransparentPageThenChangeSectionWithDelay +808205d4 Pages::Menu::LoadMessageBoxTransparentPageThenChangeSection +808207a8 Pages::Menu::LoadMessageBoxTransparentPage +808208b4 Pages::Menu::ChangePrevSection +80820900 Pages::Menu::OnMoviesActivate +8082098c Pages::Menu::LoadMovies +808209a8 Pages::Menu::UnloadMovies +808209bc Pages::Menu::IsMultiplayer +808209f8 Pages::Menu::AreAllPlayersActive +80820adc Pages::Menu::BeforeEntranceAnimations +80820b78 Pages::Menu::GetNextPage +80820b80 Pages::Menu::BeforeExitAnimations +80820c1c Pages::Menu::OnStartPress +80820c20 MenuPage_cpp_sinit_ +80820c34 Pages::MenuBG::GetPageById +80820d44 Pages::MenuBG::CreateControl +80820ea8 Pages::MenuBG::AfterControlUpdate +80820eac Pages::MenuBG::GetPlayerBifield +80820eb4 Pages::MenuBG::GetActivePlayerBitfield +80820ebc Pages::MenuBG::GetManipulatorManager +80820ec4 Pages::MenuBG::BeforeEntranceAnimations +80820ec8 Pages::MenuBG::__ct +80820f48 Pages::MenuBG::GetRuntimeTypeInfo +80820f54 BattleKartSelectPagecpp_sinit_ +80820f68 Pages::BattleModeSelect::GetPageById +80821078 Pages::BattleModeSelect::OnInit +808210cc Pages::BattleModeSelect::GetManipulatorManager +808210d4 Pages::BattleModeSelect::CreateExternalControl +80821280 Pages::BattleModeSelect::CreateControl +80821288 Pages::BattleModeSelect::OnActivate +80821660 Pages::BattleModeSelect::OnActivate_switch +80821664 Pages::BattleModeSelect::OnActivate_case_0 +8082167c Pages::BattleModeSelect::OnActivate_case_1 +80821694 Pages::BattleModeSelect::OnActivate_case_2 +808216ac Pages::BattleModeSelect::OnActivate_case_3 +808216c4 Pages::BattleModeSelect::OnActivate_case_4 +808216dc Pages::BattleModeSelect::OnActivate_case_5 +808216f4 Pages::BattleModeSelect::OnActivate_case_6 +8082170c Pages::BattleModeSelect::OnActivate_case_7 +80821754 Pages::BattleModeSelect::AfterControlUpdate +80821758 Pages::BattleModeSelect::OnButtonClick +80821834 Pages::BattleModeSelect::OnExternalButtonSelect +8082186c Pages::BattleModeSelect::OnButtonDeselect +80821870 Pages::BattleModeSelect::OnBackPress +8082187c Pages::BattleModeSelect::OnDeactivate +808218c8 Pages::BattleModeSelect::GetPlayerBitfield +808218d0 Pages::BattleModeSelect::GetActivePlayerBitfield +808218d8 Pages::BattleModeSelect::SetButtonHandlers +80821934 Pages::BattleModeSelect::__dt +808219b4 Pages::BattleModeSelect::GetRuntimeTypeInfo +808219c0 BattleModeSelectPage_cpp_sinit_ +808219d4 Pages::BattleSettings::GetPageById +80821ae4 Pages::BattleSettings::OnInit +80821dd8 Pages::BattleSettings::CreateExternalControl +80821e68 Pages::BattleSettings::CreateControl +8082222c Pages::BattleSettings::OnActivate +8082238c Pages::BattleSettings::AfterControlUpdate +80822390 Pages::BattleSettings::OnButtonClick +80822394 Pages::BattleSettings::OnExternalButtonSelect +808223c0 Pages::BattleSettings::OnButtonDeselect +808223c4 Pages::BattleSettings::OnBackPress +80822408 Pages::BattleSettings::OnRadioClick +80822574 Pages::BattleSettings::OnRadioChange +80822654 Pages::BattleSettings::OnUpDownClick +808226c0 Pages::BattleSettings::OnUpDownSelect +808226d0 Pages::BattleSettings::OnUpDownChange +80822748 Pages::BattleSettings::OnTextChange +808227c4 Pages::BattleSettings::GetPlayerBitfield +808227cc Pages::BattleSettings::GetActivePlayerBitfield +808227d4 Pages::BattleSettings::SetButtonHandlers +80822830 Pages::BattleSettings::GetManipulatorManager +80822838 Pages::BattleSettings::__dt +80822900 Pages::BattleSettings::GetRuntimeTypeInfo +8082290c Pages::BattleSettings::TriggerUpDown3APtmf +8082293c Pages::BattleSettings::TriggerRadioPtmf +8082296c Pages::BattleSettings::TriggerTextPtmf +8082299c Pages::BattleSettings::TriggerUpDown2APtmf +808229cc BattleStageSelectPage_cpp_sinit_ +808229e0 CharaName::GetClassName +808229ec Pages::CharacterSelect::GetPageById +80822afc Pages::CharacterSelect::OnInit +80822de0 CharaName::__ct +80822e1c Pages::CharacterSelect::CreateExternalControl +80822e24 Pages::CharacterSelect::CreateControl +80823018 Pages::CharacterSelect::OnActivate +80823354 Pages::CharacterSelect::GetManipulatorManager +8082335c Pages::CharacterSelect::AfterControlUpdate +80823548 Pages::CharacterSelect::OnButtonDriverClick +80823b94 Pages::CharacterSelect::OnButtonDriverSelect +80823ce0 Pages::CharacterSelect::OnButtonClick +80823e78 Pages::CharacterSelect::OnExternalButtonSelect +80823ec4 Pages::CharacterSelect::OnButtonDeselect +80823ec8 Pages::CharacterSelect::OnBackPress +808241c8 Pages::CharacterSelect::8083ec28 +808243bc Pages::CharacterSelect::8083ee1c +8082445c Pages::CharacterSelect::OnResume +808244dc Pages::CharacterSelect::OnDispose +808244ec Pages::CharacterSelect::BeforeEntranceAnimations +80824594 Pages::CharacterSelect::BeforeExitAnimations +8082463c CharaName::InitSelf +80824800 Pages::CharacterSelect::GetPlayerBitfield +80824808 Pages::CharacterSelect::GetActivePlayerBitfield +80824810 Pages::CharacterSelect::SetButtonHandlers +8082486c Pages::CharacterSelect::__dt +808248fc Pages::CharacterSelect::GetRuntimeTypeInfo +80824908 CharaName::GetRuntimeTypeInfo +80824914 CharaSelectcpp_sinit_ +80824938 Pages::GPClassSelect::GetPageById +80824a48 Pages::GPClassSelect::OnInit +80824b18 Pages::GPClassSelect::GetManipulatorManager +80824b20 Pages::GPClassSelect::CreateExternalControl +80824d50 Pages::GPClassSelect::CreateControl +80824dd8 Pages::GPClassSelect::OnActivate +80824eb4 Pages::GPClassSelect::AfterControlUpdate +80824f28 Pages::GPClassSelect::OnButtonClick +808250cc Pages::GPClassSelect::OnExternalButtonSelect +80825154 Pages::GPClassSelect::OnButtonDeselect +80825158 Pages::GPClassSelect::OnBackPress +80825164 Pages::GPClassSelect::OnDeactivate +80825168 Pages::GPClassSelect::OnStartPress +8082566c Pages::GPClassSelect::GetPlayerBitfield +80825674 Pages::GPClassSelect::GetActivePlayerBitfield +8082567c Pages::GPClassSelect::SetButtonHandlers +808256d8 Pages::GPClassSelect::__dt +80825764 Pages::GPClassSelect::GetRuntimeTypeInfo +80825770 GPClassSelectPage_cpp_sinit_ +80825784 Pages::CourseSelect::GetPageById +80825894 Pages::CourseSelect::OnInit +80825930 Pages::CourseSelect::CreateExternalControl +80825938 Pages::CourseSelect::CreateControl +80825a40 Pages::CourseSelect::OnActivate +80825b60 Pages::CourseSelect::BeforeEntranceAnimations +80825bac Pages::CourseSelect::AfterControlUpdate +80825cc8 Pages::CourseSelect::UpdateBottomText +80825dd0 Pages::CourseSelect::LoadNextPage +80825fe4 Pages::CourseSelect::OnButtonClick +8082604c Pages::CourseSelect::OnExternalButtonSelect +80826050 Pages::CourseSelect::OnButtonDeselect +80826054 Pages::CourseSelect::OnBackPress +808260bc Pages::CourseSelect::BeforeExitAnimations +80826118 Pages::CourseSelect::OnDeactivate +80826140 Pages::CourseSelect::OnTimeout +80826214 Pages::CourseSelect::GetPlayerBitfield +8082621c Pages::CourseSelect::GetActivePlayerBitfield +80826224 Pages::CourseSelect::SetButtonHandlers +80826280 Pages::CourseSelect::__dt +8082636c Pages::CourseSelect::GetRuntimeTypeInfo +80826378 Pages::CourseSelect::_sinit_ +8082638c Pages::CupSelect::GetPageById +8082649c Pages::CupSelect::OnInit +808265a0 Pages::CupSelect::CreateExternalControl +808265a8 Pages::CupSelect::CreateControl +808266b0 Pages::CupSelect::OnActivate +80826a50 Pages::CupSelect::GetManipulatorManager +80826a58 Pages::CupSelect::AfterControlUpdate +80826bb4 Pages::CupSelect::UpdateText +80826ce4 Pages::CupSelect::LoadNextPage +80826e88 Pages::CupSelect::OnButtonClick +808270ec Pages::CupSelect::OnExternalButtonSelect +808270f0 Pages::CupSelect::OnButtonDeselect +808270f4 Pages::CupSelect::OnBackPress +80827384 Pages::CupSelect::OnResume +80827598 Pages::CupSelect::OnDeactivate +808275c0 Pages::CupSelect::BeforeEntranceAnimations +8082761c Pages::CupSelect::BeforeExitAnimations +80827678 Pages::CupSelect::OnTimeout +80827774 Pages::CupSelect::GetPlayerBitfield +8082777c Pages::CupSelect::GetActivePlayerBitfield +80827784 Pages::CupSelect::SetButtonHandlers +808277e0 Pages::CupSelect::__dt +808278d4 0x808278d4 +808278e0 0x808278e0 +808278f4 Pages::KartSelect::GetPageById +80827a04 ButtonMachine::GetClassName +80827a10 Pages::KartSelect::GetVehicleID +80827a88 Pages::KartSelect::GetUnlockedVehiclesCountByWeightAndType +80827b04 Pages::KartSelect::GetUnlockedVehiclesCountByWeight +80827be4 Pages::KartSelect::GetMinUnlockedVehiclesCount +80827e90 Pages::KartSelect::OnInit +80828270 Pages::KartSelect::CreateExternalControl +80828278 Pages::KartSelect::CreateControl +808285dc Pages::KartSelect::SetButtonHandlers +80828638 Pages::KartSelect::OnActivate +80829b44 Pages::KartSelect::GetManipulatorManager +80829b4c Pages::KartSelect::GetLocalPlayerCount +80829b54 Pages::KartSelect::AfterControlUpdate +80829d44 Pages::KartSelect::OnButtonClick +80829fcc Pages::KartSelect::OnExternalButtonSelect +8082a0e4 Pages::KartSelect::OnButtonSelect +8082a0e8 Pages::KartSelect::OnBackPress +8082a1bc Pages::KartSelect::GetExternalControl +8082a2ec Pages::KartSelect::GetButtonMachineById +8082a46c Pages::KartSelect::InitButtonMachine +8082a584 Pages::KartSelect::8084745c +8082a6b8 Pages::KartSelect::80847590 +8082a758 Pages::KartSelect::BeforeEntranceAnimations +8082a7b8 Pages::KartSelect::BeforeExitAnimations +8082a818 ButtonMachine::OnUpdate +8082a938 ButtonMachine::InitSelf +8082aa1c zz_8478f4 +8082ad14 Pages::KartSelect::GetPlayerBitfield +8082ad1c Pages::KartSelect::__dt +8082adb8 Pages::KartSelect::GetRuntimeTypeInfo +8082adc4 ButtonMachine::GetRuntimeTypeInfo +8082add0 ButtonMachine::__dt +8082ae28 KartSelect_cpp_sinit +8082ae4c Pages::MiiSelect::GetPageById +8082af5c MiiName::GetClassName +8082af68 Pages::MiiSelect::OnINit +8082b16c Pages::MiiSelect::GetManipulatorManager +8082b174 Pages::MiiSelect::CreateExternalControl +8082b2f4 Pages::MiiSelect::GetActivePlayerBitfield +8082b2fc Pages::MiiSelect::SetButtonHandlers +8082b358 Pages::MiiSelect::CreateControl +8082b690 Pages::MiiSelect::OnActivate +8082b910 Pages::MiiSelect::AfterControlUpdate +8082b914 Pages::MiiSelect::OnButtonClick +8082bc10 Pages::MiiSelect::OnExternalButtonSelect +8082bc80 Pages::MiiSelect::OnButtonDeselect +8082bc88 Pages::MiiSelect::OnBackPress +8082bcfc Pages::MiiSelect::OnDeactivate +8082bd10 Pages::MiiSelect::OnRightArrowPress +8082be68 Pages::MiiSelect::OnLeftArrowPress +8082bf6c Pages::MiiSelect::OnTabButtonClick +8082c0bc Pages::MiiSelect::SetMiiIcons +8082c35c Pages::MiiSelect::GetCurTabMiiCount +8082c3ac MiiName::InitSelf +8082c570 Pages::MiiSelect::GetPlayerBitfield +8082c578 Pages::MiiSelect::__dt +8082c620 Pages::MiiSelect::GetRuntimeTypeInfo +8082c62c MiiName::GetRuntimeTypeInfo +8082c638 Pages::MiiSelect::TriggerTabPtmf +8082c668 Pages::MiiSelect::TriggerSheetPtmf +8082c698 MiiSelect_cpp_sinit_ +8082c6bc Pages::MultiKartSelect::GetPageById +8082c7cc Pages::MultiKartSelect::OnInit +8082ca68 Pages::MultiKartSelect::CreateExternalControl +8082ca70 Pages::MultiKartSelect::CreateControl +8082cd4c Pages::MultiKartSelect::OnActivate +8082cea8 Pages::MultiKartSelect::AfterControlUpdate +8082cf8c Pages::MultiKartSelect::GetManipulatorManager +8082cf94 Pages::MultiKartSelect::OnButtonClick +8082d088 Pages::MultiKartSelect::OnExternalButtonSelect +8082d08c Pages::MultiKartSelect::OnButtonDeselect +8082d090 Pages::MultiKartSelect::OnBackPress +8082d228 Pages::MultiKartSelect::OnUpDownClick +8082d3cc Pages::MultiKartSelect::OnUpDownChange +8082d3d0 Pages::MultiKartSelect::OnTextChange +8082d520 Pages::MultiKartSelect::FillPossibleKarts +8082d6ec 0x8082d6ec +8082d790 Pages::MultiKartSelect::BeforeEntranceAnimations +8082d838 Pages::MultiKartSelect::BeforeExitAnimations +8082d8e0 Pages::MultiKartSelect::GetPlayerBitfield +8082d8e8 Pages::MultiKartSelect::GetActivePlayerBitfield +8082d8f0 Pages::MultiKartSelect::SetButtonHandlers +8082d94c Pages::MultiKartSelect::__dt +8082da2c Pages::MultiKartSelect::GetRuntimeTypeInfo +8082da38 TriggerPtmf +8082da68 TriggerPtmf +8082da98 TriggerPtmf +8082dac8 MultiTeamSelectPage_cpp_sinit_ +8082dadc Pages::MultiPlayer::GetPageById +8082dbec Pages::MultiPlayer::OnINit +8082dc4c Pages::MultiPlayer::CreateExternalControl +8082dd94 Pages::MultiPlayer::CreateControl +8082dd9c Pages::MultiPlayer::OnActivate +8082dec4 Pages::MultiPlayer::AfterControlUpdate +8082dec8 Pages::MultiPlayer::OnButtonClick +8082e0e8 Pages::MultiPlayer::OnExternalButtonSelect +8082e568 Pages::MultiPlayer::OnButtonDeselect +8082e56c Pages::MultiPlayer::OnBackPress +8082e5c0 Pages::MultiPlayer::OnDeactivate +8082e5c4 Pages::MultiPlayer::GetPlayerBifield +8082e5cc Pages::MultiPlayer::GetActivePlayerBitfield +8082e5d4 Pages::MultiPlayer::SetButtonHandlers +8082e630 Pages::MultiPlayer::GetManipulatorManager +8082e638 Pages::MultiPlayer::__dt +8082e6b8 Pages::MultiPlayer::GetRuntimeTypeInfo +8082e6c4 MultiPlayerPage_cpp_sinit_ +8082e6d8 DriftSelectPage:GetPageById +8082e7e8 Pages::DriftSelect::OnInit +8082e8cc Pages::DriftSelect::GetManipulatorManager +8082e8d4 Pages::DriftSelect::CreateExternalControl +8082eb20 Pages::DriftSelect::CreateControl +8082eb28 Pages::DriftSelect::OnActivate +8082ec48 Pages::DriftSelect::AfterControlUpdate +8082ed74 Pages::DriftSelect::OnButtonClick +8082f0a8 Pages::DriftSelect::OnExternalButtonSelect +8082f0e0 Pages::DriftSelect::OnButtonDeselect +8082f0e4 Pages::DriftSelect::OnBackPress +8082f0f0 Pages::DriftSelect::OnDeactivate +8082f13c Pages::DriftSelect::GetPlayerBitfield +8082f144 Pages::DriftSelect::GetActivePlayerBitfield +8082f14c Pages::DriftSelect::SetButtonHandlers +8082f1a8 Pages::DriftSelect::__dt +8082f228 Pages::DriftSelect::GetRuntimeTypeInfo +8082f234 DriftSelectPage_cpp_sinit_ +8082f248 Pages::TopMenuOverlay::GetPageById +8082f358 Pages::TopMenuOverlay::CreateControl +8082f738 Pages::TopMenuOverlay::vf_0x98 +8082f740 Pages::TopMenuOverlay::GetPlayerBitfield +8082f748 Pages::TopMenuOverlay::GetActivePlayerBitfield +8082f750 Pages::TopMenuOverlay::GetManipulatorManager +8082f758 Pages::TopMenuOverlay::__dt +8082f7d8 Pages::TopMenuOverlay::GetRuntimeTypeInfo +8082f7e4 TopMenuOverlayPagecpp_sinit_ +8082f7f8 Pages::SinglePlayer::GetPageById +8082f908 Pages::SinglePlayer::OnInit +8082f9a8 Pages::SinglePlayer::GetManipulatorManager +8082f9b0 Pages::SinglePlayer::CreateExternalControl +8082faf4 Pages::SinglePlayer::CreateControl +8082fafc Pages::SinglePlayer::OnActivate +8082fc80 Pages::SinglePlayer::AfterControlUpdate +8082fc84 Pages::SinglePlayer::OnButtonClick +80830074 Pages::SinglePlayer::OnExternalButtonSelect +80830520 Pages::SinglePlayer::OnButtonDeselect +80830524 Pages::SinglePlayer::OnBackPress +80830578 Pages::SinglePlayer::OnDeactivate +8083057c Pages::SinglePlayer::GetPlayerBitfield +80830584 Pages::SinglePlayer::GetActivePlayerBitfield +8083058c Pages::SinglePlayer::SetButtonHandlers +808305e8 Pages::SinglePlayer::__dt +80830668 Pages::SinglePlayer::GetRuntimeTypeInfo +80830674 SinglePlayerPage_cpp_sinit_ +80830688 Pages::VSTeamsView::GetPageById +80830798 Pages::VSTeamsView::OnInit +8083079c Pages::VSTeamsView::CreateExternalControl +8083082c Pages::VSTeamsView::CreateControl +80830894 Pages::VSTeamsView::OnActivate +80830898 Pages::VSTeamsView::AfterControlUpdate +8083089c Pages::VSTeamsView::OnButtonClick +8083096c Pages::VSTeamsView::OnExternalButtonSelect +808309a4 Pages::VSTeamsView::OnButtonDeselect +808309a8 Pages::VSTeamsView::OnBackPress +808309b4 Pages::VSTeamsView::AssignTeams +80830b8c Pages::VSTeamsView::GetPlayerBitfield +80830b94 Pages::VSTeamsView::GetActivePlayerBitfield +80830b9c Pages::VSTeamsView::SetButtonHandlers +80830bf8 Pages::VSTeamsView::GetManipulatorManager +80830c00 Pages::VSTeamsView::__dt +80830c98 Pages::VSTeamsView::GetRuntimeTypeInfo +80830ca4 VSTeamsViewPage_cpp_sinit_ +80830cb8 Pages::MainMenu::GetPageById +80830dc8 Pages::MainMenu::OnInit +80830ec8 Pages::MainMenu::GetManipulatorManager +80830ed0 Pages::MainMenu::CreateExternalControl +80830f6c Pages::MainMenu::CreateControl +80831740 Pages::MainMenu::SetButtonHandlers +8083179c Pages::MainMenu::OnActivate +80831af4 Pages::MainMenu::AfterControlUpdate +80831af8 Pages::MainMenu::OnButtonClick +80831f08 Pages::MainMenu::OnExternalButtonSelect +80831f8c Pages::MainMenu::OnButtonDeselect +80832098 Pages::MainMenu::OnBackPress +808320a8 Pages::MainMenu::ResetSectionParamsAndRacedataScenario1 +80832574 Pages::MainMenu::OnDeactivate +80832578 Pages::MainMenu::ShowMessageBox +80832670 Pages::MainMenu::GetPlayerBitfield +80832678 Pages::MainMenu::GetActivePlayerBitfield +80832680 Pages::MainMenu::__dt +80832718 Pages::VSModeSelect::GetRuntimeTypeInfo +80832724 VSModeSelectPage_cpp_sinit_ +80832738 Pages::VSSettings::GetPageById +80832848 Pages::VSSettings::OnInit +80832ae0 Pages::VSSettings::CreateExternalControl +80832b70 Pages::VSSettings::CreateControl +80833004 Pages::VSSettings::OnActivate +80833108 Pages::VSSettings::AfterControlUpdate +8083310c Pages::VSSettings::OnButtonClick +8083313c Pages::VSSettings::OnExternalButtonSelect +80833168 Pages::VSSettings::OnButtonDeselect +8083316c Pages::VSSettings::OnBackPress +808331cc Pages::VSSettings::OnRadioClick +80833354 Pages::VSSettings::OnRadioChange +808333d4 Pages::VSSettings::OnUpDownClick +80833440 Pages::VSSettings::OnUpDownSelect +80833450 Pages::VSSettings::OnUpDownChange +808334c8 Pages::VSSettings::OnTextChange +80833544 Pages::VSSettings::OnDispose +80833554 Pages::VSSettings::GetPlayerBitfield +8083355c Pages::VSSettings::GetLocalPlayerCount +80833564 Pages::VSSettings::SetButtonHandlers +808335c0 Pages::VSSettings::GetManipulatorManager +808335c8 Pages::VSSettings::__dt +80833690 Pages::VSSettings::GetRuntimeTypeInfo +8083369c Pages::VSSettings::TriggerUpDown3APtmf +808336cc Pages::VSSettings::TriggerRadioPtmf +808336fc Pages::VSSettings::TriggerTextPtmf +8083372c Pages::VSSettings::TriggerUpDown2APtmf +8083375c UnlockPage_cpp_sinit_ +80833770 Pages::RaceIntro::OnInit +80833bb4 Pages::RaceIntro::__dt +80833c34 Pages::RaceIntro::GetRuntimeTypeInfo +80833c40 RaceIntroPage_cpp_sinit_ +80833c54 Pages::TTSplits::__ct +80833dc4 Pages::TTSplits::Unload +80833dd4 Pages::TTSplits::__dt +80833e94 Pages::TTSplits::OnInit +8083404c Pages::TTSplits::AfterControlUpdate +808340a0 Pages::TTSplits::BeforeEntranceAnimations +808346dc Pages::TTSplits::BeforeExitAnimations +8083474c Pages::TTSplits::GetNextPage +80834798 Pages::TTSplits::GetRuntimeTypeInfo +808347a4 Pages::TTSplits::TriggerAction +808347d4 Pages::TTSplits::_sinit_ +808347e8 Pages::RaceHUD::OnInit +80834bd4 Pages::RaceHUD::InitActions +80834f1c Pages::RaceHUD::OnNextPlayerSwitch +80834f24 Pages::RaceHUD::OnPrevPlayerSwitch +80834f2c Pages::RaceHUD::OnPause +808350e4 Pages::RaceHUD::ChangeFocusedPlayer +8083523c Pages::RaceHUD::GetLocalPlayerCount +8083525c Pages::RaceHUD::BeforeControlUpdate +80835844 Pages::RaceHUD::HasPlayerRaceEnded +8083589c Pages::RaceHUD::HasRaceEndedReplay +8083591c Pages::RaceHUD::HasRaceEnded +80835a28 Pages::RaceHUD::AfterControlUpdate +80836038 0x80836038 +80836078 Pages::RaceHUD::GetCtrlRaceBaseCount +80836230 Pages::RaceHUD::InitCtrlRaceBase +80836d98 CtrlRaceCount::__ct +80836dd4 RaceBalloons::__dt +80836e3c CtrlRaceNameBalloon::__ct +80836e8c CtrlRaceItemBalloon::__ct +80836edc Pages::TournamentHUD::GetEnabledCtrlRaceBases +80836f88 Pages::RaceHUD::OnDeactivate +80836f94 Pages::RaceHUD::OnDispose +80836fa4 Pages::RaceHUD::ChangeSectionByReinit +80836fc0 Pages::RaceHUD::OnItemObjTargeting +80837054 Pages::RaceHUD::UpdateRaceBalloons +808370f8 Pages::TournamentHUD::GetCtrlRaceNameBalloonCount +80837100 Pages::TournamentHUD::GetPausePageId +80837108 Pages::TournamentHUD::__dt +80837174 Pages::TournamentHUD::GetRuntimeTypeInfo +80837180 Pages::RaceHUD::GetRuntimeTypeInfo +8083718c TriggerPtmf +808371bc 0x808371bc +80837214 Pages::RaceMenu::__ct +808372d0 Pages::RaceMenu::OnInit +80837f9c Pages::RaceMenu::OnActivate +80838408 Pages::RaceMenu::AfterControlUpdate +808384a0 Pages::RaceMenu::BeforeEntranceAnimations +808384a4 Pages::RaceMenu::BeforeExitAnimations +80838510 Pages::RaceMenu::OnDeactivate +80838514 Pages::RaceMenu::OnDispose +808385ac 0x808385ac +80838608 Pages::RaceMenu::OnStartPress +80838664 Pages::RaceMenu::OnButtonClick +80838730 0x80838730 +80838778 0x80838778 +80838808 0x80838808 +80838af0 0x80838af0 +80838b50 0x80838b50 +80838bec 0x80838bec +80838c4c 0x80838c4c +80838d7c 0x80838d7c +80838f20 0x80838f20 +808391c4 0x808391c4 +80839594 0x80839594 +80839648 0x80839648 +808396fc 0x808396fc +8083992c 0x8083992c +808399d8 0x808399d8 +80839a2c 0x80839a2c +80839ad8 0x80839ad8 +80839b58 0x80839b58 +80839c48 0x80839c48 +80839cac 0x80839cac +80839d2c 0x80839d2c +80839d8c 0x80839d8c +80839e38 0x80839e38 +80839ea0 0x80839ea0 +80839f4c 0x80839f4c +80839fb4 0x80839fb4 +8083a060 0x8083a060 +8083a180 Pages::RaceMenu::IsFinalRace +8083a2c8 Pages::RaceMenu::GetRuntimeTypeInfo +8083a2d4 TriggerPtmf +8083a304 TriggerPtmf +8083a334 0x8083a334 +8083a3b4 Pages::Leaderboard::__ct +8083a504 Pages::Leaderboard::OnActivate +8083a5e0 0x8083a5e0 +8083a634 Pages::Leaderboard::AfterControlUpdate +8083a6dc 0x8083a6dc +8083a900 Pages::Leaderboard::GetRuntimeTypeInfo +8083a90c TriggerPtmf +8083a93c 0x8083a93c +8083a950 Pages::TeamVSLeaderboardBase::OnInit +8083aa7c Pages::TeamVSLeaderboardBase::AfterControlUpdate +8083aad8 Pages::TeamVSLeaderboardBase::CanEnd +8083ab38 Pages::TeamVSLeaderboardBase::CalcTeamScoreDiff +8083acc0 Pages::TeamVSLeaderboardTotal::FillRows +8083ad30 Pages::BattleLeaderboardTotal::FillRows +8083ad40 Pages::BattleLeaderboardUpdate::FillRows +8083b090 Pages::TeamVSLeaderboardTotal::GetNextPage +8083b0c0 Pages::BattleLeaderboardUpdate::GetNextPage +8083b0f0 Pages::BattleLeaderboardTotal::GetNextPage +8083b18c Pages::BattleLeaderboardTotal::__dt +8083b218 Pages::BattleLeaderboardTotal::GetRuntimeTypeInfo +8083b224 Pages::BattleLeaderboardUpdate::__dt +8083b2b0 Pages::BattleLeaderboardUpdate::GetRuntimeTypeInfo +8083b2bc Pages::TeamVSLeaderboardTotal::__dt +8083b348 Pages::TeamVSLeaderboardTotal::GetRuntimeTypeInfo +8083b354 Pages::TeamVSLeaderboardBase::GetRuntimeTypeInfo +8083b360 TeamLeaderboard_cpp_sinit_ +8083b388 RacePauseMgr::CreateInstance +8083b3e8 RacePauseMgr::__ct +8083b400 RacePauseMgr::DestroyInstance +8083b450 RacePauseMgr::__dt +8083b490 RacePauseMgr::RequestPause +8083b4b4 RacePauseMgr::RequestUnpause +8083b4d8 0x8083b4d8 +8083b50c 0x8083b50c +8083b514 0x8083b514 +8083b5b8 0x8083b5b8 +8083b608 0x8083b608 +8083b610 0x8083b610 +8083b618 0x8083b618 +8083b630 0x8083b630 +8083b664 0x8083b664 +8083b66c 0x8083b66c +8083b674 0x8083b674 +8083b67c 0x8083b67c +8083b684 0x8083b684 +8083b68c 0x8083b68c +8083b694 0x8083b694 +8083b69c 0x8083b69c +8083b6a4 0x8083b6a4 +8083b6ac 0x8083b6ac +8083b6b4 0x8083b6b4 +8083b6bc 0x8083b6bc +8083b6c4 0x8083b6c4 +8083b6cc 0x8083b6cc +8083b6d4 0x8083b6d4 +8083b6dc 0x8083b6dc +8083b6e4 0x8083b6e4 +8083b6ec 0x8083b6ec +8083b6f4 0x8083b6f4 +8083b6fc 0x8083b6fc +8083b70c 0x8083b70c +8083b740 0x8083b740 +8083b748 0x8083b748 +8083b750 0x8083b750 +8083b758 0x8083b758 +8083b768 0x8083b768 +8083b784 0x8083b784 +8083b788 0x8083b788 +8083b790 0x8083b790 +8083b798 0x8083b798 +8083b7a0 0x8083b7a0 +8083b7a8 0x8083b7a8 +8083b7b0 0x8083b7b0 +8083b7b8 0x8083b7b8 +8083b7c0 0x8083b7c0 +8083b7d0 0x8083b7d0 +8083b7fc 0x8083b7fc +8083b804 0x8083b804 +8083b824 0x8083b824 +8083b828 0x8083b828 +8083b838 IsOnlineSection +8083b874 IsGhostRaceSection +8083b894 IsTournamentSection +8083b8b4 GetActiveRacedataPlayers +8083b9b0 GetLocalPlayerCount +8083b9c8 0x8083b9c8 +8083ba40 0x8083ba40 +8083ba58 GetNextVSTrack +8083ba84 0x8083ba84 +8083bac0 0x8083bac0 +8083bbe0 0x8083bbe0 +8083bc98 TimerToTextInfo +8083bdb0 IsGameplaySection +8083bddc 0x8083bddc +8083be40 IsBattle +8083be80 GetCharacterIconPaneName +8083bea4 GetItemIconPaneName +8083bf08 GetCupIconPaneName +8083bf3c 0x8083bf3c +8083bf70 GetBattleCupIconPaneName +8083bfa4 0x8083bfa4 +8083c1bc GetMapIconPaneName +8083c2e0 0x8083c2e0 +8083c6f0 CtrlMenuBattleCupSelectCup::GetClassName +8083c6fc CtrlMenuBattleCupSelectStage::GetClassName +8083c70c CtrlMenuBattleCupSelectCup::Load +8083c904 CtrlMenuBattleCupSelectCup::OnInit +8083ca44 CtrlMenuBattleCupSelectCup::OnCupButtonSelect +8083cb14 CtrlMenuBattleCupSelectCup::OnCupButtonClick +8083cb74 CtrlMenuBattleCupSelectStage::Load +8083cc98 CtrlMenuBattleCupSelectStage::UpdateStageList +8083cd84 CtrlMenuBattleCupSelectStage::InitSelf +8083ce88 CtrlMenuBattleCupSelectStage::OnUpdate +8083cffc CtrlMenuBattleCupSelectStage::GetRuntimeTypeInfo +8083d008 CtrlMenuBattleCupSelectCup::GetRuntimeTypeInfo +8083d014 CtrlMenuBattleCup::_sinit_ +8083d030 CtrlMenuBattleStageSelectCupSub::GetClassName +8083d03c CtrlMenuBattleStageSelectCup::GetClassName +8083d04c CtrlMenuBattleStageSelectStage::GetClassName +8083d05c StageButton::GetClassName +8083d06c CtrlMenuBattleStageSelectCup::Load +8083d1f8 CtrlMenuBattleStageSelectCup::InitSelf +8083d2fc CtrlMenuBattleStageSelectCupSub::SetRelativePosition +8083d380 CtrlMenuBattleStageSelectCupSub::InitSelf +8083d41c CtrlMenuBattleStageSelectCupSub::OnUpdate +8083db2c Pages::BattleStageSelect::GetManipulatorManager +8083db34 CtrlMenuBattleStageSelectStage::Load +8083dc84 CtrlMenuBattleStageSelectStage::InitSelf +8083e068 CtrlMenuBattleStageSelectStage::OnStageButtonClick +8083e0c0 CtrlMenuBattleStageSelectStage::OnStageButtonSelect +8083e2bc CtrlMenuBattleStageSelectStage::GetRuntimeTypeInfo +8083e2c8 StageButton::GetRuntimeTypeInfo +8083e2d4 0x8083e2d4 +8083e2e0 0x8083e2e0 +8083e2ec 0x8083e2ec +8083e318 0x8083e318 +8083e320 0x8083e320 +8083e328 0x8083e328 +8083e330 0x8083e330 +8083e33c 0x8083e33c +8083e34c 0x8083e34c +8083e594 0x8083e594 +8083e744 0x8083e744 +8083e864 0x8083e864 +8083e8c4 0x8083e8c4 +8083ea4c 0x8083ea4c +8083eb38 0x8083eb38 +8083ec58 0x8083ec58 +8083ec5c 0x8083ec5c +8083ec68 0x8083ec68 +8083ec74 0x8083ec74 +8083ec90 CtrlMenuMRStageSelectLevelSub::GetClassName +8083ec9c CtrlMenuMRStageSelectLevel::GetClassName +8083ecac CtrlMenuMRStageSelectStage::GetClassName +8083ecbc MRStageButton::GetClassName +8083eccc MissionStageSelectLevel::OnInit +8083ee98 0x8083ee98 +8083efb8 0x8083efb8 +8083f010 0x8083f010 +8083f06c CtrlMenuMRStageSelectLevelSub::OnUpdate +8083f2c8 0x8083f2c8 +8083f2d0 MissionStageSelectStage::OnInit +8083f504 0x8083f504 +8083f6dc 0x8083f6dc +8083f734 0x8083f734 +8083f8e0 0x8083f8e0 +8083f8ec 0x8083f8ec +8083f8f8 0x8083f8f8 +8083f904 CtrlMenuMRStageSelectLevelSub::GetRuntimeTypeInfo +8083f910 0x8083f910 +8083f93c 0x8083f93c +8083f944 0x8083f944 +8083f94c 0x8083f94c +8083f954 CtrlMenuMachineGraph::GetClassName +8083f960 CtrlMenuMachineGraph::Load +8083fcb0 MachineAbility::__ct +8083fcec MachineAbility::__dt +8083fd44 CtrlMenuMachineGraph::OnUpdate +8083fd48 CtrlMenuMachineGraph::OnLoad +8083fe6c MachineAbility::InitSelf +80840040 CtrlMenuMachineGraph::GetRuntimeTypeInfo +8084004c CtrlMenuMachineGraph_cpp_sinit +80840060 CtrlMenuMovieHandler::Toggle +808400b0 CtrlMenuMovieHandler::IsMirror +808401f8 CtrlMenuMovieButton::GetPaneNames +80840204 CtrlMenuMovieLayout::GetPaneNames +80840210 CtrlMenuSingleTopMovieButton::GetPaneNames +8084021c CtrlMenuMovieButton::GetClassName +80840228 CtrlMenuMovieButton::OnLoad +808403d0 MovieScale::__ct +808403d4 CtrlMenuMovieButton::InitSelf +808405c0 CtrlMenuMovieButton::OnUpdate +808406c4 CtrlMenuSingleTopMovieButton::GetClassName +808406d4 CtrlMenuSingleTopMovieButton::OnLoad +8084087c CtrlMenuSingleTopMovieButton::GetMovieCount +80840884 CtrlMenuSingleTopMovieButton::InitSelf +80840a70 CtrlMenuSingleTopMovieButton::OnUpdate +80840b74 CtrlMenuMovieLayout::GetClassName +80840b84 CtrlMenuMovieLayout::OnLoad +80840d2c CtrlMenuMovieLayout::GetMovieCount +80840d34 CtrlMenuMovieLayout::InitSelf +80840f20 CtrlMenuMovieLayout::OnUpdate +80841024 CtrlMenuMovieLayout::GetRuntimeTypeInfo +80841030 CtrlMenuSingleTopMovieButton::GetRuntimeTypeInfo +8084103c CtrlMenuSingleTopMovieButton::__dt +80841098 CtrlMenuMovieButton::GetRuntimeTypeInfo +808410a4 CtrlMenuMovie_cpp_sinit_ +808410cc CtrlMenuMovieButton::__dt(PushButton) +808410d4 CtrlMenuMovieButton::GetClassName(PushButton) +808410dc CtrlMenuMovieButton::GetRuntimeTypeInfo(PushButton) +808410e4 CtrlMenuSingleTopMovieButton::OnUpdate(PushButton) +808410ec CtrlMenuSingleTopMovieButton::InitSelf(PushButton) +808410f4 CtrlMenuSingleTopMovieButton::OnLoad(PushButton) +808410fc CtrlMenuSingleTopMovieButton::__dt(PushButton) +80841104 CtrlMenuSingleTopMovieButton::GetClassName(PushButton) +8084110c CtrlMenuSingleTopMovieButton::GetRuntimeTypeInfo(PushButton) +80841114 CtrlMenuMovieLayout::OnUpdate(LayoutUIControl) +8084111c CtrlMenuMovieLayout::InitSelf(LayoutUIControl) +80841124 CtrlMenuMovieLayout::__dt(LayoutUIControl) +8084112c CtrlMenuMovieLayout::GetClassName(LayoutUIControl) +80841134 CtrlMenuMovieLayout::GetRuntimeTypeInfo(LayoutUIControl) +8084113c CtrlMenuBackButton::GetClassName +80841148 CtrlMenuDummyBack::GetClassName +80841158 CtrlMenuPageTitleText::GetClassName +80841168 CtrlMenuInstructionText::GetClassName +80841178 CtrlMenuObiTop::GetClassName +80841188 CtrlMenuObiBottom::GetClassName +80841198 CtrlMenuBackButton::OnUpdate +808412e0 CtrlMenuBackButton::OnInit +80841338 CtrlMenuBackButton::SetPositionAnim +808413a4 CtrlMenuPageTitleTextText::Load +80841538 CtrlMenuBackButton::SetPlayerBitfield +80841548 CtrlMenuDummyBack::Load +8084164c CtrlMenuDummyBack::OnUpdate +808417a4 CtrlMenuPageTitleText::SetMessage +808417c0 CtrlMenuPageTitleText::SetPositionAnim +8084182c CtrlMenuInstructionText::Load +808418c4 CtrlMenuInstructionText::SetPositionAnim +80841960 CtrlMenuInstructionText::SetMessage +80841990 CtrlMenuObiTop::SetPositionAnim +808419e8 0x808419e8 +80841a40 0x80841a40 +80841a98 0x80841a98 +80841aa4 CtrlMenuObiTop::__dt +80841afc CtrlMenuObiTop::GetRuntimeTypeInfo +80841b08 0x80841b08 +80841b14 CtrlMenuPageTitleText::GetRuntimeTypeInfo +80841b20 CtrlMenuDummyBack::GetRuntimeTypeInfo +80841b2c CtrlMenuBackButton::GetRuntimeTypeInfo +80841b38 CtrlMenuText_cpp_sinit_ +80841b6c CtrlRaceBattleSetPoint::GetClassName +80841b78 CtrlRaceBattleSetPoint::Load +80841c8c CtrlRaceBattleSetPoint::InitSelf +80841fac CtrlRaceBattleSetPoint::__dt +80842004 CtrlRaceBattleSetPoint::GetRuntimeTypeInfo +80842010 CtrlRaceCount_cpp_sinit +80842024 CtrlRaceGhostDiffTime::GetClassName +80842030 CtrlRaceGhostDiffTime::Init +808420e4 CtrlRaceGhostDiffTime::OnUpdate +8084235c CtrlRaceGhostDiffTime::AddTimers +808423fc CtrlRaceGhostDiffTime::SubtractTimers +8084247c CtrlRaceGhostDiffTime::Load +8084252c CtrlRaceGhostDiffTime::__dt +808425b0 0x808425b0 +808425bc 0x808425bc +808425d0 0x808425d0 +808425dc 0x808425dc +8084264c 0x8084264c +80842650 0x80842650 +80842654 0x80842654 +80842664 0x80842664 +808426b8 0x808426b8 +8084276c 0x8084276c +808427fc 0x808427fc +80842858 0x80842858 +80842864 0x80842864 +808428c0 0x808428c0 +808428cc 0x808428cc +808428e8 CtrlRaceScore::GetClassName +808428f4 CtrlRaceScore::InitSelf +80842a48 CtrlRaceScore::OnUpdate +80842b10 CtrlRaceScore::Load +80842b6c CtrlRaceScore::SetMessage +80842d44 CtrlRaceScore::__dt +80842da0 CtrlRaceTime::GetRuntimeTypeInfo +80842dac CtrlRaceTime_cpp_sinit_ +80842dc0 CtrlRaceWifiStartMessage::GetClassName +80842dcc CtrlRaceWifiStartMessage::Load +80842fdc CtrlRaceWifiStartMessage::HasStarted +80843010 CtrlRaceWifiStartMessage::IsInactive +80843020 CtrlRaceWifiStartMessage::SetPanePosition +8084306c CtrlRaceWifiStartMessage::OnUpdate +8084307c CtrlRaceWifiFinishMessage::GetClassName +8084308c CtrlRaceWifiFinishMessage::Load +80843140 CtrlRaceWifiFinishMessage::HasStarted +808431c0 CtrlRaceWifiFinishMessage::IsInactive +808431c8 CtrlRaceWifiFinishMessage::SetPanePosition +808433c4 CtrlRaceWifiFinishMessage::OnUpdate +808433d4 CtrlRaceWaitSymbol::GetClassName +808433e4 CtrlRaceWaitSymbol::Load +808434a0 CtrlRaceWaitSymbol::HasStarted +808434d4 CtrlRaceWaitSymbol::IsInactive +808434e4 CtrlRaceWaitSymbol::SetPanePosition +80843530 CtrlRaceWaitSymbol::OnUpdate +80843540 CtrlRaceWaitSymbol::GetPane +80843548 CtrlRaceWaitSymbol::__dt +808435a4 CtrlRaceWaitSymbol::GetRuntimeTypeInfo +808435b0 CtrlRaceWifiFinishMessage::GetPane +808435b8 CtrlRaceWifiFinishMessage::__dt +80843614 CtrlRaceWifiFinishMessage::GetRuntimeTypeInfo +80843620 CtrlRaceWifiStartMessage::GetPane +80843628 CtrlRaceWifiStartMessage::__dt +80843684 CtrlRaceWifiStartMessage::GetRuntimeTypeInfo +80843690 CtrlRaceWifi_cpp_sinit_ +808436b0 GeoHitTableHolder::__ct +808437f4 0x808437f4 +808438a4 Objects::Airblock::LoadCollision +808439c4 Objects::Airblock::UpdateCollision +80843a90 Objects::Airblock::vf_0xb4 +80843b5c Objects::Airblock::GetCollisionDiameter +80843b84 Objects::Airblock::IsCollidingNoTerrainInfo +80843b88 Objects::Airblock::IsCollidingAddEntryNoTerrainInfo +80843b8c Objects::Airblock::vf_0xfc +80843b90 Objects::Airblock::IsCollidingAddEntry +80843b94 Objects::Airblock::IsCollidingNoTerrainInfoNoTriangleCheck(no radius) +80843ba4 Objects::Airblock::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck(no radius) +80843bb4 Objects::Airblock::IsColliding(no radius) +80843bc4 Objects::Airblock::IsCollidingNoTriangleCheck(no radius) +80843bd4 Objects::Airblock::IsCollidingNoTerrainInfoNoTriangleCheck +80843bd8 Objects::Airblock::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +80843bdc Objects::Airblock::IsColliding +80843be0 Objects::Airblock::IsCollidingNoTriangleCheck +80843be4 Objects::Airblock::vf_0xc0 +80843bf4 Objects::Airblock::vf_0xc4 +80843c04 Objects::Airblock::vf_0xc8 +80843c14 Objects::Airblock::vf_0xcc +80843c24 Objects::Airblock::Update +80843c28 Objects::Airblock::GetPropertiesBitfield +80843c30 Objects::Airblock::__dt +80843c70 Objects::Airblock::IsCollidingNoTerrainInfoImpl +80843f34 Objects::Airblock::IsCollidingAddEntryNoTerrainInfoImplImpl +80844218 0x80844218 +8084483c Objects::Airblock::IsCollidingAddEntryImpl +80844e78 0x80844e78 +80844f40 0x80844f40 +8084506c 0x8084506c +80845090 0x80845090 +808452e8 0x808452e8 +8084548c 0x8084548c +808458ac 0x808458ac +80845b4c 0x80845b4c +80845c1c 0x80845c1c +80845c90 0x80845c90 +80845c9c 0x80845c9c +80845d34 0x80845d34 +80845d3c 0x80845d3c +80845d44 0x80845d44 +80845d84 0x80845d84 +80845d90 0x80845d90 +80845d98 0x80845d98 +80845da4 0x80845da4 +80845db0 0x80845db0 +80845df0 Objects::bblock::__dt +80845e30 Objects::DKturibashiGCc::__ct +80845ebc Objects::DKturibashiGCc::OnStart +80846008 Objects::DKturibashiGCc::Update +80846248 0x80846248 +80846328 0x80846328 +808464b8 Objects::DKturibashiGCc::UpdateOtherEntityPos +8084664c Objects::DKturibashiGCc::UpdateOtherEntityPosWithRot +80846810 Objects::DKturibashiGCc::vf_0x11c +80846818 Objects::DKturibashiGCc::vf_0x108 +80846824 Objects::DKturibashiGCc::AreItemsAllowed +8084682c Objects::DKturibashiGCc::IsCollidingAddEntryNoTerrainInfo +80846830 Objects::DKturibashiGCc::IsCollidingAddEntryNoTerrainInfo +80846834 Objects::DKturibashiGCc::vf_0xfc +80846838 Objects::DKturibashiGCc::IsCollidingAddEntry +8084683c Objects::DKturibashiGCc::IsCollidingNoTerrainInfo(no radius) +8084684c Objects::DKturibashiGCc::IsCollidingAddEntryNoTerrainInfo(no radius) +8084685c Objects::DKturibashiGCc::vf_0xec(no radius) +8084686c Objects::DKturibashiGCc::IsCollidingAddEntry(no radius) +8084687c Objects::DKturibashiGCc::IsCollidingNoTerrainInfoNoTriangleCheck +80846880 Objects::DKturibashiGCc::IsCollidingAddEntryNoTerrainInfoNoTriangleCheck +80846884 Objects::DKturibashiGCc::IsColliding +80846888 Objects::DKturibashiGCc::IsCollidingNoTriangleCheck +8084688c Objects::DKturibashiGCc::vf_0xc0 +8084689c Objects::DKturibashiGCc::vf_0xc4 +808468ac Objects::DKturibashiGCc::vf_0xc8 +808468bc Objects::DKturibashiGCc::vf_0xcc +808468cc Objects::DKturibashiGCc::GetCollisionDiameter +808468e0 Objects::DKturibashiGCc::LoadAnimations +808468e4 Objects::DKturibashiGCc::vf_0xb4 +808468e8 Objects::DKturibashiGCc::UpdateCollision +808468ec 0x808468ec +808468f0 Objects::DKturibashiGCc::GetPropertiesBitfield +808468f8 Objects::DKturibashiGCc::__dt +80846938 0x80846938 +80846c84 0x80846c84 +80847008 0x80847008 +808474f4 Objects::DKturibashiGCc::IsCollidingImpl +80847a00 Objects::TownBridgeDS::__ct +80847b70 Objects::TownBridgeDS::LoadCollision +80847d2c Objects::TownBridgeDS::Update +80848294 0x80848294 +8084857c 0x8084857c +808485d4 0x808485d4 +808486a8 Objects::TownBridgeDS::CalcOtherEntityDistance +80848a64 Objects::TownBridgeDS::UpdateOtherEntityPosWithRot +80848e6c Objects::TownBridgeDS::vf_0x11c +80848e74 Objects::TownBridgeDS::vf_0x108 +80848e80 Objects::TownBridgeDS::AreItemsAllowed +80848e88 Objects::TownBridgeDS::GetPeriod +80848e94 Objects::TownBridgeDS::LoadAnimations +80848f1c Objects::TownBridgeDS::GetTransformationMatrix +80849290 Objects::TownBridgeDS::GetPropertiesBitfield +80849298 Objects::TownBridgeDS::__dt +808492d8 0x808492d8 +80849418 0x80849418 +80849610 0x80849610 +80849618 0x80849618 +8084978c 0x8084978c +80849814 0x80849814 +8084990c 0x8084990c +80849cd8 0x80849cd8 +80849ce0 0x80849ce0 +8084a010 0x8084a010 +8084a2d8 0x8084a2d8 +8084a688 0x8084a688 +8084aa84 0x8084aa84 +8084ab7c 0x8084ab7c +8084af74 0x8084af74 +8084af80 0x8084af80 +8084b010 0x8084b010 +8084b01c 0x8084b01c +8084b024 0x8084b024 +8084b064 MenuModelBRRESHandle::__ct +8084b07c MenuModelBRRESHandle::__dt +8084b0bc 0x8084b0bc +8084b138 MenuModelBRRESHandle::BindDriverBRRES +8084b328 MenuModelBRRESHandle::BindKartBRRES +8084b438 MenuModelBRRESHandle::BindBackBRRES +8084b52c DriverModelAnmCalculator::__dt +8084b56c MenuModelBRRESHandle::LoadDriverModel +8084b8a4 MenuModelBRRESHandle::LinkDriverAnim +8084bba0 MenuModelBRRESHandle::LoadKartModel +8084bcf4 MenuModelBRRESHandle::LoadBackModel +8084bdbc MenuModelBRRESHandle::MdlExists +8084bdcc Objects::WLscreenGC::__ct +8084be94 Objects::WLscreenGC::__dt +8084bf34 Objects::WLscreenGC::LoadModels +8084c0d8 Objects::WLscreenGC::OnStart +8084c0dc Objects::WLscreenGC::Update +8084c0e0 BackModelMgr::__ct +8084c1ac BackModelMgr::__dt +8084c1ec BackModelMgr::Start +8084c2d0 BackModelMgr::Update +8084c458 BackModelMgr::SetBackModel +8084c524 BackModelMgr::ToggleVisible +8084c538 MenuDriverModel::__ct +8084c590 MenuVehicleDisplayModel::__dt +8084c5d0 MenuDriverModel::Init +8084c768 0x8084c768 +8084c850 MenuDriverModel::SwitchState +8084cbe4 MenuDriverModel::Update +8084cd78 0x8084cd78 +8084ce0c 0x8084ce0c +8084ce58 MenuDriverModelMgr::__ct +8084d3e0 MenuDriverModel::__dt +8084d420 0x8084d420 +8084d488 MenuDriverModel::Update +8084d734 MenuModel::ToggleVisible +8084d758 MenuDriverModel::Draw +8084d914 MenuDriverModelMgr::TogglePlayerModel +8084d93c MenuDriverModelMgr::PrepareDriverOnKartAnms +8084d9d8 MenuDriverModel::SetPlayerCharacter +8084dd24 0x8084dd24 +8084ddd8 0x8084ddd8 +8084e124 0x8084e124 +8084e20c 0x8084e20c +8084e3fc 0x8084e3fc +8084e7cc 0x8084e7cc +8084e8ac MenuDriverModelMgr::__dt +8084e8ec MenuModel::Update +8084e8f0 MenuModel::Init +8084e8f4 DriverModelAnmCalculator::Determine +8084e9f8 DriverModelAnmCalculator::GetPrefix +8084eaf4 0x8084eaf4 +8084eb28 0x8084eb28 +8084eb30 0x8084eb30 +8084eb88 0x8084eb88 +8084ebe0 0x8084ebe0 +8084ec38 MenuKartModel::__ct +8084ec5c MenuKartModel::__dt +8084ec9c MenuKartModel::Load +8084ef18 MenuKartModel::Init +8084f434 MenuKartModel::Update +8084f7c0 MenuKartModelMgr::__ct +8084f994 0x8084f994 +8084f998 0x8084f998 +8084f9d8 MenuKartModelMgr::Load +8084fc70 0x8084fc70 +8084fce4 MenuKartModelMgr::Update +8084fe9c MenuKartModelMgr::Draw +8084ff68 MenuKartModelMgr::SetKartModel +8084ffc0 MenuKartModelMgr::Reset +80850084 MenuKartModelMgr::ToggleVisible +8085011c 0x8085011c +8085014c MenuKartModelMgr::GetMenuKartModel +80850178 0x80850178 +808501b8 Pages::BattleCupSelect::GetPageById +808502c8 Pages::BattleCupSelect::OnInit +80850340 Pages::BattleCupSelect::CreateExternalControl +80850348 Pages::BattleCupSelect::CreateControl +808503dc Pages::BattleCupSelect::OnActivate +8085074c Pages::BattleCupSelect::AfterControlUpdate +808508a8 Pages::BattleCupSelect::UpdateText +808508b4 Pages::BattleCupSelect::LoadNextPage +808509ec Pages::BattleCupSelect::OnButtonClick +80850c5c Pages::BattleCupSelect::OnExternalButtonSelect +80850c60 Pages::BattleCupSelect::OnButtonDeselect +80850c64 Pages::BattleCupSelect::OnBackPress +80850ed4 Pages::BattleCupSelect::OnResume +808510ec Pages::BattleCupSelect::OnDeactivate +808510f0 Pages::BattleCupSelect::BeforeEntranceAnimations +8085114c Pages::BattleCupSelect::BeforeExitAnimations +808511a8 Pages::BattleCupSelect::OnTimeout +808512a4 Pages::BattleCupSelect::GetPlayerBitfield +808512ac Pages::BattleCupSelect::GetActivePlayerBitfield +808512b4 Pages::BattleCupSelect::SetButtonHandlers +80851310 Pages::BattleCupSelect::GetManipulatorManager +80851318 Pages::BattleCupSelect::__dt +8085140c Pages::BattleCupSelect::GetRuntimeTypeInfo +80851418 BattleCupSelectPage_sinit_ +8085142c Pages::BattleKartSelect::GetPageById +8085153c Pages::BattleKartSelect::OnInit +80851550 Pages::BattleKartSelect::CreateExternalControl +80851638 Pages::BattleKartSelect::SetButtonHandlers +80851694 Pages::BattleKartSelect::CreateControl +808517b0 Pages::BattleKartSelect::OnActivate +80851ae4 Pages::BattleKartSelect::AfterControlUpdate +80851c70 Pages::BattleKartSelect::OnButtonClick +80851dfc Pages::BattleKartSelect::OnExternalButtonSelect +80851ed0 Pages::BattleKartSelect::OnButtonDeselect +80851ed8 Pages::BattleKartSelect::OnBackPress +80851fac Pages::BattleKartSelect::Func_8083ac54 +808520ac Pages::BattleKartSelect::Func_8083ad54 +80852294 Pages::BattleKartSelect::BeforeEntranceAnimations +808522f4 Pages::BattleKartSelect::BeforeExitAnimations +80852354 Pages::BattleKartSelect::GetPlayerBitfield +8085235c Pages::BattleKartSelect::GetLocalPlayerCount +80852364 Pages::BattleKartSelect::GetManipulatorManager +8085236c Pages::BattleKartSelect::__dt +80852418 0x80852418 +80852424 BattleSettingsPage_cpp_sinit_ +80852438 Pages::BattleStageSelect::GetPageById +80852548 Pages::BattleStageSelect::OnInit +80852598 Pages::BattleStageSelect::CreateExternalControl +808525a0 Pages::BattleStageSelect::CreateControl +80852634 Pages::BattleStageSelect::OnActivate +80852788 Pages::BattleStageSelect::BeforeEntranceAnimations +808527a8 Pages::BattleStageSelect::AfterControlUpdate +808528c4 Pages::BattleStageSelect::UpdateBottomText +808528c8 Pages::BattleStageSelect::LoadNextPage +808529fc Pages::BattleStageSelect::OnButtonClick +80852a34 Pages::BattleStageSelect::OnExternalButtonSelect +80852a38 Pages::BattleStageSelect::OnButtonDeselect +80852a3c Pages::BattleStageSelect::OnBackPress +80852a74 Pages::BattleStageSelect::BeforeExitAnimations +80852ad0 Pages::BattleStageSelect::OnDeactivate +80852ad4 Pages::BattleStageSelect::OnTimeout +80852ba8 Pages::BattleStageSelect::GetPlayerBitfield +80852bb0 Pages::BattleStageSelect::GetActivePlayerBitfield +80852bb8 Pages::BattleStageSelect::SetButtonHandlers +80852c14 Pages::BattleStageSelect::__dt +80852d00 Pages::BattleStageSelect::GetRuntimeTypeInfo +80852d0c CupSelectPagecpp_sinit_ +80852d20 Pages::StartRace::GetPageById +80852e30 Pages::StartRace::OnInit +80852e48 Pages::StartRace::CreateExternalControl +80852fac Pages::StartRace::GetActivePlayerBitfield +80852fb4 Pages::StartRace::SetButtonHandlers +80853010 Pages::StartRace::CreateControl +8085326c Pages::StartRace::OnActivate +808532e0 Pages::StartRace::AfterControlUpdate +80853314 Pages::StartRace::OnButtonClick +80853370 Pages::StartRace::OnExternalButtonSelect +80853374 Pages::StartRace::OnButtonDeselect +80853378 Pages::StartRace::OnBackPress +80853394 Pages::StartRace::GetPlayerBitfield +8085339c Pages::StartRace::GetManipulatorManager +808533a4 Pages::StartRace::__dt +80853424 Pages::StartRace::GetRuntimeTypeInfo +80853430 StartRacePage_cpp_sinit_ +80853444 0x80853444 +80853554 0x80853554 +80853778 0x80853778 +8085381c 0x8085381c +8085388c 0x8085388c +80853978 0x80853978 +80853980 0x80853980 +80853984 0x80853984 +80853d50 0x80853d50 +80853d64 0x80853d64 +80853d68 0x80853d68 +80854050 0x80854050 +80854058 0x80854058 +808540b4 0x808540b4 +808540bc 0x808540bc +80854160 0x80854160 +8085416c 0x8085416c +80854180 0x80854180 +80854290 0x80854290 +808542c8 0x808542c8 +808542d0 0x808542d0 +80854364 0x80854364 +808543ac 0x808543ac +808543b0 0x808543b0 +808543bc 0x808543bc +80854418 0x80854418 +8085442c 0x8085442c +80854430 0x80854430 +80854434 0x80854434 +80854440 0x80854440 +8085448c 0x8085448c +808544e0 0x808544e0 +80854534 0x80854534 +8085453c 0x8085453c +80854544 0x80854544 +808545a0 0x808545a0 +808545a8 0x808545a8 +8085469c 0x8085469c +808546a8 0x808546a8 +808546bc 0x808546bc +808547cc 0x808547cc +8085483c 0x8085483c +808548c8 0x808548c8 +80854938 0x80854938 +80854a1c 0x80854a1c +80854a20 0x80854a20 +80854b04 0x80854b04 +80854b3c 0x80854b3c +80854b40 Pages::Menu::UnloadVideoSource +80854b4c 0x80854b4c +80854b50 0x80854b50 +80854b58 0x80854b58 +80854b60 0x80854b60 +80854bbc 0x80854bbc +80854bc4 0x80854bc4 +80854c64 0x80854c64 +80854c70 0x80854c70 +80854c84 0x80854c84 +80854d94 0x80854d94 +80854da8 0x80854da8 +80854db0 0x80854db0 +80854e44 Pages::Menu::OnActivate +80854e48 0x80854e48 +80854e68 0x80854e68 +80854e6c 0x80854e6c +80854e70 0x80854e70 +80854ecc 0x80854ecc +80854f28 0x80854f28 +80854f2c 0x80854f2c +80854f30 0x80854f30 +80854f80 0x80854f80 +80854fd4 0x80854fd4 +80855020 0x80855020 +80855028 0x80855028 +80855030 0x80855030 +8085508c 0x8085508c +80855178 0x80855178 +80855184 MultiKartSelectPage_cpp_sinit_ +80855198 Pages::MultiDriftSelect::GetPageById +808552a8 Pages::MultiDriftSelect::OnInit +80855760 Pages::MultiDriftSelect::GetManipulatorManager +80855768 Pages::MultiDriftSelect::GetActivePlayerBitfield +80855770 Pages::MultiDriftSelect::GetPlayerBitfield +80855778 Pages::MultiDriftSelect::SetButtonHandlers +808557d4 Pages::MultiDriftSelect::OnControlsInitialized +808557d8 Pages::MultiDriftSelect::CreateExternalControl +80855934 Pages::MultiDriftSelect::CreateControl +80855a64 Pages::MultiDriftSelect::OnActivate +80855b6c Pages::MultiDriftSelect::AfterControlUpdate +80855ce4 Pages::MultiDriftSelect::OnButtonClick +80855fd0 Pages::MultiDriftSelect::OnExternalButtonSelect +80855fd4 Pages::MultiDriftSelect::OnButtonDeselect +80855fd8 Pages::MultiDriftSelect::OnBackPress +808560a8 Pages::MultiDriftSelect::OnResume +80856168 Pages::MultiDriftSelect::__dt +808561e8 Pages::MultiDriftSelect::GetRuntimeTypeInfo +808561f4 MultiDriftSelectPage_cpp_sinit_ +80856208 Pages::MultiTeamSelect::GetPageById +80856318 Pages::MultiTeamSelect::OnInit +808567e0 Pages::MultiTeamSelect::GetManipulatorManager +808567e8 Pages::MultiTeamSelect::GetActivePlayerBitfield +808567f0 Pages::MultiTeamSelect::GetPlayerBifield +808567f8 Pages::MultiTeamSelect::SetButtonHandlers +80856854 Pages::MultiTeamSelect::OnControlsInitialized +80856858 Pages::MultiTeamSelect::BeforeEntranceAnimations +80856900 Pages::MultiTeamSelect::BeforeExitAnimations +808569a8 Pages::MultiTeamSelect::CreateExternalControl +80856af8 Pages::MultiTeamSelect::CreateControl +80856c28 Pages::MultiTeamSelect::OnActivate +80856ef8 Pages::MultiTeamSelect::AfterControlUpdate +80856efc Pages::MultiTeamSelect::OnButtonClick +80857400 Pages::MultiTeamSelect::OnExternalButtonSelect +80857404 Pages::MultiTeamSelect::OnButtonDeselect +80857408 Pages::MultiTeamSelect::OnBackPress +80857514 Pages::MultiTeamSelect::OnResume +80857600 Pages::MultiTeamSelect::AssignCPUTeams +808577d8 Pages::MultiTeamSelect::IsDifferentTeams +80857834 Pages::MultiTeamSelect::__dt +808578b4 Pages::MultiTeamSelect::GetRuntimeTypeInfo +808578c0 MainMenuPage_cpp_sinit_ +808578d4 0x808578d4 +808579e4 0x808579e4 +808579f0 0x808579f0 +808579f8 0x808579f8 +80857af8 0x80857af8 +80857b64 0x80857b64 +80857b68 0x80857b68 +80857b7c 0x80857b7c +80857b80 0x80857b80 +80857b84 Pages::Menu::UnloadVideoSource +80857b90 0x80857b90 +80857b94 0x80857b94 +80857b9c 0x80857b9c +80857ba4 0x80857ba4 +80857c00 0x80857c00 +80857c08 0x80857c08 +80857c94 0x80857c94 +80857ca0 0x80857ca0 +80857cb4 Pages::VSModeSelect::GetPageById +80857dc4 Pages::VSModeSelect::OnInit +80857e18 Pages::VSModeSelect::GetManipulatorManager +80857e20 Pages::VSModeSelect::CreateExternalControl +80857fd0 Pages::VSModeSelect::CreateControl +80857fd8 Pages::VSModeSelect::OnActivate +80858490 Pages::VSModeSelect::OnActivate_switch +80858494 Pages::VSModeSelect::OnActivate_case_0 +808584ac Pages::VSModeSelect::OnActivate_case_1 +808584c4 Pages::VSModeSelect::OnActivate_case_2 +808584dc Pages::VSModeSelect::OnActivate_case_3 +808584f4 Pages::VSModeSelect::OnActivate_case_4 +8085850c Pages::VSModeSelect::OnActivate_case_5 +80858524 Pages::VSModeSelect::OnActivate_case_6 +8085853c Pages::VSModeSelect::OnActivate_case_7 +80858584 Pages::VSModeSelect::AfterControlUpdate +80858588 Pages::VSModeSelect::OnButtonClick +80858668 Pages::VSModeSelect::OnExternalButtonSelect +808586a0 Pages::VSModeSelect::OnButtonDeselect +808586a4 Pages::VSModeSelect::OnBackPress +808586b0 Pages::VSModeSelect::OnDeactivate +808586fc Pages::VSModeSelect::GetPlayerBitfield +80858704 Pages::VSModeSelect::GetActivePlayerBitfield +8085870c Pages::VSModeSelect::SetButtonHandlers +80858768 Pages::VSModeSelect::__dt +808587e8 0x808587e8 +808587f4 VSSettingsPage_cpp_sinit_ +80858808 Pages::Unlock::GetPageById +80858918 0x80858918 +80858968 Pages::Unlock::OnInit +80858980 Pages::Unlock::CreateExternalControl +80858a10 Pages::Unlock::CreateControl +80858c54 Pages::Unlock::OnActivate +80858e70 Pages::Unlock::AfterControlUpdate +80858fcc Pages::Unlock::OnButtonClick +80859298 Pages::Unlock::OnExternalButtonSelect +8085929c Pages::Unlock::OnButtonDeselect +808592a0 Pages::Unlock::OnBackPress +808592a4 Pages::Unlock::SetTitleBMG +80859360 Pages::Unlock::PrepareControls +808595d0 0x808595d0 +80859630 0x80859630 +80859690 Pages::Unlock::SetModels +8085978c Pages::Unlock::SetModels_switch +80859790 Pages::Unlock::SetModels_caseD_1b +8085979c Pages::Unlock::SetModels_caseD_10 +808597a4 Pages::Unlock::SetModels_caseD_d +808597b0 Pages::Unlock::SetModels_caseD_b +808597bc Pages::Unlock::SetModels_caseD_e +808597c8 Pages::Unlock::SetModels_caseD_11 +808597d4 Pages::Unlock::SetModels_caseD_12 +80859828 0x80859828 +80859878 0x80859878 +808598b4 0x808598b4 +80859950 Pages::Unlock::SetMessageWindowMessage +80859af4 0x80859af4 +80859c0c Pages::Unlock::GetPlayerBifield +80859c14 Pages::Unlock::GetActivePlayerBitfield +80859c1c Pages::Unlock::SetButtonHandlers +80859c78 Pages::Unlock::GetManipulatorManager +80859c80 Pages::Unlock::__dt +80859d30 Pages::Unlock::GetRuntimeTypeInfo +80859d3c 0x80859d3c +80859d50 Pages::GPVSLeaderboardUpdate::OnInit +80859e64 Pages::GPVSLeaderboardUpdate::GetRowCount +80859e74 Pages::GPVSLeaderboardUpdate::CanEnd +80859f10 Pages::GPVSLeaderboardUpdate::Func_0x6c +8085a1c8 Pages::GPVSLeaderboardUpdate::FillRows +8085a2e4 Pages::GPVSLeaderboardUpdate::GetNextPage +8085a320 Pages::GPVSLeaderboardTotal::OnInit +8085a458 Pages::GPVSLeaderboardTotal::FillRows +8085a5b0 Pages::GPVSLeaderboardTotal::GetNextPage +8085a5f4 Pages::GPVSLeaderboardTotal::ComparePlayers +8085a688 Pages::WWLeaderboardUpdate::OnInit +8085a7fc Pages::WWLeaderboardUpdate::FillRows +8085aecc Pages::WWLeaderboardUpdate::GetNextPage +8085aed4 Pages::TTLeaderboard::OnInit +8085b0f4 Pages::TTLeaderboard::GetRowCount +8085b0fc Pages::TTLeaderboard::FillRows +8085b5b4 Pages::TTLeaderboard::GetNextPage +8085b7a4 0x8085b7a4 +8085bd1c 0x8085bd1c +8085bd24 0x8085bd24 +8085bd2c 0x8085bd2c +8085bd9c 0x8085bd9c +8085bda8 Pages::TTLeaderboard::__dt +8085be28 Pages::TTLeaderboard::GetRuntimeTypeInfo +8085be34 Pages::WWLeaderboardUpdate::__dt +8085bea4 Pages::WWLeaderboardUpdate::GetRuntimeTypeInfo +8085beb0 Pages::GPVSLeaderboardTotal::__dt +8085bf20 Pages::GPVSLeaderboardTotal::GetRuntimeTypeInfo +8085bf2c Pages::GPVSLeaderboardUpdate::__dt +8085bf9c Pages::GPVSLeaderboardUpdate::GetRuntimeTypeInfo +8085bfa8 0x8085bfa8 +8085bfb4 LeaderboardsPagescpp_sinit_ +8085bfe4 Pages::LicenseRecords::GetPageById +8085c0f4 Pages::LicenseRecords::OnInit +8085c19c Pages::LicenseRecords::CreateExternalControl +8085c248 Pages::LicenseRecords::CreateControl +8085c3a8 Pages::LicenseRecords::OnActivate +8085c414 Pages::LicenseRecords::AfterControlUpdate +8085c418 0x8085c418 +8085c4f4 Pages::LicenseRecords::OnExternalButtonSelect +8085c4f8 0x8085c4f8 +8085c4fc 0x8085c4fc +8085c524 0x8085c524 +8085c86c 0x8085c86c +8085c9a8 0x8085c9a8 +8085cb44 0x8085cb44 +8085cc5c 0x8085cc5c +8085cdf8 Pages::LicenseRecords::GetPlayerBitfield +8085ce00 Pages::LicenseRecords::GetActivePlayerBitfield +8085ce08 Pages::LicenseRecords::SetButtonHandlers +8085ce64 Pages::LicenseRecords::GetManipulatorManager +8085ce6c Pages::LicenseRecords::__dt +8085ceec Pages::LicenseRecords::GetRuntimeTypeInfo +8085cef8 LicenseRecordsPagecpp_sinit_ +8085cf0c 0x8085cf0c +8085cf74 0x8085cf74 +8085cf78 0x8085cf78 +8085cff4 0x8085cff4 +8085d05c 0x8085d05c +8085d0dc 0x8085d0dc +8085d144 0x8085d144 +8085d27c 0x8085d27c +8085d2f0 0x8085d2f0 +8085d348 0x8085d348 +8085d390 0x8085d390 +8085d468 0x8085d468 +8085d4c4 0x8085d4c4 +8085d504 0x8085d504 +8085d578 0x8085d578 +8085d660 0x8085d660 +8085d6d4 0x8085d6d4 +8085d73c 0x8085d73c +8085d784 0x8085d784 +8085d898 0x8085d898 +8085d918 0x8085d918 +8085d9fc 0x8085d9fc +8085da58 0x8085da58 +8085da98 0x8085da98 +8085db0c 0x8085db0c +8085db84 0x8085db84 +8085dbe4 0x8085dbe4 +8085dc30 0x8085dc30 +8085dd08 0x8085dd08 +8085dd64 0x8085dd64 +8085ddac 0x8085ddac +8085de20 0x8085de20 +8085de94 0x8085de94 +8085df08 0x8085df08 +8085df64 0x8085df64 +8085dfac 0x8085dfac +8085e020 0x8085e020 +8085e108 0x8085e108 +8085e17c 0x8085e17c +8085e1f0 0x8085e1f0 +8085e258 0x8085e258 +8085e298 0x8085e298 +8085e30c 0x8085e30c +8085e380 0x8085e380 +8085e464 0x8085e464 +8085e4d8 0x8085e4d8 +8085e54c 0x8085e54c +8085e5a8 0x8085e5a8 +8085e5e8 0x8085e5e8 +8085e65c 0x8085e65c +8085e6b8 0x8085e6b8 +8085e734 0x8085e734 +8085e7a0 0x8085e7a0 +8085e82c 0x8085e82c +8085e884 0x8085e884 +8085e968 0x8085e968 +8085e984 0x8085e984 +8085e988 0x8085e988 +8085e990 0x8085e990 +8085e998 0x8085e998 +8085e9a0 0x8085e9a0 +8085e9a8 0x8085e9a8 +8085e9b0 0x8085e9b0 +8085e9b8 0x8085e9b8 +8085e9c0 0x8085e9c0 +8085e9c8 0x8085e9c8 +8085e9d0 0x8085e9d0 +8085e9d8 0x8085e9d8 +8085e9e0 0x8085e9e0 +8085e9e8 0x8085e9e8 +8085e9f0 0x8085e9f0 +8085e9f8 0x8085e9f8 +8085ea00 0x8085ea00 +8085ea08 0x8085ea08 +8085ea10 0x8085ea10 +8085ea18 0x8085ea18 +8085ea20 0x8085ea20 +8085ea28 0x8085ea28 +8085ea30 0x8085ea30 +8085ea38 0x8085ea38 +8085ea40 0x8085ea40 +8085ea48 0x8085ea48 +8085ea50 0x8085ea50 +8085ea58 0x8085ea58 +8085ea60 0x8085ea60 +8085ea68 0x8085ea68 +8085ea70 0x8085ea70 +8085ea78 0x8085ea78 +8085ea80 0x8085ea80 +8085ea88 0x8085ea88 +8085ea98 0x8085ea98 +8085eab4 0x8085eab4 +8085eab8 0x8085eab8 +8085eac0 0x8085eac0 +8085eac8 0x8085eac8 +8085ead0 0x8085ead0 +8085ead8 0x8085ead8 +8085eae0 0x8085eae0 +8085eae8 0x8085eae8 +8085eaf0 0x8085eaf0 +8085eaf8 0x8085eaf8 +8085eb00 0x8085eb00 +8085eb08 0x8085eb08 +8085eb10 0x8085eb10 +8085eb18 0x8085eb18 +8085eb20 0x8085eb20 +8085eb28 0x8085eb28 +8085eb30 0x8085eb30 +8085eb38 0x8085eb38 +8085eb40 0x8085eb40 +8085eb48 0x8085eb48 +8085eb50 0x8085eb50 +8085eb58 0x8085eb58 +8085eb60 0x8085eb60 +8085eb68 0x8085eb68 +8085eb70 0x8085eb70 +8085eb78 0x8085eb78 +8085eb80 0x8085eb80 +8085eb88 0x8085eb88 +8085eb90 0x8085eb90 +8085eb98 0x8085eb98 +8085eba0 0x8085eba0 +8085eba8 0x8085eba8 +8085ebb0 0x8085ebb0 +8085ebb8 0x8085ebb8 +8085ebc0 0x8085ebc0 +8085ebc8 0x8085ebc8 +8085ebd0 0x8085ebd0 +8085ebd8 0x8085ebd8 +8085ebe0 0x8085ebe0 +8085ebe8 0x8085ebe8 +8085ebf0 0x8085ebf0 +8085ebf8 0x8085ebf8 +8085ec00 0x8085ec00 +8085ec08 0x8085ec08 +8085ec10 0x8085ec10 +8085ec18 0x8085ec18 +8085ec20 0x8085ec20 +8085ec28 0x8085ec28 +8085ec30 0x8085ec30 +8085ec38 0x8085ec38 +8085ec40 0x8085ec40 +8085ec48 0x8085ec48 +8085ec58 0x8085ec58 +8085ec7c 0x8085ec7c +8085ec98 0x8085ec98 +8085ec9c 0x8085ec9c +8085eca4 0x8085eca4 +8085ecac 0x8085ecac +8085ecb4 0x8085ecb4 +8085ecbc 0x8085ecbc +8085ecc4 0x8085ecc4 +8085eccc 0x8085eccc +8085ecd4 0x8085ecd4 +8085ecdc 0x8085ecdc +8085ece4 0x8085ece4 +8085ecec 0x8085ecec +8085ecf4 0x8085ecf4 +8085ecfc 0x8085ecfc +8085ed04 0x8085ed04 +8085ed14 0x8085ed14 +8085ed38 0x8085ed38 +8085ed58 0x8085ed58 +8085ed5c 0x8085ed5c +8085ed64 0x8085ed64 +8085ed6c 0x8085ed6c +8085ed74 0x8085ed74 +8085ed7c 0x8085ed7c +8085ed84 0x8085ed84 +8085ed8c 0x8085ed8c +8085ed94 0x8085ed94 +8085ed9c 0x8085ed9c +8085eda4 0x8085eda4 +8085edac 0x8085edac +8085edb4 0x8085edb4 +8085edbc 0x8085edbc +8085edc4 0x8085edc4 +8085edcc 0x8085edcc +8085edd4 0x8085edd4 +8085eddc 0x8085eddc +8085ede4 0x8085ede4 +8085edec 0x8085edec +8085edf4 0x8085edf4 +8085ee04 0x8085ee04 +8085ee6c 0x8085ee6c +8085ee94 0x8085ee94 +8085eec0 0x8085eec0 +8085eec4 0x8085eec4 +8085eed0 0x8085eed0 +8085eedc 0x8085eedc +8085eee8 0x8085eee8 +8085eef4 0x8085eef4 +8085ef00 0x8085ef00 +8085ef0c 0x8085ef0c +8085ef18 0x8085ef18 +8085ef28 0x8085ef28 +8085ef2c 0x8085ef2c +8085ef54 0x8085ef54 +8085ef7c 0x8085ef7c +8085ef9c 0x8085ef9c +8085efa0 0x8085efa0 +8085efac 0x8085efac +8085efb8 0x8085efb8 +8085efc4 0x8085efc4 +8085efd0 0x8085efd0 +8085efdc 0x8085efdc +8085efe8 0x8085efe8 +8085eff4 0x8085eff4 +8085f000 0x8085f000 +8085f00c 0x8085f00c +8085f018 0x8085f018 +8085f024 0x8085f024 +8085f030 0x8085f030 +8085f03c 0x8085f03c +8085f048 0x8085f048 +8085f054 0x8085f054 +8085f060 0x8085f060 +8085f068 0x8085f068 +8085f06c 0x8085f06c +8085f08c 0x8085f08c +8085f090 0x8085f090 +8085f09c 0x8085f09c +8085f0a8 0x8085f0a8 +8085f0b4 0x8085f0b4 +8085f0c0 0x8085f0c0 +8085f0cc 0x8085f0cc +8085f0d8 0x8085f0d8 +8085f0e4 0x8085f0e4 +8085f0f0 0x8085f0f0 +8085f0fc 0x8085f0fc +8085f108 0x8085f108 +8085f114 0x8085f114 +8085f120 0x8085f120 +8085f12c 0x8085f12c +8085f138 0x8085f138 +8085f144 0x8085f144 +8085f14c 0x8085f14c +8085f150 0x8085f150 +8085f170 0x8085f170 +8085f174 0x8085f174 +8085f180 0x8085f180 +8085f18c 0x8085f18c +8085f198 0x8085f198 +8085f1a4 0x8085f1a4 +8085f1b0 0x8085f1b0 +8085f1bc 0x8085f1bc +8085f1c8 0x8085f1c8 +8085f1d4 0x8085f1d4 +8085f1e0 0x8085f1e0 +8085f208 0x8085f208 +8085f230 0x8085f230 +8085f250 0x8085f250 +8085f254 0x8085f254 +8085f260 0x8085f260 +8085f26c 0x8085f26c +8085f278 0x8085f278 +8085f284 0x8085f284 +8085f290 0x8085f290 +8085f29c 0x8085f29c +8085f2a8 0x8085f2a8 +8085f2b4 0x8085f2b4 +8085f2c0 0x8085f2c0 +8085f2cc 0x8085f2cc +8085f2d8 0x8085f2d8 +8085f32c 0x8085f32c +8085f368 0x8085f368 +8085f36c 0x8085f36c +8085f378 0x8085f378 +8085f384 0x8085f384 +8085f390 0x8085f390 +8085f39c 0x8085f39c +8085f3a8 0x8085f3a8 +8085f3b4 0x8085f3b4 +8085f3c0 0x8085f3c0 +8085f3f8 0x8085f3f8 +8085f3fc 0x8085f3fc +8085f424 0x8085f424 +8085f428 0x8085f428 +8085f434 0x8085f434 +8085f440 0x8085f440 +8085f44c 0x8085f44c +8085f458 0x8085f458 +8085f464 0x8085f464 +8085f470 0x8085f470 +8085f47c 0x8085f47c +8085f488 0x8085f488 +8085f494 0x8085f494 +8085f4a0 0x8085f4a0 +8085f4ac 0x8085f4ac +8085f4b4 0x8085f4b4 +8085f4b8 0x8085f4b8 +8085f4f8 Audio::CharacterActor::__ct +8085f578 0x8085f578 +8085f5b8 Audio::RandomCharacterPicker::__dt +8085f614 Audio::RandomSoundPicker::__dt +8085f66c Audio::CharacterActor::Link +8085fa88 0x8085fa88 +8085fbc8 Audio::CharacterActor::Unlink +8085fbd0 Audio::CharacterActor::Update +80860294 Audio::CharacterActor::HoldSound +808602c0 Audio::CharacterActor::PlayCharacterSoundConditional +80860318 Audio::CharacterActor::PlayCharacterSoundConditional_switch +8086031c Audio::CharacterActor::PlayCharacterSoundConditional_case1a +80860398 Audio::CharacterActor::PlayCharacterSoundConditional_case1b +80860424 Audio::CharacterActor::PlayCharacterSoundConditional_case16 +80860444 Audio::CharacterActor::PlayCharacterSoundConditional_case17 +80860494 Audio::CharacterActor::PlayCharacterSoundConditional_caseb +808604a0 Audio::CharacterActor::PlayCharacterSoundConditional_casec +808604bc Audio::CharacterActor::PlayCharacterSoundConditional_case10 +808604e4 Audio::CharacterActor::PlayCharacterSound +808608bc 0x808608bc +80860c20 0x80860c20 +80860d08 0x80860d08 +80860f60 0x80860f60 +80861018 Audio::CharacterActor::PlayCharacterCollisionSound +80861050 0x80861050 +80861058 0x80861058 +80861060 0x80861060 +80861068 0x80861068 +80861078 0x80861078 +808610e8 0x808610e8 +80861104 0x80861104 +80861150 0x80861150 +80861184 0x80861184 +808611e8 Audio::CharacterActor::StartSound +80861294 0x80861294 +8086129c 0x8086129c +80861490 0x80861490 +808614e8 0x808614e8 +80861514 0x80861514 +80861534 0x80861534 +80861554 Audio::CharacterActor::StopSound +808615e8 0x808615e8 +80861668 0x80861668 +808617a4 0x808617a4 +808619b8 0x808619b8 +80861ad4 0x80861ad4 +80861b08 0x80861b08 +80861b20 0x80861b20 +80861b34 0x80861b34 +80861b9c Jumbotron_StopPlaying +80861bb0 0x80861bb0 +80861ce0 0x80861ce0 +80861d40 0x80861d40 +80861d68 0x80861d68 +80861dfc 0x80861dfc +80861eb4 0x80861eb4 +80861edc 0x80861edc +80861f58 Audio::CharacterActor::GetCharacterGroupId +80861fd4 Audio::CharacterActor::GetCharacterCannonGroupId +80862094 0x80862094 +808621f8 0x808621f8 +808626ec 0x808626ec +80862764 0x80862764 +808627d8 Audio::CharacterActor::__dt +808628dc Audio::CharacterActor::__dt(thunk) +808628e4 Audio::CharacterActor::StopSound(thunk) +808628ec Audio::CharacterActor::HoldSound(thunk) +808628f4 Audio::CharacterActor::StartSound(thunk) +808628fc Audio::CharacterActor::Update(thunk) +80862904 Audio::CharacterActor::Unlink(thunk) +8086290c Audio::CharacterActor::Link(thunk) +80862914 AudioRandomMgr::Disposer__dt +808629ac AudioRandomMgr::CreateInstance +80862a34 AudioRandomMgr::DestroyInstance +80862a68 AudioRandomMgr::__dt +80862b1c AudioRandomMgr::RandInt +80862b50 AudioRandomMgr::RandFloat +80862b90 0x80862b90 +80862bf0 0x80862bf0 +80862c5c Audio::RandomCharacterPicker::__ct +80862ca0 0x80862ca0 +80862d04 0x80862d04 +80862d0c 0x80862d0c +80862dcc 0x80862dcc +80862e8c 0x80862e8c +80862f4c 0x80862f4c +8086300c 0x8086300c +808630b8 0x808630b8 +80863234 0x80863234 +80863358 0x80863358 +80863488 0x80863488 +80863580 0x80863580 +808635c0 0x808635c0 +808636f8 0x808636f8 +8086395c 0x8086395c +80863ad0 0x80863ad0 +80863b08 0x80863b08 +80863bb4 0x80863bb4 +80863cf0 cAIPad__ct +80863cfc 0x80863cfc +80863d10 0x80863d10 +80863ef0 0x80863ef0 +80863f58 0x80863f58 +80863fb8 0x80863fb8 +80864038 0x80864038 +8086419c 0x8086419c +808642b8 0x808642b8 +808642d0 0x808642d0 +808643a8 0x808643a8 +80864498 0x80864498 +808644b0 0x808644b0 +808645a0 0x808645a0 +808645b4 0x808645b4 +808645d0 0x808645d0 +808645e8 0x808645e8 +80864600 0x80864600 +80864614 0x80864614 +80864624 cTeam_GetPlayer +80864634 0x80864634 +8086465c 0x8086465c +80864678 0x80864678 +80864694 0x80864694 +80864778 0x80864778 +80864844 0x80864844 +808648bc thunk_0x808691fc +808648c0 0x808648c0 +808648e0 0x808648e0 +808648f0 0x808648f0 +808648fc 0x808648fc +80864908 0x80864908 +80864934 0x80864934 +80864a04 0x80864a04 +80864bd8 0x80864bd8 +80864c74 0x80864c74 +80864d20 0x80864d20 +80864d38 Audio::RandomSoundPicker::__ct +80864d7c 0x80864d7c +80864e0c 0x80864e0c +80864e40 0x80864e40 +80864fa0 0x80864fa0 +80865050 0x80865050 +808650ac 0x808650ac +80865178 0x80865178 +808651ec 0x808651ec +808651fc 0x808651fc +80865230 0x80865230 +80865298 0x80865298 +80865350 0x80865350 +80865384 0x80865384 +8086538c 0x8086538c +80865414 0x80865414 +80865454 0x80865454 +80865568 0x80865568 +808655a8 0x808655a8 +808656fc 0x808656fc +80865818 0x80865818 +808658f0 0x808658f0 +808659c4 0x808659c4 +80865ba0 0x80865ba0 +80865cac 0x80865cac +80865e24 0x80865e24 +80865e34 0x80865e34 +80865e48 0x80865e48 +808669a4 0x808669a4 +808669d0 0x808669d0 +808669dc 0x808669dc +80866be8 0x80866be8 +80866bf0 0x80866bf0 +80866bf8 0x80866bf8 +80866c00 0x80866c00 +80866c08 0x80866c08 +80866c2c 0x80866c2c +80866c3c 0x80866c3c +80866c40 0x80866c40 +80866c58 0x80866c58 +80866c78 0x80866c78 +80866d80 0x80866d80 +80866f2c 0x80866f2c +80866ff8 0x80866ff8 +8086704c 0x8086704c +80867064 0x80867064 +808671a4 0x808671a4 +80867410 0x80867410 +8086747c 0x8086747c +80867538 0x80867538 +808675d8 0x808675d8 +808677a8 0x808677a8 +808679b4 0x808679b4 +80867b88 0x80867b88 +80867c7c 0x80867c7c +80867d6c 0x80867d6c +80867e50 0x80867e50 +80867fb4 0x80867fb4 +80867fc8 0x80867fc8 +80868040 0x80868040 +8086868c 0x8086868c +808686fc 0x808686fc +8086886c 0x8086886c +80868924 0x80868924 +80868930 0x80868930 +808689e8 GoalOverlay_SceneCreated +808689f4 0x808689f4 +80868d54 0x80868d54 +80869018 0x80869018 +80869998 0x80869998 +808699b8 0x808699b8 +80869c0c 0x80869c0c +8086a69c 0x8086a69c +8086a6b0 0x8086a6b0 +8086a81c 0x8086a81c +8086ac1c 0x8086ac1c +8086ae88 0x8086ae88 +8086b478 0x8086b478 +8086b5cc 0x8086b5cc +8086b73c 0x8086b73c +8086bb44 0x8086bb44 +8086c8fc 0x8086c8fc +8086c940 0x8086c940 +8086c9c8 0x8086c9c8 +8086cebc 0x8086cebc +8086d048 0x8086d048 +8086d3e0 0x8086d3e0 +8086d654 0x8086d654 +8086d784 0x8086d784 +8086d9b4 0x8086d9b4 +8086d9c0 0x8086d9c0 +8086e29c 0x8086e29c +8086e2a0 0x8086e2a0 +8086e440 0x8086e440 +8086e4b4 0x8086e4b4 +8086e4cc 0x8086e4cc +8086e4d0 0x8086e4d0 +8086e594 0x8086e594 +8086e59c 0x8086e59c +8086e684 0x8086e684 +8086e714 0x8086e714 +8086e778 0x8086e778 +8086ecc8 0x8086ecc8 +8086eccc 0x8086eccc +8086ed0c 0x8086ed0c +8086ed74 0x8086ed74 +8086f28c 0x8086f28c +8086fdac 0x8086fdac +8086fdec 0x8086fdec +8086fdf4 0x8086fdf4 +8086fe34 0x8086fe34 +8086fe3c 0x8086fe3c +8086fe7c 0x8086fe7c +8086fe84 0x8086fe84 +8086fec4 0x8086fec4 +8086ff04 0x8086ff04 +8086ff0c 0x8086ff0c +8086ff4c 0x8086ff4c +8086ff54 0x8086ff54 +8086ff94 0x8086ff94 +8086ff9c 0x8086ff9c +80870e8c 0x80870e8c +80870ef0 0x80870ef0 +80870f54 0x80870f54 +80870f94 0x80870f94 +80871000 0x80871000 +80871008 0x80871008 +8087106c 0x8087106c +808710d8 0x808710d8 +80871144 0x80871144 +808711ac 0x808711ac +808711ec 0x808711ec +80871250 0x80871250 +80871258 0x80871258 +80871298 0x80871298 +808712fc 0x808712fc +80871304 0x80871304 +80871344 0x80871344 +808713a8 0x808713a8 +808713b0 0x808713b0 +808713f0 0x808713f0 +80871420 0x80871420 +80871460 0x80871460 +80871490 0x80871490 +808714d0 0x808714d0 +80871500 0x80871500 +80871540 0x80871540 +808715ac 0x808715ac +808715b4 0x808715b4 +808715f4 0x808715f4 +80871658 0x80871658 +80871660 0x80871660 +808716a0 0x808716a0 +808716e0 0x808716e0 +80871710 0x80871710 +808745bc 0x808745bc +80874624 0x80874624 +8087468c 0x8087468c +80874704 0x80874704 +8087476c 0x8087476c +808747d4 0x808747d4 +8087484c 0x8087484c +808748b4 0x808748b4 +8087491c 0x8087491c +80874984 0x80874984 +808749ec 0x808749ec +80874a40 0x80874a40 +80874a94 0x80874a94 +80874ae8 0x80874ae8 +80874b60 0x80874b60 +80874bc8 0x80874bc8 +80874c1c 0x80874c1c +80874c38 0x80874c38 +80874c3c 0x80874c3c +80875e00 0x80875e00 +80875e90 0x80875e90 +80875f7c 0x80875f7c +80876008 0x80876008 +8087635c 0x8087635c +808764f8 0x808764f8 +808765d0 0x808765d0 +808766d0 0x808766d0 +808766d4 0x808766d4 +808766dc 0x808766dc +808766e4 0x808766e4 +808766ec 0x808766ec +808766f4 0x808766f4 +80876774 0x80876774 +808767b8 0x808767b8 +80876e8c 0x80876e8c +80876e90 0x80876e90 +80876ed0 0x80876ed0 +80876ed4 0x80876ed4 +80876f14 0x80876f14 +80877008 0x80877008 +80877048 0x80877048 +808770c0 obj_casino_roulette::__ct +80877188 obj_casino_roulette_generateBigassLongListOfFloatsForRotation +808773d0 0x808773d0 +80877694 obj_casino_roulette_spinVisually +80877714 obj_casino_roulette_update +808777dc obj_casino_roulette_spinEverythingElse +80877bc0 obj_casino_roulette_calculateSpin +80877d18 obj_casino_roulette_spinPlayer +80877f4c obj_casino_roulette_initDushBoardAnimationSpeed? +80877fc8 0x80877fc8 +80877fd4 0x80877fd4 +80878054 0x80878054 +8087805c 0x8087805c +80878064 0x80878064 +80878074 0x80878074 +8087807c 0x8087807c +808780bc Objects::WLwallGC::__ct +80878284 Objects::WLwallGC::__dt +808782d4 Objects::WLwallGC::OnStart +808783a8 0x808783a8 +808783d0 Objects::WLwallGC::GetTransformationMatrix +80878538 Objects::WLwallGC::Update +808786b0 Objects::WLwallGC::CalcOtherEntityDistance +808786d8 Objects::WLwallGC::UpdateOtherEntityPos +80878758 Objects::WLwallGC::IsCollidingAddEntryNoTriangleCheckImpl +808789d8 Objects::WLwallGC::IsCollidingImpl +80878a70 Objects::WLwallGC::GetPropertiesBitfield +80878a78 Objects::WLwallGC::GetPeriod +80878ab4 Objects::WLwallGC::vf_0x11c +80878abc 0x80878abc +80878db8 0x80878db8 +80878e44 0x80878e44 +80878f14 0x80878f14 +80879c08 0x80879c08 +8087a20c 0x8087a20c +8087a220 0x8087a220 +8087a240 0x8087a240 +8087a260 0x8087a260 +8087a268 0x8087a268 +8087a3ac 0x8087a3ac +8087a488 0x8087a488 +8087a590 0x8087a590 +8087a594 0x8087a594 +8087a59c 0x8087a59c +8087ac88 0x8087ac88 +8087ad54 0x8087ad54 +8087ae54 0x8087ae54 +8087afb4 0x8087afb4 +8087afd4 0x8087afd4 +8087b1c8 0x8087b1c8 +8087b2ac 0x8087b2ac +8087b394 0x8087b394 +8087b514 0x8087b514 +8087b5b4 0x8087b5b4 +8087b788 0x8087b788 +8087ba84 0x8087ba84 +8087bc64 0x8087bc64 +8087d388 0x8087d388 +8087d3d8 0x8087d3d8 +8087d7f4 0x8087d7f4 +8087d9fc 0x8087d9fc +8087da10 0x8087da10 +8087dc28 0x8087dc28 +8087dc78 0x8087dc78 +8087de6c 0x8087de6c +8087debc 0x8087debc +8087df28 0x8087df28 +8087e580 0x8087e580 +8087ebd0 0x8087ebd0 +8087ee44 0x8087ee44 +8087ef4c 0x8087ef4c +8087ef58 0x8087ef58 +8087ef60 0x8087ef60 +8087ef68 0x8087ef68 +8087ef6c 0x8087ef6c +8087ef70 0x8087ef70 +8087ef74 0x8087ef74 +8087ef78 0x8087ef78 +8087ef80 0x8087ef80 +8087ef84 0x8087ef84 +8087ef8c 0x8087ef8c +8087f01c 0x8087f01c +8087f388 0x8087f388 +8087f414 0x8087f414 +8087f768 0x8087f768 +80881d7c 0x80881d7c +80881ea4 0x80881ea4 +80882008 0x80882008 +8088201c 0x8088201c +808820a4 0x808820a4 +808820ac 0x808820ac +808820b4 0x808820b4 +80882144 obj_cruiserR::__ct +8088237c 0x8088237c +80882408 0x80882408 +80882660 0x80882660 +80882680 0x80882680 +80882728 0x80882728 +80882fa0 0x80882fa0 +80883584 0x80883584 +80883598 0x80883598 +808835e0 0x808835e0 +808835e8 0x808835e8 +808835f0 0x808835f0 +80883628 0x80883628 +80883684 0x80883684 +808836d4 0x808836d4 +808837b4 0x808837b4 +808838e4 0x808838e4 +8088392c 0x8088392c +80883934 0x80883934 +80883954 0x80883954 +8088395c 0x8088395c +80883a30 0x80883a30 +80883a70 0x80883a70 +80883b3c 0x80883b3c +80883b5c 0x80883b5c +80884034 0x80884034 +80884164 0x80884164 +80884170 0x80884170 +8088417c 0x8088417c +80884180 0x80884180 +808841d4 0x808841d4 +808841d8 0x808841d8 +808841e0 0x808841e0 +808841e4 0x808841e4 +808841e8 0x808841e8 +808841f0 0x808841f0 +80884394 0x80884394 +808843d4 0x808843d4 +8088469c 0x8088469c +80884740 0x80884740 +80884d3c 0x80884d3c +80884e80 0x80884e80 +80884ec4 0x80884ec4 +80885084 0x80885084 +80885090 0x80885090 +80885098 GetOneTimerLeadGroundContactAnims +808850a4 0x808850a4 +808850a8 0x808850a8 +80885164 0x80885164 +8088516c 0x8088516c +80885170 0x80885170 +80885174 0x80885174 +8088517c 0x8088517c +80885314 0x80885314 +80885370 0x80885370 +808853c0 0x808853c0 +80885578 0x80885578 +80885e64 0x80885e64 +80885e78 0x80885e78 +80885ec0 0x80885ec0 +80885ec8 0x80885ec8 +80885ee8 0x80885ee8 +80885ef0 0x80885ef0 +80885f80 obj_Twanwan::__ct +8088603c obj_Twanwan::__dt +8088608c obj_Twanwan_load +80886474 0x80886474 +80886548 0x80886548 +808866d4 0x808866d4 +8088744c obj_Twanwan_update +8088774c 0x8088774c +80887764 obj_Twanwan_draw_init +8088779c 0x8088779c +808878d8 0x808878d8 +8088791c 0x8088791c +80887990 0x80887990 +80887998 0x80887998 +808879d0 0x808879d0 +80887a18 0x80887a18 +80887a84 0x80887a84 +80888080 0x80888080 +808880f0 0x808880f0 +808880fc 0x808880fc +80888154 0x80888154 +80888170 0x80888170 +80888744 0x80888744 +80888890 0x80888890 +80888894 0x80888894 +808888d4 0x808888d4 +80888a28 0x80888a28 +80888a2c 0x80888a2c +80888a6c 0x80888a6c +80888bc0 0x80888bc0 +80888bc4 0x80888bc4 +80888c04 0x80888c04 +80888cd0 0x80888cd0 +80888d9c 0x80888d9c +80888e68 0x80888e68 +80888ef4 0x80888ef4 +80888f80 0x80888f80 +80889008 0x80889008 +808894e4 0x808894e4 +808899cc 0x808899cc +80889ea8 0x80889ea8 +80889fb8 0x80889fb8 +8088a0cc 0x8088a0cc +8088a1dc 0x8088a1dc +8088a23c 0x8088a23c +8088a29c 0x8088a29c +8088a2fc 0x8088a2fc +8088a350 0x8088a350 +8088a3a4 0x8088a3a4 +8088a3f8 0x8088a3f8 +8088a5e8 0x8088a5e8 +8088a7d8 0x8088a7d8 +8088a9c8 0x8088a9c8 +8088aa08 0x8088aa08 +8088aa48 0x8088aa48 +8088aa88 0x8088aa88 +8088ac08 0x8088ac08 +8088ad8c 0x8088ad8c +8088af04 RelEndFuncLink::AddEntry +8088af20 RelEndFuncLink::ExecFuncs +8088af74 0x8088af74 diff --git a/projects/mkwii-ntsc-u/data_addresses.txt b/projects/mkwii-ntsc-u/data_addresses.txt new file mode 100644 index 0000000..113feef --- /dev/null +++ b/projects/mkwii-ntsc-u/data_addresses.txt @@ -0,0 +1,243 @@ +# NTSC-U (RMCE01) addresses for the PAL (RMCP01) data globals named by the WiiCompiled runtime. +# Format: +# Every cited instruction was disassembled from the RMCE01 main.dol (or StaticR.rel) at the +# stated NTSC-U address; the function names are the PAL MAP.txt names of the function that the +# validated PAL->NTSC-U port table (CHUNKS_E) maps onto that NTSC-U code. +# Small-data bases: NTSC-U r13=0x80388880 r2=0x8038AC20; PAL r13=0x8038CC00 r2=0x8038EFA0. +# Deltas observed: all .data/.bss objects, .sdata2 and every .sbss global up to (at least) PAL 0x80386F27 +# are PAL-0x4380; .sbss from PAL 0x80386F60 onward is PAL-0x4388 (r13 offset 8 less). See notes at end. + +# ---------------------------------------------------------------- GX +# Display-list fifo object (GXBeginDisplayList/GXEndDisplayList): NTSC base 0x8033FD10 = PAL 0x80344090 - 0x4380 +80344090 8033FD10 GX::BeginDisplayList@80172d78 lis r31,0x8034; @80172d7c addi r31,r31,-0x2f0 (=0x8033FD10 dlFifo); @80172d8c addi r29,r31,0; @80172dc4 stw r27,0x0(r29) (dlFifo.base=list); @80172df0 addi r3,r31,0 -> GXSetCPUFifo(&dlFifo); GX::EndDisplayList@80172e2c addi r30,r30,-0x2f0; @80172e34 addi r3,r30,0 -> GXGetCPUFifo(&dlFifo) +80344094 8033FD14 GX::BeginDisplayList@80172dcc stw r4,0x4(r29) (dlFifo.end = list+size-4, r29=0x8033FD10; r4 from @80172db8 add r4,r27,r28 / @80172dc0 addi r4,r4,-4) +80344098 8033FD18 GX::BeginDisplayList@80172dd0 stw r28,0x8(r29) (dlFifo.size = size) +803440A4 8033FD24 GX::BeginDisplayList@80172dd8 stw r27,0x14(r29) (dlFifo.rdPtr = list) +803440A8 8033FD28 GX::BeginDisplayList@80172ddc stw r27,0x18(r29) (dlFifo.wrPtr = list) +803440AC 8033FD2C GX::BeginDisplayList@80172dd4 stw r3,0x1c(r29) (dlFifo.count = 0, li r3,0 @80172dbc) +80344110 8033FD90 GX::BeginDisplayList@80172dac addi r3,r31,0x80 -> memcpy(0x8033FD90, gx, 0x600) (li r5,0x600 @80172db0, saved GXData copy); GX::EndDisplayList@80172e6c addi r4,r30,0x80 (memcpy src) +80344710 80340390 GX::BeginDisplayList@80172de8 addi r3,r31,0x680 -> GXGetCPUFifo(0x80340390) (saved CPU fifo); GX::EndDisplayList@80172e48 addi r3,r30,0x680 -> GXSetCPUFifo(0x80340390) +803867D8 80382458 GX::DrawDone@8016ea84 stb r31,-0x6428(r13); GX::DrawDone@8016eaa4 lbz r0,-0x6428(r13); GX::FinishInterruptHandler@8016ed20 stb r3,-0x6428(r13) # r13-0x6428 in both regions (PAL 0x8038CC00-0x6428=0x803867D8) +803886C8 80384348 GX::Init@8016b7d4 lwz r31,-0x68d8(r2); GX::SetCPUFifo@8016c978 lwz r5,-0x68d8(r2); GX::DrawDone@8016ea3c lwz r4,-0x68d8(r2); GX::BeginDisplayList@80172d74 lwz r30,-0x68d8(r2) # .sdata2 `gx` (__GXData ptr), r2-0x68d8 in both regions (PAL 0x8038EFA0-0x68D8=0x803886C8) + +# ---------------------------------------------------------------- DVD +80343230 8033EEB0 __DVDClearWaitingQueue@80163520 lis r6,0x8034; @80163524 addi r6,r6,-0x1150 (=0x8033EEB0); @8016352c stw r6,0x0(r6); @80163538 stw r6,0x4(r6) (4 self-linked queues of 8 bytes: +0..+0x1c); __DVDPushWaitingQueue@80163580 addi r4,r4,-0x1150; __DVDPopWaitingQueue@801635e0 addi r4,r4,-0x1150 +803434E0 8033F160 DVD::LowInit@801648e0 lis r4,0x8034; @801648e4 stwu r5,-0xea0(r4) (r4=0x8033F160=ctx[0], ctx[0]+0=0); @801648e8 lis r3,0xfeec; @801648f8 addi r3,r3,-0x2513 (=0xFEEBDAED); @80164900 stw r3,0xc(r4) (ctx[0]+0xC=magic); @80164904 stw r5,0x10(r4) (ctx[0]+0x10=0); @80164918 stw r0,0x30(r4) (ctx[1]+0x10=1); @8016492c stw r6,0x50(r4) (ctx[2]+0x10=2); @80164944 stw r6,0x70(r4) (ctx[3]+0x10=3) +80386664 803822E4 DVD::Pause@80162b74 stw r4,-0x659c(r13); DVD::Resume@80162bb4 stw r4,-0x659c(r13); DVD::CancelAll@80163070 stw r4,-0x659c(r13); DVD::InquiryAsync@801629b4 lwz r0,-0x659c(r13) # r13-0x659c both regions +80386668 803822E8 DVD::Resume@80162bb8 lwz r0,-0x6598(r13); DVD::Resume@80162bc4 stw r4,-0x6598(r13); DVD::Pause@80162b80 stw r4,-0x6598(r13); DVD::GetDriveStatus@80162ae0 lwz r0,-0x6598(r13) +80386670 803822F0 __DVDPrepareReset@801633f0 lwz r0,-0x6590(r13); __DVDPrepareResetAsync@801632c0 lwz r0,-0x6590(r13) +8038667C 803822FC DVD::CancelAll@80163058 stw r0,-0x6584(r13); DVD::CancelAll@801630d4 stw r0,-0x6584(r13); DVD::CancelAll@80163128 lwz r0,-0x6584(r13) +803866A8 80382328 __DVDPrepareReset@801633e0 stw r31,-0x6558(r13); __DVDPrepareReset@80163488 stw r0,-0x6558(r13); __DVDPrepareReset@801634cc lwz r0,-0x6558(r13) +803866F0 80382370 DVD::Pause@80162b6c lwz r0,-0x6510(r13); DVD::CancelAll@80163068 lwz r0,-0x6510(r13); __DVDPrepareReset@8016340c lwz r3,-0x6510(r13); DVD::ReadAbsAsyncPrio@801628c8 lwz r0,-0x6510(r13) # `executing` command block +80386720 803823A0 DVD::LowInit@80164948 stw r5,-0x64e0(r13) (r5=0, current context index, right after the 4-context init); DVD::LowReadDiskID@80164a3c lwz r9,-0x64e0(r13) +80386724 803823A4 DVD::LowInit@801648d0 lbz r0,-0x64dc(r13) (skip context init if already set); DVD::LowInit@8016494c stb r0,-0x64dc(r13) (=1) +80386725 803823A5 DVD::LowInit@801647c4 lbz r0,-0x64db(r13); DVD::LowInit@801647d4 stb r0,-0x64db(r13) (=1); DVD::LowFinalize@80164794 stb r0,-0x64db(r13) (=0) +803866A0 80382320 DVD::Init@8015e990 lwz r0,-0x6560(r13) (return if already initialized); DVD::Init@8015e9a8 stw r0,-0x6560(r13) (=1) + +# ---------------------------------------------------------------- NAND +80346D20 803429A0 nandGetHomeDir@8019e7d4 lis r3,0x8034; @8019e7d8 addi r3,r3,0x29a0 (returns &NANDHomeDir=0x803429A0); NAND::Init@8019e178 lis r5,0x8034; @8019e184 addi r5,r5,0x29a0 (ESP_GetDataDir out buffer); NAND::Init@8019e198 lis r4,0x8034; @8019e1a0 addi r4,r4,0x29a0 +80386848 803824C8 NAND::Init@8019e10c lwz r0,-0x63b8(r13) (cmpwi 1 / cmpwi 2 = init state); NAND::Init@8019e13c stw r0,-0x63b8(r13) (=1); NAND::Init@8019e1d0 stw r0,-0x63b8(r13) (=2 on success); NAND::GetCurrentDir@8019e308 lwz r0,-0x63b8(r13) + +# ---------------------------------------------------------------- VI +# VI HorVer struct (.bss): NTSC 0x8034C4E0 = PAL 0x80350860 - 0x4380; fields +4 DispSizeX, +6 DispSizeY, +0x12 FBSizeX, +0x1C PanSizeY, +0x30 bufAddr +80350864 8034C4E4 VIInit@801b962c lis r30,0x8035; @801b9630 addi r31,r30,-0x3b20 (=0x8034C4E0 HorVer); @801b965c li r7,640; @801b969c sth r7,0x4(r31) (HorVer.DispSizeX=640) +80350866 8034C4E6 VIInit@801b96b0 sth r0,0x6(r31) (HorVer.DispSizeY = timing->acv*2; r31=0x8034C4E0) +80350872 8034C4F2 VIInit@801b970c lis r4,0x8035; @801b9714 addi r4,r4,-0x3b20 (=0x8034C4E0); @801b9718 li r9,640; @801b97b4 sth r9,0x12(r4) (HorVer.FBSizeX=640) +8035087C 8034C4FC VIInit@801b9804 sth r5,0x1c(r4) (HorVer.PanSizeY; r4=0x8034C4E0) +80350890 8034C510 VISetNextFrameBuffer@801baa34 lis r7,0x8035; @801baa3c addi r7,r7,-0x3b20 (=0x8034C4E0); @801baa44 stw r30,0x30(r7) (HorVer.bufAddr=fb); @801baa4c addi r4,r7,0x34; @801baa50 addi r5,r7,0x38 (setFbbRegs(&HorVer,&tfbb,&bfbb,...)) +80386B38 803827B8 VIInit@801b9418 lwz r0,-0x60c8(r13) (already-initialised check); VIInit@801b9434 stw r0,-0x60c8(r13) # r13-0x60c8 both regions +80386BA8 80382828 VIGetTvFormat@801bac4c lwz r31,-0x6058(r13); VIInit@801b9690 stw r8,-0x6058(r13) (CurrTvMode=HorVer.tv); __VIRetraceHandler@801b8b10 stw r3,-0x6058(r13) +80386BE4 80382864 VIWaitForRetrace@801b9968 lwz r30,-0x601c(r13); VIWaitForRetrace@801b9974 lwz r0,-0x601c(r13); VIGetRetraceCount@801bab04 lwz r3,-0x601c(r13); __VIRetraceHandler@801b8974 stw r0,-0x601c(r13) (retraceCount++) +80386B44 803827C4 VIInit@801b9904 stw r0,-0x60bc(r13) (=1, VIInit tail); __VIRetraceHandler@801b8da4 lwz r0,-0x60bc(r13); __VIRetraceHandler@801b8dcc stw r0,-0x60bc(r13) +80386BB8 80382838 VISetPreRetraceCallback@801b906c lwz r31,-0x6048(r13); VISetPreRetraceCallback@801b9074 stw r30,-0x6048(r13); __VIRetraceHandler@801b8984 lwz r12,-0x6048(r13); VIInit@801b984c stw r29,-0x6048(r13) +80386BB4 80382834 VISetPostRetraceCallback@801b90b0 lwz r31,-0x604c(r13); VISetPostRetraceCallback@801b90b8 stw r30,-0x604c(r13); __VIRetraceHandler@801b8d7c lwz r12,-0x604c(r13); VIInit@801b9850 stw r29,-0x604c(r13) +80386BA0 80382820 VIGetNextFrameBuffer@801baa84 lwz r3,-0x6060(r13); __VIRetraceHandler@801b8b14 stw r0,-0x6060(r13) +80386BC0 80382840 VIWaitForRetrace@801b996c addi r3,r13,-0x6040 -> OSSleepThread(&retraceQueue); VIInit@801b97f8 addi r3,r13,-0x6040 -> OSInitThreadQueue; __VIRetraceHandler@801b8d8c addi r3,r13,-0x6040 -> OSWakeupThread + +# ---------------------------------------------------------------- EGG +# NOTE: past the .sbss gap: PAL r13-0x5ca0, NTSC r13-0x5ca8 (delta 0x4388) +80386F60 80382BD8 RKSystem::Main@80008ec0 lis r31,0x802a; @80008ec4 addi r31,r31,-0x300 (=0x8029FD00 system instance, .bss start); @80008ed8 stw r31,-0x5ca8(r13) (BaseSystem::sSystem = instance, then virtual call via vtable+0x38); EGG::AsyncDisplay::beginFrame@8020fe74 lwz r3,-0x5ca8(r13) (sSystem->vtable[2] call); EGG::Display::beginFrame@80219e50 lwz r3,-0x5ca8(r13); EGG::SceneManager::createScene@8023ad94 lwz r4,-0x5ca8(r13); EGG::DrawDoneCallback@8020fc48 lwz r3,-0x5ca8(r13); EGG::StateGX::InitFrame@80240054 lwz r3,-0x5ca8(r13) + +# ---------------------------------------------------------------- Range constants (section tables) +# NTSC-U DOL header: section 9 = .ctors file off 0x240E40 addr 0x80244D40 size 0xC0 (end 0x80244E00) +# section 10 = .dtors file off 0x240F00 addr 0x80244E00 size 0x20 (end 0x80244E20) +# .ctors contents: 80244D40 __init_cpp_exceptions(0x80020684), 80244D44 __sinit_\RKSystem_cpp(0x8000998C), ... 80244DE8 __sinit__eggVector_cpp(0x80242D2C), 80244DEC..80244DFC zero +# .dtors contents: 80244E00 __destroy__global_chain(0x800207F0), 80244E04 __fini_cpp_exceptions(0x800206C0), rest zero +80244DE0 80244D40 DOL section table: .ctors start (sec9 addr), delta 0xA0 like the surrounding text +80244EA0 80244E00 DOL section table: .ctors end = .dtors start (sec9 addr+size = sec10 addr) +# NTSC-U StaticR.rel section table (load base 0x8050BF60): section 2 = .ctors file off 0x37F070 size 0x304 -> 0x8088AFD0..0x8088B2D4 (193 words: 192 R_PPC_ADDR32 self-relocations + null terminator); +# section 3 = .dtors file off 0x37F374 size 0xC -> 0x8088B2D4..0x8088B2E0 (2 ADDR32 relocations); section 4 (.rodata) starts 0x8088B2E0 +8088F400 8088AFD0 REL section table: .ctors start (sec2 off 0x37F070 + base 0x8050BF60) +8088F704 8088B2D4 REL section table: .ctors end (0x8088AFD0 + 0x304) = .dtors (sec3) start + +# ================================================================ Batch 2 +# ---------------------------------------------------------------- GX (DOL .bss/.sbss) - GXInit / __GXFifoInit / __GXPEInit objects +80343740 8033F3C0 GX::Init@8016b824 lis r28,0x8034; @8016b830 addi r3,r28,-0xc40 (=0x8033F3C0 FifoObj -> GXInitFifoBase); @8016b838 addi r3,r28,-0xc40 (GXSetCPUFifo); @8016b840 addi r3,r28,-0xc40 (GXSetGPFifo); @8016bc9c addi r3,r3,-0xc40 (return &FifoObj) +803437C0 8033F440 .sdata2 cell: the `gx` pointer at NTSC 0x80384348 (r2-0x68d8, see 803886C8 above) contains 0x8033F440 in the DOL image (sec14 file data) = &gxData; PAL cell 0x803886C8 holds 0x803437C0. GX::Init@8016b7d4 (ctx) lwz r31,-0x68d8(r2) loads that cell. +80343DC0 8033FA40 __GX::FifoInit@8016d12c lis r3,0x8034; @8016d134 addi r3,r3,-0x5c0 (=0x8033FA40); @8016d138 li r5,0x24 -> memset(&GPFifo,0,0x24) +80343DE4 8033FA64 __GX::FifoInit@8016d114 lis r3,0x8034; @8016d120 addi r3,r3,-0x59c (=0x8033FA64); @8016d124 li r5,0x24 -> memset(&CPUFifo,0,0x24); GX::SetCPUFifo@8016c8d4 lis r4,0x8034; @8016c8dc addi r4,r4,-0x59c; @8016c8e8 stb r0,0x22(r4) +803867B0 80382430 __GX::FifoInit@8016d140 stb r31,-0x6450(r13) (=0); GX::SetCPUFifo@8016c8e0 stb r0,-0x6450(r13); GX::GetCPUFifo@8016ce84 lbz r0,-0x6450(r13) +803867B1 80382431 __GX::FifoInit@8016d144 stb r31,-0x644f(r13) (=0) +803867C0 80382440 __GX::FifoInit@8016d11c stw r31,-0x6440(r13) (r31=0: thread queue head cleared) +803867C4 80382444 __GX::FifoInit@8016d110 stw r3,-0x643c(r13) (r3 = OSGetCurrentThread()); GX::GetCurrentGXThread@8016d2fc lwz r3,-0x643c(r13) +803867D0 80382450 __GX::PEInit@8016eda0 addi r3,r13,-0x6430 -> OSInitThreadQueue; GX::DrawDone@8016ea9c addi r3,r13,-0x6430 -> OSSleepThread; GX::FinishInterruptHandler@8016ed58 addi r3,r13,-0x6430 -> OSWakeupThread + +# ---------------------------------------------------------------- OS scheduler (DOL .bss/.sbss) +803477B0 80343430 SetEffectivePriority@801a99b0 lis r3,0x8034; @801a99b8 addi r3,r3,0x3430 (=0x80343430 RunQueue[32], indexed by prio*8: @801a99b4 slwi r0,r31,3); SelectThread@801a9bec lis r3,0x8034; @801a9bf4 addi r3,r3,0x3430; OS::ResumeThread@801aa580 lis r3,0x8034; @801aa588 addi r3,r3,0x3430 +80386918 80382598 OS::__ThreadInit@801a97e0 stw r29,-0x62e8(r13) (=0); OS::DisableScheduler@801a985c lwz r31,-0x62e8(r13); @801a9864 stw r0,-0x62e8(r13) (count+1); SelectThread@801a9b80 lwz r0,-0x62e8(r13) (early exit while >0) +8038691C 8038259C OS::__ThreadInit@801a9718 stw r3,-0x62e4(r13) +80386920 803825A0 OS::__ThreadInit@801a9710 stw r3,-0x62e0(r13); UnsetRun@801a9908 lwz r5,-0x62e0(r13); @801a9918 stw r0,-0x62e0(r13) + +# ---------------------------------------------------------------- SC / game system (DOL .sbss) +803869E0 80382660 SCGetProductCode@801b2390 addi r4,r13,-0x6220 (6-byte CODE output buffer: @801b2398 li r5,6); @801b23ac addi r3,r13,-0x6220 (returned pointer) +80386000 80381C80 SystemManager::create@8000a5a4 lwz r0,-0x6c00(r13) (s_instance null check); @8000a5c8 stw r3,-0x6c00(r13) (s_instance = new SystemManager); @8000a5d4 lwz r3,-0x6c00(r13); also REL GameScreen::__ct@80561520 lis r3 + @80561524 lwz r3,0(r3) carry module-0 relocations to 0x80381C80 + +# ---------------------------------------------------------------- EGG::Screen statics (DOL .sbss) - delta 0x4380 still holds here +80386F14 80382B94 EGG::Screen::SetTVModeDefault@8023e1cc lwz r6,-0x5cec(r13) (active screen, cmpwi 0 -> skip); EGG::Screen::SetTVMode@8023e114 lwz r6,-0x5cec(r13); EGG::Screen::CreateDummy@8023cf08 stw r3,-0x5cec(r13) +80386F20 80382BA0 EGG_Screen_cpp_sinit_@8023e37c (ctx) lfs f1,-0x5f84(r2) (=1.0f constant at 0x80384C9C); @8023e380 addi r4,r13,-0x5ce0; @8023e38c stfs f1,-0x5ce0(r13) (gScreenScale.x = 1.0); EGG::Screen::GetPosSizeInEFB@8023d62c lfs f0,-0x5ce0(r13); EGG::Screen::LoadDirectly@8023d1c4 lfs f0,-0x5ce0(r13) +80386F24 80382BA4 EGG_Screen_cpp_sinit_@8023e390 stfs f1,0x4(r4) with r4 = r13-0x5ce0 (=0x80382BA0) from @8023e380 (ctx) addi r4,r13,-0x5ce0 (gScreenScale.y = 1.0; second float of the Vector2f at 0x80382BA0) + +# ---------------------------------------------------------------- EGG::DrawGX::SetVtxState vertex arrays (DOL .sdata2 / .rodata) +# .sdata2 arrays keep their r2 offsets (delta 0x4380); the .rodata arrays sit at PAL-0x320 (PAL .rodata carries 0x280 more bytes before them than NTSC; .rodata starts at PAL-0xA0). +80388B80 80384800 EGG::DrawGX::SetVtxState@8021b484 li r3,10(GX_VA_NRM); @8021b488 addi r4,r2,-0x6420; @8021b48c li r5,6 -> GXSetArray (states 7/8) +80388BA0 80384820 EGG::DrawGX::SetVtxState@8021b514 li r3,10; @8021b518 addi r4,r2,-0x6400; @8021b51c li r5,6 -> GXSetArray (state 9) +80388BC0 80384840 EGG::DrawGX::SetVtxState@8021b588 addi r4,r2,-0x63e0 (POS array, states 10/12); @8021b58c li r3,9; @8021b590 li r5,2 +80388BE0 80384860 EGG::DrawGX::SetVtxState@8021b580 addi r4,r2,-0x63c0 (POS array, states 11/13); @8021b5a0 li r3,13(GX_VA_TEX0); @8021b5a4 addi r4,r2,-0x63c0; @8021b5a8 li r5,2 +802574A0 80257180 EGG::DrawGX::SetVtxState@8021b270 lis r31,0x8025; @8021b274 addi r31,r31,0x7160 (=0x80257160); @8021b2d8 addi r4,r31,0x20 (=0x80257180); @8021b2dc li r3,9(GX_VA_POS); @8021b2e0 li r5,6 (state 0) +802574E0 802571C0 EGG::DrawGX::SetVtxState@8021b2e8 addi r4,r31,0x60 (=0x802571C0); @8021b2ec li r3,10(GX_VA_NRM); @8021b2f0 li r5,6 (state 0) +80257520 80257200 EGG::DrawGX::SetVtxState@8021b474 addi r4,r31,0xa0 (=0x80257200); @8021b478 li r3,9; @8021b47c li r5,4 (states 7/8) +80257540 80257220 EGG::DrawGX::SetVtxState@8021b504 addi r4,r31,0xc0 (=0x80257220); @8021b508 li r3,9; @8021b50c li r5,6 (state 9) + +# ---------------------------------------------------------------- EGG::Screen canvas records + vtable (DOL .data) - these sit at PAL-0x4368 (not 0x4380) +# NTSC record table 0x8029FB80: {608,480,1.0526,1.0} then {832,480,0.7692,1.0} (12-byte records, matching the runtime's 608/832 widths); vtable 0x8029FBA4 = {EGG::Screen::__dt, EGG::Screen::LoadDirectly, EGG::Screen::CopyToG3D, ...} +802A3EE8 8029FB80 EGG::Screen::SetTVModeDefault@8023e1c4 bl SCGetAspectRatio; @8023e1e8 mulli r4,r0,12; @8023e1f0 lis r5,0x802a; @8023e1fc addi r5,r5,-0x480 (=0x8029FB80 record[0]); @8023e200 lhzx r4,r5,r4 (record[aspect].width); EGG::Screen::__ct@8023cf38 lis r5,0x802a; @8023cf48 addi r5,r5,-0x480; REL GameScreen::__ct@80561558 lis r4 / @80561568 addi r4,r4,0 carry module-0 relocations to 0x8029FB80 +802A3EF4 8029FB8C record[1] = 0x8029FB80 + 12 (SetTVModeDefault index*12 above; 16:9 record {832,480,...} at 0x8029FB8C in the DOL image) +802A3F0C 8029FBA4 EGG::Screen::__ct@8023cfac lis r3,0x802a; @8023cfb0 addi r3,r3,-0x45c (=0x8029FBA4); @8023cfb8 stw r3,0x38(r31) (vtable at this+0x38); EGG::Screen::__ct(args)@8023d058 addi r3,r3,-0x45c + +# ---------------------------------------------------------------- StaticR.rel (.data / .bss) - resolved through the NTSC-U REL relocation table +# Method: the REL text carries pre-relocation immediates (lis/addi = 0), so each cited instruction's R_PPC_ADDR16_HA/LO entry (module 1) was +# looked up at instruction+2 in the import table; target = section address + addend. NTSC-U section addresses: .data (sec5) = 0x808AE520, +# .bss (sec6) = 0x809B8F20 = 0x8050BF60 + alignUp(filesize 0x4ACF94 + 0x20 heap header, 0x20), which is exactly where the translator +# (RelFile.CalculateBssOffset) and the NTSC base manifest (build/base/mkwii_base_manifest.json: StaticR.rel:6 = 0x809b8f20..0x809c07d0) place it. +# PAL cross-check: the runtime's PAL bss identities imply PAL bss base 0x809BD6E0 (0x809C1830 - 0x4150; THP flag 0x809BECF0 = +0x1610 is +# referenced by NTSC THP::PlayerQuit/PlayerDrawDone at sec6+0x1610; Race::JugemManager 0x809C28B8 = +0x51D8 referenced by NTSC RaceScene::OnEnterEnd). +# The PAL bss layout is NOT identical everywhere: the audio singleton cluster sits 0x480 higher in PAL (mkw-sp PAL RaceSoundManager 0x809C27F8 = +# +0x5118 vs NTSC Audio::RaceMgr::CreateInstance -> +0x4C98; ItemMusicManager 0x809C27F0 = +0x5110 vs Audio::ItemAlterationMgr -> +0x4C90), so +# REL bss identities were matched by function, never by delta. +808B4C20 808B0570 GameScreen::__ct@805614cc bl -> EGG::Screen::__ct (module-0 REL24 reloc to 0x8023cf30; GameScreen is the only REL caller of an EGG::Screen ctor); @805614d0 lis r3 (ADDR16_HA -> sec5+0x2050); @805614d8 addi r3,r3 (ADDR16_LO -> sec5+0x2050 = 0x808B0570); @805614dc stw r3,0x38(r30) (vtable at this+0x38, same slot as the EGG::Screen vtable). Vtable contents via ADDR32 relocs: +8 GameScreen::__dt, +0xC EGG::Screen::LoadDirectly, +0x10 EGG::Screen::CopyToG3D (same layout as the EGG::Screen vtable at 0x8029FBA4). +809C1830 809BD070 Renderer::Register(listIdx)@80560d9c lis r5 (ADDR16_HA -> sec6+0x4150); @80560da8 addi r5,r5 (ADDR16_LO -> sec6+0x4150 = 0x809BD070 = Render::DrawList instance); @80560da4 mulli r0,r4,12; @80560dc0 add r3,r5,r0 (&lists[listIdx], 12-byte nw4r::ut::List); 38 sites reference sec6+0x4150 (Renderer::Register2ndList, RemoveFrom1stList/2ndList, ...) +809C183C 809BD07C Renderer::Register2ndList(NoAppend)@80560ef0 lis r5 (-> sec6+0x4150); @80560ef8 addi r5,r5 (-> 0x809BD070); @80560f08 addi r3,r5,0xc (second list = DrawList+0xC = 0x809BD07C); Renderer::RemoveFrom2ndList@80560f54 lis r5; @80560f5c addi r5,r5 (-> 0x809BD070); @80560f60 addi r3,r5,0xc +809C2898 809BDC58 Audio::Manager::CreateInstance@8070f390 lis r3 (ADDR16_HA -> sec6+0x4d38); @8070f3ac lwz r0,0(r3) (ADDR16_LO -> sec6+0x4d38 = 0x809BDC58, null check); @8070f440 lis r3; @8070f444 stw r30,0(r3) (-> sec6+0x4d38: spInstance = new Audio::Manager); the object is EGG::ExpAudioMgr-derived: Audio::Manager::StartSound@8070fcc0 lwz r3,0x5bc(r3) (archive player pointer) and DOL EGG::ExpAudioMgr::Initialize@802114e4 lwz r3,0x5bc(r27), matching the runtime's kArchivePlayerOffset 0x5BC. PAL offset 0x51B8 = NTSC 0x4D38 + 0x480, the same shift as the mkw-sp audio singletons. + +# ---------------------------------------------------------------- .ctors/.dtors confirmation (batch 2 request) - unchanged from above +# DOL: PAL .ctors 80244DE0..80244EA0 -> NTSC 80244D40..80244E00 (sec9); .dtors NTSC 80244E00..80244E20 (sec10). REL: PAL .ctors 8088F400..8088F704 -> NTSC 8088AFD0..8088B2D4 (sec2); .dtors 8088B2D4..8088B2E0 (sec3). +# The NTSC base manifest agrees: .ctors 0x80244d40-0x80244e00, .dtors 0x80244e00-0x80244e20, StaticR.rel:2 0x8088afd0-0x8088b2d4, StaticR.rel:3 0x8088b2d4-0x8088b2e0. + +# ================================================================ Batch 3 +# ---------------------------------------------------------------- AX / DSP (DOL .data/.bss/.sbss/.sdata2) +# __AXOutInitDSP fills the DSPTaskInfo __AXDSPTask (NTSC 0x802F3E20): +0xC iram_mmem_addr, +0x10 iram_length, +0x18 dram_mmem_addr, +0x1C dram_length(64), +0x20 dram_addr(3282), +0x28.. callbacks 0x801268a8/0x801268b4/0x80126908/0x80126918 (= PAL 80126948/54/9A8/9B8 - 0xA0) +8027F820 8027B4E0 __AXOutInitDSP@80126960 lis r29,0x8028; @80126964 addi r29,r29,-0x4b20 (=0x8027B4E0, DSP ucode image: vector table 029f 0f3c 029f 0f48 ... at that address); @80126990 stw r29,0xc(r30) (task.iram_mmem_addr; r30 = __AXDSPTask) # .data delta 0x4340 for this object (not 0x4380) +802F81A0 802F3E20 __AXOutInitDSP@80126950 lis r30,0x802f; @80126954 addi r30,r30,0x3e20 (=0x802F3E20 __AXDSPTask); @801269d8 lis r3,0x802f; @801269dc addi r3,r3,0x3e20 -> DSPAddTask(&__AXDSPTask); __AXOutAiCallback@80126830 lis r3,0x802f; @80126838 addi r3,r3,0x3e20 +802F8200 802F3E80 __AXOutInitDSP@80126924 lis r11,0x802f; @80126944 addi r11,r11,0x3e80 (=0x802F3E80 DRAM image); @8012699c stw r11,0x18(r30) (task.dram_mmem_addr); @80126978 li r10,64; @801269a0 stw r10,0x1c(r30) (dram_length = 64); @80126980 li r9,3282; @801269a4 stw r9,0x20(r30) (dram_addr) +80386608 80382288 DSPInit@8015d3d0 lwz r0,-0x65f8(r13) (already-initialised check); DSPInit@8015d448 stw r0,-0x65f8(r13) (=1); DSPCheckInit@8015d464 lwz r3,-0x65f8(r13) +80386610 80382290 DSPAssertTask@8015d510 stw r0,-0x65f0(r13) (=1); DSPAssertTask@8015d538 stw r0,-0x65f0(r13); __DSPHandler@8015d6d8 lwz r0,-0x65f0(r13) +80386614 80382294 DSPAssertTask@8015d50c stw r30,-0x65ec(r13) (= task being asserted); DSPAssertTask@8015d534 stw r30,-0x65ec(r13) +80386618 80382298 DSPInit@8015d438 stw r4,-0x65e8(r13) (=0, cleared with the task pointers below) +8038661C 8038229C DSPInit@8015d440 stw r4,-0x65e4(r13) (=0); __DSPHandler@8015d96c lwz r3,-0x65e4(r13); __DSP_insert_task@8015dd60 stw r3,-0x65e4(r13) +80386620 803822A0 DSPInit@8015d444 stw r4,-0x65e0(r13) (=0); DSPAddTask@8015d4ac lwz r0,-0x65e0(r13); __DSPHandler@8015d968 lwz r0,-0x65e0(r13) +80386624 803822A4 DSPInit@8015d43c stw r4,-0x65dc(r13) (=0); DSPAssertTask@8015d4f8 lwz r5,-0x65dc(r13); __DSPHandler@8015d634 lwz r5,-0x65dc(r13) +80388588 80384208 AXFXReverbStdExpCallback@8012b81c lfs f2,-0x6a18(r2) (cell 0x80384208 = 1.0f in the DOL image); AXFXReverbStdExp__InitParams@8012becc lfs f1,-0x6a18(r2) # r2-0x6a18 in both regions (PAL 0x8038EFA0-0x6A18=0x80388588) +8038858C 8038420C AXFXReverbStdExpCallback@8012b82c lfs f3,-0x6a14(r2) (cell 0x8038420C = 0.6f in the DOL image) + +# ---------------------------------------------------------------- AI (DOL .sbss) +80386448 803820C8 AIInit@8012402c lwz r0,-0x67b8(r13) (already-initialised check); AIInit@80124170 stw r0,-0x67b8(r13) (=1); AICheckInit@80123ff4 lwz r3,-0x67b8(r13) +8038644C 803820CC __AIDHandler@801241d8 lwz r0,-0x67b4(r13) (callback-busy check); __AIDHandler@801241ec stw r4,-0x67b4(r13) (=1) +8038647C 803820FC AIInit@8012415c stw r31,-0x6784(r13); __AIDHandler@801241e4 lwz r0,-0x6784(r13); __AICallbackStackSwitch@8012425c lis r5,0x8038; @80124260 addi r5,r5,0x20fc (=0x803820FC) +80386480 80382100 AIRegisterDMACallback@80123f00 lwz r31,-0x6780(r13) (old callback); AIRegisterDMACallback@80123f08 stw r30,-0x6780(r13) (new callback); AIInit@80124150 stw r0,-0x6780(r13) (=0); __AIDHandler@801241cc lwz r3,-0x6780(r13) + +# ---------------------------------------------------------------- OS thread/interrupt globals (DOL .bss/.sdata/.sbss) +80347130 80342DB0 OS::CreateThread@801a9ea8 lis r4,0x8034; @801a9eac addi r4,r4,0x2d70; @801a9eb0 lwz r0,0x40(r4) (=0x80342DB0); @801a9eb4 cmpwi r0,0 -> skip the FP/PS context init; when set: @801a9ecc ori r5,r5,0x900 (srr1), @801a9ed4 ori r4,r4,1 (mode), fpscr from the .sdata word below (exactly the sequence os_thread.cpp mirrors) +80347498 80343118 OS::__ThreadInit@801a95a0 lis r31,0x8034; @801a95a4 addi r31,r31,0x3118 (=0x80343118 DefaultThread; RunQueue[32] at 0x80343430 = +0x318 follows it) +803478B0 80343530 SelectThread@801a9ca0 lis r3,0x8034; @801a9ca8 addi r3,r3,0x3530 (=0x80343530 IdleContext -> OSLoadContext); SelectThread@801a9cd0 lis r3,0x8034; @801a9cd4 addi r3,r3,0x3530 +80385AA8 80381728 OS::CreateThread@801a9ee0 lwz r4,-0x7158(r13) (__OSFpscrEnableBits); @801a9ee4 rlwinm r4,r4,0,24,28 (&0xF8); @801a9ee8 ori r4,r4,4; @801a9eec stw r4,0x194(r31) (thread->context.fpscr); OS::SetErrorHandler@801a28ac lwz r4,-0x7158(r13) # .sdata, r13-0x7158 both regions +80385AE0 80381760 OS::SetSwitchThreadCallback@801a952c lwz r31,-0x7120(r13) (old callback); @801a9540 stw r30,-0x7120(r13) (new); SelectThread@801a9c84 lwz r12,-0x7120(r13) (called on switch); OS::__ThreadInit@801a9620 lwz r12,-0x7120(r13) # .sdata, r13-0x7120 both regions +803868F8 80382578 OS::__SetInterruptHandler@801a6558 lwz r5,-0x6308(r13) (InterruptHandlerTable ptr, then stwx handler); OS::__GetInterruptHandler@801a656c lwz r4,-0x6308(r13); OS::__InterruptInit@801a65a4 stw r3,-0x6308(r13); OS::__DispatchInterrupt@801a6bc0 lwz r3,-0x6308(r13) +80386298 80381F18 RFL::iGetManager@800bc3d0 lwz r3,-0x6968(r13) (returns the RFL manager pointer); RFL::Init@800bbb34 lwz r0,-0x6968(r13) +80336278 80331EF8 BTM_IsDeviceUp@8013a260 lis r3,0x8033; @8013a264 addi r3,r3,0x1ef8 (=0x80331EF8 btm_cb); @8013a268 lbz r3,0x64e(r3) (device state; compared with 5, matching os_init.cpp's +0x64E/5); btm_acl_init@80137bc4 addi r3,r3,0x1ef8 + +# ---------------------------------------------------------------- StaticR.rel THP player state and movie mode table (relocation method, bss base 0x809B8F20) +# THP ActivePlayer struct = REL bss+0x1420 in both regions (PAL 0x809BEB00 = 0x809BD6E0+0x1420; NTSC 0x809BA340); the runtime's 809BEBA0..A7 are its +0xA0 (open) and +0xA4..+0xA7 byte fields. +809BEBA0 809BA3E0 THP::PlayerOpen@8054ad7c lis r29 (ADDR16_HA -> sec6+0x1420); @8054ad84 addi r29,r29 (ADDR16_LO -> 0x809BA340 ActivePlayer); @8054ada0 addi r30,r29,0; @8054ada4 lwz r0,0xa0(r30) (already-open check); @8054afc8 stw r0,0xa0(r30) (open = 1); THP::PlayerClose@8054aff8 lis r3; @8054b000 addi r3,r3 (-> 0x809BA340); @8054b020 stw r0,0xa0(r3) (open = 0) [reloc-base 0x809BA340 + 0xA0] +809BEBA4 809BA3E4 THP::PlayerOpen@8054afbc stb r4,0xa4(r30) (r30 = ActivePlayer 0x809BA340 from @8054ad7c / @8054ad84 / @8054ada0 [3bdd0000]) [reloc-base 0x809BA340 + 0xA4] +809BEBA5 809BA3E5 THP::PlayerOpen@8054afb4 stb r4,0xa5(r30) (same base: @8054ad7c / @8054ad84 / @8054ada0 [3bdd0000]) [reloc-base 0x809BA340 + 0xA5] +809BEBA6 809BA3E6 THP::PlayerOpen@8054afc0 stb r4,0xa6(r30) (same base: @8054ad7c / @8054ad84 / @8054ada0 [3bdd0000]) [reloc-base 0x809BA340 + 0xA6] +809BEBA7 809BA3E7 THP::PlayerOpen@8054aec4 stb r0,0xa7(r30) (same base: @8054ad7c / @8054ad84 / @8054ada0 [3bdd0000]) [reloc-base 0x809BA340 + 0xA7] +809BECF0 809BA530 THP::PlayerQuit@8054ad48 lis r3 (ADDR16_HA -> sec6+0x1610); @8054ad50 stw r0,0(r3) (ADDR16_LO -> sec6+0x1610 = 0x809BA530, Initialized = 0); THP::PlayerDrawDone@8054bee0 lis r3; @8054bee4 lwz r0,0(r3) (-> 0x809BA530) # PAL +0x1610 under base 0x809BD6E0, same offset +8088FDB8 8088B960 MovieManager::Prepare@805258b0 lwz r0,0xa8(r31) (mode); @805258b4 lis r4 (ADDR16_HA -> sec4+0x680); @805258b8 addi r4,r4 (ADDR16_LO -> sec4+0x680 = 0x8088B960); @805258c0 slwi r0,r0,2; @805258c8 lwzx r4,r4,r0 (audioSystem = table[mode]) -> THP::PlayerPrepare; MovieManager::PrepareAsync@8052594c lis r4; @80525950 addi r4,r4 (-> 0x8088B960); @80525960 lwzx r4,r4,r0 # REL .rodata: PAL 0x8088FDB8 is .rodata+0x698 from 0x8088F720 but the NTSC table is .rodata+0x680; matched by function, not by delta + +# ---------------------------------------------------------------- Notes +# * No PAL binary is available on this machine (both MKW images found are RMCE01), so PAL-side offsets are +# PAL_addr - PAL_r13/r2 by definition; each NTSC-U instruction above was matched by function identity (port table + +# PAL MAP name), by the instruction's role in the SDK/EGG function, and by consistency with sibling globals. +# * .sbss gap: delta 0x4380 is directly witnessed up to PAL 0x80386F27 (EGG::Screen gScreenScale Vector2f at +# PAL 0x80386F20/24 -> NTSC 0x80382BA0/A4: EGG_Screen_cpp_sinit_@8023e38c stfs f1,-0x5ce0(r13), +# @8023e390 stfs f1,4(r4) with @8023e380 addi r4,r13,-0x5ce0; EGG::Screen::SetTVModeDefault@8023e1cc lwz r6,-0x5cec(r13) +# = PAL 0x80386F14 active-screen ptr), and delta 0x4388 at PAL 0x80386F60 (sSystem). The extra 8 PAL bytes therefore +# lie in PAL 0x80386F28..0x80386F5F (NTSC 0x80382BA8..0x80382BD7: EGG::Screen/StateGX statics); which object was +# added/removed could not be identified without the PAL binary. None of the identities above fall inside that window. +# * The runtime's comment labels for some DVD .sbss globals do not match the SDK roles visible in the code +# (0x80386664 is the flag DVDPause sets / DVDResume clears, 0x80386668 the one DVDResume tests-and-clears, +# 0x80386670 the one __DVDPrepareReset tests); the address identities are unaffected. +# STM (State Transition Manager) globals. __OSInitSTM stores the two /dev/stm handles and its +# initialized flag into the small-data block; the runtime's stub writes the same three words so +# OSResetSystem's zero-checks pass. Their SDA offsets are NOT the same in every region (RMCK01 +# puts them 0x20 lower, where PAL/NTSC-U/NTSC-J keep the OSDisableScheduler nesting count), so +# they are named as identities here rather than as a hardcoded r13 offset. +80386934 803825B4 __OSInitSTM@801AB810 stw r31,-0x62cc(r13) (STM initialized flag) +80386938 803825B8 __OSInitSTM@801AB808 stw r3,-0x62c8(r13) (/dev/stm/immediate handle) +8038693C 803825BC __OSInitSTM@801AB830 stw r3,-0x62c4(r13) (/dev/stm/eventhook handle) +80386940 803825C0 OS::SetPowerCallback@801AB700 lwz r0,-0x62c0(r13); @801AB750 stw r0,-0x62c0(r13); @801AB75C stw r0,-0x62c0(r13) (STM event handler registered flag) +80386948 803825C8 OS::SetPowerCallback@801AB6E0 lwz r29,-0x62b8(r13); @801AB6EC stw r31,-0x62b8(r13); @801AB6FC stw r3,-0x62b8(r13) (registered power callback pointer) + +# ISFS / IPC globals. The runtime's ISFS_OpenLib stub brings the filesystem client up itself: +# it writes the "/dev/fs" path string and the device fd, then creates the ISFS heap out of the +# IPC buffer window. Like the STM globals above, these do NOT sit at the same r13 offsets in +# every region - RMCK01 keeps the .sbss cluster 0x20 lower and __ISFS_fd/__ISFS_path 0x8 lower - +# so they are named as identities rather than as hardcoded r13 offsets. Addresses below are the +# NTSC-U ones, each confirmed by the RMCE01 instructions cited; PAL is uniformly +0x4380 here, +# matching the .sbss delta documented at the top of this file. +80386770 803823F0 ISFS@80169B44 lwz r0,-0x6490(r13); ISFS@80169B64 lwz r0,-0x6490(r13); ISFS@80169BCC lwz r4,-0x6490(r13); ISFS@80169C18 stw r0,-0x6490(r13) # isfsHeapInitialized, 4 sites in RMCE01 +80386774 803823F4 ISFS@80169B74 stw r3,-0x648C(r13); ISFS@80169BAC lwz r3,-0x648C(r13); ISFS@80169BD0 lwz r30,-0x648C(r13) # isfsHeapBase, 3 sites in RMCE01 +8038677C 803823FC ISFS@80169B54 stw r3,-0x6484(r13); ISFS@80169B60 lwz r3,-0x6484(r13) # __IPCArenaLo, 2 sites in RMCE01 +80386780 80382400 ISFS@80169B5C stw r3,-0x6480(r13); ISFS@80169B7C lwz r0,-0x6480(r13); ISFS@80169BDC lwz r0,-0x6480(r13) # __IPCArenaHi, 3 sites in RMCE01 +80386784 80382404 ISFS@80169C2C stw r3,-0x647C(r13); ISFS@80169DAC lwz r3,-0x647C(r13); ISFS@80169E30 lwz r3,-0x647C(r13); ISFS@80169EA0 lwz r3,-0x647C(r13) # isfsHeapHandle, 36 sites in RMCE01 +803867EC 8038246C ISFS@80192F10 stw r3,-0x6414(r13); ISFS@80192F58 stw r3,-0x6414(r13); ISFS@80192F98 lwz r3,-0x6414(r13); ISFS@80192FA0 stw r3,-0x6414(r13) # ipcBufferLo, 4 sites in RMCE01 +803867F0 80382470 ISFS@80192F0C stw r4,-0x6410(r13); ISFS@80192F54 stw r4,-0x6410(r13); ISFS@80192F90 lwz r3,-0x6410(r13) # ipcBufferHi, 3 sites in RMCE01 +80385920 803815A0 ISFS@80169BBC stw r3,-0x72E0(r13); ISFS@80169E08 lwz r0,-0x72E0(r13); ISFS@80169E88 lwz r3,-0x72E0(r13); ISFS@80169F00 lwz r0,-0x72E0(r13) # __ISFS_fd, 33 sites in RMCE01 +80385928 803815A8 ISFS@80169BA4 addi r4,r13,-0x72D8 # __ISFS_path, 1 sites in RMCE01 + +# OS alarm queue and the two AX state flags. Same story as the STM and ISFS globals above: the +# runtime's alarm stubs walk OSAlarmQueue and the AX stub sets two flags, and RMCK01 keeps this +# part of .sbss 0x20 lower than PAL/NTSC-U/NTSC-J (OSAlarmQueue is r13-0x6360 in PAL but +# r13-0x6340 in RMCK01), so a hardcoded offset walks a string table there instead of the queue. +803868A0 80382520 OSAlarmQueue@801A0540 addi r3,r13,-0x6360; OSAlarmQueue@801A054C stw r0,-0x6360(r13); OSAlarmQueue@801A064C lwz r7,-0x6360(r13); OSAlarmQueue@801A0698 stw r30,-0x6360(r13) # OSAlarmQueue, 13 sites in RMCE01 +80386528 803821A8 AX@801268AC stw r0,-0x66D8(r13); AX@8012698C stw r12,-0x66D8(r13); AX@801269E4 lwz r0,-0x66D8(r13) # AX flag 0x66d8, 3 sites in RMCE01 +80386524 803821A4 AX@80126804 lwz r0,-0x66DC(r13); AX@80126910 stw r0,-0x66DC(r13); AX@801269C0 stw r12,-0x66DC(r13) # AX flag 0x66dc, 3 sites in RMCE01 + +# The three .sdata halfwords __AXOutInitDSP copies into the AX DSPTaskInfo: the ucode length +# (task+0x10) and the DSP init/resume vectors (task+0x24/+0x26). The runtime's AX stub reads +# the same three when it builds the task. +80385800 80381480 __AXOutInitDSP@80126974 lhz r8,-0x7400(r13) -> sth r8,0x24(task) # dsp_init_vector +80385802 80381482 __AXOutInitDSP@8012697C lhz r0,-0x73fe(r13) -> sth r0,0x26(task) # dsp_resume_vector +80385804 80381484 __AXOutInitDSP@8012696C lhz r31,-0x73fc(r13) -> stw r31,0x10(task) # iram_length (ucode length) + +# EGG fog constants in .sdata2, read through r2 by the EGG::StateGX fog-quad code. Unlike the +# .sbss globals above, the r2 offset of these three is 8 LARGER in NTSC-U than in PAL, while +# NTSC-J and NTSC-K keep PAL's offset. The values settle it: at the addresses below all four +# regions read 0.0 / 0.99 / 0.5, whereas NTSC-U at PAL's offset reads 176.0 / 176.0 / 1.0 - +# so the runtime's old hardcoded PAL r2 offsets were reading the wrong constants on NTSC-U only. +80388DD0 80384A48 EGG@8022D3F0 lfs r0,-0x61D8(r2); EGG@8022D71C lfs r2,-0x61D8(r2); EGG@8022D7A0 lfs r5,-0x61D8(r2); EGG@8022DB0C lfs r31,-0x61D8(r2) # EGG fog origin (m!=2), 9 sites in RMCE01 +80388DE0 80384A58 EGG@8022DB24 lfs r0,-0x61C8(r2); EGG@8022DEBC lfs r0,-0x61C8(r2); EGG@8022E018 lfs r0,-0x61C8(r2) # EGG fog span, 3 sites in RMCE01 +80388DF4 80384A6C EGG@8022DE7C lfs r31,-0x61B4(r2); EGG@8022DE90 lfs r30,-0x61B4(r2); EGG@8022DFD8 lfs r31,-0x61B4(r2); EGG@8022DFEC lfs r30,-0x61B4(r2) # EGG fog origin (m==2), 4 sites in RMCE01 +8029CEB0 80298B70 SCGetProductArea@801b2320 lis r30,0x802a; @801b2324 addi r30,r30,-0x7490 (=0x80298B70, SC area table; 13 records identical to PAL) +8029CEF8 80298BB8 SCGetProductGameRegion@801b2448 lis r30,0x802a; @801b244c addi r30,r30,-0x7448 (=0x80298BB8, SC game region table; 4 records identical to PAL) diff --git a/projects/mkwii-ntsc-u/recomp.yml b/projects/mkwii-ntsc-u/recomp.yml new file mode 100644 index 0000000..2243c28 --- /dev/null +++ b/projects/mkwii-ntsc-u/recomp.yml @@ -0,0 +1,72 @@ +schema_version: 1 +workspace_root: ../.. + +# Mario Kart Wii NTSC-U (RMCE01). The same translation surface as projects/mkwii/recomp.yml, with +# the facts that differ per region: the small-data bases the DOL's __init_registers installs, the +# StaticR.rel load address and the clean-input digests. The function map is the PAL map ported +# through the community region table and validated against these binaries. +project: + id: mkwii-rmce01 + display_name: Mario Kart Wii NTSC-U + game_id: RMCE01 + region: E + base_manifest_format: mkwii-recomp-base-manifest + base_manifest_stem: mkwii_base + +memory: + base: 0x80000000 + size: 0x01A00000 + sda_base: 0x80388880 + sda2_base: 0x8038AC20 + +inputs: + dol: + path: Assets/main.dol + sha256: d2beec1b1645fcd134efe9e7e63774b546667764ed8d431029daccd725995694 + + rel: + path: Assets/StaticR.rel + load_address: 0x8050BF60 + sha256: 1168107f8fdef27a356df76036db55afe4fbf7752606dbac991726701133a617 + +translation: + entry_points: + - 0x800060A4 + function_map: + path: projects/mkwii-ntsc-u/MAP.txt + allow_unsupported_instructions: false + +runtime: + native_registration_root: runtime/src + native_abi_directories: + - runtime/src/hle/gx + +output: + root: generated + functions: functions + runtime_config: RuntimeConfig.h + data_initializer: data_sections_init.cpp + base_manifest: ../build/base/mkwii_base_manifest.json + +# Code.pul carries a separate chunk for this region. The regional link base determines +# the branch bytes checked at startup; execution is remapped to module_guest_base. +profiles: + retro-rewind: + enabled: true + requires_game_id: RMCE01 + requires_dol_sha256: d2beec1b1645fcd134efe9e7e63774b546667764ed8d431029daccd725995694 + code_pul: PulsarPacks/completed/RetroRewind/RetroRewind6/Binaries/Code.pul + mod_root: PulsarPacks/completed/RetroRewind/RetroRewind6 + region: E + module_guest_base: 0x81800000 + module_link_base: 0x80394F60 + output: build/mods/retro_rewind_full_cpp + enable_retro_wfc: true + retro_wfc_payload: https://rwfc.net/api/wfc/payload?g=RMCED00 + retro_wfc_legacy_bootstrap_hook: 0x800ED648 + riivolution: + xml: xml/RetroRewind6.xml + options: + - section: Retro Rewind + option: Pack + choice: 1 diff --git a/projects/mkwii-ntsc-u/region_port.json b/projects/mkwii-ntsc-u/region_port.json new file mode 100644 index 0000000..caf2845 --- /dev/null +++ b/projects/mkwii-ntsc-u/region_port.json @@ -0,0 +1,1826 @@ +{ + "source_region": "P", + "target_region": "E", + "attribution": "chunk table and section layouts vendored from the mkw-sp project (https://github.com/mkw-sp/mkw-sp, port.py)", + "license": "MIT. Copyright (c) 2021-2023 Pablo Stebler. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.", + "port_rule": "if src_start <= a < src_end then a - src_start + dst_start", + "address_format": "hex strings", + "chunks": [ + [ + "0x80004000", + "0x80008030", + "0x80004000" + ], + [ + "0x8000808C", + "0x8000ADBC", + "0x8000804C" + ], + [ + "0x8000AF24", + "0x8000B6B4", + "0x8000AE84" + ], + [ + "0x8000B6B4", + "0x8000C174", + "0x80021048" + ], + [ + "0x8000C174", + "0x80021BA8", + "0x8000B614" + ], + [ + "0x80021BA8", + "0x80225F1C", + "0x80021B08" + ], + [ + "0x802261F8", + "0x802402E0", + "0x80225E74" + ], + [ + "0x802402E0", + "0x80240E18", + "0x802441FC" + ], + [ + "0x80240E18", + "0x80244DD4", + "0x8023FF5C" + ], + [ + "0x802A4080", + "0x80384C18", + "0x8029FD00" + ], + [ + "0x80385908", + "0x8038590C", + "0x80381588" + ], + [ + "0x80385FC0", + "0x80386008", + "0x80381C40" + ], + [ + "0x80386638", + "0x80386644", + "0x803822B8" + ], + [ + "0x80386F48", + "0x80386F90", + "0x80382BC0" + ], + [ + "0x805103B4", + "0x80510A90", + "0x8050C034" + ], + [ + "0x80510B84", + "0x8052D298", + "0x8050C710" + ], + [ + "0x8052D298", + "0x8052D96C", + "0x8054F800" + ], + [ + "0x8052D96C", + "0x8053D97C", + "0x80528E24" + ], + [ + "0x8053D97C", + "0x8053E370", + "0x8054FED4" + ], + [ + "0x8053E370", + "0x8054FB2C", + "0x80538E34" + ], + [ + "0x8054FB2C", + "0x80550548", + "0x805508C8" + ], + [ + "0x80550548", + "0x805537CC", + "0x8054A5F0" + ], + [ + "0x80553894", + "0x8055572C", + "0x8054D874" + ], + [ + "0x8055572C", + "0x8056AB6C", + "0x805513AC" + ], + [ + "0x8056AB6C", + "0x8056B63C", + "0x805AE0E8" + ], + [ + "0x8056B63C", + "0x80574030", + "0x805667EC" + ], + [ + "0x80574030", + "0x805758AC", + "0x805AEBB8" + ], + [ + "0x80575A44", + "0x80583F2C", + "0x8056F1E0" + ], + [ + "0x80583F2C", + "0x8059B5A4", + "0x8057D708" + ], + [ + "0x8059B5A4", + "0x8059EAA4", + "0x805B058C" + ], + [ + "0x8059EAA4", + "0x805A0558", + "0x80594D80" + ], + [ + "0x805A068C", + "0x805A1478", + "0x805B3AC8" + ], + [ + "0x805A1488", + "0x805A1864", + "0x805B48B4" + ], + [ + "0x805A1864", + "0x805A9EDC", + "0x8059682C" + ], + [ + "0x805A9EDC", + "0x805AB574", + "0x8059EEAC" + ], + [ + "0x805AB574", + "0x805ABC90", + "0x805A0604" + ], + [ + "0x805ABC90", + "0x805ADD98", + "0x805A0D28" + ], + [ + "0x805ADD98", + "0x805B9010", + "0x805A2E70" + ], + [ + "0x805B9010", + "0x805B9300", + "0x805B4C90" + ], + [ + "0x805B9300", + "0x805BAB40", + "0x8061F7F4" + ], + [ + "0x805BAB40", + "0x805BB2B8", + "0x805B4F80" + ], + [ + "0x805BB2B8", + "0x805BD2D8", + "0x80621034" + ], + [ + "0x805BD2D8", + "0x805BD2E4", + "0x805B695C" + ], + [ + "0x805BD2E4", + "0x805BD39C", + "0x80623054" + ], + [ + "0x805BD39C", + "0x805BE600", + "0x805B56F8" + ], + [ + "0x805BE600", + "0x805BE61C", + "0x805B6968" + ], + [ + "0x805BE66C", + "0x805BE7F4", + "0x8062310C" + ], + [ + "0x805BE7F4", + "0x805BE84C", + "0x805B76D0" + ], + [ + "0x805BE84C", + "0x805BED68", + "0x80623294" + ], + [ + "0x805BED68", + "0x805BED74", + "0x805B7420" + ], + [ + "0x805BED74", + "0x805BF2D8", + "0x806237B0" + ], + [ + "0x805BF2D8", + "0x805BF2DC", + "0x805B919C" + ], + [ + "0x805BF3CC", + "0x805BFE1C", + "0x805B69D0" + ], + [ + "0x805BFE1C", + "0x805C00C0", + "0x805B742C" + ], + [ + "0x805C00C0", + "0x805C1B34", + "0x805B7728" + ], + [ + "0x805C1B34", + "0x805C35F8", + "0x805B91A0" + ], + [ + "0x805C35F8", + "0x805C3BCC", + "0x80623E08" + ], + [ + "0x805C3BCC", + "0x805C4768", + "0x805BAC64" + ], + [ + "0x805C4768", + "0x805C579C", + "0x806243DC" + ], + [ + "0x805C57B0", + "0x805CADDC", + "0x805BB800" + ], + [ + "0x805CADDC", + "0x805CC0A8", + "0x80625424" + ], + [ + "0x805CC1B4", + "0x805CD94C", + "0x80626758" + ], + [ + "0x805CD94C", + "0x805D1888", + "0x805C0E2C" + ], + [ + "0x805D1888", + "0x805D1E84", + "0x80627EF0" + ], + [ + "0x805D1E84", + "0x805D7F78", + "0x805C4D68" + ], + [ + "0x805D7F78", + "0x805DBFDC", + "0x806284EC" + ], + [ + "0x805DC034", + "0x805DE838", + "0x8062C550" + ], + [ + "0x805DE838", + "0x805DE844", + "0x805E4438" + ], + [ + "0x805DE844", + "0x805E0C38", + "0x8062ED54" + ], + [ + "0x805E0C38", + "0x805E6B50", + "0x805CAE5C" + ], + [ + "0x805E6B50", + "0x805E7460", + "0x80631148" + ], + [ + "0x805E7460", + "0x805EA780", + "0x805D0D74" + ], + [ + "0x805EA780", + "0x805EEB68", + "0x80631A58" + ], + [ + "0x805EEB68", + "0x805F2D24", + "0x805D4094" + ], + [ + "0x805F2D24", + "0x805F8B34", + "0x80635E40" + ], + [ + "0x805F8B34", + "0x805FB5BC", + "0x805D8250" + ], + [ + "0x805FB5BC", + "0x805FB820", + "0x8063BC50" + ], + [ + "0x805FB820", + "0x805FD518", + "0x805DACD8" + ], + [ + "0x805FD518", + "0x806012B0", + "0x8063BEB4" + ], + [ + "0x806012B0", + "0x80608D18", + "0x805DC9D0" + ], + [ + "0x80608D18", + "0x8060A72C", + "0x805E4444" + ], + [ + "0x8060A72C", + "0x8061186C", + "0x8063FC4C" + ], + [ + "0x8061186C", + "0x80616844", + "0x805E5E58" + ], + [ + "0x80616844", + "0x8061AE6C", + "0x80646D8C" + ], + [ + "0x8061AE6C", + "0x8061E898", + "0x805EAE30" + ], + [ + "0x8061E898", + "0x8061F6E8", + "0x8064B3B4" + ], + [ + "0x8061F6E8", + "0x80620CB4", + "0x805EE85C" + ], + [ + "0x80620D7C", + "0x80634F48", + "0x805EFEC8" + ], + [ + "0x80634F48", + "0x80637494", + "0x806040B0" + ], + [ + "0x80637494", + "0x80637514", + "0x806066A4" + ], + [ + "0x80637514", + "0x80637A30", + "0x8064C204" + ], + [ + "0x80637AC0", + "0x8063BCF8", + "0x80606720" + ], + [ + "0x8063BE40", + "0x806453E4", + "0x8060AA20" + ], + [ + "0x806453E4", + "0x806467D4", + "0x8064C78C" + ], + [ + "0x806467D4", + "0x8064A3F4", + "0x80613FC4" + ], + [ + "0x8064A3F4", + "0x8064AEE4", + "0x8064DB7C" + ], + [ + "0x8064AEF8", + "0x80651BEC", + "0x80617BE4" + ], + [ + "0x80651BEC", + "0x80652300", + "0x8064E66C" + ], + [ + "0x80652300", + "0x80653208", + "0x8061E8EC" + ], + [ + "0x80653208", + "0x8065B354", + "0x8064ED80" + ], + [ + "0x8065B4E8", + "0x8065C0EC", + "0x80656ECC" + ], + [ + "0x8065C0EC", + "0x8065FA14", + "0x8065CD74" + ], + [ + "0x8065FA4C", + "0x8065FE4C", + "0x80657AD0" + ], + [ + "0x8065FE4C", + "0x80662778", + "0x80657F10" + ], + [ + "0x80662778", + "0x80663194", + "0x80660694" + ], + [ + "0x80663194", + "0x80665538", + "0x8065A83C" + ], + [ + "0x80665538", + "0x80668814", + "0x80673188" + ], + [ + "0x80668814", + "0x8067906C", + "0x806610B0" + ], + [ + "0x8067906C", + "0x80679380", + "0x80676464" + ], + [ + "0x80679380", + "0x8067AC00", + "0x80671908" + ], + [ + "0x8067AC00", + "0x806BF4C8", + "0x80676778" + ], + [ + "0x806BF4C8", + "0x806BFB14", + "0x806E20A8" + ], + [ + "0x806BFB14", + "0x806C050C", + "0x806BB040" + ], + [ + "0x806C050C", + "0x806C35A8", + "0x806E26F4" + ], + [ + "0x806C35A8", + "0x806C3AA4", + "0x806BBA38" + ], + [ + "0x806C3AA4", + "0x806C4ED4", + "0x806E5790" + ], + [ + "0x806C4EF0", + "0x806C63A8", + "0x806E6BC0" + ], + [ + "0x806C63B0", + "0x806C6B44", + "0x806E8078" + ], + [ + "0x806C6B44", + "0x806CCE90", + "0x806BBF50" + ], + [ + "0x806CCE90", + "0x806CE820", + "0x806E880C" + ], + [ + "0x806CE828", + "0x806D02BC", + "0x806C229C" + ], + [ + "0x806D02BC", + "0x806D28F4", + "0x806EA19C" + ], + [ + "0x806D2908", + "0x806D5C5C", + "0x806C3D38" + ], + [ + "0x806D5C60", + "0x806D5ED8", + "0x806EC7D4" + ], + [ + "0x806D5ED8", + "0x806DA914", + "0x806C7098" + ], + [ + "0x806DA914", + "0x806DB184", + "0x806ECA58" + ], + [ + "0x806DB184", + "0x806DDA84", + "0x806CBAD4" + ], + [ + "0x806DDA84", + "0x806DEB40", + "0x806ED2C8" + ], + [ + "0x806DEB40", + "0x806DF7D0", + "0x806CE3D4" + ], + [ + "0x806DF7D0", + "0x806DFD14", + "0x806EE384" + ], + [ + "0x806DFD14", + "0x806E3A8C", + "0x806CF064" + ], + [ + "0x806E3A8C", + "0x806E3E20", + "0x806EE8C8" + ], + [ + "0x806E3E20", + "0x806E95B0", + "0x806D2DDC" + ], + [ + "0x806E95B0", + "0x806EC7C0", + "0x806EEC5C" + ], + [ + "0x806EC7C0", + "0x806ED53C", + "0x806D8564" + ], + [ + "0x806ED53C", + "0x806F62FC", + "0x806D92E8" + ], + [ + "0x806F62FC", + "0x806F7698", + "0x806F1E74" + ], + [ + "0x806F77C4", + "0x806F7A54", + "0x80713A78" + ], + [ + "0x806F7AA8", + "0x806F8220", + "0x80713D08" + ], + [ + "0x806F8220", + "0x806F8934", + "0x806F3210" + ], + [ + "0x806F8934", + "0x806FA3FC", + "0x806F3978" + ], + [ + "0x806FA3FC", + "0x806FE240", + "0x806F5494" + ], + [ + "0x806FE240", + "0x806FE9E0", + "0x806F9330" + ], + [ + "0x806FE9E0", + "0x807001A4", + "0x80714480" + ], + [ + "0x80700230", + "0x80700474", + "0x80715C44" + ], + [ + "0x80700474", + "0x8070E7B8", + "0x806F9AD0" + ], + [ + "0x8070E7B8", + "0x8070F8B8", + "0x80715E88" + ], + [ + "0x8070F8B8", + "0x807179C4", + "0x80707E14" + ], + [ + "0x807179C4", + "0x80717E34", + "0x8070FFAC" + ], + [ + "0x80717E34", + "0x807182E8", + "0x80716F88" + ], + [ + "0x807182E8", + "0x8071B86C", + "0x8071041C" + ], + [ + "0x8071B86C", + "0x80726574", + "0x8071743C" + ], + [ + "0x80726574", + "0x8072820C", + "0x8073C5DC" + ], + [ + "0x8072821C", + "0x807285C8", + "0x8073E274" + ], + [ + "0x807285CC", + "0x80729338", + "0x8073E620" + ], + [ + "0x80729350", + "0x80729B88", + "0x80722144" + ], + [ + "0x80729B88", + "0x8072A894", + "0x80722984" + ], + [ + "0x8072A894", + "0x8072B95C", + "0x80723698" + ], + [ + "0x8072B95C", + "0x8072DE64", + "0x80724770" + ], + [ + "0x8072DFCC", + "0x8072FF60", + "0x8073F390" + ], + [ + "0x8072FF78", + "0x80730198", + "0x80741324" + ], + [ + "0x80730198", + "0x80730A80", + "0x80726DE8" + ], + [ + "0x80730B40", + "0x80731960", + "0x80741544" + ], + [ + "0x80731960", + "0x80735948", + "0x807277A8" + ], + [ + "0x80735948", + "0x80738DB8", + "0x80742364" + ], + [ + "0x80738DB8", + "0x8073C54C", + "0x8072B790" + ], + [ + "0x8073C54C", + "0x8073EDF0", + "0x807457D4" + ], + [ + "0x8073EDF0", + "0x8074C4A8", + "0x8072EF24" + ], + [ + "0x8074C4A8", + "0x8074D5B8", + "0x8076CEAC" + ], + [ + "0x8074D5B8", + "0x807519C8", + "0x80748078" + ], + [ + "0x807519C8", + "0x80754104", + "0x8076DFBC" + ], + [ + "0x80754104", + "0x80758BDC", + "0x8074C488" + ], + [ + "0x80758BDC", + "0x8075DB24", + "0x807706F8" + ], + [ + "0x8075DB3C", + "0x8075E78C", + "0x80750F60" + ], + [ + "0x8075E78C", + "0x8075EAFC", + "0x80775658" + ], + [ + "0x8075EAFC", + "0x80765C94", + "0x80751BB0" + ], + [ + "0x80765C94", + "0x807678F4", + "0x807759C8" + ], + [ + "0x807678F4", + "0x80768D20", + "0x80758D48" + ], + [ + "0x80768D20", + "0x807693EC", + "0x80777628" + ], + [ + "0x8076960C", + "0x8076C85C", + "0x80777E68" + ], + [ + "0x8076C85C", + "0x8076EBDC", + "0x8075A174" + ], + [ + "0x8076EBE0", + "0x8076F2DC", + "0x8077B0B8" + ], + [ + "0x8076F2DC", + "0x807726C4", + "0x8075C4F4" + ], + [ + "0x80772704", + "0x80773C14", + "0x8077B7B8" + ], + [ + "0x80773C1C", + "0x8077439C", + "0x8075F8DC" + ], + [ + "0x807743A0", + "0x807787F0", + "0x8076010C" + ], + [ + "0x807787F0", + "0x8077902C", + "0x8077CD10" + ], + [ + "0x8077902C", + "0x8077CE88", + "0x8076455C" + ], + [ + "0x8077CEC8", + "0x8077DF24", + "0x8077D54C" + ], + [ + "0x8077DF24", + "0x807829D8", + "0x807683F8" + ], + [ + "0x807829D8", + "0x80787D84", + "0x8077E5A8" + ], + [ + "0x80787D84", + "0x8078C960", + "0x807D031C" + ], + [ + "0x8078C960", + "0x807A81B4", + "0x80783954" + ], + [ + "0x807A81B4", + "0x807A9D70", + "0x807D4F74" + ], + [ + "0x807A9EB8", + "0x807AF140", + "0x8079F210" + ], + [ + "0x807AF140", + "0x807B2EF8", + "0x807D6B94" + ], + [ + "0x807B2EF8", + "0x807D976C", + "0x807A4498" + ], + [ + "0x807D976C", + "0x807D9B80", + "0x807DA94C" + ], + [ + "0x807D9B98", + "0x807DA5C0", + "0x807CAD0C" + ], + [ + "0x807DA5C0", + "0x807DBCCC", + "0x807DAD78" + ], + [ + "0x807DBCCC", + "0x807DC8C8", + "0x807CB734" + ], + [ + "0x807DC950", + "0x807E093C", + "0x807CC330" + ], + [ + "0x807E093C", + "0x807E2520", + "0x8083C6F0" + ], + [ + "0x807E259C", + "0x807E5610", + "0x807DC50C" + ], + [ + "0x807E5654", + "0x807E6414", + "0x807DF5E4" + ], + [ + "0x807E6414", + "0x807E9C44", + "0x8083E33C" + ], + [ + "0x807E9C50", + "0x807EDD98", + "0x807E03A4" + ], + [ + "0x807EDD98", + "0x807EE23C", + "0x80841B6C" + ], + [ + "0x807EE250", + "0x807EE468", + "0x807E44EC" + ], + [ + "0x807EE474", + "0x807EEA14", + "0x80842010" + ], + [ + "0x807EEA14", + "0x807EF9F4", + "0x807E4704" + ], + [ + "0x807EFD0C", + "0x807F76EC", + "0x807E56E4" + ], + [ + "0x807F76EC", + "0x807F7BA4", + "0x808428E8" + ], + [ + "0x807F7BC4", + "0x807F890C", + "0x807ED0C4" + ], + [ + "0x807F8968", + "0x807F9280", + "0x80842DA0" + ], + [ + "0x807F9580", + "0x807FAB58", + "0x808438A0" + ], + [ + "0x807FAB58", + "0x807FEB68", + "0x807EDF98" + ], + [ + "0x807FEB68", + "0x807FFAE0", + "0x80844E78" + ], + [ + "0x807FFB20", + "0x80805A0C", + "0x807F1FA8" + ], + [ + "0x80805A0C", + "0x8080761C", + "0x80845DF0" + ], + [ + "0x8080761C", + "0x80809448", + "0x807F7ED4" + ], + [ + "0x80809448", + "0x8080AD20", + "0x80847A00" + ], + [ + "0x8080AD20", + "0x80811E48", + "0x807F9D00" + ], + [ + "0x80811E48", + "0x80813BD4", + "0x808492D8" + ], + [ + "0x80813BD4", + "0x8081E284", + "0x80800E28" + ], + [ + "0x8081E284", + "0x8081EFEC", + "0x8084B064" + ], + [ + "0x8081EFEC", + "0x8082E540", + "0x8080B4D8" + ], + [ + "0x8082E540", + "0x8082E854", + "0x8084BDCC" + ], + [ + "0x8082E854", + "0x8082F408", + "0x8081AA2C" + ], + [ + "0x8082F408", + "0x808334A0", + "0x8084C0E0" + ], + [ + "0x808334E0", + "0x80833B00", + "0x8081B5E0" + ], + [ + "0x80833B00", + "0x80838E4C", + "0x8081BC08" + ], + [ + "0x80838E60", + "0x8083B0C0", + "0x808501B8" + ], + [ + "0x8083B0CC", + "0x8083CB44", + "0x80820F54" + ], + [ + "0x8083CB44", + "0x8083D42C", + "0x80852424" + ], + [ + "0x8083D42C", + "0x80842334", + "0x808229CC" + ], + [ + "0x80842340", + "0x808447AC", + "0x80852D0C" + ], + [ + "0x808447AC", + "0x8084A9A0", + "0x808278D4" + ], + [ + "0x8084A9A0", + "0x8084D0DC", + "0x80855184" + ], + [ + "0x8084D0DC", + "0x80851D2C", + "0x8082DAC8" + ], + [ + "0x80851D38", + "0x80852C60", + "0x808578C0" + ], + [ + "0x80852C60", + "0x80853CA4", + "0x80832718" + ], + [ + "0x80853CA4", + "0x808551EC", + "0x808587F4" + ], + [ + "0x808551EC", + "0x8085C3CC", + "0x8083375C" + ], + [ + "0x8085C3CC", + "0x8085E674", + "0x80859D3C" + ], + [ + "0x8085E674", + "0x8085F0AC", + "0x8083A950" + ], + [ + "0x8085F0AC", + "0x8085FFD4", + "0x8085BFE4" + ], + [ + "0x8085FFD4", + "0x80860F2C", + "0x8083B388" + ], + [ + "0x80860F2C", + "0x80862E24", + "0x8085CF0C" + ], + [ + "0x80863234", + "0x8086708C", + "0x8085EE04" + ], + [ + "0x8086708C", + "0x808676E0", + "0x80864D38" + ], + [ + "0x808676E0", + "0x808697BC", + "0x80862C5C" + ], + [ + "0x808697BC", + "0x8086A254", + "0x8086538C" + ], + [ + "0x8086A254", + "0x8086C098", + "0x808766F4" + ], + [ + "0x8086C108", + "0x8086C988", + "0x80878538" + ], + [ + "0x8086CA40", + "0x80872CA4", + "0x80878DB8" + ], + [ + "0x80872CA4", + "0x808739B0", + "0x80865E24" + ], + [ + "0x808739B0", + "0x80875454", + "0x80866BE8" + ], + [ + "0x80875454", + "0x8088344C", + "0x808686FC" + ], + [ + "0x8088344C", + "0x8088F400", + "0x8087F01C" + ], + [ + "0x808913C0", + "0x808913C4", + "0x8088CF78" + ], + [ + "0x80895238", + "0x808952B8", + "0x8088F940" + ], + [ + "0x808AD3C4", + "0x808AD3C8", + "0x808A7304" + ], + [ + "0x808B3984", + "0x808B3988", + "0x808AF134" + ], + [ + "0x808B5B1C", + "0x808B5B20", + "0x808B125C" + ], + [ + "0x808B5C78", + "0x808B5C7C", + "0x808B13B8" + ], + [ + "0x808BB034", + "0x808BB098", + "0x808B4F3C" + ], + [ + "0x808CB550", + "0x808CB554", + "0x808C6048" + ], + [ + "0x808D3698", + "0x808D369C", + "0x808D5148" + ], + [ + "0x808D36CC", + "0x808D36D0", + "0x808D517C" + ], + [ + "0x808D36D4", + "0x808D36D8", + "0x808D5184" + ], + [ + "0x808D3744", + "0x808D3748", + "0x808D51F4" + ], + [ + "0x808D374C", + "0x808D3750", + "0x808D51FC" + ], + [ + "0x808D3E14", + "0x808D3E18", + "0x808CEEAC" + ], + [ + "0x808DA070", + "0x808DA080", + "0x808D3E50" + ], + [ + "0x808DA318", + "0x808DA368", + "0x808D3F60" + ], + [ + "0x809BD6E8", + "0x809BD74C", + "0x809B8F28" + ], + [ + "0x809C1830", + "0x809C1834", + "0x809BD070" + ], + [ + "0x809C1874", + "0x809C1878", + "0x809BD0B4" + ], + [ + "0x809C18F8", + "0x809C18FC", + "0x809BD110" + ], + [ + "0x809C1988", + "0x809C198C", + "0x809BD378" + ], + [ + "0x809C19A0", + "0x809C19BC", + "0x809BD180" + ], + [ + "0x809C1E38", + "0x809C1E3C", + "0x809BD508" + ], + [ + "0x809C21D0", + "0x809C21D4", + "0x809BDA10" + ], + [ + "0x809C21D8", + "0x809C21DC", + "0x809BDA18" + ], + [ + "0x809C2328", + "0x809C232C", + "0x809BDB60" + ], + [ + "0x809C27F0", + "0x809C27FC", + "0x809BDBB0" + ], + [ + "0x809C282C", + "0x809C2854", + "0x809BDBEC" + ], + [ + "0x809C28B8", + "0x809C28BC", + "0x809BE0F8" + ], + [ + "0x809C2BE8", + "0x809C2BEC", + "0x809BE398" + ], + [ + "0x809C2EF0", + "0x809C2EF4", + "0x809BE730" + ], + [ + "0x809C2F38", + "0x809C2F40", + "0x809BE740" + ], + [ + "0x809C2F44", + "0x809C2F48", + "0x809BE74C" + ], + [ + "0x809C3618", + "0x809C361C", + "0x809BEE20" + ], + [ + "0x809C38B8", + "0x809C38BC", + "0x809BF0B0" + ], + [ + "0x809C4330", + "0x809C4334", + "0x809BFAF0" + ], + [ + "0x809C4680", + "0x809C4684", + "0x809BFDC0" + ], + [ + "0x809C4740", + "0x809C474C", + "0x809BFF90" + ], + [ + "0x809C496C", + "0x809C4970", + "0x809C014C" + ] + ], + "rel_load_address": { + "P": "0x805102E0", + "E": "0x8050BF60", + "J": "0x8050FC60" + }, + "dol_sections": { + "P": [ + { + "name": "init", + "start": "0x80004000", + "end": "0x80006460" + }, + { + "name": "extab", + "start": "0x80006460", + "end": "0x80006A20" + }, + { + "name": "extabindex", + "start": "0x80006A20", + "end": "0x800072C0" + }, + { + "name": "text", + "start": "0x800072C0", + "end": "0x80244DE0" + }, + { + "name": "ctors", + "start": "0x80244DE0", + "end": "0x80244EA0" + }, + { + "name": "dtors", + "start": "0x80244EA0", + "end": "0x80244EC0" + }, + { + "name": "rodata", + "start": "0x80244EC0", + "end": "0x80258580" + }, + { + "name": "data", + "start": "0x80258580", + "end": "0x802A4040" + }, + { + "name": "bss", + "start": "0x802A4080", + "end": "0x80384C00" + }, + { + "name": "sdata", + "start": "0x80384C00", + "end": "0x80385FC0" + }, + { + "name": "sbss", + "start": "0x80385FC0", + "end": "0x80386FA0" + }, + { + "name": "sdata2", + "start": "0x80386FA0", + "end": "0x80389140" + }, + { + "name": "sbss2", + "start": "0x80389140", + "end": "0x8038917C" + } + ], + "E": [ + { + "name": "init", + "start": "0x80004000", + "end": "0x80006460" + }, + { + "name": "extab", + "start": "0x80006460", + "end": "0x80006A20" + }, + { + "name": "extabindex", + "start": "0x80006A20", + "end": "0x800072C0" + }, + { + "name": "text", + "start": "0x800072C0", + "end": "0x80244D40" + }, + { + "name": "ctors", + "start": "0x80244D40", + "end": "0x80244E00" + }, + { + "name": "dtors", + "start": "0x80244E00", + "end": "0x80244E20" + }, + { + "name": "rodata", + "start": "0x80244E40", + "end": "0x80258260" + }, + { + "name": "data", + "start": "0x80258260", + "end": "0x8029FD00" + }, + { + "name": "bss", + "start": "0x8029FD00", + "end": "0x80380880" + }, + { + "name": "sdata", + "start": "0x80380880", + "end": "0x80381C40" + }, + { + "name": "sbss", + "start": "0x80381C40", + "end": "0x80382C20" + }, + { + "name": "sdata2", + "start": "0x80382C20", + "end": "0x80384DC0" + }, + { + "name": "sbss2", + "start": "0x80384DC0", + "end": "0x80384DFC" + } + ], + "J": [ + { + "name": "init", + "start": "0x80004000", + "end": "0x80006460" + }, + { + "name": "extab", + "start": "0x80006460", + "end": "0x80006A20" + }, + { + "name": "extabindex", + "start": "0x80006A20", + "end": "0x800072C0" + }, + { + "name": "text", + "start": "0x800072C0", + "end": "0x80244D00" + }, + { + "name": "ctors", + "start": "0x80244D00", + "end": "0x80244DC0" + }, + { + "name": "dtors", + "start": "0x80244DC0", + "end": "0x80244DE0" + }, + { + "name": "rodata", + "start": "0x80244E00", + "end": "0x80257F20" + }, + { + "name": "data", + "start": "0x80257F20", + "end": "0x802A39E0" + }, + { + "name": "bss", + "start": "0x802A3A00", + "end": "0x80384580" + }, + { + "name": "sdata", + "start": "0x80384580", + "end": "0x80385940" + }, + { + "name": "sbss", + "start": "0x80385940", + "end": "0x80386920" + }, + { + "name": "sdata2", + "start": "0x80386920", + "end": "0x80388AC0" + }, + { + "name": "sbss2", + "start": "0x80388AC0", + "end": "0x80388AFC" + } + ] + }, + "rel_sections": { + "P": [ + { + "name": "text", + "start": "0x805103B4", + "end": "0x8088F400" + }, + { + "name": "ctors", + "start": "0x8088F400", + "end": "0x8088F704" + }, + { + "name": "dtors", + "start": "0x8088F704", + "end": "0x8088F710" + }, + { + "name": "rodata", + "start": "0x8088F720", + "end": "0x808B2BD0" + }, + { + "name": "data", + "start": "0x808B2BD0", + "end": "0x808DD3D4" + }, + { + "name": "bss", + "start": "0x809BD6E0", + "end": "0x809C4F90" + } + ], + "E": [ + { + "name": "text", + "start": "0x8050C034", + "end": "0x8088AFD0" + }, + { + "name": "ctors", + "start": "0x8088AFD0", + "end": "0x8088B2D4" + }, + { + "name": "dtors", + "start": "0x8088B2D4", + "end": "0x8088B2E0" + }, + { + "name": "rodata", + "start": "0x8088B2E0", + "end": "0x808AE520" + }, + { + "name": "data", + "start": "0x808AE520", + "end": "0x808D8C7C" + }, + { + "name": "bss", + "start": "0x809B8F20", + "end": "0x809C07D0" + } + ], + "J": [ + { + "name": "text", + "start": "0x8050FD34", + "end": "0x8088EA6C" + }, + { + "name": "ctors", + "start": "0x8088EA6C", + "end": "0x8088ED70" + }, + { + "name": "dtors", + "start": "0x8088ED70", + "end": "0x8088ED7C" + }, + { + "name": "rodata", + "start": "0x8088ED80", + "end": "0x808B1D30" + }, + { + "name": "data", + "start": "0x808B1D30", + "end": "0x808DC524" + }, + { + "name": "bss", + "start": "0x809BC740", + "end": "0x809C3FF0" + } + ] + }, + "validated_against": { + "dol": { + "path": "main.dol", + "sha256": "d2beec1b1645fcd134efe9e7e63774b546667764ed8d431029daccd725995694", + "entry": "0x800060A4" + }, + "rel": { + "path": "StaticR.rel", + "sha256": "1168107f8fdef27a356df76036db55afe4fbf7752606dbac991726701133a617", + "module_id": 1, + "prolog": "0x8054F2FC", + "epilog": "0x8054F348", + "unresolved": "0x8054F390" + } + } +} diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index c34b148..f0d4fd4 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -196,7 +196,14 @@ set(MKW_CPPWINRT_INCLUDE_DIR "" CACHE PATH "Optional self-contained C++/WinRT in # not compiled at all; imported targets with the same names are wired up from # the package instead, so this project's own code compiles and links exactly # as before. -set(MKW_AURORA_DIR "${CMAKE_CURRENT_LIST_DIR}/../aurora-main") +set(MKW_AURORA_DIR "${CMAKE_CURRENT_LIST_DIR}/../aurora-main" CACHE PATH + "Aurora source directory") +if(NOT EXISTS "${MKW_AURORA_DIR}/CMakeLists.txt" + OR NOT EXISTS "${MKW_AURORA_DIR}/include/aurora/aurora.h") + message(FATAL_ERROR + "Aurora sources are missing at ${MKW_AURORA_DIR}. From the repository root, run " + "git submodule update --init --recursive, or set MKW_AURORA_DIR to an initialized Aurora checkout.") +endif() # The translator's explicit float casts are PPC single-precision rounding points. # Fast-math may erase them and change guest-visible integer conversions. @@ -223,9 +230,6 @@ if(MKW_NATIVE_PREBUILT_DIR) # not compiled here. include("${CMAKE_CURRENT_LIST_DIR}/cmake/NativePrebuilt.cmake") else() - if(NOT EXISTS ${MKW_AURORA_DIR}/CMakeLists.txt) - message(FATAL_ERROR "Requested aurora-main but ${MKW_AURORA_DIR} is missing") - endif() set(DAWN_ENABLE_D3D11 OFF CACHE BOOL "" FORCE) if(MKW_PLATFORM_WINDOWS) set(DAWN_ENABLE_D3D12 ON CACHE BOOL "" FORCE) @@ -271,6 +275,19 @@ else() set(SDL_STATIC ON CACHE BOOL "" FORCE) set(SDL_TEST OFF CACHE BOOL "" FORCE) + # Aurora components the runtime does not use. They would otherwise fetch + # extra dependencies at configure time, which offline builds cannot do. + set(AURORA_ENABLE_TESTS OFF CACHE BOOL "" FORCE) + set(AURORA_ENABLE_EXAMPLES OFF CACHE BOOL "" FORCE) + set(AURORA_ENABLE_DVD OFF CACHE BOOL "" FORCE) + set(AURORA_ENABLE_THP OFF CACHE BOOL "" FORCE) + set(AURORA_ENABLE_RMLUI OFF CACHE BOOL "" FORCE) + set(AURORA_ENABLE_CARD OFF CACHE BOOL "" FORCE) + # The runtime implements the Wii SDK itself; Aurora stays on its GameCube SDK. + set(AURORA_TARGET_RVL OFF CACHE BOOL "" FORCE) + # Every dependency comes from the pinned sources, never the build host. + set(AURORA_USE_SYSTEM_DEPENDENCIES OFF CACHE BOOL "" FORCE) + # MinGW/WSL can choke on SDL precompiled headers; disable PCH for aurora/SDL. set(CMAKE_DISABLE_PRECOMPILE_HEADERS ON) # Isolate aurora build products to a subdirectory under the main build dir. @@ -400,7 +417,7 @@ else() add_library(mkw_macos_native_compile OBJECT ${SOURCES}) target_include_directories(mkw_macos_native_compile PRIVATE "${CMAKE_CURRENT_LIST_DIR}/include" "${CMAKE_CURRENT_LIST_DIR}/src" - "${CMAKE_CURRENT_LIST_DIR}/.." "${CMAKE_CURRENT_LIST_DIR}/../aurora-main/include") + "${CMAKE_CURRENT_LIST_DIR}/.." "${MKW_AURORA_DIR}/include") target_compile_features(mkw_macos_native_compile PRIVATE cxx_std_20) target_compile_definitions(mkw_macos_native_compile PRIVATE SDL_MAIN_HANDLED TARGET_PC) target_link_libraries(mkw_macos_native_compile PRIVATE diff --git a/runtime/assets/pipeline/initial_pipeline_cache.db b/runtime/assets/pipeline/initial_pipeline_cache.db index f3856fe561286312a76bfad19d802e8faa03c1db..dbe36daea51a5ea37946dd056acd8cbdc6af2afa 100644 GIT binary patch literal 4567040 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 z01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW0 z3ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWA zpa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S> z01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW0 z3ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWA zpa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S> z01BYM|EK^-kfIWTZ729;Ji$MlPyhu`00mG01yBG5Pyhu`00mG01yBG5Pyhu`00mG0 z1yBG5Pyhu`00mG01yBG5Pyhu`00mG01yBG5Pyhu`00mG01yBG5Pyhu`00mG01yBG5 zPyhu`00mG01yBG5Pyhu`00mG01yBG5Pyhu`00mG01yBG5Pyhu`00mG01yBG5Pyhu` z00mG01yBG5Pyhu`00mG01yBG5Pyhu`00mG01yBG5Pyhu`00mG01yBG5Pyhu`00mG0 z1yBG5Pyhu`00mG01yBG5Pyhu`00mG01yBG5Pyhu`00mG01yBG5Pyhu`00mG01yBG5 zPyhu`00mG01yBG5Pyhu`00mG01yBG5Pyhu`00mG01yBG5Pyhu`00mG01yBG5Pyhu` z00mG01yBG5Pyhu`00mG01yBG5Pyhu`00mG01yBG5Pyhu`00mG01yBG5Pyhu`00mG0 z1yBG5Pyhu`00mG01yBG5Pyhu`00mG01yBG5Pyhu`00sVc1SAQnzvzZ_+m%)sZ81^W zWVBvPu01BW03ZMWApa2S>01BW03ZMWApa2S>01BW0 z3ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWA zpa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S> z01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW0 z3ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWA 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 pd@vs(0_H.h" # instead of a ../ chain whose depth depends on the includer. "${MKW_RUNTIME_SOURCE_DIR}/.." - "${MKW_RUNTIME_SOURCE_DIR}/../aurora-main/include") + "${MKW_AURORA_DIR}/include") target_compile_definitions(${target} PRIVATE SDL_MAIN_HANDLED _DISABLE_STRING_ANNOTATION _DISABLE_VECTOR_ANNOTATION TARGET_PC) target_compile_features(${target} PRIVATE cxx_std_20) @@ -206,7 +213,7 @@ function(mkw_configure_product target) if(MKW_PLATFORM_WINDOWS) target_link_libraries(${target} PRIVATE - dbghelp user32 winmm ws2_32 iphlpapi secur32 crypt32 windowsapp) + dbghelp user32 winmm ws2_32 iphlpapi secur32 crypt32 windowsapp bthprops) set_target_properties(${target} PROPERTIES WIN32_EXECUTABLE TRUE) elseif(MKW_PLATFORM_LINUX OR MKW_PLATFORM_MACOS_X86_64) @@ -286,8 +293,21 @@ function(mkw_configure_product target) endif() endfunction() +if(MKW_PLATFORM_WINDOWS) + enable_language(RC) +endif() + +# Own object library so the products' C++ options never reach the resource compiler. +function(mkw_add_product_icon target) + if(MKW_PLATFORM_WINDOWS) + add_library(${target}_icon OBJECT "${MKW_RUNTIME_SOURCE_DIR}/resources/${target}.rc") + target_sources(${target} PRIVATE $) + endif() +endfunction() + add_executable(WiiCompiled "${MKW_BASE_PRODUCT_SOURCE}") mkw_configure_product(WiiCompiled) +mkw_add_product_icon(WiiCompiled) target_sources(WiiCompiled PRIVATE $) target_precompile_headers(WiiCompiled PRIVATE "${MKW_RUNTIME_SOURCE_DIR}/include/mkw_pch.h") @@ -298,6 +318,7 @@ endif() if(MKW_HAVE_RETRO_REWIND) add_executable(RetroRewind "${MKW_RETRO_REWIND_PRODUCT_SOURCE}") mkw_configure_product(RetroRewind) + mkw_add_product_icon(RetroRewind) target_precompile_headers(RetroRewind REUSE_FROM WiiCompiled) target_sources(RetroRewind PRIVATE $) if(TARGET mkw_retro_sensitive) diff --git a/runtime/cmake/RuntimeLibrary.cmake b/runtime/cmake/RuntimeLibrary.cmake index 75fc9b6..8d6160a 100644 --- a/runtime/cmake/RuntimeLibrary.cmake +++ b/runtime/cmake/RuntimeLibrary.cmake @@ -54,7 +54,7 @@ function(mkw_configure_object_target target) # Workspace root, so translator output is spelled "generated/.h" # instead of a ../ chain whose depth depends on the includer. "${MKW_RUNTIME_SOURCE_DIR}/.." - "${MKW_RUNTIME_SOURCE_DIR}/../aurora-main/include") + "${MKW_AURORA_DIR}/include") target_compile_definitions(${target} PRIVATE TARGET_PC) set_target_properties(${target} PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON) @@ -66,7 +66,7 @@ function(mkw_runtime_link_dependencies target scope) aurora::gx aurora::pad aurora::si aurora::vi aurora::mtx) target_link_libraries(${target} ${scope} mkw_platform mkw::pugixml mkw::toml11 mkw::cryptopp mkw::mbedtls) if(MKW_PLATFORM_WINDOWS) - target_link_libraries(${target} ${scope} shell32 windowsapp) + target_link_libraries(${target} ${scope} shell32 windowsapp bthprops) elseif(MKW_PLATFORM_LINUX OR MKW_PLATFORM_MACOS_X86_64) # ${CMAKE_DL_LIBS} for music_attenuation.cpp's dlopen of libdbus-1 (MPRIS # media monitoring). Empty on platforms where dl* is already in libc/libSystem. diff --git a/runtime/game/guest_region.cpp b/runtime/game/guest_region.cpp new file mode 100644 index 0000000..7504a2e --- /dev/null +++ b/runtime/game/guest_region.cpp @@ -0,0 +1,9 @@ +#include "guest_abi/guest_region.h" + +#if !defined(MKW_TRANSLATED_GUEST_REGION) +#error "MKW_TRANSLATED_GUEST_REGION comes from the translator's shard manifest (emit-build-shards)" +#endif + +static_assert(MKW_TRANSLATED_GUEST_REGION >= 0 && MKW_TRANSLATED_GUEST_REGION < GuestRegion::kCount); + +extern "C" const uint8_t kMkwGuestRegion = MKW_TRANSLATED_GUEST_REGION; diff --git a/runtime/include/abi_bridge.h b/runtime/include/abi_bridge.h index f7474e1..205cd62 100644 --- a/runtime/include/abi_bridge.h +++ b/runtime/include/abi_bridge.h @@ -157,14 +157,14 @@ public: #define MKW_DETAIL_CAT(a, b) a##b #define MKW_DETAIL_MAKE_UNIQUE(a, b) MKW_DETAIL_CAT(a, b) -// Three hand-written registration macros. Generated code never registers per function; every -// translated function reaches the registry via the bulk BulkTranslatedFunctionRecord tables -// in the translator's *_registration TUs. +// Three hand-written registration macros, given the PAL address. Generated code never registers +// per function; every translated function reaches the registry via the bulk +// BulkTranslatedFunctionRecord tables in the translator's *_registration TUs. #define REGISTER_TRANSLATED_FUNCTION(address, fn) \ - static AbiTrampoline MKW_DETAIL_MAKE_UNIQUE(_abi_trampoline_, __COUNTER__)(address, #fn, fn, FunctionKind::BaseTranslated, false, kPpcAllNonvolatileFprMask, 0, 0, nullptr, KnownTranslatedCpuCall
::kMustRemainDynamicallyDispatchable) + static AbiTrampoline MKW_DETAIL_MAKE_UNIQUE(_abi_trampoline_, __COUNTER__)(::GuestRegion::Translate(address), #fn, fn, FunctionKind::BaseTranslated, false, kPpcAllNonvolatileFprMask, 0, 0, nullptr, KnownTranslatedCpuCall
::kMustRemainDynamicallyDispatchable) #define REGISTER_NATIVE_FUNCTION(address, fn) \ - static AbiTrampoline MKW_DETAIL_MAKE_UNIQUE(_abi_native_trampoline_, __COUNTER__)(address, #fn, fn, FunctionKind::Native, false, kPpcAllNonvolatileFprMask, 0, 0, &AbiRawCpuThunk<&fn>::Invoke) + static AbiTrampoline MKW_DETAIL_MAKE_UNIQUE(_abi_native_trampoline_, __COUNTER__)(::GuestRegion::Translate(address), #fn, fn, FunctionKind::Native, false, kPpcAllNonvolatileFprMask, 0, 0, &AbiRawCpuThunk<&fn>::Invoke) #define REGISTER_NATIVE_FUNCTION_AS(address, fn, pretty_name) \ - static AbiTrampoline MKW_DETAIL_MAKE_UNIQUE(_abi_native_trampoline_named_, __COUNTER__)(address, pretty_name, fn, FunctionKind::Native, false, kPpcAllNonvolatileFprMask, 0, 0, &AbiRawCpuThunk<&fn>::Invoke) + static AbiTrampoline MKW_DETAIL_MAKE_UNIQUE(_abi_native_trampoline_named_, __COUNTER__)(::GuestRegion::Translate(address), pretty_name, fn, FunctionKind::Native, false, kPpcAllNonvolatileFprMask, 0, 0, &AbiRawCpuThunk<&fn>::Invoke) diff --git a/runtime/include/aurora_events.h b/runtime/include/aurora_events.h index e10c151..211ebf6 100644 --- a/runtime/include/aurora_events.h +++ b/runtime/include/aurora_events.h @@ -1,7 +1,9 @@ #pragma once +#include "friend_code_keyboard.h" #include "settings_overlay.h" #include "runtime_config.h" +#include "gx_worker.h" #include #include @@ -117,6 +119,7 @@ inline void ProcessAuroraEvents(const AuroraEvent* events) { g_mkwDynamicAspectSurfacePending.store(true, std::memory_order_release); } settings_overlay::HandleEvents(events); + FriendCodeKeyboard::HandleEvents(events); } inline void ApplyPendingMkwDynamicAspectSurface() { @@ -131,14 +134,42 @@ inline void ApplyPendingMkwDynamicAspectSurface() { UpdateMkwDynamicAspectSurface(surfaceWidth, surfaceHeight); } +void GxWorkerBeginFrame(); +void GxWorkerEndFrame(AuroraImguiFrame* imgui); +void SetAuroraFrameGxBegun(bool begun); + inline bool BeginAuroraFrame() { + if (GxWorker::ShouldDefer()) { + // The window half can touch the surface and render targets the worker draws into. + GxWorker::Sync(); + if (!aurora_begin_frame_window()) { + return false; + } + GxWorker::Submit([] { GxWorkerBeginFrame(); }); + ApplyPendingMkwDynamicAspectSurface(); + return true; + } if (!aurora_begin_frame()) { return false; } + SetAuroraFrameGxBegun(true); ApplyPendingMkwDynamicAspectSurface(); return true; } +// Ends the frame; with the GX worker, the game thread joins it here so the next frame never +// overlaps guest memory the worker may still read. +inline void EndAuroraFrame() { + if (GxWorker::ShouldDefer()) { + AuroraImguiFrame* imgui = aurora_end_frame_window(); + GxWorker::Submit([imgui] { GxWorkerEndFrame(imgui); }); + GxWorker::Sync(); + return; + } + aurora_end_frame(); + SetAuroraFrameGxBegun(false); +} + // Poll Aurora events and update cached window/framebuffer dimensions. inline void UpdateAuroraAndProcessEvents() { ProcessAuroraEvents(aurora_update()); diff --git a/runtime/include/bluetooth/bt_bytes.h b/runtime/include/bluetooth/bt_bytes.h new file mode 100644 index 0000000..5af9c71 --- /dev/null +++ b/runtime/include/bluetooth/bt_bytes.h @@ -0,0 +1,19 @@ +#pragma once + +// HCI and L2CAP fields are little-endian. + +#include +#include + +namespace Bluetooth { + +inline uint16_t Le16(const uint8_t* p) { + return static_cast(p[0] | (p[1] << 8)); +} + +inline void PutLe16(std::vector& out, uint16_t v) { + out.push_back(static_cast(v)); + out.push_back(static_cast(v >> 8)); +} + +} // namespace Bluetooth diff --git a/runtime/include/bluetooth/bt_controller.h b/runtime/include/bluetooth/bt_controller.h new file mode 100644 index 0000000..5dd5995 --- /dev/null +++ b/runtime/include/bluetooth/bt_controller.h @@ -0,0 +1,153 @@ +#pragma once + +// Emulated Bluetooth controller behind the Wii's internal USB module +// (/dev/usb/oh1/57e/305). The game's own Broadcom stack (BTE), WUD, WPAD and KPAD +// talk HCI to it; each of the four virtual Wii Remotes it hosts is backed by a +// physical remote on the PC (see RemoteHost), whose HID reports are passed +// through unchanged. Pure host code: no guest memory, so it is unit-testable. + +#include +#include +#include +#include +#include +#include + +namespace Bluetooth { + +// Bluetooth device address in HCI (least significant byte first) order. +using BdAddr = std::array; + +inline constexpr size_t kRemoteSlots = 4; + +enum class LinkState : uint8_t { + Down, // no baseband connection to the game + Connecting, // baseband up, HID channels being opened + Ready, // HID control and interrupt channels open +}; + +// The physical side of the virtual remotes. Called from the thread that drives +// the Controller; implementations synchronize with their own I/O threads. +class RemoteHost { +public: + virtual ~RemoteHost() = default; + // A physical remote is attached to `slot` and can carry a connection. + virtual bool IsAttached(size_t slot) const = 0; + // True once each time the remote on `slot` asks to connect (it was just + // attached, or a button was pressed while it had no connection). + virtual bool ConsumeWake(size_t slot) = 0; + // Next input report (report id first, no HID header), false when none. + virtual bool PopInputReport(size_t slot, std::vector& report) = 0; + // Output report from the game (report id first, no HID header). + virtual void SendOutputReport(size_t slot, const uint8_t* report, size_t size) = 0; + virtual void OnLinkStateChanged(size_t slot, LinkState state) = 0; + // The game ended a working connection; a real remote powers off here. + virtual void OnGuestDisconnect(size_t slot) = 0; + // The game is searching for remotes (its 1+2 / reconnect screens). + virtual void OnGuestInquiry(bool active) = 0; + // "Nintendo RVL-CNT-01" or "Nintendo RVL-CNT-01-TR". + virtual const char* DeviceName(size_t slot) const = 0; +}; + +class RemoteLink; + +class Controller { +public: + explicit Controller(RemoteHost& host); + ~Controller(); + Controller(const Controller&) = delete; + Controller& operator=(const Controller&) = delete; + + // The guest opened / closed the USB device. + void Open(uint64_t nowUs); + void Close(); + bool IsOpen() const { return m_open; } + + // Raw HCI command packet (opcode first, no H4 byte). + void ExecuteCommand(const uint8_t* packet, size_t size, uint64_t nowUs); + // Raw ACL packet from the guest (handle first). + void ReceiveAcl(const uint8_t* packet, size_t size, uint64_t nowUs); + // Advances timers, connection attempts, input forwarding and flow control. + void Tick(uint64_t nowUs); + + bool HasEvent() const { return !m_events.empty(); } + bool PopEvent(std::vector& event); + // ACL data is only handed out once every queued event has been delivered, + // so the guest always sees a connection before data on it. + bool PopAcl(std::vector& packet); + size_t AclQueued() const { return m_acl.size(); } + + LinkState SlotLinkState(size_t slot) const; + bool PageScanEnabled() const { return (m_scanEnable & 0x02) != 0; } + bool InquiryActive() const { return m_inquiry.active; } + + static BdAddr LocalAddress(); + static BdAddr RemoteAddress(size_t slot); + static uint16_t ConnectionHandle(size_t slot); + + // Used by RemoteLink. + void QueueEvent(std::vector event); + void QueueAcl(uint16_t handle, const std::vector& l2capFrame); + RemoteHost& Host() { return m_host; } + uint32_t PageTimeoutUs() const { return static_cast(m_pageTimeoutSlots) * 625u; } + +private: + struct StoredKey { + BdAddr addr{}; + std::array key{}; + }; + struct Inquiry { + bool active = false; + uint64_t endUs = 0; + uint8_t maxResponses = 0; + uint8_t reported = 0; + std::array slotReported{}; + }; + struct Reassembly { + std::vector frame; + size_t expected = 0; + }; + // A reply the controller sends after a delay (page / name request timeouts). + struct PendingEvent { + uint64_t dueUs = 0; + std::vector event; + }; + + void ResetState(bool keepStoredKeys); + void CommandComplete(uint16_t opcode, const std::vector& params); + void CommandStatus(uint16_t opcode, uint8_t status); + void TickInquiry(uint64_t nowUs); + void FinishInquiry(); + void SendNumberOfCompletedPackets(); + int SlotForAddress(const BdAddr& addr) const; + int SlotForHandle(uint16_t handle) const; + const StoredKey* FindStoredKey(const BdAddr& addr) const; + + void HandleLinkControl(uint16_t opcode, const uint8_t* p, size_t n, uint64_t nowUs); + void HandleLinkPolicy(uint16_t opcode, const uint8_t* p, size_t n); + void HandleControllerBaseband(uint16_t opcode, const uint8_t* p, size_t n, uint64_t nowUs); + void HandleInformational(uint16_t opcode, const uint8_t* p, size_t n); + void HandleStatusParameters(uint16_t opcode, const uint8_t* p, size_t n); + void HandleVendor(uint16_t opcode, const uint8_t* p, size_t n); + void UnknownCommand(uint16_t opcode); + + RemoteHost& m_host; + bool m_open = false; + uint8_t m_scanEnable = 0; + uint16_t m_pageTimeoutSlots = 0x2000; + uint8_t m_inquiryMode = 0; + std::array m_classOfDevice{}; + std::array m_localName{}; + Inquiry m_inquiry; + bool m_hostInquiryNotified = false; + std::vector m_storedKeys; + std::array, kRemoteSlots> m_links; + std::array m_completedPackets{}; + std::array m_reassembly; + std::array m_authPending{}; + std::vector m_pending; + std::deque> m_events; + std::deque> m_acl; +}; + +} // namespace Bluetooth diff --git a/runtime/include/bluetooth/bt_remote_link.h b/runtime/include/bluetooth/bt_remote_link.h new file mode 100644 index 0000000..4beea04 --- /dev/null +++ b/runtime/include/bluetooth/bt_remote_link.h @@ -0,0 +1,107 @@ +#pragma once + +// One emulated Wii Remote as seen from the controller: its baseband connection, +// L2CAP channels (SDP, HID control, HID interrupt) and the HID transaction layer +// that carries the physical remote's reports. + +#include "bluetooth/bt_controller.h" + +#include +#include +#include + +namespace Bluetooth { + +class RemoteLink { +public: + enum class Baseband : uint8_t { + Idle, + Requesting, // Connection Request sent, waiting for the guest to accept + Paging, // the guest paged this remote (Create Connection) + Connected, + }; + + RemoteLink(Controller& controller, size_t slot); + + // Drops every connection without telling the guest (controller reset/close). + void Reset(); + void Tick(uint64_t nowUs); + + // Remote side wants a connection and should be offered to the guest's inquiry. + bool Discoverable() const; + bool ConnectWanted() const { return m_connectWanted; } + + // Guest accepted / rejected this remote's Connection Request. + bool IsRequesting() const { return m_baseband == Baseband::Requesting; } + void OnAccepted(uint8_t role); + void OnRejected(uint8_t reason, uint64_t nowUs); + // Guest paged this remote. Returns false when the remote cannot answer. + bool OnPaged(uint64_t nowUs); + // Baseband went down. `byGuest` = the guest's HCI Disconnect. + void OnDisconnected(bool byGuest, uint64_t nowUs); + // The physical remote vanished while connected: tells the guest. + void DropFromRemote(uint8_t reason); + + void ReceiveL2cap(const uint8_t* frame, size_t size); + + Baseband BasebandState() const { return m_baseband; } + LinkState State() const { return m_state; } + +private: + struct Channel { + uint16_t psm = 0; + uint16_t localCid = 0; + uint16_t remoteCid = 0; + uint16_t remoteMtu = 672; + bool weInitiated = false; + bool connected = false; // connection response success seen/sent + bool configSent = false; // our Configuration Request is out + bool localConfigured = false; // the guest accepted our configuration + bool remoteConfigured = false; // we accepted the guest's configuration + uint8_t connectIdent = 0; + uint8_t configIdent = 0; + uint64_t requestUs = 0; + std::vector pendingOptions; // continued Configuration Request + bool Open() const { return connected && localConfigured && remoteConfigured; } + }; + + Channel* FindByLocal(uint16_t cid); + Channel* FindByPsm(uint16_t psm); + uint16_t AllocateCid() const; + uint8_t NextIdent(); + + void SendSignal(uint8_t code, uint8_t ident, const std::vector& data); + void SendData(const Channel& channel, const std::vector& payload); + void RequestChannel(uint16_t psm, uint64_t nowUs); + void SendConfigRequest(Channel& channel); + void HandleSignalling(const uint8_t* data, size_t size); + void HandleConnectionRequest(uint8_t ident, const uint8_t* p, size_t n); + void HandleConnectionResponse(uint8_t ident, const uint8_t* p, size_t n); + void HandleConfigurationRequest(uint8_t ident, const uint8_t* p, size_t n); + void HandleConfigurationResponse(uint8_t ident, const uint8_t* p, size_t n); + void HandleDisconnectionRequest(uint8_t ident, const uint8_t* p, size_t n); + void HandleDisconnectionResponse(const uint8_t* p, size_t n); + void HandleChannelData(Channel& channel, const uint8_t* data, size_t size); + void HandleHidControl(Channel& channel, const uint8_t* data, size_t size); + void UpdateState(); + void SetState(LinkState state); + void ForwardInput(); + void SendInput(const Channel& interrupt, const std::vector& report); + void ClearConnection(); + + Controller& m_controller; + size_t m_slot; + Baseband m_baseband = Baseband::Idle; + LinkState m_state = LinkState::Down; + bool m_connectWanted = false; + bool m_guestInitiated = false; + bool m_everReady = false; + uint8_t m_ident = 0; + uint64_t m_stateSinceUs = 0; + uint64_t m_retryAtUs = 0; + uint64_t m_nowUs = 0; + std::vector m_channels; + std::vector m_report; +}; + +} // namespace Bluetooth diff --git a/runtime/include/bluetooth/bt_sdp.h b/runtime/include/bluetooth/bt_sdp.h new file mode 100644 index 0000000..4cd2d7f --- /dev/null +++ b/runtime/include/bluetooth/bt_sdp.h @@ -0,0 +1,19 @@ +#pragma once + +// SDP server of an emulated Wii Remote: the HID service record (0x00010000) +// and the Device ID record (0x00010001) a real RVL-CNT-01 publishes. + +#include +#include +#include + +namespace Bluetooth::Sdp { + +// The Wii Remote's HID report descriptor, as the game also embeds it. +const std::vector& WiiRemoteHidDescriptor(); + +// Answers one SDP request PDU. `maxResponse` bounds the PDU returned (the +// guest's L2CAP MTU on the SDP channel). +std::vector HandleRequest(const uint8_t* pdu, size_t size, size_t maxResponse); + +} // namespace Bluetooth::Sdp diff --git a/runtime/include/friend_code_keyboard.h b/runtime/include/friend_code_keyboard.h new file mode 100644 index 0000000..f0b8387 --- /dev/null +++ b/runtime/include/friend_code_keyboard.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +// Lets the keyboard type into Retro Rewind's friend code entry page. +namespace FriendCodeKeyboard { +void HandleEvents(const AuroraEvent* events) noexcept; +} // namespace FriendCodeKeyboard diff --git a/runtime/include/guest_abi/abi_version.h b/runtime/include/guest_abi/abi_version.h index ce7f320..aa4f8f3 100644 --- a/runtime/include/guest_abi/abi_version.h +++ b/runtime/include/guest_abi/abi_version.h @@ -1,4 +1,4 @@ #pragma once // Bump whenever guest_abi/, isa/ or ppc_isa_memory.h changes what translated code compiles against. -#define MKW_GUEST_ABI_VERSION 1 +#define MKW_GUEST_ABI_VERSION 2 diff --git a/runtime/include/guest_abi/dispatch.h b/runtime/include/guest_abi/dispatch.h index 9752c04..841ae69 100644 --- a/runtime/include/guest_abi/dispatch.h +++ b/runtime/include/guest_abi/dispatch.h @@ -2,6 +2,7 @@ #include "guest_abi/cpu_context.h" #include "guest_abi/exec_guard.h" +#include "guest_abi/guest_region.h" #include "isa/ppc_isa_config.h" #include "isa/ppc_isa_cr.h" @@ -24,7 +25,7 @@ uint32_t FilterScnRendererPathMaskOption(uint32_t pathMask) noexcept; // (used for the path mask filtering in ScnRenderer::createPath: depth of // field is always removed, bloom when the user disabled it) inline void ApplyRuntimeCallOptions(uint32_t target, CpuContext* ctx) { - if (target == 0x8023BD38u) { + if (::GuestRegion::Is<0x8023BD38u>(target)) { // ScnRenderer::createPath receives the post-processing path mask in r4. ctx->gpr[4] = FilterScnRendererPathMaskOption(ctx->gpr[4]); } @@ -242,13 +243,11 @@ private: std::array saved_; }; -// Guest address of OSLoadContext, which models rfi-style context restoration -// and intentionally replaces the full guest register file instead of returning -// like a normal ABI call. It can never be guarded. -inline constexpr uint32_t kOSLoadContextAddress = 0x801A1F58u; - +// OSLoadContext models rfi-style context restoration and intentionally replaces +// the full guest register file instead of returning like a normal ABI call. It +// can never be guarded. inline bool ShouldPreserveNonvolatileGprsForRawCpuCall(const TranslatedFunctionInfo* info) noexcept { - return info->kind == FunctionKind::Native && info->address != kOSLoadContextAddress; + return info->kind == FunctionKind::Native && info->address != MKW_GADDR(801A1F58); } inline uint32_t NonvolatileFprGuardMaskFor(const TranslatedFunctionInfo* info) noexcept { diff --git a/runtime/include/guest_abi/guest_region.h b/runtime/include/guest_abi/guest_region.h new file mode 100644 index 0000000..1836717 --- /dev/null +++ b/runtime/include/guest_abi/guest_region.h @@ -0,0 +1,166 @@ +#pragma once + +// Guest addresses are named by their PAL (RMCP01) address. Which address that identity has +// depends on the region the game was translated from, which runtime/game supplies at link +// time, so one compiled runtime serves every region. +// +// MKW_GADDR(801A9E84) address of that identity in the running region +// MKW_GADDR_CT(801A9E84) same, as a constant expression; translated code only +// +// guest_versions.inc maps PAL ranges to the other regions. A PAL address outside every range +// of a region does not compile. + +#include +#include + +namespace GuestRegion { + +enum class Id : uint8_t { + Pal = 0, + NtscU = 1, + NtscJ = 2, +}; +inline constexpr size_t kCount = 3; + +struct Row { + uint32_t address[kCount]; + + constexpr uint32_t In(Id region) const { return address[static_cast(region)]; } +}; + +struct Range { + Id region; + uint32_t first; + uint32_t last; + int32_t delta; +}; + +inline constexpr Range kRanges[] = { +#define MKW_REGION_RANGE(region, first, last, delta) {Id::region, 0x##first##u, 0x##last##u, delta}, +#include "guest_abi/guest_versions.inc" +#undef MKW_REGION_RANGE +}; +inline constexpr size_t kRangeCount = sizeof(kRanges) / sizeof(kRanges[0]); + +constexpr bool Precedes(Id region, uint32_t address, const Range& range) { + return region < range.region || (region == range.region && address < range.first); +} + +constexpr bool RangesAreOrdered() { + for (size_t i = 0; i < kRangeCount; ++i) { + const Range& range = kRanges[i]; + if (range.region == Id::Pal || range.first > range.last) { + return false; + } + if (i != 0 && !Precedes(kRanges[i - 1].region, kRanges[i - 1].last, range)) { + return false; + } + } + return true; +} +static_assert(RangesAreOrdered(), "guest_versions.inc ranges must be sorted by region and PAL address without overlaps"); + +struct Mapping { + bool found; + uint32_t address; +}; + +constexpr Mapping Map(uint32_t pal, Id region) { + if (region == Id::Pal) { + return {true, pal}; + } + size_t lo = 0; + size_t hi = kRangeCount; + while (lo < hi) { + const size_t mid = lo + (hi - lo) / 2; + if (Precedes(region, pal, kRanges[mid])) { + hi = mid; + } else { + lo = mid + 1; + } + } + if (lo == 0) { + return {false, 0}; + } + const Range& range = kRanges[lo - 1]; + if (range.region != region || pal > range.last) { + return {false, 0}; + } + return {true, static_cast(static_cast(pal) + range.delta)}; +} + +constexpr Row RowOf(uint32_t pal) { + const Mapping ntscU = Map(pal, Id::NtscU); + const Mapping ntscJ = Map(pal, Id::NtscJ); + return ntscU.found && ntscJ.found ? Row{{pal, ntscU.address, ntscJ.address}} + : throw "PAL address outside guest_abi/guest_versions.inc"; +} + +} // namespace GuestRegion + +// Defined by runtime/game for the translated region. +extern "C" const uint8_t kMkwGuestRegion; + +namespace GuestRegion { + +inline Id Current() noexcept { return static_cast(kMkwGuestRegion); } + +template +inline uint32_t Address() noexcept { + constexpr Row row = RowOf(Pal); + if constexpr (row.address[1] == Pal && row.address[2] == Pal) { + return Pal; + } else { + return row.In(Current()); + } +} + +// Folds to false at compile time for a constant target that no region uses for Pal. +template +inline bool Is(uint32_t target) noexcept { + constexpr Row row = RowOf(Pal); + return (target == row.address[0] || target == row.address[1] || target == row.address[2]) && + target == row.In(Current()); +} + +[[noreturn]] void FatalUnknownAddress(uint32_t pal) noexcept; + +// For hand-written registrations, which name the PAL address. +inline uint32_t Translate(uint32_t pal) noexcept { + const Mapping mapping = Map(pal, Current()); + if (!mapping.found) { + FatalUnknownAddress(pal); + } + return mapping.address; +} + +struct Facts { + const char* gameId; + char letter; + uint32_t gameCode; + uint32_t viTvFormat; + uint32_t mem1ArenaLo; + // setting.txt defaults for a new NAND + const char* area; + const char* model; + const char* productCode; + const char* video; + const char* gameRegion; +}; + +inline constexpr Facts kFacts[kCount] = { + {"RMCP01", 'P', 0x524D4350u, 1u, 0x80399180u, "EUR", "RVL-001(EUR)", "LEH", "PAL", "EU"}, + {"RMCE01", 'E', 0x524D4345u, 0u, 0x80394E00u, "USA", "RVL-001(USA)", "LU", "NTSC", "US"}, + {"RMCJ01", 'J', 0x524D434Au, 0u, 0x80398B00u, "JPN", "RVL-001(JPN)", "LJ", "NTSC", "JP"}, +}; + +inline const Facts& CurrentFacts() noexcept { return kFacts[static_cast(Current())]; } + +} // namespace GuestRegion + +#define MKW_GADDR(pal) (::GuestRegion::Address<0x##pal##u>()) + +#if defined(MKW_TRANSLATED_GUEST_REGION) +#define MKW_GADDR_CT(pal) \ + (::GuestRegion::RowOf(0x##pal##u).In(static_cast<::GuestRegion::Id>(MKW_TRANSLATED_GUEST_REGION))) +#endif diff --git a/runtime/include/guest_abi/guest_versions.inc b/runtime/include/guest_abi/guest_versions.inc new file mode 100644 index 0000000..8ea9860 --- /dev/null +++ b/runtime/include/guest_abi/guest_versions.inc @@ -0,0 +1,416 @@ +// PAL address ranges -> address in each other region, in the style of Retro Rewind's +// versions.txt: MKW_REGION_RANGE(region, first PAL, last PAL (inclusive), delta). +// PAL maps to itself. Code ranges come from mkw-sp's port.py chunk table (MIT, Pablo Stebler), +// data ranges from Retro Rewind's versions.txt plus the verified data_addresses.txt anchors. +// An address outside every range has no known counterpart and fails to compile. + +MKW_REGION_RANGE(NtscU, 80000000, 8000802F, +0x0) +MKW_REGION_RANGE(NtscU, 8000808C, 8000ADBB, -0x40) +MKW_REGION_RANGE(NtscU, 8000AF24, 8000B6B3, -0xA0) +MKW_REGION_RANGE(NtscU, 8000B6B4, 8000C173, +0x15994) +MKW_REGION_RANGE(NtscU, 8000C174, 80021BA7, -0xB60) +MKW_REGION_RANGE(NtscU, 80021BA8, 80225F1B, -0xA0) +MKW_REGION_RANGE(NtscU, 802261F8, 802402DF, -0x384) +MKW_REGION_RANGE(NtscU, 802402E0, 80240E17, +0x3F1C) +MKW_REGION_RANGE(NtscU, 80240E18, 80244DD3, -0xEBC) +MKW_REGION_RANGE(NtscU, 80244DDA, 80244EBF, -0xA0) +MKW_REGION_RANGE(NtscU, 80244EC0, 80244ECF, -0x80) +MKW_REGION_RANGE(NtscU, 802572BF, 802575DF, -0x320) +MKW_REGION_RANGE(NtscU, 80257E64, 80258184, -0x320) +MKW_REGION_RANGE(NtscU, 80276054, 8029CEFB, -0x4340) +MKW_REGION_RANGE(NtscU, 802A3D60, 802A407F, -0x4368) +MKW_REGION_RANGE(NtscU, 802A4080, 80386F27, -0x4380) +MKW_REGION_RANGE(NtscU, 80386F48, 80386F8F, -0x4388) +MKW_REGION_RANGE(NtscU, 80386FA0, 80388BE3, -0x4380) +MKW_REGION_RANGE(NtscU, 80388DD0, 80388DF7, -0x4388) +MKW_REGION_RANGE(NtscU, 80389140, 8038917B, -0x4380) +MKW_REGION_RANGE(NtscU, 80399200, 80399400, -0x4380) +MKW_REGION_RANGE(NtscU, 805103B4, 80510A8F, -0x4380) +MKW_REGION_RANGE(NtscU, 80510B84, 8052D297, -0x4474) +MKW_REGION_RANGE(NtscU, 8052D298, 8052D96B, +0x22568) +MKW_REGION_RANGE(NtscU, 8052D96C, 8053D97B, -0x4B48) +MKW_REGION_RANGE(NtscU, 8053D97C, 8053E36F, +0x12558) +MKW_REGION_RANGE(NtscU, 8053E370, 8054FB2B, -0x553C) +MKW_REGION_RANGE(NtscU, 8054FB2C, 80550547, +0xD9C) +MKW_REGION_RANGE(NtscU, 80550548, 805537CB, -0x5F58) +MKW_REGION_RANGE(NtscU, 80553894, 8055572B, -0x6020) +MKW_REGION_RANGE(NtscU, 8055572C, 8056AB6B, -0x4380) +MKW_REGION_RANGE(NtscU, 8056AB6C, 8056B63B, +0x4357C) +MKW_REGION_RANGE(NtscU, 8056B63C, 8057402F, -0x4E50) +MKW_REGION_RANGE(NtscU, 80574030, 805758AB, +0x3AB88) +MKW_REGION_RANGE(NtscU, 80575A44, 80583F2B, -0x6864) +MKW_REGION_RANGE(NtscU, 80583F2C, 8059B5A3, -0x6824) +MKW_REGION_RANGE(NtscU, 8059B5A4, 8059EAA3, +0x14FE8) +MKW_REGION_RANGE(NtscU, 8059EAA4, 805A0557, -0x9D24) +MKW_REGION_RANGE(NtscU, 805A068C, 805A1477, +0x1343C) +MKW_REGION_RANGE(NtscU, 805A1488, 805A1863, +0x1342C) +MKW_REGION_RANGE(NtscU, 805A1864, 805A9EDB, -0xB038) +MKW_REGION_RANGE(NtscU, 805A9EDC, 805AB573, -0xB030) +MKW_REGION_RANGE(NtscU, 805AB574, 805ABC8F, -0xAF70) +MKW_REGION_RANGE(NtscU, 805ABC90, 805ADD97, -0xAF68) +MKW_REGION_RANGE(NtscU, 805ADD98, 805B900F, -0xAF28) +MKW_REGION_RANGE(NtscU, 805B9010, 805B92FF, -0x4380) +MKW_REGION_RANGE(NtscU, 805B9300, 805BAB3F, +0x664F4) +MKW_REGION_RANGE(NtscU, 805BAB40, 805BB2B7, -0x5BC0) +MKW_REGION_RANGE(NtscU, 805BB2B8, 805BD2D7, +0x65D7C) +MKW_REGION_RANGE(NtscU, 805BD2D8, 805BD2E3, -0x697C) +MKW_REGION_RANGE(NtscU, 805BD2E4, 805BD39B, +0x65D70) +MKW_REGION_RANGE(NtscU, 805BD39C, 805BE5FF, -0x7CA4) +MKW_REGION_RANGE(NtscU, 805BE600, 805BE61B, -0x7C98) +MKW_REGION_RANGE(NtscU, 805BE66C, 805BE7F3, +0x64AA0) +MKW_REGION_RANGE(NtscU, 805BE7F4, 805BE84B, -0x7124) +MKW_REGION_RANGE(NtscU, 805BE84C, 805BED67, +0x64A48) +MKW_REGION_RANGE(NtscU, 805BED68, 805BED73, -0x7948) +MKW_REGION_RANGE(NtscU, 805BED74, 805BF2D7, +0x64A3C) +MKW_REGION_RANGE(NtscU, 805BF2D8, 805BF2DB, -0x613C) +MKW_REGION_RANGE(NtscU, 805BF3CC, 805BFE1B, -0x89FC) +MKW_REGION_RANGE(NtscU, 805BFE1C, 805C00BF, -0x89F0) +MKW_REGION_RANGE(NtscU, 805C00C0, 805C1B33, -0x8998) +MKW_REGION_RANGE(NtscU, 805C1B34, 805C35F7, -0x8994) +MKW_REGION_RANGE(NtscU, 805C35F8, 805C3BCB, +0x60810) +MKW_REGION_RANGE(NtscU, 805C3BCC, 805C4767, -0x8F68) +MKW_REGION_RANGE(NtscU, 805C4768, 805C579B, +0x5FC74) +MKW_REGION_RANGE(NtscU, 805C57B0, 805CADDB, -0x9FB0) +MKW_REGION_RANGE(NtscU, 805CADDC, 805CC0A7, +0x5A648) +MKW_REGION_RANGE(NtscU, 805CC1B4, 805CD94B, +0x5A5A4) +MKW_REGION_RANGE(NtscU, 805CD94C, 805D1887, -0xCB20) +MKW_REGION_RANGE(NtscU, 805D1888, 805D1E83, +0x56668) +MKW_REGION_RANGE(NtscU, 805D1E84, 805D7F77, -0xD11C) +MKW_REGION_RANGE(NtscU, 805D7F78, 805DBFDB, +0x50574) +MKW_REGION_RANGE(NtscU, 805DBFDC, 805DC033, +0x2A620) +MKW_REGION_RANGE(NtscU, 805DC034, 805DE837, +0x5051C) +MKW_REGION_RANGE(NtscU, 805DE838, 805DE843, +0x5C00) +MKW_REGION_RANGE(NtscU, 805DE844, 805E0C37, +0x50510) +MKW_REGION_RANGE(NtscU, 805E0C38, 805E6B4F, -0x15DDC) +MKW_REGION_RANGE(NtscU, 805E6B50, 805E745F, +0x4A5F8) +MKW_REGION_RANGE(NtscU, 805E7460, 805EA77F, -0x166EC) +MKW_REGION_RANGE(NtscU, 805EA780, 805EEB67, +0x472D8) +MKW_REGION_RANGE(NtscU, 805EEB68, 805F2D23, -0x1AAD4) +MKW_REGION_RANGE(NtscU, 805F2D24, 805F8B33, +0x4311C) +MKW_REGION_RANGE(NtscU, 805F8B34, 805FB5BB, -0x208E4) +MKW_REGION_RANGE(NtscU, 805FB5BC, 805FB81F, +0x40694) +MKW_REGION_RANGE(NtscU, 805FB820, 805FD517, -0x20B48) +MKW_REGION_RANGE(NtscU, 805FD518, 806012AF, +0x3E99C) +MKW_REGION_RANGE(NtscU, 806012B0, 80608D17, -0x248E0) +MKW_REGION_RANGE(NtscU, 80608D18, 8060A72B, -0x248D4) +MKW_REGION_RANGE(NtscU, 8060A72C, 8061186B, +0x35520) +MKW_REGION_RANGE(NtscU, 8061186C, 80616843, -0x2BA14) +MKW_REGION_RANGE(NtscU, 80616844, 8061AE6B, +0x30548) +MKW_REGION_RANGE(NtscU, 8061AE6C, 8061E897, -0x3003C) +MKW_REGION_RANGE(NtscU, 8061E898, 8061F6E7, +0x2CB1C) +MKW_REGION_RANGE(NtscU, 8061F6E8, 80620CB3, -0x30E8C) +MKW_REGION_RANGE(NtscU, 80620D7C, 80634F47, -0x30EB4) +MKW_REGION_RANGE(NtscU, 80634F48, 80637493, -0x30E98) +MKW_REGION_RANGE(NtscU, 80637494, 80637513, -0x30DF0) +MKW_REGION_RANGE(NtscU, 80637514, 80637A2F, +0x14CF0) +MKW_REGION_RANGE(NtscU, 80637AC0, 8063BCF7, -0x313A0) +MKW_REGION_RANGE(NtscU, 8063BE40, 806453E3, -0x31420) +MKW_REGION_RANGE(NtscU, 806453E4, 806467D3, +0x73A8) +MKW_REGION_RANGE(NtscU, 806467D4, 8064A3F3, -0x32810) +MKW_REGION_RANGE(NtscU, 8064A3F4, 8064AEE3, +0x3788) +MKW_REGION_RANGE(NtscU, 8064AEF8, 80651BEB, -0x33314) +MKW_REGION_RANGE(NtscU, 80651BEC, 806522FF, -0x3580) +MKW_REGION_RANGE(NtscU, 80652300, 80653207, -0x33A14) +MKW_REGION_RANGE(NtscU, 80653208, 8065B353, -0x4488) +MKW_REGION_RANGE(NtscU, 8065B4E8, 8065C0EB, -0x461C) +MKW_REGION_RANGE(NtscU, 8065C0EC, 8065FA13, +0xC88) +MKW_REGION_RANGE(NtscU, 8065FA4C, 8065FE4B, -0x7F7C) +MKW_REGION_RANGE(NtscU, 8065FE4C, 80662777, -0x7F3C) +MKW_REGION_RANGE(NtscU, 80662778, 80663193, -0x20E4) +MKW_REGION_RANGE(NtscU, 80663194, 80665537, -0x8958) +MKW_REGION_RANGE(NtscU, 80665538, 80668813, +0xDC50) +MKW_REGION_RANGE(NtscU, 80668814, 8067906B, -0x7764) +MKW_REGION_RANGE(NtscU, 8067906C, 8067937F, -0x2C08) +MKW_REGION_RANGE(NtscU, 80679380, 8067ABFF, -0x7A78) +MKW_REGION_RANGE(NtscU, 8067AC00, 806BF4C7, -0x4488) +MKW_REGION_RANGE(NtscU, 806BF4C8, 806BFB13, +0x22BE0) +MKW_REGION_RANGE(NtscU, 806BFB14, 806C050B, -0x4AD4) +MKW_REGION_RANGE(NtscU, 806C050C, 806C35A7, +0x221E8) +MKW_REGION_RANGE(NtscU, 806C35A8, 806C3AA3, -0x7B70) +MKW_REGION_RANGE(NtscU, 806C3AA4, 806C4ED3, +0x21CEC) +MKW_REGION_RANGE(NtscU, 806C4EF0, 806C63A7, +0x21CD0) +MKW_REGION_RANGE(NtscU, 806C63B0, 806C6B43, +0x21CC8) +MKW_REGION_RANGE(NtscU, 806C6B44, 806CCE8F, -0xABF4) +MKW_REGION_RANGE(NtscU, 806CCE90, 806CE81F, +0x1B97C) +MKW_REGION_RANGE(NtscU, 806CE828, 806D02BB, -0xC58C) +MKW_REGION_RANGE(NtscU, 806D02BC, 806D28F3, +0x19EE0) +MKW_REGION_RANGE(NtscU, 806D2908, 806D5C5B, -0xEBD0) +MKW_REGION_RANGE(NtscU, 806D5C60, 806D5ED7, +0x16B74) +MKW_REGION_RANGE(NtscU, 806D5ED8, 806DA913, -0xEE40) +MKW_REGION_RANGE(NtscU, 806DA914, 806DB183, +0x12144) +MKW_REGION_RANGE(NtscU, 806DB184, 806DDA83, -0xF6B0) +MKW_REGION_RANGE(NtscU, 806DDA84, 806DEB3F, +0xF844) +MKW_REGION_RANGE(NtscU, 806DEB40, 806DF7CF, -0x1076C) +MKW_REGION_RANGE(NtscU, 806DF7D0, 806DFD13, +0xEBB4) +MKW_REGION_RANGE(NtscU, 806DFD14, 806E3A8B, -0x10CB0) +MKW_REGION_RANGE(NtscU, 806E3A8C, 806E3E1F, +0xAE3C) +MKW_REGION_RANGE(NtscU, 806E3E20, 806E95AF, -0x11044) +MKW_REGION_RANGE(NtscU, 806E95B0, 806EC7BF, +0x56AC) +MKW_REGION_RANGE(NtscU, 806EC7C0, 806ED53B, -0x1425C) +MKW_REGION_RANGE(NtscU, 806ED53C, 806F62FB, -0x14254) +MKW_REGION_RANGE(NtscU, 806F62FC, 806F7697, -0x4488) +MKW_REGION_RANGE(NtscU, 806F77C4, 806F7A53, +0x1C2B4) +MKW_REGION_RANGE(NtscU, 806F7AA8, 806F821F, +0x1C260) +MKW_REGION_RANGE(NtscU, 806F8220, 806F8933, -0x5010) +MKW_REGION_RANGE(NtscU, 806F8934, 806FA3FB, -0x4FBC) +MKW_REGION_RANGE(NtscU, 806FA3FC, 806FE23F, -0x4F68) +MKW_REGION_RANGE(NtscU, 806FE240, 806FE9DF, -0x4F10) +MKW_REGION_RANGE(NtscU, 806FE9E0, 807001A3, +0x15AA0) +MKW_REGION_RANGE(NtscU, 80700230, 80700473, +0x15A14) +MKW_REGION_RANGE(NtscU, 80700474, 8070E7B7, -0x69A4) +MKW_REGION_RANGE(NtscU, 8070E7B8, 8070F8B7, +0x76D0) +MKW_REGION_RANGE(NtscU, 8070F8B8, 807179C3, -0x7AA4) +MKW_REGION_RANGE(NtscU, 807179C4, 80717E33, -0x7A18) +MKW_REGION_RANGE(NtscU, 80717E34, 807182E7, -0xEAC) +MKW_REGION_RANGE(NtscU, 807182E8, 8071B86B, -0x7ECC) +MKW_REGION_RANGE(NtscU, 8071B86C, 80726573, -0x4430) +MKW_REGION_RANGE(NtscU, 80726574, 8072820B, +0x16068) +MKW_REGION_RANGE(NtscU, 8072821C, 807285C7, +0x16058) +MKW_REGION_RANGE(NtscU, 807285CC, 80729337, +0x16054) +MKW_REGION_RANGE(NtscU, 80729350, 80729B87, -0x720C) +MKW_REGION_RANGE(NtscU, 80729B88, 8072A893, -0x7204) +MKW_REGION_RANGE(NtscU, 8072A894, 8072B95B, -0x71FC) +MKW_REGION_RANGE(NtscU, 8072B95C, 8072DE63, -0x71EC) +MKW_REGION_RANGE(NtscU, 8072DFCC, 8072FF5F, +0x113C4) +MKW_REGION_RANGE(NtscU, 8072FF78, 80730197, +0x113AC) +MKW_REGION_RANGE(NtscU, 80730198, 80730A7F, -0x93B0) +MKW_REGION_RANGE(NtscU, 80730B40, 8073195F, +0x10A04) +MKW_REGION_RANGE(NtscU, 80731960, 80735947, -0xA1B8) +MKW_REGION_RANGE(NtscU, 80735948, 80738DB7, +0xCA1C) +MKW_REGION_RANGE(NtscU, 80738DB8, 8073C54B, -0xD628) +MKW_REGION_RANGE(NtscU, 8073C54C, 8073EDEF, +0x9288) +MKW_REGION_RANGE(NtscU, 8073EDF0, 8074C4A7, -0xFECC) +MKW_REGION_RANGE(NtscU, 8074C4A8, 8074D5B7, +0x20A04) +MKW_REGION_RANGE(NtscU, 8074D5B8, 807519C7, -0x5540) +MKW_REGION_RANGE(NtscU, 807519C8, 80754103, +0x1C5F4) +MKW_REGION_RANGE(NtscU, 80754104, 80758BDB, -0x7C7C) +MKW_REGION_RANGE(NtscU, 80758BDC, 8075DB23, +0x17B1C) +MKW_REGION_RANGE(NtscU, 8075DB3C, 8075E78B, -0xCBDC) +MKW_REGION_RANGE(NtscU, 8075E78C, 8075EAFB, +0x16ECC) +MKW_REGION_RANGE(NtscU, 8075EAFC, 80765C93, -0xCF4C) +MKW_REGION_RANGE(NtscU, 80765C94, 807678F3, +0xFD34) +MKW_REGION_RANGE(NtscU, 807678F4, 80768D1F, -0xEBAC) +MKW_REGION_RANGE(NtscU, 80768D20, 807693EB, +0xE908) +MKW_REGION_RANGE(NtscU, 8076960C, 8076C85B, +0xE85C) +MKW_REGION_RANGE(NtscU, 8076C85C, 8076EBDB, -0x126E8) +MKW_REGION_RANGE(NtscU, 8076EBE0, 8076F2DB, +0xC4D8) +MKW_REGION_RANGE(NtscU, 8076F2DC, 807726C3, -0x12DE8) +MKW_REGION_RANGE(NtscU, 80772704, 80773C13, +0x90B4) +MKW_REGION_RANGE(NtscU, 80773C1C, 8077439B, -0x14340) +MKW_REGION_RANGE(NtscU, 807743A0, 807787EF, -0x14294) +MKW_REGION_RANGE(NtscU, 807787F0, 8077902B, +0x4520) +MKW_REGION_RANGE(NtscU, 8077902C, 8077CE87, -0x14AD0) +MKW_REGION_RANGE(NtscU, 8077CEC8, 8077DF23, +0x684) +MKW_REGION_RANGE(NtscU, 8077DF24, 807829D7, -0x15B2C) +MKW_REGION_RANGE(NtscU, 807829D8, 80787D83, -0x4430) +MKW_REGION_RANGE(NtscU, 80787D84, 8078C95F, +0x48598) +MKW_REGION_RANGE(NtscU, 8078C960, 807A81B3, -0x900C) +MKW_REGION_RANGE(NtscU, 807A81B4, 807A9D6F, +0x2CDC0) +MKW_REGION_RANGE(NtscU, 807A9E50, 807A9E53, +0x2CCAC) +MKW_REGION_RANGE(NtscU, 807A9EB8, 807AF13F, -0xACA8) +MKW_REGION_RANGE(NtscU, 807AF140, 807B2EF7, +0x27A54) +MKW_REGION_RANGE(NtscU, 807B2EF8, 807D976B, -0xEA60) +MKW_REGION_RANGE(NtscU, 807D976C, 807D9B7F, +0x11E0) +MKW_REGION_RANGE(NtscU, 807D9B98, 807DA5BF, -0xEE8C) +MKW_REGION_RANGE(NtscU, 807DA5C0, 807DBCCB, +0x7B8) +MKW_REGION_RANGE(NtscU, 807DBCCC, 807DC8C7, -0x10598) +MKW_REGION_RANGE(NtscU, 807DC950, 807E093B, -0x10620) +MKW_REGION_RANGE(NtscU, 807E093C, 807E251F, +0x5BDB4) +MKW_REGION_RANGE(NtscU, 807E259C, 807E560F, -0x6090) +MKW_REGION_RANGE(NtscU, 807E5654, 807E6413, -0x6070) +MKW_REGION_RANGE(NtscU, 807E6414, 807E9C43, +0x57F28) +MKW_REGION_RANGE(NtscU, 807E9C50, 807EDD97, -0x98AC) +MKW_REGION_RANGE(NtscU, 807EDD98, 807EE23B, +0x53DD4) +MKW_REGION_RANGE(NtscU, 807EE250, 807EE467, -0x9D64) +MKW_REGION_RANGE(NtscU, 807EE474, 807EEA13, +0x53B9C) +MKW_REGION_RANGE(NtscU, 807EEA14, 807EF9F3, -0xA310) +MKW_REGION_RANGE(NtscU, 807EFD0C, 807F76EB, -0xA628) +MKW_REGION_RANGE(NtscU, 807F76EC, 807F7BA3, +0x4B1FC) +MKW_REGION_RANGE(NtscU, 807F7BC4, 807F890B, -0xAB00) +MKW_REGION_RANGE(NtscU, 807F8968, 807F927F, +0x4A438) +MKW_REGION_RANGE(NtscU, 807F9280, 807F9387, -0xB3F0) +MKW_REGION_RANGE(NtscU, 807F9580, 807FAB57, +0x4A320) +MKW_REGION_RANGE(NtscU, 807FAB58, 807FEB67, -0xCBC0) +MKW_REGION_RANGE(NtscU, 807FEB68, 807FFADF, +0x46310) +MKW_REGION_RANGE(NtscU, 807FFB20, 80805A0B, -0xDB78) +MKW_REGION_RANGE(NtscU, 80805A0C, 8080761B, +0x403E4) +MKW_REGION_RANGE(NtscU, 8080761C, 80809447, -0xF748) +MKW_REGION_RANGE(NtscU, 80809448, 8080AD1F, +0x3E5B8) +MKW_REGION_RANGE(NtscU, 8080AD20, 80811E47, -0x11020) +MKW_REGION_RANGE(NtscU, 80811E48, 80813BD3, +0x37490) +MKW_REGION_RANGE(NtscU, 80813BD4, 8081E283, -0x12DAC) +MKW_REGION_RANGE(NtscU, 8081E284, 8081EFEB, +0x2CDE0) +MKW_REGION_RANGE(NtscU, 8081EFEC, 8082E53F, -0x13B14) +MKW_REGION_RANGE(NtscU, 8082E540, 8082E853, +0x1D88C) +MKW_REGION_RANGE(NtscU, 8082E854, 8082F407, -0x13E28) +MKW_REGION_RANGE(NtscU, 8082F408, 8083349F, +0x1CCD8) +MKW_REGION_RANGE(NtscU, 808334E0, 80833AFF, -0x17F00) +MKW_REGION_RANGE(NtscU, 80833B00, 80838E5F, -0x17EF8) +MKW_REGION_RANGE(NtscU, 80838E60, 8083B0CB, +0x17358) +MKW_REGION_RANGE(NtscU, 8083B0CC, 8083CB43, -0x1A178) +MKW_REGION_RANGE(NtscU, 8083CB44, 8083D42B, +0x158E0) +MKW_REGION_RANGE(NtscU, 8083D42C, 8084233F, -0x1AA60) +MKW_REGION_RANGE(NtscU, 80842340, 808447AB, +0x109CC) +MKW_REGION_RANGE(NtscU, 808447AC, 8084A99F, -0x1CED8) +MKW_REGION_RANGE(NtscU, 8084A9A0, 8084D0DB, +0xA7E4) +MKW_REGION_RANGE(NtscU, 8084D0DC, 80851D2B, -0x1F614) +MKW_REGION_RANGE(NtscU, 80851D38, 80852C5F, +0x5B88) +MKW_REGION_RANGE(NtscU, 80852C60, 80853CA3, -0x20548) +MKW_REGION_RANGE(NtscU, 80853CA4, 808551EB, +0x4B50) +MKW_REGION_RANGE(NtscU, 808551EC, 8085C3CB, -0x21A90) +MKW_REGION_RANGE(NtscU, 8085C3CC, 8085E673, -0x2690) +MKW_REGION_RANGE(NtscU, 8085E674, 8085F0AB, -0x23D24) +MKW_REGION_RANGE(NtscU, 8085F0AC, 8085FFD3, -0x30C8) +MKW_REGION_RANGE(NtscU, 8085FFD4, 80860F2B, -0x24C4C) +MKW_REGION_RANGE(NtscU, 80860F2C, 80862E23, -0x4020) +MKW_REGION_RANGE(NtscU, 80863234, 8086708B, -0x4430) +MKW_REGION_RANGE(NtscU, 8086708C, 808676DF, -0x2354) +MKW_REGION_RANGE(NtscU, 808676E0, 808697BB, -0x4A84) +MKW_REGION_RANGE(NtscU, 808697BC, 8086A253, -0x4430) +MKW_REGION_RANGE(NtscU, 8086A254, 8086C097, +0xC4A0) +MKW_REGION_RANGE(NtscU, 8086C108, 8086C987, +0xC430) +MKW_REGION_RANGE(NtscU, 8086CA40, 80872CA3, +0xC378) +MKW_REGION_RANGE(NtscU, 80872CA4, 808739AF, -0xCE80) +MKW_REGION_RANGE(NtscU, 808739B0, 80875453, -0xCDC8) +MKW_REGION_RANGE(NtscU, 80875454, 8088344B, -0xCD58) +MKW_REGION_RANGE(NtscU, 8088344C, 8088F70F, -0x4430) +MKW_REGION_RANGE(NtscU, 8088FDB8, 8088FDBB, -0x4458) +MKW_REGION_RANGE(NtscU, 80890030, 80890215, -0x4470) +MKW_REGION_RANGE(NtscU, 80890490, 80890977, -0x4578) +MKW_REGION_RANGE(NtscU, 808913C0, 808913C3, -0x4448) +MKW_REGION_RANGE(NtscU, 80891750, 8089175F, -0x44D0) +MKW_REGION_RANGE(NtscU, 80891A28, 80891C28, -0x4518) +MKW_REGION_RANGE(NtscU, 80892F2C, 80892F96, -0x1B0) +MKW_REGION_RANGE(NtscU, 80893217, 8089321D, -0x4A30) +MKW_REGION_RANGE(NtscU, 808944DE, 80894769, -0x50E8) +MKW_REGION_RANGE(NtscU, 80894B98, 80894B9C, -0x1330) +MKW_REGION_RANGE(NtscU, 80895238, 808952B7, -0x58F8) +MKW_REGION_RANGE(NtscU, 80895A08, 80895C8C, -0x1930) +MKW_REGION_RANGE(NtscU, 80895CBC, 80895CF0, -0x5FA8) +MKW_REGION_RANGE(NtscU, 8089647A, 808966D4, -0x1CA0) +MKW_REGION_RANGE(NtscU, 80896820, 80897040, -0x6678) +MKW_REGION_RANGE(NtscU, 80897C63, 80897C67, -0x6DA0) +MKW_REGION_RANGE(NtscU, 80897DD3, 80897DEF, -0x6DA8) +MKW_REGION_RANGE(NtscU, 80898955, 80898959, -0x7388) +MKW_REGION_RANGE(NtscU, 80899692, 8089973A, -0x7730) +MKW_REGION_RANGE(NtscU, 808998B3, 808998CA, -0x3FB0) +MKW_REGION_RANGE(NtscU, 80899A36, 80899EEF, -0x7890) +MKW_REGION_RANGE(NtscU, 8089A194, 8089A1B7, -0x46D0) +MKW_REGION_RANGE(NtscU, 808A1D80, 808A1E6F, -0x4A08) +MKW_REGION_RANGE(NtscU, 808A22E0, 808A22EF, -0x46D0) +MKW_REGION_RANGE(NtscU, 808A4E00, 808A56FF, -0x49C0) +MKW_REGION_RANGE(NtscU, 808A587C, 808A5897, -0x2B20) +MKW_REGION_RANGE(NtscU, 808A5A30, 808A5DC3, -0x4AD8) +MKW_REGION_RANGE(NtscU, 808A7DE0, 808A85F3, -0x4CD8) +MKW_REGION_RANGE(NtscU, 808A98D0, 808A98DF, -0x5728) +MKW_REGION_RANGE(NtscU, 808A9AF8, 808A9AFF, +0x780) +MKW_REGION_RANGE(NtscU, 808A9C0A, 808A9CC8, -0x58C8) +MKW_REGION_RANGE(NtscU, 808A9FEC, 808AA1AF, -0x5928) +MKW_REGION_RANGE(NtscU, 808AAA04, 808AAA10, -0x5980) +MKW_REGION_RANGE(NtscU, 808ACB3F, 808ACB43, -0x5F10) +MKW_REGION_RANGE(NtscU, 808ACFDF, 808AD02B, -0x60C0) +MKW_REGION_RANGE(NtscU, 808AD3C4, 808AD3C7, -0x60C0) +MKW_REGION_RANGE(NtscU, 808AD48E, 808AD492, -0x2980) +MKW_REGION_RANGE(NtscU, 808AD9F7, 808AD9FC, -0x6320) +MKW_REGION_RANGE(NtscU, 808ADCBC, 808ADD2C, -0x2FA8) +MKW_REGION_RANGE(NtscU, 808AEB45, 808AEB55, -0x68A8) +MKW_REGION_RANGE(NtscU, 808AF8E0, 808AF95F, -0x6AC0) +MKW_REGION_RANGE(NtscU, 808AFC18, 808AFC1B, -0x46B8) +MKW_REGION_RANGE(NtscU, 808B30C8, 808B3108, -0x46B0) +MKW_REGION_RANGE(NtscU, 808B35A0, 808B35AF, -0x46B0) +MKW_REGION_RANGE(NtscU, 808B3984, 808B3987, -0x4850) +MKW_REGION_RANGE(NtscU, 808B3A90, 808B3A9F, -0x4850) +MKW_REGION_RANGE(NtscU, 808B4C20, 808B4DEF, -0x46B0) +MKW_REGION_RANGE(NtscU, 808B54B8, 808B550F, -0x4738) +MKW_REGION_RANGE(NtscU, 808B59F4, 808B5CCF, -0x48C0) +MKW_REGION_RANGE(NtscU, 808B5CD8, 808B5CDB, -0x48BC) +MKW_REGION_RANGE(NtscU, 808BB034, 808BB097, -0x60F8) +MKW_REGION_RANGE(NtscU, 808BBEC8, 808BE908, -0x6430) +MKW_REGION_RANGE(NtscU, 808BFAF0, 808BFAFF, -0x65B0) +MKW_REGION_RANGE(NtscU, 808C069C, 808C06FF, -0x66B0) +MKW_REGION_RANGE(NtscU, 808CB550, 808CB553, -0x5508) +MKW_REGION_RANGE(NtscU, 808CB700, 808CB70F, -0x5508) +MKW_REGION_RANGE(NtscU, 808D1DD0, 808D1E2B, -0x3A98) +MKW_REGION_RANGE(NtscU, 808D30D8, 808D324F, -0x4908) +MKW_REGION_RANGE(NtscU, 808D3698, 808D369B, +0x1AB0) +MKW_REGION_RANGE(NtscU, 808D36CC, 808D36CF, +0x1AB0) +MKW_REGION_RANGE(NtscU, 808D36D4, 808D36D7, +0x1AB0) +MKW_REGION_RANGE(NtscU, 808D3744, 808D3747, +0x1AB0) +MKW_REGION_RANGE(NtscU, 808D374C, 808D374F, +0x1AB0) +MKW_REGION_RANGE(NtscU, 808D3C78, 808D3D1B, +0x1610) +MKW_REGION_RANGE(NtscU, 808D3E14, 808D3F2F, -0x4F68) +MKW_REGION_RANGE(NtscU, 808D9A58, 808D9A98, -0x60F0) +MKW_REGION_RANGE(NtscU, 808D9BC8, 808D9C5F, -0x36C0) +MKW_REGION_RANGE(NtscU, 808D9DB0, 808D9F97, -0x6220) +MKW_REGION_RANGE(NtscU, 808DA070, 808DA07F, -0x6220) +MKW_REGION_RANGE(NtscU, 808DA318, 808DA367, -0x63B8) +MKW_REGION_RANGE(NtscU, 808DA5DC, 808DA63F, -0x64C0) +MKW_REGION_RANGE(NtscU, 808DAD60, 808DAD6F, -0x6778) +MKW_REGION_RANGE(NtscU, 808DC540, 808DC54F, -0x4138) +MKW_REGION_RANGE(NtscU, 808E2BBC, 808E2BBE, +0x0) +MKW_REGION_RANGE(NtscU, 809BD6E0, 809C186B, -0x47C0) +MKW_REGION_RANGE(NtscU, 809C1874, 809C1877, -0x47C0) +MKW_REGION_RANGE(NtscU, 809C18F8, 809C18FB, -0x47E8) +MKW_REGION_RANGE(NtscU, 809C1918, 809C191B, -0x47E8) +MKW_REGION_RANGE(NtscU, 809C1980, 809C198F, -0x4610) +MKW_REGION_RANGE(NtscU, 809C19A0, 809C19BB, -0x4820) +MKW_REGION_RANGE(NtscU, 809C1E38, 809C1E3B, -0x4930) +MKW_REGION_RANGE(NtscU, 809C1F50, 809C20EF, -0x47C0) +MKW_REGION_RANGE(NtscU, 809C20F0, 809C20F7, -0x47C8) +MKW_REGION_RANGE(NtscU, 809C20F8, 809C20FB, -0x47A8) +MKW_REGION_RANGE(NtscU, 809C2100, 809C2107, -0x47D0) +MKW_REGION_RANGE(NtscU, 809C2108, 809C210B, -0x47B0) +MKW_REGION_RANGE(NtscU, 809C210C, 809C210F, -0x47D0) +MKW_REGION_RANGE(NtscU, 809C2110, 809C211B, -0x47D8) +MKW_REGION_RANGE(NtscU, 809C21D0, 809C21D3, -0x47C0) +MKW_REGION_RANGE(NtscU, 809C21D4, 809C21D7, +0xB840) +MKW_REGION_RANGE(NtscU, 809C21D8, 809C21DB, -0x47C0) +MKW_REGION_RANGE(NtscU, 809C2328, 809C232B, -0x47C8) +MKW_REGION_RANGE(NtscU, 809C26B8, 809C26BB, -0x4700) +MKW_REGION_RANGE(NtscU, 809C27F0, 809C289B, -0x4C40) +MKW_REGION_RANGE(NtscU, 809C28B8, 809C28BB, -0x47C0) +MKW_REGION_RANGE(NtscU, 809C2BE8, 809C2BEB, -0x4850) +MKW_REGION_RANGE(NtscU, 809C2CB8, 809C2CBB, -0x47E0) +MKW_REGION_RANGE(NtscU, 809C2EF0, 809C2EF3, -0x47C0) +MKW_REGION_RANGE(NtscU, 809C2F38, 809C361B, -0x47F8) +MKW_REGION_RANGE(NtscU, 809C3670, 809C38CF, -0x4808) +MKW_REGION_RANGE(NtscU, 809C4330, 809C4333, -0x4840) +MKW_REGION_RANGE(NtscU, 809C4680, 809C4683, -0x48C0) +MKW_REGION_RANGE(NtscU, 809C4730, 809C474F, -0x47B0) +MKW_REGION_RANGE(NtscU, 809C496C, 809C496F, -0x4820) + +MKW_REGION_RANGE(NtscJ, 80000000, 80008023, +0x0) +MKW_REGION_RANGE(NtscJ, 800080E8, 8000ADBF, -0xA4) +MKW_REGION_RANGE(NtscJ, 8000AF08, 80021BAB, -0xDC) +MKW_REGION_RANGE(NtscJ, 80021BAC, 80244EBF, -0xE0) +MKW_REGION_RANGE(NtscJ, 802572BF, 802575DF, -0x660) +MKW_REGION_RANGE(NtscJ, 80257F40, 80258184, -0x660) +MKW_REGION_RANGE(NtscJ, 80276054, 802A407F, -0x660) +MKW_REGION_RANGE(NtscJ, 802A4080, 8038917B, -0x680) +MKW_REGION_RANGE(NtscJ, 80399200, 80399400, -0x680) +MKW_REGION_RANGE(NtscJ, 805103B4, 805CC0A7, -0x680) +MKW_REGION_RANGE(NtscJ, 805CC1B4, 805FA33B, -0x724) +MKW_REGION_RANGE(NtscJ, 805FA344, 805FF6E7, -0x724) +MKW_REGION_RANGE(NtscJ, 805FFD70, 806003E7, -0x848) +MKW_REGION_RANGE(NtscJ, 80600C78, 80620CB3, -0x88C) +MKW_REGION_RANGE(NtscJ, 80620D7C, 80637A23, -0x8B4) +MKW_REGION_RANGE(NtscJ, 80637A80, 8063BCF7, -0x914) +MKW_REGION_RANGE(NtscJ, 8063BD28, 8063BD2F, -0x920) +MKW_REGION_RANGE(NtscJ, 8063BD38, 8063BD3F, -0x920) +MKW_REGION_RANGE(NtscJ, 8063BE40, 8088F70F, -0x994) +MKW_REGION_RANGE(NtscJ, 8088F720, 8088FDBB, -0x9A0) +MKW_REGION_RANGE(NtscJ, 80890208, 80890977, -0x9B0) +MKW_REGION_RANGE(NtscJ, 808913C0, 808913C3, -0x9B0) +MKW_REGION_RANGE(NtscJ, 80891750, 8089175F, -0x9B0) +MKW_REGION_RANGE(NtscJ, 80891A60, 80891A6F, -0x9B0) +MKW_REGION_RANGE(NtscJ, 80891B28, 80891C28, -0x9B0) +MKW_REGION_RANGE(NtscJ, 80892F2C, 80897DEF, -0x9B0) +MKW_REGION_RANGE(NtscJ, 80898955, 80898959, -0xE60) +MKW_REGION_RANGE(NtscJ, 80899692, 808B5CCF, -0xEA0) +MKW_REGION_RANGE(NtscJ, 808B5CD8, 808B5CDB, -0xE9C) +MKW_REGION_RANGE(NtscJ, 808BB034, 808BB097, -0xEB0) +MKW_REGION_RANGE(NtscJ, 808BBEC8, 808DA617, -0xEB0) +MKW_REGION_RANGE(NtscJ, 808DC540, 808DC54F, -0xEB0) +MKW_REGION_RANGE(NtscJ, 808E2BBC, 808E2BBE, +0x0) +MKW_REGION_RANGE(NtscJ, 809BD6E8, 809C474B, -0xFA0) +MKW_REGION_RANGE(NtscJ, 809C496C, 809C496F, -0xFA0) diff --git a/runtime/include/guest_abi/native_cpu_calls.inc b/runtime/include/guest_abi/native_cpu_calls.inc index 83fa99a..035c608 100644 --- a/runtime/include/guest_abi/native_cpu_calls.inc +++ b/runtime/include/guest_abi/native_cpu_calls.inc @@ -44,56 +44,62 @@ extern "C" void GX__SetBlendMode_8017277c(uint32_t t, uint32_t s, uint32_t d, ui extern "C" void GX__LoadPosMtxImm_8017310c(uint32_t ma, uint32_t id); extern "C" void GX__SetCurrentMtx_80173214(uint32_t id); +// Keyed by the translated region's addresses, so only translated code sees them; +// runtime calls resolve through the registry. +#if defined(MKW_TRANSLATED_GUEST_REGION) + #define MKW_KNOWN_TYPED_NATIVE(addr, fn, ...) \ -template <> struct KnownTypedNativeCpuCall { \ +template <> struct KnownTypedNativeCpuCall { \ static constexpr bool kAvailable = true; \ static void Invoke(CpuContext* cpu) { (void)cpu; fn(__VA_ARGS__); } \ } -MKW_KNOWN_TYPED_NATIVE(0x8016D3A4u, GX__SetVtxDesc_8016d3a4, cpu->gpr[3], cpu->gpr[4]); -MKW_KNOWN_TYPED_NATIVE(0x8016DC34u, GX__ClearVtxDesc_8016dc34); -MKW_KNOWN_TYPED_NATIVE(0x8016DC68u, GX__SetVtxAttrFmt_8016dc68, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6], cpu->gpr[7]); -MKW_KNOWN_TYPED_NATIVE(0x8016E37Cu, GX__SetTexCoordGen2_8016e37c, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6], cpu->gpr[7], cpu->gpr[8]); -MKW_KNOWN_TYPED_NATIVE(0x8016E5A4u, GX__SetNumTexGens_8016e5a4, cpu->gpr[3]); -MKW_KNOWN_TYPED_NATIVE(0x8016EAB0u, GX__DrawDone_8016eab0); -MKW_KNOWN_TYPED_NATIVE(0x8016F0F0u, GX__Begin_8016f0f0, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5]); -MKW_KNOWN_TYPED_NATIVE(0x8016F314u, GX__SetLineWidth_8016f314, cpu->gpr[3], cpu->gpr[4]); -MKW_KNOWN_TYPED_NATIVE(0x8016F348u, GX__SetPointSize_8016f348, cpu->gpr[3], cpu->gpr[4]); -MKW_KNOWN_TYPED_NATIVE(0x8016F3B8u, GX__SetCullMode_8016f3b8, cpu->gpr[3]); -MKW_KNOWN_TYPED_NATIVE(0x8017054Cu, GX__SetNumChans_8017054c, cpu->gpr[3]); -MKW_KNOWN_TYPED_NATIVE(0x80170570u, GX__SetChanCtrl_80170570, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6], cpu->gpr[7], cpu->gpr[8], cpu->gpr[9]); -MKW_KNOWN_TYPED_NATIVE(0x801707F8u, GX__InitTexObj_801707f8, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6], cpu->gpr[7], cpu->gpr[8], cpu->gpr[9], cpu->gpr[10]); -MKW_KNOWN_TYPED_NATIVE(0x80170A4Cu, GX__InitTexObjLOD_80170a4c, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], static_cast(cpu->fpr[1].d), static_cast(cpu->fpr[2].d), static_cast(cpu->fpr[3].d), cpu->gpr[6], cpu->gpr[7], cpu->gpr[8]); -MKW_KNOWN_TYPED_NATIVE(0x80171110u, GX__InvalidateTexAll_80171110); -MKW_KNOWN_TYPED_NATIVE(0x80170F2Cu, GX__LoadTexObj_80170f2c, cpu->gpr[3], cpu->gpr[4]); -MKW_KNOWN_TYPED_NATIVE(0x80171B38u, GX__SetNumIndStages_80171b38, cpu->gpr[3]); -MKW_KNOWN_TYPED_NATIVE(0x80171B58u, GX__SetTevDirect_80171b58, cpu->gpr[3]); -MKW_KNOWN_TYPED_NATIVE(0x80171CE0u, GX__SetTevColorIn_80171ce0, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6], cpu->gpr[7]); -MKW_KNOWN_TYPED_NATIVE(0x80171D20u, GX__SetTevAlphaIn_80171d20, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6], cpu->gpr[7]); -MKW_KNOWN_TYPED_NATIVE(0x80171D60u, GX__SetTevColorOp_80171d60, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6], cpu->gpr[7], cpu->gpr[8]); -MKW_KNOWN_TYPED_NATIVE(0x80171DB8u, GX__SetTevAlphaOp_80171db8, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6], cpu->gpr[7], cpu->gpr[8]); -MKW_KNOWN_TYPED_NATIVE(0x80171E70u, GX__SetTevColorS10_80171e70, cpu->gpr[3], cpu->gpr[4]); -MKW_KNOWN_TYPED_NATIVE(0x80171ED4u, GX__SetTevKColor_80171ed4, cpu->gpr[3], cpu->gpr[4]); -MKW_KNOWN_TYPED_NATIVE(0x80171F30u, GX__SetTevKColorSel_80171f30, cpu->gpr[3], cpu->gpr[4]); -MKW_KNOWN_TYPED_NATIVE(0x80171F80u, GX__SetTevKAlphaSel_80171f80, cpu->gpr[3], cpu->gpr[4]); -MKW_KNOWN_TYPED_NATIVE(0x80171FD0u, GX__SetTevSwapMode_80171fd0, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5]); -MKW_KNOWN_TYPED_NATIVE(0x8017200Cu, GX__SetTevSwapModeTable_8017200c, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6], cpu->gpr[7]); -MKW_KNOWN_TYPED_NATIVE(0x8017214Cu, GX__SetTevOrder_8017214c, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6]); -MKW_KNOWN_TYPED_NATIVE(0x801722A8u, GX__SetNumTevStages_801722a8, cpu->gpr[3]); -MKW_KNOWN_TYPED_NATIVE(0x8017277Cu, GX__SetBlendMode_8017277c, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6]); -MKW_KNOWN_TYPED_NATIVE(0x8017310Cu, GX__LoadPosMtxImm_8017310c, cpu->gpr[3], cpu->gpr[4]); -MKW_KNOWN_TYPED_NATIVE(0x80173214u, GX__SetCurrentMtx_80173214, cpu->gpr[3]); +MKW_KNOWN_TYPED_NATIVE(8016D3A4, GX__SetVtxDesc_8016d3a4, cpu->gpr[3], cpu->gpr[4]); +MKW_KNOWN_TYPED_NATIVE(8016DC34, GX__ClearVtxDesc_8016dc34); +MKW_KNOWN_TYPED_NATIVE(8016DC68, GX__SetVtxAttrFmt_8016dc68, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6], cpu->gpr[7]); +MKW_KNOWN_TYPED_NATIVE(8016E37C, GX__SetTexCoordGen2_8016e37c, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6], cpu->gpr[7], cpu->gpr[8]); +MKW_KNOWN_TYPED_NATIVE(8016E5A4, GX__SetNumTexGens_8016e5a4, cpu->gpr[3]); +MKW_KNOWN_TYPED_NATIVE(8016EAB0, GX__DrawDone_8016eab0); +MKW_KNOWN_TYPED_NATIVE(8016F0F0, GX__Begin_8016f0f0, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5]); +MKW_KNOWN_TYPED_NATIVE(8016F314, GX__SetLineWidth_8016f314, cpu->gpr[3], cpu->gpr[4]); +MKW_KNOWN_TYPED_NATIVE(8016F348, GX__SetPointSize_8016f348, cpu->gpr[3], cpu->gpr[4]); +MKW_KNOWN_TYPED_NATIVE(8016F3B8, GX__SetCullMode_8016f3b8, cpu->gpr[3]); +MKW_KNOWN_TYPED_NATIVE(8017054C, GX__SetNumChans_8017054c, cpu->gpr[3]); +MKW_KNOWN_TYPED_NATIVE(80170570, GX__SetChanCtrl_80170570, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6], cpu->gpr[7], cpu->gpr[8], cpu->gpr[9]); +MKW_KNOWN_TYPED_NATIVE(801707F8, GX__InitTexObj_801707f8, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6], cpu->gpr[7], cpu->gpr[8], cpu->gpr[9], cpu->gpr[10]); +MKW_KNOWN_TYPED_NATIVE(80170A4C, GX__InitTexObjLOD_80170a4c, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], static_cast(cpu->fpr[1].d), static_cast(cpu->fpr[2].d), static_cast(cpu->fpr[3].d), cpu->gpr[6], cpu->gpr[7], cpu->gpr[8]); +MKW_KNOWN_TYPED_NATIVE(80171110, GX__InvalidateTexAll_80171110); +MKW_KNOWN_TYPED_NATIVE(80170F2C, GX__LoadTexObj_80170f2c, cpu->gpr[3], cpu->gpr[4]); +MKW_KNOWN_TYPED_NATIVE(80171B38, GX__SetNumIndStages_80171b38, cpu->gpr[3]); +MKW_KNOWN_TYPED_NATIVE(80171B58, GX__SetTevDirect_80171b58, cpu->gpr[3]); +MKW_KNOWN_TYPED_NATIVE(80171CE0, GX__SetTevColorIn_80171ce0, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6], cpu->gpr[7]); +MKW_KNOWN_TYPED_NATIVE(80171D20, GX__SetTevAlphaIn_80171d20, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6], cpu->gpr[7]); +MKW_KNOWN_TYPED_NATIVE(80171D60, GX__SetTevColorOp_80171d60, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6], cpu->gpr[7], cpu->gpr[8]); +MKW_KNOWN_TYPED_NATIVE(80171DB8, GX__SetTevAlphaOp_80171db8, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6], cpu->gpr[7], cpu->gpr[8]); +MKW_KNOWN_TYPED_NATIVE(80171E70, GX__SetTevColorS10_80171e70, cpu->gpr[3], cpu->gpr[4]); +MKW_KNOWN_TYPED_NATIVE(80171ED4, GX__SetTevKColor_80171ed4, cpu->gpr[3], cpu->gpr[4]); +MKW_KNOWN_TYPED_NATIVE(80171F30, GX__SetTevKColorSel_80171f30, cpu->gpr[3], cpu->gpr[4]); +MKW_KNOWN_TYPED_NATIVE(80171F80, GX__SetTevKAlphaSel_80171f80, cpu->gpr[3], cpu->gpr[4]); +MKW_KNOWN_TYPED_NATIVE(80171FD0, GX__SetTevSwapMode_80171fd0, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5]); +MKW_KNOWN_TYPED_NATIVE(8017200C, GX__SetTevSwapModeTable_8017200c, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6], cpu->gpr[7]); +MKW_KNOWN_TYPED_NATIVE(8017214C, GX__SetTevOrder_8017214c, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6]); +MKW_KNOWN_TYPED_NATIVE(801722A8, GX__SetNumTevStages_801722a8, cpu->gpr[3]); +MKW_KNOWN_TYPED_NATIVE(8017277C, GX__SetBlendMode_8017277c, cpu->gpr[3], cpu->gpr[4], cpu->gpr[5], cpu->gpr[6]); +MKW_KNOWN_TYPED_NATIVE(8017310C, GX__LoadPosMtxImm_8017310c, cpu->gpr[3], cpu->gpr[4]); +MKW_KNOWN_TYPED_NATIVE(80173214, GX__SetCurrentMtx_80173214, cpu->gpr[3]); #undef MKW_KNOWN_TYPED_NATIVE #define MKW_KNOWN_NATIVE_CPU_CALL(addr, fn) \ -template <> struct KnownNativeCpuCall { \ +template <> struct KnownNativeCpuCall { \ static constexpr bool kAvailable = true; \ static constexpr uint32_t kNonvolatileFprWriteMask = 0; \ static constexpr void (*Entry)(CpuContext*) = &fn; \ } -MKW_KNOWN_NATIVE_CPU_CALL(0x800847C0u, nw4r__lyt__detail__DrawQuad_800847c0); -MKW_KNOWN_NATIVE_CPU_CALL(0x80084D20u, nw4r__lyt__detail__DrawQuad_80084d20); +MKW_KNOWN_NATIVE_CPU_CALL(800847C0, nw4r__lyt__detail__DrawQuad_800847c0); +MKW_KNOWN_NATIVE_CPU_CALL(80084D20, nw4r__lyt__detail__DrawQuad_80084d20); #undef MKW_KNOWN_NATIVE_CPU_CALL + +#endif diff --git a/runtime/include/guest_function_imports.h b/runtime/include/guest_function_imports.h new file mode 100644 index 0000000..2b32810 --- /dev/null +++ b/runtime/include/guest_function_imports.h @@ -0,0 +1,21 @@ +#pragma once + +// Base translations the runtime calls directly, named by PAL identity and resolved through the +// function registry on first use. +// MKW_GUEST_FUNC(801A0620)(ctx); + +#include "guest_abi/cpu_context.h" +#include "guest_abi/guest_region.h" + +namespace GuestFunctions { +using Entry = void (*)(CpuContext*); + +// The base translation at a guest address, also where a native or mod overrides it. +Entry BaseTranslation(uint32_t address); +} // namespace GuestFunctions + +#define MKW_GUEST_FUNC(pal) \ + (*[] { \ + static const ::GuestFunctions::Entry entry = ::GuestFunctions::BaseTranslation(MKW_GADDR(pal)); \ + return entry; \ + }()) diff --git a/runtime/include/gx_worker.h b/runtime/include/gx_worker.h new file mode 100644 index 0000000..25179e2 --- /dev/null +++ b/runtime/include/gx_worker.h @@ -0,0 +1,114 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +// Dedicated GX thread (Dolphin "dual core"): the game thread records GX HLE calls in order and +// the worker executes them. While active, GX work runs on the worker except inside inline scopes, +// which run on the game thread after the worker has caught up. +namespace GxWorker { + +namespace detail { +inline constexpr size_t kAlign = 16; + +extern std::atomic g_active; +extern constinit thread_local bool t_onWorker; +extern constinit thread_local int t_inlineDepth; +extern bool g_fifoPending; + +void* Reserve(size_t payloadSize, void (*run)(void*)); +void Commit(); +void FlushFifo(); +} // namespace detail + +// Starts the worker unless [video] gx_worker disables it. Call once Aurora is up. +void Start(); +void Stop(); +// Stops without running queued work; bounded, for fatal exits. +void Abandon(); + +inline bool Active() noexcept { return detail::g_active.load(std::memory_order_relaxed); } +inline bool OnWorker() noexcept { return detail::t_onWorker; } +// True when a GX entry point on this thread must be recorded instead of executed. +inline bool ShouldDefer() noexcept { + return Active() && !detail::t_onWorker && detail::t_inlineDepth == 0; +} + +template +void Submit(F&& fn) { + using Fn = std::decay_t; + static_assert(alignof(Fn) <= detail::kAlign, "over-aligned GX command"); + if (detail::g_fifoPending) { + detail::FlushFifo(); + } + void* storage = detail::Reserve(sizeof(Fn), [](void* p) { + struct Destroy { + Fn* f; + ~Destroy() { f->~Fn(); } + } guard{static_cast(p)}; + (*guard.f)(); + }); + new (storage) Fn(std::forward(fn)); + detail::Commit(); +} + +// Records fn when deferring, otherwise runs it now. Read call-time guest memory before calling. +template +void Run(F&& fn) { + if (ShouldDefer()) { + Submit(std::forward(fn)); + } else { + fn(); + } +} + +// Gather-pipe writes, coalesced into one record per run of consecutive writes and replayed +// with their original sizes. +void FifoWrite(uint32_t value, uint32_t sizeBytes); +void FifoBurst(const uint8_t* data, uint32_t sizeBytes); + +// Called about every millisecond while the game thread waits in Sync. +void SetWaitCallback(void (*callback)()); + +// Blocks until every recorded command has executed. +void Sync(); + +// GX entry points run inline on the game thread while inside (after a Sync), for work whose +// results the guest needs immediately. +void BeginInline(); +void EndInline(); + +class InlineScope { +public: + InlineScope() { BeginInline(); } + ~InlineScope() { EndInline(); } + InlineScope(const InlineScope&) = delete; + InlineScope& operator=(const InlineScope&) = delete; +}; + +} // namespace GxWorker + +// Records the enclosing call for the GX worker and returns, or falls through when it should run +// here (worker thread, inline scope, worker disabled). +#define GX_DEFER_CALL(fn, ...) \ + do { \ + if (GxWorker::ShouldDefer()) { \ + GxWorker::Submit([=] { fn(__VA_ARGS__); }); \ + return; \ + } \ + } while (false) + +#define GX_DEFER_CALL0(fn) \ + do { \ + if (GxWorker::ShouldDefer()) { \ + GxWorker::Submit([] { fn(); }); \ + return; \ + } \ + } while (false) + +// Runs the rest of the enclosing function on this thread once the worker has caught up. +#define GX_SYNC_INLINE() GxWorker::InlineScope gxInlineScope_ diff --git a/runtime/include/hle/bluetooth_hle.h b/runtime/include/hle/bluetooth_hle.h new file mode 100644 index 0000000..b9944b2 --- /dev/null +++ b/runtime/include/hle/bluetooth_hle.h @@ -0,0 +1,22 @@ +#pragma once + +// IOS side of the emulated Bluetooth module (/dev/usb/oh1/57e/305): routes the +// guest's USB control / bulk / interrupt transfers to Bluetooth::Controller and +// completes the held event and ACL reads from the alarm pump. + +#include + +struct CpuContext; + +// Returns the fd for the Bluetooth device path, 0 when `path` is not ours. +int32_t Bluetooth_HLE_OpenDevice(const char* path); +bool Bluetooth_HLE_IsFd(uint32_t fd); +// Cancels the held reads (their callbacks are queued) and closes the device. +int32_t Bluetooth_HLE_Close(uint32_t fd); +// True when the request completed now with `result`; false when it is held +// until data arrives (its callback is queued later by the pump). +bool Bluetooth_HLE_IoctlvAsync(uint32_t fd, uint32_t cmd, uint32_t numIn, uint32_t numOut, uint32_t vectorPtr, + uint32_t callback, uint32_t callbackArg, int32_t& result); +int32_t Bluetooth_HLE_Ioctlv(uint32_t fd, uint32_t cmd, uint32_t numIn, uint32_t numOut, uint32_t vectorPtr); +// Runs the controller and completes held reads. Emulation thread only. +bool Bluetooth_HLE_ProcessCompletions(CpuContext* cpu); diff --git a/runtime/include/hle/controller_status_contract.h b/runtime/include/hle/controller_status_contract.h index e948e10..8ff7318 100644 --- a/runtime/include/hle/controller_status_contract.h +++ b/runtime/include/hle/controller_status_contract.h @@ -41,42 +41,3 @@ inline GuestStatus Encode(const Fields& fields) } } // namespace PadStatusContract - -namespace WpadContract { - -inline constexpr std::size_t kChannelCount = 4; -inline constexpr int32_t kStatusDisabled = 0; -inline constexpr int32_t kStatusReady = 3; -inline constexpr int32_t kErrorNoController = -1; -inline constexpr int32_t kErrorNotReady = -2; -inline constexpr int32_t kErrorBadChannel = -6; -inline constexpr int32_t kExtensionCore = 0; - -class State { -public: - void Initialize() { m_initialized = true; } - bool IsInitialized() const { return m_initialized; } - int32_t GetLibraryStatus() const { return m_initialized ? kStatusReady : kStatusDisabled; } - - int32_t GetDataFormat(uint32_t chan) const - { - if (chan >= kChannelCount) { - return kErrorBadChannel; - } - return m_initialized ? 0 : kErrorNotReady; - } - - int32_t SetDataFormat(uint32_t chan, int32_t format) const - { - (void)format; - if (chan >= kChannelCount) { - return kErrorBadChannel; - } - return m_initialized ? kErrorNoController : kErrorNotReady; - } - -private: - bool m_initialized = false; -}; - -} // namespace WpadContract diff --git a/runtime/include/hle/hollywood_gpio.h b/runtime/include/hle/hollywood_gpio.h new file mode 100644 index 0000000..a383fe1 --- /dev/null +++ b/runtime/include/hle/hollywood_gpio.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +// HW_GPIOB_OUT, the GPIO outputs the PPC owns. WPAD sets bit 8 to power the +// sensor bar; there is nothing behind it on a PC, so the register only latches. +inline constexpr uint32_t kHollywoodGpioBOut = 0xCD0000C0u; + +bool HollywoodGpio_Read32(uint32_t address, uint32_t& value); +bool HollywoodGpio_Write32(uint32_t address, uint32_t value); diff --git a/runtime/include/hle_stubs.h b/runtime/include/hle_stubs.h index 92ea526..e3ba175 100644 --- a/runtime/include/hle_stubs.h +++ b/runtime/include/hle_stubs.h @@ -38,10 +38,12 @@ extern "C" void OS_HLE_EndDeferredGuestCallbacks(); // renaming requires updating Translator.Cli/Program.cs, RuntimeNativeGuestEffectAnalyzer.cs, // TranslatedBuildShardEmitter.cs and RuntimeNativeFunctionAbiProvider.cs together. +// addr_hex is the PAL address (see guest_abi/guest_region.h). The translator reads arg_list as +// the guest ABI, so the unused wrapper keeps it checked against the implementation. #define PPC_NATIVE_OVERRIDE(addr_hex, name, ret_type, arg_list, call_list) \ - extern "C" ret_type func_##addr_hex arg_list { return name call_list; } \ + [[maybe_unused]] static ret_type native_signature_##addr_hex arg_list { return name call_list; } \ REGISTER_NATIVE_FUNCTION(0x##addr_hex, name) #define PPC_NATIVE_OVERRIDE_VOID(addr_hex, name, arg_list, call_list) \ - extern "C" void func_##addr_hex arg_list { name call_list; } \ + [[maybe_unused]] static void native_signature_##addr_hex arg_list { name call_list; } \ REGISTER_NATIVE_FUNCTION(0x##addr_hex, name) diff --git a/runtime/include/nand_path.h b/runtime/include/nand_path.h index eb0fda8..b607a9a 100644 --- a/runtime/include/nand_path.h +++ b/runtime/include/nand_path.h @@ -1,6 +1,7 @@ #pragma once #include "runtime_config.h" +#include "guest_abi/guest_region.h" #include "nand_settings.h" #include "runtime_log.h" #include "system_bridge.h" @@ -184,7 +185,9 @@ inline std::filesystem::path DiscoverNandRootPath() { static const auto root = [] { const auto resolved = ResolveNandRootPath(); std::string error; - if (!RuntimeNandSettings::Ensure(resolved, error)) { + const auto& facts = ::GuestRegion::CurrentFacts(); + if (!RuntimeNandSettings::Ensure(resolved, error, + {facts.area, facts.model, facts.productCode, facts.video, facts.gameRegion})) { FailNandRoot(error.c_str(), RuntimeNandSettings::FilePath(resolved)); } return resolved; diff --git a/runtime/include/nand_settings.h b/runtime/include/nand_settings.h index 055f4c2..fd48dce 100644 --- a/runtime/include/nand_settings.h +++ b/runtime/include/nand_settings.h @@ -88,10 +88,20 @@ inline std::string GenerateSerial(std::time_t now) { return std::string(9 - digits.size(), '0') + digits; } -// This recompilation targets the European disc. These are Dolphin's PAL boot -// defaults; an existing setting.txt always takes precedence, in every region. -inline std::optional> EncodeNew(const std::string& serial) { - const Settings identity{{"SERNO", serial}, {"CODE", "LEH"}, {"AREA", "EUR"}, {"GAME", "EU"}}; +// Console identity for a new setting.txt; Dolphin's boot defaults for the game's region. +struct BootDefaults { + std::string area = "EUR"; + std::string model = "RVL-001(EUR)"; + std::string code = "LEH"; + std::string video = "PAL"; + std::string game = "EU"; +}; + +// An existing setting.txt always takes precedence, in every region. +inline std::optional> EncodeNew( + const std::string& serial, + const BootDefaults& defaults = BootDefaults{}) { + const Settings identity{{"SERNO", serial}, {"CODE", defaults.code}, {"AREA", defaults.area}, {"GAME", defaults.game}}; if (!HasIdentity(identity)) { return std::nullopt; } @@ -102,9 +112,15 @@ inline std::optional> EncodeNew(const std::string& seri bytes[position++] = static_cast(value) ^ static_cast(key); key = (key << 1) | (key >> 31); }; - for (const std::string& line : {std::string("AREA=EUR\r\n"), std::string("MODEL=RVL-001(EUR)\r\n"), - std::string("DVD=0\r\n"), std::string("MPCH=0x7FFE\r\n"), std::string("CODE=LEH\r\n"), - "SERNO=" + serial + "\r\n", std::string("VIDEO=PAL\r\n"), std::string("GAME=EU\r\n")}) { + for (const std::string& line : { + "AREA=" + defaults.area + "\r\n", + "MODEL=" + defaults.model + "\r\n", + std::string("DVD=0\r\n"), + std::string("MPCH=0x7FFE\r\n"), + "CODE=" + defaults.code + "\r\n", + "SERNO=" + serial + "\r\n", + "VIDEO=" + defaults.video + "\r\n", + "GAME=" + defaults.game + "\r\n"}) { for (;;) { if (position + line.size() > bytes.size()) { return std::nullopt; @@ -146,6 +162,7 @@ inline std::optional CreateScratchDirectory( // Never replace an existing file, including an unreadable or damaged one. // Publish a complete file atomically so simultaneous launches use one identity. inline bool Ensure(const std::filesystem::path& root, std::string& error, + const BootDefaults& defaults, std::time_t now = std::time(nullptr)) { const auto path = FilePath(root); std::error_code ec; @@ -163,7 +180,7 @@ inline bool Ensure(const std::filesystem::path& root, std::string& error, return false; } - const auto bytes = EncodeNew(GenerateSerial(now)); + const auto bytes = EncodeNew(GenerateSerial(now), defaults); if (!bytes) { error = "Cannot initialize NAND settings: invalid system clock"; return false; diff --git a/runtime/include/runtime_config.h b/runtime/include/runtime_config.h index 99d6c2b..11962a4 100644 --- a/runtime/include/runtime_config.h +++ b/runtime/include/runtime_config.h @@ -44,6 +44,8 @@ struct RuntimeUserConfig { std::optional frameInterpolationFps; std::optional metalFxSpatialUpscaling; std::optional skipUnreadyPipelines; + std::optional vsync; + std::optional gxWorker; std::optional disableCopyFilter; std::optional textureReplacements; std::optional textureDumps; @@ -57,26 +59,16 @@ struct RuntimeUserConfig { std::optional audioMuted; std::optional audioMixWorker; std::optional attenuateMusicWhenMediaPlays; - // Real Wii Remotes (with or without Nunchuk / Classic Controller) and Wii U Pro - // Controllers paired over Bluetooth, driven by SDL's HIDAPI Wii driver. The driver - // is opt-in on SDL's side, so this decides whether the runtime turns it on. + // Real Wii Remotes passed through to the game's own Bluetooth stack. Off hands + // Nintendo controllers (e.g. the Wii U Pro Controller) to SDL as plain gamepads. std::optional wiiRemotes; - // Keep re-enumerating Bluetooth HID devices while no Wii controller is connected - // (Dolphin's "continuous scanning"), so a remote that dropped or was switched on - // after launch shows up without restarting. - std::optional wiiContinuousScan; - // Accelerometer zero-point correction for the Bluetooth Wii Remote, in g and in - // SDL's sensor frame (x right, y out of the button face, z towards the user). - // SDL's Wii driver falls back to a nominal zero point when its read of the - // remote's calibration block times out (common over Bluetooth), so this is - // measured in the overlay with the remote at rest. Stored per remote under - // [controller.wii_accel_offsets]; the old shared - // wii_accel_offset_* keys are only detected, to report that they are ignored. - std::map> wiiAccelOffsets; - bool hasLegacyWiiAccelOffset = false; - // Debugging aid: append every KPAD sample of the Bluetooth remote (raw and - // corrected accelerometer, buttons) to wii_accel_trace.csv next to Config.toml. - std::optional wiiAccelTrace; + // Look for remotes in pairing mode (1+2 / SYNC) while none is connected. + std::optional wiiAutoPair; + // The console's Wii Remote settings (SYSCONF BT.BAR, BT.SENS, BT.SPKV, BT.MOT). + std::optional wiiSensorBarAbove; + std::optional wiiIrSensitivity; + std::optional wiiSpeakerVolume; + std::optional wiiRumble; std::optional networkEnabled; std::optional discordPresenceEnabled; // The application ID of the WiiCompiled Discord application. This is only @@ -285,6 +277,9 @@ inline void EnsureConfigFile() { "display_mode = \"windowed\"\n" "graphics_api = \"auto\"\n" "skip_unready_pipelines = true\n" + "vsync = false\n" + "# Runs GX command processing on its own thread. Read once, at startup.\n" + "gx_worker = true\n" "disable_copy_filter = true\n" "show_fps = true\n" "# Dolphin-style custom textures. When enabled, the renderer indexes\n" @@ -382,28 +377,6 @@ inline void AppendOverlayRoots(RuntimeUserConfig& config, const std::string& roo } // Reads every supported setting out of a parsed Config.toml document. -// [x, y, z] of finite numbers (integers allowed), else nullopt. -inline std::optional> ParseAccelOffset(const toml::value& value) { - if (!value.is_array() || value.as_array().size() != 3) { - return std::nullopt; - } - std::array offset{}; - for (size_t i = 0; i < 3; ++i) { - const toml::value& element = value.as_array()[i]; - if (element.is_floating()) { - offset[i] = element.as_floating(); - } else if (element.is_integer()) { - offset[i] = static_cast(element.as_integer()); - } else { - return std::nullopt; - } - if (!std::isfinite(offset[i])) { - return std::nullopt; - } - } - return offset; -} - inline RuntimeUserConfig ParseConfigDocument(const toml::value& document) { RuntimeUserConfig config; @@ -427,13 +400,6 @@ inline RuntimeUserConfig ParseConfigDocument(const toml::value& document) { config.controllerExpressions[key] = value.as_string(); } } - if (section->contains("wii_accel_offsets") && section->at("wii_accel_offsets").is_table()) { - for (const auto& [key, value] : section->at("wii_accel_offsets").as_table()) { - if (const auto offset = ParseAccelOffset(value)) { - config.wiiAccelOffsets[key] = *offset; - } - } - } } config.widescreen = FindConfigValue(document, "video", "widescreen"); @@ -471,6 +437,8 @@ inline RuntimeUserConfig ParseConfigDocument(const toml::value& document) { config.metalFxSpatialUpscaling = FindConfigValue(document, "video", "metalfx_spatial_upscaling"); config.skipUnreadyPipelines = FindConfigValue(document, "video", "skip_unready_pipelines"); + config.vsync = FindConfigValue(document, "video", "vsync"); + config.gxWorker = FindConfigValue(document, "video", "gx_worker"); config.disableCopyFilter = FindConfigValue(document, "video", "disable_copy_filter"); config.showFps = FindConfigValue(document, "video", "show_fps"); config.textureReplacements = FindConfigValue(document, "video", "texture_replacements"); @@ -494,11 +462,17 @@ inline RuntimeUserConfig ParseConfigDocument(const toml::value& document) { config.attenuateMusicWhenMediaPlays = FindConfigValue(document, "audio", "attenuate_music_when_media_plays"); config.wiiRemotes = FindConfigValue(document, "controller", "wii_remotes"); - config.wiiContinuousScan = FindConfigValue(document, "controller", "wii_continuous_scan"); - for (const char* key : {"wii_accel_offset_x", "wii_accel_offset_y", "wii_accel_offset_z"}) { - config.hasLegacyWiiAccelOffset |= FindConfigValue(document, "controller", key).value_or(0.0) != 0.0; + config.wiiAutoPair = FindConfigValue(document, "controller", "wii_auto_pair"); + if (const auto bar = FindConfigValue(document, "controller", "wii_sensor_bar")) { + if (*bar == "above" || *bar == "below") config.wiiSensorBarAbove = *bar == "above"; } - config.wiiAccelTrace = FindConfigValue(document, "controller", "wii_accel_trace"); + if (const auto value = FindConfigInt(document, "controller", "wii_ir_sensitivity"); value && *value >= 1 && *value <= 5) { + config.wiiIrSensitivity = *value; + } + if (const auto value = FindConfigInt(document, "controller", "wii_speaker_volume"); value && *value >= 0 && *value <= 127) { + config.wiiSpeakerVolume = *value; + } + config.wiiRumble = FindConfigValue(document, "controller", "wii_rumble"); config.networkEnabled = FindConfigValue(document, "network", "enabled"); config.discordPresenceEnabled = FindConfigValue(document, "discord", "enabled"); config.discordClientId = FindConfigValue(document, "discord", "client_id"); @@ -669,6 +643,11 @@ inline bool SetSkipUnreadyPipelines(bool value) { return WriteSetting("video", "skip_unready_pipelines", value ? "true" : "false"); } +inline bool SetVsync(bool value) { + Mutable().vsync = value; + return WriteSetting("video", "vsync", value ? "true" : "false"); +} + inline bool SetDisableCopyFilter(bool value) { Mutable().disableCopyFilter = value; return WriteSetting("video", "disable_copy_filter", value ? "true" : "false"); @@ -844,56 +823,70 @@ inline bool AudioMixWorkerEnabled(bool fallback = true) { return Get().audioMixWorker.value_or(fallback); } +inline bool GxWorkerEnabled(bool fallback = true) { + return Get().gxWorker.value_or(fallback); +} + // Whether background music should duck automatically for other media playback. inline bool AttenuateMusicWhenMediaPlays(bool fallback = false) { return Get().attenuateMusicWhenMediaPlays.value_or(fallback); } -// Bluetooth Wii Remotes / Wii U Pro Controllers. Read once before SDL's joystick -// subsystem comes up, so a change only takes effect on the next launch. -inline bool WiiRemotesEnabled(bool fallback = true) { +// Bluetooth Wii Remotes. Read once before SDL's joystick subsystem comes up, so a +// change only takes effect on the next launch. +inline bool WiiRemotesEnabled(bool fallback = false) { return Get().wiiRemotes.value_or(fallback); } -// Persists the Bluetooth Wii Remote driver switch. inline bool SetWiiRemotesEnabled(bool value) { Mutable().wiiRemotes = value; return WriteSetting("controller", "wii_remotes", value ? "true" : "false"); } -// Whether to keep rescanning Bluetooth while no Wii controller is connected. -inline bool WiiContinuousScanEnabled(bool fallback = false) { - return Get().wiiContinuousScan.value_or(fallback); +inline bool WiiAutoPairEnabled(bool fallback = true) { + return Get().wiiAutoPair.value_or(fallback); } -// Persists the continuous scanning switch. -inline bool SetWiiContinuousScanEnabled(bool value) { - Mutable().wiiContinuousScan = value; - return WriteSetting("controller", "wii_continuous_scan", value ? "true" : "false"); +inline bool SetWiiAutoPairEnabled(bool value) { + Mutable().wiiAutoPair = value; + return WriteSetting("controller", "wii_auto_pair", value ? "true" : "false"); } -// Stored correction of the remote identified by `remoteKey`, if it has one. -inline std::optional> WiiAccelOffsetFor(const std::string& remoteKey) { - const auto it = Get().wiiAccelOffsets.find(remoteKey); - if (it == Get().wiiAccelOffsets.end()) { - return std::nullopt; - } - return it->second; +// Defaults are the console's. +inline bool WiiSensorBarAbove(bool fallback = false) { + return Get().wiiSensorBarAbove.value_or(fallback); } -// Whether to write the per-frame accelerometer trace (off unless asked for). -inline bool WiiAccelTraceEnabled(bool fallback = false) { - return Get().wiiAccelTrace.value_or(fallback); +inline bool SetWiiSensorBarAbove(bool value) { + Mutable().wiiSensorBarAbove = value; + return WriteSetting("controller", "wii_sensor_bar", value ? "\"above\"" : "\"below\""); } -// Persists the accelerometer correction of one remote. `remoteKey` must be a bare TOML key. -inline bool SetWiiAccelOffsetFor(const std::string& remoteKey, const std::array& offset) { - Mutable().wiiAccelOffsets[remoteKey] = offset; - // Always float literals, so a whole-number offset does not come back as a TOML integer. - std::ostringstream formatted; - formatted << std::fixed << std::setprecision(4) << '[' << offset[0] << ", " << offset[1] << ", " << offset[2] - << ']'; - return WriteSetting("controller.wii_accel_offsets", remoteKey, formatted.str()); +inline int32_t WiiIrSensitivity(int32_t fallback = 3) { + return Get().wiiIrSensitivity.value_or(fallback); +} + +inline bool SetWiiIrSensitivity(int32_t value) { + Mutable().wiiIrSensitivity = value; + return WriteSetting("controller", "wii_ir_sensitivity", std::to_string(value)); +} + +inline int32_t WiiSpeakerVolume(int32_t fallback = 0x59) { + return Get().wiiSpeakerVolume.value_or(fallback); +} + +inline bool SetWiiSpeakerVolume(int32_t value) { + Mutable().wiiSpeakerVolume = value; + return WriteSetting("controller", "wii_speaker_volume", std::to_string(value)); +} + +inline bool WiiRumbleEnabled(bool fallback = true) { + return Get().wiiRumble.value_or(fallback); +} + +inline bool SetWiiRumbleEnabled(bool value) { + Mutable().wiiRumble = value; + return WriteSetting("controller", "wii_rumble", value ? "true" : "false"); } // Target frame rate for frame interpolation, or 0 to disable it. @@ -906,6 +899,10 @@ inline bool SkipUnreadyPipelines(bool fallback = true) { return Get().skipUnreadyPipelines.value_or(fallback); } +inline bool Vsync(bool fallback = false) { + return Get().vsync.value_or(fallback); +} + inline bool DisableCopyFilter(bool fallback = true) { return Get().disableCopyFilter.value_or(fallback); } @@ -1018,6 +1015,9 @@ inline void LogLoadedConfig() { if (config.skipUnreadyPipelines) { std::cout << " skip_unready_pipelines=" << (*config.skipUnreadyPipelines ? "true" : "false"); } + if (config.vsync) { + std::cout << " vsync=" << (*config.vsync ? "true" : "false"); + } if (config.disableCopyFilter) { std::cout << " disable_copy_filter=" << (*config.disableCopyFilter ? "true" : "false"); } diff --git a/runtime/include/system_bridge.h b/runtime/include/system_bridge.h index a2d4cf6..1c2ab8e 100644 --- a/runtime/include/system_bridge.h +++ b/runtime/include/system_bridge.h @@ -84,7 +84,8 @@ public: // Crash-path helpers shared by the centralized reporter in main.cpp. // DumpCrashHeuristics prints plain-language "likely cause" hints derived // from the register state; WriteGuestMemorySnapshot writes MEM1 to - // `mem1Path` and MEM2 to `mem1Path + ".mem2"`, logging outcomes to `os`. + // `mem1Path`, MEM2 to `mem1Path + ".mem2"` and the Kamek overlay to + // `mem1Path + ".kamek"`, logging outcomes to `os`. static void DumpCrashHeuristics(std::ostream& os, const struct CpuContext* cpu, const uint32_t* missingGuestTarget); static void WriteGuestMemorySnapshot(std::ostream& os, const std::filesystem::path& mem1Path); diff --git a/runtime/include/wii_remote_input.h b/runtime/include/wii_remote_input.h deleted file mode 100644 index d6780cd..0000000 --- a/runtime/include/wii_remote_input.h +++ /dev/null @@ -1,111 +0,0 @@ -#pragma once - -#include -#include -#include - -struct PADStatus; - -// Real Wii Remotes paired over Bluetooth. -// -// SDL 3 ships a HIDAPI driver for them (Wii Remote alone, with Nunchuk, with a -// Classic Controller, and the Wii U Pro Controller) that exposes each as a -// regular SDL gamepad; it is off by default on SDL's side and ConfigureSdlHints -// turns it on. A remote, alone or with a Nunchuk or Classic Controller, is -// handed to the game as a real Wii Remote with that extension: the KPAD/WPAD -// HLE builds a KPADStatus (and the WPADCLStatus behind KPADGetUnifiedWpadStatus) -// from it every frame (see ReadKpadSample), so the game's own code does wheelies, -// tricks, Wii Wheel steering and the Classic Controller layout, and plugging an -// extension in or out mid-game switches control scheme like on the console. Only -// the Wii U Pro Controller, which has no Wii-era equivalent, goes through -// aurora's PAD layer as a GameCube pad. -namespace WiiRemoteInput { - -enum class Kind : uint8_t { - NotWii, - Remote, // Wii Remote with no extension - RemoteWithNunchuk, - RemoteWithClassic, - WiiUPro, -}; - -// Must run before SDL's joystick subsystem is initialized (aurora does that -// inside aurora_initialize); SDL only consults the hint on its first device scan. -void ConfigureSdlHints(bool enabled); - -// Classifies a gamepad by the name SDL's Wii driver reports for it. -Kind KindForName(const char* gamepadName); -// Classification of the SDL gamepad currently assigned to a game port. -Kind KindForPort(uint32_t port); -const char* KindLabel(Kind kind); - -// One frame of a Wii Remote in the units KPAD uses. -struct KpadSample { - uint32_t hold = 0; // WPAD button bits (WPAD_BUTTON_*), Nunchuk C/Z included - float acc[3] = {}; // remote accelerometer in g, KPAD frame (rest: y = -1) - bool hasNunchuk = false; - float stick[2] = {}; // Nunchuk stick, -1..1, +y up - float nunchukAcc[3] = {}; - bool hasClassic = false; - uint32_t clHold = 0; // WPAD_CL_BUTTON_* bits - float clLStick[2] = {}; // Classic sticks, -1..1, +y up - float clRStick[2] = {}; - int16_t clLStickRaw[2] = {}; // as WPADCLStatus reports them: -512..511, centre 0, +y up - int16_t clRStickRaw[2] = {}; - uint8_t clTriggerL = 0; // 0..255; SDL only exposes the digital click - uint8_t clTriggerR = 0; -}; - -// What the game should see on `chan`: the controller SDL has there right now, -// or, for a few seconds after a remote vanished, the kind it had. SDL's driver -// destroys and re-creates the joystick when an extension is plugged in or out, -// and the console never disconnects for that, so the gap is papered over with -// neutral input instead of a "communications interrupted" prompt. -Kind EffectiveKind(uint32_t chan); -// True when the game reads `chan` through KPAD: a Wii Remote alone, with a -// Nunchuk or with a Classic Controller (live or within the swap grace period). -bool IsRemoteChannel(uint32_t chan); -// Reads the current state of the remote on `chan`; false when IsRemoteChannel -// is false. During the swap grace period the sample is neutral. -bool ReadKpadSample(uint32_t chan, KpadSample& sample); - -// Remote accelerometer for the overlay readout: the SDL sample in g after the -// zero-point correction (x right across the face, y out of the button face, z -// towards the user) and the KPAD vector built from it. False when the port has -// no remote or SDL has not delivered a sample yet. -bool ReadAccelDebug(uint32_t chan, float sdlG[3], float kpadAcc[3]); - -// Residual zero-point trim on top of SDL's factory-calibrated decode, stored per -// physical remote under [controller.wii_accel_offsets]. Expects the remote lying -// still, buttons up; Poll() averages about a second and stores it for that remote. -void StartAccelCalibration(uint32_t chan); -// Forgets the stored correction of the remote on `chan`. -void ClearAccelCalibration(uint32_t chan); -bool IsAccelCalibrating(uint32_t chan); -// 0..1 while a calibration is collecting samples. -float AccelCalibrationProgress(); -// Correction in effect for the remote on `chan` (zeros when uncalibrated), or -// nullopt when the port has no remote. -std::optional> ReadAccelOffset(uint32_t chan); -// Outcome of the last calibration attempt on `chan` for the overlay, or nullptr. -const char* AccelCalibrationMessage(uint32_t chan); - -// Reports "no controller" on the GameCube side for every port served through -// KPAD, so the game never sees the same remote twice. Runs after aurora's PADRead. -void HideRemotesFromPad(PADStatus* statuses, uint32_t count); - -// Dolphin-style continuous scanning. SDL's HIDAPI Wii driver drops a remote on -// a failed Bluetooth read or an extension change and never re-adds it on its -// own. Poll() runs once per PADRead and, while no Wii controller is present, -// periodically forces SDL to re-enumerate HIDAPI by toggling the driver hint. -void Poll(); -// Forces one re-enumeration right now (settings overlay "Rescan now"). -void RescanNow(); -// True while Poll() is looking for a remote (no Wii controller connected). -bool IsScanning(); -// True where looking means periodic rescans; elsewhere Poll() waits for hotplug. -bool PeriodicRescanEnabled(); -// Rescans issued since a Wii controller was last seen. -uint32_t ScanCount(); - -} // namespace WiiRemoteInput diff --git a/runtime/include/wiimote_ext_crypto.h b/runtime/include/wiimote_ext_crypto.h new file mode 100644 index 0000000..b92293c --- /dev/null +++ b/runtime/include/wiimote_ext_crypto.h @@ -0,0 +1,24 @@ +#pragma once + +// The Wii's extension controller encryption: the game writes a random key to +// the extension, which then XORs and offsets every byte it reports. + +#include +#include +#include +#include + +namespace Wiimote::ExtCrypto { + +struct Tables { + std::array ft{}; + std::array sb{}; + void Encrypt(uint8_t* data, uint32_t address, size_t length) const; + void Decrypt(uint8_t* data, uint32_t address, size_t length) const; +}; + +// Tables for the key the game wrote to registers 0x40..0x4F, or nullopt when it +// does not come from the first-party key schedule. +std::optional FromKey(const std::array& keyData); + +} // namespace Wiimote::ExtCrypto diff --git a/runtime/include/wiimote_extension.h b/runtime/include/wiimote_extension.h new file mode 100644 index 0000000..d1c492c --- /dev/null +++ b/runtime/include/wiimote_extension.h @@ -0,0 +1,40 @@ +#pragma once + +// Follows the game's conversation with a remote's extension (type, calibration, +// encryption key) so its data can be put at rest while the overlay owns input. + +#include "wiimote_ext_crypto.h" + +#include +#include +#include +#include +#include + +namespace Wiimote { + +class ExtensionState { +public: + void ObserveOutput(const uint8_t* report, size_t size); + void ObserveInput(const uint8_t* report, size_t size); + // Centres the sticks and releases the buttons of the extension data in a + // data report, leaving its motion data alone. + void Neutralize(std::vector& report) const; + +private: + enum class Type : uint8_t { Unknown, Nunchuk, Classic }; + + void Reset(); + uint8_t Calibration(size_t index, uint8_t fallback) const; + + Type m_type = Type::Unknown; + uint8_t m_format = 0; + bool m_encrypted = false; + std::array m_key{}; + std::optional m_tables; + std::array m_calibration{}; + bool m_haveCalibration = false; + uint32_t m_readAddress = 0; +}; + +} // namespace Wiimote diff --git a/runtime/include/wiimote_host.h b/runtime/include/wiimote_host.h new file mode 100644 index 0000000..1975252 --- /dev/null +++ b/runtime/include/wiimote_host.h @@ -0,0 +1,52 @@ +#pragma once + +// Physical Wii Remotes on the PC. Each one is attached to one of the four +// virtual remotes of the emulated Bluetooth controller and its HID reports are +// passed through unchanged, so the game's own WPAD/KPAD drive it (IR, speaker, +// rumble, extensions, battery). + +#include "bluetooth/bt_controller.h" + +#include +#include + +namespace Wiimote { + +struct SlotInfo { + bool attached = false; + // The game disconnected it and the platform could not power it off; any + // button wakes it up again. + bool asleep = false; + Bluetooth::LinkState link = Bluetooth::LinkState::Down; + std::string model; // "Wii Remote" / "Wii Remote Plus" + std::string extension; // empty when none + int battery = -1; // 0..4 like the game's battery bars, -1 unknown +}; + +struct PairingInfo { + bool supported = false; // this platform can discover and pair remotes itself + bool searching = false; + std::string status; // last pairing outcome, for the overlay +}; + +// Must run before SDL's joystick subsystem starts (aurora_initialize). +void ConfigureSdlHints(bool enabled); +// Starts device scanning when Wii Remotes are enabled. +void Initialize(); +// Powers the remotes off, like a console shutting down, and stops the threads. +void Shutdown(); + +Bluetooth::RemoteHost& Host(); + +SlotInfo Slot(size_t slot); +PairingInfo Pairing(); +// The console's SYNC button: look for remotes in pairing mode for a while. +void StartPairing(); +// Ends the game's connection to the remote on `slot` and powers it off. +void Disconnect(size_t slot); +// Setup problems worth showing (kernel driver, missing permissions), else empty. +std::string PlatformNotice(); +// Connected remotes waiting for a free player slot. +size_t WaitingRemotes(); + +} // namespace Wiimote diff --git a/runtime/include/wiimote_platform.h b/runtime/include/wiimote_platform.h new file mode 100644 index 0000000..5c89f9f --- /dev/null +++ b/runtime/include/wiimote_platform.h @@ -0,0 +1,43 @@ +#pragma once + +// Host Bluetooth services the Wii Remote manager needs from the OS: finding and +// pairing remotes in pairing mode, naming a HID device, and dropping a remote's +// connection (which powers it off, as a console does). + +#include +#include + +struct SDL_hid_device_info; + +namespace Wiimote::Platform { + +struct Capabilities { + bool pairing = false; + bool powerOff = false; +}; + +Capabilities Query(); + +// One search for remotes in pairing mode (red SYNC or 1+2); pairs and connects +// each one found. Blocks for a few seconds. Returns the number connected. +int DiscoverAndPair(const std::atomic& cancel, std::string& status); + +// Disconnects the remote; it switches itself off. False when not possible. +bool PowerOff(const std::string& address); + +// Bluetooth address of a HID device as 12 lowercase hex digits, or empty. +std::string AddressFor(const SDL_hid_device_info& info); + +// Bluetooth name ("Nintendo RVL-CNT-01-TR", ...) or the HID product string. +std::string NameFor(const std::string& address, const SDL_hid_device_info& info); + +// False only when the OS knows the remote is not connected right now. +bool MaybeConnected(const std::string& address); + +// False when the OS driver would fight over the device (Linux hid-wiimote). +bool Usable(const SDL_hid_device_info& info); + +// Setup problems worth showing in the overlay, else empty. +std::string Notice(); + +} // namespace Wiimote::Platform diff --git a/runtime/resources/RetroRewind.ico b/runtime/resources/RetroRewind.ico new file mode 100644 index 0000000000000000000000000000000000000000..e118f35140e5aca02f56ad875f8f7f7ceebc43fe GIT binary patch literal 51368 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 Y0?eRu`D^{sP5=M^07*qoM6N<$f~hC6{Qv*} literal 0 HcmV?d00001 diff --git a/runtime/resources/RetroRewind.rc b/runtime/resources/RetroRewind.rc new file mode 100644 index 0000000..9e1cd04 --- /dev/null +++ b/runtime/resources/RetroRewind.rc @@ -0,0 +1 @@ +1 ICON "RetroRewind.ico" diff --git a/runtime/resources/WiiCompiled.ico b/runtime/resources/WiiCompiled.ico new file mode 100644 index 0000000000000000000000000000000000000000..cede9d2080fe4fdcc364d16a4212faeb694c6453 GIT binary patch literal 110751 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 VSO(@fZLH~f%it&vVFlWUjY{pQK@G$>$ah5{6z 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 #include #include +#include "guest_function_imports.h" #include "guest_small_data.h" #include "runtime_log.h" @@ -425,6 +426,31 @@ const TranslatedFunctionInfo* TranslatedFunctionRegistry::FindByAddressPtrSlow(u return nullptr; } +GuestFunctions::Entry GuestFunctions::BaseTranslation(uint32_t address) { + std::unique_lock lock(RegistryMutex(), std::defer_lock); + if (!RegistryFrozen().load(std::memory_order_acquire)) { + lock.lock(); + } + for (const auto& entry : Registry()) { + if (entry.address == address && entry.kind == FunctionKind::BaseTranslated && entry.rawCpuInvoker) { + return entry.rawCpuInvoker; + } + } + if (lock.owns_lock()) { + lock.unlock(); + } + RT_LOG(RT_TAG_RUNTIME) << "ERROR: no base translation registered at 0x" << std::hex << address << std::dec + << std::endl; + std::ostringstream message; + message << "The runtime calls the translated function at guest address 0x" << std::hex << address + << ", but it was not translated."; + RuntimeCrash::WriteCrashArtifacts("missing_guest_function", message.str(), &address); + SetRuntimeExitCode(EXIT_FAILURE); + ShowRuntimeFatalPopup("Missing translated function", message.str()); + MarkFatalErrorReported(); + std::exit(EXIT_FAILURE); +} + const RawDispatchRecord* TranslatedFunctionRegistry::FindRawByAddressPtrSlow(uint32_t address) { if (!RegistryFrozen().load(std::memory_order_acquire)) { return nullptr; diff --git a/runtime/src/dynamic_aspect.cpp b/runtime/src/dynamic_aspect.cpp index 693f8a7..2646e0f 100644 --- a/runtime/src/dynamic_aspect.cpp +++ b/runtime/src/dynamic_aspect.cpp @@ -24,29 +24,29 @@ uint32_t g_lastEggWidth169 = 0; // EGG::Screen's static canvas records (PAL). See gx_dynamic_aspect.h for the // record layout and the anamorphic presentation model. -constexpr uint32_t kEggScreenRecord43 = 0x802A3EE8u; -constexpr uint32_t kEggScreenRecord169 = 0x802A3EF4u; -constexpr uint32_t kEggActiveScreenPtr = 0x80386F14u; +const uint32_t kEggScreenRecord43 = MKW_GADDR(802A3EE8); +const uint32_t kEggScreenRecord169 = MKW_GADDR(802A3EF4); +const uint32_t kEggActiveScreenPtr = MKW_GADDR(80386F14); -constexpr uint32_t kEggScreenProjScaleX = 0x80386F20u; -constexpr uint32_t kEggScreenProjScaleY = 0x80386F24u; +const uint32_t kEggScreenProjScaleX = MKW_GADDR(80386F20); +const uint32_t kEggScreenProjScaleY = MKW_GADDR(80386F24); -constexpr uint32_t kEggScreenAspectHandler = 0x8023E53Cu; +const uint32_t kEggScreenAspectHandler = MKW_GADDR(8023E53C); -constexpr uint32_t kMkwUpdateAllScreens = 0x805653D0u; -constexpr uint32_t kMkwGfxDrawList = 0x809C1830u; -constexpr uint32_t kSystemManagerInstance = 0x80386000u; +const uint32_t kMkwUpdateAllScreens = MKW_GADDR(805653D0); +const uint32_t kMkwGfxDrawList = MKW_GADDR(809C1830); +const uint32_t kSystemManagerInstance = MKW_GADDR(80386000); // The draw list is an nw4r::ut::List: +0x00 head, +0x04 tail, +0x08 u16 count, // +0x0A u16 link offset, with next = *(node + linkOffset + 4) (List_GetNext, // 0x800AF180). constexpr uint32_t kMkwGfxDrawListLinkOffset = 0x0Au; -constexpr uint32_t kMkwGfxOffscreenList = 0x809C183Cu; +const uint32_t kMkwGfxOffscreenList = MKW_GADDR(809C183C); constexpr uint32_t kMkwGfxOffscreenNodeScreenSlot = 0x10u; constexpr uint32_t kEggScreenVTableOffset = 0x38u; -constexpr uint32_t kEggScreenVTable = 0x802A3F0Cu; -constexpr uint32_t kMkwScreenVTable = 0x808B4C20u; +const uint32_t kEggScreenVTable = MKW_GADDR(802A3F0C); +const uint32_t kMkwScreenVTable = MKW_GADDR(808B4C20); constexpr uint32_t kEggScreenFlagsOffset = 0x34u; constexpr uint16_t kEggScreenFlagFramebufferCanvas = 0x0008u; constexpr uint16_t kEggScreenFlagKeepFrustumScale = 0x0040u; diff --git a/runtime/src/fiber_manager.cpp b/runtime/src/fiber_manager.cpp index 9eee67c..87fb7c5 100644 --- a/runtime/src/fiber_manager.cpp +++ b/runtime/src/fiber_manager.cpp @@ -46,10 +46,10 @@ std::atomic g_viRetracePendingCount{0}; namespace { constexpr uint32_t kOSCurrentContextAddr = 0x800000d4u; constexpr uint32_t kOSRunningContextAddr = 0x800000e4u; // OSGetCurrentThread reads this -constexpr uint32_t kThreadQueueArrayAddr = 0x803477b0u; -constexpr uint32_t kSchedulerPendingFlagAddr = 0x80386920u; -constexpr uint32_t kSchedulerReschedCounterAddr = 0x8038691cu; -constexpr uint32_t kSchedulerIdleFlagAddr = 0x80386918u; +const uint32_t kThreadQueueArrayAddr = MKW_GADDR(803477b0); +const uint32_t kSchedulerPendingFlagAddr = MKW_GADDR(80386920); +const uint32_t kSchedulerReschedCounterAddr = MKW_GADDR(8038691c); +const uint32_t kSchedulerIdleFlagAddr = MKW_GADDR(80386918); // OSThread structure offsets constexpr uint32_t kThreadStateOffset = 0x2C8u; @@ -584,7 +584,7 @@ void GuestFiberManager::FiberProc(void* param) CpuContextScope scope(cpu); int startDeferAttempts = 0; - while (entryPoint == 0x8024373c) { // EGG::Thread::start + while (entryPoint == MKW_GADDR(8024373c)) { // EGG::Thread::start uint32_t vtable = 0; uint32_t startFn = 0; try { diff --git a/runtime/src/friend_code_keyboard.cpp b/runtime/src/friend_code_keyboard.cpp new file mode 100644 index 0000000..a32b0bf --- /dev/null +++ b/runtime/src/friend_code_keyboard.cpp @@ -0,0 +1,168 @@ +#include "friend_code_keyboard.h" + +#include "abi_bridge.h" +#include "guest_abi/guest_region.h" +#include "guest_function_imports.h" +#include "input_bindings.h" +#include "memory.h" +#include "runtime_product.h" + +#include +#include + +#include +#include +#include +#include +#include + +namespace { + +// UI::RegisterFriendPage +constexpr uint32_t kDigitButtonsOffset = 0x44; +constexpr uint32_t kPushButtonSize = 0x254; +constexpr uint32_t kDigitButtonCount = 10; +constexpr uint32_t kButtonDigitOffset = 0x240; +constexpr uint32_t kPageStateOffset = 0x8; +constexpr uint32_t kPageStateActive = 4; +constexpr uint32_t kVtableGetTypeInfoOffset = 0x60; +constexpr int kBackspace = -1; +constexpr size_t kMaxPendingKeys = 32; +constexpr size_t kFriendCodeDigits = 12; + +std::mutex g_pendingMutex; +std::vector g_pending; +std::atomic_bool g_pageFocused{false}; + +bool IsPaste(const SDL_KeyboardEvent& key) { + return !key.repeat && key.key == SDLK_V && (key.mod & (SDL_KMOD_CTRL | SDL_KMOD_GUI)) != 0 && + (key.mod & SDL_KMOD_ALT) == 0; +} + +void AppendClipboardDigits(std::vector& keys) { + char* text = SDL_GetClipboardText(); + if (!text) { + return; + } + size_t digits = 0; + for (const char* c = text; *c && digits < kFriendCodeDigits; ++c) { + if (*c >= '0' && *c <= '9') { + keys.push_back(*c - '0'); + ++digits; + } + } + SDL_free(text); +} + +std::optional KeyValue(const SDL_KeyboardEvent& key) { + if ((key.mod & (SDL_KMOD_CTRL | SDL_KMOD_ALT | SDL_KMOD_GUI)) != 0) { + return std::nullopt; + } + if (key.scancode == SDL_SCANCODE_BACKSPACE) { + return kBackspace; + } + if (key.repeat) { + return std::nullopt; + } + if (key.scancode == SDL_SCANCODE_0 || key.scancode == SDL_SCANCODE_KP_0) { + return 0; + } + if (key.scancode >= SDL_SCANCODE_1 && key.scancode <= SDL_SCANCODE_9) { + return 1 + (key.scancode - SDL_SCANCODE_1); + } + if (key.scancode >= SDL_SCANCODE_KP_1 && key.scancode <= SDL_SCANCODE_KP_9) { + return 1 + (key.scancode - SDL_SCANCODE_KP_1); + } + return std::nullopt; +} + +bool IsFocusedRegisterFriendPage(uint32_t page) { + try { + const uint32_t vtable = Memory::Read32(page); + return Memory::Read32(vtable + kVtableGetTypeInfoOffset) == MKW_GADDR(8061E804) && + Memory::Read32(page + kPageStateOffset) == kPageStateActive; + } catch (const Memory::AccessViolation&) { + return false; + } +} + +std::optional DigitButton(uint32_t page, int digit) { + for (uint32_t i = 0; i < kDigitButtonCount; ++i) { + const uint32_t button = page + kDigitButtonsOffset + i * kPushButtonSize; + if (static_cast(Memory::Read32(button + kButtonDigitOffset)) == digit) { + return button; + } + } + return std::nullopt; +} + +void Type(CpuContext* ctx, uint32_t page, int key) { + if (key == kBackspace) { + ctx->gpr[3] = page; + MKW_GUEST_FUNC(8061E3B4)(ctx); + return; + } + const std::optional button = DigitButton(page, key); + if (!button) { + return; + } + ctx->gpr[3] = page; + ctx->gpr[4] = *button; + ctx->gpr[5] = 0; + MKW_GUEST_FUNC(8061E348)(ctx); +} + +} // namespace + +namespace FriendCodeKeyboard { + +void HandleEvents(const AuroraEvent* events) noexcept { + if (!events || !g_pageFocused.load(std::memory_order_acquire) || InputBindings::InputBlocked()) { + return; + } + std::vector keys; + for (const AuroraEvent* ev = events; ev->type != AURORA_NONE; ++ev) { + if (ev->type != AURORA_SDL_EVENT || ev->sdl.type != SDL_EVENT_KEY_DOWN) { + continue; + } + if (IsPaste(ev->sdl.key)) { + AppendClipboardDigits(keys); + } else if (const std::optional key = KeyValue(ev->sdl.key)) { + keys.push_back(*key); + } + } + if (keys.empty()) { + return; + } + std::lock_guard lock(g_pendingMutex); + for (const int key : keys) { + if (g_pending.size() >= kMaxPendingKeys) { + break; + } + g_pending.push_back(key); + } +} + +} // namespace FriendCodeKeyboard + +// Page::CheckActions, only ever called for the topmost page. +extern "C" void Page_CheckActions_80601c64(CpuContext* ctx) { + const uint32_t page = ctx->gpr[3]; + MKW_GUEST_FUNC(80601C64)(ctx); + + const bool focused = RuntimeProduct::IsRetroRewind() && IsFocusedRegisterFriendPage(page); + g_pageFocused.store(focused, std::memory_order_release); + std::vector keys; + { + std::lock_guard lock(g_pendingMutex); + keys.swap(g_pending); + } + if (!focused || InputBindings::InputBlocked()) { + return; + } + for (const int key : keys) { + Type(ctx, page, key); + } +} + +REGISTER_NATIVE_FUNCTION_AS(0x80601C64, Page_CheckActions_80601c64, "Page_CheckActions_80601c64"); diff --git a/runtime/src/guest_region.cpp b/runtime/src/guest_region.cpp new file mode 100644 index 0000000..66fb1ae --- /dev/null +++ b/runtime/src/guest_region.cpp @@ -0,0 +1,15 @@ +#include "guest_abi/guest_region.h" + +#include +#include + +namespace GuestRegion { + +void FatalUnknownAddress(uint32_t pal) noexcept { + std::fprintf(stderr, "Guest region: PAL address 0x%08X has no %s address in guest_versions.inc\n", + pal, CurrentFacts().gameId); + std::fflush(stderr); + std::abort(); +} + +} // namespace GuestRegion diff --git a/runtime/src/hle/audio/audio.cpp b/runtime/src/hle/audio/audio.cpp index 1be5008..fd19215 100644 --- a/runtime/src/hle/audio/audio.cpp +++ b/runtime/src/hle/audio/audio.cpp @@ -21,14 +21,16 @@ namespace { constexpr uint32_t kDefaultSampleRate = 32000u; constexpr uint32_t kAudioChannels = 2u; constexpr uint32_t kBytesPerSample = 2u; -constexpr uint32_t kAIInitializedAddr = 0x80386448u; -constexpr uint32_t kAICallbackBusyAddr = 0x8038644Cu; -constexpr uint32_t kAICallbackStackSwitchAddr = 0x8038647Cu; -constexpr uint32_t kAIDmaCallbackAddr = 0x80386480u; +const uint32_t kAIInitializedAddr = MKW_GADDR(80386448); +const uint32_t kAICallbackBusyAddr = MKW_GADDR(8038644C); +const uint32_t kAICallbackStackSwitchAddr = MKW_GADDR(8038647C); +const uint32_t kAIDmaCallbackAddr = MKW_GADDR(80386480); // Max completed 3 ms DMA blocks delivered per tick. Draining several at once catches up // backlog from a long frame without letting a large stall spiral into an unbounded loop. constexpr int kMaxBlocksPerTick = 4; +// Backlog (in blocks) tolerated before a catch-up block waits on an in-flight mix. +constexpr double kMaxDeferredBlocks = 2.0; struct AIDmaState { std::mutex mutex; @@ -407,11 +409,15 @@ void Audio_HLE_Tick(CpuContext* ctx, uint32_t deltaMicros) int blocksCompleted = 0; while (true) { + // A block due while the previous mix is still running would block on it; leave it for the + // next service point unless the backlog is getting long. + const bool deferWhileMixing = AxDspHle::MixWorkerBusy(); // Claim the block in one critical section; sample-then-consume separately gains // nothing since the callback below (the only reentrancy point) runs mutex-released. { std::lock_guard lock(g_ai.mutex); - if (g_ai.accumulatorSeconds < blockDuration) { + if (g_ai.accumulatorSeconds < blockDuration || + (deferWhileMixing && g_ai.accumulatorSeconds < blockDuration * kMaxDeferredBlocks)) { break; } g_ai.accumulatorSeconds -= blockDuration; diff --git a/runtime/src/hle/audio/ax_dsp.h b/runtime/src/hle/audio/ax_dsp.h index 8c5f169..1889621 100644 --- a/runtime/src/hle/audio/ax_dsp.h +++ b/runtime/src/hle/audio/ax_dsp.h @@ -25,6 +25,9 @@ void ServiceDeferredCallbacks(); // Cheap when the mix already finished (the normal case). void JoinMixWorker(); +// True while a deferred mix is queued or still running. +bool MixWorkerBusy(); + // Joins and tears down the mix worker thread. Call before the guest memory map // is destroyed or re-created. void ShutdownMixWorker(); diff --git a/runtime/src/hle/audio/ax_effects.cpp b/runtime/src/hle/audio/ax_effects.cpp index a30a4ac..ade28b5 100644 --- a/runtime/src/hle/audio/ax_effects.cpp +++ b/runtime/src/hle/audio/ax_effects.cpp @@ -3,6 +3,7 @@ #include "hle_stubs.h" #include "memory.h" #include "ppc_runtime.h" +#include "guest_function_imports.h" #include #include @@ -10,8 +11,6 @@ #include -extern "C" void func_8012B830(CpuContext* ctx); - #if defined(__clang__) // PowerPC uses discrete fmuls/fadds; a fused multiply-add would change sample rounding. #pragma clang fp contract(off) @@ -24,8 +23,8 @@ constexpr uint32_t kSamplesPerFrame = 96; constexpr uint32_t kChannels = 3; // .sdata2 constants the guest function loads through r2. -constexpr uint32_t kOneConstantAddr = 0x80388588u; // 1.0f -constexpr uint32_t kScaleConstantAddr = 0x8038858Cu; // 0.6f send pre-scale +const uint32_t kOneConstantAddr = MKW_GADDR(80388588); // 1.0f +const uint32_t kScaleConstantAddr = MKW_GADDR(8038858C); // 0.6f send pre-scale // AXFX_REVERBSTD_EXP field offsets (byte offsets into the struct in r4). constexpr uint32_t kFieldPreDelayCoef = 0x18; @@ -346,7 +345,7 @@ extern "C" void AXFXReverbStdExpCallback_8012b830(CpuContext* ctx) { try { flags = Memory::Read32(stateAddr + ReverbStd::kFieldFlags); } catch (const Memory::AccessViolation&) { - func_8012B830(ctx); + MKW_GUEST_FUNC(8012B830)(ctx); return; } if (flags != 0) { @@ -364,7 +363,7 @@ extern "C" void AXFXReverbStdExpCallback_8012b830(CpuContext* ctx) { built = false; } if (!built) { - func_8012B830(ctx); + MKW_GUEST_FUNC(8012B830)(ctx); return; } diff --git a/runtime/src/hle/audio/ax_internal.h b/runtime/src/hle/audio/ax_internal.h index 734d9ee..ab1ac55 100644 --- a/runtime/src/hle/audio/ax_internal.h +++ b/runtime/src/hle/audio/ax_internal.h @@ -4,6 +4,7 @@ // Hot accessors stay header-inline because the shipped build links runtime shards without LTO. #include "isa/big_endian.h" +#include "guest_abi/guest_region.h" #include "memory.h" #include @@ -31,21 +32,21 @@ constexpr uint32_t kMailReset = kTaskMailToDsp | 0x0002u; constexpr size_t kResamplingCoefficientCount = 0x800; constexpr uint32_t kMailContinue = kTaskMailToDsp | 0x0003u; constexpr uint32_t kAxSamplesPerFrame = 96u; -constexpr uint32_t kAxDspTaskAddr = 0x802F81A0u; -constexpr uint32_t kDspInitializedAddr = 0x80386608u; -constexpr uint32_t kDspAssertPendingAddr = 0x80386610u; -constexpr uint32_t kDspAssertTaskAddr = 0x80386614u; -constexpr uint32_t kDspCurrentTaskAddr = 0x8038661Cu; -constexpr uint32_t kDspFirstTaskAddr = 0x80386620u; -constexpr uint32_t kDspRunningTaskAddr = 0x80386624u; -constexpr uint32_t kAxIramMmemAddr = 0x8027F820u; -constexpr uint32_t kAxDramMmemAddr = 0x802F8200u; +const uint32_t kAxDspTaskAddr = MKW_GADDR(802F81A0); +const uint32_t kDspInitializedAddr = MKW_GADDR(80386608); +const uint32_t kDspAssertPendingAddr = MKW_GADDR(80386610); +const uint32_t kDspAssertTaskAddr = MKW_GADDR(80386614); +const uint32_t kDspCurrentTaskAddr = MKW_GADDR(8038661C); +const uint32_t kDspFirstTaskAddr = MKW_GADDR(80386620); +const uint32_t kDspRunningTaskAddr = MKW_GADDR(80386624); +const uint32_t kAxIramMmemAddr = MKW_GADDR(8027F820); +const uint32_t kAxDramMmemAddr = MKW_GADDR(802F8200); constexpr uint32_t kAxDramLength = 64u; constexpr uint32_t kAxDramDspAddr = 3282u; -constexpr uint32_t kAxInitCallback = 0x80126948u; -constexpr uint32_t kAxResumeCallback = 0x80126954u; -constexpr uint32_t kAxDoneCallback = 0x801269A8u; -constexpr uint32_t kAxRequestCallback = 0x801269B8u; +const uint32_t kAxInitCallback = MKW_GADDR(80126948); +const uint32_t kAxResumeCallback = MKW_GADDR(80126954); +const uint32_t kAxDoneCallback = MKW_GADDR(801269A8); +const uint32_t kAxRequestCallback = MKW_GADDR(801269B8); extern uint32_t g_axTaskPtr; diff --git a/runtime/src/hle/audio/ax_memory.cpp b/runtime/src/hle/audio/ax_memory.cpp index 588e525..4ac3358 100644 --- a/runtime/src/hle/audio/ax_memory.cpp +++ b/runtime/src/hle/audio/ax_memory.cpp @@ -68,7 +68,7 @@ void MarkDspInitialized() { void ResetDspTaskGlobals() { Memory::TryWrite32(kDspAssertPendingAddr, 0); Memory::TryWrite32(kDspAssertTaskAddr, 0); - Memory::TryWrite32(0x80386618u, 0); + Memory::TryWrite32(MKW_GADDR(80386618), 0); Memory::TryWrite32(kDspCurrentTaskAddr, 0); Memory::TryWrite32(kDspFirstTaskAddr, 0); Memory::TryWrite32(kDspRunningTaskAddr, 0); diff --git a/runtime/src/hle/audio/ax_mix.cpp b/runtime/src/hle/audio/ax_mix.cpp index ba225e6..c110c6c 100644 --- a/runtime/src/hle/audio/ax_mix.cpp +++ b/runtime/src/hle/audio/ax_mix.cpp @@ -112,6 +112,14 @@ public: ConfigureFromTaskLocked(taskPtr); } + bool MixBusy() { + if (!m_mixThread.joinable()) { + return false; + } + std::lock_guard lock(m_mixMutex); + return m_mixPending || m_mixBusy; + } + void JoinMix() { if (m_mixThread.joinable()) { std::unique_lock lock(m_mixMutex); @@ -1467,19 +1475,15 @@ void InitForAXOut(CpuContext* ctx) { Memory::Write32(g_axTaskPtr + 0x2cu, kAxResumeCallback); Memory::Write32(g_axTaskPtr + 0x30u, kAxDoneCallback); Memory::Write32(g_axTaskPtr + 0x34u, kAxRequestCallback); - if (ctx) { - const uint32_t r13 = ctx->gpr[13]; - Memory::Write32(g_axTaskPtr + 0x10u, Memory::Read16(r13 - 0x73fcu)); - Memory::Write16(g_axTaskPtr + 0x24u, Memory::Read16(r13 - 0x7400u)); - Memory::Write16(g_axTaskPtr + 0x26u, Memory::Read16(r13 - 0x73feu)); - } + // __AXOutInitDSP's ucode length and DSP init/resume vectors, then its two flags. + (void)ctx; + Memory::Write32(g_axTaskPtr + 0x10u, Memory::Read16(MKW_GADDR(80385804))); + Memory::Write16(g_axTaskPtr + 0x24u, Memory::Read16(MKW_GADDR(80385800))); + Memory::Write16(g_axTaskPtr + 0x26u, Memory::Read16(MKW_GADDR(80385802))); Instance().ConfigureFromTask(g_axTaskPtr); LinkSingleDspTask(g_axTaskPtr); - if (ctx) { - const uint32_t r13 = ctx->gpr[13]; - Memory::Write32(r13 - 0x66d8u, 1); - Memory::Write32(r13 - 0x66dcu, 0); - } + Memory::Write32(MKW_GADDR(80386528), 1); + Memory::Write32(MKW_GADDR(80386524), 0); } void Stop() { @@ -1560,6 +1564,10 @@ void JoinMixWorker() { Instance().JoinMix(); } +bool MixWorkerBusy() { + return Instance().MixBusy(); +} + void ShutdownMixWorker() { Instance().ShutdownMixWorker(); } diff --git a/runtime/src/hle/bluetooth/bt_controller.cpp b/runtime/src/hle/bluetooth/bt_controller.cpp new file mode 100644 index 0000000..923aa00 --- /dev/null +++ b/runtime/src/hle/bluetooth/bt_controller.cpp @@ -0,0 +1,951 @@ +#include "bluetooth/bt_controller.h" + +#include "bluetooth/bt_bytes.h" +#include "bluetooth/bt_remote_link.h" + +#include +#include +#include + +namespace Bluetooth { +namespace HciDetail { + + +constexpr uint16_t kOgfLinkControl = 0x01; +constexpr uint16_t kOgfLinkPolicy = 0x02; +constexpr uint16_t kOgfControllerBaseband = 0x03; +constexpr uint16_t kOgfInformational = 0x04; +constexpr uint16_t kOgfStatus = 0x05; +constexpr uint16_t kOgfVendor = 0x3F; + +constexpr uint8_t kEventInquiryComplete = 0x01; +constexpr uint8_t kEventInquiryResult = 0x02; +constexpr uint8_t kEventConnectionComplete = 0x03; +constexpr uint8_t kEventDisconnectionComplete = 0x05; +constexpr uint8_t kEventAuthenticationComplete = 0x06; +constexpr uint8_t kEventRemoteNameComplete = 0x07; +constexpr uint8_t kEventEncryptionChange = 0x08; +constexpr uint8_t kEventRemoteFeatures = 0x0B; +constexpr uint8_t kEventRemoteVersion = 0x0C; +constexpr uint8_t kEventCommandComplete = 0x0E; +constexpr uint8_t kEventCommandStatus = 0x0F; +constexpr uint8_t kEventRoleChange = 0x12; +constexpr uint8_t kEventNumberOfCompletedPackets = 0x13; +constexpr uint8_t kEventModeChange = 0x14; +constexpr uint8_t kEventReturnLinkKeys = 0x15; +constexpr uint8_t kEventPinCodeRequest = 0x16; +constexpr uint8_t kEventLinkKeyRequest = 0x17; +constexpr uint8_t kEventLinkKeyNotification = 0x18; +constexpr uint8_t kEventClockOffset = 0x1C; +constexpr uint8_t kEventPacketTypeChanged = 0x1D; +constexpr uint8_t kEventInquiryResultWithRssi = 0x22; +constexpr uint8_t kEventExtendedInquiryResult = 0x2F; + +constexpr uint8_t kStatusSuccess = 0x00; +constexpr uint8_t kStatusUnknownCommand = 0x01; +constexpr uint8_t kStatusUnknownConnection = 0x02; +constexpr uint8_t kStatusPageTimeout = 0x04; +constexpr uint8_t kStatusAuthenticationFailure = 0x05; +constexpr uint8_t kStatusKeyMissing = 0x06; +constexpr uint8_t kStatusUnsupportedFeature = 0x11; +constexpr uint8_t kReasonLocalHostTerminated = 0x16; + +// What a Wii's BCM2045 reports (the version makes WUD apply its usual patch). +constexpr BdAddr kLocalAddress = {0x11, 0x02, 0x19, 0x79, 0x00, 0xFF}; +constexpr std::array kLocalFeatures = {0xFF, 0xFF, 0x8D, 0xFE, 0x9B, 0xF9, 0x00, 0x80}; +// Never advertise more than 10 ACL buffers: the stack keeps the count in a u8. +constexpr uint16_t kAclBufferSize = 339; +constexpr uint16_t kAclBufferCount = 10; +constexpr uint8_t kScoBufferSize = 64; + +// A real RVL-CNT-01. +constexpr std::array kRemoteFeatures = {0xBC, 0x02, 0x04, 0x38, 0x08, 0x00, 0x00, 0x00}; +constexpr uint8_t kRemoteLmpVersion = 0x02; +constexpr uint16_t kRemoteManufacturer = 0x000F; +constexpr uint16_t kRemoteLmpSubversion = 0x0229; +constexpr uint16_t kRemoteClockOffset = 0x3818; +constexpr uint8_t kInquiryRssi = 0xD8; // -40 dBm +constexpr uint64_t kInquiryUnitUs = 1'280'000; +constexpr uint16_t kMaxStoredKeys = 0x00FF; +constexpr uint8_t kKeysPerEvent = 11; + +void PutAddr(std::vector& out, const BdAddr& addr) { + out.insert(out.end(), addr.begin(), addr.end()); +} + +BdAddr ReadAddr(const uint8_t* p) { + BdAddr addr{}; + std::memcpy(addr.data(), p, addr.size()); + return addr; +} + +std::vector Event(uint8_t code, const std::vector& params) { + std::vector event; + event.reserve(2 + params.size()); + event.push_back(code); + event.push_back(static_cast(params.size())); + event.insert(event.end(), params.begin(), params.end()); + return event; +} + +std::array SlotLinkKey(size_t slot) { + std::array key{}; + for (size_t i = 0; i < key.size(); ++i) { + key[i] = static_cast(0xA0 + slot + i * 0x11); + } + return key; +} + +} // namespace HciDetail + +using namespace HciDetail; + +Controller::Controller(RemoteHost& host) : m_host(host) { + for (size_t slot = 0; slot < kRemoteSlots; ++slot) { + m_links[slot] = std::make_unique(*this, slot); + m_storedKeys.push_back({RemoteAddress(slot), SlotLinkKey(slot)}); + } + ResetState(true); +} + +Controller::~Controller() = default; + +BdAddr Controller::LocalAddress() { + return kLocalAddress; +} + +BdAddr Controller::RemoteAddress(size_t slot) { + return {0x11, 0x02, 0x19, 0x79, 0x00, static_cast(slot)}; +} + +uint16_t Controller::ConnectionHandle(size_t slot) { + return static_cast(0x0100 + slot); +} + +void Controller::Open(uint64_t nowUs) { + (void)nowUs; + ResetState(true); + m_open = true; +} + +void Controller::Close() { + ResetState(true); + m_open = false; +} + +void Controller::ResetState(bool keepStoredKeys) { + for (size_t slot = 0; slot < kRemoteSlots; ++slot) { + RemoteLink& link = *m_links[slot]; + // A reset drops the radio links: the remotes lose their connection. + if (link.State() == LinkState::Ready) { + m_host.OnGuestDisconnect(slot); + } + link.Reset(); + } + if (!keepStoredKeys) { + m_storedKeys.clear(); + } + if (m_hostInquiryNotified) { + m_host.OnGuestInquiry(false); + m_hostInquiryNotified = false; + } + m_inquiry = {}; + m_scanEnable = 0; + m_pageTimeoutSlots = 0x2000; + m_inquiryMode = 0; + m_classOfDevice = {}; + m_localName = {}; + m_completedPackets = {}; + for (Reassembly& r : m_reassembly) r = {}; + m_events.clear(); + m_acl.clear(); + m_pending.clear(); + m_authPending = {}; +} + +LinkState Controller::SlotLinkState(size_t slot) const { + return slot < kRemoteSlots ? m_links[slot]->State() : LinkState::Down; +} + +int Controller::SlotForAddress(const BdAddr& addr) const { + for (size_t slot = 0; slot < kRemoteSlots; ++slot) { + if (RemoteAddress(slot) == addr) return static_cast(slot); + } + return -1; +} + +int Controller::SlotForHandle(uint16_t handle) const { + for (size_t slot = 0; slot < kRemoteSlots; ++slot) { + if (ConnectionHandle(slot) == (handle & 0x0FFF) && + m_links[slot]->BasebandState() == RemoteLink::Baseband::Connected) { + return static_cast(slot); + } + } + return -1; +} + +const Controller::StoredKey* Controller::FindStoredKey(const BdAddr& addr) const { + for (const StoredKey& key : m_storedKeys) { + if (key.addr == addr) return &key; + } + return nullptr; +} + +void Controller::QueueEvent(std::vector event) { + m_events.push_back(std::move(event)); +} + +void Controller::QueueAcl(uint16_t handle, const std::vector& l2capFrame) { + std::vector packet; + packet.reserve(4 + l2capFrame.size()); + // Packet boundary 0x2: first (and only) fragment, automatically flushable. + PutLe16(packet, static_cast((handle & 0x0FFF) | 0x2000)); + PutLe16(packet, static_cast(l2capFrame.size())); + packet.insert(packet.end(), l2capFrame.begin(), l2capFrame.end()); + m_acl.push_back(std::move(packet)); +} + +bool Controller::PopEvent(std::vector& event) { + if (m_events.empty()) return false; + event = std::move(m_events.front()); + m_events.pop_front(); + return true; +} + +bool Controller::PopAcl(std::vector& packet) { + if (!m_events.empty() || m_acl.empty()) return false; + packet = std::move(m_acl.front()); + m_acl.pop_front(); + return true; +} + +void Controller::CommandComplete(uint16_t opcode, const std::vector& params) { + std::vector body = {0x01}; + PutLe16(body, opcode); + body.insert(body.end(), params.begin(), params.end()); + QueueEvent(Event(kEventCommandComplete, body)); +} + +void Controller::CommandStatus(uint16_t opcode, uint8_t status) { + std::vector body = {status, 0x01}; + PutLe16(body, opcode); + QueueEvent(Event(kEventCommandStatus, body)); +} + +void Controller::UnknownCommand(uint16_t opcode) { + std::cerr << "[bluetooth] unsupported HCI command 0x" << std::hex << opcode << std::dec << std::endl; + CommandStatus(opcode, kStatusUnknownCommand); +} + +void Controller::ExecuteCommand(const uint8_t* packet, size_t size, uint64_t nowUs) { + if (size < 3) return; + const uint16_t opcode = Le16(packet); + const size_t length = packet[2]; + if (3 + length > size) { + std::cerr << "[bluetooth] truncated HCI command 0x" << std::hex << opcode << std::dec << std::endl; + return; + } + const uint8_t* p = packet + 3; + switch (opcode >> 10) { + case kOgfLinkControl: HandleLinkControl(opcode, p, length, nowUs); break; + case kOgfLinkPolicy: HandleLinkPolicy(opcode, p, length); break; + case kOgfControllerBaseband: HandleControllerBaseband(opcode, p, length, nowUs); break; + case kOgfInformational: HandleInformational(opcode, p, length); break; + case kOgfStatus: HandleStatusParameters(opcode, p, length); break; + case kOgfVendor: HandleVendor(opcode, p, length); break; + default: UnknownCommand(opcode); break; + } +} + +void Controller::HandleLinkControl(uint16_t opcode, const uint8_t* p, size_t n, uint64_t nowUs) { + const auto handleSlot = [&](size_t offset) { return n >= offset + 2 ? SlotForHandle(Le16(p + offset)) : -1; }; + switch (opcode & 0x3FF) { + case 0x0001: { // Inquiry + if (n < 5) break; + CommandStatus(opcode, kStatusSuccess); + m_inquiry = {}; + m_inquiry.active = true; + m_inquiry.endUs = nowUs + std::max(p[3], 1) * kInquiryUnitUs; + m_inquiry.maxResponses = p[4]; + if (!m_hostInquiryNotified) { + m_host.OnGuestInquiry(true); + m_hostInquiryNotified = true; + } + return; + } + case 0x0002: // Inquiry Cancel + m_inquiry = {}; + if (m_hostInquiryNotified) { + m_host.OnGuestInquiry(false); + m_hostInquiryNotified = false; + } + CommandComplete(opcode, {kStatusSuccess}); + return; + case 0x0003: // Periodic Inquiry Mode + case 0x0004: // Exit Periodic Inquiry Mode + CommandComplete(opcode, {kStatusUnsupportedFeature}); + return; + case 0x0005: { // Create Connection + if (n < 6) break; + const BdAddr addr = ReadAddr(p); + CommandStatus(opcode, kStatusSuccess); + const int slot = SlotForAddress(addr); + if (slot >= 0 && m_links[slot]->OnPaged(nowUs)) { + std::vector body = {kStatusSuccess}; + PutLe16(body, ConnectionHandle(slot)); + PutAddr(body, addr); + body.insert(body.end(), {0x01, 0x00}); + QueueEvent(Event(kEventConnectionComplete, body)); + } else { + std::vector body = {kStatusPageTimeout, 0x00, 0x00}; + PutAddr(body, addr); + body.insert(body.end(), {0x01, 0x00}); + m_pending.push_back({nowUs + PageTimeoutUs(), Event(kEventConnectionComplete, body)}); + } + return; + } + case 0x0006: { // Disconnect + const int slot = handleSlot(0); + if (slot < 0 || n < 3) { + CommandStatus(opcode, kStatusUnknownConnection); + return; + } + CommandStatus(opcode, kStatusSuccess); + std::vector body = {kStatusSuccess}; + PutLe16(body, ConnectionHandle(slot)); + body.push_back(kReasonLocalHostTerminated); + QueueEvent(Event(kEventDisconnectionComplete, body)); + m_completedPackets[slot] = 0; + m_reassembly[slot] = {}; + m_authPending[slot] = false; + m_links[slot]->OnDisconnected(true, nowUs); + return; + } + case 0x0008: { // Create Connection Cancel + if (n < 6) break; + const BdAddr addr = ReadAddr(p); + auto it = std::find_if(m_pending.begin(), m_pending.end(), [&](const PendingEvent& e) { + return e.event[0] == kEventConnectionComplete && ReadAddr(&e.event[5]) == addr; + }); + std::vector body = {static_cast(it == m_pending.end() ? kStatusUnknownConnection + : kStatusSuccess)}; + PutAddr(body, addr); + CommandComplete(opcode, body); + if (it != m_pending.end()) { + std::vector complete = it->event; + complete[2] = kStatusUnknownConnection; + m_pending.erase(it); + QueueEvent(std::move(complete)); + } + return; + } + case 0x0009: { // Accept Connection Request + if (n < 7) break; + const BdAddr addr = ReadAddr(p); + const uint8_t role = p[6]; + const int slot = SlotForAddress(addr); + if (slot < 0 || !m_links[slot]->IsRequesting()) { + CommandStatus(opcode, kStatusUnknownConnection); + return; + } + CommandStatus(opcode, kStatusSuccess); + if (role == 0x00) { + std::vector change = {kStatusSuccess}; + PutAddr(change, addr); + change.push_back(0x00); + QueueEvent(Event(kEventRoleChange, change)); + } + std::vector body = {kStatusSuccess}; + PutLe16(body, ConnectionHandle(slot)); + PutAddr(body, addr); + body.insert(body.end(), {0x01, 0x00}); + QueueEvent(Event(kEventConnectionComplete, body)); + m_completedPackets[slot] = 0; + m_reassembly[slot] = {}; + m_links[slot]->OnAccepted(role); + return; + } + case 0x000A: { // Reject Connection Request + if (n < 7) break; + const BdAddr addr = ReadAddr(p); + const int slot = SlotForAddress(addr); + if (slot < 0 || !m_links[slot]->IsRequesting()) { + CommandStatus(opcode, kStatusUnknownConnection); + return; + } + CommandStatus(opcode, kStatusSuccess); + std::vector body = {p[6], 0x00, 0x00}; + PutAddr(body, addr); + body.insert(body.end(), {0x01, 0x00}); + QueueEvent(Event(kEventConnectionComplete, body)); + m_links[slot]->OnRejected(p[6], nowUs); + return; + } + case 0x000B: { // Link Key Request Reply + if (n < 22) break; + const BdAddr addr = ReadAddr(p); + std::vector body = {kStatusSuccess}; + PutAddr(body, addr); + CommandComplete(opcode, body); + const int slot = SlotForAddress(addr); + if (slot >= 0 && m_authPending[slot]) { + m_authPending[slot] = false; + const bool match = std::equal(p + 6, p + 22, SlotLinkKey(slot).begin()); + std::vector auth = {static_cast(match ? kStatusSuccess : kStatusKeyMissing)}; + PutLe16(auth, ConnectionHandle(slot)); + QueueEvent(Event(kEventAuthenticationComplete, auth)); + } + return; + } + case 0x000C: { // Link Key Request Negative Reply + if (n < 6) break; + const BdAddr addr = ReadAddr(p); + std::vector body = {kStatusSuccess}; + PutAddr(body, addr); + CommandComplete(opcode, body); + const int slot = SlotForAddress(addr); + if (slot >= 0 && m_authPending[slot]) { + std::vector request; + PutAddr(request, addr); + QueueEvent(Event(kEventPinCodeRequest, request)); + } + return; + } + case 0x000D: { // PIN Code Request Reply + if (n < 23) break; + const BdAddr addr = ReadAddr(p); + std::vector body = {kStatusSuccess}; + PutAddr(body, addr); + CommandComplete(opcode, body); + const int slot = SlotForAddress(addr); + if (slot < 0 || !m_authPending[slot]) return; + m_authPending[slot] = false; + // A remote takes the host's address (SYNC button) or its own (1+2) as PIN. + const uint8_t pinLength = p[6]; + const uint8_t* pin = p + 7; + const BdAddr local = LocalAddress(); + const bool valid = pinLength == 6 && (std::equal(pin, pin + 6, local.begin()) || + std::equal(pin, pin + 6, addr.begin())); + if (valid) { + std::vector notification; + PutAddr(notification, addr); + const auto key = SlotLinkKey(slot); + notification.insert(notification.end(), key.begin(), key.end()); + notification.push_back(0x00); // combination key + QueueEvent(Event(kEventLinkKeyNotification, notification)); + } + std::vector auth = {static_cast(valid ? kStatusSuccess : kStatusAuthenticationFailure)}; + PutLe16(auth, ConnectionHandle(slot)); + QueueEvent(Event(kEventAuthenticationComplete, auth)); + return; + } + case 0x000E: { // PIN Code Request Negative Reply + if (n < 6) break; + const BdAddr addr = ReadAddr(p); + std::vector body = {kStatusSuccess}; + PutAddr(body, addr); + CommandComplete(opcode, body); + const int slot = SlotForAddress(addr); + if (slot >= 0 && m_authPending[slot]) { + m_authPending[slot] = false; + std::vector auth = {kStatusKeyMissing}; + PutLe16(auth, ConnectionHandle(slot)); + QueueEvent(Event(kEventAuthenticationComplete, auth)); + } + return; + } + case 0x000F: { // Change Connection Packet Type + const int slot = handleSlot(0); + if (slot < 0 || n < 4) { + CommandStatus(opcode, kStatusUnknownConnection); + return; + } + CommandStatus(opcode, kStatusSuccess); + std::vector body = {kStatusSuccess}; + PutLe16(body, ConnectionHandle(slot)); + PutLe16(body, Le16(p + 2)); + QueueEvent(Event(kEventPacketTypeChanged, body)); + return; + } + case 0x0011: { // Authentication Requested + const int slot = handleSlot(0); + if (slot < 0) { + CommandStatus(opcode, kStatusUnknownConnection); + return; + } + CommandStatus(opcode, kStatusSuccess); + m_authPending[slot] = true; + std::vector request; + PutAddr(request, RemoteAddress(slot)); + QueueEvent(Event(kEventLinkKeyRequest, request)); + return; + } + case 0x0013: { // Set Connection Encryption + const int slot = handleSlot(0); + if (slot < 0 || n < 3) { + CommandStatus(opcode, kStatusUnknownConnection); + return; + } + CommandStatus(opcode, kStatusSuccess); + std::vector body = {kStatusSuccess}; + PutLe16(body, ConnectionHandle(slot)); + body.push_back(p[2]); + QueueEvent(Event(kEventEncryptionChange, body)); + return; + } + case 0x0019: { // Remote Name Request + if (n < 6) break; + const BdAddr addr = ReadAddr(p); + CommandStatus(opcode, kStatusSuccess); + const int slot = SlotForAddress(addr); + const bool reachable = slot >= 0 && (m_links[slot]->BasebandState() == RemoteLink::Baseband::Connected || + m_links[slot]->Discoverable()); + std::vector body = {static_cast(reachable ? kStatusSuccess : kStatusPageTimeout)}; + PutAddr(body, addr); + std::array name{}; + if (reachable) { + std::strncpy(name.data(), m_host.DeviceName(slot), name.size() - 1); + } + body.insert(body.end(), name.begin(), name.end()); + if (reachable) { + QueueEvent(Event(kEventRemoteNameComplete, body)); + } else { + m_pending.push_back({nowUs + PageTimeoutUs(), Event(kEventRemoteNameComplete, body)}); + } + return; + } + case 0x001A: { // Remote Name Request Cancel + if (n < 6) break; + const BdAddr addr = ReadAddr(p); + auto it = std::find_if(m_pending.begin(), m_pending.end(), [&](const PendingEvent& e) { + return e.event[0] == kEventRemoteNameComplete && ReadAddr(&e.event[3]) == addr; + }); + std::vector body = {static_cast(it == m_pending.end() ? kStatusUnknownConnection + : kStatusSuccess)}; + PutAddr(body, addr); + CommandComplete(opcode, body); + if (it != m_pending.end()) { + std::vector complete = it->event; + complete[2] = kStatusUnknownConnection; + m_pending.erase(it); + QueueEvent(std::move(complete)); + } + return; + } + case 0x001B: { // Read Remote Supported Features + const int slot = handleSlot(0); + if (slot < 0) { + CommandStatus(opcode, kStatusUnknownConnection); + return; + } + CommandStatus(opcode, kStatusSuccess); + std::vector body = {kStatusSuccess}; + PutLe16(body, ConnectionHandle(slot)); + body.insert(body.end(), kRemoteFeatures.begin(), kRemoteFeatures.end()); + QueueEvent(Event(kEventRemoteFeatures, body)); + return; + } + case 0x001D: { // Read Remote Version Information + const int slot = handleSlot(0); + if (slot < 0) { + CommandStatus(opcode, kStatusUnknownConnection); + return; + } + CommandStatus(opcode, kStatusSuccess); + std::vector body = {kStatusSuccess}; + PutLe16(body, ConnectionHandle(slot)); + body.push_back(kRemoteLmpVersion); + PutLe16(body, kRemoteManufacturer); + PutLe16(body, kRemoteLmpSubversion); + QueueEvent(Event(kEventRemoteVersion, body)); + return; + } + case 0x001F: { // Read Clock Offset + const int slot = handleSlot(0); + if (slot < 0) { + CommandStatus(opcode, kStatusUnknownConnection); + return; + } + CommandStatus(opcode, kStatusSuccess); + std::vector body = {kStatusSuccess}; + PutLe16(body, ConnectionHandle(slot)); + PutLe16(body, kRemoteClockOffset); + QueueEvent(Event(kEventClockOffset, body)); + return; + } + case 0x0007: // Add SCO Connection + case 0x0028: // Setup Synchronous Connection + case 0x0029: // Accept Synchronous Connection Request + case 0x002A: // Reject Synchronous Connection Request + CommandStatus(opcode, kStatusUnsupportedFeature); + return; + default: + UnknownCommand(opcode); + return; + } + std::cerr << "[bluetooth] short HCI command 0x" << std::hex << opcode << std::dec << std::endl; + CommandStatus(opcode, kStatusUnknownCommand); +} + +void Controller::HandleLinkPolicy(uint16_t opcode, const uint8_t* p, size_t n) { + const int slot = n >= 2 ? SlotForHandle(Le16(p)) : -1; + const auto modeChange = [&](uint8_t mode, uint16_t interval) { + if (slot < 0) { + CommandStatus(opcode, kStatusUnknownConnection); + return; + } + CommandStatus(opcode, kStatusSuccess); + std::vector body = {kStatusSuccess}; + PutLe16(body, ConnectionHandle(static_cast(slot))); + body.push_back(mode); + PutLe16(body, interval); + QueueEvent(Event(kEventModeChange, body)); + }; + const auto handleReply = [&](std::vector extra) { + std::vector body = {static_cast(slot < 0 ? kStatusUnknownConnection : kStatusSuccess)}; + PutLe16(body, n >= 2 ? Le16(p) : 0); + body.insert(body.end(), extra.begin(), extra.end()); + CommandComplete(opcode, body); + }; + switch (opcode & 0x3FF) { + case 0x0001: modeChange(0x01, n >= 4 ? Le16(p + 2) : 0); return; // Hold Mode + case 0x0003: modeChange(0x02, n >= 4 ? Le16(p + 2) : 0); return; // Sniff Mode + case 0x0004: modeChange(0x00, 0); return; // Exit Sniff Mode + case 0x0005: modeChange(0x03, n >= 4 ? Le16(p + 2) : 0); return; // Park State + case 0x0006: modeChange(0x00, 0); return; // Exit Park State + case 0x0009: handleReply({0x00}); return; // Role Discovery + case 0x000B: { // Switch Role + if (n < 7) break; + CommandStatus(opcode, kStatusSuccess); + std::vector body = {kStatusSuccess}; + body.insert(body.end(), p, p + 7); + QueueEvent(Event(kEventRoleChange, body)); + return; + } + case 0x000C: handleReply({0x05, 0x00}); return; // Read Link Policy Settings + case 0x000D: handleReply({}); return; // Write Link Policy Settings + case 0x000E: CommandComplete(opcode, {kStatusSuccess, 0x05, 0x00}); return; // Read Default Link Policy + case 0x000F: CommandComplete(opcode, {kStatusSuccess}); return; // Write Default Link Policy + default: + UnknownCommand(opcode); + return; + } + CommandStatus(opcode, kStatusUnknownCommand); +} + +void Controller::HandleControllerBaseband(uint16_t opcode, const uint8_t* p, size_t n, uint64_t nowUs) { + (void)nowUs; + const auto handleReply = [&](std::vector extra) { + const int slot = n >= 2 ? SlotForHandle(Le16(p)) : -1; + std::vector body = {static_cast(slot < 0 ? kStatusUnknownConnection : kStatusSuccess)}; + PutLe16(body, n >= 2 ? Le16(p) : 0); + body.insert(body.end(), extra.begin(), extra.end()); + CommandComplete(opcode, body); + }; + switch (opcode & 0x3FF) { + case 0x0003: // Reset + ResetState(true); + CommandComplete(opcode, {kStatusSuccess}); + return; + case 0x000D: { // Read Stored Link Key + if (n < 7) break; + const BdAddr addr = ReadAddr(p); + const bool readAll = p[6] == 0x01; + std::vector keys; + for (const StoredKey& key : m_storedKeys) { + if (readAll || key.addr == addr) keys.push_back(key); + } + for (size_t start = 0; start < keys.size(); start += kKeysPerEvent) { + const size_t count = std::min(kKeysPerEvent, keys.size() - start); + std::vector body = {static_cast(count)}; + for (size_t i = start; i < start + count; ++i) { + PutAddr(body, keys[i].addr); + body.insert(body.end(), keys[i].key.begin(), keys[i].key.end()); + } + QueueEvent(Event(kEventReturnLinkKeys, body)); + } + std::vector body = {kStatusSuccess}; + PutLe16(body, kMaxStoredKeys); + PutLe16(body, static_cast(keys.size())); + CommandComplete(opcode, body); + return; + } + case 0x0011: { // Write Stored Link Key + if (n < 1) break; + const uint8_t count = p[0]; + if (n < 1 + count * size_t{22}) break; + for (uint8_t i = 0; i < count; ++i) { + const uint8_t* entry = p + 1 + i * 22; + StoredKey key{ReadAddr(entry), {}}; + std::copy(entry + 6, entry + 22, key.key.begin()); + auto existing = std::find_if(m_storedKeys.begin(), m_storedKeys.end(), + [&](const StoredKey& k) { return k.addr == key.addr; }); + if (existing != m_storedKeys.end()) { + *existing = key; + } else if (m_storedKeys.size() < kMaxStoredKeys) { + m_storedKeys.push_back(key); + } + } + CommandComplete(opcode, {kStatusSuccess, count}); + return; + } + case 0x0012: { // Delete Stored Link Key + if (n < 7) break; + const BdAddr addr = ReadAddr(p); + const bool deleteAll = p[6] == 0x01; + const size_t before = m_storedKeys.size(); + m_storedKeys.erase(std::remove_if(m_storedKeys.begin(), m_storedKeys.end(), + [&](const StoredKey& k) { return deleteAll || k.addr == addr; }), + m_storedKeys.end()); + std::vector body = {kStatusSuccess}; + PutLe16(body, static_cast(before - m_storedKeys.size())); + CommandComplete(opcode, body); + return; + } + case 0x0013: // Change Local Name + if (n < m_localName.size()) break; + std::memcpy(m_localName.data(), p, m_localName.size()); + CommandComplete(opcode, {kStatusSuccess}); + return; + case 0x0014: { // Read Local Name + std::vector body = {kStatusSuccess}; + body.insert(body.end(), m_localName.begin(), m_localName.end()); + CommandComplete(opcode, body); + return; + } + case 0x0018: // Write Page Timeout + if (n < 2) break; + m_pageTimeoutSlots = Le16(p); + CommandComplete(opcode, {kStatusSuccess}); + return; + case 0x0019: // Read Scan Enable + CommandComplete(opcode, {kStatusSuccess, m_scanEnable}); + return; + case 0x001A: // Write Scan Enable + if (n < 1) break; + m_scanEnable = p[0]; + CommandComplete(opcode, {kStatusSuccess}); + return; + case 0x0023: // Read Class of Device + CommandComplete(opcode, {kStatusSuccess, m_classOfDevice[0], m_classOfDevice[1], m_classOfDevice[2]}); + return; + case 0x0024: // Write Class of Device + if (n < 3) break; + std::copy(p, p + 3, m_classOfDevice.begin()); + CommandComplete(opcode, {kStatusSuccess}); + return; + case 0x0045: // Write Inquiry Mode + if (n < 1) break; + m_inquiryMode = p[0]; + CommandComplete(opcode, {kStatusSuccess}); + return; + case 0x0028: // Write Automatic Flush Timeout + case 0x0037: // Write Link Supervision Timeout + handleReply({}); + return; + case 0x0036: // Read Link Supervision Timeout + handleReply({0x80, 0x0C}); + return; + case 0x0001: // Set Event Mask + case 0x0005: // Set Event Filter + case 0x000A: // Write PIN Type + case 0x0016: // Write Connection Accept Timeout + case 0x001C: // Write Page Scan Activity + case 0x001E: // Write Inquiry Scan Activity + case 0x0020: // Write Authentication Enable + case 0x0022: // Write Encryption Mode + case 0x0031: // Set Controller To Host Flow Control + case 0x0033: // Host Buffer Size + case 0x003A: // Write Current IAC LAP + case 0x003F: // Set AFH Host Channel Classification + case 0x0043: // Write Inquiry Scan Type + case 0x0047: // Write Page Scan Type + CommandComplete(opcode, {kStatusSuccess}); + return; + case 0x0035: // Host Number Of Completed Packets: no event + return; + default: + UnknownCommand(opcode); + return; + } + std::cerr << "[bluetooth] short HCI command 0x" << std::hex << opcode << std::dec << std::endl; + CommandComplete(opcode, {kStatusUnknownCommand}); +} + +void Controller::HandleInformational(uint16_t opcode, const uint8_t* p, size_t n) { + (void)p; + (void)n; + switch (opcode & 0x3FF) { + case 0x0001: { // Read Local Version Information + std::vector body = {kStatusSuccess, 0x03}; + PutLe16(body, 0x40A7); + body.push_back(0x03); + PutLe16(body, 0x000F); + PutLe16(body, 0x430E); + CommandComplete(opcode, body); + return; + } + case 0x0003: { // Read Local Supported Features + std::vector body = {kStatusSuccess}; + body.insert(body.end(), kLocalFeatures.begin(), kLocalFeatures.end()); + CommandComplete(opcode, body); + return; + } + case 0x0005: { // Read Buffer Size + std::vector body = {kStatusSuccess}; + PutLe16(body, kAclBufferSize); + body.push_back(kScoBufferSize); + PutLe16(body, kAclBufferCount); + PutLe16(body, 0); + CommandComplete(opcode, body); + return; + } + case 0x0009: { // Read BD_ADDR + std::vector body = {kStatusSuccess}; + PutAddr(body, LocalAddress()); + CommandComplete(opcode, body); + return; + } + default: + UnknownCommand(opcode); + return; + } +} + +void Controller::HandleStatusParameters(uint16_t opcode, const uint8_t* p, size_t n) { + const int slot = n >= 2 ? SlotForHandle(Le16(p)) : -1; + std::vector body = {static_cast(slot < 0 ? kStatusUnknownConnection : kStatusSuccess)}; + PutLe16(body, n >= 2 ? Le16(p) : 0); + switch (opcode & 0x3FF) { + case 0x0003: // Get Link Quality + body.push_back(0xFF); + CommandComplete(opcode, body); + return; + case 0x0005: // Read RSSI: 0 = inside the golden receive power range + body.push_back(0x00); + CommandComplete(opcode, body); + return; + default: + UnknownCommand(opcode); + return; + } +} + +void Controller::HandleVendor(uint16_t opcode, const uint8_t* p, size_t n) { + (void)p; + (void)n; + // WUD's firmware patch upload (0xFC4C writes, 0xFC4F install) and friends. + CommandComplete(opcode, {kStatusSuccess}); +} + +void Controller::ReceiveAcl(const uint8_t* packet, size_t size, uint64_t nowUs) { + (void)nowUs; + if (size < 4) return; + const uint16_t header = Le16(packet); + const uint16_t length = Le16(packet + 2); + if (length != size - 4) { + std::cerr << "[bluetooth] dropped malformed ACL packet" << std::endl; + return; + } + const int slot = SlotForHandle(header & 0x0FFF); + if (slot < 0) return; + ++m_completedPackets[slot]; + const uint8_t boundary = static_cast((header >> 12) & 0x3); + Reassembly& r = m_reassembly[slot]; + const uint8_t* data = packet + 4; + if (boundary == 0x1) { + if (r.expected == 0) return; + r.frame.insert(r.frame.end(), data, data + length); + } else { + r.frame.assign(data, data + length); + r.expected = length >= 2 ? static_cast(Le16(data)) + 4 : 0; + } + if (r.expected != 0 && r.frame.size() >= r.expected) { + const std::vector frame(r.frame.begin(), r.frame.begin() + static_cast(r.expected)); + r = {}; + m_links[slot]->ReceiveL2cap(frame.data(), frame.size()); + } +} + +void Controller::Tick(uint64_t nowUs) { + if (!m_open) return; + for (size_t i = 0; i < m_pending.size();) { + if (nowUs >= m_pending[i].dueUs) { + QueueEvent(std::move(m_pending[i].event)); + m_pending.erase(m_pending.begin() + static_cast(i)); + } else { + ++i; + } + } + TickInquiry(nowUs); + for (auto& link : m_links) { + link->Tick(nowUs); + } + SendNumberOfCompletedPackets(); +} + +void Controller::TickInquiry(uint64_t nowUs) { + if (!m_inquiry.active) return; + if (nowUs >= m_inquiry.endUs || + (m_inquiry.maxResponses != 0 && m_inquiry.reported >= m_inquiry.maxResponses)) { + FinishInquiry(); + return; + } + // One result per tick, lowest slot first, so remotes keep their order. + for (size_t slot = 0; slot < kRemoteSlots; ++slot) { + if (m_inquiry.slotReported[slot] || !m_links[slot]->Discoverable()) continue; + m_inquiry.slotReported[slot] = true; + ++m_inquiry.reported; + const BdAddr addr = RemoteAddress(slot); + std::vector body = {0x01}; + PutAddr(body, addr); + body.push_back(0x01); // page scan repetition mode R1 + if (m_inquiryMode == 0) { + body.insert(body.end(), {0x00, 0x00, 0x04, 0x25, 0x00}); + PutLe16(body, kRemoteClockOffset); + QueueEvent(Event(kEventInquiryResult, body)); + } else { + body.insert(body.end(), {0x00, 0x04, 0x25, 0x00}); + PutLe16(body, kRemoteClockOffset); + body.push_back(kInquiryRssi); + if (m_inquiryMode == 2) { + std::array eir{}; + const char* name = m_host.DeviceName(slot); + const size_t nameLength = std::min(std::strlen(name), eir.size() - 2); + eir[0] = static_cast(nameLength + 1); + eir[1] = 0x09; // complete local name + std::memcpy(&eir[2], name, nameLength); + body.insert(body.end(), eir.begin(), eir.end()); + QueueEvent(Event(kEventExtendedInquiryResult, body)); + } else { + QueueEvent(Event(kEventInquiryResultWithRssi, body)); + } + } + return; + } +} + +void Controller::FinishInquiry() { + m_inquiry = {}; + QueueEvent(Event(kEventInquiryComplete, {kStatusSuccess})); + if (m_hostInquiryNotified) { + m_host.OnGuestInquiry(false); + m_hostInquiryNotified = false; + } +} + +void Controller::SendNumberOfCompletedPackets() { + std::vector body = {0}; + for (size_t slot = 0; slot < kRemoteSlots; ++slot) { + if (m_completedPackets[slot] == 0) continue; + PutLe16(body, ConnectionHandle(slot)); + PutLe16(body, m_completedPackets[slot]); + m_completedPackets[slot] = 0; + ++body[0]; + } + if (body[0] != 0) { + QueueEvent(Event(kEventNumberOfCompletedPackets, body)); + } +} + +} // namespace Bluetooth diff --git a/runtime/src/hle/bluetooth/bt_remote_link.cpp b/runtime/src/hle/bluetooth/bt_remote_link.cpp new file mode 100644 index 0000000..f12938e --- /dev/null +++ b/runtime/src/hle/bluetooth/bt_remote_link.cpp @@ -0,0 +1,567 @@ +#include "bluetooth/bt_remote_link.h" + +#include "bluetooth/bt_bytes.h" +#include "bluetooth/bt_sdp.h" + +#include +#include + +namespace Bluetooth { +namespace L2capDetail { + +constexpr uint16_t kSignallingCid = 0x0001; +constexpr uint16_t kFirstDynamicCid = 0x0040; + +constexpr uint16_t kPsmSdp = 0x0001; +constexpr uint16_t kPsmHidControl = 0x0011; +constexpr uint16_t kPsmHidInterrupt = 0x0013; + +constexpr uint8_t kCommandReject = 0x01; +constexpr uint8_t kConnectionRequest = 0x02; +constexpr uint8_t kConnectionResponse = 0x03; +constexpr uint8_t kConfigurationRequest = 0x04; +constexpr uint8_t kConfigurationResponse = 0x05; +constexpr uint8_t kDisconnectionRequest = 0x06; +constexpr uint8_t kDisconnectionResponse = 0x07; +constexpr uint8_t kEchoRequest = 0x08; +constexpr uint8_t kEchoResponse = 0x09; +constexpr uint8_t kInformationRequest = 0x0A; +constexpr uint8_t kInformationResponse = 0x0B; + +constexpr uint16_t kResultSuccess = 0x0000; +constexpr uint16_t kResultPending = 0x0001; +constexpr uint16_t kResultPsmNotSupported = 0x0002; +constexpr uint16_t kResultNoResources = 0x0004; + +constexpr uint8_t kOptionMtu = 0x01; +constexpr uint8_t kOptionFlushTimeout = 0x02; +// A real remote asks for this MTU on its own channels. +constexpr uint16_t kRemoteMtu = 185; + +constexpr uint8_t kHidHandshake = 0x0; +constexpr uint8_t kHidControl = 0x1; +constexpr uint8_t kHidSetReport = 0x5; +constexpr uint8_t kHidData = 0xA; +constexpr uint8_t kHidParamOutput = 0x2; +constexpr uint8_t kHidHandshakeSuccess = 0x00; +constexpr uint8_t kHidHandshakeUnsupported = 0x03; +constexpr uint8_t kHidVirtualCableUnplug = 0x5; +constexpr uint8_t kHidDataInput = 0xA1; + +constexpr uint64_t kRequestTimeoutUs = 10'000'000; +constexpr uint64_t kRetryDelayUs = 3'000'000; +constexpr uint8_t kReasonRemoteUserTerminated = 0x13; +// Output reports carry at most 21 payload bytes; anything longer is not a Wii Remote report. +constexpr size_t kMaxReportSize = 22; +constexpr size_t kInputBacklog = 8; + +} // namespace L2capDetail + +using namespace L2capDetail; + +RemoteLink::RemoteLink(Controller& controller, size_t slot) : m_controller(controller), m_slot(slot) {} + +void RemoteLink::Reset() { + ClearConnection(); + m_baseband = Baseband::Idle; + SetState(LinkState::Down); + m_retryAtUs = 0; +} + +void RemoteLink::ClearConnection() { + m_channels.clear(); + m_guestInitiated = false; + m_everReady = false; +} + +bool RemoteLink::Discoverable() const { + return m_baseband == Baseband::Idle && m_connectWanted && m_controller.Host().IsAttached(m_slot); +} + +void RemoteLink::Tick(uint64_t nowUs) { + m_nowUs = nowUs; + RemoteHost& host = m_controller.Host(); + if (m_baseband == Baseband::Idle) { + if (host.ConsumeWake(m_slot)) { + m_connectWanted = true; + m_retryAtUs = 0; + } + if (!host.IsAttached(m_slot)) { + m_connectWanted = false; + } + if (m_connectWanted && m_controller.PageScanEnabled() && nowUs >= m_retryAtUs) { + std::vector event = {0x04, 10}; + const BdAddr addr = Controller::RemoteAddress(m_slot); + event.insert(event.end(), addr.begin(), addr.end()); + // Class of device 0x002504: peripheral, joystick. + event.insert(event.end(), {0x04, 0x25, 0x00, 0x01}); + m_controller.QueueEvent(std::move(event)); + m_baseband = Baseband::Requesting; + m_stateSinceUs = nowUs; + } + } else if (m_baseband == Baseband::Requesting) { + if (nowUs - m_stateSinceUs > kRequestTimeoutUs) { + m_baseband = Baseband::Idle; + m_retryAtUs = nowUs + kRetryDelayUs; + } + } else if (m_baseband == Baseband::Connected) { + if (!host.IsAttached(m_slot)) { + DropFromRemote(kReasonRemoteUserTerminated); + m_connectWanted = false; + return; + } + if (!m_guestInitiated) { + const Channel* control = FindByPsm(kPsmHidControl); + if (control == nullptr) { + RequestChannel(kPsmHidControl, nowUs); + } else if (control->Open() && FindByPsm(kPsmHidInterrupt) == nullptr) { + RequestChannel(kPsmHidInterrupt, nowUs); + } + } + for (const Channel& channel : m_channels) { + const bool waiting = (channel.weInitiated && !channel.connected) || + (channel.configSent && !channel.localConfigured); + if (waiting && nowUs - channel.requestUs > kRequestTimeoutUs) { + std::cerr << "[bluetooth] Wii Remote " << (m_slot + 1) << ": L2CAP channel 0x" << std::hex + << channel.psm << std::dec << " did not open, dropping the connection" << std::endl; + DropFromRemote(kReasonRemoteUserTerminated); + m_retryAtUs = nowUs + kRetryDelayUs; + return; + } + } + } + ForwardInput(); +} + +void RemoteLink::ForwardInput() { + RemoteHost& host = m_controller.Host(); + if (m_state != LinkState::Ready) { + while (host.PopInputReport(m_slot, m_report)) { + } + return; + } + const Channel* interrupt = FindByPsm(kPsmHidInterrupt); + while (m_controller.AclQueued() < kInputBacklog && host.PopInputReport(m_slot, m_report)) { + if (m_report.empty() || m_report.size() > kMaxReportSize) continue; + SendInput(*interrupt, m_report); + } +} + +void RemoteLink::SendInput(const Channel& interrupt, const std::vector& report) { + std::vector payload; + payload.reserve(report.size() + 1); + payload.push_back(kHidDataInput); + payload.insert(payload.end(), report.begin(), report.end()); + if (payload.size() <= interrupt.remoteMtu) { + SendData(interrupt, payload); + } +} + + +void RemoteLink::OnAccepted(uint8_t role) { + (void)role; + m_baseband = Baseband::Connected; + m_guestInitiated = false; + m_everReady = false; + m_stateSinceUs = m_nowUs; + SetState(LinkState::Connecting); +} + +void RemoteLink::OnRejected(uint8_t reason, uint64_t nowUs) { + std::cerr << "[bluetooth] Wii Remote " << (m_slot + 1) << ": connection rejected (0x" << std::hex + << static_cast(reason) << std::dec << ")" << std::endl; + m_baseband = Baseband::Idle; + m_retryAtUs = nowUs + kRetryDelayUs; +} + +bool RemoteLink::OnPaged(uint64_t nowUs) { + if (!Discoverable()) { + return false; + } + m_nowUs = nowUs; + m_baseband = Baseband::Connected; + m_guestInitiated = true; + m_everReady = false; + m_stateSinceUs = nowUs; + SetState(LinkState::Connecting); + return true; +} + +void RemoteLink::OnDisconnected(bool byGuest, uint64_t nowUs) { + const bool wasReady = m_everReady; + ClearConnection(); + m_baseband = Baseband::Idle; + SetState(LinkState::Down); + if (byGuest && wasReady) { + m_connectWanted = false; + m_controller.Host().OnGuestDisconnect(m_slot); + } else { + m_retryAtUs = nowUs + kRetryDelayUs; + } +} + +void RemoteLink::DropFromRemote(uint8_t reason) { + std::vector event = {0x05, 4, 0x00}; + PutLe16(event, Controller::ConnectionHandle(m_slot)); + event.push_back(reason); + m_controller.QueueEvent(std::move(event)); + ClearConnection(); + m_baseband = Baseband::Idle; + SetState(LinkState::Down); +} + +void RemoteLink::SetState(LinkState state) { + if (m_state == state) return; + m_state = state; + if (state == LinkState::Ready) { + m_everReady = true; + m_connectWanted = false; + } + m_controller.Host().OnLinkStateChanged(m_slot, state); +} + +void RemoteLink::UpdateState() { + if (m_baseband != Baseband::Connected) { + SetState(LinkState::Down); + return; + } + const Channel* control = FindByPsm(kPsmHidControl); + const Channel* interrupt = FindByPsm(kPsmHidInterrupt); + const bool ready = control != nullptr && interrupt != nullptr && control->Open() && interrupt->Open(); + SetState(ready ? LinkState::Ready : LinkState::Connecting); +} + +RemoteLink::Channel* RemoteLink::FindByLocal(uint16_t cid) { + for (Channel& channel : m_channels) { + if (channel.localCid == cid) return &channel; + } + return nullptr; +} + +RemoteLink::Channel* RemoteLink::FindByPsm(uint16_t psm) { + for (Channel& channel : m_channels) { + if (channel.psm == psm) return &channel; + } + return nullptr; +} + +uint16_t RemoteLink::AllocateCid() const { + uint16_t cid = kFirstDynamicCid; + while (std::any_of(m_channels.begin(), m_channels.end(), [&](const Channel& c) { return c.localCid == cid; })) { + ++cid; + } + return cid; +} + +uint8_t RemoteLink::NextIdent() { + m_ident = static_cast(m_ident + 1); + if (m_ident == 0) m_ident = 1; + return m_ident; +} + +void RemoteLink::SendSignal(uint8_t code, uint8_t ident, const std::vector& data) { + std::vector frame; + frame.reserve(8 + data.size()); + PutLe16(frame, static_cast(4 + data.size())); + PutLe16(frame, kSignallingCid); + frame.push_back(code); + frame.push_back(ident); + PutLe16(frame, static_cast(data.size())); + frame.insert(frame.end(), data.begin(), data.end()); + m_controller.QueueAcl(Controller::ConnectionHandle(m_slot), frame); +} + +void RemoteLink::SendData(const Channel& channel, const std::vector& payload) { + std::vector frame; + frame.reserve(4 + payload.size()); + PutLe16(frame, static_cast(payload.size())); + PutLe16(frame, channel.remoteCid); + frame.insert(frame.end(), payload.begin(), payload.end()); + m_controller.QueueAcl(Controller::ConnectionHandle(m_slot), frame); +} + +void RemoteLink::RequestChannel(uint16_t psm, uint64_t nowUs) { + Channel channel; + channel.psm = psm; + channel.localCid = AllocateCid(); + channel.weInitiated = true; + channel.connectIdent = NextIdent(); + channel.requestUs = nowUs; + std::vector data; + PutLe16(data, psm); + PutLe16(data, channel.localCid); + SendSignal(kConnectionRequest, channel.connectIdent, data); + m_channels.push_back(channel); +} + +void RemoteLink::SendConfigRequest(Channel& channel) { + channel.configSent = true; + channel.configIdent = NextIdent(); + channel.requestUs = m_nowUs; + std::vector data; + PutLe16(data, channel.remoteCid); + PutLe16(data, 0); + data.push_back(kOptionMtu); + data.push_back(2); + PutLe16(data, kRemoteMtu); + SendSignal(kConfigurationRequest, channel.configIdent, data); +} + +void RemoteLink::ReceiveL2cap(const uint8_t* frame, size_t size) { + if (m_baseband != Baseband::Connected || size < 4) return; + const uint16_t length = Le16(frame); + const uint16_t cid = Le16(frame + 2); + if (length != size - 4) { + std::cerr << "[bluetooth] Wii Remote " << (m_slot + 1) << ": dropped malformed L2CAP frame" << std::endl; + return; + } + if (cid == kSignallingCid) { + HandleSignalling(frame + 4, length); + } else if (Channel* channel = FindByLocal(cid)) { + HandleChannelData(*channel, frame + 4, length); + } +} + +void RemoteLink::HandleSignalling(const uint8_t* data, size_t size) { + while (size >= 4) { + const uint8_t code = data[0]; + const uint8_t ident = data[1]; + const uint16_t length = Le16(data + 2); + if (static_cast(length) + 4 > size) { + return; + } + const uint8_t* p = data + 4; + switch (code) { + case kConnectionRequest: HandleConnectionRequest(ident, p, length); break; + case kConnectionResponse: HandleConnectionResponse(ident, p, length); break; + case kConfigurationRequest: HandleConfigurationRequest(ident, p, length); break; + case kConfigurationResponse: HandleConfigurationResponse(ident, p, length); break; + case kDisconnectionRequest: HandleDisconnectionRequest(ident, p, length); break; + case kDisconnectionResponse: HandleDisconnectionResponse(p, length); break; + case kEchoRequest: SendSignal(kEchoResponse, ident, std::vector(p, p + length)); break; + case kInformationRequest: { + if (length >= 2) { + std::vector reply; + PutLe16(reply, Le16(p)); + PutLe16(reply, 0x0001); // not supported + SendSignal(kInformationResponse, ident, reply); + } + break; + } + case kCommandReject: + std::cerr << "[bluetooth] Wii Remote " << (m_slot + 1) << ": the game rejected L2CAP command " + << static_cast(ident) << std::endl; + break; + case kEchoResponse: + case kInformationResponse: + break; + default: { + std::vector reply; + PutLe16(reply, 0x0000); // command not understood + SendSignal(kCommandReject, ident, reply); + break; + } + } + data += 4 + length; + size -= 4 + length; + } +} + +void RemoteLink::HandleConnectionRequest(uint8_t ident, const uint8_t* p, size_t n) { + if (n < 4) return; + const uint16_t psm = Le16(p); + const uint16_t scid = Le16(p + 2); + uint16_t result = kResultSuccess; + uint16_t dcid = 0; + if (psm != kPsmSdp && psm != kPsmHidControl && psm != kPsmHidInterrupt) { + result = kResultPsmNotSupported; + } else if (FindByPsm(psm) != nullptr) { + // A real remote refuses a second channel on the same PSM. + result = kResultNoResources; + } else { + Channel channel; + channel.psm = psm; + channel.localCid = AllocateCid(); + channel.remoteCid = scid; + channel.connected = true; + dcid = channel.localCid; + m_channels.push_back(channel); + } + std::vector reply; + PutLe16(reply, dcid); + PutLe16(reply, scid); + PutLe16(reply, result); + PutLe16(reply, 0); + SendSignal(kConnectionResponse, ident, reply); + if (result == kResultSuccess) { + SendConfigRequest(*FindByLocal(dcid)); + } +} + +void RemoteLink::HandleConnectionResponse(uint8_t ident, const uint8_t* p, size_t n) { + if (n < 8) return; + const uint16_t dcid = Le16(p); + const uint16_t scid = Le16(p + 2); + const uint16_t result = Le16(p + 4); + Channel* channel = FindByLocal(scid); + if (channel == nullptr || !channel->weInitiated || channel->connected || channel->connectIdent != ident) { + return; + } + if (result == kResultSuccess) { + channel->remoteCid = dcid; + channel->connected = true; + SendConfigRequest(*channel); + } else if (result == kResultPending) { + channel->requestUs = m_nowUs; + } else { + std::cerr << "[bluetooth] Wii Remote " << (m_slot + 1) << ": the game refused L2CAP PSM 0x" << std::hex + << channel->psm << " (result 0x" << result << ")" << std::dec << std::endl; + DropFromRemote(kReasonRemoteUserTerminated); + m_retryAtUs = m_nowUs + kRetryDelayUs; + } +} + +void RemoteLink::HandleConfigurationRequest(uint8_t ident, const uint8_t* p, size_t n) { + if (n < 4) return; + const uint16_t dcid = Le16(p); + const uint16_t flags = Le16(p + 2); + Channel* channel = FindByLocal(dcid); + if (channel == nullptr) { + std::vector reply; + PutLe16(reply, 0x0002); // invalid CID + PutLe16(reply, dcid); + PutLe16(reply, 0); + SendSignal(kCommandReject, ident, reply); + return; + } + channel->pendingOptions.insert(channel->pendingOptions.end(), p + 4, p + n); + std::vector reply; + PutLe16(reply, channel->remoteCid); + if (flags & 1) { + PutLe16(reply, 1); + PutLe16(reply, kResultSuccess); + SendSignal(kConfigurationResponse, ident, reply); + return; + } + PutLe16(reply, 0); + PutLe16(reply, kResultSuccess); + const std::vector& options = channel->pendingOptions; + for (size_t i = 0; i + 2 <= options.size();) { + const uint8_t type = options[i] & 0x7F; + const uint8_t length = options[i + 1]; + if (i + 2 + length > options.size()) break; + if (type == kOptionMtu && length == 2) { + channel->remoteMtu = Le16(&options[i + 2]); + reply.insert(reply.end(), options.begin() + static_cast(i), + options.begin() + static_cast(i + 4)); + } else if (type == kOptionFlushTimeout && length == 2) { + reply.insert(reply.end(), options.begin() + static_cast(i), + options.begin() + static_cast(i + 4)); + } + i += 2 + length; + } + channel->pendingOptions.clear(); + channel->remoteConfigured = true; + SendSignal(kConfigurationResponse, ident, reply); + UpdateState(); +} + +void RemoteLink::HandleConfigurationResponse(uint8_t ident, const uint8_t* p, size_t n) { + if (n < 6) return; + const uint16_t scid = Le16(p); + const uint16_t flags = Le16(p + 2); + const uint16_t result = Le16(p + 4); + Channel* channel = FindByLocal(scid); + if (channel == nullptr || !channel->configSent || channel->configIdent != ident) return; + if (flags & 1) { + return; + } + if (result == kResultSuccess) { + channel->localConfigured = true; + UpdateState(); + return; + } + // Our only option is the MTU; offer the default instead. + channel->configIdent = NextIdent(); + channel->requestUs = m_nowUs; + std::vector data; + PutLe16(data, channel->remoteCid); + PutLe16(data, 0); + SendSignal(kConfigurationRequest, channel->configIdent, data); +} + +void RemoteLink::HandleDisconnectionRequest(uint8_t ident, const uint8_t* p, size_t n) { + if (n < 4) return; + const uint16_t dcid = Le16(p); + const uint16_t scid = Le16(p + 2); + std::vector reply; + PutLe16(reply, dcid); + PutLe16(reply, scid); + SendSignal(kDisconnectionResponse, ident, reply); + m_channels.erase(std::remove_if(m_channels.begin(), m_channels.end(), + [&](const Channel& c) { return c.localCid == dcid; }), + m_channels.end()); + UpdateState(); +} + +void RemoteLink::HandleDisconnectionResponse(const uint8_t* p, size_t n) { + if (n < 4) return; + const uint16_t scid = Le16(p + 2); + m_channels.erase(std::remove_if(m_channels.begin(), m_channels.end(), + [&](const Channel& c) { return c.localCid == scid; }), + m_channels.end()); + UpdateState(); +} + +void RemoteLink::HandleChannelData(Channel& channel, const uint8_t* data, size_t size) { + if (size == 0) return; + if (channel.psm == kPsmSdp) { + const std::vector response = Sdp::HandleRequest(data, size, channel.remoteMtu); + SendData(channel, response); + return; + } + if (channel.psm == kPsmHidControl) { + HandleHidControl(channel, data, size); + return; + } + const uint8_t type = data[0] >> 4; + const uint8_t param = data[0] & 0x0F; + if (type == kHidData && param == kHidParamOutput && size >= 2 && size - 1 <= kMaxReportSize) { + m_controller.Host().SendOutputReport(m_slot, data + 1, size - 1); + } +} + +void RemoteLink::HandleHidControl(Channel& channel, const uint8_t* data, size_t size) { + const uint8_t type = data[0] >> 4; + const uint8_t param = data[0] & 0x0F; + switch (type) { + case kHidHandshake: + return; + case kHidControl: + if (param == kHidVirtualCableUnplug) { + const bool wasReady = m_everReady; + DropFromRemote(kReasonRemoteUserTerminated); + if (wasReady) { + m_connectWanted = false; + m_controller.Host().OnGuestDisconnect(m_slot); + } + } + return; + case kHidSetReport: + SendData(channel, {kHidHandshakeSuccess}); + if ((param & 0x3) == kHidParamOutput && size >= 2 && size - 1 <= kMaxReportSize) { + m_controller.Host().SendOutputReport(m_slot, data + 1, size - 1); + } + return; + case kHidData: + if (param == kHidParamOutput && size >= 2 && size - 1 <= kMaxReportSize) { + m_controller.Host().SendOutputReport(m_slot, data + 1, size - 1); + } + return; + default: + SendData(channel, {kHidHandshakeUnsupported}); + return; + } +} + +} // namespace Bluetooth diff --git a/runtime/src/hle/bluetooth/bt_sdp.cpp b/runtime/src/hle/bluetooth/bt_sdp.cpp new file mode 100644 index 0000000..21ac26d --- /dev/null +++ b/runtime/src/hle/bluetooth/bt_sdp.cpp @@ -0,0 +1,438 @@ +#include "bluetooth/bt_sdp.h" + +#include +#include +#include +#include +#include +#include + +namespace Bluetooth::Sdp { +namespace { + +using Bytes = std::vector; + +constexpr uint8_t kErrorResponse = 0x01; +constexpr uint8_t kServiceSearchRequest = 0x02; +constexpr uint8_t kServiceSearchResponse = 0x03; +constexpr uint8_t kServiceAttributeRequest = 0x04; +constexpr uint8_t kServiceAttributeResponse = 0x05; +constexpr uint8_t kServiceSearchAttributeRequest = 0x06; +constexpr uint8_t kServiceSearchAttributeResponse = 0x07; + +constexpr uint16_t kErrInvalidHandle = 0x0002; +constexpr uint16_t kErrInvalidSyntax = 0x0003; +constexpr uint16_t kErrInvalidPduSize = 0x0004; +constexpr uint16_t kErrInvalidContinuation = 0x0005; + +void PutBe16(Bytes& out, uint16_t v) { + out.push_back(static_cast(v >> 8)); + out.push_back(static_cast(v)); +} + +void PutBe32(Bytes& out, uint32_t v) { + PutBe16(out, static_cast(v >> 16)); + PutBe16(out, static_cast(v)); +} + +uint16_t Be16(const uint8_t* p) { + return static_cast((p[0] << 8) | p[1]); +} + +uint32_t Be32(const uint8_t* p) { + return (static_cast(Be16(p)) << 16) | Be16(p + 2); +} + +// Data element constructors (Bluetooth Core, Vol 3 Part B, 3.2). +Bytes U8(uint8_t v) { return {0x08, v}; } +Bytes U16(uint16_t v) { Bytes b{0x09}; PutBe16(b, v); return b; } +Bytes U32(uint32_t v) { Bytes b{0x0A}; PutBe32(b, v); return b; } +Bytes Uuid16(uint16_t v) { Bytes b{0x19}; PutBe16(b, v); return b; } +Bytes Bool(bool v) { return {0x28, static_cast(v ? 1 : 0)}; } + +Bytes WithLength(uint8_t type, size_t length, bool wide = false) { + if (length <= 0xFF && !wide) { + return {static_cast((type << 3) | 5), static_cast(length)}; + } + Bytes b{static_cast((type << 3) | 6)}; + PutBe16(b, static_cast(length)); + return b; +} + +Bytes Text(const Bytes& raw) { + Bytes b = WithLength(4, raw.size()); + b.insert(b.end(), raw.begin(), raw.end()); + return b; +} + +Bytes Text(std::string_view s) { + return Text(Bytes(s.begin(), s.end())); +} + +Bytes Seq(std::initializer_list items) { + size_t length = 0; + for (const Bytes& item : items) length += item.size(); + Bytes b = WithLength(6, length); + for (const Bytes& item : items) b.insert(b.end(), item.begin(), item.end()); + return b; +} + +using Record = std::vector>; + +const Bytes kHidDescriptor = { + 0x05, 0x01, 0x09, 0x05, 0xA1, 0x01, 0x85, 0x10, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 0x08, 0x95, + 0x01, 0x06, 0x00, 0xFF, 0x09, 0x01, 0x91, 0x00, 0x85, 0x11, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, + 0x85, 0x12, 0x95, 0x02, 0x09, 0x01, 0x91, 0x00, 0x85, 0x13, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, + 0x85, 0x14, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85, 0x15, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, + 0x85, 0x16, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00, 0x85, 0x17, 0x95, 0x06, 0x09, 0x01, 0x91, 0x00, + 0x85, 0x18, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00, 0x85, 0x19, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, + 0x85, 0x1A, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00, 0x85, 0x20, 0x95, 0x06, 0x09, 0x01, 0x81, 0x00, + 0x85, 0x21, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, 0x22, 0x95, 0x04, 0x09, 0x01, 0x81, 0x00, + 0x85, 0x30, 0x95, 0x02, 0x09, 0x01, 0x81, 0x00, 0x85, 0x31, 0x95, 0x05, 0x09, 0x01, 0x81, 0x00, + 0x85, 0x32, 0x95, 0x0A, 0x09, 0x01, 0x81, 0x00, 0x85, 0x33, 0x95, 0x11, 0x09, 0x01, 0x81, 0x00, + 0x85, 0x34, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, 0x35, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, + 0x85, 0x36, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, 0x37, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, + 0x85, 0x3D, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0x85, 0x3E, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, + 0x85, 0x3F, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00, 0xC0, +}; + +constexpr uint32_t kHidRecordHandle = 0x00010000; +constexpr uint32_t kDeviceIdRecordHandle = 0x00010001; + +const Record& HidRecord() { + static const Record record = { + {0x0000, U32(kHidRecordHandle)}, + {0x0001, Seq({Uuid16(0x1124)})}, + {0x0004, Seq({Seq({Uuid16(0x0100), U16(0x0011)}), Seq({Uuid16(0x0011)})})}, + {0x0005, Seq({Uuid16(0x1002)})}, + {0x0006, Seq({U16(0x656E), U16(0x006A), U16(0x0100)})}, + {0x0009, Seq({Seq({Uuid16(0x1124), U16(0x0100)})})}, + {0x000D, Seq({Seq({Seq({Uuid16(0x0100), U16(0x0013)}), Seq({Uuid16(0x0011)})})})}, + {0x0100, Text("Nintendo RVL-CNT-01")}, + {0x0101, Text("Nintendo RVL-CNT-01")}, + {0x0102, Text("Nintendo")}, + {0x0200, U16(0x0100)}, + {0x0201, U16(0x0111)}, + {0x0202, U8(0x04)}, + {0x0203, U8(0x33)}, + {0x0204, Bool(false)}, + {0x0205, Bool(true)}, + {0x0206, Seq({Seq({U8(0x22), Text(kHidDescriptor)})})}, + {0x0207, Seq({Seq({U16(0x0409), U16(0x0100)})})}, + {0x0208, Bool(false)}, + {0x0209, Bool(true)}, + {0x020A, Bool(true)}, + {0x020B, U16(0x0100)}, + {0x020C, U16(0x0C80)}, + {0x020D, Bool(false)}, + {0x020E, Bool(false)}, + }; + return record; +} + +const Record& DeviceIdRecord() { + static const Record record = { + {0x0000, U32(kDeviceIdRecordHandle)}, + {0x0001, Seq({Uuid16(0x1200)})}, + {0x0004, Seq({Seq({Uuid16(0x0100), U16(0x0001)}), Seq({Uuid16(0x0001)})})}, + {0x0005, Seq({Uuid16(0x1002)})}, + {0x0009, Seq({Seq({Uuid16(0x1200), U16(0x0100)})})}, + {0x0200, U16(0x0100)}, + {0x0201, U16(0x057E)}, + {0x0202, U16(0x0306)}, + {0x0203, U16(0x0600)}, + {0x0204, Bool(true)}, + {0x0205, U16(0x0002)}, + }; + return record; +} + +struct NamedRecord { + uint32_t handle; + const Record& (*get)(); +}; +constexpr std::array kRecords = {{ + {kHidRecordHandle, HidRecord}, + {kDeviceIdRecordHandle, DeviceIdRecord}, +}}; + +using Uuid = std::array; + +Uuid FromShort(uint32_t value) { + // Bluetooth base UUID 00000000-0000-1000-8000-00805F9B34FB. + Uuid u = {0, 0, 0, 0, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}; + u[0] = static_cast(value >> 24); + u[1] = static_cast(value >> 16); + u[2] = static_cast(value >> 8); + u[3] = static_cast(value); + return u; +} + +// One parsed data element header: type, header size and payload size. +struct ElementHeader { + uint8_t type = 0; + size_t headerSize = 0; + size_t dataSize = 0; +}; + +std::optional ParseHeader(const uint8_t* p, size_t n) { + if (n == 0) return std::nullopt; + ElementHeader h; + h.type = static_cast(p[0] >> 3); + const uint8_t sizeIndex = p[0] & 7; + if (h.type == 0) { + h.headerSize = 1; + h.dataSize = 0; + } else if (sizeIndex <= 4) { + h.headerSize = 1; + h.dataSize = size_t{1} << sizeIndex; + } else if (sizeIndex == 5) { + if (n < 2) return std::nullopt; + h.headerSize = 2; + h.dataSize = p[1]; + } else if (sizeIndex == 6) { + if (n < 3) return std::nullopt; + h.headerSize = 3; + h.dataSize = Be16(p + 1); + } else { + if (n < 5) return std::nullopt; + h.headerSize = 5; + h.dataSize = Be32(p + 1); + } + if (h.headerSize + h.dataSize > n) return std::nullopt; + return h; +} + +std::optional ReadUuid(const uint8_t* p, const ElementHeader& h) { + if (h.type != 3) return std::nullopt; + const uint8_t* d = p + h.headerSize; + if (h.dataSize == 2) return FromShort(Be16(d)); + if (h.dataSize == 4) return FromShort(Be32(d)); + if (h.dataSize == 16) { + Uuid u{}; + std::copy(d, d + 16, u.begin()); + return u; + } + return std::nullopt; +} + +void CollectUuids(const uint8_t* p, size_t n, std::vector& out) { + while (n > 0) { + const auto h = ParseHeader(p, n); + if (!h) return; + if (h->type == 6 || h->type == 7) { + CollectUuids(p + h->headerSize, h->dataSize, out); + } else if (const auto uuid = ReadUuid(p, *h)) { + out.push_back(*uuid); + } + const size_t total = h->headerSize + h->dataSize; + p += total; + n -= total; + } +} + +bool RecordMatches(const Record& record, const std::vector& pattern) { + std::vector present; + for (const auto& [id, value] : record) CollectUuids(value.data(), value.size(), present); + return std::all_of(pattern.begin(), pattern.end(), [&](const Uuid& wanted) { + return std::find(present.begin(), present.end(), wanted) != present.end(); + }); +} + +// Parses a data element sequence at `p`; advances `p`/`n` past it. +std::optional> TakeSequence(const uint8_t*& p, size_t& n) { + const auto h = ParseHeader(p, n); + if (!h || (h->type != 6)) return std::nullopt; + const std::pair body{p + h->headerSize, h->dataSize}; + p += h->headerSize + h->dataSize; + n -= h->headerSize + h->dataSize; + return body; +} + +std::optional> ParsePattern(const uint8_t*& p, size_t& n) { + const auto body = TakeSequence(p, n); + if (!body) return std::nullopt; + std::vector pattern; + const uint8_t* q = body->first; + size_t m = body->second; + while (m > 0) { + const auto h = ParseHeader(q, m); + if (!h) return std::nullopt; + const auto uuid = ReadUuid(q, *h); + if (!uuid) return std::nullopt; + pattern.push_back(*uuid); + q += h->headerSize + h->dataSize; + m -= h->headerSize + h->dataSize; + } + if (pattern.empty() || pattern.size() > 12) return std::nullopt; + return pattern; +} + +using IdRange = std::pair; + +std::optional> ParseAttributeIds(const uint8_t*& p, size_t& n) { + const auto body = TakeSequence(p, n); + if (!body) return std::nullopt; + std::vector ranges; + const uint8_t* q = body->first; + size_t m = body->second; + while (m > 0) { + const auto h = ParseHeader(q, m); + if (!h || h->type != 1) return std::nullopt; + const uint8_t* d = q + h->headerSize; + if (h->dataSize == 2) { + ranges.emplace_back(Be16(d), Be16(d)); + } else if (h->dataSize == 4) { + ranges.emplace_back(Be16(d), Be16(d + 2)); + } else { + return std::nullopt; + } + q += h->headerSize + h->dataSize; + m -= h->headerSize + h->dataSize; + } + if (ranges.empty()) return std::nullopt; + return ranges; +} + +// Continuation state is the byte offset into the complete response (2 bytes BE). +std::optional ParseContinuation(const uint8_t* p, size_t n) { + if (n < 1 || p[0] + size_t{1} != n) return std::nullopt; + if (p[0] == 0) return 0; + if (p[0] != 2) return std::nullopt; + return Be16(p + 1); +} + +Bytes AttributeList(const Record& record, const std::vector& ranges) { + Bytes inner; + for (const auto& [id, value] : record) { + const bool wanted = std::any_of(ranges.begin(), ranges.end(), + [id = id](const IdRange& r) { return id >= r.first && id <= r.second; }); + if (!wanted) continue; + const Bytes idElement = U16(id); + inner.insert(inner.end(), idElement.begin(), idElement.end()); + inner.insert(inner.end(), value.begin(), value.end()); + } + // A real remote always sends attribute lists with a 16-bit length. + Bytes list = WithLength(6, inner.size(), true); + list.insert(list.end(), inner.begin(), inner.end()); + return list; +} + +Bytes Pdu(uint8_t id, uint16_t tid, const Bytes& params) { + Bytes out{id}; + PutBe16(out, tid); + PutBe16(out, static_cast(params.size())); + out.insert(out.end(), params.begin(), params.end()); + return out; +} + +Bytes Error(uint16_t tid, uint16_t code) { + Bytes params; + PutBe16(params, code); + return Pdu(kErrorResponse, tid, params); +} + +// Emits the slice of `full` starting at `offset` that fits, plus continuation. +Bytes Chunked(uint8_t responseId, uint16_t tid, const Bytes& full, size_t offset, uint16_t maxBytes, + size_t maxResponse) { + // PDU header 5, byte count 2, continuation up to 3. + const size_t room = maxResponse > 10 ? maxResponse - 10 : 1; + const size_t limit = std::max(1, std::min(maxBytes, room)); + const size_t count = std::min(limit, full.size() - offset); + Bytes params; + PutBe16(params, static_cast(count)); + params.insert(params.end(), full.begin() + static_cast(offset), + full.begin() + static_cast(offset + count)); + const size_t next = offset + count; + if (next < full.size()) { + params.push_back(2); + PutBe16(params, static_cast(next)); + } else { + params.push_back(0); + } + return Pdu(responseId, tid, params); +} + +} // namespace + +const std::vector& WiiRemoteHidDescriptor() { + return kHidDescriptor; +} + +std::vector HandleRequest(const uint8_t* pdu, size_t size, size_t maxResponse) { + if (size < 5) { + return Error(0, kErrInvalidPduSize); + } + const uint8_t id = pdu[0]; + const uint16_t tid = Be16(pdu + 1); + const uint16_t paramLength = Be16(pdu + 3); + if (paramLength != size - 5) { + return Error(tid, kErrInvalidPduSize); + } + const uint8_t* p = pdu + 5; + size_t n = paramLength; + + switch (id) { + case kServiceSearchRequest: { + const auto pattern = ParsePattern(p, n); + if (!pattern || n < 2) return Error(tid, kErrInvalidSyntax); + const uint16_t maxCount = Be16(p); + if (!ParseContinuation(p + 2, n - 2)) return Error(tid, kErrInvalidContinuation); + Bytes handles; + uint16_t found = 0; + for (const NamedRecord& record : kRecords) { + if (found < maxCount && RecordMatches(record.get(), *pattern)) { + PutBe32(handles, record.handle); + ++found; + } + } + Bytes params; + PutBe16(params, found); + PutBe16(params, found); + params.insert(params.end(), handles.begin(), handles.end()); + params.push_back(0); + return Pdu(kServiceSearchResponse, tid, params); + } + case kServiceAttributeRequest: { + if (n < 6) return Error(tid, kErrInvalidSyntax); + const uint32_t handle = Be32(p); + const uint16_t maxBytes = Be16(p + 4); + p += 6; + n -= 6; + const auto ranges = ParseAttributeIds(p, n); + if (!ranges || maxBytes < 7) return Error(tid, kErrInvalidSyntax); + const auto record = std::find_if(kRecords.begin(), kRecords.end(), + [&](const NamedRecord& r) { return r.handle == handle; }); + if (record == kRecords.end()) return Error(tid, kErrInvalidHandle); + const Bytes full = AttributeList(record->get(), *ranges); + const auto offset = ParseContinuation(p, n); + if (!offset || *offset > full.size()) return Error(tid, kErrInvalidContinuation); + return Chunked(kServiceAttributeResponse, tid, full, *offset, maxBytes, maxResponse); + } + case kServiceSearchAttributeRequest: { + const auto pattern = ParsePattern(p, n); + if (!pattern || n < 2) return Error(tid, kErrInvalidSyntax); + const uint16_t maxBytes = Be16(p); + p += 2; + n -= 2; + const auto ranges = ParseAttributeIds(p, n); + if (!ranges || maxBytes < 7) return Error(tid, kErrInvalidSyntax); + Bytes lists; + for (const NamedRecord& record : kRecords) { + if (RecordMatches(record.get(), *pattern)) { + const Bytes list = AttributeList(record.get(), *ranges); + lists.insert(lists.end(), list.begin(), list.end()); + } + } + Bytes full = WithLength(6, lists.size()); + full.insert(full.end(), lists.begin(), lists.end()); + const auto offset = ParseContinuation(p, n); + if (!offset || *offset > full.size()) return Error(tid, kErrInvalidContinuation); + return Chunked(kServiceSearchAttributeResponse, tid, full, *offset, maxBytes, maxResponse); + } + default: + return Error(tid, kErrInvalidSyntax); + } +} + +} // namespace Bluetooth::Sdp diff --git a/runtime/src/hle/bluetooth/bt_sysconf.cpp b/runtime/src/hle/bluetooth/bt_sysconf.cpp new file mode 100644 index 0000000..1c3f01f --- /dev/null +++ b/runtime/src/hle/bluetooth/bt_sysconf.cpp @@ -0,0 +1,126 @@ +// SYSCONF items behind the Wii Remote stack. The runtime never parses a +// SYSCONF (SCCheckStatus is HLE'd), so these accessors serve the Bluetooth items +// directly: BT.DINF registers the four virtual remotes of the emulated +// controller, and the console settings come from Config.toml. + +#include "bluetooth/bt_controller.h" +#include "hle_stubs.h" +#include "memory.h" +#include "runtime_config.h" +#include "runtime_log.h" + +#include +#include +#include + +namespace BluetoothSysconf { + +constexpr uint32_t kDeviceInfoSize = 0x461; +constexpr uint32_t kCmpDeviceInfoSize = 0x205; +constexpr uint32_t kDeviceEntrySize = 0x46; +// [0..9] registered remotes, [10..13] the remote last connected on each channel. +constexpr uint32_t kActiveEntriesStart = 10; +constexpr const char kRemoteName[] = "Nintendo RVL-CNT-01"; + +void Fill(uint32_t buffer, uint32_t size, uint8_t value) { + std::memset(Memory::GetPointer(buffer, size), value, size); +} + +void WriteEntry(uint32_t buffer, uint32_t index, size_t slot) { + const uint32_t entry = buffer + 1 + index * kDeviceEntrySize; + // SYSCONF keeps addresses most significant byte first. + const Bluetooth::BdAddr addr = Bluetooth::Controller::RemoteAddress(slot); + for (size_t i = 0; i < addr.size(); ++i) { + Memory::Write8(entry + static_cast(i), addr[addr.size() - 1 - i]); + } + std::memcpy(Memory::GetPointer(entry + 6, sizeof(kRemoteName)), kRemoteName, sizeof(kRemoteName)); +} + +void SetReturn(CpuContext* ctx, uint32_t value) { + ctx->gpr[3] = value; +} + +} // namespace BluetoothSysconf + +extern "C" void SCGetBtDeviceInfoArray_HLE(CpuContext* ctx) { + const uint32_t buffer = ctx->gpr[3]; + try { + BluetoothSysconf::Fill(buffer, BluetoothSysconf::kDeviceInfoSize, 0); + Memory::Write8(buffer, static_cast(Bluetooth::kRemoteSlots)); + for (size_t slot = 0; slot < Bluetooth::kRemoteSlots; ++slot) { + BluetoothSysconf::WriteEntry(buffer, static_cast(slot), slot); + BluetoothSysconf::WriteEntry(buffer, BluetoothSysconf::kActiveEntriesStart + static_cast(slot), slot); + } + BluetoothSysconf::SetReturn(ctx, 1); + } catch (const Memory::AccessViolation& e) { + LogMemoryError(RT_TAG_HLE, "SCGetBtDeviceInfoArray", e); + BluetoothSysconf::SetReturn(ctx, 0); + } +} +PPC_NATIVE_OVERRIDE_VOID(801B1ED0, SCGetBtDeviceInfoArray_HLE, (CpuContext* ctx), (ctx)); + +// WUD writes the list back after reconciling it with the controller's link +// keys, and WPAD whenever a channel's remote changes. The virtual remotes are +// fixed, so the list is rebuilt on every boot. +extern "C" void SCSetBtDeviceInfoArray_HLE(CpuContext* ctx) { + BluetoothSysconf::SetReturn(ctx, 1); +} +PPC_NATIVE_OVERRIDE_VOID(801B1EDC, SCSetBtDeviceInfoArray_HLE, (CpuContext* ctx), (ctx)); + +// Remotes paired with 1+2 on the game's own sync screens. The virtual remotes +// are all registered, so the list is always empty. +extern "C" void SCGetBtCmpDevInfoArray_HLE(CpuContext* ctx) { + try { + BluetoothSysconf::Fill(ctx->gpr[3], BluetoothSysconf::kCmpDeviceInfoSize, 0); + BluetoothSysconf::SetReturn(ctx, 1); + } catch (const Memory::AccessViolation& e) { + LogMemoryError(RT_TAG_HLE, "SCGetBtCmpDevInfoArray", e); + BluetoothSysconf::SetReturn(ctx, 0); + } +} +PPC_NATIVE_OVERRIDE_VOID(801B1EE8, SCGetBtCmpDevInfoArray_HLE, (CpuContext* ctx), (ctx)); + +extern "C" void SCSetBtCmpDevInfoArray_HLE(CpuContext* ctx) { + BluetoothSysconf::SetReturn(ctx, 1); +} +PPC_NATIVE_OVERRIDE_VOID(801B1EF4, SCSetBtCmpDevInfoArray_HLE, (CpuContext* ctx), (ctx)); + +extern "C" void SCGetBtDpdSensibility_HLE(CpuContext* ctx) { + BluetoothSysconf::SetReturn(ctx, static_cast(std::clamp(RuntimeConfigFile::WiiIrSensitivity(), 1, 5))); +} +PPC_NATIVE_OVERRIDE_VOID(801B1F00, SCGetBtDpdSensibility_HLE, (CpuContext* ctx), (ctx)); + +extern "C" void SCGetWpadMotorMode_HLE(CpuContext* ctx) { + BluetoothSysconf::SetReturn(ctx, RuntimeConfigFile::WiiRumbleEnabled() ? 1u : 0u); +} +PPC_NATIVE_OVERRIDE_VOID(801B1F68, SCGetWpadMotorMode_HLE, (CpuContext* ctx), (ctx)); + +// The Home Menu's vibration switch, saved by WPADSaveConfig. +extern "C" void SCSetWpadMotorMode_HLE(CpuContext* ctx) { + const bool enabled = (ctx->gpr[3] & 0xFF) == 1; + if (enabled != RuntimeConfigFile::WiiRumbleEnabled()) { + RuntimeConfigFile::SetWiiRumbleEnabled(enabled); + } + BluetoothSysconf::SetReturn(ctx, 1); +} +PPC_NATIVE_OVERRIDE_VOID(801B1FBC, SCSetWpadMotorMode_HLE, (CpuContext* ctx), (ctx)); + +extern "C" void SCGetWpadSensorBarPosition_HLE(CpuContext* ctx) { + BluetoothSysconf::SetReturn(ctx, RuntimeConfigFile::WiiSensorBarAbove() ? 1u : 0u); +} +PPC_NATIVE_OVERRIDE_VOID(801B1FC4, SCGetWpadSensorBarPosition_HLE, (CpuContext* ctx), (ctx)); + +extern "C" void SCGetWpadSpeakerVolume_HLE(CpuContext* ctx) { + BluetoothSysconf::SetReturn(ctx, static_cast(std::clamp(RuntimeConfigFile::WiiSpeakerVolume(), 0, 0x7F))); +} +PPC_NATIVE_OVERRIDE_VOID(801B2018, SCGetWpadSpeakerVolume_HLE, (CpuContext* ctx), (ctx)); + +// The Home Menu's speaker volume, saved by WPADSaveConfig. +extern "C" void SCSetWpadSpeakerVolume_HLE(CpuContext* ctx) { + const int32_t volume = std::min(static_cast(ctx->gpr[3] & 0xFF), 0x7F); + if (volume != RuntimeConfigFile::WiiSpeakerVolume()) { + RuntimeConfigFile::SetWiiSpeakerVolume(volume); + } + BluetoothSysconf::SetReturn(ctx, 1); +} +PPC_NATIVE_OVERRIDE_VOID(801B206C, SCSetWpadSpeakerVolume_HLE, (CpuContext* ctx), (ctx)); diff --git a/runtime/src/hle/bluetooth/bt_usb_device.cpp b/runtime/src/hle/bluetooth/bt_usb_device.cpp new file mode 100644 index 0000000..eab7934 --- /dev/null +++ b/runtime/src/hle/bluetooth/bt_usb_device.cpp @@ -0,0 +1,270 @@ +#include "hle/bluetooth_hle.h" + +#include "bluetooth/bt_controller.h" +#include "hle/runtime_parse_helpers.h" +#include "memory.h" +#include "runtime_log.h" +#include "wiimote_host.h" + +#include +#include +#include +#include +#include + +void NandQueueIosCallback(uint32_t callbackPtr, int32_t result, uint32_t callbackArg); + +namespace BluetoothUsb { + +constexpr const char* kDevicePath = "/dev/usb/oh1/57e/305"; +constexpr int32_t kDeviceFd = 5; +constexpr int32_t kIpcSuccess = 0; +constexpr int32_t kIpcEinval = -4; + +constexpr uint32_t kCtrlMsg = 0; +constexpr uint32_t kBulkMsg = 1; +constexpr uint32_t kIntrMsg = 2; + +constexpr uint8_t kEndpointEvents = 0x81; +constexpr uint8_t kEndpointAclIn = 0x82; +constexpr uint8_t kEndpointAclOut = 0x02; + +// The guest copies each delivered packet into a GKI buffer that its 2 ms +// Bluetooth tick frees; a pool it cannot refill drops the packet, so ACL data is +// paced. Plenty for four remotes reporting at 200 Hz. +constexpr double kAclPacketsPerMs = 3.0; +constexpr double kAclBurst = 6.0; + +struct HeldRead { + bool active = false; + uint32_t buffer = 0; + uint32_t length = 0; + uint32_t callback = 0; + uint32_t callbackArg = 0; +}; + +struct Device { + bool open = false; + std::unique_ptr controller; + HeldRead eventRead; + HeldRead aclRead; + double aclTokens = kAclBurst; + uint64_t lastRefillUs = 0; +}; + +Device& Dev() { + static Device device; + return device; +} + +uint64_t NowUs() { + using namespace std::chrono; + return static_cast(duration_cast(steady_clock::now().time_since_epoch()).count()); +} + +Bluetooth::Controller& ControllerFor(Device& device) { + if (!device.controller) { + device.controller = std::make_unique(Wiimote::Host()); + } + return *device.controller; +} + +std::vector ReadGuest(uint32_t address, uint32_t length) { + std::vector data(length); + if (length != 0) { + std::memcpy(data.data(), Memory::GetPointer(address, length), length); + } + return data; +} + +void Complete(HeldRead& read, const std::vector& data) { + const uint32_t size = static_cast(std::min(data.size(), read.length)); + if (size < data.size()) { + RT_LOG(RT_TAG_HLE) << "Bluetooth: packet of " << data.size() << " bytes truncated to " << size << std::endl; + } + if (size != 0) { + std::memcpy(Memory::GetPointer(read.buffer, size), data.data(), size); + } + read.active = false; + NandQueueIosCallback(read.callback, static_cast(size), read.callbackArg); +} + +// Hands queued events and ACL data to whichever reads the guest has armed. +bool Deliver(Device& device, uint64_t nowUs) { + Bluetooth::Controller& controller = ControllerFor(device); + bool delivered = false; + std::vector packet; + if (device.eventRead.active && controller.PopEvent(packet)) { + Complete(device.eventRead, packet); + delivered = true; + } + if (nowUs > device.lastRefillUs) { + device.aclTokens = std::min(kAclBurst, device.aclTokens + (nowUs - device.lastRefillUs) / 1000.0 * kAclPacketsPerMs); + device.lastRefillUs = nowUs; + } + if (device.aclRead.active && device.aclTokens >= 1.0 && controller.PopAcl(packet)) { + device.aclTokens -= 1.0; + Complete(device.aclRead, packet); + delivered = true; + } + return delivered; +} + +bool Hold(HeldRead& read, uint32_t buffer, uint32_t length, uint32_t callback, uint32_t callbackArg) { + if (length != 0) { + Memory::GetPointer(buffer, length); + } + if (read.active) { + RT_LOG(RT_TAG_HLE) << "Bluetooth: a second read on the same endpoint replaced the first" << std::endl; + NandQueueIosCallback(read.callback, kIpcEinval, read.callbackArg); + } + read = {true, buffer, length, callback, callbackArg}; + return true; +} + +// Executes a transfer. Returns true with `result` when it completed now. +bool Transfer(uint32_t cmd, uint32_t numIn, uint32_t numOut, uint32_t vectorPtr, uint32_t callback, + uint32_t callbackArg, bool async, int32_t& result) { + Device& device = Dev(); + Bluetooth::Controller& controller = ControllerFor(device); + const uint64_t nowUs = NowUs(); + try { + if (cmd == kCtrlMsg && numIn == 6 && numOut == 1) { + const auto requestType = RuntimeHle::ReadIoVector(vectorPtr, 0); + const auto lengthVector = RuntimeHle::ReadIoVector(vectorPtr, 4); + const auto data = RuntimeHle::ReadIoVector(vectorPtr, 6); + const uint8_t bmRequestType = Memory::Read8(requestType.address); + // wLength is little-endian in the request block. + const uint16_t wLength = static_cast(Memory::Read8(lengthVector.address) | + (Memory::Read8(lengthVector.address + 1) << 8)); + if (bmRequestType != 0x20 || wLength > data.size) { + RT_LOG(RT_TAG_HLE) << "Bluetooth: unexpected control transfer type 0x" << std::hex + << static_cast(bmRequestType) << std::dec << std::endl; + result = kIpcEinval; + return true; + } + const std::vector command = ReadGuest(data.address, wLength); + controller.ExecuteCommand(command.data(), command.size(), nowUs); + result = wLength; + return true; + } + if ((cmd == kBulkMsg || cmd == kIntrMsg) && numIn == 2 && numOut == 1) { + const auto endpointVector = RuntimeHle::ReadIoVector(vectorPtr, 0); + const auto lengthVector = RuntimeHle::ReadIoVector(vectorPtr, 1); + const auto data = RuntimeHle::ReadIoVector(vectorPtr, 2); + const uint8_t endpoint = Memory::Read8(endpointVector.address); + // Bulk / interrupt lengths are big-endian. + const uint16_t length = Memory::Read16(lengthVector.address); + if (length > data.size) { + result = kIpcEinval; + return true; + } + if (cmd == kBulkMsg && endpoint == kEndpointAclOut) { + const std::vector packet = ReadGuest(data.address, length); + controller.ReceiveAcl(packet.data(), packet.size(), nowUs); + result = length; + return true; + } + if (async && cmd == kBulkMsg && endpoint == kEndpointAclIn) { + Hold(device.aclRead, data.address, length, callback, callbackArg); + Deliver(device, nowUs); + return false; + } + if (async && cmd == kIntrMsg && endpoint == kEndpointEvents) { + Hold(device.eventRead, data.address, length, callback, callbackArg); + Deliver(device, nowUs); + return false; + } + RT_LOG(RT_TAG_HLE) << "Bluetooth: unsupported transfer cmd " << cmd << " endpoint 0x" << std::hex + << static_cast(endpoint) << std::dec << (async ? "" : " (sync)") << std::endl; + result = kIpcEinval; + return true; + } + } catch (const Memory::AccessViolation& e) { + LogMemoryError(RT_TAG_HLE, "Bluetooth transfer", e); + result = kIpcEinval; + return true; + } + RT_LOG(RT_TAG_HLE) << "Bluetooth: unsupported ioctlv " << cmd << " (" << numIn << " in, " << numOut << " out)" + << std::endl; + result = kIpcEinval; + return true; +} + +} // namespace BluetoothUsb + +int32_t Bluetooth_HLE_OpenDevice(const char* path) { + if (path == nullptr || std::strcmp(path, BluetoothUsb::kDevicePath) != 0) { + return 0; + } + BluetoothUsb::Device& device = BluetoothUsb::Dev(); + if (device.open) { + RT_LOG(RT_TAG_HLE) << "Bluetooth: device opened twice" << std::endl; + } + device.open = true; + device.eventRead = {}; + device.aclRead = {}; + device.aclTokens = BluetoothUsb::kAclBurst; + device.lastRefillUs = BluetoothUsb::NowUs(); + BluetoothUsb::ControllerFor(device).Open(device.lastRefillUs); + RT_LOG(RT_TAG_HLE) << "Bluetooth: " << BluetoothUsb::kDevicePath << " opened" << std::endl; + return BluetoothUsb::kDeviceFd; +} + +bool Bluetooth_HLE_IsFd(uint32_t fd) { + return static_cast(fd) == BluetoothUsb::kDeviceFd; +} + +int32_t Bluetooth_HLE_Close(uint32_t fd) { + if (!Bluetooth_HLE_IsFd(fd)) { + return BluetoothUsb::kIpcEinval; + } + BluetoothUsb::Device& device = BluetoothUsb::Dev(); + // IOS cancels the transfers still queued on a device it closes. + for (BluetoothUsb::HeldRead* read : {&device.eventRead, &device.aclRead}) { + if (read->active) { + read->active = false; + NandQueueIosCallback(read->callback, BluetoothUsb::kIpcEinval, read->callbackArg); + } + } + BluetoothUsb::ControllerFor(device).Close(); + device.open = false; + RT_LOG(RT_TAG_HLE) << "Bluetooth: " << BluetoothUsb::kDevicePath << " closed" << std::endl; + return BluetoothUsb::kIpcSuccess; +} + +bool Bluetooth_HLE_IoctlvAsync(uint32_t fd, uint32_t cmd, uint32_t numIn, uint32_t numOut, uint32_t vectorPtr, + uint32_t callback, uint32_t callbackArg, int32_t& result) { + (void)fd; + if (!BluetoothUsb::Dev().open) { + result = BluetoothUsb::kIpcEinval; + return true; + } + return BluetoothUsb::Transfer(cmd, numIn, numOut, vectorPtr, callback, callbackArg, true, result); +} + +int32_t Bluetooth_HLE_Ioctlv(uint32_t fd, uint32_t cmd, uint32_t numIn, uint32_t numOut, uint32_t vectorPtr) { + (void)fd; + if (!BluetoothUsb::Dev().open) { + return BluetoothUsb::kIpcEinval; + } + int32_t result = BluetoothUsb::kIpcEinval; + BluetoothUsb::Transfer(cmd, numIn, numOut, vectorPtr, 0, 0, false, result); + return result; +} + +bool Bluetooth_HLE_ProcessCompletions(CpuContext* cpu) { + (void)cpu; + BluetoothUsb::Device& device = BluetoothUsb::Dev(); + if (!device.open) { + return false; + } + const uint64_t nowUs = BluetoothUsb::NowUs(); + try { + BluetoothUsb::ControllerFor(device).Tick(nowUs); + return BluetoothUsb::Deliver(device, nowUs); + } catch (const Memory::AccessViolation& e) { + LogMemoryError(RT_TAG_HLE, "Bluetooth delivery", e); + return false; + } +} diff --git a/runtime/src/hle/esp.cpp b/runtime/src/hle/esp.cpp index 1211ea6..f8c4caa 100644 --- a/runtime/src/hle/esp.cpp +++ b/runtime/src/hle/esp.cpp @@ -12,7 +12,6 @@ #include static constexpr uint32_t MKW_TITLE_ID_HI = 0x00010004; -static constexpr uint32_t MKW_TITLE_ID_LO = 0x524D4350; // "RMCP" fallback static bool IsValidEspTitleCode(uint32_t code) { for (int shift = 24; shift >= 0; shift -= 8) { @@ -32,7 +31,7 @@ static uint32_t CurrentTitleIdLo() { } } - return MKW_TITLE_ID_LO; + return ::GuestRegion::CurrentFacts().gameCode; } // The guest asked for its title ID or data directory through a pointer we cannot diff --git a/runtime/src/hle/gx/gx_copy.cpp b/runtime/src/hle/gx/gx_copy.cpp index 5631a01..3dbdc8d 100644 --- a/runtime/src/hle/gx/gx_copy.cpp +++ b/runtime/src/hle/gx/gx_copy.cpp @@ -71,11 +71,14 @@ void InvalidateEfbCopyDestinationsForRange(uint32_t addr, uint32_t size) { // ============================================================================ extern "C" void GX__SetDispCopySrc_8016f438(uint32_t l, uint32_t t, uint32_t w, uint32_t h) { + GX_DEFER_CALL(GX__SetDispCopySrc_8016f438, l, t, w, h); GXSetDispCopySrc((u16)l, (u16)t, (u16)w, (u16)h); } PPC_NATIVE_OVERRIDE_VOID(8016f438, GX__SetDispCopySrc_8016f438, (uint32_t l, uint32_t t, uint32_t w, uint32_t h), (l, t, w, h)); -extern "C" void GX__SetDispCopyDst_8016f4b8(uint32_t w, uint32_t h) { GXSetDispCopyDst((u16)w, (u16)h); } +extern "C" void GX__SetDispCopyDst_8016f4b8(uint32_t w, uint32_t h) { + GxWorker::Run([w, h] { GXSetDispCopyDst((u16)w, (u16)h); }); +} PPC_NATIVE_OVERRIDE_VOID(8016f4b8, GX__SetDispCopyDst_8016f4b8, (uint32_t w, uint32_t h), (w, h)); // ============================================================================ @@ -83,14 +86,14 @@ PPC_NATIVE_OVERRIDE_VOID(8016f4b8, GX__SetDispCopyDst_8016f4b8, (uint32_t w, uin // ============================================================================ extern "C" void GX__SetTexCopySrc_8016f478(uint32_t l, uint32_t t, uint32_t w, uint32_t h) { - GXSetTexCopySrc((u16)l, (u16)t, (u16)w, (u16)h); + GxWorker::Run([l, t, w, h] { GXSetTexCopySrc((u16)l, (u16)t, (u16)w, (u16)h); }); g_texCopyState.srcLeft=(u16)l; g_texCopyState.srcTop=(u16)t; g_texCopyState.srcWidth=(u16)w; g_texCopyState.srcHeight=(u16)h; } PPC_NATIVE_OVERRIDE_VOID(8016f478, GX__SetTexCopySrc_8016f478, (uint32_t l, uint32_t t, uint32_t w, uint32_t h), (l, t, w, h)); extern "C" void GX__SetTexCopyDst_8016f4dc(uint32_t w, uint32_t h, uint32_t f, uint32_t m) { - GXSetTexCopyDst((u16)w, (u16)h, (GXTexFmt)f, (GXBool)m); + GxWorker::Run([w, h, f, m] { GXSetTexCopyDst((u16)w, (u16)h, (GXTexFmt)f, (GXBool)m); }); g_texCopyState.dstWidth=(u16)w; g_texCopyState.dstHeight=(u16)h; g_texCopyState.dstFormat=f; g_texCopyState.dstMipmap=m; } @@ -100,11 +103,19 @@ extern "C" void GX__SetCopyFilter_8016fa40(uint32_t aa, uint32_t spa, uint32_t v uint8_t sp[12][2]={}, vfb[7]={}; if(spa) std::memcpy(sp, GuestToHostPtr(spa, 24), 24); if(vfa) std::memcpy(vfb, GuestToHostPtr(vfa, 7), 7); - GXSetCopyFilter((GXBool)aa, sp, (GXBool)vf, vfb); + std::array spCopy{}; + std::array vfCopy{}; + std::memcpy(spCopy.data(), sp, 24); + std::memcpy(vfCopy.data(), vfb, 7); + GxWorker::Run([aa, vf, spCopy, vfCopy]() mutable { + GXSetCopyFilter((GXBool)aa, reinterpret_cast(spCopy.data()), (GXBool)vf, vfCopy.data()); + }); } PPC_NATIVE_OVERRIDE_VOID(8016fa40, GX__SetCopyFilter_8016fa40, (uint32_t aa, uint32_t spa, uint32_t vf, uint32_t vfa), (aa, spa, vf, vfa)); -extern "C" void GX__SetDispCopyGamma_8016fc24(uint32_t g) { GXSetDispCopyGamma((GXGamma)g); } +extern "C" void GX__SetDispCopyGamma_8016fc24(uint32_t g) { + GxWorker::Run([g] { GXSetDispCopyGamma((GXGamma)g); }); +} PPC_NATIVE_OVERRIDE_VOID(8016fc24, GX__SetDispCopyGamma_8016fc24, (uint32_t g), (g)); // ============================================================================ @@ -113,18 +124,24 @@ PPC_NATIVE_OVERRIDE_VOID(8016fc24, GX__SetDispCopyGamma_8016fc24, (uint32_t g), extern "C" void GX__CopyDisp_8016fc38(uint32_t da, uint32_t c) { EnsureAuroraFrameActive(); - // GX copies are FIFO-ordered on hardware. Drain submitted draws before - // resolving the EFB so high-level copies see the same contents. - GXDrawDone(); - GXCopyDisp(GuestToHostPtr(da), (GXBool)c); - // No second GXDrawDone here: the frame-worker wait below is for the DONE - // phase, which strictly subsumes the drain this call would perform. + if (GxWorker::ShouldDefer()) { + // The worker drains like the inline path; EndAuroraFrame joins it before the next frame. + GxWorker::Submit([da, c] { + GXDrawDone(); + GXCopyDisp(GuestToHostPtr(da), (GXBool)c); + }); + } else { + // GX copies are FIFO-ordered on hardware. Drain submitted draws before + // resolving the EFB so high-level copies see the same contents. + GXDrawDone(); + GXCopyDisp(GuestToHostPtr(da), (GXBool)c); + // Present immediately so post-copy draws don't leak into this frame. Join at the DONE phase + // (not the cheaper SEALED phase GXDrawDone waits for) because ImGui's draw lists, owned by + // Aurora's render worker, replay during encode; aurora_end_frame would join here anyway. + aurora_wait_for_frame_worker(); + } ++g_gxFrameCount; VI_HLE_SetXfbReady(da); - // Present immediately so post-copy draws don't leak into this frame. Join at the DONE phase - // (not the cheaper SEALED phase GXDrawDone waits for) because ImGui's draw lists, owned by - // Aurora's render worker, replay during encode; aurora_end_frame would join here anyway. - aurora_wait_for_frame_worker(); settings_overlay::Draw(); // Seal, pace to the VI retrace boundary (Aurora renders the sealed frame // during the wait), and pre-warm the next frame. @@ -135,7 +152,9 @@ PPC_NATIVE_OVERRIDE_VOID(8016fc38, GX__CopyDisp_8016fc38, (uint32_t da, uint32_t extern "C" void GX__CopyTex_8016fd74(uint32_t da, uint32_t c) { + // Begin the frame before going inline so a deferred begin reaches the worker first. EnsureAuroraFrameActive(); + GX_SYNC_INLINE(); // Match GX FIFO ordering: texture copies observe all prior draws. GXDrawDone(); const uint16_t rawSrcLeft = g_texCopyState.srcLeft; diff --git a/runtime/src/hle/gx/gx_dl.cpp b/runtime/src/hle/gx/gx_dl.cpp index 4a984a7..daceeb7 100644 --- a/runtime/src/hle/gx/gx_dl.cpp +++ b/runtime/src/hle/gx/gx_dl.cpp @@ -89,39 +89,42 @@ static inline uint32_t ReadModulatedLytColor(uint32_t colorAddr, int index, uint static_cast(a); } -static inline void AppendLytTexCoords(uint8_t* packet, uint32_t& pos, uint32_t texCoordAddr, - int texCoordCount, uint32_t cornerOffset) { - if (texCoordCount <= 0) { - return; - } - for (int i = 0; i < texCoordCount; ++i) { - const uint32_t coordAddr = texCoordAddr + static_cast(i * 32) + cornerOffset; - BigEndian::AppendFloat32(packet, pos, Memory::ReadFloat32(coordAddr)); - BigEndian::AppendFloat32(packet, pos, Memory::ReadFloat32(coordAddr + 4)); +// An nw4r::lyt quad as read on the game thread: texcoords are 8 sets of 4 corners x (s, t). +struct LytQuad { + float x0 = 0, y0 = 0, x1 = 0, y1 = 0; + int texCoordCount = 0; + std::array texCoords{}; + bool hasColors = false; + std::array colors{}; +}; + +static inline void AppendLytTexCoords(uint8_t* packet, uint32_t& pos, const LytQuad& quad, + uint32_t cornerOffset) { + for (int i = 0; i < quad.texCoordCount; ++i) { + const size_t at = static_cast(i) * 8u + cornerOffset / 4u; + BigEndian::AppendFloat32(packet, pos, quad.texCoords[at]); + BigEndian::AppendFloat32(packet, pos, quad.texCoords[at + 1]); } } -static inline void AppendLytQuadVertex(uint8_t* packet, uint32_t& pos, float x, float y, - uint32_t texCoordAddr, int texCoordCount, - uint32_t cornerOffset, const uint32_t* colors, int colorIndex) { +static inline void AppendLytQuadVertex(uint8_t* packet, uint32_t& pos, float x, float y, const LytQuad& quad, + uint32_t cornerOffset, int colorIndex) { BigEndian::AppendFloat32(packet, pos, x); BigEndian::AppendFloat32(packet, pos, y); - if (colors) { - BigEndian::Append32(packet, pos, colors[colorIndex]); + if (quad.hasColors) { + BigEndian::Append32(packet, pos, quad.colors[colorIndex]); } - AppendLytTexCoords(packet, pos, texCoordAddr, texCoordCount, cornerOffset); + AppendLytTexCoords(packet, pos, quad, cornerOffset); } // The four corners of an nw4r::lyt quad, in the order GX_QUADS expects, with // each corner's texcoord byte offset and colour index. The winding order is // load-bearing and both emit paths below share this one copy of it. -static inline void AppendLytQuadVertices(uint8_t* packet, uint32_t& pos, float x0, float y0, - float x1, float y1, uint32_t texCoordAddr, - int texCoordCount, const uint32_t* colors) { - AppendLytQuadVertex(packet, pos, x0, y0, texCoordAddr, texCoordCount, 0, colors, 0); - AppendLytQuadVertex(packet, pos, x1, y0, texCoordAddr, texCoordCount, 8, colors, 1); - AppendLytQuadVertex(packet, pos, x1, y1, texCoordAddr, texCoordCount, 24, colors, 3); - AppendLytQuadVertex(packet, pos, x0, y1, texCoordAddr, texCoordCount, 16, colors, 2); +static inline void AppendLytQuadVertices(uint8_t* packet, uint32_t& pos, const LytQuad& quad) { + AppendLytQuadVertex(packet, pos, quad.x0, quad.y0, quad, 0, 0); + AppendLytQuadVertex(packet, pos, quad.x1, quad.y0, quad, 8, 1); + AppendLytQuadVertex(packet, pos, quad.x1, quad.y1, quad, 24, 3); + AppendLytQuadVertex(packet, pos, quad.x0, quad.y1, quad, 16, 2); } static bool CanSubmitLytDrawDirect(int texCoordCount, const uint32_t* colors) { @@ -175,9 +178,8 @@ static bool CanSubmitLytDrawDirect(int texCoordCount, const uint32_t* colors) { return true; } -static bool SubmitLytDrawDirect(float x0, float y0, float x1, float y1, int texCoordCount, - uint32_t texCoordAddr, const uint32_t* colors) { - if (!CanSubmitLytDrawDirect(texCoordCount, colors)) { +static bool SubmitLytDrawDirect(const LytQuad& quad) { + if (!CanSubmitLytDrawDirect(quad.texCoordCount, quad.hasColors ? quad.colors.data() : nullptr)) { return false; } @@ -193,7 +195,7 @@ static bool SubmitLytDrawDirect(float x0, float y0, float x1, float y1, int texC std::array vertices{}; uint32_t pos = 0; - AppendLytQuadVertices(vertices.data(), pos, x0, y0, x1, y1, texCoordAddr, texCoordCount, colors); + AppendLytQuadVertices(vertices.data(), pos, quad); if (!aurora::gx::fifo::submit_raw_draw(GX_QUADS, GX_VTXFMT0, vertices.data(), 4, pos)) { return false; @@ -204,23 +206,8 @@ static bool SubmitLytDrawDirect(float x0, float y0, float x1, float y1, int texC return true; } -static inline void EmitLytDrawQuad(uint32_t posAddr, uint32_t sizeAddr, int texCoordCount, - uint32_t texCoordAddr, const uint32_t* colors) { - const float x0 = Memory::ReadFloat32(posAddr); - const float y0 = Memory::ReadFloat32(posAddr + 4); - // The casts pin the arithmetic to PPC single precision regardless of the - // host's FLT_EVAL_METHOD. - const float x1 = static_cast(x0 + Memory::ReadFloat32(sizeAddr)); - const float y1 = static_cast(y0 - Memory::ReadFloat32(sizeAddr + 4)); - - if (SubmitLytDrawDirect(x0, y0, x1, y1, texCoordCount, texCoordAddr, colors)) { - return; - } - - // GX has exactly 8 texture coordinates, so nw4r::lyt cannot ask for more. - // The fixed packet buffer below is sized for that maximum; bail rather than - // overrun it if the guest ever hands us something else. - if (texCoordCount > 8) { +static void EmitLytQuad(const LytQuad& quad) { + if (SubmitLytDrawDirect(quad)) { return; } @@ -228,10 +215,39 @@ static inline void EmitLytDrawQuad(uint32_t posAddr, uint32_t sizeAddr, int texC uint32_t pos = 0; packet[pos++] = GX_DRAW_QUADS_CMD | GX_VTXFMT0; BigEndian::Append16(packet.data(), pos, 4); - AppendLytQuadVertices(packet.data(), pos, x0, y0, x1, y1, texCoordAddr, texCoordCount, colors); + AppendLytQuadVertices(packet.data(), pos, quad); SubmitLytDrawPacket(packet.data(), pos); } +static inline void EmitLytDrawQuad(uint32_t posAddr, uint32_t sizeAddr, int texCoordCount, + uint32_t texCoordAddr, const uint32_t* colors) { + // GX has exactly 8 texture coordinates, so nw4r::lyt cannot ask for more; the packet buffer + // is sized for that maximum. + if (texCoordCount > 8) { + return; + } + LytQuad quad; + quad.x0 = Memory::ReadFloat32(posAddr); + quad.y0 = Memory::ReadFloat32(posAddr + 4); + // The casts pin the arithmetic to PPC single precision regardless of the + // host's FLT_EVAL_METHOD. + quad.x1 = static_cast(quad.x0 + Memory::ReadFloat32(sizeAddr)); + quad.y1 = static_cast(quad.y0 - Memory::ReadFloat32(sizeAddr + 4)); + quad.texCoordCount = std::max(texCoordCount, 0); + for (int i = 0; i < quad.texCoordCount; ++i) { + for (uint32_t f = 0; f < 8; ++f) { + quad.texCoords[static_cast(i) * 8u + f] = + Memory::ReadFloat32(texCoordAddr + static_cast(i * 32) + f * 4u); + } + } + if (colors != nullptr) { + quad.hasColors = true; + std::copy(colors, colors + 4, quad.colors.begin()); + } + EnsureAuroraFrameActive(); + GxWorker::Run([quad] { EmitLytQuad(quad); }); +} + static uint32_t SubmitDLVertex(const uint8_t* ptr, GXVtxFmt vtxfmt, const GXAttrType* sourceVtxDesc) { uint32_t offset = 0; for (int attr = 0; attr < 26; ++attr) { @@ -791,21 +807,17 @@ struct DlMayContainDrawVisitor { bool OnNop(uint8_t) { return true; } bool OnBpReg(const uint8_t*, uint32_t) { return true; } - // An array base/stride write means the list is setting up indexed geometry. - bool OnCpReg(const uint8_t*, uint8_t reg, uint32_t) { return !(reg >= 0xA0 && reg <= 0xBF); } + // CP writes must reach the HLE vertex state, and indexed XF loads need their + // array resolved, so neither may be passed through raw. + bool OnCpReg(const uint8_t*, uint8_t, uint32_t) { return false; } bool OnXfReg(const uint8_t*, uint32_t) { return true; } - bool OnIndexedXf(const uint8_t*, uint8_t, uint32_t) { return true; } + bool OnIndexedXf(const uint8_t*, uint8_t, uint32_t) { return false; } bool OnInvalidateVertexCache(uint8_t) { return true; } // Draw opcodes reach this too (kHandlesDraw is false): a draw opcode, or a // command byte this walker does not model, both mean "assume it draws". bool OnUnknownCommand(uint8_t) { return false; } - bool OnCallDisplayList(uint32_t addr, uint32_t size, int depth) { - if (addr == 0 || size == 0) return true; - const uint8_t* nested = static_cast(GuestToHostPtr(addr, size)); - if (!nested) return false; - DlMayContainDrawVisitor child; - return WalkDisplayList(nested, size, child, depth + 1); - } + // Aurora skips nested calls, so the child has to be flattened. + bool OnCallDisplayList(uint32_t addr, uint32_t size, int) { return addr == 0 || size == 0; } }; static bool DisplayListMayContainDraw(const uint8_t* data, uint32_t nbytes) { @@ -1040,7 +1052,6 @@ static std::vector& FlattenDisplayListScratch() { static bool s_appliedVtxDescValid = false; static std::array s_appliedVtxDesc{}; -static std::array s_appliedSourceVtxDesc{}; static bool s_appliedVtxAttrFmtValid = false; static VtxAttrFmt s_appliedVtxAttrFmt[8][26]{}; @@ -1075,14 +1086,12 @@ static void SyncAppliedVtxStateFromHleReal() { s_appliedVtxStateGeneration == g_hleGxState.vtxStateGeneration) { return; } - // Both mirrors are dense arrays of the same trivially copyable element types - // as their HLE counterparts, so publish them with three memcpys instead of + // The mirrors are dense arrays of the same trivially copyable element types + // as their HLE counterparts, so publish them with memcpys instead of // 234 individual element assignments. static_assert(sizeof(s_appliedVtxDesc) == sizeof(g_hleGxState.vtxDesc)); - static_assert(sizeof(s_appliedSourceVtxDesc) == sizeof(g_hleGxState.vtxDesc)); static_assert(sizeof(s_appliedVtxAttrFmt) == sizeof(g_hleGxState.vtxAttrFmt)); std::memcpy(s_appliedVtxDesc.data(), g_hleGxState.vtxDesc, sizeof(g_hleGxState.vtxDesc)); - std::memcpy(s_appliedSourceVtxDesc.data(), g_hleGxState.vtxDesc, sizeof(g_hleGxState.vtxDesc)); s_appliedVtxDescValid = true; std::memcpy(s_appliedVtxAttrFmt, g_hleGxState.vtxAttrFmt, sizeof(g_hleGxState.vtxAttrFmt)); @@ -1129,18 +1138,13 @@ static void ApplyAuroraVtxDesc() { // GXGetVtxDesc only decodes GX_VA_PNMTXIDX..GX_VA_TEX7; the XF array // pseudo-attributes above GX_VA_TEX7 have no CP descriptor bits, so // probing them would always report GX_NONE and republish a no-op. - if (!needsPublish && !IsMatrixIndexAttr(gxAttr) && gxAttr <= GX_VA_TEX7 && - (type == GX_INDEX8 || type == GX_INDEX16)) { + if (!needsPublish && gxAttr <= GX_VA_TEX7) { needsPublish = !AuroraVtxDescMatchesLive(gxAttr, type); } if (needsPublish) { GXSetVtxDesc(gxAttr, type); s_appliedVtxDesc[attr] = type; } - if (!hadValidState || s_appliedSourceVtxDesc[attr] != type) { - GXSetSourceVtxDesc(gxAttr, type); - s_appliedSourceVtxDesc[attr] = type; - } } s_appliedVtxDescValid = true; } @@ -1291,6 +1295,12 @@ extern "C" void GxNotifyDisplayListMemoryWrite(uint32_t addr, uint32_t size) { extern "C" void GX__CallDisplayList_80172f64(uint32_t listAddr, uint32_t nbytes) { if (nbytes == 0 || listAddr == 0) return; + // List bytes and the arrays it indexes are GPU-side reads, so they are read when the worker runs. + if (GxWorker::ShouldDefer()) { + EnsureAuroraFrameActive(); + GxWorker::Submit([=] { GX__CallDisplayList_80172f64(listAddr, nbytes); }); + return; + } try { const uint8_t* list = static_cast(GuestToHostPtr(listAddr, nbytes)); if (!list) return; diff --git a/runtime/src/hle/gx/gx_egg.cpp b/runtime/src/hle/gx/gx_egg.cpp index 8a9fd75..c5d254f 100644 --- a/runtime/src/hle/gx/gx_egg.cpp +++ b/runtime/src/hle/gx/gx_egg.cpp @@ -22,8 +22,8 @@ static void EGG__DrawGX__SetVtxState_HLE(uint32_t state) { case 0: setFmt(GX_VA_POS, GX_POS_XYZ, GX_S16, 0xE); setFmt(GX_VA_NRM, GX_NRM_XYZ, GX_S16, 0xE); - setArray(GX_VA_POS, 0x802574a0u, 6); - setArray(GX_VA_NRM, 0x802574e0u, 6); + setArray(GX_VA_POS, MKW_GADDR(802574a0), 6); + setArray(GX_VA_NRM, MKW_GADDR(802574e0), 6); setDesc(GX_VA_POS, GX_INDEX8); setDesc(GX_VA_NRM, GX_INDEX8); break; @@ -45,22 +45,22 @@ static void EGG__DrawGX__SetVtxState_HLE(uint32_t state) { if (state == 7) setDesc(GX_VA_TEX0, GX_DIRECT); setFmt(GX_VA_POS, GX_POS_XY, GX_S16, 0xE); setFmt(GX_VA_NRM, GX_NRM_XYZ, GX_S16, 0xE); if (state == 7) setFmt(GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); - setArray(GX_VA_POS, 0x80257520u, 4); setArray(GX_VA_NRM, 0x80388b80u, 6); + setArray(GX_VA_POS, MKW_GADDR(80257520), 4); setArray(GX_VA_NRM, MKW_GADDR(80388b80), 6); break; case 9: setDesc(GX_VA_POS, GX_INDEX8); setDesc(GX_VA_NRM, GX_INDEX8); setDesc(GX_VA_TEX0, GX_DIRECT); setFmt(GX_VA_POS, GX_POS_XYZ, GX_S16, 0xE); setFmt(GX_VA_NRM, GX_NRM_XYZ, GX_S16, 0xE); setFmt(GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); - setArray(GX_VA_POS, 0x80257540u, 6); setArray(GX_VA_NRM, 0x80388ba0u, 6); + setArray(GX_VA_POS, MKW_GADDR(80257540), 6); setArray(GX_VA_NRM, MKW_GADDR(80388ba0), 6); break; case 10: case 11: case 12: case 13: { const bool useAltPos = (state == 11 || state == 13); const bool useTex = (state == 10 || state == 11); setDesc(GX_VA_POS, GX_INDEX8); if (useTex) setDesc(GX_VA_TEX0, GX_INDEX8); - const uint32_t posBase = useAltPos ? 0x80388be0u : 0x80388bc0u; + const uint32_t posBase = useAltPos ? MKW_GADDR(80388be0) : MKW_GADDR(80388bc0); setArray(GX_VA_POS, posBase, 2); - if (useTex) setArray(GX_VA_TEX0, 0x80388be0u, 2); + if (useTex) setArray(GX_VA_TEX0, MKW_GADDR(80388be0), 2); setFmt(GX_VA_POS, GX_POS_XY, GX_U8, 0); if (useTex) setFmt(GX_VA_TEX0, GX_TEX_ST, GX_U8, 0); break; @@ -81,14 +81,20 @@ extern "C" void EGG__LightTexture__SetupTevFinish_HLE_8022e2bc(CpuContext* ctx) if (remainder > 0) { const GXColor black{0, 0, 0, 255}; while (remainder < stageCount) { - GXSetTevColor(static_cast(remainder + 1), black); - GXSetTevKColor(static_cast(remainder), black); + GxWorker::Run([remainder, black] { + GXSetTevColor(static_cast(remainder + 1), black); + GXSetTevKColor(static_cast(remainder), black); + }); ++remainder; } + const uint32_t kFogOriginDefault = MKW_GADDR(80388DD0); + const uint32_t kFogOriginMode2 = MKW_GADDR(80388DF4); + const uint32_t kFogSpan = MKW_GADDR(80388DE0); const uint32_t mode = Memory::Read32(self + 0x44); - const float origin = Memory::ReadFloat32(ctx->gpr[2] + ((mode == 2) ? -25004 : -25040)); - const float span = Memory::ReadFloat32(ctx->gpr[2] + -25024); + const float origin = + Memory::ReadFloat32((mode == 2) ? kFogOriginMode2 : kFogOriginDefault); + const float span = Memory::ReadFloat32(kFogSpan); const float end = static_cast(origin + span); const float lower = static_cast(origin - span); @@ -115,8 +121,8 @@ PPC_NATIVE_OVERRIDE_VOID(8022e2bc, EGG__LightTexture__SetupTevFinish_HLE_8022e2b // ============================================================================ extern "C" void EGG__AsyncDisplay__endRender_HLE_8020ff9c(CpuContext* ctx) { - uint32_t p = ctx->gpr[3]; ctx->gpr[3] = p; ctx->lr = 0x8020FF9C; - InvokeIndirectCpu(0x80219FB4u, ctx); - InvokeIndirectCpu(0x8016ED50u, ctx); + uint32_t p = ctx->gpr[3]; ctx->gpr[3] = p; ctx->lr = MKW_GADDR(8020FF9C); + InvokeIndirectCpu(MKW_GADDR(80219FB4), ctx); + InvokeIndirectCpu(MKW_GADDR(8016ED50), ctx); } PPC_NATIVE_OVERRIDE_VOID(8020FF9C, EGG__AsyncDisplay__endRender_HLE_8020ff9c, (CpuContext* ctx), (ctx)); diff --git a/runtime/src/hle/gx/gx_fatal_stubs.cpp b/runtime/src/hle/gx/gx_fatal_stubs.cpp index 42ca4e5..0baaa0f 100644 --- a/runtime/src/hle/gx/gx_fatal_stubs.cpp +++ b/runtime/src/hle/gx/gx_fatal_stubs.cpp @@ -28,7 +28,7 @@ namespace { // index sees the literal PPC_NATIVE_OVERRIDE_VOID invocation. Hiding it inside // this macro would leave the index unable to associate an address with the stub. #define GX_FATAL_STUB(addr, sym) \ - extern "C" void gx_stub_##addr(CpuContext* ctx) { (void)ctx; HaltGX(0x##addr, sym); } + extern "C" void gx_stub_##addr(CpuContext* ctx) { (void)ctx; HaltGX(MKW_GADDR(addr), sym); } GX_FATAL_STUB(8016b49c, "__GX__DefaultTexRegionCallback_8016b49c") PPC_NATIVE_OVERRIDE_VOID(8016b49c, gx_stub_8016b49c, (CpuContext* ctx), (ctx)); GX_FATAL_STUB(8016b590, "__GX__DefaultTlutRegionCallback_8016b590") PPC_NATIVE_OVERRIDE_VOID(8016b590, gx_stub_8016b590, (CpuContext* ctx), (ctx)); diff --git a/runtime/src/hle/gx/gx_fifo.cpp b/runtime/src/hle/gx/gx_fifo.cpp index a77e96e..108e4fd 100644 --- a/runtime/src/hle/gx/gx_fifo.cpp +++ b/runtime/src/hle/gx/gx_fifo.cpp @@ -490,9 +490,16 @@ void HleFifoWrite(u32 val, uint32_t sizeBytes) { const uint16_t vtxCount = ReadBE16(data + 1); const GXVtxFmt vtxFmt = static_cast(cmd & GX_VAT_MASK_CMD); const GXPrimitive prim = OpcodeToGXPrimitive(cmd); + if (vtxCount == 0) { + if (!consumeBytes(3, sink)) break; + continue; + } uint32_t rawVertexSize = 0; - if (TryGetRawDirectFifoVertexSize(vtxFmt, rawVertexSize)) { - const uint32_t packetBytes = 3u + static_cast(vtxCount) * rawVertexSize; + const uint32_t packetBytes = TryGetRawDirectFifoVertexSize(vtxFmt, rawVertexSize) + ? 3u + static_cast(vtxCount) * rawVertexSize + : 0u; + // A packet that cannot fit the buffer is streamed per vertex instead. + if (packetBytes != 0 && packetBytes <= g_hleGxState.fifoBytes.size()) { if (g_hleGxState.fifoByteCount < packetBytes) { break; } @@ -775,11 +782,25 @@ static bool WriteDisplayListBurst(const uint8_t* data, uint32_t sizeBytes) { return true; } +static void FifoWriteBurstImpl(const uint8_t* data, uint32_t sizeBytes); + extern "C" void GX_HLE_FIFO_WriteBurst(const uint8_t* data, uint32_t sizeBytes) { if (data == nullptr || sizeBytes == 0) { return; } + if (GxWorker::ShouldDefer()) { + EnsureAuroraFrameForFifo(); + GxWorker::FifoBurst(data, sizeBytes); + return; + } + FifoWriteBurstImpl(data, sizeBytes); +} +void GxWorkerReplayFifoWrite(uint32_t value, uint32_t sizeBytes) { HleFifoWrite(value, sizeBytes); } + +void GxWorkerReplayFifoBurst(const uint8_t* data, uint32_t sizeBytes) { FifoWriteBurstImpl(data, sizeBytes); } + +static void FifoWriteBurstImpl(const uint8_t* data, uint32_t sizeBytes) { if (IsDisplayListActive() && WriteDisplayListBurst(data, sizeBytes)) { return; } diff --git a/runtime/src/hle/gx/gx_frame.cpp b/runtime/src/hle/gx/gx_frame.cpp index 6df3885..78fd1cc 100644 --- a/runtime/src/hle/gx/gx_frame.cpp +++ b/runtime/src/hle/gx/gx_frame.cpp @@ -87,8 +87,54 @@ void BeginNextAuroraFrameWithRetry(std::chrono::milliseconds timeout) { ++s_beginExpiredLogCount; } +void EnsureAuroraFrameForFifo() { + // The game thread can't see where draws start in recorded FIFO bytes, so any write may begin the + // frame. A failed begin is only retried once the next frame is presented. + static int s_attemptedFrame = -1; + if (g_auroraFrameActive.load(std::memory_order_acquire) || s_attemptedFrame == g_gxFrameCount) { + return; + } + s_attemptedFrame = g_gxFrameCount; + UpdateAuroraAndProcessEvents(); + if (BeginAuroraFrame()) { + g_auroraFrameActive.store(true, std::memory_order_release); + } +} + void EnsureAuroraFrameActive() { + // The game thread begins frames before it records work for the GX worker. + if (GxWorker::OnWorker()) { + return; + } if (!g_auroraFrameActive.load(std::memory_order_acquire)) { BeginNextAuroraFrameWithRetry(); } } + +namespace { +// Whether the GX half of the current frame has begun, on either path. Inline frame calls only run +// after a sync, so the ring orders every access. +bool g_frameGxBegun = false; +} + +void SetAuroraFrameGxBegun(bool begun) { g_frameGxBegun = begun; } + +void GxWorkerBeginFrame() { + // gfx::begin_frame can briefly fail to map a staging buffer; retry like the inline path does. + const auto deadline = std::chrono::steady_clock::now() + std::chrono::milliseconds(100); + while (!(g_frameGxBegun = aurora_begin_frame_gx()) && std::chrono::steady_clock::now() < deadline) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + if (!g_frameGxBegun) { + RT_LOGF(RT_TAG_GX, "GX worker could not begin an aurora frame\n"); + } +} + +void GxWorkerEndFrame(AuroraImguiFrame* imgui) { + if (g_frameGxBegun) { + aurora_end_frame_gx(imgui); + } else { + aurora_release_imgui_frame(imgui); + } + g_frameGxBegun = false; +} diff --git a/runtime/src/hle/gx/gx_indirect.cpp b/runtime/src/hle/gx/gx_indirect.cpp index 7855f30..f8bb76c 100644 --- a/runtime/src/hle/gx/gx_indirect.cpp +++ b/runtime/src/hle/gx/gx_indirect.cpp @@ -5,22 +5,25 @@ // Indirect Texture Stages // ============================================================================ -extern "C" void GX__SetNumIndStages_80171b38(uint32_t n) { GXSetNumIndStages((u8)n); } +extern "C" void GX__SetNumIndStages_80171b38(uint32_t n) { + GX_DEFER_CALL(GX__SetNumIndStages_80171b38, n); GXSetNumIndStages((u8)n); } PPC_NATIVE_OVERRIDE_VOID(80171b38, GX__SetNumIndStages_80171b38, (uint32_t n), (n)); extern "C" void GX__SetIndTexOrder_80171a6c(uint32_t s, uint32_t c, uint32_t m) { + GX_DEFER_CALL(GX__SetIndTexOrder_80171a6c, s, c, m); GXSetIndTexOrder((GXIndTexStageID)s, (GXTexCoordID)(c==0xFFu?0:c), (GXTexMapID)(m==0xFFu?0:m)); } PPC_NATIVE_OVERRIDE_VOID(80171a6c, GX__SetIndTexOrder_80171a6c, (uint32_t s, uint32_t c, uint32_t m), (s, c, m)); extern "C" void GX__SetIndTexCoordScale_80171968(uint32_t s, uint32_t ss, uint32_t ts) { + GX_DEFER_CALL(GX__SetIndTexCoordScale_80171968, s, ss, ts); GXSetIndTexCoordScale((GXIndTexStageID)s, (GXIndTexScale)ss, (GXIndTexScale)ts); } PPC_NATIVE_OVERRIDE_VOID(80171968, GX__SetIndTexCoordScale_80171968, (uint32_t s, uint32_t ss, uint32_t ts), (s, ss, ts)); extern "C" void GX__SetIndTexMtx_80171814(uint32_t id, uint32_t ma, uint32_t se) { float m[6]; for(int i=0; i<6; ++i) m[i]=Memory::ReadFloat32(ma+i*4); - GXSetIndTexMtx((GXIndTexMtxID)id, m, (s8)se); + GxWorker::Run([id, se, mtx = std::to_array(m)]() mutable { GXSetIndTexMtx((GXIndTexMtxID)id, mtx.data(), (s8)se); }); } PPC_NATIVE_OVERRIDE_VOID(80171814, GX__SetIndTexMtx_80171814, (uint32_t id, uint32_t ma, uint32_t se), (id, ma, se)); @@ -28,16 +31,19 @@ PPC_NATIVE_OVERRIDE_VOID(80171814, GX__SetIndTexMtx_80171814, (uint32_t id, uint // TEV Indirect Texture Control // ============================================================================ -extern "C" void GX__SetTevDirect_80171b58(uint32_t s) { GXSetTevDirect((GXTevStageID)s); } +extern "C" void GX__SetTevDirect_80171b58(uint32_t s) { + GX_DEFER_CALL(GX__SetTevDirect_80171b58, s); GXSetTevDirect((GXTevStageID)s); } PPC_NATIVE_OVERRIDE_VOID(80171b58, GX__SetTevDirect_80171b58, (uint32_t s), (s)); extern "C" void GX__SetTevIndWarp_80171ba0(uint32_t ts, uint32_t is, uint32_t so, uint32_t rm, uint32_t ms) { + GX_DEFER_CALL(GX__SetTevIndWarp_80171ba0, ts, is, so, rm, ms); GXSetTevIndWarp((GXTevStageID)std::min(ts, 15u), (GXIndTexStageID)std::min(is, 3u), (GXBool)so, (GXBool)rm, (GXIndTexMtxID)ms); } PPC_NATIVE_OVERRIDE_VOID(80171ba0, GX__SetTevIndWarp_80171ba0, (uint32_t ts, uint32_t is, uint32_t so, uint32_t rm, uint32_t ms), (ts, is, so, rm, ms)); extern "C" void GX__SetTevIndirect_801717ac(uint32_t ts, uint32_t is, uint32_t f, uint32_t bs, uint32_t ms, uint32_t ws, uint32_t wt, uint32_t ap, uint32_t il, uint32_t as) { + GX_DEFER_CALL(GX__SetTevIndirect_801717ac, ts, is, f, bs, ms, ws, wt, ap, il, as); GXSetTevIndirect((GXTevStageID)std::min(ts,15u), (GXIndTexStageID)std::min(is,3u), (GXIndTexFormat)f, (GXIndTexBiasSel)bs, (GXIndTexMtxID)ms, (GXIndTexWrap)ws, (GXIndTexWrap)wt, (GXBool)ap, (GXBool)il, (GXIndTexAlphaSel)as); diff --git a/runtime/src/hle/gx/gx_init.cpp b/runtime/src/hle/gx/gx_init.cpp index d1cbaf4..edf6f9c 100644 --- a/runtime/src/hle/gx/gx_init.cpp +++ b/runtime/src/hle/gx/gx_init.cpp @@ -24,8 +24,9 @@ extern "C" GXFifoObj* GXInit(void* base, u32 size); */ extern "C" uint32_t GX__Init_8016b850(uint32_t fifoBase, uint32_t fifoSize) { - constexpr uint32_t kFifoObjAddr = 0x80343740u; - constexpr uint32_t kGXDataAddr = 0x803437C0u; + GX_SYNC_INLINE(); + const uint32_t kFifoObjAddr = MKW_GADDR(80343740); + const uint32_t kGXDataAddr = MKW_GADDR(803437C0); constexpr uint32_t kGXDataSize = 0x600u; GXInit(GuestToHostPtr(fifoBase, fifoSize), fifoSize); @@ -77,7 +78,6 @@ extern "C" uint32_t GX__Init_8016b850(uint32_t fifoBase, uint32_t fifoSize) } catch (...) {} __GX__SetTmemConfig_80171458(2); - RT_LOGF(RT_TAG_GX, "GX initialized, FIFO at 0x%08X (base=0x%08X size=0x%08X)\n", kFifoObjAddr, fifoBase, fifoSize); @@ -91,30 +91,30 @@ PPC_NATIVE_OVERRIDE(8016b850, GX__Init_8016b850, uint32_t, (uint32_t fifoBase, u extern "C" void GX__InitFifoBase_8016c7c8(uint32_t fa, uint32_t ba, uint32_t s) { GXInitFifoBase((GXFifoObj*)GuestToHostPtr(fa, sizeof(GXFifoObj)), GuestToHostPtr(ba, s), s); } -extern "C" void GX__SetCPUFifo_8016c94c(uint32_t fa) { GXSetCPUFifo((GXFifoObj*)GuestToHostPtr(fa, sizeof(GXFifoObj))); } +extern "C" void GX__SetCPUFifo_8016c94c(uint32_t fa) { GX_SYNC_INLINE(); GXSetCPUFifo((GXFifoObj*)GuestToHostPtr(fa, sizeof(GXFifoObj))); } PPC_NATIVE_OVERRIDE_VOID(8016c94c, GX__SetCPUFifo_8016c94c, (uint32_t fa), (fa)); -extern "C" void GX__SetGPFifo_8016cb2c(uint32_t fa) { GXSetGPFifo((GXFifoObj*)GuestToHostPtr(fa, sizeof(GXFifoObj))); } +extern "C" void GX__SetGPFifo_8016cb2c(uint32_t fa) { GX_SYNC_INLINE(); GXSetGPFifo((GXFifoObj*)GuestToHostPtr(fa, sizeof(GXFifoObj))); } PPC_NATIVE_OVERRIDE_VOID(8016cb2c, GX__SetGPFifo_8016cb2c, (uint32_t fa), (fa)); -extern "C" void __GX__SaveFifo_8016cdbc(uint32_t fa) { GXSaveCPUFifo((GXFifoObj*)GuestToHostPtr(fa, sizeof(GXFifoObj))); } +extern "C" void __GX__SaveFifo_8016cdbc(uint32_t fa) { GX_SYNC_INLINE(); GXSaveCPUFifo((GXFifoObj*)GuestToHostPtr(fa, sizeof(GXFifoObj))); } PPC_NATIVE_OVERRIDE_VOID(8016cdbc, __GX__SaveFifo_8016cdbc, (uint32_t fa), (fa)); -extern "C" void GX__GetCPUFifo_8016cf10(uint32_t fa) { auto* d=(GXFifoObj*)GuestToHostPtr(fa, sizeof(GXFifoObj)); auto* s=GXGetCPUFifo(); if(d&&s) std::memcpy(d,s,sizeof(GXFifoObj)); } +extern "C" void GX__GetCPUFifo_8016cf10(uint32_t fa) { GX_SYNC_INLINE(); auto* d=(GXFifoObj*)GuestToHostPtr(fa, sizeof(GXFifoObj)); auto* s=GXGetCPUFifo(); if(d&&s) std::memcpy(d,s,sizeof(GXFifoObj)); } PPC_NATIVE_OVERRIDE_VOID(8016cf10, GX__GetCPUFifo_8016cf10, (uint32_t fa), (fa)); extern "C" void __GX__FifoInit_8016d180() { constexpr uint32_t kCpInterruptId = 0x11u; constexpr uint32_t kCpInterruptMask = 0x4000u; - constexpr uint32_t kCpInterruptHandlerAddr = 0x8016c668u; - constexpr uint32_t kGxCurrentThreadPtrAddr = 0x803867c4u; - constexpr uint32_t kGxThreadQueueAddr = 0x803867c0u; - constexpr uint32_t kCpuFifoObjAddr = 0x80343de4u; - constexpr uint32_t kGpFifoObjAddr = 0x80343dc0u; + const uint32_t kCpInterruptHandlerAddr = MKW_GADDR(8016c668); + const uint32_t kGxCurrentThreadPtrAddr = MKW_GADDR(803867c4); + const uint32_t kGxThreadQueueAddr = MKW_GADDR(803867c0); + const uint32_t kCpuFifoObjAddr = MKW_GADDR(80343de4); + const uint32_t kGpFifoObjAddr = MKW_GADDR(80343dc0); constexpr size_t kFifoObjSize = 0x24u; - constexpr uint32_t kFifoWrapFlagAddr = 0x803867b0u; - constexpr uint32_t kFifoWrapFlag2Addr = 0x803867b1u; + const uint32_t kFifoWrapFlagAddr = MKW_GADDR(803867b0); + const uint32_t kFifoWrapFlag2Addr = MKW_GADDR(803867b1); __OSSetInterruptHandler_801a65f8_hle(kCpInterruptId, kCpInterruptHandlerAddr); __OSUnmaskInterrupts_801a69bc_hle(kCpInterruptMask); @@ -137,13 +137,14 @@ extern "C" void __GX__FifoInit_8016d180() extern "C" void __GX__PEInit_8016ee14() { + GX_SYNC_INLINE(); constexpr uint32_t kPeTokenInterruptId = 0x12u; constexpr uint32_t kPeFinishInterruptId = 0x13u; constexpr uint32_t kPeTokenInterruptMask = 0x1000u; constexpr uint32_t kPeFinishInterruptMask = 0x2000u; - constexpr uint32_t kPeTokenHandlerAddr = 0x8016eccc; - constexpr uint32_t kPeFinishHandlerAddr = 0x8016ed94; - constexpr uint32_t kPeThreadQueueAddr = 0x803867d0u; + const uint32_t kPeTokenHandlerAddr = MKW_GADDR(8016eccc); + const uint32_t kPeFinishHandlerAddr = MKW_GADDR(8016ed94); + const uint32_t kPeThreadQueueAddr = MKW_GADDR(803867d0); __OSSetInterruptHandler_801a65f8_hle(kPeTokenInterruptId, kPeTokenHandlerAddr); __OSSetInterruptHandler_801a65f8_hle(kPeFinishInterruptId, kPeFinishHandlerAddr); @@ -165,35 +166,51 @@ PPC_NATIVE_OVERRIDE_VOID(8016ee14, __GX__PEInit_8016ee14, (), ()); // Display List Recording // ============================================================================ +namespace { +// Display-list recording runs inline: the guest list buffer and its size are needed synchronously. +bool g_dlInline = false; +} + extern "C" void GX__BeginDisplayList_80172e00(uint32_t la, uint32_t s) { + if (!g_dlInline) { + GxWorker::BeginInline(); + g_dlInline = true; + } try { uint32_t gd = Memory::Read32(kGXDataPtrAddr); if (!gd) return; if (Memory::Read32(gd + 0x5FCu)) GX__SetDirtyState_8016ee78(); - if (Memory::Read8(gd + 0x5F9u)) std::memcpy(Memory::GetPointer(0x80344110, 0x600), Memory::GetPointer(gd, 0x600), 0x600); - Memory::Write32(0x80344094, la + s - 4u); - Memory::Write32(0x803440AC, 0); - Memory::Write32(0x80344090, la); - Memory::Write32(0x80344098, s); - Memory::Write32(0x803440A4, la); - Memory::Write32(0x803440A8, la); + if (Memory::Read8(gd + 0x5F9u)) std::memcpy(Memory::GetPointer(MKW_GADDR(80344110), 0x600), Memory::GetPointer(gd, 0x600), 0x600); + Memory::Write32(MKW_GADDR(80344094), la + s - 4u); + Memory::Write32(MKW_GADDR(803440AC), 0); + Memory::Write32(MKW_GADDR(80344090), la); + Memory::Write32(MKW_GADDR(80344098), s); + Memory::Write32(MKW_GADDR(803440A4), la); + Memory::Write32(MKW_GADDR(803440A8), la); Memory::Write8(gd + 0x5F8u, 1u); // Mirror the guest fifo-object fields the FIFO write path consumes so // HleFifoWrite never has to read them back out of guest memory. BeginDisplayListRecording(la, s); GXFlush(); - GX__GetCPUFifo_8016cf10(0x80344710); - GX__SetCPUFifo_8016c94c(0x80344090); + GX__GetCPUFifo_8016cf10(MKW_GADDR(80344710)); + GX__SetCPUFifo_8016c94c(MKW_GADDR(80344090)); } catch (...) {} } PPC_NATIVE_OVERRIDE_VOID(80172e00, GX__BeginDisplayList_80172e00, (uint32_t la, uint32_t s), (la, s)); +static void EndDisplayListInline() { + if (g_dlInline) { + g_dlInline = false; + GxWorker::EndInline(); + } +} + extern "C" uint32_t GX__EndDisplayList_80172eb4() { try { GXFlush(); - GX__GetCPUFifo_8016cf10(0x80344090); + GX__GetCPUFifo_8016cf10(MKW_GADDR(80344090)); const uint8_t wrapped = Memory::Read8(kDlFifoAddr + kDlWrapFlagOffset); - GX__SetCPUFifo_8016c94c(0x80344710); + GX__SetCPUFifo_8016c94c(MKW_GADDR(80344710)); const uint32_t gd = Memory::Read32(kGXDataPtrAddr); if (gd) { @@ -201,7 +218,7 @@ extern "C" uint32_t GX__EndDisplayList_80172eb4() { const int32_t interruptLevel = OS__DisableInterrupts_801a65ac(); const uint32_t savedWord8 = Memory::Read32(gd + 0x08u); std::memcpy(Memory::GetPointer(gd, 0x600), - Memory::GetPointer(0x80344110, 0x600), + Memory::GetPointer(MKW_GADDR(80344110), 0x600), 0x600); Memory::Write32(gd + 0x08u, savedWord8); OS__RestoreInterrupts_801a65d4(interruptLevel); @@ -214,12 +231,14 @@ extern "C" uint32_t GX__EndDisplayList_80172eb4() { // "inactive" whenever the GXData pointer was null, so recording must // stop here even on the gd == 0 path. EndDisplayListRecording(); + EndDisplayListInline(); return wrapped == 0 ? Memory::Read32(kDlCountAddr) : 0; } catch (...) { // Leaving the shadow active would silently swallow every subsequent // FIFO write into a dead list. EndDisplayListRecording(); + EndDisplayListInline(); return 0; } } @@ -229,5 +248,8 @@ PPC_NATIVE_OVERRIDE(80172EB4, GX__EndDisplayList_80172eb4, uint32_t, (), ()); // Flush // ============================================================================ -extern "C" void GX__Flush_8016e654() { GXFlush(); } +extern "C" void GX__Flush_8016e654() { + GX_DEFER_CALL0(GX__Flush_8016e654); + GXFlush(); +} PPC_NATIVE_OVERRIDE_VOID(8016e654, GX__Flush_8016e654, (), ()); diff --git a/runtime/src/hle/gx/gx_internal.h b/runtime/src/hle/gx/gx_internal.h index 8656dba..b8270a9 100644 --- a/runtime/src/hle/gx/gx_internal.h +++ b/runtime/src/hle/gx/gx_internal.h @@ -1,6 +1,7 @@ #pragma once #include "hle_stubs.h" +#include "guest_abi/guest_region.h" #include "memory.h" #include "gx_guest_write.h" #include "ppc_runtime.h" @@ -34,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -54,13 +56,13 @@ bool is_offscreen() noexcept; } // --- Constants --- -constexpr uint32_t kGXDataPtrAddr = 0x803886C8; -constexpr uint32_t kDlFifoAddr = 0x80344090; -constexpr uint32_t kDlWritePtrAddr = 0x803440A4; -constexpr uint32_t kDlCountAddr = 0x803440AC; +const uint32_t kGXDataPtrAddr = MKW_GADDR(803886C8); +const uint32_t kDlFifoAddr = MKW_GADDR(80344090); +const uint32_t kDlWritePtrAddr = MKW_GADDR(803440A4); +const uint32_t kDlCountAddr = MKW_GADDR(803440AC); constexpr uint32_t kDlWrapFlagOffset = 0x20; constexpr uint32_t kMaxTluts = 20; -constexpr uint32_t kGxDrawDoneFlagAddr = 0x803867d8; +const uint32_t kGxDrawDoneFlagAddr = MKW_GADDR(803867d8); // --- External Declarations --- extern "C" void GXInitTexObjTlut(GXTexObj* obj, u32 tlut); @@ -300,6 +302,9 @@ void EndDisplayListRecording(); void WriteDisplayListData(uint32_t val, uint32_t sizeBytes); void BeginNextAuroraFrameWithRetry(std::chrono::milliseconds timeout = std::chrono::milliseconds(100)); void EnsureAuroraFrameActive(); +void EnsureAuroraFrameForFifo(); +// Array base/stride as last set through GXSetArray on the game thread. +bool ApiVtxArray(uint32_t attr, uint32_t& base, uint32_t& stride); GXColor DecodeGxColor(uint32_t colorWord); void WriteGuestFloat(uint32_t addr, float value, const char* label = nullptr); @@ -342,6 +347,17 @@ bool ValidateTlutData(uint32_t objAddr, const TlutObjMeta& meta); TexObjMeta& GetTexObjMeta(uint32_t addr); TexObjMeta ExtractTexObjMetaFromGuest(uint32_t addr); bool TryGetOrExtractTexObjMeta(uint32_t addr, TexObjMeta& outMeta); + +// Guest GXTexObj bytes captured on the game thread; while a scope is active on a thread, texobj +// decoding for that address reads the captured bytes instead of live guest memory. +using TexObjBytes = std::array; +TexObjBytes CaptureTexObjBytes(uint32_t addr); +struct TexObjSnapshotScope { + TexObjSnapshotScope(uint32_t addr, const TexObjBytes& bytes) noexcept; + ~TexObjSnapshotScope(); + TexObjSnapshotScope(const TexObjSnapshotScope&) = delete; + TexObjSnapshotScope& operator=(const TexObjSnapshotScope&) = delete; +}; TlutObjMeta& GetTlutObjMeta(uint32_t addr); GXTexObj* GetHostTexObj(uint32_t addr); GXTexObj* TryGetHostTexObj(uint32_t addr); diff --git a/runtime/src/hle/gx/gx_lighting.cpp b/runtime/src/hle/gx/gx_lighting.cpp index 1b1d392..3b186cf 100644 --- a/runtime/src/hle/gx/gx_lighting.cpp +++ b/runtime/src/hle/gx/gx_lighting.cpp @@ -66,7 +66,7 @@ extern "C" void GX__LoadLightObjImm_80170320(uint32_t la, uint32_t lid) { if (!ValidateGuestLightObj(la, "GXLoadLightObjImm")) return; GXLightObj host{}; InitializeHostLightFromGuest(host, la); - GXLoadLightObjImm(&host, static_cast(lid)); + GxWorker::Run([host, lid]() mutable { GXLoadLightObjImm(&host, static_cast(lid)); }); } PPC_NATIVE_OVERRIDE_VOID(80170320, GX__LoadLightObjImm_80170320, (uint32_t la, uint32_t lid), (la, lid)); @@ -77,21 +77,23 @@ PPC_NATIVE_OVERRIDE_VOID(80170320, GX__LoadLightObjImm_80170320, (uint32_t la, u extern "C" void GX__SetChanAmbColor_8017039c(uint32_t c, uint32_t cp) { EnsureAuroraFrameActive(); GXColor color = DecodeGxColor(Memory::Read32(cp)); - GXSetChanAmbColor((GXChannelID)c, color); + GxWorker::Run([c, color] { GXSetChanAmbColor((GXChannelID)c, color); }); } PPC_NATIVE_OVERRIDE_VOID(8017039c, GX__SetChanAmbColor_8017039c, (uint32_t c, uint32_t cp), (c, cp)); extern "C" void GX__SetChanMatColor_80170474(uint32_t c, uint32_t cp) { EnsureAuroraFrameActive(); GXColor color = DecodeGxColor(Memory::Read32(cp)); - GXSetChanMatColor((GXChannelID)c, color); + GxWorker::Run([c, color] { GXSetChanMatColor((GXChannelID)c, color); }); } PPC_NATIVE_OVERRIDE_VOID(80170474, GX__SetChanMatColor_80170474, (uint32_t c, uint32_t cp), (c, cp)); -extern "C" void GX__SetNumChans_8017054c(uint32_t n) { GXSetNumChans((u8)n); } +extern "C" void GX__SetNumChans_8017054c(uint32_t n) { + GX_DEFER_CALL(GX__SetNumChans_8017054c, n); GXSetNumChans((u8)n); } PPC_NATIVE_OVERRIDE_VOID(8017054c, GX__SetNumChans_8017054c, (uint32_t n), (n)); extern "C" void GX__SetChanCtrl_80170570(uint32_t ch, uint32_t en, uint32_t as, uint32_t ms, uint32_t lm, uint32_t df, uint32_t af) { + GX_DEFER_CALL(GX__SetChanCtrl_80170570, ch, en, as, ms, lm, df, af); GXSetChanCtrl((GXChannelID)ch, en!=0, (GXColorSrc)as, (GXColorSrc)ms, lm, (GXDiffuseFn)df, (GXAttnFn)af); } PPC_NATIVE_OVERRIDE_VOID(80170570, GX__SetChanCtrl_80170570, (uint32_t ch, uint32_t en, uint32_t as, uint32_t ms, uint32_t lm, uint32_t df, uint32_t af), (ch, en, as, ms, lm, df, af)); diff --git a/runtime/src/hle/gx/gx_objects.cpp b/runtime/src/hle/gx/gx_objects.cpp index ce4f368..645658d 100644 --- a/runtime/src/hle/gx/gx_objects.cpp +++ b/runtime/src/hle/gx/gx_objects.cpp @@ -110,17 +110,65 @@ bool g_tlutObjBoundsDirty = true; // word3 data address (<<5), word4 user data, word5 texFmt, word6 tlut, byte 0x1F flags. Exact // bit positions are decoded inline below. +namespace { +thread_local uint32_t t_texObjSnapshotAddr = 0; +thread_local const uint8_t* t_texObjSnapshotBytes = nullptr; + +const uint8_t* TexObjSnapshotFor(uint32_t addr) noexcept { + return (t_texObjSnapshotBytes != nullptr && addr == t_texObjSnapshotAddr) ? t_texObjSnapshotBytes : nullptr; +} + +uint32_t ReadTexObj32(uint32_t addr, uint32_t offset) { + if (const uint8_t* bytes = TexObjSnapshotFor(addr)) return BigEndian::Read32(bytes + offset); + return Memory::Read32(addr + offset); +} + +uint8_t ReadTexObj8(uint32_t addr, uint32_t offset) { + if (const uint8_t* bytes = TexObjSnapshotFor(addr)) return bytes[offset]; + return Memory::Read8(addr + offset); +} + +uint64_t ReadTexObj64(uint32_t addr, uint32_t offset) { + if (const uint8_t* bytes = TexObjSnapshotFor(addr)) { + return (static_cast(BigEndian::Read32(bytes + offset)) << 32) | BigEndian::Read32(bytes + offset + 4); + } + return Memory::Read64(addr + offset); +} +} // namespace + +TexObjBytes CaptureTexObjBytes(uint32_t addr) { + TexObjBytes bytes{}; + for (uint32_t offset = 0; offset < bytes.size(); offset += 4) { + const uint32_t word = Memory::Read32(addr + offset); + bytes[offset + 0] = static_cast(word >> 24); + bytes[offset + 1] = static_cast(word >> 16); + bytes[offset + 2] = static_cast(word >> 8); + bytes[offset + 3] = static_cast(word); + } + return bytes; +} + +TexObjSnapshotScope::TexObjSnapshotScope(uint32_t addr, const TexObjBytes& bytes) noexcept { + t_texObjSnapshotAddr = addr; + t_texObjSnapshotBytes = bytes.data(); +} + +TexObjSnapshotScope::~TexObjSnapshotScope() { + t_texObjSnapshotAddr = 0; + t_texObjSnapshotBytes = nullptr; +} + TexObjMeta ExtractTexObjMetaFromGuest(uint32_t addr) { TexObjMeta meta{}; try { - uint32_t word0 = Memory::Read32(addr + 0x00); - uint32_t word1 = Memory::Read32(addr + 0x04); - uint32_t word2 = Memory::Read32(addr + 0x08); - uint32_t word3 = Memory::Read32(addr + 0x0C); - uint32_t word4 = Memory::Read32(addr + 0x10); - uint32_t word5 = Memory::Read32(addr + 0x14); - uint32_t word6 = Memory::Read32(addr + 0x18); - uint8_t flags = Memory::Read8(addr + 0x1F); + uint32_t word0 = ReadTexObj32(addr, 0x00); + uint32_t word1 = ReadTexObj32(addr, 0x04); + uint32_t word2 = ReadTexObj32(addr, 0x08); + uint32_t word3 = ReadTexObj32(addr, 0x0C); + uint32_t word4 = ReadTexObj32(addr, 0x10); + uint32_t word5 = ReadTexObj32(addr, 0x14); + uint32_t word6 = ReadTexObj32(addr, 0x18); + uint8_t flags = ReadTexObj8(addr, 0x1F); meta.wrapS = word0 & 0x3; meta.wrapT = (word0 >> 2) & 0x3; @@ -449,10 +497,10 @@ TexObjMeta MergeGuestTexObjMeta(const TexObjMeta& cached, const TexObjMeta& gues // caller must treat the shadow as absent) when the address is unreadable. bool ReadTexObjShadow(uint32_t addr, uint64_t (&out)[4]) noexcept { try { - out[0] = Memory::Read64(addr + 0x00); - out[1] = Memory::Read64(addr + 0x08); - out[2] = Memory::Read64(addr + 0x10); - out[3] = Memory::Read64(addr + 0x18); + out[0] = ReadTexObj64(addr, 0x00); + out[1] = ReadTexObj64(addr, 0x08); + out[2] = ReadTexObj64(addr, 0x10); + out[3] = ReadTexObj64(addr, 0x18); } catch (...) { return false; } @@ -642,8 +690,11 @@ extern "C" void GxNotifyGuestRamDmaWrite(uint32_t addr, uint32_t size) { if (size == 0) { return; } - MarkTexObjsDirtyForRange(addr, size); - MarkTlutObjsDirtyForRange(addr, size); + // Ordered with recorded GX work: retiring EFB copy textures emits aurora commands. + GxWorker::Run([addr, size] { + MarkTexObjsDirtyForRange(addr, size); + MarkTlutObjsDirtyForRange(addr, size); + }); GxNotifyDisplayListMemoryWrite(addr, size); } diff --git a/runtime/src/hle/gx/gx_pixel.cpp b/runtime/src/hle/gx/gx_pixel.cpp index 8866ab1..68182a5 100644 --- a/runtime/src/hle/gx/gx_pixel.cpp +++ b/runtime/src/hle/gx/gx_pixel.cpp @@ -6,17 +6,20 @@ // ============================================================================ extern "C" void GX__SetBlendMode_8017277c(uint32_t t, uint32_t s, uint32_t d, uint32_t op) { + GX_DEFER_CALL(GX__SetBlendMode_8017277c, t, s, d, op); GXSetBlendMode(static_cast(t), static_cast(s), static_cast(d), static_cast(op)); } PPC_NATIVE_OVERRIDE_VOID(8017277c, GX__SetBlendMode_8017277c, (uint32_t t, uint32_t s, uint32_t d, uint32_t op), (t, s, d, op)); extern "C" void GX__SetColorUpdate_801727cc(uint32_t en) { + GX_DEFER_CALL(GX__SetColorUpdate_801727cc, en); GXSetColorUpdate(static_cast(en)); } PPC_NATIVE_OVERRIDE_VOID(801727cc, GX__SetColorUpdate_801727cc, (uint32_t en), (en)); extern "C" void GX__SetAlphaUpdate_801727f8(uint32_t en) { + GX_DEFER_CALL(GX__SetAlphaUpdate_801727f8, en); GXSetAlphaUpdate(static_cast(en)); } PPC_NATIVE_OVERRIDE_VOID(801727f8, GX__SetAlphaUpdate_801727f8, (uint32_t en), (en)); @@ -26,11 +29,13 @@ PPC_NATIVE_OVERRIDE_VOID(801727f8, GX__SetAlphaUpdate_801727f8, (uint32_t en), ( // ============================================================================ extern "C" void GX__SetZMode_80172824(uint32_t ce, uint32_t f, uint32_t ue) { + GX_DEFER_CALL(GX__SetZMode_80172824, ce, f, ue); GXSetZMode(static_cast(ce), static_cast(f), static_cast(ue)); } PPC_NATIVE_OVERRIDE_VOID(80172824, GX__SetZMode_80172824, (uint32_t ce, uint32_t f, uint32_t ue), (ce, f, ue)); extern "C" void GX__SetZCompLoc_80172858(uint32_t bt) { + GX_DEFER_CALL(GX__SetZCompLoc_80172858, bt); GXSetZCompLoc(static_cast(bt)); } PPC_NATIVE_OVERRIDE_VOID(80172858, GX__SetZCompLoc_80172858, (uint32_t bt), (bt)); @@ -40,16 +45,19 @@ PPC_NATIVE_OVERRIDE_VOID(80172858, GX__SetZCompLoc_80172858, (uint32_t bt), (bt) // ============================================================================ extern "C" void GX__SetPixelFmt_80172888(uint32_t pf, uint32_t zf) { + GX_DEFER_CALL(GX__SetPixelFmt_80172888, pf, zf); GXSetPixelFmt(static_cast(pf), static_cast(zf)); } PPC_NATIVE_OVERRIDE_VOID(80172888, GX__SetPixelFmt_80172888, (uint32_t pf, uint32_t zf), (pf, zf)); extern "C" void GX__SetDither_80172930(uint32_t d) { + GX_DEFER_CALL(GX__SetDither_80172930, d); GXSetDither(static_cast(d)); } PPC_NATIVE_OVERRIDE_VOID(80172930, GX__SetDither_80172930, (uint32_t d), (d)); extern "C" void GX__SetDstAlpha_8017295c(uint32_t en, uint32_t a) { + GX_DEFER_CALL(GX__SetDstAlpha_8017295c, en, a); GXSetDstAlpha(static_cast(en), static_cast(a)); } PPC_NATIVE_OVERRIDE_VOID(8017295c, GX__SetDstAlpha_8017295c, (uint32_t en, uint32_t a), (en, a)); @@ -59,17 +67,20 @@ PPC_NATIVE_OVERRIDE_VOID(8017295c, GX__SetDstAlpha_8017295c, (uint32_t en, uint3 // ============================================================================ extern "C" void GX__SetFog_801722cc(uint32_t t, float sz, float ez, float nz, float fz, uint32_t cp) { - GXSetFog((GXFogType)t, sz, ez, nz, fz, DecodeGxColor(Memory::Read32(cp))); + const GXColor color = DecodeGxColor(Memory::Read32(cp)); + GxWorker::Run([=] { GXSetFog((GXFogType)t, sz, ez, nz, fz, color); }); } PPC_NATIVE_OVERRIDE_VOID(801722cc, GX__SetFog_801722cc, (uint32_t t, float sz, float ez, float nz, float fz, uint32_t cp), (t, sz, ez, nz, fz, cp)); extern "C" void GX__SetAlphaCompare_80172088(uint32_t c0, uint32_t r0, uint32_t op, uint32_t c1, uint32_t r1) { + GX_DEFER_CALL(GX__SetAlphaCompare_80172088, c0, r0, op, c1, r1); g_alphaCompareValid = true; GXSetAlphaCompare((GXCompare)c0, (u8)r0, (GXAlphaOp)op, (GXCompare)c1, (u8)r1); } PPC_NATIVE_OVERRIDE_VOID(80172088, GX__SetAlphaCompare_80172088, (uint32_t c0, uint32_t r0, uint32_t op, uint32_t c1, uint32_t r1), (c0, r0, op, c1, r1)); -extern "C" void GX__SetZTexture_801720c0(uint32_t op, uint32_t f, uint32_t b) { GXSetZTexture((GXZTexOp)op, (GXTexFmt)f, b); } +extern "C" void GX__SetZTexture_801720c0(uint32_t op, uint32_t f, uint32_t b) { + GX_DEFER_CALL(GX__SetZTexture_801720c0, op, f, b); GXSetZTexture((GXZTexOp)op, (GXTexFmt)f, b); } PPC_NATIVE_OVERRIDE_VOID(801720c0, GX__SetZTexture_801720c0, (uint32_t op, uint32_t f, uint32_t b), (op, f, b)); // ============================================================================ @@ -77,12 +88,15 @@ PPC_NATIVE_OVERRIDE_VOID(801720c0, GX__SetZTexture_801720c0, (uint32_t op, uint3 // ============================================================================ extern "C" void GX__SetCullMode_8016f3b8(uint32_t m) { + GX_DEFER_CALL(GX__SetCullMode_8016f3b8, m); GXSetCullMode(static_cast(m)); } PPC_NATIVE_OVERRIDE_VOID(8016f3b8, GX__SetCullMode_8016f3b8, (uint32_t m), (m)); -extern "C" void GX__SetCoPlanar_8016f3e0(uint32_t en) { GXSetCoPlanar((GXBool)en); } +extern "C" void GX__SetCoPlanar_8016f3e0(uint32_t en) { + GX_DEFER_CALL(GX__SetCoPlanar_8016f3e0, en); GXSetCoPlanar((GXBool)en); } PPC_NATIVE_OVERRIDE_VOID(8016f3e0, GX__SetCoPlanar_8016f3e0, (uint32_t en), (en)); -extern "C" void GX__SetClipMode_8017351c(uint32_t m) { GXSetClipMode((GXClipMode)m); } +extern "C" void GX__SetClipMode_8017351c(uint32_t m) { + GX_DEFER_CALL(GX__SetClipMode_8017351c, m); GXSetClipMode((GXClipMode)m); } PPC_NATIVE_OVERRIDE_VOID(8017351c, GX__SetClipMode_8017351c, (uint32_t m), (m)); diff --git a/runtime/src/hle/gx/gx_stubs.cpp b/runtime/src/hle/gx/gx_stubs.cpp index bba6585..edbafdc 100644 --- a/runtime/src/hle/gx/gx_stubs.cpp +++ b/runtime/src/hle/gx/gx_stubs.cpp @@ -7,14 +7,23 @@ extern "C" void __GXSetSUTexRegs(); // FIFO Write Helpers // ============================================================================ -extern "C" void GX_HLE_FIFO_WriteFloat(float val) { - u32 raw; std::memcpy(&raw, &val, 4); - try { HleFifoWrite(raw, 4); } catch (...) { RT_LOGF(RT_TAG_GX, "FIFO write float failed\n"); } +static void FifoWrite(u32 val, uint32_t sizeBytes) { + if (GxWorker::ShouldDefer()) { + EnsureAuroraFrameForFifo(); + GxWorker::FifoWrite(val, sizeBytes); + return; + } + HleFifoWrite(val, sizeBytes); } -extern "C" void GX_HLE_FIFO_Write32(uint32_t val) { HleFifoWrite(val, 4); } -extern "C" void GX_HLE_FIFO_Write16(uint16_t val) { HleFifoWrite(static_cast(val), 2); } -extern "C" void GX_HLE_FIFO_Write8(uint8_t val) { HleFifoWrite(static_cast(val), 1); } +extern "C" void GX_HLE_FIFO_WriteFloat(float val) { + u32 raw; std::memcpy(&raw, &val, 4); + try { FifoWrite(raw, 4); } catch (...) { RT_LOGF(RT_TAG_GX, "FIFO write float failed\n"); } +} + +extern "C" void GX_HLE_FIFO_Write32(uint32_t val) { FifoWrite(val, 4); } +extern "C" void GX_HLE_FIFO_Write16(uint16_t val) { FifoWrite(static_cast(val), 2); } +extern "C" void GX_HLE_FIFO_Write8(uint8_t val) { FifoWrite(static_cast(val), 1); } extern "C" void GX__SetDrawSync_8016ed08(uint32_t token) { (void)token; @@ -37,6 +46,7 @@ extern "C" void GX__FinishInterruptHandler_8016ed94() { PPC_NATIVE_OVERRIDE_VOID(8016ed94, GX__FinishInterruptHandler_8016ed94, (), ()); extern "C" void GX__DrawDone_8016eab0() { + GX_SYNC_INLINE(); try { Memory::Write8(kGxDrawDoneFlagAddr, 0); } catch (...) {} GXDrawDone(); GX__FinishInterruptHandler_8016ed94(); } @@ -44,7 +54,7 @@ PPC_NATIVE_OVERRIDE_VOID(8016eab0, GX__DrawDone_8016eab0, (), ()); extern "C" void GX__PixModeSync_8016eb70() { try { uint32_t gd = Memory::Read32(kGXDataPtrAddr); if (gd) Memory::Write16(gd + 2, 0); } catch (...) {} - GXPixModeSync(); + GxWorker::Run([] { GXPixModeSync(); }); } PPC_NATIVE_OVERRIDE_VOID(8016eb70, GX__PixModeSync_8016eb70, (), ()); @@ -60,7 +70,7 @@ PPC_NATIVE_OVERRIDE_VOID(8016b720, __GX__InitRevisionBits_8016b720, (), ()); // ============================================================================ extern "C" void __GX__SetSUTexRegs_801712f0() { - __GXSetSUTexRegs(); + GxWorker::Run([] { __GXSetSUTexRegs(); }); try { uint32_t gd = Memory::Read32(kGXDataPtrAddr); if (gd) Memory::Write16(gd + 2, 0); } catch (...) {} } PPC_NATIVE_OVERRIDE_VOID(801712f0, __GX__SetSUTexRegs_801712f0, (), ()); @@ -82,7 +92,7 @@ PPC_NATIVE_OVERRIDE_VOID(80171c28, __GX__FlushTextureState_80171c28, (), ()); // ============================================================================ extern "C" void GX__SetDispCopyFrame2Field_8016f5f8(uint32_t f) { - GXSetDispCopyFrame2Field(f); + GxWorker::Run([f] { GXSetDispCopyFrame2Field(f); }); try { const uint32_t gd = Memory::Read32(kGXDataPtrAddr); if (gd) { @@ -94,7 +104,7 @@ extern "C" void GX__SetDispCopyFrame2Field_8016f5f8(uint32_t f) { PPC_NATIVE_OVERRIDE_VOID(8016f5f8, GX__SetDispCopyFrame2Field_8016f5f8, (uint32_t f), (f)); extern "C" void GX__SetCopyClamp_8016f618(uint32_t c) { - GXSetCopyClamp(static_cast(c)); + GxWorker::Run([c] { GXSetCopyClamp(static_cast(c)); }); try { const uint32_t gd = Memory::Read32(kGXDataPtrAddr); if (gd) { @@ -107,7 +117,7 @@ extern "C" void GX__SetCopyClamp_8016f618(uint32_t c) { PPC_NATIVE_OVERRIDE_VOID(8016f618, GX__SetCopyClamp_8016f618, (uint32_t c), (c)); extern "C" void GX__ClearBoundingBox_8016fecc() { - GXClearBoundingBox(); + GxWorker::Run([] { GXClearBoundingBox(); }); try { const uint32_t gd = Memory::Read32(kGXDataPtrAddr); if (gd) Memory::Write16(gd + 2, 0); diff --git a/runtime/src/hle/gx/gx_tev.cpp b/runtime/src/hle/gx/gx_tev.cpp index 54c01a9..57ab64b 100644 --- a/runtime/src/hle/gx/gx_tev.cpp +++ b/runtime/src/hle/gx/gx_tev.cpp @@ -25,6 +25,7 @@ inline bool TevSwapOk(uint32_t id) { return GxTevIdOk(id, GX_MAX_TEVSWAP, "TEV s // ============================================================================ extern "C" void GX__SetNumTevStages_801722a8(uint32_t n) { + GX_DEFER_CALL(GX__SetNumTevStages_801722a8, n); // GXSetNumTevStages takes a count, not an index, so the inclusive bound is // GX_MAX_TEVSTAGE itself. if (n > GX_MAX_TEVSTAGE) { @@ -36,12 +37,14 @@ extern "C" void GX__SetNumTevStages_801722a8(uint32_t n) { PPC_NATIVE_OVERRIDE_VOID(801722a8, GX__SetNumTevStages_801722a8, (uint32_t n), (n)); extern "C" void GX__SetTevOp_80171c4c(uint32_t s, uint32_t m) { + GX_DEFER_CALL(GX__SetTevOp_80171c4c, s, m); if (!TevStageOk(s)) return; GXSetTevOp((GXTevStageID)s, (GXTevMode)m); } PPC_NATIVE_OVERRIDE_VOID(80171c4c, GX__SetTevOp_80171c4c, (uint32_t s, uint32_t m), (s, m)); extern "C" void GX__SetTevOrder_8017214c(uint32_t s, uint32_t c, uint32_t m, uint32_t col) { + GX_DEFER_CALL(GX__SetTevOrder_8017214c, s, c, m, col); if (!TevStageOk(s)) return; GXSetTevOrder((GXTevStageID)s, (GXTexCoordID)c, (GXTexMapID)m, (GXChannelID)col); } @@ -52,12 +55,14 @@ PPC_NATIVE_OVERRIDE_VOID(8017214c, GX__SetTevOrder_8017214c, (uint32_t s, uint32 // ============================================================================ extern "C" void GX__SetTevColorIn_80171ce0(uint32_t s, uint32_t a, uint32_t b, uint32_t c, uint32_t d) { + GX_DEFER_CALL(GX__SetTevColorIn_80171ce0, s, a, b, c, d); if (!TevStageOk(s)) return; GXSetTevColorIn((GXTevStageID)s, (GXTevColorArg)a, (GXTevColorArg)b, (GXTevColorArg)c, (GXTevColorArg)d); } PPC_NATIVE_OVERRIDE_VOID(80171ce0, GX__SetTevColorIn_80171ce0, (uint32_t s, uint32_t a, uint32_t b, uint32_t c, uint32_t d), (s, a, b, c, d)); extern "C" void GX__SetTevAlphaIn_80171d20(uint32_t s, uint32_t a, uint32_t b, uint32_t c, uint32_t d) { + GX_DEFER_CALL(GX__SetTevAlphaIn_80171d20, s, a, b, c, d); if (!TevStageOk(s)) return; GXSetTevAlphaIn((GXTevStageID)s, (GXTevAlphaArg)a, (GXTevAlphaArg)b, (GXTevAlphaArg)c, (GXTevAlphaArg)d); } @@ -68,12 +73,14 @@ PPC_NATIVE_OVERRIDE_VOID(80171d20, GX__SetTevAlphaIn_80171d20, (uint32_t s, uint // ============================================================================ extern "C" void GX__SetTevColorOp_80171d60(uint32_t s, uint32_t op, uint32_t b, uint32_t sc, uint32_t cl, uint32_t or_) { + GX_DEFER_CALL(GX__SetTevColorOp_80171d60, s, op, b, sc, cl, or_); if (!TevStageOk(s) || !TevRegOk(or_)) return; GXSetTevColorOp((GXTevStageID)s, (GXTevOp)op, (GXTevBias)b, (GXTevScale)sc, (GXBool)cl, (GXTevRegID)or_); } PPC_NATIVE_OVERRIDE_VOID(80171d60, GX__SetTevColorOp_80171d60, (uint32_t s, uint32_t op, uint32_t b, uint32_t sc, uint32_t cl, uint32_t or_), (s, op, b, sc, cl, or_)); extern "C" void GX__SetTevAlphaOp_80171db8(uint32_t s, uint32_t op, uint32_t b, uint32_t sc, uint32_t cl, uint32_t or_) { + GX_DEFER_CALL(GX__SetTevAlphaOp_80171db8, s, op, b, sc, cl, or_); if (!TevStageOk(s) || !TevRegOk(or_)) return; GXSetTevAlphaOp((GXTevStageID)s, (GXTevOp)op, (GXTevBias)b, (GXTevScale)sc, (GXBool)cl, (GXTevRegID)or_); } @@ -86,7 +93,7 @@ PPC_NATIVE_OVERRIDE_VOID(80171db8, GX__SetTevAlphaOp_80171db8, (uint32_t s, uint extern "C" void GX__SetTevColor_80171e10(uint32_t id, uint32_t cp) { if (!TevRegOk(id)) return; const uint8_t* p=Memory::GetPointer(cp, 4); GXColor c; c.r=p[0]; c.g=p[1]; c.b=p[2]; c.a=p[3]; - GXSetTevColor((GXTevRegID)id, c); + GxWorker::Run([id, c] { GXSetTevColor((GXTevRegID)id, c); }); } PPC_NATIVE_OVERRIDE_VOID(80171e10, GX__SetTevColor_80171e10, (uint32_t id, uint32_t cp), (id, cp)); @@ -94,21 +101,23 @@ extern "C" void GX__SetTevColorS10_80171e70(uint32_t id, uint32_t cp) { if (!TevRegOk(id)) return; const uint8_t* p=Memory::GetPointer(cp, 8); GXColorS10 c; c.r=(p[0]<<8)|p[1]; c.g=(p[2]<<8)|p[3]; c.b=(p[4]<<8)|p[5]; c.a=(p[6]<<8)|p[7]; - GXSetTevColorS10((GXTevRegID)id, c); + GxWorker::Run([id, c] { GXSetTevColorS10((GXTevRegID)id, c); }); } PPC_NATIVE_OVERRIDE_VOID(80171e70, GX__SetTevColorS10_80171e70, (uint32_t id, uint32_t cp), (id, cp)); extern "C" void GX__SetTevKColor_80171ed4(uint32_t id, uint32_t cp) { if (!TevKColorOk(id)) return; const uint8_t* p=Memory::GetPointer(cp, 4); GXColor c; c.r=p[0]; c.g=p[1]; c.b=p[2]; c.a=p[3]; - GXSetTevKColor((GXTevKColorID)id, c); + GxWorker::Run([id, c] { GXSetTevKColor((GXTevKColorID)id, c); }); } PPC_NATIVE_OVERRIDE_VOID(80171ed4, GX__SetTevKColor_80171ed4, (uint32_t id, uint32_t cp), (id, cp)); -extern "C" void GX__SetTevKColorSel_80171f30(uint32_t s, uint32_t sel) { if (!TevStageOk(s)) return; GXSetTevKColorSel((GXTevStageID)s, (GXTevKColorSel)sel); } +extern "C" void GX__SetTevKColorSel_80171f30(uint32_t s, uint32_t sel) { + GX_DEFER_CALL(GX__SetTevKColorSel_80171f30, s, sel); if (!TevStageOk(s)) return; GXSetTevKColorSel((GXTevStageID)s, (GXTevKColorSel)sel); } PPC_NATIVE_OVERRIDE_VOID(80171f30, GX__SetTevKColorSel_80171f30, (uint32_t s, uint32_t sel), (s, sel)); -extern "C" void GX__SetTevKAlphaSel_80171f80(uint32_t s, uint32_t sel) { if (!TevStageOk(s)) return; GXSetTevKAlphaSel((GXTevStageID)s, (GXTevKAlphaSel)sel); } +extern "C" void GX__SetTevKAlphaSel_80171f80(uint32_t s, uint32_t sel) { + GX_DEFER_CALL(GX__SetTevKAlphaSel_80171f80, s, sel); if (!TevStageOk(s)) return; GXSetTevKAlphaSel((GXTevStageID)s, (GXTevKAlphaSel)sel); } PPC_NATIVE_OVERRIDE_VOID(80171f80, GX__SetTevKAlphaSel_80171f80, (uint32_t s, uint32_t sel), (s, sel)); // ============================================================================ @@ -116,12 +125,14 @@ PPC_NATIVE_OVERRIDE_VOID(80171f80, GX__SetTevKAlphaSel_80171f80, (uint32_t s, ui // ============================================================================ extern "C" void GX__SetTevSwapModeTable_8017200c(uint32_t id, uint32_t r, uint32_t g, uint32_t b, uint32_t a) { + GX_DEFER_CALL(GX__SetTevSwapModeTable_8017200c, id, r, g, b, a); if (!TevSwapOk(id)) return; GXSetTevSwapModeTable((GXTevSwapSel)id, (GXTevColorChan)r, (GXTevColorChan)g, (GXTevColorChan)b, (GXTevColorChan)a); } PPC_NATIVE_OVERRIDE_VOID(8017200c, GX__SetTevSwapModeTable_8017200c, (uint32_t id, uint32_t r, uint32_t g, uint32_t b, uint32_t a), (id, r, g, b, a)); extern "C" void GX__SetTevSwapMode_80171fd0(uint32_t s, uint32_t rs, uint32_t ts) { + GX_DEFER_CALL(GX__SetTevSwapMode_80171fd0, s, rs, ts); if (!TevStageOk(s) || !TevSwapOk(rs) || !TevSwapOk(ts)) return; GXSetTevSwapMode((GXTevStageID)s, (GXTevSwapSel)rs, (GXTevSwapSel)ts); } diff --git a/runtime/src/hle/gx/gx_texture.cpp b/runtime/src/hle/gx/gx_texture.cpp index b5ebedd..0f79533 100644 --- a/runtime/src/hle/gx/gx_texture.cpp +++ b/runtime/src/hle/gx/gx_texture.cpp @@ -242,6 +242,31 @@ static uint32_t ComputeMaxMipLevel(uint16_t width, uint16_t height) noexcept { return levels; } +// GXInitTexObj* writes the guest struct synchronously; the host half runs on the GX worker with the +// struct bytes from before that write, which is what an inline call's shadow capture sees. +template +static void InitTexObjSplit(uint32_t oa, Hle&& hle, Guest&& guest) { + if (!GxWorker::ShouldDefer()) { + hle(); + guest(); + return; + } + std::optional before; + try { + before = CaptureTexObjBytes(oa); + } catch (...) { + } + guest(); + GxWorker::Submit([oa, before, hle = std::forward(hle)] { + if (before) { + TexObjSnapshotScope snapshot(oa, *before); + hle(); + } else { + hle(); + } + }); +} + extern "C" void GX__InitTexObj_801707f8(uint32_t oa, uint32_t da, uint32_t w, uint32_t h, uint32_t f, uint32_t ws, uint32_t wt, uint32_t m) { if (w == 0 || h == 0) { auto* cpu = TryGetCpuContext(); @@ -250,12 +275,15 @@ extern "C" void GX__InitTexObj_801707f8(uint32_t oa, uint32_t da, uint32_t w, ui oa, da, w, h, f, ws, wt, m, cpu ? cpu->pc : 0u, cpu ? cpu->lr : 0u); } const uint32_t canonicalDataAddr = CanonicalizeGxMainRamAddress(da); - std::lock_guard guard(g_texObjMutex); GXTexObj* obj = CreateHostTexObj(oa); TexObjMeta& meta = GetTexObjMeta(oa); - meta.dataAddr=canonicalDataAddr; meta.width=(u16)w; meta.height=(u16)h; meta.format=f; meta.wrapS=ws; meta.wrapT=wt; meta.mipmap=(m!=0); meta.userData=0; meta.needsUpload=true; - GXInitTexObj(obj, GuestToHostPtr(da), (u16)w, (u16)h, (GXTexFmt)f, (GXTexWrapMode)ws, (GXTexWrapMode)wt, (GXBool)m); MarkHostTexObjConstructed(oa); - // Also write to guest memory so reads work - WriteGuestTexObj(oa, canonicalDataAddr, (u16)w, (u16)h, f, ws, wt, m != 0, false, 0); + InitTexObjSplit(oa, [=] { + std::lock_guard guard(g_texObjMutex); GXTexObj* obj = CreateHostTexObj(oa); TexObjMeta& meta = GetTexObjMeta(oa); + meta.dataAddr=canonicalDataAddr; meta.width=(u16)w; meta.height=(u16)h; meta.format=f; meta.wrapS=ws; meta.wrapT=wt; meta.mipmap=(m!=0); meta.userData=0; meta.needsUpload=true; + GXInitTexObj(obj, GuestToHostPtr(da), (u16)w, (u16)h, (GXTexFmt)f, (GXTexWrapMode)ws, (GXTexWrapMode)wt, (GXBool)m); MarkHostTexObjConstructed(oa); + }, [=] { + WriteGuestTexObj(oa, canonicalDataAddr, (u16)w, (u16)h, f, ws, wt, m != 0, false, 0); + }); } + PPC_NATIVE_OVERRIDE_VOID(801707f8, GX__InitTexObj_801707f8, (uint32_t oa, uint32_t da, uint32_t w, uint32_t h, uint32_t f, uint32_t ws, uint32_t wt, uint32_t m), (oa, da, w, h, f, ws, wt, m)); extern "C" void GX__InitTexObj_switch_80170938(uint32_t oa, uint32_t da, uint32_t w, uint32_t h, uint32_t f, uint32_t ws, uint32_t wt, uint32_t m) { GX__InitTexObj_801707f8(oa, da, w, h, f, ws, wt, m); } @@ -291,132 +319,151 @@ extern "C" void GX__InitTexObjCI_80170a04(uint32_t oa, uint32_t da, uint32_t w, oa, da, w, h, f, ws, wt, m, tl, cpu ? cpu->pc : 0u, cpu ? cpu->lr : 0u); } const uint32_t canonicalDataAddr = CanonicalizeGxMainRamAddress(da); - std::lock_guard guard(g_texObjMutex); GXTexObj* obj = CreateHostTexObj(oa); TexObjMeta& meta = GetTexObjMeta(oa); - meta.dataAddr=canonicalDataAddr; meta.width=(u16)w; meta.height=(u16)h; meta.format=f; meta.wrapS=ws; meta.wrapT=wt; meta.mipmap=(m!=0); meta.tlut=tl; meta.userData=0; meta.needsUpload=true; - GXInitTexObjCI(obj, GuestToHostPtr(da), (u16)w, (u16)h, (GXCITexFmt)f, (GXTexWrapMode)ws, (GXTexWrapMode)wt, (GXBool)m, tl); MarkHostTexObjConstructed(oa); - // Also write to guest memory so reads work - WriteGuestTexObj(oa, canonicalDataAddr, (u16)w, (u16)h, f, ws, wt, m != 0, true, tl); - // GXInitTexObjCI clears bit1 in the flags byte; keep guest memory consistent. - try { - uint8_t flags = Memory::Read8(oa + 0x1F); - Memory::Write8(oa + 0x1F, static_cast(flags & 0xFD)); - } catch (...) { - } + InitTexObjSplit(oa, [=] { + std::lock_guard guard(g_texObjMutex); GXTexObj* obj = CreateHostTexObj(oa); TexObjMeta& meta = GetTexObjMeta(oa); + meta.dataAddr=canonicalDataAddr; meta.width=(u16)w; meta.height=(u16)h; meta.format=f; meta.wrapS=ws; meta.wrapT=wt; meta.mipmap=(m!=0); meta.tlut=tl; meta.userData=0; meta.needsUpload=true; + GXInitTexObjCI(obj, GuestToHostPtr(da), (u16)w, (u16)h, (GXCITexFmt)f, (GXTexWrapMode)ws, (GXTexWrapMode)wt, (GXBool)m, tl); MarkHostTexObjConstructed(oa); + }, [=] { + WriteGuestTexObj(oa, canonicalDataAddr, (u16)w, (u16)h, f, ws, wt, m != 0, true, tl); + // GXInitTexObjCI clears bit1 in the flags byte; keep guest memory consistent. + try { + uint8_t flags = Memory::Read8(oa + 0x1F); + Memory::Write8(oa + 0x1F, static_cast(flags & 0xFD)); + } catch (...) { + } + }); } + PPC_NATIVE_OVERRIDE_VOID(80170a04, GX__InitTexObjCI_80170a04, (uint32_t oa, uint32_t da, uint32_t w, uint32_t h, uint32_t f, uint32_t ws, uint32_t wt, uint32_t m, uint32_t tl), (oa, da, w, h, f, ws, wt, m, tl)); extern "C" void GX__InitTexObjLOD_80170a4c(uint32_t oa, uint32_t mif, uint32_t maf, float mil, float mal, float lb, uint32_t bc, uint32_t el, uint32_t ma) { - std::lock_guard guard(g_texObjMutex); GXTexObj* obj = GetHostTexObj(oa); TexObjMeta& meta = GetTexObjMeta(oa); - float fmal = std::isfinite(mal) && mal >= 0.f ? mal : 0.f, fmil = std::isfinite(mil) && mil >= 0.f ? std::min(mil, fmal) : 0.f; - meta.minFilter=mif; meta.magFilter=maf; meta.minLod=fmil; meta.maxLod=fmal; meta.lodBias=lb; meta.biasClamp=(bc!=0); meta.edgeLod=(el!=0); meta.maxAniso=ma; - GXInitTexObjLOD(obj, (GXTexFilter)mif, (GXTexFilter)maf, fmil, fmal, lb, (GXBool)bc, (GXBool)el, (GXAnisotropy)ma); - // Also write LOD info to guest memory - WriteGuestTexObjLOD(oa, mif, maf, fmil, fmal, lb, bc != 0, el != 0, ma); + const float fmal = std::isfinite(mal) && mal >= 0.f ? mal : 0.f, fmil = std::isfinite(mil) && mil >= 0.f ? std::min(mil, fmal) : 0.f; + InitTexObjSplit(oa, [=] { + std::lock_guard guard(g_texObjMutex); GXTexObj* obj = GetHostTexObj(oa); TexObjMeta& meta = GetTexObjMeta(oa); + meta.minFilter=mif; meta.magFilter=maf; meta.minLod=fmil; meta.maxLod=fmal; meta.lodBias=lb; meta.biasClamp=(bc!=0); meta.edgeLod=(el!=0); meta.maxAniso=ma; + GXInitTexObjLOD(obj, (GXTexFilter)mif, (GXTexFilter)maf, fmil, fmal, lb, (GXBool)bc, (GXBool)el, (GXAnisotropy)ma); + }, [=] { + WriteGuestTexObjLOD(oa, mif, maf, fmil, fmal, lb, bc != 0, el != 0, ma); + }); } + PPC_NATIVE_OVERRIDE_VOID(80170a4c, GX__InitTexObjLOD_80170a4c, (uint32_t oa, uint32_t mif, uint32_t maf, float mil, float mal, float lb, uint32_t bc, uint32_t el, uint32_t ma), (oa, mif, maf, mil, mal, lb, bc, el, ma)); extern "C" void GX__InitTexObjWrapMode_80170b50(uint32_t oa, uint32_t ws, uint32_t wt) { - std::lock_guard guard(g_texObjMutex); - GXTexObj* obj = GetHostTexObj(oa); - TexObjMeta& meta = GetTexObjMeta(oa); - meta.wrapS = ws; - meta.wrapT = wt; - try { - uint32_t word0 = Memory::Read32(oa + 0x00); - word0 = (word0 & ~0xFu) | (ws & 0x3u) | ((wt & 0x3u) << 2); - Memory::Write32(oa + 0x00, word0); - } catch (...) { - } - GXInitTexObjWrapMode(obj, (GXTexWrapMode)ws, (GXTexWrapMode)wt); + InitTexObjSplit(oa, [=] { + std::lock_guard guard(g_texObjMutex); + GXTexObj* obj = GetHostTexObj(oa); + TexObjMeta& meta = GetTexObjMeta(oa); + meta.wrapS = ws; + meta.wrapT = wt; + GXInitTexObjWrapMode(obj, (GXTexWrapMode)ws, (GXTexWrapMode)wt); + }, [=] { + try { + uint32_t word0 = Memory::Read32(oa + 0x00); + word0 = (word0 & ~0xFu) | (ws & 0x3u) | ((wt & 0x3u) << 2); + Memory::Write32(oa + 0x00, word0); + } catch (...) { + } + }); } + PPC_NATIVE_OVERRIDE_VOID(80170b50, GX__InitTexObjWrapMode_80170b50, (uint32_t oa, uint32_t ws, uint32_t wt), (oa, ws, wt)); extern "C" void GX__InitTexObjTlut_80170b64(uint32_t oa, uint32_t tl) { - std::lock_guard guard(g_texObjMutex); - GXTexObj* obj = GetHostTexObj(oa); - TexObjMeta& meta = GetTexObjMeta(oa); - meta.tlut = tl; - GXInitTexObjTlut(obj, tl); - // Keep guest GXTexObj coherent for later GXLoadTexObj from memory. - try { - Memory::Write32(oa + 0x18, tl); - } catch (...) { - } + InitTexObjSplit(oa, [=] { + std::lock_guard guard(g_texObjMutex); + GXTexObj* obj = GetHostTexObj(oa); + TexObjMeta& meta = GetTexObjMeta(oa); + meta.tlut = tl; + GXInitTexObjTlut(obj, tl); + }, [=] { + // Keep guest GXTexObj coherent for later GXLoadTexObj from memory. + try { + Memory::Write32(oa + 0x18, tl); + } catch (...) { + } + }); } + PPC_NATIVE_OVERRIDE_VOID(80170b64, GX__InitTexObjTlut_80170b64, (uint32_t oa, uint32_t tl), (oa, tl)); // GXInitTexObjFilter - sets mag/min filter modes extern "C" void GX__InitTexObjFilter_80170b6c(uint32_t oa, uint32_t minFilter, uint32_t magFilter) { - std::lock_guard guard(g_texObjMutex); - TexObjMeta& meta = GetTexObjMeta(oa); - meta.minFilter = minFilter; - meta.magFilter = magFilter; - - try { - uint32_t word0 = Memory::Read32(oa + 0x00); - // bit 4: magFilter - set if magFilter == GX_LINEAR (1), clear otherwise - // Original code used cntlzw to check: cntlzw(magFilter-1) >> 1 & 0x10 - // This sets bit 4 when magFilter-1 is 0 (i.e., magFilter == 1) - uint32_t magBit = (magFilter == 1) ? 0x10 : 0; - word0 = (word0 & 0xFFFFFFEF) | magBit; - // bits [7:5]: minFilter from LUT - uint32_t minBits = (kGxToHwMinFilter[minFilter & 7] & 7) << 5; - word0 = (word0 & 0xFFFFFF0F) | magBit | minBits; - Memory::Write32(oa + 0x00, word0); - } catch (...) {} - - // Update host texture object if it exists - if (GXTexObj* obj = TryGetHostTexObj(oa)) { - ApplyHostTexObjLod(obj, meta, (GXTexFilter)minFilter, (GXTexFilter)magFilter, meta.lodBias, - (GXAnisotropy)meta.maxAniso); - } + InitTexObjSplit(oa, [=] { + std::lock_guard guard(g_texObjMutex); + TexObjMeta& meta = GetTexObjMeta(oa); + meta.minFilter = minFilter; + meta.magFilter = magFilter; + // Update host texture object if it exists + if (GXTexObj* obj = TryGetHostTexObj(oa)) { + ApplyHostTexObjLod(obj, meta, (GXTexFilter)minFilter, (GXTexFilter)magFilter, meta.lodBias, + (GXAnisotropy)meta.maxAniso); + } + }, [=] { + try { + uint32_t word0 = Memory::Read32(oa + 0x00); + // bit 4: magFilter - set if magFilter == GX_LINEAR (1), clear otherwise + // Original code used cntlzw to check: cntlzw(magFilter-1) >> 1 & 0x10 + // This sets bit 4 when magFilter-1 is 0 (i.e., magFilter == 1) + uint32_t magBit = (magFilter == 1) ? 0x10 : 0; + word0 = (word0 & 0xFFFFFFEF) | magBit; + // bits [7:5]: minFilter from LUT + uint32_t minBits = (kGxToHwMinFilter[minFilter & 7] & 7) << 5; + word0 = (word0 & 0xFFFFFF0F) | magBit | minBits; + Memory::Write32(oa + 0x00, word0); + } catch (...) {} + }); } + PPC_NATIVE_OVERRIDE_VOID(80170b6c, GX__InitTexObjFilter_80170b6c, (uint32_t oa, uint32_t minFilter, uint32_t magFilter), (oa, minFilter, magFilter)); // GXInitTexObjLODBias - sets LOD bias value extern "C" void GX__InitTexObjLODBias_80170b94(uint32_t oa, float bias) { - std::lock_guard guard(g_texObjMutex); - TexObjMeta& meta = GetTexObjMeta(oa); - // Clamp bias to [-4.0, 3.99...] range as per SDK constexpr float kMinBias = -4.0f; constexpr float kMaxBias = 3.99f; // Actually ~3.990000009536743 float clampedBias = bias; if (clampedBias < kMinBias) clampedBias = kMinBias; if (clampedBias >= 4.0f) clampedBias = kMaxBias; - - meta.lodBias = clampedBias; - - // Update guest GXTexObj word0 with bias (scale by 32, store in bits [16:9]) - try { - uint32_t word0 = Memory::Read32(oa + 0x00); - int8_t biasScaled = static_cast(clampedBias * 32.0f); - word0 = (word0 & 0xFFFE01FF) | ((static_cast(static_cast(biasScaled)) & 0xFF) << 9); - Memory::Write32(oa + 0x00, word0); - } catch (...) {} - - // Update host texture object if it exists - if (GXTexObj* obj = TryGetHostTexObj(oa)) { - ApplyHostTexObjLod(obj, meta, (GXTexFilter)meta.minFilter, (GXTexFilter)meta.magFilter, - clampedBias, (GXAnisotropy)meta.maxAniso); - } + + InitTexObjSplit(oa, [=] { + std::lock_guard guard(g_texObjMutex); + TexObjMeta& meta = GetTexObjMeta(oa); + meta.lodBias = clampedBias; + // Update host texture object if it exists + if (GXTexObj* obj = TryGetHostTexObj(oa)) { + ApplyHostTexObjLod(obj, meta, (GXTexFilter)meta.minFilter, (GXTexFilter)meta.magFilter, + clampedBias, (GXAnisotropy)meta.maxAniso); + } + }, [=] { + // Update guest GXTexObj word0 with bias (scale by 32, store in bits [16:9]) + try { + uint32_t word0 = Memory::Read32(oa + 0x00); + int8_t biasScaled = static_cast(clampedBias * 32.0f); + word0 = (word0 & 0xFFFE01FF) | ((static_cast(static_cast(biasScaled)) & 0xFF) << 9); + Memory::Write32(oa + 0x00, word0); + } catch (...) {} + }); } + PPC_NATIVE_OVERRIDE_VOID(80170b94, GX__InitTexObjLODBias_80170b94, (uint32_t oa, float bias), (oa, bias)); extern "C" void GX__InitTexObjUserData_80170be8(uint32_t oa, uint32_t userData) { - std::lock_guard guard(g_texObjMutex); - TexObjMeta& meta = GetTexObjMeta(oa); - meta.userData = userData; - - // The RVL SDK stores this opaque guest pointer verbatim at GXTexObj + 0x10. - WriteGuest32(oa + 0x10, userData, "GXInitTexObjUserData"); - - // Aurora keeps an expanded host-side object, so mirror the pointer when - // that representation has already been constructed. - if (GXTexObj* obj = TryGetHostTexObj(oa)) { - GXInitTexObjUserData(obj, GuestToHostPtr(userData)); - } + InitTexObjSplit(oa, [=] { + std::lock_guard guard(g_texObjMutex); + TexObjMeta& meta = GetTexObjMeta(oa); + meta.userData = userData; + // Aurora keeps an expanded host-side object, so mirror the pointer when + // that representation has already been constructed. + if (GXTexObj* obj = TryGetHostTexObj(oa)) { + GXInitTexObjUserData(obj, GuestToHostPtr(userData)); + } + }, [=] { + // The RVL SDK stores this opaque guest pointer verbatim at GXTexObj + 0x10. + WriteGuest32(oa + 0x10, userData, "GXInitTexObjUserData"); + }); } + PPC_NATIVE_OVERRIDE_VOID(80170be8, GX__InitTexObjUserData_80170be8, (uint32_t oa, uint32_t userData), (oa, userData)); @@ -446,7 +493,7 @@ static void BindUnloadableTexturePlaceholder(uint32_t tid) { GXLoadTexObj(&s_placeholder, (GXTexMapID)tid); } -extern "C" void GX__LoadTexObj_80170f2c(uint32_t oa, uint32_t tid) { +static void LoadTexObjImpl(uint32_t oa, uint32_t tid) { static uint32_t s_invalidMetaLogCount = 0; static uint32_t s_invalidTidLogCount = 0; static uint32_t s_invalidDimLogCount = 0; @@ -631,18 +678,43 @@ extern "C" void GX__LoadTexObj_80170f2c(uint32_t oa, uint32_t tid) { BindUnloadableTexturePlaceholder(tid); return; } +} + +extern "C" void GX__LoadTexObj_80170f2c(uint32_t oa, uint32_t tid) { + if (GxWorker::ShouldDefer()) { + // The CPU-side SDK reads the GXTexObj at call time; the texture data itself is read later. + std::optional bytes; + try { + bytes = CaptureTexObjBytes(oa); + } catch (...) { + } + GxWorker::Submit([oa, tid, bytes] { + if (bytes) { + TexObjSnapshotScope snapshot(oa, *bytes); + LoadTexObjImpl(oa, tid); + } else { + LoadTexObjImpl(oa, tid); + } + }); + } else { + LoadTexObjImpl(oa, tid); + } try { uint32_t gd = Memory::Read32(kGXDataPtrAddr); if (gd) { Memory::Write32(gd + 0x5FCu, Memory::Read32(gd + 0x5FCu) | 1u); Memory::Write16(gd + 2, 0); } } catch (...) {} } PPC_NATIVE_OVERRIDE_VOID(80170f2c, GX__LoadTexObj_80170f2c, (uint32_t oa, uint32_t tid), (oa, tid)); -extern "C" void GX__LoadTexObjPreLoaded_80170dc8(uint32_t oa, uint32_t tid) { GX__LoadTexObj_80170f2c(oa, tid); } -PPC_NATIVE_OVERRIDE_VOID(80170dc8, GX__LoadTexObjPreLoaded_80170dc8, (uint32_t oa, uint32_t tid), (oa, tid)); +extern "C" void GX__LoadTexObjPreLoaded_80170dc8(uint32_t oa, uint32_t region, uint32_t tid) { + (void)region; + GX__LoadTexObj_80170f2c(oa, tid); +} +PPC_NATIVE_OVERRIDE_VOID(80170dc8, GX__LoadTexObjPreLoaded_80170dc8, (uint32_t oa, uint32_t region, uint32_t tid), (oa, region, tid)); // ============================================================================ // Texture Object Getters // ============================================================================ extern "C" void GX__GetTexObjAll_80170bf8(uint32_t oa, uint32_t dp, uint32_t wp, uint32_t hp, uint32_t fp, uint32_t wsp, uint32_t wtp, uint32_t mp) { + GX_SYNC_INLINE(); std::lock_guard guard(g_texObjMutex); TexObjMeta meta; if (!TryGetOrExtractTexObjMeta(oa, meta)) { @@ -657,6 +729,7 @@ extern "C" void GX__GetTexObjAll_80170bf8(uint32_t oa, uint32_t dp, uint32_t wp, PPC_NATIVE_OVERRIDE_VOID(80170bf8, GX__GetTexObjAll_80170bf8, (uint32_t oa, uint32_t dp, uint32_t wp, uint32_t hp, uint32_t fp, uint32_t wsp, uint32_t wtp, uint32_t mp), (oa, dp, wp, hp, fp, wsp, wtp, mp)); extern "C" void GX__GetTexObjLODAll_80170cbc(uint32_t oa, uint32_t mifp, uint32_t mafp, uint32_t milp, uint32_t malp, uint32_t lbp, uint32_t bcp, uint32_t elp, uint32_t map) { + GX_SYNC_INLINE(); std::lock_guard guard(g_texObjMutex); TexObjMeta meta; if (!TryGetOrExtractTexObjMeta(oa, meta)) { @@ -676,6 +749,7 @@ PPC_NATIVE_OVERRIDE_VOID(80170cbc, GX__GetTexObjLODAll_80170cbc, (uint32_t oa, u // ============================================================================ extern "C" void GX__InitTlutObj_80170f80(uint32_t oa, uint32_t da, uint32_t f, uint32_t e) { + GX_DEFER_CALL(GX__InitTlutObj_80170f80, oa, da, f, e); std::lock_guard guard(g_tlutObjMutex); GXTlutObj* obj = CreateHostTlutObj(oa); TlutObjMeta& meta = GetTlutObjMeta(oa); meta.dataAddr=CanonicalizeGxMainRamAddress(da); meta.format=f; meta.entries=(u16)e; meta.dirty=false; // Leave the object unconstructed on a bad descriptor. A later GXLoadTlut @@ -686,7 +760,12 @@ extern "C" void GX__InitTlutObj_80170f80(uint32_t oa, uint32_t da, uint32_t f, u } PPC_NATIVE_OVERRIDE_VOID(80170f80, GX__InitTlutObj_80170f80, (uint32_t oa, uint32_t da, uint32_t f, uint32_t e), (oa, da, f, e)); -extern "C" void GX__LoadTlut_80170fa8(uint32_t oa, uint32_t tl) { std::lock_guard guard(g_tlutObjMutex); if (tl >= kMaxTluts) { RT_LOGF(RT_TAG_GX, "GXLoadTlut: invalid TLUT index %u (oa=0x%08X)\n", tl, oa); return; } auto metaIt = g_TlutObjMeta.find(oa); if (metaIt != g_TlutObjMeta.end() && metaIt->second.dirty) { if (ValidateTlutData(oa, metaIt->second)) { GXTlutObj* rebuild = CreateHostTlutObj(oa); GXInitTlutObj(rebuild, GuestToHostPtr(metaIt->second.dataAddr), (GXTlutFmt)metaIt->second.format, metaIt->second.entries); MarkHostTlutObjConstructed(oa); } metaIt->second.dirty = false; } GXTlutObj* obj = GetHostTlutObj(oa); GXLoadTlut(obj, (GXTlut)tl); try { uint32_t gd = Memory::Read32(kGXDataPtrAddr); if (gd) Memory::Write16(gd + 2, 0); } catch (...) {} } +static void LoadTlutImpl(uint32_t oa, uint32_t tl) { std::lock_guard guard(g_tlutObjMutex); if (tl >= kMaxTluts) { RT_LOGF(RT_TAG_GX, "GXLoadTlut: invalid TLUT index %u (oa=0x%08X)\n", tl, oa); return; } auto metaIt = g_TlutObjMeta.find(oa); if (metaIt != g_TlutObjMeta.end() && metaIt->second.dirty) { if (ValidateTlutData(oa, metaIt->second)) { GXTlutObj* rebuild = CreateHostTlutObj(oa); GXInitTlutObj(rebuild, GuestToHostPtr(metaIt->second.dataAddr), (GXTlutFmt)metaIt->second.format, metaIt->second.entries); MarkHostTlutObjConstructed(oa); } metaIt->second.dirty = false; } GXTlutObj* obj = GetHostTlutObj(oa); GXLoadTlut(obj, (GXTlut)tl); } + +extern "C" void GX__LoadTlut_80170fa8(uint32_t oa, uint32_t tl) { + GxWorker::Run([oa, tl] { LoadTlutImpl(oa, tl); }); + try { uint32_t gd = Memory::Read32(kGXDataPtrAddr); if (gd) Memory::Write16(gd + 2, 0); } catch (...) {} +} PPC_NATIVE_OVERRIDE_VOID(80170fa8, GX__LoadTlut_80170fa8, (uint32_t oa, uint32_t tl), (oa, tl)); // ============================================================================ @@ -694,6 +773,7 @@ PPC_NATIVE_OVERRIDE_VOID(80170fa8, GX__LoadTlut_80170fa8, (uint32_t oa, uint32_t // ============================================================================ extern "C" void GX__InvalidateTexAll_80171110() { + GX_DEFER_CALL0(GX__InvalidateTexAll_80171110); // Real GX invalidates its internal texture cache here. Aurora forwards the // invalidate to the renderer, which keeps unchanged source uploads hot but // revalidates reused guest buffers before serving cached texture handles. @@ -701,8 +781,8 @@ extern "C" void GX__InvalidateTexAll_80171110() { } PPC_NATIVE_OVERRIDE_VOID(80171110, GX__InvalidateTexAll_80171110, (), ()); -extern "C" void GX__SetTexCoordScaleManually_80171180(uint32_t c, uint32_t en, uint32_t ss, uint32_t ts) { GXSetTexCoordScaleManually((GXTexCoordID)c, (GXBool)en, (u16)ss, (u16)ts); try{ uint32_t gd=Memory::Read32(kGXDataPtrAddr); if(gd){ Memory::Write32(gd+0x5E4u, (Memory::Read32(gd+0x5E4u)&~(1u< apply_logical_render_state), // so re-issuing the current viewport would be duplicate work. - GXSetScissor(l, t, w, h); + GxWorker::Run([l, t, w, h] { GXSetScissor(l, t, w, h); }); } PPC_NATIVE_OVERRIDE_VOID(80173430, GX__SetScissor_80173430, (uint32_t l, uint32_t t, uint32_t w, uint32_t h), (l, t, w, h)); @@ -115,7 +115,7 @@ PPC_NATIVE_OVERRIDE_VOID(80173430, GX__SetScissor_80173430, (uint32_t l, uint32_ extern "C" void GX__SetProjection_8017301c(uint32_t ma, uint32_t pt) { const uint32_t* raw=(const uint32_t*)GuestToHostPtr(ma, 64); float m[16]; SwapBeF32ArrayToHost(raw, m, 16); - GXSetProjection(m, (GXProjectionType)pt); + GxWorker::Run([mtx = std::to_array(m), pt]() mutable { GXSetProjection(mtx.data(), (GXProjectionType)pt); }); UpdateProjectionVectorFromMatrix(m, (GXProjectionType)pt); } PPC_NATIVE_OVERRIDE_VOID(8017301c, GX__SetProjection_8017301c, (uint32_t ma, uint32_t pt), (ma, pt)); @@ -126,7 +126,7 @@ extern "C" void GX__SetProjectionv_80173080(uint32_t pa) { GXProjectionType pt=(v[0]!=0.f)?GX_ORTHOGRAPHIC:GX_PERSPECTIVE; float m[16]={0.f}; m[0]=v[1]; m[5]=v[3]; m[10]=v[5]; m[11]=v[6]; if(pt==GX_PERSPECTIVE){ m[2]=v[2]; m[6]=v[4]; m[14]=-1.f; } else { m[3]=v[2]; m[7]=v[4]; m[15]=1.f; } - GXSetProjection(m, pt); + GxWorker::Run([mtx = std::to_array(m), pt]() mutable { GXSetProjection(mtx.data(), pt); }); UpdateProjectionVectorFromProjV(v); } PPC_NATIVE_OVERRIDE_VOID(80173080, GX__SetProjectionv_80173080, (uint32_t pa), (pa)); @@ -146,28 +146,51 @@ PPC_NATIVE_OVERRIDE_VOID(801730cc, GX__GetProjectionv_801730cc, (uint32_t pa), ( extern "C" void GX__LoadPosMtxImm_8017310c(uint32_t ma, uint32_t id) { const uint32_t* raw=(const uint32_t*)GuestToHostPtr(ma); float m[12]; SwapBeF32ArrayToHost(raw, m, 12); - GXLoadPosMtxImm((float(*)[4])m, id); + GxWorker::Run([mtx = std::to_array(m), id]() mutable { GXLoadPosMtxImm((float(*)[4])mtx.data(), id); }); } PPC_NATIVE_OVERRIDE_VOID(8017310c, GX__LoadPosMtxImm_8017310c, (uint32_t ma, uint32_t id), (ma, id)); +// The matrix is read at load time, as Dolphin does, since the worker can run well behind the game. +// Returns false only when the game thread doesn't know the array and the worker must resolve it. +static bool IndexedMtxArray(uint32_t attr, uint32_t& base, uint32_t& stride) { + if (GxWorker::ShouldDefer()) { + return ApiVtxArray(attr, base, stride); + } + base = g_hleGxState.vtxArray[attr].base; + stride = g_hleGxState.vtxArray[attr].stride; + return true; +} + extern "C" void GX__LoadPosMtxIndx_8017315c(uint32_t mi, uint32_t id) { - const auto& arr=g_hleGxState.vtxArray[GX_POS_MTX_ARRAY]; - if(arr.base==0||arr.stride==0) return; - const uint32_t* raw=(const uint32_t*)GuestToHostPtr(arr.base+mi*arr.stride, 48); - if(raw){ float m[12]; SwapBeF32ArrayToHost(raw,m,12); GXLoadPosMtxImm((float(*)[4])m,id); } + uint32_t base = 0, stride = 0; + if (!IndexedMtxArray(GX_POS_MTX_ARRAY, base, stride)) { + GX_DEFER_CALL(GX__LoadPosMtxIndx_8017315c, mi, id); + return; + } + if (base == 0 || stride == 0) return; + const uint32_t* raw=(const uint32_t*)GuestToHostPtr(base+mi*stride, 48); + if(raw){ + float m[12]; SwapBeF32ArrayToHost(raw,m,12); + GxWorker::Run([mtx = std::to_array(m), id]() mutable { GXLoadPosMtxImm((float(*)[4])mtx.data(), id); }); + } } PPC_NATIVE_OVERRIDE_VOID(8017315c, GX__LoadPosMtxIndx_8017315c, (uint32_t mi, uint32_t id), (mi, id)); extern "C" void GX__LoadNrmMtxImm_80173188(uint32_t ma, uint32_t id) { const uint32_t* raw=(const uint32_t*)GuestToHostPtr(ma, 48); float m[12]; - SwapBeF32ArrayToHost(raw, m, 12); GXLoadNrmMtxImm((float(*)[4])m, id); + SwapBeF32ArrayToHost(raw, m, 12); + GxWorker::Run([mtx = std::to_array(m), id]() mutable { GXLoadNrmMtxImm((float(*)[4])mtx.data(), id); }); } PPC_NATIVE_OVERRIDE_VOID(80173188, GX__LoadNrmMtxImm_80173188, (uint32_t ma, uint32_t id), (ma, id)); extern "C" void GX__LoadNrmMtxIndx3x3_801731e0(uint32_t mi, uint32_t id) { - const auto& arr=g_hleGxState.vtxArray[GX_NRM_MTX_ARRAY]; - if(arr.base==0||arr.stride==0) return; - const uint32_t* raw=(const uint32_t*)GuestToHostPtr(arr.base+mi*arr.stride, 36); + uint32_t base = 0, stride = 0; + if (!IndexedMtxArray(GX_NRM_MTX_ARRAY, base, stride)) { + GX_DEFER_CALL(GX__LoadNrmMtxIndx3x3_801731e0, mi, id); + return; + } + if (base == 0 || stride == 0) return; + const uint32_t* raw=(const uint32_t*)GuestToHostPtr(base+mi*stride, 36); if(raw){ float src[9]{}; float m[12]{}; @@ -177,7 +200,7 @@ extern "C" void GX__LoadNrmMtxIndx3x3_801731e0(uint32_t mi, uint32_t id) { m[row * 4 + col] = src[row * 3 + col]; } } - GXLoadNrmMtxImm((float(*)[4])m, id); + GxWorker::Run([mtx = std::to_array(m), id]() mutable { GXLoadNrmMtxImm((float(*)[4])mtx.data(), id); }); } } PPC_NATIVE_OVERRIDE_VOID(801731e0, GX__LoadNrmMtxIndx3x3_801731e0, (uint32_t mi, uint32_t id), (mi, id)); @@ -185,9 +208,13 @@ PPC_NATIVE_OVERRIDE_VOID(801731e0, GX__LoadNrmMtxIndx3x3_801731e0, (uint32_t mi, extern "C" void GX__LoadTexMtxImm_80173234(uint32_t ma, uint32_t id, uint32_t t) { size_t c=(t==(uint32_t)GX_MTX3x4)?12:8; const uint32_t* raw=(const uint32_t*)GuestToHostPtr(ma,c*4); float l[12]={}; - SwapBeF32ArrayToHost(raw,l,c); GXLoadTexMtxImm(l, id, (GXTexMtxType)t); + SwapBeF32ArrayToHost(raw,l,c); + GxWorker::Run([mtx = std::to_array(l), id, t]() mutable { GXLoadTexMtxImm(mtx.data(), id, (GXTexMtxType)t); }); } PPC_NATIVE_OVERRIDE_VOID(80173234, GX__LoadTexMtxImm_80173234, (uint32_t ma, uint32_t id, uint32_t t), (ma, id, t)); -extern "C" void GX__SetCurrentMtx_80173214(uint32_t id) { GXSetCurrentMtx(id); } +extern "C" void GX__SetCurrentMtx_80173214(uint32_t id) { + GX_DEFER_CALL(GX__SetCurrentMtx_80173214, id); + GXSetCurrentMtx(id); +} PPC_NATIVE_OVERRIDE_VOID(80173214, GX__SetCurrentMtx_80173214, (uint32_t id), (id)); diff --git a/runtime/src/hle/gx/gx_vertex.cpp b/runtime/src/hle/gx/gx_vertex.cpp index 68cbf92..3a8c43b 100644 --- a/runtime/src/hle/gx/gx_vertex.cpp +++ b/runtime/src/hle/gx/gx_vertex.cpp @@ -13,6 +13,9 @@ uint32_t CanonicalVtxAttr(uint32_t attr) { return attr == GX_VA_NBT ? GX_VA_NRM : attr; } +// Array bases as last set through GXSetArray on the game thread. +std::array, 26> g_apiVtxArrays{}; + // There is deliberately no indexed-aurora path here. The immediate begin path // streams vertex data incrementally, and aurora's indexed-array upload must // precede the draw carrying the max-index bounds, which cannot be known without @@ -27,11 +30,19 @@ void ApplyAuroraVtxStateForBegin(GXVtxFmt fmt) { } } +bool ApiVtxArray(uint32_t attr, uint32_t& base, uint32_t& stride) { + if (attr >= 26) return false; + base = g_apiVtxArrays[attr][0]; + stride = g_apiVtxArrays[attr][1]; + return base != 0 && stride != 0; +} + // ============================================================================ // Vertex Descriptor // ============================================================================ extern "C" void GX__ClearVtxDesc_8016dc34() { + GX_DEFER_CALL0(GX__ClearVtxDesc_8016dc34); bool changed = false; for(int i=0; i<26; ++i){ changed |= g_hleGxState.vtxDesc[i] != GX_NONE; @@ -44,6 +55,7 @@ extern "C" void GX__ClearVtxDesc_8016dc34() { PPC_NATIVE_OVERRIDE_VOID(8016dc34, GX__ClearVtxDesc_8016dc34, (), ()); extern "C" void GX__SetVtxDesc_8016d3a4(uint32_t a, uint32_t t) { + GX_DEFER_CALL(GX__SetVtxDesc_8016d3a4, a, t); const uint32_t attr = CanonicalVtxAttr(a); if(attr>=26||attr==GX_VA_NULL) return; const GXAttrType oldType = g_hleGxState.vtxDesc[attr]; @@ -59,16 +71,22 @@ PPC_NATIVE_OVERRIDE_VOID(8016d3a4, GX__SetVtxDesc_8016d3a4, (uint32_t a, uint32_ extern "C" void GX__SetVtxDescv_8016d608(uint32_t la) { if(!la) return; uint32_t p=la; + std::vector> list; while(true){ uint32_t a=Memory::Read32(p); if(a==0xFFu) break; - GX__SetVtxDesc_8016d3a4(a, Memory::Read32(p+4)); + list.push_back({a, Memory::Read32(p+4)}); p+=8; } + GxWorker::Run([list = std::move(list)] { + for (const auto& [a, t] : list) GX__SetVtxDesc_8016d3a4(a, t); + }); } PPC_NATIVE_OVERRIDE_VOID(8016d608, GX__SetVtxDescv_8016d608, (uint32_t la), (la)); +// Display lists can change the vertex layout, so answer from the state the worker has applied. extern "C" void GX__GetVtxDesc_8016d9f0(uint32_t a, uint32_t tp) { + GX_SYNC_INLINE(); GXAttrType type = GX_NONE; const uint32_t attr = CanonicalVtxAttr(a); if (attr < GX_VA_MAX_ATTR && attr != GX_VA_NULL) { @@ -84,6 +102,7 @@ extern "C" void GX__GetVtxDescv_8016dba4(uint32_t la) { if (!la) { return; } + GX_SYNC_INLINE(); uint32_t p = la; for (uint32_t a = GX_VA_PNMTXIDX; a <= GX_VA_TEX7; ++a) { @@ -103,6 +122,7 @@ PPC_NATIVE_OVERRIDE_VOID(8016dba4, GX__GetVtxDescv_8016dba4, (uint32_t la), (la) // ============================================================================ extern "C" void GX__SetVtxAttrFmt_8016dc68(uint32_t vf, uint32_t a, uint32_t c, uint32_t t, uint32_t fr) { + GX_DEFER_CALL(GX__SetVtxAttrFmt_8016dc68, vf, a, c, t, fr); const uint32_t attr = CanonicalVtxAttr(a); if(vf<8&&attr<26){ const VtxAttrFmt oldFmt = g_hleGxState.vtxAttrFmt[vf][attr]; @@ -126,16 +146,21 @@ PPC_NATIVE_OVERRIDE_VOID(8016dc68, GX__SetVtxAttrFmt_8016dc68, (uint32_t vf, uin extern "C" void GX__SetVtxAttrFmtv_8016de08(uint32_t vf, uint32_t la) { if(!la) return; uint32_t p=la; + std::vector> list; while(true){ uint32_t a=Memory::Read32(p); if(a==0xFFu) break; - GX__SetVtxAttrFmt_8016dc68(vf, a, Memory::Read32(p+4), Memory::Read32(p+8), Memory::Read32(p+12)&0xFFu); + list.push_back({a, Memory::Read32(p+4), Memory::Read32(p+8), Memory::Read8(p+12)}); p+=16; } + GxWorker::Run([vf, list = std::move(list)] { + for (const auto& [a, c, t, fr] : list) GX__SetVtxAttrFmt_8016dc68(vf, a, c, t, fr); + }); } PPC_NATIVE_OVERRIDE_VOID(8016de08, GX__SetVtxAttrFmtv_8016de08, (uint32_t vf, uint32_t la), (vf, la)); extern "C" void GX__GetVtxAttrFmt_8016e04c(uint32_t vf, uint32_t a, uint32_t cp, uint32_t tp, uint32_t fp) { + GX_SYNC_INLINE(); VtxAttrFmt fmt{}; const uint32_t attr = CanonicalVtxAttr(a); if (vf < 8 && attr < GX_VA_MAX_ATTR && attr != GX_VA_NULL) { @@ -157,6 +182,7 @@ extern "C" void GX__GetVtxAttrFmtv_8016e2b8(uint32_t vf, uint32_t la) { if (!la) { return; } + GX_SYNC_INLINE(); uint32_t p = la; for (uint32_t a = GX_VA_POS; a <= GX_VA_TEX7; ++a) { @@ -179,6 +205,11 @@ PPC_NATIVE_OVERRIDE_VOID(8016e2b8, GX__GetVtxAttrFmtv_8016e2b8, (uint32_t vf, ui // ============================================================================ extern "C" void GX__SetArray_8016e32c(uint32_t a, uint32_t ba, uint32_t str) { + if (!GxWorker::OnWorker()) { + const uint32_t attr = CanonicalVtxAttr(a); + if (attr < 26) g_apiVtxArrays[attr] = {ba, str}; + } + GX_DEFER_CALL(GX__SetArray_8016e32c, a, ba, str); const uint32_t attr = CanonicalVtxAttr(a); if(attr<26){ g_hleGxState.vtxArray[attr].base=ba; g_hleGxState.vtxArray[attr].stride=str; } } @@ -194,11 +225,13 @@ PPC_NATIVE_OVERRIDE_VOID(8016e1c4, GX__SetArray_8016e1c4, (uint32_t a, uint32_t // ============================================================================ extern "C" void GX__SetNumTexGens_8016e5a4(uint32_t n) { + GX_DEFER_CALL(GX__SetNumTexGens_8016e5a4, n); GXSetNumTexGens((u8)n); } PPC_NATIVE_OVERRIDE_VOID(8016e5a4, GX__SetNumTexGens_8016e5a4, (uint32_t n), (n)); extern "C" void GX__SetTexCoordGen2_8016e37c(uint32_t dc, uint32_t f, uint32_t sp, uint32_t m, uint32_t n, uint32_t pm) { + GX_DEFER_CALL(GX__SetTexCoordGen2_8016e37c, dc, f, sp, m, n, pm); if (sp >= static_cast(GX_MAX_TEXGENSRC)) { uint32_t pc = 0; uint32_t lr = 0; @@ -215,6 +248,7 @@ extern "C" void GX__SetTexCoordGen2_8016e37c(uint32_t dc, uint32_t f, uint32_t s PPC_NATIVE_OVERRIDE_VOID(8016e37c, GX__SetTexCoordGen2_8016e37c, (uint32_t dc, uint32_t f, uint32_t sp, uint32_t m, uint32_t n, uint32_t pm), (dc, f, sp, m, n, pm)); extern "C" void GX__EnableTexOffsets_8016f37c(uint32_t coord, uint32_t lineEnable, uint32_t pointEnable) { + GX_DEFER_CALL(GX__EnableTexOffsets_8016f37c, coord, lineEnable, pointEnable); GXEnableTexOffsets(static_cast(coord), lineEnable ? GX_TRUE : GX_FALSE, pointEnable ? GX_TRUE : GX_FALSE); @@ -222,11 +256,13 @@ extern "C" void GX__EnableTexOffsets_8016f37c(uint32_t coord, uint32_t lineEnabl PPC_NATIVE_OVERRIDE_VOID(8016f37c, GX__EnableTexOffsets_8016f37c, (uint32_t coord, uint32_t lineEnable, uint32_t pointEnable), (coord, lineEnable, pointEnable)); extern "C" void GX__SetLineWidth_8016f314(uint32_t width, uint32_t texOffsets) { + GX_DEFER_CALL(GX__SetLineWidth_8016f314, width, texOffsets); GXSetLineWidth(static_cast(width), static_cast(texOffsets)); } PPC_NATIVE_OVERRIDE_VOID(8016f314, GX__SetLineWidth_8016f314, (uint32_t width, uint32_t texOffsets), (width, texOffsets)); extern "C" void GX__SetPointSize_8016f348(uint32_t pointSize, uint32_t texOffsets) { + GX_DEFER_CALL(GX__SetPointSize_8016f348, pointSize, texOffsets); GXSetPointSize(static_cast(pointSize), static_cast(texOffsets)); } PPC_NATIVE_OVERRIDE_VOID(8016f348, GX__SetPointSize_8016f348, (uint32_t pointSize, uint32_t texOffsets), (pointSize, texOffsets)); @@ -274,6 +310,8 @@ void ServiceDeferredTimingDuringGxWork() { } } +static void GxBeginImpl(uint32_t t, uint32_t vf, uint32_t nv); + extern "C" void GX__Begin_8016f0f0(uint32_t t, uint32_t vf, uint32_t nv) { if(IsDisplayListActive()){ WriteDisplayListData((u8)(t|vf), 1); @@ -281,21 +319,32 @@ extern "C" void GX__Begin_8016f0f0(uint32_t t, uint32_t vf, uint32_t nv) { return; } ServiceDeferredTimingDuringGxWork(); + GX_DEFER_CALL(GxBeginImpl, t, vf, nv); + GxBeginImpl(t, vf, nv); +} + +static void GxBeginImpl(uint32_t t, uint32_t vf, uint32_t nv) { ApplyAuroraVtxStateForBegin(static_cast(vf)); g_hleGxState.currentVtxFmt=(GXVtxFmt)vf; g_hleGxState.currentPrim=(GXPrimitive)t; - g_hleGxState.vertsRemaining=nv; g_hleGxState.inBegin=true; g_hleGxState.auroraBeginCalled=false; + g_hleGxState.vertsRemaining=nv; g_hleGxState.inBegin=nv!=0; g_hleGxState.auroraBeginCalled=false; g_hleGxState.fifoReadOffset = 0; g_hleGxState.fifoByteCount=0; g_hleGxState.ResetVertex(); } PPC_NATIVE_OVERRIDE_VOID(8016f0f0, GX__Begin_8016f0f0, (uint32_t t, uint32_t vf, uint32_t nv), (t, vf, nv)); -extern "C" void GX__End_80044b30() { g_hleGxState.inBegin=false; GXEnd(); } +extern "C" void GX__End_80044b30() { + GX_DEFER_CALL0(GX__End_80044b30); g_hleGxState.inBegin=false; GXEnd(); } PPC_NATIVE_OVERRIDE_VOID(80044b30, GX__End_80044b30, (), ()); extern "C" void GX__End_80048c30() { GX__End_80044b30(); } PPC_NATIVE_OVERRIDE_VOID(80048c30, GX__End_80048c30, (), ()); extern "C" void GX__DrawSphere_80172a30(uint32_t numMajor, uint32_t numMinor) { + if (GxWorker::ShouldDefer()) { + EnsureAuroraFrameActive(); + GxWorker::Submit([=] { GX__DrawSphere_80172a30(numMajor, numMinor); }); + return; + } constexpr uint32_t kAttrCount = 26; constexpr float kSphereRadius = 1.0f; constexpr float kPi = 3.14159265358979323846f; diff --git a/runtime/src/hle/gx/gx_worker.cpp b/runtime/src/hle/gx/gx_worker.cpp new file mode 100644 index 0000000..717ebc7 --- /dev/null +++ b/runtime/src/hle/gx/gx_worker.cpp @@ -0,0 +1,371 @@ +#include "gx_worker.h" + +#include "runtime_config.h" +#include "runtime_log.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) +#include +#endif +#if defined(__x86_64__) || defined(_M_X64) +#include +#endif + +void GxWorkerReplayFifoWrite(uint32_t value, uint32_t sizeBytes); +void GxWorkerReplayFifoBurst(const uint8_t* data, uint32_t sizeBytes); + +namespace GxWorker { +namespace detail { +std::atomic g_active{false}; +constinit thread_local bool t_onWorker = false; +constinit thread_local int t_inlineDepth = 0; +bool g_fifoPending = false; +} // namespace detail + +namespace { +struct Header { + void (*run)(void* payload); + uint32_t size; + uint32_t reserved; +}; +constexpr size_t kHeaderSize = 16; +static_assert(sizeof(Header) == kHeaderSize); + +constexpr size_t kCapacity = size_t{8} << 20; +// How long the worker keeps polling before it sleeps; recording arrives in bursts and each wake-up +// costs the game thread a lock and notify. +constexpr auto kIdleSpin = std::chrono::microseconds{50}; +constexpr size_t kFifoFlushBytes = 8 * 1024; +constexpr uint8_t kFifoBurstTag = 0xB0; + +uint8_t* g_ring = nullptr; +uint64_t g_write = 0; +std::atomic g_head{0}; +std::atomic g_tail{0}; +std::atomic g_consumerWaiting{false}; +std::atomic g_producerWaiting{false}; +std::mutex g_headMutex; +std::condition_variable g_headCv; +std::mutex g_tailMutex; +std::condition_variable g_tailCv; +void (*g_waitCallback)() = nullptr; +std::atomic g_stop{false}; +std::atomic g_abandon{false}; +std::atomic g_exited{false}; +std::thread* g_thread = nullptr; +std::vector g_fifoBytes; + +constexpr size_t AlignUp(size_t value) { return (value + detail::kAlign - 1) & ~(detail::kAlign - 1); } + +inline void CpuRelax() { +#if defined(__x86_64__) || defined(_M_X64) + _mm_pause(); +#endif +} + +// libc++ on Windows truncates sub-millisecond condvar timeouts to zero (a spin), so the bounded +// wait goes straight to the OS there. +void WaitTailBriefly(std::unique_lock& lock) { +#if defined(_WIN32) && defined(_LIBCPP_VERSION) + SleepConditionVariableSRW(reinterpret_cast(g_tailCv.native_handle()), + reinterpret_cast(lock.mutex()->native_handle()), 1, 0); +#else + g_tailCv.wait_for(lock, std::chrono::milliseconds{1}); +#endif +} + +void WaitForTail(uint64_t minTail, bool service) { + for (int spin = 0; spin < 256 && g_tail.load(std::memory_order_acquire) < minTail; ++spin) { + CpuRelax(); + } + while (g_tail.load(std::memory_order_acquire) < minTail) { + { + std::unique_lock lock{g_tailMutex}; + g_producerWaiting.store(true, std::memory_order_seq_cst); + if (g_tail.load(std::memory_order_seq_cst) < minTail) { + WaitTailBriefly(lock); + } + g_producerWaiting.store(false, std::memory_order_relaxed); + } + if (service && g_waitCallback != nullptr && g_tail.load(std::memory_order_acquire) < minTail) { + g_waitCallback(); + } + } +} + +void WaitForSpace(size_t bytes) { + if (g_write + bytes > kCapacity) { + WaitForTail(g_write + bytes - kCapacity, false); + } +} + +void ReplayFifo(void* payload) { + uint32_t size = 0; + std::memcpy(&size, payload, sizeof(size)); + const uint8_t* data = static_cast(payload) + sizeof(size); + const uint8_t* end = data + size; + while (data < end) { + const uint8_t tag = *data++; + if (tag == kFifoBurstTag) { + uint32_t length = 0; + std::memcpy(&length, data, sizeof(length)); + data += sizeof(length); + try { + GxWorkerReplayFifoBurst(data, length); + } catch (...) { + RT_LOGF(RT_TAG_GX, "GX worker FIFO burst failed\n"); + } + data += length; + } else { + uint32_t value = 0; + std::memcpy(&value, data, sizeof(value)); + data += sizeof(value); + try { + GxWorkerReplayFifoWrite(value, tag); + } catch (...) { + RT_LOGF(RT_TAG_GX, "GX worker FIFO write failed\n"); + } + } + } +} + +void WorkerMain() { + detail::t_onWorker = true; + struct SignalExit { + ~SignalExit() { + std::lock_guard lock{g_tailMutex}; + g_exited.store(true, std::memory_order_release); + g_tailCv.notify_all(); + } + } signalExit; + AuroraSetGxProducerThread(); +#if defined(_WIN32) + SetThreadDescription(GetCurrentThread(), L"GX worker"); +#endif + uint64_t tail = g_tail.load(std::memory_order_relaxed); + for (;;) { + uint64_t head = g_head.load(std::memory_order_acquire); + if (head == tail) { + const auto spinUntil = std::chrono::steady_clock::now() + kIdleSpin; + while (head == tail) { + for (int spin = 0; spin < 64 && head == tail; ++spin) { + CpuRelax(); + head = g_head.load(std::memory_order_acquire); + } + if (head == tail && std::chrono::steady_clock::now() >= spinUntil) { + break; + } + } + } + if (head == tail) { + if (g_stop.load(std::memory_order_acquire)) { + return; + } + { + std::unique_lock lock{g_headMutex}; + g_consumerWaiting.store(true, std::memory_order_seq_cst); + while (g_head.load(std::memory_order_seq_cst) == tail && !g_stop.load(std::memory_order_acquire)) { + g_headCv.wait(lock); + } + g_consumerWaiting.store(false, std::memory_order_relaxed); + } + continue; + } + while (tail != head) { + if (g_abandon.load(std::memory_order_acquire)) { + return; + } + uint8_t* record = g_ring + tail % kCapacity; + const Header* header = reinterpret_cast(record); + if (header->run != nullptr) { + try { + header->run(record + kHeaderSize); + } catch (const std::exception& error) { + RT_LOGF(RT_TAG_GX, "GX worker command failed: %s\n", error.what()); + } catch (...) { + RT_LOGF(RT_TAG_GX, "GX worker command failed\n"); + } + } + tail += header->size; + g_tail.store(tail, std::memory_order_seq_cst); + if (g_producerWaiting.load(std::memory_order_seq_cst)) { + std::lock_guard lock{g_tailMutex}; + g_tailCv.notify_all(); + } + } + } +} +} // namespace + +namespace detail { +void* Reserve(size_t payloadSize, void (*run)(void*)) { + const size_t total = kHeaderSize + AlignUp(payloadSize); + if (total > kCapacity) { + RT_LOGF(RT_TAG_GX, "GX worker command of %zu bytes exceeds the ring\n", total); + std::abort(); + } + size_t offset = static_cast(g_write % kCapacity); + const size_t remaining = kCapacity - offset; + if (total > remaining) { + WaitForSpace(remaining); + auto* wrap = reinterpret_cast(g_ring + offset); + wrap->run = nullptr; + wrap->size = static_cast(remaining); + g_write += remaining; + // Publish the skip so the worker can drain past it while we wait for the front. + Commit(); + offset = 0; + } + WaitForSpace(total); + auto* header = reinterpret_cast(g_ring + offset); + header->run = run; + header->size = static_cast(total); + g_write += total; + return g_ring + offset + kHeaderSize; +} + +void Commit() { + g_head.store(g_write, std::memory_order_seq_cst); + if (g_consumerWaiting.load(std::memory_order_seq_cst)) { + std::lock_guard lock{g_headMutex}; + g_headCv.notify_one(); + } +} + +void FlushFifo() { + g_fifoPending = false; + if (g_fifoBytes.empty()) { + return; + } + const uint32_t size = static_cast(g_fifoBytes.size()); + void* payload = Reserve(sizeof(size) + size, &ReplayFifo); + std::memcpy(payload, &size, sizeof(size)); + std::memcpy(static_cast(payload) + sizeof(size), g_fifoBytes.data(), size); + g_fifoBytes.clear(); + Commit(); +} +} // namespace detail + +void FifoWrite(uint32_t value, uint32_t sizeBytes) { + const size_t at = g_fifoBytes.size(); + g_fifoBytes.resize(at + 1 + sizeof(value)); + g_fifoBytes[at] = static_cast(sizeBytes); + std::memcpy(g_fifoBytes.data() + at + 1, &value, sizeof(value)); + detail::g_fifoPending = true; + if (g_fifoBytes.size() >= kFifoFlushBytes) { + detail::FlushFifo(); + } +} + +void FifoBurst(const uint8_t* data, uint32_t sizeBytes) { + const size_t at = g_fifoBytes.size(); + g_fifoBytes.resize(at + 1 + sizeof(sizeBytes) + sizeBytes); + g_fifoBytes[at] = kFifoBurstTag; + std::memcpy(g_fifoBytes.data() + at + 1, &sizeBytes, sizeof(sizeBytes)); + std::memcpy(g_fifoBytes.data() + at + 1 + sizeof(sizeBytes), data, sizeBytes); + detail::g_fifoPending = true; + if (g_fifoBytes.size() >= kFifoFlushBytes) { + detail::FlushFifo(); + } +} + +void Sync() { + if (!Active() || detail::t_onWorker) { + return; + } + // Guest callbacks serviced while waiting can record more work. + do { + if (detail::g_fifoPending) { + detail::FlushFifo(); + } + WaitForTail(g_write, true); + } while (detail::g_fifoPending || g_tail.load(std::memory_order_acquire) != g_write); +} + +void SetWaitCallback(void (*callback)()) { g_waitCallback = callback; } + +void BeginInline() { + if (detail::t_inlineDepth == 0 && Active() && !detail::t_onWorker) { + Sync(); + } + ++detail::t_inlineDepth; +} + +void EndInline() { --detail::t_inlineDepth; } + +void Start() { + if (Active()) { + return; + } + if (!RuntimeConfigFile::GxWorkerEnabled(true)) { + RT_LOGF(RT_TAG_GX, "GX worker disabled\n"); + return; + } + if (g_ring == nullptr) { + g_ring = static_cast(::operator new(kCapacity, std::align_val_t{64})); + } + g_fifoBytes.reserve(kFifoFlushBytes + 4096); + g_stop.store(false, std::memory_order_relaxed); + g_abandon.store(false, std::memory_order_relaxed); + g_exited.store(false, std::memory_order_relaxed); + g_thread = new std::thread(WorkerMain); + detail::g_active.store(true, std::memory_order_release); + RT_LOGF(RT_TAG_GX, "GX worker started\n"); +} + +void Stop() { + if (!Active()) { + return; + } + // Guest state may already be torn down; don't service it while draining. + g_waitCallback = nullptr; + Sync(); + detail::g_active.store(false, std::memory_order_release); + g_stop.store(true, std::memory_order_release); + Submit([] {}); + if (g_thread != nullptr) { + g_thread->join(); + delete g_thread; + g_thread = nullptr; + } +} + +void Abandon() { + if (!Active() || detail::t_onWorker) { + return; + } + detail::g_active.store(false, std::memory_order_release); + g_abandon.store(true, std::memory_order_release); + g_stop.store(true, std::memory_order_release); + { + std::lock_guard lock{g_headMutex}; + g_headCv.notify_one(); + } + bool exited = false; + { + std::unique_lock lock{g_tailMutex}; + exited = g_tailCv.wait_for(lock, std::chrono::seconds{2}, + [] { return g_exited.load(std::memory_order_acquire); }); + } + if (g_thread != nullptr) { + if (exited) { + g_thread->join(); + delete g_thread; + } else { + g_thread->detach(); + } + g_thread = nullptr; + } +} + +} // namespace GxWorker diff --git a/runtime/src/hle/hollywood_gpio.cpp b/runtime/src/hle/hollywood_gpio.cpp new file mode 100644 index 0000000..ff774bd --- /dev/null +++ b/runtime/src/hle/hollywood_gpio.cpp @@ -0,0 +1,32 @@ +#include "hle/hollywood_gpio.h" + +#include "runtime_log.h" + +#include + +namespace HollywoodGpio { + +constexpr uint32_t kSensorBarPower = 0x100; + +std::atomic g_gpioBOut{0}; + +} // namespace HollywoodGpio + +bool HollywoodGpio_Read32(uint32_t address, uint32_t& value) { + if (address != kHollywoodGpioBOut) { + return false; + } + value = HollywoodGpio::g_gpioBOut.load(std::memory_order_relaxed); + return true; +} + +bool HollywoodGpio_Write32(uint32_t address, uint32_t value) { + if (address != kHollywoodGpioBOut) { + return false; + } + const uint32_t previous = HollywoodGpio::g_gpioBOut.exchange(value, std::memory_order_relaxed); + if ((previous ^ value) & HollywoodGpio::kSensorBarPower) { + RT_LOG(RT_TAG_HLE) << "Sensor bar power " << ((value & HollywoodGpio::kSensorBarPower) ? "on" : "off") << std::endl; + } + return true; +} diff --git a/runtime/src/hle/input/kpad.cpp b/runtime/src/hle/input/kpad.cpp deleted file mode 100644 index 5246d63..0000000 --- a/runtime/src/hle/input/kpad.cpp +++ /dev/null @@ -1,268 +0,0 @@ -#include "hle_stubs.h" -#include "input_bindings.h" -#include "memory.h" -#include "wii_remote_input.h" - -#include -#include -#include -#include - -// KPAD HLE fed by a real Bluetooth Wii Remote. The game calls KPADRead once per -// frame with room for 16 KPADStatus entries and only looks at entry 0; with a -// Classic Controller it also calls KPADGetUnifiedWpadStatus for the raw -// WPADCLStatus (buttons, sticks and triggers of the extension). -namespace { - -constexpr uint32_t kKpadStatusSize = 0x84; - -// KPADStatus field offsets (RVL SDK). -constexpr uint32_t kHold = 0x00, kTrig = 0x04, kRelease = 0x08, kAcc = 0x0C, kAccValue = 0x18, - kAccSpeed = 0x1C, kPos = 0x20, kAccVertical = 0x54, kDevType = 0x5C, kWpadErr = 0x5D, - kDpdValidFg = 0x5E, kDataFormat = 0x5F, kFsStick = 0x60, kFsAcc = 0x68, kFsAccValue = 0x74, - kFsAccSpeed = 0x78; -// KPADStatus.ex_status.cl (KPADEXStatus, Classic Controller view). -constexpr uint32_t kClHold = 0x60, kClTrig = 0x64, kClRelease = 0x68, kClLStick = 0x6C, kClRStick = 0x74, - kClLTrigger = 0x7C, kClRTrigger = 0x80; - -// KPADUnifiedWpadStatus: WPADStatus / WPADFSStatus / WPADCLStatus union, then fmt. -constexpr uint32_t kUnifiedSize = 0x38; -constexpr uint32_t kUButton = 0x00, kUAccX = 0x02, kUAccY = 0x04, kUAccZ = 0x06, kUObj = 0x08, kUDev = 0x28, - kUErr = 0x29, kUFsStickX = 0x2A, kUFsStickY = 0x2B, kUFsAccX = 0x2C, kUFsAccY = 0x2E, - kUFsAccZ = 0x30, kUClButton = 0x2A, kUClLStickX = 0x2C, kUClLStickY = 0x2E, kUClRStickX = 0x30, - kUClRStickY = 0x32, kUClTriggerL = 0x34, kUClTriggerR = 0x35, kUFmt = 0x36; - -// WPAD device types (WPAD_DEV_*) and the data formats KPAD runs each of them -// in (WPAD_FMT_*_ACC_DPD): the values KPADStatus.dev_type / data_format and -// KPADUnifiedWpadStatus.dev / fmt carry on the console. -constexpr uint8_t kDevCore = 0; -constexpr uint8_t kDevFreestyle = 1; -constexpr uint8_t kDevClassic = 2; -constexpr uint8_t kFmtCoreAccDpd = 2; -constexpr uint8_t kFmtFreestyleAccDpd = 5; -constexpr uint8_t kFmtClassicAccDpd = 8; -constexpr int8_t kWpadErrNone = 0; -constexpr int8_t kWpadErrNoController = -1; - -// Raw accelerometer as WPADStatus carries it: 10 bits, 0x200 at 0 g, 100 per g. -constexpr float kRawAccZero = 512.0f; -constexpr float kRawAccPerG = 100.0f; - -struct ChannelState { - uint32_t prevHold = 0; - uint32_t prevClHold = 0; - float prevAcc[3] = {0.0f, -1.0f, 0.0f}; - float prevFsAcc[3] = {0.0f, -1.0f, 0.0f}; -}; - -std::array g_channels{}; - -// Euclidean length of a 3-vector. -float Length(const float* v) { - return std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); -} - -// Euclidean distance between two 3-vectors. -float Distance(const float* a, const float* b) { - const float d[3] = {a[0] - b[0], a[1] - b[1], a[2] - b[2]}; - return Length(d); -} - -// Writes three big-endian floats to guest memory. -void WriteVec3(uint32_t addr, const float* v) { - Memory::WriteFloat32(addr, v[0]); - Memory::WriteFloat32(addr + 4, v[1]); - Memory::WriteFloat32(addr + 8, v[2]); -} - -// Zeroes `count` consecutive floats in guest memory. -void WriteZeroFloats(uint32_t addr, uint32_t count) { - for (uint32_t i = 0; i < count; ++i) { - Memory::WriteFloat32(addr + i * 4, 0.0f); - } -} - -// Fills one KPADStatus at `addr` and returns the number of valid entries (1), -// or writes an "unplugged" status and returns 0. -int32_t WriteStatus(uint32_t chan, uint32_t addr, const WiiRemoteInput::KpadSample* sample) { - ChannelState& state = g_channels[chan]; - if (sample == nullptr) { - state = {}; - Memory::Write32(addr + kHold, 0); - Memory::Write32(addr + kTrig, 0); - Memory::Write32(addr + kRelease, 0); - Memory::Write8(addr + kDevType, kDevCore); - Memory::Write8(addr + kWpadErr, static_cast(kWpadErrNoController)); - Memory::Write8(addr + kDpdValidFg, 0); - return 0; - } - - const uint32_t hold = sample->hold; - Memory::Write32(addr + kHold, hold); - Memory::Write32(addr + kTrig, hold & ~state.prevHold); - Memory::Write32(addr + kRelease, state.prevHold & ~hold); - state.prevHold = hold; - - WriteVec3(addr + kAcc, sample->acc); - Memory::WriteFloat32(addr + kAccValue, Length(sample->acc)); - Memory::WriteFloat32(addr + kAccSpeed, Distance(sample->acc, state.prevAcc)); - for (int i = 0; i < 3; ++i) state.prevAcc[i] = sample->acc[i]; - - // No IR pointer: pos .. acc_vertical zeroed and dpd_valid_fg clear, which - // the game treats as "pointing away from the screen". - WriteZeroFloats(addr + kPos, (kAccVertical + 8 - kPos) / 4); - Memory::Write8(addr + kDpdValidFg, 0); - - const uint8_t devType = sample->hasClassic ? kDevClassic : sample->hasNunchuk ? kDevFreestyle : kDevCore; - const uint8_t dataFormat = - sample->hasClassic ? kFmtClassicAccDpd : sample->hasNunchuk ? kFmtFreestyleAccDpd : kFmtCoreAccDpd; - Memory::Write8(addr + kDevType, devType); - Memory::Write8(addr + kWpadErr, static_cast(kWpadErrNone)); - Memory::Write8(addr + kDataFormat, dataFormat); - - if (sample->hasClassic) { - const uint32_t clHold = sample->clHold; - Memory::Write32(addr + kClHold, clHold); - Memory::Write32(addr + kClTrig, clHold & ~state.prevClHold); - Memory::Write32(addr + kClRelease, state.prevClHold & ~clHold); - state.prevClHold = clHold; - Memory::WriteFloat32(addr + kClLStick, sample->clLStick[0]); - Memory::WriteFloat32(addr + kClLStick + 4, sample->clLStick[1]); - Memory::WriteFloat32(addr + kClRStick, sample->clRStick[0]); - Memory::WriteFloat32(addr + kClRStick + 4, sample->clRStick[1]); - Memory::WriteFloat32(addr + kClLTrigger, sample->clTriggerL / 255.0f); - Memory::WriteFloat32(addr + kClRTrigger, sample->clTriggerR / 255.0f); - } else if (sample->hasNunchuk) { - state.prevClHold = 0; - Memory::WriteFloat32(addr + kFsStick, sample->stick[0]); - Memory::WriteFloat32(addr + kFsStick + 4, sample->stick[1]); - WriteVec3(addr + kFsAcc, sample->nunchukAcc); - Memory::WriteFloat32(addr + kFsAccValue, Length(sample->nunchukAcc)); - Memory::WriteFloat32(addr + kFsAccSpeed, Distance(sample->nunchukAcc, state.prevFsAcc)); - for (int i = 0; i < 3; ++i) state.prevFsAcc[i] = sample->nunchukAcc[i]; - } else { - state.prevClHold = 0; - WriteZeroFloats(addr + kFsStick, (kKpadStatusSize - kFsStick) / 4); - } - return 1; -} - -// One accelerometer axis of KPAD's g vector back to the 10-bit raw WPAD value. -uint16_t RawAcc(float g) { - const float raw = kRawAccZero + g * kRawAccPerG; - return static_cast(std::clamp(raw, 0.0f, 1023.0f)); -} - -// Fills one KPADUnifiedWpadStatus at `addr` from the sample: the WPADStatus core -// (remote buttons, raw accelerometer, no IR objects), then the Nunchuk or Classic -// Controller tail, then the data format. -void WriteUnifiedStatus(uint32_t addr, const WiiRemoteInput::KpadSample* sample) { - for (uint32_t offset = 0; offset < kUnifiedSize; offset += 4) { - Memory::Write32(addr + offset, 0); - } - if (sample == nullptr) { - Memory::Write8(addr + kUDev, kDevCore); - Memory::Write8(addr + kUErr, static_cast(kWpadErrNoController)); - Memory::Write8(addr + kUFmt, kFmtCoreAccDpd); - return; - } - Memory::Write16(addr + kUButton, static_cast(sample->hold & 0xFFFF)); - // KPAD's acc is (-wiiX, -wiiZ, wiiY); WPADStatus keeps the remote's own axes. - Memory::Write16(addr + kUAccX, RawAcc(-sample->acc[0])); - Memory::Write16(addr + kUAccY, RawAcc(sample->acc[2])); - Memory::Write16(addr + kUAccZ, RawAcc(-sample->acc[1])); - // No IR: every DPDObject invalid (x/y at the sensor's out-of-range value). - for (uint32_t i = 0; i < 4; ++i) { - Memory::Write16(addr + kUObj + i * 8, 0x3FF); - Memory::Write16(addr + kUObj + i * 8 + 2, 0x3FF); - } - Memory::Write8(addr + kUErr, static_cast(kWpadErrNone)); - if (sample->hasClassic) { - Memory::Write8(addr + kUDev, kDevClassic); - Memory::Write16(addr + kUClButton, static_cast(sample->clHold & 0xFFFF)); - Memory::Write16(addr + kUClLStickX, static_cast(sample->clLStickRaw[0])); - Memory::Write16(addr + kUClLStickY, static_cast(sample->clLStickRaw[1])); - Memory::Write16(addr + kUClRStickX, static_cast(sample->clRStickRaw[0])); - Memory::Write16(addr + kUClRStickY, static_cast(sample->clRStickRaw[1])); - Memory::Write8(addr + kUClTriggerL, sample->clTriggerL); - Memory::Write8(addr + kUClTriggerR, sample->clTriggerR); - Memory::Write8(addr + kUFmt, kFmtClassicAccDpd); - } else if (sample->hasNunchuk) { - Memory::Write8(addr + kUDev, kDevFreestyle); - // WPADFSStatus: 8-bit stick (centre 128) and 10-bit Nunchuk accelerometer. - Memory::Write8(addr + kUFsStickX, - static_cast(std::clamp(128.0f + sample->stick[0] * 100.0f, 0.0f, 255.0f))); - Memory::Write8(addr + kUFsStickY, - static_cast(std::clamp(128.0f + sample->stick[1] * 100.0f, 0.0f, 255.0f))); - Memory::Write16(addr + kUFsAccX, RawAcc(-sample->nunchukAcc[0])); - Memory::Write16(addr + kUFsAccY, RawAcc(sample->nunchukAcc[2])); - Memory::Write16(addr + kUFsAccZ, RawAcc(-sample->nunchukAcc[1])); - Memory::Write8(addr + kUFmt, kFmtFreestyleAccDpd); - } else { - Memory::Write8(addr + kUDev, kDevCore); - Memory::Write8(addr + kUFmt, kFmtCoreAccDpd); - } -} - -// Neutral sticks and no buttons while an overlay owns input; the remote stays connected. -bool ReadSample(uint32_t chan, WiiRemoteInput::KpadSample& sample) { - if (!WiiRemoteInput::ReadKpadSample(chan, sample)) { - return false; - } - if (InputBindings::InputBlocked()) { - sample.hold = 0; - sample.clHold = 0; - sample.stick[0] = sample.stick[1] = 0.0f; - sample.clLStick[0] = sample.clLStick[1] = 0.0f; - sample.clRStick[0] = sample.clRStick[1] = 0.0f; - sample.clLStickRaw[0] = sample.clLStickRaw[1] = 0; - sample.clRStickRaw[0] = sample.clRStickRaw[1] = 0; - sample.clTriggerL = sample.clTriggerR = 0; - } - return true; -} - -} // namespace - -// KPADRead: fills KPADStatus[0] for `chan` from the Bluetooth remote, returns the entry count. -extern "C" int32_t KPAD__Read_HLE(uint32_t chan, uint32_t statusPtr, uint32_t count) -{ - if (chan >= g_channels.size() || statusPtr == 0 || count == 0) { - return 0; - } - WiiRemoteInput::KpadSample sample; - const bool have = ReadSample(chan, sample); - try { - return WriteStatus(chan, statusPtr, have ? &sample : nullptr); - } catch (const Memory::AccessViolation&) { - return 0; - } -} -PPC_NATIVE_OVERRIDE(80197380, KPAD__Read_HLE, int32_t, (uint32_t chan, uint32_t statusPtr, uint32_t count), - (chan, statusPtr, count)); - -// KPADGetUnifiedWpadStatus: the raw WPAD status behind KPADStatus. The game -// reads the Classic Controller's buttons, sticks and triggers from here. The -// SDK fills `count` entries with the channel's recent samples (the game asks for -// as many as it asked KPADRead for and looks at entry 0); with one sample per -// frame here, every entry gets the current one. -extern "C" int32_t KPAD__GetUnifiedWpadStatus_HLE(uint32_t chan, uint32_t statusPtr, uint32_t count) -{ - constexpr uint32_t kMaxEntries = 16; // KPAD_MAX_READ_BUFS - if (chan >= g_channels.size() || statusPtr == 0 || count == 0) { - return 0; - } - WiiRemoteInput::KpadSample sample; - const bool have = ReadSample(chan, sample); - try { - const uint32_t entries = std::min(count, kMaxEntries); - for (uint32_t i = 0; i < entries; ++i) { - WriteUnifiedStatus(statusPtr + i * kUnifiedSize, have ? &sample : nullptr); - } - } catch (const Memory::AccessViolation&) { - return 0; - } - return have ? 1 : 0; -} -PPC_NATIVE_OVERRIDE(8019812C, KPAD__GetUnifiedWpadStatus_HLE, int32_t, - (uint32_t chan, uint32_t statusPtr, uint32_t count), (chan, statusPtr, count)); diff --git a/runtime/src/hle/input/pad.cpp b/runtime/src/hle/input/pad.cpp index c0bbfdb..24ad29f 100644 --- a/runtime/src/hle/input/pad.cpp +++ b/runtime/src/hle/input/pad.cpp @@ -2,7 +2,6 @@ #include "memory.h" #include "hle/controller_status_contract.h" #include "input_bindings.h" -#include "wii_remote_input.h" #include #include @@ -113,13 +112,7 @@ extern "C" uint32_t PAD__Read_HLE(uint32_t statusPtr) } PADStatus statuses[PAD_CHANMAX]{}; - // Keep looking for a Bluetooth Wii Remote that dropped out (or was turned on late). - WiiRemoteInput::Poll(); uint32_t rumbleMask = PADRead(statuses); - // Wii Remotes reach the game through KPAD, not as GameCube pads. This also - // applies while input is blocked (overlay open) so the port does not flip - // between "connected" and "no controller" every time the overlay toggles. - WiiRemoteInput::HideRemotesFromPad(statuses, PAD_CHANMAX); FillTriggersHeldByButtons(statuses); InputBindings::Apply(statuses); diff --git a/runtime/src/hle/input/wpad.cpp b/runtime/src/hle/input/wpad.cpp deleted file mode 100644 index 5c53953..0000000 --- a/runtime/src/hle/input/wpad.cpp +++ /dev/null @@ -1,217 +0,0 @@ -#include "hle_stubs.h" -#include "memory.h" -#include "hle/controller_status_contract.h" -#include "wii_remote_input.h" - -#include - -#include - -extern "C" bool PAD_HLE_RumbleEnabled(); -void NandQueueIosCallback(uint32_t callbackPtr, int32_t result, uint32_t callbackArg); - -namespace { - -constexpr uint32_t kDefaultWorkMemSize = 0x20000; -constexpr uint8_t kDefaultDpdSensitivity = 3; -constexpr int32_t kStatusOk = 0; - -struct WpadStubState { - bool initSubRan = false; - bool simpleSyncActive = false; - uint32_t syncDeviceCallback = 0; - uint32_t workMemSize = kDefaultWorkMemSize; - uint8_t dpdSensitivity = kDefaultDpdSensitivity; - WpadContract::State contract{}; -}; - -WpadStubState g_state{}; - -void InvokeWpadCallback(uint32_t callback, uint32_t chan, int32_t result) -{ - if (callback == 0) { - return; - } - if (!TranslatedFunctionRegistry::FindByAddressPtr(callback)) { - return; - } - auto& cpu = GetPersistentCpuContext(); - cpu.gpr[3] = chan; - cpu.gpr[4] = static_cast(result); - InvokeIndirectCpu(callback, &cpu); -} - -int32_t InitializeWpadLibrary() -{ - g_state.contract.Initialize(); - return kStatusOk; -} - -// The async WPAD entry points all report their outcome to the guest callback and -// then return the same value. -int32_t CompleteWpadRequest(uint32_t chan, uint32_t callback, int32_t result) -{ - InvokeWpadCallback(callback, chan, result); - return result; -} - -} // namespace - -extern "C" int32_t WPADGetStatus_HLE() -{ - // RVL::WPADGetStatus takes no channel arg; it reports global WUD library state. - // Reading r3 here would leak a caller's stale register value into the result. - return g_state.contract.GetLibraryStatus(); -} -PPC_NATIVE_OVERRIDE(801BF64C, WPADGetStatus_HLE, int32_t, (), ()); - -extern "C" uint32_t WPADGetDpdSensitivity_HLE() -{ - return static_cast(g_state.dpdSensitivity); -} -PPC_NATIVE_OVERRIDE(801C329C, WPADGetDpdSensitivity_HLE, uint32_t, (), ()); - -extern "C" int32_t WPADInitSub_HLE() -{ - if (!g_state.initSubRan) { - g_state.initSubRan = true; - return InitializeWpadLibrary(); - } - return kStatusOk; -} -PPC_NATIVE_OVERRIDE(801BF3B4, WPADInitSub_HLE, int32_t, (), ()); - -extern "C" int32_t WPADInit_HLE() -{ - return InitializeWpadLibrary(); -} -PPC_NATIVE_OVERRIDE(801BF5C4, WPADInit_HLE, int32_t, (), ()); - -extern "C" int32_t WUDGetStatus_HLE() -{ - return WpadContract::kStatusReady; -} -PPC_NATIVE_OVERRIDE(801CDB84, WUDGetStatus_HLE, int32_t, (), ()); - -// WPADGetDataFormat: the format KPAD runs the attached extension in (WPAD_FMT_*_ACC_DPD). -// WPADClampStick keys off it. Can't reuse the translated SDK implementation: it dereferences -// Bluetooth control blocks that HLE'd WPADInit never constructs. -extern "C" int32_t WPADGetDataFormat_HLE(uint32_t chan) -{ - const int32_t status = g_state.contract.GetDataFormat(chan); - if (status < 0) { - return status; - } - switch (WiiRemoteInput::EffectiveKind(chan)) { - case WiiRemoteInput::Kind::RemoteWithNunchuk: return 5; - case WiiRemoteInput::Kind::RemoteWithClassic: return 8; - default: return 2; - } -} -PPC_NATIVE_OVERRIDE(801C0B54, WPADGetDataFormat_HLE, int32_t, (uint32_t chan), (chan)); - -// WPADSetDataFormat: records the per-channel data format the game asked for. -extern "C" int32_t WPADSetDataFormat_HLE(uint32_t chan, int32_t format) -{ - return g_state.contract.SetDataFormat(chan, format); -} -PPC_NATIVE_OVERRIDE(801C0B9C, WPADSetDataFormat_HLE, int32_t, (uint32_t chan, int32_t format), (chan, format)); - -// WPADProbe: reports the extension type of a Bluetooth remote on `chan`, or no controller. -extern "C" int32_t WPADProbe_HLE(uint32_t chan, uint32_t typePtr) -{ - if (chan >= WpadContract::kChannelCount) { - return WpadContract::kErrorBadChannel; - } - - // Drive the rescan state machine here too: a reconnect probe can arrive - // before the next PADRead, and only Poll() brings a dropped remote back. - WiiRemoteInput::Poll(); - - // A real Bluetooth remote: WPAD_DEV_CORE (0) for a bare remote, - // WPAD_DEV_FREESTYLE (1) with a Nunchuk, WPAD_DEV_CLASSIC (2) with a Classic - // Controller. The game reads the type from here (not from - // KPADStatus.dev_type) to pick its control scheme, and re-reads it when it - // changes, which is what makes an extension swap mid-game work like on the - // console. EffectiveKind keeps the last type through SDL's re-creation of - // the joystick after a swap. - const WiiRemoteInput::Kind kind = WiiRemoteInput::EffectiveKind(chan); - if (WiiRemoteInput::IsRemoteChannel(chan)) { - if (typePtr != 0) { - uint32_t type = WpadContract::kExtensionCore; - if (kind == WiiRemoteInput::Kind::RemoteWithNunchuk) type = 1u; - if (kind == WiiRemoteInput::Kind::RemoteWithClassic) type = 2u; - Memory::Write32(typePtr, type); - } - return kStatusOk; - } - if (typePtr != 0) { - Memory::Write32(typePtr, WpadContract::kExtensionCore); - } - return WpadContract::kErrorNoController; -} -PPC_NATIVE_OVERRIDE(801C0990, WPADProbe_HLE, int32_t, (uint32_t chan, uint32_t typePtr), (chan, typePtr)); - -extern "C" void WPADControlMotor_HLE(uint32_t chan, uint32_t command) -{ - const bool on = command != 0 && PAD_HLE_RumbleEnabled(); - PADControlMotor(chan, on ? PAD_MOTOR_RUMBLE : PAD_MOTOR_STOP_HARD); -} -PPC_NATIVE_OVERRIDE(801C0EC4, WPADControlMotor_HLE, void, (uint32_t chan, uint32_t command), (chan, command)); - -extern "C" int32_t WPADGetInfoAsync_HLE(uint32_t chan, uint32_t infoPtr, uint32_t callback) -{ - if (chan >= WpadContract::kChannelCount) { - return CompleteWpadRequest(chan, callback, WpadContract::kErrorBadChannel); - } - - (void)infoPtr; - return CompleteWpadRequest(chan, callback, WpadContract::kErrorNoController); -} -PPC_NATIVE_OVERRIDE(801C0CA4, WPADGetInfoAsync_HLE, int32_t, - (uint32_t chan, uint32_t infoPtr, uint32_t callback), (chan, infoPtr, callback)); - -extern "C" int32_t WPADControlLed_HLE(uint32_t chan, uint32_t ledMask, uint32_t callback) -{ - if (chan >= WpadContract::kChannelCount) { - return CompleteWpadRequest(chan, callback, WpadContract::kErrorBadChannel); - } - (void)ledMask; - return CompleteWpadRequest(chan, callback, WpadContract::kErrorNoController); -} -PPC_NATIVE_OVERRIDE(801C0FF8, WPADControlLed_HLE, int32_t, - (uint32_t chan, uint32_t ledMask, uint32_t callback), (chan, ledMask, callback)); - -extern "C" int32_t WPADStartSimpleSync_HLE() -{ - if (g_state.simpleSyncActive) { - return 0; - } - g_state.simpleSyncActive = true; - return 1; -} -PPC_NATIVE_OVERRIDE(801BF634, WPADStartSimpleSync_HLE, int32_t, (), ()); // WUDStartSyncSimple -PPC_NATIVE_OVERRIDE(801BF638, WPADStartSimpleSync_HLE, int32_t, (), ()); // WPADStartSimpleSync (HBM) - -// due to multiplayer controller screen hle this to avoid startsyncdevice to return fail every frame -// causing you to get softlocked in the game -extern "C" int32_t WPADStopSimpleSync_HLE() -{ - if (g_state.simpleSyncActive) { - g_state.simpleSyncActive = false; - const uint32_t callback = g_state.syncDeviceCallback; - if (callback != 0 && TranslatedFunctionRegistry::FindByAddressPtr(callback)) { - NandQueueIosCallback(callback, 1, 0); // callback(WUD_SYNC_DONE, devicesSynced=0) - } - } - return 1; -} -PPC_NATIVE_OVERRIDE(801BF63C, WPADStopSimpleSync_HLE, int32_t, (), ()); - -extern "C" uint32_t WPADSetSyncDeviceCallback_HLE(uint32_t callback) -{ - const uint32_t previous = g_state.syncDeviceCallback; - g_state.syncDeviceCallback = callback; - return previous; -} -PPC_NATIVE_OVERRIDE(801BF640, WPADSetSyncDeviceCallback_HLE, uint32_t, (uint32_t callback), (callback)); diff --git a/runtime/src/hle/ios.cpp b/runtime/src/hle/ios.cpp index bdeab3b..9de2c3c 100644 --- a/runtime/src/hle/ios.cpp +++ b/runtime/src/hle/ios.cpp @@ -4,6 +4,7 @@ #include "hle_stubs.h" #include "memory.h" +#include "hle/bluetooth_hle.h" #include "hle/net/network.h" #include @@ -120,6 +121,10 @@ extern "C" void IOS_OpenAsync_HLE(CpuContext* ctx) { const uint32_t callbackArg = ctx->gpr[6]; const char* path = pathPtr ? (const char*)Memory::GetPointer(pathPtr) : "(null)"; if (pathPtr) { + if (const int32_t btFd = Bluetooth_HLE_OpenDevice(path)) { + CompleteAsync(ctx, callback, btFd, callbackArg); + return; + } if (const int32_t netFd = Network_HLE_OpenDevice(path, mode)) { CompleteAsync(ctx, callback, netFd, callbackArg); return; @@ -135,6 +140,11 @@ extern "C" void IOS_CloseAsync_HLE(CpuContext* ctx) { const uint32_t fd = ctx->gpr[3]; const uint32_t callback = ctx->gpr[4]; const uint32_t callbackArg = ctx->gpr[5]; + if (Bluetooth_HLE_IsFd(fd)) { + const int32_t result = Bluetooth_HLE_Close(fd); + CompleteAsync(ctx, callback, result, callbackArg); + return; + } if (Network_HLE_IsFd(fd)) { const int32_t result = Network_HLE_Close(fd); CompleteAsync(ctx, callback, result, callbackArg); @@ -179,6 +189,15 @@ extern "C" void IOS_IoctlvAsync_HLE(CpuContext* ctx) const uint32_t vectorPtr = ctx->gpr[7]; const uint32_t callback = ctx->gpr[8]; const uint32_t callbackArg = ctx->gpr[9]; + if (Bluetooth_HLE_IsFd(fd)) { + int32_t result = 0; + if (Bluetooth_HLE_IoctlvAsync(fd, cmd, numIn, numOut, vectorPtr, callback, callbackArg, result)) { + CompleteAsync(ctx, callback, result, callbackArg); + } else { + SetIosReturn(ctx, 0); + } + return; + } if (TryDeferredNetworkAsync( ctx, fd, callback, callbackArg, [&] { diff --git a/runtime/src/hle/net/network_config.cpp b/runtime/src/hle/net/network_config.cpp index 78802c0..e033eb7 100644 --- a/runtime/src/hle/net/network_config.cpp +++ b/runtime/src/hle/net/network_config.cpp @@ -2,17 +2,15 @@ #include "abi_bridge.h" #include "ppc_runtime.h" +#include "guest_function_imports.h" namespace NetworkHle { -extern "C" void func_801D8D30(CpuContext* ctx); -extern "C" void func_801D9E94(CpuContext* ctx); - static uint32_t GetNHttpSystemInfo(CpuContext* ctx, uint32_t& savedR3, uint32_t& savedR4, uint32_t& savedR5) { savedR3 = ctx->gpr[3]; savedR4 = ctx->gpr[4]; savedR5 = ctx->gpr[5]; - func_801D9E94(ctx); + MKW_GUEST_FUNC(801D9E94)(ctx); const uint32_t systemInfo = ctx->gpr[3]; ctx->gpr[3] = savedR3; ctx->gpr[4] = savedR4; @@ -47,7 +45,7 @@ extern "C" void NHTTPStartup_Reentrant_HLE_801d8d30(CpuContext* ctx) { ctx->gpr[3] = savedR3; ctx->gpr[4] = savedR4; ctx->gpr[5] = savedR5; - func_801D8D30(ctx); + MKW_GUEST_FUNC(801D8D30)(ctx); const int32_t result = static_cast(ctx->gpr[3]); if (result < 0) { diff --git a/runtime/src/hle/net/network_deferred.cpp b/runtime/src/hle/net/network_deferred.cpp index 8ed5e0e..c1627fb 100644 --- a/runtime/src/hle/net/network_deferred.cpp +++ b/runtime/src/hle/net/network_deferred.cpp @@ -1,4 +1,5 @@ #include "network_internal.h" +#include "guest_abi/guest_region.h" #include "fiber_manager.h" #include "hle/net/network.h" @@ -627,7 +628,7 @@ static bool InitializeDeferredSyncRoute(DeferredNetworkRoute& route, uint32_t wa // early scheduler setup. Capture its identity before yielding so a late // resolver result cannot wake a stale/reused stack queue after cancellation. constexpr uint32_t kOSRunningContextAddr = 0x800000E4u; - constexpr uint32_t kDefaultThreadContextAddr = 0x80347498u; + const uint32_t kDefaultThreadContextAddr = MKW_GADDR(80347498); uint32_t expectedThread = Memory::Read32(kOSRunningContextAddr); if (expectedThread == 0) { expectedThread = kDefaultThreadContextAddr; diff --git a/runtime/src/hle/os/os_alarm.cpp b/runtime/src/hle/os/os_alarm.cpp index a0bf0c0..ecf8300 100644 --- a/runtime/src/hle/os/os_alarm.cpp +++ b/runtime/src/hle/os/os_alarm.cpp @@ -10,12 +10,11 @@ #include "hle_stubs.h" #include "ppc_runtime.h" #include "runtime_log.h" +#include "hle/bluetooth_hle.h" #include "hle/net/network.h" #include "guest_small_data.h" #include "os_internal.h" - -extern "C" void func_801AADE0(CpuContext* ctx); -extern "C" void func_801A0620(CpuContext* ctx); +#include "guest_function_imports.h" // ============================================================================ // Alarm queue helpers @@ -99,7 +98,7 @@ void SanitizeAlarmQueue(CpuContext* cpu) return; } - const uint32_t queueBase = cpu->gpr[13] - kAlarmQueueOffsetFromR13; + const uint32_t queueBase = kAlarmQueueAddr; try { const uint32_t head = ::Memory::Read32(queueBase); const uint32_t tail = ::Memory::Read32(queueBase + 4u); @@ -168,7 +167,7 @@ bool ProcessAlarmQueue(CpuContext* cpu, int maxToProcess) { AlarmProcessScope alarmProcessScope; SanitizeAlarmQueue(cpu); - const uint32_t queueBase = cpu->gpr[13] - kAlarmQueueOffsetFromR13; + const uint32_t queueBase = kAlarmQueueAddr; try { for (int i = 0; i < maxToProcess; ++i) { @@ -208,7 +207,7 @@ bool ProcessAlarmQueue(CpuContext* cpu, int maxToProcess) cpu->gpr[5] = 0; cpu->gpr[6] = 0; cpu->gpr[7] = handler; - func_801A0620(cpu); + MKW_GUEST_FUNC(801A0620)(cpu); } if (handler != 0) { @@ -237,6 +236,10 @@ bool ProcessAlarmQueue(CpuContext* cpu, int maxToProcess) handledAny = true; completionNeedsReschedule = true; } + if (Bluetooth_HLE_ProcessCompletions(cpu)) { + handledAny = true; + completionNeedsReschedule = true; + } if (NandProcessPendingCallbacks(cpu, maxToProcess)) { handledAny = true; @@ -304,7 +307,7 @@ extern "C" void OSSetAlarm_HLE_801a0870(CpuContext* ctx) return; } - const uint32_t queueBase = cpu->gpr[13] - kAlarmQueueOffsetFromR13; + const uint32_t queueBase = kAlarmQueueAddr; try { const uint32_t head = ::Memory::Read32(queueBase); if (head == 0) { @@ -422,7 +425,7 @@ extern "C" void OS__SetPeriodicAlarm_801a08e0(CpuContext* ctx) cpu->gpr[3] = startHi; cpu->gpr[4] = startLo; - func_801AADE0(cpu); + MKW_GUEST_FUNC(801AADE0)(cpu); Memory::Write32(alarm + 0x20u, cpu->gpr[3]); Memory::Write32(alarm + 0x24u, cpu->gpr[4]); @@ -430,7 +433,7 @@ extern "C" void OS__SetPeriodicAlarm_801a08e0(CpuContext* ctx) cpu->gpr[5] = 0; cpu->gpr[6] = 0; cpu->gpr[7] = handler; - func_801A0620(cpu); + MKW_GUEST_FUNC(801A0620)(cpu); cpu->gpr[3] = static_cast(OS__RestoreInterrupts_801a65d4(level)); } @@ -459,7 +462,7 @@ extern "C" uint32_t RFLiIsWorking_HLE_800bd860() DecrementSchedulerDisableCount(); // Now return the actual "working" status - constexpr uint32_t kRflManagerPtrAddr = 0x80386298u; + const uint32_t kRflManagerPtrAddr = MKW_GADDR(80386298); constexpr uint32_t kWorkingFlagOffset = 0x1b34u; try { diff --git a/runtime/src/hle/os/os_init.cpp b/runtime/src/hle/os/os_init.cpp index 08472a8..620a7ed 100644 --- a/runtime/src/hle/os/os_init.cpp +++ b/runtime/src/hle/os/os_init.cpp @@ -17,19 +17,17 @@ #include "recomp_mod_loader.h" #include "runtime_log.h" #include "system_bridge.h" - -extern "C" void func_801A961C(CpuContext* ctx); -extern "C" void func_8055531C(CpuContext* ctx); +#include "guest_function_imports.h" extern "C" void OSInitAlarm_RecompModLateInit_801a961c(CpuContext* ctx) { - func_801A961C(ctx); + MKW_GUEST_FUNC(801A961C)(ctx); } REGISTER_NATIVE_FUNCTION_AS(0x801A961C, OSInitAlarm_RecompModLateInit_801a961c, "OSInitAlarm_RecompModLateInit_801a961c"); extern "C" void StaticRProlog_RecompModInit_8055531c(CpuContext* ctx) { RecompMod::RunMemoryInitializers(); - func_8055531C(ctx); + MKW_GUEST_FUNC(8055531C)(ctx); RecompMod::RunPostRelInitializers(); } @@ -80,33 +78,16 @@ extern "C" void OSFatal_HLE_801a4ec4(CpuContext* ctx) { REGISTER_NATIVE_FUNCTION_AS(0x801A4EC4, OSFatal_HLE_801a4ec4, "OSFatal_HLE_801a4ec4"); -extern "C" void GKI_delay_HLE_801301b4(CpuContext* ctx) +extern "C" void GKI_delay_HLE_801301b4() { - const uint32_t delayMs = ctx ? static_cast(ctx->gpr[3]) : 0; - const uint32_t sleepMs = delayMs == 0 ? 1u : std::min(delayMs, 10u); - std::this_thread::sleep_for(std::chrono::milliseconds(sleepMs)); + // The guest's GKI_delay is empty: BTA_Init spins on it while the Bluetooth + // module answers through IPC interrupts and the 2 ms BTU alarm. Service both + // here and let the wall clock advance. + OS_HLE_ProcessAlarms(32); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); } -extern "C" uint32_t BTM_IsDeviceUp_HLE_8013a300(CpuContext* ctx) -{ - // Force Bluetooth stack to "up" to avoid endless polling loops while we lack - // real hardware bring-up. - constexpr uint32_t kBtmCbBase = 0x80336278u; - constexpr uint32_t kDevStateOffset = 0x64Eu; - try { - ::Memory::Write8(kBtmCbBase + kDevStateOffset, 5u); - } catch (const ::Memory::AccessViolation&) { - // Ignore; best-effort write - } - - if (ctx) { - ctx->gpr[3] = 1; - } - return 1; -} - -PPC_NATIVE_OVERRIDE_VOID(801301B4, GKI_delay_HLE_801301b4, (CpuContext* ctx), (ctx)); -PPC_NATIVE_OVERRIDE(8013A300, BTM_IsDeviceUp_HLE_8013a300, uint32_t, (CpuContext* ctx), (ctx)); +PPC_NATIVE_OVERRIDE_VOID(801301B4, GKI_delay_HLE_801301b4, (), ()); // Serial Interface (SI) - GameCube controller ports; stubbed since we don't emulate the MMIO. @@ -124,13 +105,14 @@ extern "C" void HLE_SISetSamplingRate_801b3acc(uint32_t msec) // Video Interface (VI) - TV output. -// VIGetTvFormat (0x801bacd8): CRITICAL, must return 1 (VI_PAL) not 0, or PAL builds -// misbehave/panic. +// VIGetTvFormat (0x801bacd8): CRITICAL, must report the game's own TV format or it +// misbehaves/panics. extern "C" uint32_t HLE_VIGetTvFormat_801bacd8() { // VI_NTSC = 0, VI_PAL = 1, VI_MPAL = 2 - RT_LOG(RT_TAG_OS) << "HLE_VIGetTvFormat_801bacd8 called: returning VI_PAL (1)" << std::endl; - return 1; + RT_LOG(RT_TAG_OS) << "HLE_VIGetTvFormat_801bacd8 called: returning " << ::GuestRegion::CurrentFacts().viTvFormat + << std::endl; + return ::GuestRegion::CurrentFacts().viTvFormat; } REGISTER_NATIVE_FUNCTION(0x801B2DE0, SIInit_801b2de0); @@ -193,22 +175,18 @@ extern "C" uint32_t __OSInitSTM_HLE_801ab848(CpuContext* ctx) RT_LOG(RT_TAG_OS) << "__OSInitSTM_HLE_801ab848 called: initializing STM state" << std::endl; - // R13 (SDA2) holds the base for small data variables - const uint32_t r13 = cpu->gpr[13]; - if (r13 == 0) { - RT_LOG(RT_TAG_OS) << "__OSInitSTM: Warning - R13 is 0, cannot write state." << std::endl; - return 0; - } + // STM_Initialized, /dev/stm/immediate and /dev/stm/eventhook. + const uint32_t kStmInitializedAddr = MKW_GADDR(80386934); + const uint32_t kStmImmediateHandleAddr = MKW_GADDR(80386938); + const uint32_t kStmEventHookHandleAddr = MKW_GADDR(8038693C); - // Offsets from disassembly: r13-0x62cc=STM_Initialized, r13-0x62c8=/dev/stm/immediate, - // r13-0x62c4=/dev/stm/eventhook. try { // Mark STM as initialized - ::Memory::Write32(r13 - 0x62ccu, 1); + ::Memory::Write32(kStmInitializedAddr, 1); // Fake non-zero handles so callers' zero-checks pass. - ::Memory::Write32(r13 - 0x62c8u, 0x00535401); // "ST\x01" - ::Memory::Write32(r13 - 0x62c4u, 0x00535402); // "ST\x02" + ::Memory::Write32(kStmImmediateHandleAddr, 0x00535401); // "ST\x01" + ::Memory::Write32(kStmEventHookHandleAddr, 0x00535402); // "ST\x02" // Default Power/Reset callback pointers are left unset; safe since we never fire // the STM hardware interrupt that would invoke them. diff --git a/runtime/src/hle/os/os_internal.h b/runtime/src/hle/os/os_internal.h index 9b2b700..2e7eb88 100644 --- a/runtime/src/hle/os/os_internal.h +++ b/runtime/src/hle/os/os_internal.h @@ -24,7 +24,7 @@ extern std::atomic g_interrupts_enabled; // observable state, not just bookkeeping. extern std::atomic g_interrupt_mask; -constexpr uint32_t kInterruptHandlerTablePtrAddr = 0x803868f8u; +const uint32_t kInterruptHandlerTablePtrAddr = MKW_GADDR(803868f8); constexpr uint32_t kInterruptHandlerTableAddr = 0x80003040u; constexpr size_t kInterruptHandlerTableBytes = 0x80u; constexpr uint32_t kInterruptMaskLoAddr = 0x800000c4u; @@ -36,17 +36,17 @@ constexpr uint32_t kThreadListHeadAddr = 0x800000dcu; // First thread in thre constexpr uint32_t kThreadListTailAddr = 0x800000e0u; // Last added thread (tail of thread list) constexpr uint32_t kOSRunningContextAddr = 0x800000e4u; // Currently running thread context -constexpr uint32_t kDefaultThreadContextAddr = 0x80347498u; -constexpr uint32_t kIdleThreadContextAddr = 0x803478b0u; -constexpr uint32_t kThreadQueueArrayAddr = 0x803477b0u; +const uint32_t kDefaultThreadContextAddr = MKW_GADDR(80347498); +const uint32_t kIdleThreadContextAddr = MKW_GADDR(803478b0); +const uint32_t kThreadQueueArrayAddr = MKW_GADDR(803477b0); constexpr size_t kThreadQueueArrayBytes = 0x100u; -constexpr uint32_t kSwitchThreadCallbackPtrAddr = 0x80385ae0u; -constexpr uint32_t kSchedulerReschedCounterAddr = 0x8038691cu; -constexpr uint32_t kSchedulerPendingFlagAddr = 0x80386920u; +const uint32_t kSwitchThreadCallbackPtrAddr = MKW_GADDR(80385ae0); +const uint32_t kSchedulerReschedCounterAddr = MKW_GADDR(8038691c); +const uint32_t kSchedulerPendingFlagAddr = MKW_GADDR(80386920); // RVL OS uses this as the OSDisableScheduler/OSEnableScheduler nesting count. // SelectThread exits early while the count is non-zero. -constexpr uint32_t kSchedulerIdleFlagAddr = 0x80386918u; -constexpr uint32_t kAlarmQueueOffsetFromR13 = 0x6360u; +const uint32_t kSchedulerIdleFlagAddr = MKW_GADDR(80386918); +const uint32_t kAlarmQueueAddr = MKW_GADDR(803868A0); constexpr uint32_t kThreadStateOffset = 0x2C8u; constexpr uint32_t kThreadAttrOffset = 0x2CAu; diff --git a/runtime/src/hle/os/os_interrupt.cpp b/runtime/src/hle/os/os_interrupt.cpp index 29bc4c1..56f6871 100644 --- a/runtime/src/hle/os/os_interrupt.cpp +++ b/runtime/src/hle/os/os_interrupt.cpp @@ -391,14 +391,12 @@ extern "C" uint32_t OSSetPowerCallback_801ab75c(CpuContext* ctx) if (!cpu) return 0; const uint32_t newCallback = cpu->gpr[3]; - const uint32_t r13 = cpu->gpr[13]; - // Assembly defines the default callback address as (0x801b0000 - 0x43f4) - constexpr uint32_t kDefaultCallbackAddr = 0x801b0000u - 0x43f4u; // 0x801abc0c - - // Offsets from R13 (SDA2) - const uint32_t kCallbackPtrAddr = r13 - 0x62b8u; - const uint32_t kHandlerActiveAddr = r13 - 0x62c0u; + // The SDK's default power callback, the registered callback pointer and the + // "event handler registered" flag. + const uint32_t kDefaultCallbackAddr = MKW_GADDR(801ABC0C); + const uint32_t kCallbackPtrAddr = MKW_GADDR(80386948); + const uint32_t kHandlerActiveAddr = MKW_GADDR(80386940); RT_LOG(RT_TAG_OS) << "OSSetPowerCallback_801ab75c called: newCB=0x" << std::hex << newCallback << std::dec << std::endl; @@ -489,12 +487,13 @@ extern "C" int32_t IPCCltInit_80193478(CpuContext* ctx) RT_LOG(RT_TAG_OS) << "IPCCltInit_80193478 called: calling IPCInit for buffer setup" << std::endl; // Sets 0x803867EC/F0/E8 (IPC buffer lo/hi + init flag) from __OSGetIPCBufferLo/Hi. - InvokeIndirectCpu(0x80192F7Cu, ctx); + InvokeIndirectCpu(MKW_GADDR(80192F7C), ctx); // Advance the buffer lo pointer by 0x1000 (iosHeap size), matching real IPCCltInit. - uint32_t bufferLo = Memory::Read32(ctx->gpr[13] + -25620); // 0x803867EC at r13-0x6414 + const uint32_t kIpcBufferLoGlobal = MKW_GADDR(803867EC); + uint32_t bufferLo = Memory::Read32(kIpcBufferLoGlobal); uint32_t newBufLo = bufferLo + 0x1000; // Advance by 4KB for iosHeap - Memory::Write32(ctx->gpr[13] + -25620, newBufLo); + Memory::Write32(kIpcBufferLoGlobal, newBufLo); RT_LOG(RT_TAG_OS) << "IPCCltInit: IPC buffer lo advanced from 0x" << std::hex << bufferLo << " to 0x" << newBufLo << std::dec << std::endl; diff --git a/runtime/src/hle/os/os_reset.cpp b/runtime/src/hle/os/os_reset.cpp index e36af5e..b6dbc53 100644 --- a/runtime/src/hle/os/os_reset.cpp +++ b/runtime/src/hle/os/os_reset.cpp @@ -1,5 +1,6 @@ #include "memory.h" #include "hle/audio/ax_dsp.h" +#include "gx_worker.h" #include "hle_stubs.h" #include "ppc_runtime.h" #include "runtime_log.h" @@ -124,6 +125,7 @@ extern "C" uint32_t OSResetSystem() std::fflush(stderr); // The AX mix worker holds resolved host pointers into the guest regions; // it must be stopped before those mappings are torn down. + GxWorker::Stop(); AxDspHle::ShutdownMixWorker(); Memory::Reset(); SetRuntimeExitCode(0); @@ -145,6 +147,7 @@ extern "C" uint32_t Exit_801AE58C(int status) ShowRuntimeFatalPopup("the game exited with an error status", details); MarkFatalErrorReported(); } + GxWorker::Stop(); SetRuntimeExitCode(status); std::exit(status); return static_cast(status); diff --git a/runtime/src/hle/os/os_scheduler.cpp b/runtime/src/hle/os/os_scheduler.cpp index c6bbd00..ffb0e8c 100644 --- a/runtime/src/hle/os/os_scheduler.cpp +++ b/runtime/src/hle/os/os_scheduler.cpp @@ -10,6 +10,7 @@ #include "fiber_manager.h" #include "runtime_log.h" #include "os_internal.h" +#include "guest_function_imports.h" namespace { void LinkMutexToThread(uint32_t threadPtr, uint32_t mutexPtr) @@ -119,7 +120,6 @@ static void TryInvokeSwitchCallback(uint32_t oldCtx, uint32_t newCtx, CpuContext // Forward declare for SelectThread to use extern "C" void OS__SetCurrentContext_801a1e70(uint32_t contextAddr); -extern "C" void func_801A1ED8(CpuContext* ctx); // ============================================================================ // SelectThread HLE - Thread Scheduler (Fiber-Aware) @@ -200,7 +200,7 @@ extern "C" void SelectThread_801a9c08(CpuContext* ctx) const uint16_t modeFlags = ::Memory::Read16(runningContext + 0x1A2u); if ((modeFlags & 0x0002u) == 0) { cpu->gpr[3] = runningContext; - func_801A1ED8(cpu); + MKW_GUEST_FUNC(801A1ED8)(cpu); if (cpu->gpr[3] != 0) { cpu->gpr[3] = 0; return; diff --git a/runtime/src/hle/os/os_thread.cpp b/runtime/src/hle/os/os_thread.cpp index 5de684a..d2423e6 100644 --- a/runtime/src/hle/os/os_thread.cpp +++ b/runtime/src/hle/os/os_thread.cpp @@ -73,13 +73,7 @@ int32_t ComputeThreadEffectivePriority(uint32_t threadPtr) bool IsThpVideoDecoderEntry(uint32_t entryFunc) { - switch (entryFunc) { - case 0x805529A8u: - case 0x80552A74u: - return true; - default: - return false; - } + return entryFunc == MKW_GADDR(805529A8) || entryFunc == MKW_GADDR(80552A74); } void InsertThreadIntoQueueByPriority(uint32_t queuePtr, uint32_t threadPtr, int32_t priority) @@ -216,7 +210,7 @@ void UnlockAllThreadMutexes(CpuContext* cpu, uint32_t threadPtr) } CpuContextScope scope(cpu); cpu->gpr[3] = threadPtr; - InvokeIndirectCpu(0x801A8088u, cpu); // __OSUnlockAllMutex + InvokeIndirectCpu(MKW_GADDR(801A8088), cpu); // __OSUnlockAllMutex } // Shared tail of OSExitThread/OSCancelThread: clears context, delists if detached, marks @@ -311,7 +305,7 @@ extern "C" void OSCreateThread_HLE_801a9e84(CpuContext* ctx) cpu->gpr[3] = threadPtr; cpu->gpr[4] = entryFunc; cpu->gpr[5] = alignedStack - 8; - InvokeIndirectCpu(0x801A20BCu, cpu); // OSInitContext + InvokeIndirectCpu(MKW_GADDR(801A20BC), cpu); // OSInitContext } if (IsThpVideoDecoderEntry(entryFunc)) { @@ -325,7 +319,7 @@ extern "C" void OSCreateThread_HLE_801a9e84(CpuContext* ctx) } - ::Memory::Write32(threadPtr + 0x84u, 0x801AA0F0u); // LR = OSExitThread + ::Memory::Write32(threadPtr + 0x84u, MKW_GADDR(801AA0F0)); // LR = OSExitThread ::Memory::Write32(threadPtr + 0x0Cu, entryArg); // r3 = argument // Stack info @@ -341,8 +335,8 @@ extern "C" void OSCreateThread_HLE_801a9e84(CpuContext* ctx) // Match the original OSCreateThread slow-path initialization that runs // once scheduler globals are live. THP worker threads depend on these // queue/list blocks being fully zeroed. - constexpr uint32_t kSchedulerInitFlagAddr = 0x80347130u; - constexpr uint32_t kThreadAttrSourceAddr = 0x80385AA8u; + const uint32_t kSchedulerInitFlagAddr = MKW_GADDR(80347130); + const uint32_t kThreadAttrSourceAddr = MKW_GADDR(80385AA8); if (Memory::Contains(kSchedulerInitFlagAddr, 4) && ::Memory::Read32(kSchedulerInitFlagAddr) != 0) { uint32_t srr1 = ::Memory::Read32(threadPtr + 0x19Cu); diff --git a/runtime/src/hle/sc.cpp b/runtime/src/hle/sc.cpp index bb33e01..72314e5 100644 --- a/runtime/src/hle/sc.cpp +++ b/runtime/src/hle/sc.cpp @@ -74,7 +74,7 @@ PPC_NATIVE_OVERRIDE(801B1CAC, SCGetEuRgb60Mode_HLE, uint32_t, (), ()); extern "C" uint32_t SCGetProductArea_HLE() { - return LookupProductRegion(0x8029CEB0u, 5, 13, + return LookupProductRegion(MKW_GADDR(8029CEB0), 5, 13, RuntimeConsoleIdentity::Current().area); } @@ -82,8 +82,8 @@ PPC_NATIVE_OVERRIDE(801B23A0, SCGetProductArea_HLE, uint32_t, (), ()); extern "C" uint32_t SCGetProductCode_HLE() { - // Original PAL SC storage for the six-byte CODE value. - constexpr uint32_t kProductCodeAddress = 0x803869E0u; + // Original SC storage for the six-byte CODE value. + const uint32_t kProductCodeAddress = MKW_GADDR(803869E0); const std::string& productCode = RuntimeConsoleIdentity::Current().productCode; const size_t size = productCode.size() + 1; if (!Memory::Contains(kProductCodeAddress, size)) { @@ -108,7 +108,7 @@ PPC_NATIVE_OVERRIDE(801B2460, SCGetProductSN_HLE, uint32_t, (uint32_t serialAddr extern "C" uint32_t SCGetProductGameRegion_HLE() { - return LookupProductRegion(0x8029CEF8u, 4, 4, + return LookupProductRegion(MKW_GADDR(8029CEF8), 4, 4, RuntimeConsoleIdentity::Current().gameRegion); } diff --git a/runtime/src/hle/storage/dvd.cpp b/runtime/src/hle/storage/dvd.cpp index 1acf239..b76e5e1 100644 --- a/runtime/src/hle/storage/dvd.cpp +++ b/runtime/src/hle/storage/dvd.cpp @@ -1,4 +1,4 @@ -#include "hle_stubs.h" +#include "hle_stubs.h" #include "isa/big_endian.h" #include "hle/dvd_contract.h" #include "hle/runtime_parse_helpers.h" @@ -44,7 +44,7 @@ static fs::path g_dvdRoot; static std::once_flag g_dvdRootOnce; static uint32_t CurrentDiscGameCode() { - return RuntimeHle::CurrentGameCode(0x524D4350u); // RMCP + return RuntimeHle::CurrentGameCode(::GuestRegion::CurrentFacts().gameCode); } // ============================================================================ @@ -162,6 +162,21 @@ static const fs::path& GetDvdRoot() { if (!IsDvdDataRoot(path)) { FailDvdRoot("Configured DVD root is not an extracted DATA directory", path); } + std::error_code ec; + const auto bootBin = path / "sys" / "boot.bin"; + if (fs::is_regular_file(bootBin, ec)) { + std::ifstream file(bootBin, std::ios::binary); + char id[7] = {}; + if (!file.read(id, 6)) { + FailDvdRoot("Configured DVD root has an unreadable or truncated sys/boot.bin", bootBin); + } + if (std::memcmp(id, "RMC", 3) == 0 && id[3] != ::GuestRegion::CurrentFacts().letter) { + FailDvd("dvd_region_mismatch", "DVD region mismatch", + std::string("Configured DVD root has disc ID '") + id + + "', but this build was compiled for region " + ::GuestRegion::CurrentFacts().gameId + + ".\nThe extracted game assets must match the region of the compiled executable."); + } + } g_dvdRoot = path; }); @@ -749,7 +764,7 @@ extern "C" const char* DVDResolveHostPathForTest(const char* dvdPath) static void InitDvdWaitingQueues() { - constexpr uint32_t kQueueBase = 0x80343230; + const uint32_t kQueueBase = MKW_GADDR(80343230); for (uint32_t i = 0; i < 4; ++i) { const uint32_t queue = kQueueBase + (i * 8); Memory::Write32(queue + 0, queue); @@ -763,12 +778,12 @@ static void CompleteDvdCancelState() // These are the SDK DVD globals used by DVDCancelAll/__DVDPrepareReset. // The actual drive work is HLE'd, so complete pending cancel/reset waits. - Memory::Write32(0x80386664, 0); // Canceling - Memory::Write32(0x80386668, 0); // ResumeFromHere - Memory::Write32(0x80386670, 0); // PausingFlag - Memory::Write32(0x8038667C, 1); // CancelAllSync complete - Memory::Write32(0x803866A8, 1); // PrepareReset complete - Memory::Write32(0x803866F0, 0); // executing command block + Memory::Write32(MKW_GADDR(80386664), 0); // Canceling + Memory::Write32(MKW_GADDR(80386668), 0); // ResumeFromHere + Memory::Write32(MKW_GADDR(80386670), 0); // PausingFlag + Memory::Write32(MKW_GADDR(8038667C), 1); // CancelAllSync complete + Memory::Write32(MKW_GADDR(803866A8), 1); // PrepareReset complete + Memory::Write32(MKW_GADDR(803866F0), 0); // executing command block } // 0x8015EA1C -> DVDInit @@ -785,14 +800,14 @@ extern "C" void DVDInit_8015EA1C() // 1. Initialize Global Flags (Emulate OS state) // These addresses are standard OS globals for DVD context - Memory::Write8(0x80386724, 1); // Contexts initialized - Memory::Write8(0x80386725, 1); // LowInit called - Memory::Write32(0x80386720, 0); // Current context index - Memory::Write8(0x803866a0, 1); // DVDInit called flag + Memory::Write8(MKW_GADDR(80386724), 1); // Contexts initialized + Memory::Write8(MKW_GADDR(80386725), 1); // LowInit called + Memory::Write32(MKW_GADDR(80386720), 0); // Current context index + Memory::Write8(MKW_GADDR(803866a0), 1); // DVDInit called flag CompleteDvdCancelState(); // 2. Initialize DVD Context structures (prevent crashes in callbacks) - constexpr uint32_t kContextBase = 0x803434e0; + const uint32_t kContextBase = MKW_GADDR(803434e0); constexpr uint32_t kMagicValue = 0xFEEBDAED; for (int i = 0; i < 4; i++) { uint32_t ctx = kContextBase + i * 0x20; @@ -840,7 +855,7 @@ extern "C" void DVDInit_8015EA1C() BuildAndPublishRuntimeFst(); // Initialize the translated DVD filesystem so it can use the published FST. - constexpr uint32_t kDvdFsInitAddress = 0x8015DF1C; + const uint32_t kDvdFsInitAddress = MKW_GADDR(8015DF1C); if (TranslatedFunctionRegistry::FindByAddressPtr(kDvdFsInitAddress)) { InvokeIndirectCpu(kDvdFsInitAddress, &GetPersistentCpuContext()); } @@ -1016,31 +1031,46 @@ extern "C" int32_t DVDLowInit_80164848() { } PPC_NATIVE_OVERRIDE(80164848, DVDLowInit_80164848, int32_t, (), ()); -extern "C" int32_t DVDLowInquiry_80165A30(uint32_t cmdBlockPtr, uint32_t callback) +// DVDLowInquiry(DVDDriveInfo* info, DVDLowCallback cb); reports a retail drive. +extern "C" int32_t DVDLowInquiry_80165A30(uint32_t driveInfoPtr, uint32_t callback) { - // HLE: acknowledge the drive is present. Must mark the command block complete - // (State = 0) or callers polling this address hang waiting for "Busy" to clear. - if (cmdBlockPtr) { - Memory::Write32(cmdBlockPtr + DVD_CB_OFFSET_STATE, DVD_STATE_END); + if (driveInfoPtr && Memory::Contains(driveInfoPtr, 0x20)) { + Memory::Write32(driveInfoPtr + 0x0, 0x00000002); // revision level, device code + Memory::Write32(driveInfoPtr + 0x4, 0x20060526); // release date + Memory::Write32(driveInfoPtr + 0x8, 0x41000000); } + InvokeDvdLowCallback(callback, DvdReadContract::kInterruptTransferComplete); CompleteDvdCancelState(); - - return 1; // Return 1 to indicate the command was successfully issued. + return 1; } PPC_NATIVE_OVERRIDE(80165A30, DVDLowInquiry_80165A30, int32_t, (uint32_t b, uint32_t c), (b, c)); // 0x80164AAC -> DVDLowReadDiskID extern "C" int32_t DVDLowReadDiskID_80164AAC(uint32_t diskIdPtr, uint32_t callback) { - if (diskIdPtr) { + if (diskIdPtr && Memory::Contains(diskIdPtr, 0x20)) { + for (uint32_t i = 0x07; i < 0x20; ++i) { + Memory::Write8(diskIdPtr + i, 0); + } Memory::Write32(diskIdPtr + 0x00, CurrentDiscGameCode()); Memory::Write16(diskIdPtr + 0x04, 0x3031); Memory::Write8 (diskIdPtr + 0x06, 0x01); + Memory::Write32(diskIdPtr + 0x18, 0x5D1C9EA3); // Wii disc magic } + InvokeDvdLowCallback(callback, DvdReadContract::kInterruptTransferComplete); CompleteDvdCancelState(); return 1; // Success } PPC_NATIVE_OVERRIDE(80164AAC, DVDLowReadDiskID_80164AAC, int32_t, (uint32_t p, uint32_t c), (p, c)); +// Host files need no head positioning. +extern "C" int32_t DVDLowSeek_801664E0(uint32_t offset, uint32_t callback) { + (void)offset; + InvokeDvdLowCallback(callback, DvdReadContract::kInterruptTransferComplete); + CompleteDvdCancelState(); + return 1; +} +PPC_NATIVE_OVERRIDE(801664E0, DVDLowSeek_801664E0, int32_t, (uint32_t o, uint32_t c), (o, c)); + // 0x80166330 -> DVDLowRead (And 0x80165708 UnencryptedRead) // The game calls this to read the Disk Header (offset 0) or raw data. extern "C" int32_t DVDLowRead_80166330(uint32_t buffer, uint32_t length, uint32_t offset, uint32_t callback) diff --git a/runtime/src/hle/storage/nand_api.cpp b/runtime/src/hle/storage/nand_api.cpp index f09d88e..39963ce 100644 --- a/runtime/src/hle/storage/nand_api.cpp +++ b/runtime/src/hle/storage/nand_api.cpp @@ -83,10 +83,10 @@ extern "C" int32_t NANDInit_HLE(void) { ISFS_OpenLib_Initialize(&GetPersistentCpuContext()); // NANDHomeDir is at 0x80346D20 (from ESP_GetDataDir output) - WriteGuestNandPath(0x80346D20, CurrentNandDataDir()); + WriteGuestNandPath(MKW_GADDR(80346D20), CurrentNandDataDir()); // Mark NAND as initialized (0x80386848 = 2) - Memory::Write32(0x80386848, 2); + Memory::Write32(MKW_GADDR(80386848), 2); return NAND_RESULT_OK; } diff --git a/runtime/src/hle/storage/nand_fs.cpp b/runtime/src/hle/storage/nand_fs.cpp index 4dba4f0..28c0cbd 100644 --- a/runtime/src/hle/storage/nand_fs.cpp +++ b/runtime/src/hle/storage/nand_fs.cpp @@ -78,7 +78,7 @@ void CloseFd(int32_t fd) { // ============================================================================ uint32_t CurrentMkwTitleIdLo() { - return RuntimeHle::CurrentGameCode(kNandTitleIdLo); + return RuntimeHle::CurrentGameCode(NandTitleIdLo()); } std::string CurrentNandDataDir() { diff --git a/runtime/src/hle/storage/nand_internal.h b/runtime/src/hle/storage/nand_internal.h index 346be4f..ef9caac 100644 --- a/runtime/src/hle/storage/nand_internal.h +++ b/runtime/src/hle/storage/nand_internal.h @@ -10,6 +10,7 @@ #include "memory.h" #include "nand_path.h" #include "nand_save_probe.h" +#include "hle/bluetooth_hle.h" #include "hle/net/network.h" #include "recomp_mod_loader.h" #include "runtime_config.h" @@ -44,7 +45,7 @@ // Mario Kart Wii Title ID namespace { constexpr uint32_t kNandTitleIdHi = 0x00010004; -constexpr uint32_t kNandTitleIdLo = 0x524D4350; // "RMCP" fallback +inline uint32_t NandTitleIdLo() { return ::GuestRegion::CurrentFacts().gameCode; } } // anonymous namespace // ============================================================================ diff --git a/runtime/src/hle/storage/nand_isfs.cpp b/runtime/src/hle/storage/nand_isfs.cpp index f084226..d91dd89 100644 --- a/runtime/src/hle/storage/nand_isfs.cpp +++ b/runtime/src/hle/storage/nand_isfs.cpp @@ -187,7 +187,7 @@ static int32_t HandleDolphinIoctlv(uint32_t cmd, uint32_t numIn, uint32_t numOut return ISFS_EINVAL; } char productCode[8] = {}; - uint32_t discId = Memory::Contains(0x80000000u, 4u) ? Memory::Read32(0x80000000u) : kNandTitleIdLo; + uint32_t discId = Memory::Contains(0x80000000u, 4u) ? Memory::Read32(0x80000000u) : NandTitleIdLo(); productCode[0] = static_cast((discId >> 24) & 0xffu); productCode[1] = static_cast((discId >> 16) & 0xffu); productCode[2] = static_cast((discId >> 8) & 0xffu); @@ -382,6 +382,9 @@ extern "C" int32_t NAND_IOS_Open_HLE(uint32_t pathPtr, uint32_t mode) { if (const int32_t netFd = Network_HLE_OpenDevice(path, mode)) { return netFd; } + if (const int32_t btFd = Bluetooth_HLE_OpenDevice(path)) { + return btFd; + } if (std::strcmp(path, "/dev/dolphin") == 0) { return DOLPHIN_DEV_FD; } @@ -452,6 +455,9 @@ extern "C" int32_t NAND_IOS_Close_HLE(uint32_t fd) { if (Network_HLE_IsFd(fd)) { return Network_HLE_Close(fd); } + if (Bluetooth_HLE_IsFd(fd)) { + return Bluetooth_HLE_Close(fd); + } auto* handle = GetHandle(fd); if (!handle) { @@ -566,6 +572,10 @@ extern "C" int32_t NAND_IOS_Ioctl_HLE( LogNandWarning("IOS_Ioctl", "/dev/sha does not support scalar ioctl cmd=%u", cmd); return ISFS_EINVAL; } + if (Bluetooth_HLE_IsFd(fd)) { + LogNandWarning("IOS_Ioctl", "/dev/usb/oh1 does not support scalar ioctl cmd=%u", cmd); + return -4; + } if (fd == DOLPHIN_DEV_FD) { LogNandWarning("IOS_Ioctl", "/dev/dolphin does not support scalar ioctl cmd=%u", cmd); return ISFS_EINVAL; @@ -831,15 +841,16 @@ static bool g_isfsInitialized = false; // load-bearing and must not be "tidied". Names come from the RVL IPC/ISFS // sources; only the naming changed here, never a value. namespace { -constexpr uint32_t kIsfsFdSda1Offset = 29408u; // __ISFS_fd -constexpr uint32_t kIsfsPathSda1Offset = 29400u; // __ISFS_path ("/dev/fs") -constexpr uint32_t kIpcBufferLoSda1Offset = 25620u; // IPC buffer window, low -constexpr uint32_t kIpcBufferHiSda1Offset = 25616u; // IPC buffer window, high -constexpr uint32_t kIpcArenaLoSda1Offset = 25732u; // __IPCArenaLo -constexpr uint32_t kIpcArenaHiSda1Offset = 25728u; // __IPCArenaHi -constexpr uint32_t kIsfsHeapHandleSda1Offset = 25724u; // ISFS heap handle -constexpr uint32_t kIsfsHeapBaseSda1Offset = 25740u; // ISFS heap base address -constexpr uint32_t kIsfsHeapInitializedSda1Offset = 25744u; // ISFS heap created flag +// The ISFS client's small-data globals. +const uint32_t kIsfsFdGlobal = MKW_GADDR(80385920); // __ISFS_fd +const uint32_t kIsfsPathGlobal = MKW_GADDR(80385928); // __ISFS_path ("/dev/fs") +const uint32_t kIpcBufferLoGlobal = MKW_GADDR(803867EC); // IPC buffer window, low +const uint32_t kIpcBufferHiGlobal = MKW_GADDR(803867F0); // IPC buffer window, high +const uint32_t kIpcArenaLoGlobal = MKW_GADDR(8038677C); // __IPCArenaLo +const uint32_t kIpcArenaHiGlobal = MKW_GADDR(80386780); // __IPCArenaHi +const uint32_t kIsfsHeapHandleGlobal = MKW_GADDR(80386784); // ISFS heap handle +const uint32_t kIsfsHeapBaseGlobal = MKW_GADDR(80386774); // ISFS heap base address +const uint32_t kIsfsHeapInitializedGlobal = MKW_GADDR(80386770); // ISFS heap created flag } // namespace static void WriteGuestString(uint32_t address, const char* value) { @@ -869,51 +880,36 @@ int32_t ISFS_OpenLib_Initialize(CpuContext* ctx) { return ISFS_OK; } - const uint32_t r13 = ctx->gpr[13]; - if (r13 == 0) { - return ISFS_OK; - } + WriteGuestString(kIsfsPathGlobal, "/dev/fs"); - const uint32_t isfsFdGlobal = r13 - kIsfsFdSda1Offset; - const uint32_t isfsPathGlobal = r13 - kIsfsPathSda1Offset; - const uint32_t ipcBufferLoGlobal = r13 - kIpcBufferLoSda1Offset; - const uint32_t ipcBufferHiGlobal = r13 - kIpcBufferHiSda1Offset; - const uint32_t ipcArenaLoGlobal = r13 - kIpcArenaLoSda1Offset; - const uint32_t ipcArenaHiGlobal = r13 - kIpcArenaHiSda1Offset; - const uint32_t isfsHeapGlobal = r13 - kIsfsHeapHandleSda1Offset; - const uint32_t isfsHeapBaseGlobal = r13 - kIsfsHeapBaseSda1Offset; - const uint32_t isfsHeapInitializedGlobal = r13 - kIsfsHeapInitializedSda1Offset; - - WriteGuestString(isfsPathGlobal, "/dev/fs"); - - if (Memory::Contains(isfsFdGlobal, 4)) { - Memory::Write32(isfsFdGlobal, static_cast(ISFS_DEV_FD)); + if (Memory::Contains(kIsfsFdGlobal, 4)) { + Memory::Write32(kIsfsFdGlobal, static_cast(ISFS_DEV_FD)); } // The heap bring-up below reads and writes all seven IPC globals, so it only // runs when every one of them is inside guest memory. - for (const uint32_t global : {ipcBufferLoGlobal, ipcBufferHiGlobal, ipcArenaLoGlobal, - ipcArenaHiGlobal, isfsHeapGlobal, isfsHeapBaseGlobal, - isfsHeapInitializedGlobal}) { + for (const uint32_t global : {kIpcBufferLoGlobal, kIpcBufferHiGlobal, kIpcArenaLoGlobal, + kIpcArenaHiGlobal, kIsfsHeapHandleGlobal, kIsfsHeapBaseGlobal, + kIsfsHeapInitializedGlobal}) { if (!Memory::Contains(global, 4)) { return ISFS_OK; } } - uint32_t ipcLo = Memory::Read32(ipcBufferLoGlobal); - uint32_t ipcHi = Memory::Read32(ipcBufferHiGlobal); + uint32_t ipcLo = Memory::Read32(kIpcBufferLoGlobal); + uint32_t ipcHi = Memory::Read32(kIpcBufferHiGlobal); if (ipcLo == 0 || ipcHi == 0 || ipcLo >= ipcHi) { return ISFS_OK; } - if (Memory::Read32(isfsHeapInitializedGlobal) == 0) { - Memory::Write32(ipcArenaLoGlobal, ipcLo); - Memory::Write32(ipcArenaHiGlobal, ipcHi); + if (Memory::Read32(kIsfsHeapInitializedGlobal) == 0) { + Memory::Write32(kIpcArenaLoGlobal, ipcLo); + Memory::Write32(kIpcArenaHiGlobal, ipcHi); const uint32_t heapBase = (ipcLo + 31u) & ~31u; const uint32_t heapSize = 5440u; if (heapBase + heapSize <= ipcHi) { - Memory::Write32(isfsHeapBaseGlobal, heapBase); + Memory::Write32(kIsfsHeapBaseGlobal, heapBase); const uint32_t savedR3 = ctx->gpr[3]; const uint32_t savedR4 = ctx->gpr[4]; @@ -922,21 +918,21 @@ int32_t ISFS_OpenLib_Initialize(CpuContext* ctx) { ctx->gpr[3] = heapBase; ctx->gpr[4] = heapSize; - ctx->lr = 0x80169BCCu; - InvokeDirectCpu<0x801949B8u>(ctx); + ctx->lr = MKW_GADDR(80169BCC); + InvokeIndirectCpu(MKW_GADDR(801949B8), ctx); const uint32_t heapHandle = ctx->gpr[3]; ctx->gpr[3] = heapBase + heapSize; - ctx->lr = 0x80169BCCu; - InvokeDirectCpu<0x80193040u>(ctx); + ctx->lr = MKW_GADDR(80169BCC); + InvokeIndirectCpu(MKW_GADDR(80193040), ctx); ctx->gpr[3] = savedR3; ctx->gpr[4] = savedR4; ctx->gpr[5] = savedR5; ctx->lr = savedLr; - Memory::Write32(isfsHeapGlobal, heapHandle); - Memory::Write32(isfsHeapInitializedGlobal, 1u); + Memory::Write32(kIsfsHeapHandleGlobal, heapHandle); + Memory::Write32(kIsfsHeapInitializedGlobal, 1u); } } @@ -968,7 +964,7 @@ static int32_t HandleIsfsReadDir(uint32_t numIn, uint32_t numOut, uint32_t vecto } const std::filesystem::path hostPath = TranslateNandPath(wiiPath.c_str()); if (!IsDirectory(hostPath)) { - return ISFS_ENOENT; + return PathExists(hostPath) ? ISFS_EINVAL : ISFS_ENOENT; } // NAND names are at most 12 characters; longer host names cannot exist on @@ -1032,6 +1028,9 @@ extern "C" int32_t NAND_IOS_Ioctlv_HLE( if (Network_HLE_IsFd(fd)) { return Network_HLE_Ioctlv(fd, cmd, numIn, numOut, vectorPtr); } + if (Bluetooth_HLE_IsFd(fd)) { + return Bluetooth_HLE_Ioctlv(fd, cmd, numIn, numOut, vectorPtr); + } if (GetShaHandle(static_cast(fd))) { return HandleShaIoctlv(static_cast(fd), cmd, numIn, numOut, vectorPtr); diff --git a/runtime/src/hle/storage/riivolution.cpp b/runtime/src/hle/storage/riivolution.cpp index 7fddf83..00659d0 100644 --- a/runtime/src/hle/storage/riivolution.cpp +++ b/runtime/src/hle/storage/riivolution.cpp @@ -6,6 +6,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "hle/storage/riivolution.h" +#include "guest_abi/guest_region.h" #include "hle/riivolution_contract.h" #include "hle/runtime_parse_helpers.h" @@ -46,11 +47,9 @@ std::optional RiivoReadFile(const fs::path& path) { return buffer.str(); } -// Six-character game ID ("RMCP01") from guest low memory, with the same RMCP -// fallback the rest of the storage HLE uses for boots that have not written -// the disc header yet. +// Six-character game ID from guest low memory, falling back to the translated game's. std::string RiivoGameId() { - const uint32_t code = RuntimeHle::CurrentGameCode(0x524D4350u); // "RMCP" + const uint32_t code = RuntimeHle::CurrentGameCode(::GuestRegion::CurrentFacts().gameCode); std::string id(6, '\0'); id[0] = static_cast((code >> 24) & 0xffu); id[1] = static_cast((code >> 16) & 0xffu); diff --git a/runtime/src/hle/task_thread.cpp b/runtime/src/hle/task_thread.cpp index dc4810d..5dc9b54 100644 --- a/runtime/src/hle/task_thread.cpp +++ b/runtime/src/hle/task_thread.cpp @@ -20,7 +20,7 @@ constexpr uint32_t kJobSize = 0x18u; bool ShouldRetryThpPrepareAfterClose(uint32_t callback, uint32_t arg, uint32_t result) { - if (callback != 0x80529D68u || result != 0) { + if (callback != MKW_GADDR(80529D68) || result != 0) { return false; } if (arg == 0 || !Memory::Contains(arg + 0xACu, 4)) { @@ -30,11 +30,11 @@ bool ShouldRetryThpPrepareAfterClose(uint32_t callback, uint32_t arg, uint32_t r if (state != 0) { return false; } - if (!Memory::Contains(0x809BECF0u, 4) || !Memory::Contains(0x809BEBA0u, 4)) { + if (!Memory::Contains(MKW_GADDR(809BECF0), 4) || !Memory::Contains(MKW_GADDR(809BEBA0), 4)) { return false; } - const uint32_t thpInit = Memory::Read32(0x809BECF0u); - const uint32_t thpOpen = Memory::Read32(0x809BEBA0u); + const uint32_t thpInit = Memory::Read32(MKW_GADDR(809BECF0)); + const uint32_t thpOpen = Memory::Read32(MKW_GADDR(809BEBA0)); return thpInit != 0 && thpOpen != 0; } @@ -52,23 +52,23 @@ uint32_t RunMovieManagerPrepareAsync(uint32_t manager, CpuContext* cpu) CpuContextScope scope(cpu); cpu->gpr[3] = manager + 0x28u; cpu->gpr[4] = 0; - InvokeIndirectCpu(0x80550CC0u, cpu); + InvokeIndirectCpu(MKW_GADDR(80550CC0), cpu); return cpu->gpr[3]; }; uint32_t openResult = callThpPlayerOpen(); - if (openResult == 0 && ShouldRetryThpPrepareAfterClose(0x80529D68u, manager, 0)) { + if (openResult == 0 && ShouldRetryThpPrepareAfterClose(MKW_GADDR(80529D68), manager, 0)) { { CpuContextScope scope(cpu); - InvokeIndirectCpu(0x80551658u, cpu); // THP__PlayerStop - InvokeIndirectCpu(0x80550F48u, cpu); // THP__PlayerClose + InvokeIndirectCpu(MKW_GADDR(80551658), cpu); // THP__PlayerStop + InvokeIndirectCpu(MKW_GADDR(80550F48), cpu); // THP__PlayerClose } - if (Memory::Contains(0x809BEBA0u, 8) && Memory::Read32(0x809BEBA0u) != 0) { - Memory::Write32(0x809BEBA0u, 0); - Memory::Write8(0x809BEBA4u, 0); - Memory::Write8(0x809BEBA5u, 0); - Memory::Write8(0x809BEBA6u, 0); - Memory::Write8(0x809BEBA7u, 0); + if (Memory::Contains(MKW_GADDR(809BEBA0), 8) && Memory::Read32(MKW_GADDR(809BEBA0)) != 0) { + Memory::Write32(MKW_GADDR(809BEBA0), 0); + Memory::Write8(MKW_GADDR(809BEBA4), 0); + Memory::Write8(MKW_GADDR(809BEBA5), 0); + Memory::Write8(MKW_GADDR(809BEBA6), 0); + Memory::Write8(MKW_GADDR(809BEBA7), 0); } openResult = callThpPlayerOpen(); } @@ -81,8 +81,8 @@ uint32_t RunMovieManagerPrepareAsync(uint32_t manager, CpuContext* cpu) { CpuContextScope scope(cpu); cpu->gpr[3] = manager + 0x10u; - InvokeIndirectCpu(0x80551D38u, cpu); // THP__PlayerGetVideoInfo - InvokeIndirectCpu(0x80550F9Cu, cpu); // THP__PlayerCalcNeedMemory + InvokeIndirectCpu(MKW_GADDR(80551D38), cpu); // THP__PlayerGetVideoInfo + InvokeIndirectCpu(MKW_GADDR(80550F9C), cpu); // THP__PlayerCalcNeedMemory } const uint32_t needMemory = cpu->gpr[3]; Memory::Write32(manager + 0x20u, needMemory); @@ -92,18 +92,18 @@ uint32_t RunMovieManagerPrepareAsync(uint32_t manager, CpuContext* cpu) { CpuContextScope scope(cpu); cpu->gpr[3] = setBufferArg; - InvokeIndirectCpu(0x80551054u, cpu); // THP__PlayerSetBuffer + InvokeIndirectCpu(MKW_GADDR(80551054), cpu); // THP__PlayerSetBuffer } const uint32_t mode = Memory::Read32(manager + 0xA8u); - const uint32_t audioSystem = Memory::Read32(0x8088FDB8u + (mode << 2)); + const uint32_t audioSystem = Memory::Read32(MKW_GADDR(8088FDB8) + (mode << 2)); uint32_t prepareResult = 0; { CpuContextScope scope(cpu); cpu->gpr[3] = Memory::Read32(manager + 0x24u); cpu->gpr[4] = audioSystem; cpu->gpr[5] = 0; - InvokeIndirectCpu(0x80551378u, cpu); // THP__PlayerPrepare + InvokeIndirectCpu(MKW_GADDR(80551378), cpu); // THP__PlayerPrepare prepareResult = cpu->gpr[3]; } if (prepareResult != 0) { @@ -162,7 +162,7 @@ extern "C" void TaskThread_run_HLE_80242d7c(CpuContext* ctx) { cpu->gpr[3] = taskThread + kTaskMessageQueueOffset; cpu->gpr[4] = outMsgPtr; cpu->gpr[5] = 1; // OS_MESSAGE_BLOCK - InvokeIndirectCpu(0x801A7424u, cpu); // OSReceiveMessage + InvokeIndirectCpu(MKW_GADDR(801A7424), cpu); // OSReceiveMessage } const uint32_t job = Memory::Read32(outMsgPtr); @@ -176,7 +176,7 @@ extern "C" void TaskThread_run_HLE_80242d7c(CpuContext* ctx) { if (callback != 0) { CpuContextScope scope(cpu); - if (callback == 0x80529D68u) { + if (callback == MKW_GADDR(80529D68)) { RunMovieManagerPrepareAsync(arg, cpu); } else { cpu->gpr[3] = arg; @@ -198,7 +198,7 @@ extern "C" void TaskThread_run_HLE_80242d7c(CpuContext* ctx) { cpu->gpr[3] = doneQueue; cpu->gpr[4] = token; cpu->gpr[5] = 0; // OS_MESSAGE_NOBLOCK - InvokeIndirectCpu(0x801A735Cu, cpu); // OSSendMessage + InvokeIndirectCpu(MKW_GADDR(801A735C), cpu); // OSSendMessage } } } diff --git a/runtime/src/hle/vi.cpp b/runtime/src/hle/vi.cpp index 7ee76b5..e0a160d 100644 --- a/runtime/src/hle/vi.cpp +++ b/runtime/src/hle/vi.cpp @@ -133,22 +133,22 @@ ViState g_vi; // Guest-side state addresses used by the SDK's VI globals. -constexpr uint32_t kViInitializedFlagAddr = 0x80386b38; -constexpr uint32_t kViTvFormatAddr = 0x80386ba8; -constexpr uint32_t kViRenderWidthAddr = 0x80350864; -constexpr uint32_t kViRenderHeightAddr = 0x80350866; -constexpr uint32_t kViXfbWidthAddr = 0x80350872; -constexpr uint32_t kViXfbHeightAddr = 0x8035087c; -constexpr uint32_t kViRetraceCountAddr = 0x80386be4; // matches VIWaitForRetrace/handler -constexpr uint32_t kViTimingGuardAddr = 0x80386b44; -constexpr uint32_t kViPreRetraceCallback = 0x80386bb8; -constexpr uint32_t kViPostRetraceCallback = 0x80386bb4; -constexpr uint32_t kViNextFrameBufferAddr = 0x80386ba0; -constexpr uint32_t kViNextFrameBufferHwAddr = 0x80350890; -constexpr uint32_t kViRetraceQueueAddr = 0x80386bc0; // Thread queue for VIWaitForRetrace +const uint32_t kViInitializedFlagAddr = MKW_GADDR(80386b38); +const uint32_t kViTvFormatAddr = MKW_GADDR(80386ba8); +const uint32_t kViRenderWidthAddr = MKW_GADDR(80350864); +const uint32_t kViRenderHeightAddr = MKW_GADDR(80350866); +const uint32_t kViXfbWidthAddr = MKW_GADDR(80350872); +const uint32_t kViXfbHeightAddr = MKW_GADDR(8035087c); +const uint32_t kViRetraceCountAddr = MKW_GADDR(80386be4); // matches VIWaitForRetrace/handler +const uint32_t kViTimingGuardAddr = MKW_GADDR(80386b44); +const uint32_t kViPreRetraceCallback = MKW_GADDR(80386bb8); +const uint32_t kViPostRetraceCallback = MKW_GADDR(80386bb4); +const uint32_t kViNextFrameBufferAddr = MKW_GADDR(80386ba0); +const uint32_t kViNextFrameBufferHwAddr = MKW_GADDR(80350890); +const uint32_t kViRetraceQueueAddr = MKW_GADDR(80386bc0); // Thread queue for VIWaitForRetrace // EGG::BaseSystem::sSystem pointer - must be non-null before post-retrace callback is valid -constexpr uint32_t kEggSSystemAddr = 0x80386F60; +const uint32_t kEggSSystemAddr = MKW_GADDR(80386F60); std::chrono::microseconds IntervalForFormat(uint32_t tvFormat) { // NTSC-ish defaults to 60 Hz; PAL uses 50 Hz. @@ -577,7 +577,7 @@ void VI_HLE_PresentFrame(bool presentedXfb, bool paceToRetrace) { aurora_set_present_schedule(0, 0); } - aurora_end_frame(); + EndAuroraFrame(); if (paceThisFrame) { PaceToRetraceBoundary(paceDeadline); std::lock_guard lock(g_viMutex); @@ -751,7 +751,10 @@ extern "C" void VIConfigure_HLE_801b9f6c(CpuContext* ctx) renderMode.xfbHeight != 0 ? renderMode.xfbHeight : renderMode.efbHeight; } - ::VIConfigure(&renderMode); + { + GX_SYNC_INLINE(); + ::VIConfigure(&renderMode); + } ViSetR3(ctx, 0); } diff --git a/runtime/src/main.cpp b/runtime/src/main.cpp index 5f37a54..ae85098 100644 --- a/runtime/src/main.cpp +++ b/runtime/src/main.cpp @@ -63,9 +63,10 @@ #include "system_bridge.h" #include "ppc_runtime.h" #include "aurora_events.h" -#include "wii_remote_input.h" +#include "wiimote_host.h" #include "discord_presence.h" #include "fiber_manager.h" +#include "gx_worker.h" #include "hle_stubs.h" #include "runtime_config.h" #include "runtime_log.h" @@ -88,6 +89,9 @@ namespace { std::string FormatHostStackTrace(unsigned framesToSkip = 0); void ServiceGuestTimingDuringAuroraFrameWait() { + if (GxWorker::OnWorker()) { + return; + } // Aurora can block inside FIFO drains before control returns to GX HLE, for as long as a // whole display period. Keep VI retraces, alarms and audio moving at wall-clock cadence here // while still suppressing guest rescheduling and recursive Aurora work. @@ -761,6 +765,8 @@ extern "C" void DumpHostStackTraceForRuntimeHelper() { void MarkFatalErrorReported() { g_fatalErrorReported.store(true, std::memory_order_release); + // Every caller exits next; keep the worker out of static teardown. + GxWorker::Abandon(); } void ShowRuntimeFatalPopup(std::string_view category, std::string_view details) noexcept { @@ -1384,7 +1390,7 @@ int RuntimeMain(int argc, char** argv) { auroraConfig.allowTextureReplacements = RuntimeConfigFile::TextureReplacements(false); auroraConfig.allowTextureDumps = auroraConfig.allowTextureReplacements && RuntimeConfigFile::TextureDumps(false); - // No vsync knob: aurora always configures a non-blocking present mode. + auroraConfig.vsync = RuntimeConfigFile::Vsync(); auroraConfig.desiredBackend = BACKEND_AUTO; const float resolutionMultiplier = RuntimeConfigFile::ResolutionMultiplier(1.0f); ConfigureMkwDynamicAspect(configWidescreen, forceAspect169, @@ -1430,10 +1436,9 @@ int RuntimeMain(int argc, char** argv) { } const AuroraBackend requestedBackend = auroraConfig.desiredBackend; - // SDL only reads its Wii driver hint when the joystick subsystem starts, which - // aurora_initialize does; a Bluetooth Wii Remote paired before launch must be - // visible on that first scan. - WiiRemoteInput::ConfigureSdlHints(RuntimeConfigFile::WiiRemotesEnabled(true)); + // SDL reads its device hints when the joystick subsystem starts, which + // aurora_initialize does. + Wiimote::ConfigureSdlHints(RuntimeConfigFile::WiiRemotesEnabled()); const AuroraInfo auroraInfo = aurora_initialize(0, nullptr, &auroraConfig); if (auroraInfo.initializationStatus != AURORA_INITIALIZATION_SUCCESS) { @@ -1450,6 +1455,7 @@ int RuntimeMain(int argc, char** argv) { << std::endl; } aurora_set_frame_worker_wait_callback(ServiceGuestTimingDuringAuroraFrameWait); + Wiimote::Initialize(); GxGuestWrite::InstallAuroraHooks(); UpdateMkwDynamicAspectSurface(auroraInfo.windowSize.native_fb_width, auroraInfo.windowSize.native_fb_height); @@ -1466,6 +1472,8 @@ int RuntimeMain(int argc, char** argv) { << (forceAspect169 ? "16:9" : (configWidescreen ? "surface (dynamic EGG canvas)" : "4:3")) << std::endl; g_auroraInitialized.store(true, std::memory_order_release); + GxWorker::SetWaitCallback(ServiceGuestTimingDuringAuroraFrameWait); + GxWorker::Start(); auto entry = ResolveEntry(); InitializePersistentCpuContext(); @@ -1493,6 +1501,8 @@ int RuntimeMain(int argc, char** argv) { // Shutdown fiber system Fiber::GuestFiberManager::Shutdown(); WindowPlacementPersistence::Flush(true); + Wiimote::Shutdown(); + GxWorker::Stop(); aurora_shutdown(); DiscordPresence::Shutdown(); SetRuntimeExitCodeImpl(0); @@ -1511,6 +1521,8 @@ int RuntimeMain(int argc, char** argv) { SetRuntimeExitCodeImpl(1); Fiber::GuestFiberManager::Shutdown(); WindowPlacementPersistence::Flush(true); + Wiimote::Shutdown(); + GxWorker::Stop(); aurora_shutdown(); DiscordPresence::Shutdown(); ShutdownProcessTranscript(); @@ -1523,6 +1535,8 @@ int RuntimeMain(int argc, char** argv) { SetRuntimeExitCodeImpl(1); Fiber::GuestFiberManager::Shutdown(); WindowPlacementPersistence::Flush(true); + Wiimote::Shutdown(); + GxWorker::Stop(); aurora_shutdown(); DiscordPresence::Shutdown(); ShutdownProcessTranscript(); diff --git a/runtime/src/memory.cpp b/runtime/src/memory.cpp index 88a484e..7225f4b 100644 --- a/runtime/src/memory.cpp +++ b/runtime/src/memory.cpp @@ -1,4 +1,5 @@ #include "memory.h" +#include "hle/hollywood_gpio.h" #include #include @@ -643,6 +644,9 @@ uint16_t MemoryInline::Read16Slow(uint32_t addr) { uint32_t MemoryInline::Read32Slow(uint32_t addr) { if (IsMmioAddress(addr)) { + if (uint32_t value = 0; HollywoodGpio_Read32(addr, value)) { + return value; + } ThrowMmioReadBlocked(addr, sizeof(uint32_t)); } ResolveDeferredReads(addr, sizeof(uint32_t)); @@ -708,6 +712,9 @@ void MemoryInline::Write32Slow(uint32_t addr, uint32_t val) { return; } if (IsMmioAddress(addr)) { + if (HollywoodGpio_Write32(addr, val)) { + return; + } throw Memory::AccessViolation(addr, sizeof(val), "MMIO write blocked (non-GPU)"); } WriteScalar(addr, val); diff --git a/runtime/src/music_attenuation.cpp b/runtime/src/music_attenuation.cpp index d03c3cf..ad031c1 100644 --- a/runtime/src/music_attenuation.cpp +++ b/runtime/src/music_attenuation.cpp @@ -1,4 +1,5 @@ #include "music_attenuation.h" +#include "guest_abi/guest_region.h" #include "memory.h" @@ -28,7 +29,7 @@ namespace MusicAttenuation { namespace { -constexpr uint32_t kSoundManagerPointer = 0x809C2898u; +const uint32_t kSoundManagerPointer = MKW_GADDR(809C2898); constexpr uint32_t kArchivePlayerOffset = 0x5BCu; constexpr uint32_t kSoundPlayersOffset = 0x34u; constexpr uint32_t kSoundPlayerVolumeOffset = 0x2Cu; diff --git a/runtime/src/recomp_mod_loader.cpp b/runtime/src/recomp_mod_loader.cpp index 104ff0d..61637ff 100644 --- a/runtime/src/recomp_mod_loader.cpp +++ b/runtime/src/recomp_mod_loader.cpp @@ -1,4 +1,5 @@ #include "recomp_mod_loader.h" +#include "guest_abi/guest_region.h" #include #include @@ -198,8 +199,8 @@ bool IsKnownBaseRelLoaderWrite(const ExecutableRange& range) { // The game copies and relocates REL sections before executing them. Those // writes are normal loading/linking, not runtime code patches. - return (cpu->lr >= 0x8000A000u && cpu->lr < 0x8000A400u) || - (cpu->lr >= 0x801A6000u && cpu->lr < 0x801A7000u); + return (cpu->lr >= MKW_GADDR(8000A000) && cpu->lr < MKW_GADDR(8000A400)) || + (cpu->lr >= MKW_GADDR(801A6000) && cpu->lr < MKW_GADDR(801A7000)); } } // namespace diff --git a/runtime/src/settings_overlay.cpp b/runtime/src/settings_overlay.cpp index 4836c6e..4873c4c 100644 --- a/runtime/src/settings_overlay.cpp +++ b/runtime/src/settings_overlay.cpp @@ -1,4 +1,5 @@ #include "settings_overlay.h" +#include "gx_worker.h" #include "audio_backend.h" #include "aurora_events.h" #include "controller_button_names.h" @@ -8,7 +9,7 @@ #include "music_attenuation.h" #include "runtime_config.h" #include "runtime_log.h" -#include "wii_remote_input.h" +#include "wiimote_host.h" #include #include @@ -108,6 +109,7 @@ int g_displayMode = [] { return static_cast(AURORA_DISPLAY_MODE_WINDOWED); }(); bool g_skipUnreadyPipelines = RuntimeConfigFile::SkipUnreadyPipelines(true); +bool g_vsync = RuntimeConfigFile::Vsync(); bool g_disableCopyFilter = RuntimeConfigFile::DisableCopyFilter(true); bool g_showFps = RuntimeConfigFile::ShowFps(true); bool g_forceAspect169 = RuntimeConfigFile::ForceAspect169Enabled(); @@ -188,6 +190,7 @@ bool IsHighFrameRateMode() { } void SetResolutionScale(float scale) { + GX_SYNC_INLINE(); g_resolutionScale = scale; VISetFrameBufferScale(scale); RuntimeConfigFile::SetResolutionMultiplier(scale); @@ -259,9 +262,9 @@ void ApplyConfiguredMappings() { // they describe whatever pad the user set them up with (usually an Xbox // layout: a = south). A Wii U Pro Controller has a fixed, known layout // (A on the east position) that aurora already maps by name; applying - // the shared bindings on top swaps A/B and X/Y. (Wii Remotes with any - // extension never reach the PAD layer: the game reads them through KPAD.) - if (WiiRemoteInput::KindForPort(port) == WiiRemoteInput::Kind::WiiUPro) { + // the shared bindings on top swaps A/B and X/Y. + if (const char* name = PADGetNameForControllerIndex(static_cast(controllerIndex)); + name != nullptr && std::string_view(name).find("Wii U Pro") != std::string_view::npos) { continue; } @@ -295,139 +298,114 @@ void ApplyConfiguredMappings() { } } -bool g_wiiRemotesEnabled = RuntimeConfigFile::WiiRemotesEnabled(true); -bool g_wiiContinuousScan = RuntimeConfigFile::WiiContinuousScanEnabled(false); +bool g_wiiRemotesEnabled = RuntimeConfigFile::WiiRemotesEnabled(); +bool g_wiiAutoPair = RuntimeConfigFile::WiiAutoPairEnabled(true); +bool g_wiiSensorBarAbove = RuntimeConfigFile::WiiSensorBarAbove(false); +int g_wiiIrSensitivity = RuntimeConfigFile::WiiIrSensitivity(3); -// Accelerometer readout and zero-point calibration for a bare remote / remote + Nunchuk. -void DrawWiiRemoteAccelerometer(uint32_t port) { - ImGui::SeparatorText("Accelerometer"); - float sdlG[3] = {}; - float kpad[3] = {}; - if (WiiRemoteInput::ReadAccelDebug(port, sdlG, kpad)) { - ImGui::Text("KPAD acc: x %+.2f y %+.2f z %+.2f g", kpad[0], kpad[1], kpad[2]); - ImGui::TextDisabled("Flat, buttons up: (0, -1, 0). Sideways as a wheel: (1, 0, 0); z follows the turn."); - } else { - ImGui::TextDisabled("No accelerometer data yet."); - } - // Residual per-axis bias left after SDL's factory-calibrated decode, measured - // here with the remote at rest. - if (WiiRemoteInput::IsAccelCalibrating(port)) { - ImGui::ProgressBar(WiiRemoteInput::AccelCalibrationProgress(), ImVec2(220.0f, 0.0f), "Hold still..."); - } else if (ImGui::Button("Calibrate (remote lying flat, buttons up)")) { - WiiRemoteInput::StartAccelCalibration(port); - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Put the remote down on a flat surface with the buttons facing up and do not touch it\n" - "for about two seconds. Corrects the steering offset of a remote held sideways."); - } - ImGui::SameLine(); - const auto stored = WiiRemoteInput::ReadAccelOffset(port); - const std::array offset = stored.value_or(std::array{}); - const bool calibrated = offset[0] != 0.0 || offset[1] != 0.0 || offset[2] != 0.0; - ImGui::BeginDisabled(!calibrated || WiiRemoteInput::IsAccelCalibrating(port)); - if (ImGui::Button("Clear calibration")) { - WiiRemoteInput::ClearAccelCalibration(port); - } - ImGui::EndDisabled(); - if (const char* message = WiiRemoteInput::AccelCalibrationMessage(port)) { - ImGui::TextWrapped("%s", message); - } else if (calibrated) { - ImGui::TextDisabled("Stored offset: x %+.3f y %+.3f z %+.3f g", offset[0], offset[1], offset[2]); - } else { - ImGui::TextDisabled("No trim stored."); - } + +constexpr float kControllerMenuWidth = 460.0f; + +void PushMenuTextWrap() { + ImGui::PushTextWrapPos(0.0f); } -// Wii Remotes (Bluetooth) menu: driver switch, pairing help, continuous scanning and the port's controller kind. -void DrawWiiRemoteSettings(uint32_t selectedGamePort) { - if (!ImGui::BeginMenu("Wii Remotes (Bluetooth)")) { +std::string WiiRemoteLabel(const Wiimote::SlotInfo& info) { + std::string label = info.model; + if (!info.extension.empty()) { + label += " + " + info.extension; + } + return label; +} + +// Pairing, the console's Wii Remote settings and the driver switch; applies to every remote. +void DrawWiiRemoteSetup() { + if (!ImGui::CollapsingHeader("Wii Remote setup (Bluetooth)")) { return; } - if (ImGui::Checkbox("Use Wii Remotes / Wii U Pro Controllers", &g_wiiRemotesEnabled)) { + ImGui::Indent(); + PushMenuTextWrap(); + const std::string notice = Wiimote::PlatformNotice(); + if (!notice.empty()) { + ImGui::TextColored(ImVec4(1.0f, 0.75f, 0.25f, 1.0f), "%s", notice.c_str()); + } + const Wiimote::PairingInfo pairing = Wiimote::Pairing(); + if (pairing.supported) { + ImGui::TextUnformatted("Press the red SYNC button (or 1 and 2) on the Wii Remote, like on a Wii."); + ImGui::TextDisabled("Paired before? Just press any button on it."); + } else if (g_wiiRemotesEnabled) { + ImGui::TextUnformatted("Pair the Wii Remote in your system's Bluetooth settings, then press any button on it."); + } + ImGui::PopTextWrapPos(); + ImGui::BeginDisabled(!pairing.supported); + if (ImGui::Button("Pair a Wii Remote")) { + Wiimote::StartPairing(); + } + ImGui::EndDisabled(); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Searches for a minute, like pressing SYNC on the console."); + } + ImGui::SameLine(); + if (pairing.searching) { + ImGui::TextDisabled("Searching..."); + } else if (!pairing.status.empty()) { + ImGui::TextDisabled("%s", pairing.status.c_str()); + } + if (const size_t waiting = Wiimote::WaitingRemotes(); waiting != 0) { + ImGui::TextDisabled("%zu more Wii Remote%s connected; joins when a player leaves.", waiting, + waiting == 1 ? "" : "s"); + } + if (ImGui::Checkbox("Look for Wii Remotes automatically", &g_wiiAutoPair)) { + RuntimeConfigFile::SetWiiAutoPairEnabled(g_wiiAutoPair); + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("While no Wii Remote is connected, keep searching for one in pairing mode.\n" + "Searching can briefly disturb Bluetooth headphones."); + } + ImGui::SetNextItemWidth(160.0f); + int sensorBar = g_wiiSensorBarAbove ? 1 : 0; + if (ImGui::Combo("Sensor bar", &sensorBar, "Below TV\0Above TV\0")) { + g_wiiSensorBarAbove = sensorBar == 1; + RuntimeConfigFile::SetWiiSensorBarAbove(g_wiiSensorBarAbove); + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Takes effect the next time the game starts."); + } + ImGui::SetNextItemWidth(160.0f); + if (ImGui::SliderInt("Pointer sensitivity", &g_wiiIrSensitivity, 1, 5, "%d", ImGuiSliderFlags_AlwaysClamp)) { + RuntimeConfigFile::SetWiiIrSensitivity(g_wiiIrSensitivity); + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("The sensor bar sensitivity from the Wii settings.\nTakes effect the next time the game starts."); + } + if (ImGui::Checkbox("Use Wii Remotes", &g_wiiRemotesEnabled)) { RuntimeConfigFile::SetWiiRemotesEnabled(g_wiiRemotesEnabled); } if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Takes effect on the next launch. Turn this off if you use a Mayflash DolphinBar."); + ImGui::SetTooltip("Takes effect on the next launch. Turn this off to use a Wii U Pro Controller as a gamepad."); } - ImGui::TextDisabled("Pairing: Windows Settings > Bluetooth > Add device, then press 1+2"); - ImGui::TextDisabled("(or the red SYNC button) on the remote. Leave the PIN empty."); - ImGui::TextDisabled("A remote that was paired before also needs to be turned on with 1+2/SYNC."); - if (ImGui::Checkbox("Keep scanning for Wii Remotes (like Dolphin's Continuous Scanning)", - &g_wiiContinuousScan)) { - RuntimeConfigFile::SetWiiContinuousScanEnabled(g_wiiContinuousScan); + ImGui::Unindent(); +} + +// The Wii Remote the game has on this player's channel. +void DrawWiiRemoteDetails(uint32_t port, const Wiimote::SlotInfo& info) { + ImGui::Text("%s", WiiRemoteLabel(info).c_str()); + if (info.battery >= 0) { + ImGui::SameLine(); + ImGui::TextDisabled("Battery %d/4", info.battery); } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("While no Wii controller is connected, re-check Bluetooth every 2 seconds so a\n" - "remote that dropped out (\"Communications with the controller have been\n" - "interrupted\") or was turned on after launch comes back by itself."); - } - // The driver hint is only read at launch, so a rescan after the user turned - // the setting off would still re-enumerate Wii devices in this session. - ImGui::BeginDisabled(!g_wiiRemotesEnabled); - if (ImGui::Button("Rescan now")) { - WiiRemoteInput::RescanNow(); - } - ImGui::EndDisabled(); - ImGui::SameLine(); - if (WiiRemoteInput::IsScanning()) { - ImGui::TextDisabled("Scanning... (%u so far) - press 1+2 on the remote", WiiRemoteInput::ScanCount()); + PushMenuTextWrap(); + if (info.asleep) { + ImGui::TextUnformatted("Disconnected by the game. Press any button on it to reconnect."); + } else if (info.link == Bluetooth::LinkState::Ready) { + ImGui::TextUnformatted("The game reads it like a real Wii Remote. Nothing to set up."); } else { - ImGui::TextDisabled("Not scanning"); + ImGui::TextUnformatted("Connecting to the game..."); } - ImGui::Separator(); - - const WiiRemoteInput::Kind kind = WiiRemoteInput::KindForPort(selectedGamePort); - ImGui::Text("Port %u: %s", static_cast(selectedGamePort + 1), WiiRemoteInput::KindLabel(kind)); - if (kind == WiiRemoteInput::Kind::RemoteWithClassic) { - WiiRemoteInput::KpadSample sample; - if (WiiRemoteInput::ReadKpadSample(selectedGamePort, sample)) { - // WPAD_CL_BUTTON_* bits, in the game's own layout (no mapping involved). - const auto held = [&](uint32_t bit, const char* on, const char* off) { return (sample.clHold & bit) ? on : off; }; - ImGui::Text("Classic: %s %s %s %s %s %s %s %s %s %s %s %s %s %s", held(0x0010, "A", "a"), - held(0x0040, "B", "b"), held(0x0008, "X", "x"), held(0x0020, "Y", "y"), held(0x2000, "L", "l"), - held(0x0200, "R", "r"), held(0x0080, "ZL", "zl"), held(0x0004, "ZR", "zr"), - held(0x0400, "PLUS", "plus"), held(0x1000, "MINUS", "minus"), held(0x0001, "UP", "up"), - held(0x4000, "DOWN", "down"), held(0x0002, "LEFT", "left"), held(0x8000, "RIGHT", "right")); - ImGui::Text("Sticks: L %+.2f %+.2f (WPAD %+d %+d) R %+.2f %+.2f (WPAD %+d %+d)", sample.clLStick[0], - sample.clLStick[1], static_cast(sample.clLStickRaw[0]), - static_cast(sample.clLStickRaw[1]), sample.clRStick[0], sample.clRStick[1], - static_cast(sample.clRStickRaw[0]), static_cast(sample.clRStickRaw[1])); - ImGui::TextDisabled("Capitals = held. The game reads this Classic Controller through KPAD, as on the"); - ImGui::TextDisabled("console: its buttons mean what the game says they mean, no mapping applies."); - } + ImGui::PopTextWrapPos(); + if (!info.asleep && ImGui::Button("Disconnect")) { + Wiimote::Disconnect(port); } - if (kind == WiiRemoteInput::Kind::WiiUPro) { - if (SDL_Gamepad* gamepad = SDL_GetGamepadFromPlayerIndex(static_cast(selectedGamePort))) { - // SDL's Wii driver posts the D-pad as joystick buttons 11-14 (the - // SDL_GAMEPAD_BUTTON_DPAD_* values) while its default HIDAPI mapping - // expects a hat, so SDL_GetGamepadButton never sees them; read the - // joystick directly, like the fallback in aurora's PADRead does. - SDL_Joystick* joystick = SDL_GetGamepadJoystick(gamepad); - const auto rawButton = [&](int index) { - return joystick != nullptr && SDL_GetJoystickButton(joystick, index); - }; - ImGui::Text("Raw D-pad: %s %s %s %s", rawButton(SDL_GAMEPAD_BUTTON_DPAD_UP) ? "UP" : "up", - rawButton(SDL_GAMEPAD_BUTTON_DPAD_DOWN) ? "DOWN" : "down", - rawButton(SDL_GAMEPAD_BUTTON_DPAD_LEFT) ? "LEFT" : "left", - rawButton(SDL_GAMEPAD_BUTTON_DPAD_RIGHT) ? "RIGHT" : "right"); - ImGui::Text("Raw face buttons: %s %s %s %s", rawButton(SDL_GAMEPAD_BUTTON_EAST) ? "A" : "a", - rawButton(SDL_GAMEPAD_BUTTON_SOUTH) ? "B" : "b", rawButton(SDL_GAMEPAD_BUTTON_NORTH) ? "X" : "x", - rawButton(SDL_GAMEPAD_BUTTON_WEST) ? "Y" : "y"); - ImGui::Text("Raw ZL/ZR: %d / %d (pressed above 0)", - SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFT_TRIGGER), - SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER)); - ImGui::TextDisabled("Capitals = held. If a button never turns to capitals while physically held,"); - ImGui::TextDisabled("that press is not reaching SDL at all (a driver-level issue, not a mapping one)."); - ImGui::TextDisabled("This pad uses Nintendo's own layout (a/b/x/y as labelled); the shared"); - ImGui::TextDisabled("button mapping above does not apply to it."); - } - } - if (kind == WiiRemoteInput::Kind::Remote || kind == WiiRemoteInput::Kind::RemoteWithNunchuk || - kind == WiiRemoteInput::Kind::RemoteWithClassic) { - DrawWiiRemoteAccelerometer(selectedGamePort); - } - - ImGui::EndMenu(); } const char* KeyBindingName(int scancode) { @@ -594,65 +572,74 @@ void DrawKeyBinding(const char* label, int scancode, RebindKind kind, uint16_t t } -bool DrawKeyboardSettings(uint32_t port) { +void ApplyKeyboardPreset(uint32_t port) { + const std::array keys = { + PAD_KEY_MOUSE_LEFT, SDL_SCANCODE_SPACE, SDL_SCANCODE_E, SDL_SCANCODE_Q, + SDL_SCANCODE_RETURN, PAD_KEY_MOUSE_MIDDLE, SDL_SCANCODE_LSHIFT, PAD_KEY_MOUSE_RIGHT, + SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT, + }; + for (size_t i = 0; i < keys.size(); ++i) + PADSetKeyButtonBinding(port, {keys[i], kControllerButtons[i].padButton}); + const std::array axes = { + SDL_SCANCODE_D, SDL_SCANCODE_A, SDL_SCANCODE_W, SDL_SCANCODE_S, + SDL_SCANCODE_L, SDL_SCANCODE_J, SDL_SCANCODE_I, SDL_SCANCODE_K, + SDL_SCANCODE_LSHIFT, PAD_KEY_MOUSE_RIGHT, + }; + uint32_t axisCount = 0; + auto* mappings = PADGetKeyAxisBindings(port, &axisCount); + for (uint32_t i = 0; i < axisCount; ++i) + PADSetKeyAxisBinding(port, {axes[i], mappings[i].padAxis, 1}); + PADSerializeMappings(); +} + +bool KeyboardActive(uint32_t port) { + uint32_t count = 0; + return PADGetKeyButtonBindings(port, &count) != nullptr; +} + +void SetKeyboardActive(uint32_t port, bool active) { + if (KeyboardActive(port) == active) return; + PADSetKeyboardActive(port, active); + PADSerializeMappings(); uint32_t count = 0; auto* buttons = PADGetKeyButtonBindings(port, &count); - bool enabled = buttons != nullptr; - bool usePreset = false; - if (ImGui::Checkbox("Keyboard and mouse", &enabled)) { - PADSetKeyboardActive(port, enabled); - PADSerializeMappings(); - buttons = PADGetKeyButtonBindings(port, &count); - usePreset = enabled && std::all_of(buttons, buttons + count, [](const auto& binding) { + if (active && buttons != nullptr && std::all_of(buttons, buttons + count, [](const auto& binding) { return binding.scancode == PAD_KEY_INVALID; - }); + })) { + ApplyKeyboardPreset(port); } - if (!enabled) return false; - ImGui::TextDisabled("Replaces the gamepad on this port. F10 opens settings."); - if (ImGui::Button("Use WASD + mouse preset") || usePreset) { - const std::array keys = { - PAD_KEY_MOUSE_LEFT, SDL_SCANCODE_SPACE, SDL_SCANCODE_E, SDL_SCANCODE_Q, - SDL_SCANCODE_RETURN, PAD_KEY_MOUSE_MIDDLE, SDL_SCANCODE_LSHIFT, PAD_KEY_MOUSE_RIGHT, - SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT, - }; - for (size_t i = 0; i < keys.size(); ++i) - PADSetKeyButtonBinding(port, {keys[i], kControllerButtons[i].padButton}); - const std::array axes = { - SDL_SCANCODE_D, SDL_SCANCODE_A, SDL_SCANCODE_W, SDL_SCANCODE_S, - SDL_SCANCODE_L, SDL_SCANCODE_J, SDL_SCANCODE_I, SDL_SCANCODE_K, - SDL_SCANCODE_LSHIFT, PAD_KEY_MOUSE_RIGHT, - }; - uint32_t axisCount = 0; - auto* mappings = PADGetKeyAxisBindings(port, &axisCount); - for (uint32_t i = 0; i < axisCount; ++i) - PADSetKeyAxisBinding(port, {axes[i], mappings[i].padAxis, 1}); - PADSerializeMappings(); - } - ImGui::SeparatorText("Button mapping"); - for (uint32_t i = 0; i < count; ++i) { - int key = buttons[i].scancode; +} + +void DrawKeyboardSettings(uint32_t port) { + PushMenuTextWrap(); + ImGui::TextUnformatted("Default: WASD to steer, mouse left to accelerate, Space to brake."); + ImGui::PopTextWrapPos(); + if (!ImGui::CollapsingHeader("Customize keys")) return; + ImGui::Indent(); + if (ImGui::Button("Reset to WASD + mouse")) ApplyKeyboardPreset(port); + uint32_t count = 0; + auto* buttons = PADGetKeyButtonBindings(port, &count); + ImGui::SeparatorText("Buttons"); + for (uint32_t i = 0; buttons != nullptr && i < count; ++i) { ImGui::PushID(static_cast(i)); - ImGui::SetNextItemWidth(220.0f); - DrawKeyBinding(PADGetButtonName(buttons[i].padButton), key, RebindKind::KeyboardButton, buttons[i].padButton); + DrawKeyBinding(PADGetButtonName(buttons[i].padButton), buttons[i].scancode, RebindKind::KeyboardButton, + buttons[i].padButton); ImGui::PopID(); } - ImGui::SeparatorText("Stick and trigger mapping"); + ImGui::SeparatorText("Sticks and triggers"); uint32_t axisCount = 0; auto* axes = PADGetKeyAxisBindings(port, &axisCount); - for (uint32_t i = 0; i < axisCount; ++i) { - int key = axes[i].scancode; + for (uint32_t i = 0; axes != nullptr && i < axisCount; ++i) { ImGui::PushID(static_cast(count + i)); const char* direction = PADGetAxisDirectionLabel(axes[i].padAxis); const std::string label = std::string(PADGetAxisName(axes[i].padAxis)) + " " + (direction != nullptr ? direction : ""); - ImGui::SetNextItemWidth(220.0f); - DrawKeyBinding(label.c_str(), key, RebindKind::KeyboardAxis, axes[i].padAxis); + DrawKeyBinding(label.c_str(), axes[i].scancode, RebindKind::KeyboardAxis, axes[i].padAxis); ImGui::PopID(); } - return true; + ImGui::Unindent(); } -// Controller settings menu: port selection, controller assignment and button mapping. int ExpressionResizeCallback(ImGuiInputTextCallbackData* data) { if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) { auto* text = static_cast(data->UserData); @@ -663,7 +650,6 @@ int ExpressionResizeCallback(ImGuiInputTextCallbackData* data) { } void DrawExpressionSettings() { - ImGui::SeparatorText("Expressions (Dolphin syntax)"); ImGui::PushTextWrapPos(ImGui::GetCursorPosX() + 440.0f); ImGui::TextDisabled( "Optional. An expression overrides nothing: its result is combined with the " @@ -729,7 +715,7 @@ void DrawExpressionSettings() { } void DrawRumbleSettings() { - ImGui::SeparatorText("Vibration"); + ImGui::Separator(); if (ImGui::Checkbox("Controller vibration", &g_rumbleEnabled)) { PAD_HLE_SetRumbleEnabled(g_rumbleEnabled); RuntimeConfigFile::SetRumbleEnabled(g_rumbleEnabled); @@ -747,73 +733,15 @@ void DrawRumbleSettings() { } } -void DrawControllerSettings() { - for (int port = 0; port < PAD_MAX_CONTROLLERS; ++port) { - const std::string label = "Port " + std::to_string(port + 1); - ImGui::RadioButton(label.c_str(), &g_controllerPort, port); - if (port + 1 < PAD_MAX_CONTROLLERS) { - ImGui::SameLine(); - } - } - - ImGui::Separator(); - const uint32_t selectedGamePort = static_cast(g_controllerPort); - if (DrawKeyboardSettings(selectedGamePort)) { - return; - } - ImGui::Separator(); - const char* currentName = PADGetName(selectedGamePort); - ImGui::Text("Assigned: %s", currentName != nullptr ? currentName : "None"); - if (ImGui::MenuItem("Unassign controller")) { - PADClearPort(selectedGamePort); - g_configuredControllerIndices.fill(std::numeric_limits::min()); - } - ImGui::Separator(); - controller_mapping_wizard::DrawSetupList(); - DrawWiiRemoteSettings(selectedGamePort); - const uint32_t controllerCount = PADCount(); - if (controllerCount == 0) { - ImGui::TextDisabled("No controller connected"); - return; - } - - if (ImGui::BeginMenu("Assign connected controller")) { - for (uint32_t index = 0; index < controllerCount; ++index) { - const char* name = PADGetNameForControllerIndex(index); - std::string label = name != nullptr ? name : "Unknown controller"; - for (int port = 0; port < PAD_MAX_CONTROLLERS; ++port) { - if (PADGetIndexForPort(port) == static_cast(index)) { - label += " (Port " + std::to_string(port + 1) + ")"; - break; - } - } - ImGui::PushID(static_cast(index)); - if (ImGui::MenuItem(label.c_str())) { - PADSetPortForIndex(index, selectedGamePort); - g_configuredControllerIndices.fill(std::numeric_limits::min()); - ApplyConfiguredMappings(); - } - ImGui::PopID(); - } - ImGui::EndMenu(); - } - - if (WiiRemoteInput::IsRemoteChannel(selectedGamePort)) { - ImGui::TextDisabled("The game reads this controller as a Wii Remote, so the button mapping does not apply."); - DrawRumbleSettings(); - return; - } - +void DrawGamepadMapping(uint32_t port) { uint32_t mappingCount = 0; - PADButtonMapping* mappings = PADGetButtonMappings(static_cast(g_controllerPort), &mappingCount); + PADButtonMapping* mappings = PADGetButtonMappings(port, &mappingCount); if (mappings == nullptr || mappingCount != PAD_BUTTON_COUNT) { - ImGui::TextDisabled("Assign a controller to edit its buttons"); return; } uint32_t altMappingCount = 0; - PADButtonMapping* altMappings = - PADGetAltButtonMappings(static_cast(g_controllerPort), &altMappingCount); + PADButtonMapping* altMappings = PADGetAltButtonMappings(port, &altMappingCount); const auto writeBinding = [](size_t index, uint32_t primaryNative, uint32_t altNative) { std::string value = NativeBindingConfig(primaryNative); @@ -824,18 +752,18 @@ void DrawControllerSettings() { RuntimeConfigFile::SetControllerButton(index, value); }; - // Which rows show the second-binding combo without one being bound yet; + // Which rows show the second-binding button without one being bound yet; // reset when the user switches ports so a stale "+" click doesn't linger. static std::array altRowExpanded{}; static int altRowExpandedPort = -1; - if (altRowExpandedPort != g_controllerPort) { - altRowExpandedPort = g_controllerPort; + if (altRowExpandedPort != static_cast(port)) { + altRowExpandedPort = static_cast(port); altRowExpanded.fill(false); } - ImGui::SeparatorText("Presets"); - if (ImGui::Button("GameCube")) { - const uint32_t port = static_cast(g_controllerPort); + ImGui::TextUnformatted("Layout:"); + ImGui::SameLine(); + if (ImGui::SmallButton("GameCube")) { PADRestoreDefaultMapping(port); uint32_t restoredCount = 0; if (PADButtonMapping* restored = PADGetButtonMappings(port, &restoredCount)) { @@ -853,7 +781,6 @@ void DrawControllerSettings() { mappings = PADGetButtonMappings(port, &mappingCount); } const auto applyPreset = [&](const std::array& preset) { - const uint32_t port = static_cast(g_controllerPort); for (size_t i = 0; i < kControllerButtons.size(); ++i) { if (const NativeButtonItem* native = FindNativeButton(preset[i])) { PADSetButtonMapping(port, PADButtonMapping{native->nativeButton, kControllerButtons[i].padButton}); @@ -866,22 +793,20 @@ void DrawControllerSettings() { PADSerializeMappings(); mappings = PADGetButtonMappings(port, &mappingCount); }; - ImGui::SameLine(); - if (ImGui::Button("Classic Controller Pro")) { + if (ImGui::SmallButton("Classic Controller Pro")) { applyPreset(kClassicProPreset); } ImGui::SameLine(); - if (ImGui::Button("PlayStation")) { + if (ImGui::SmallButton("PlayStation")) { applyPreset(kPlayStationPreset); } - ImGui::SeparatorText("Button mapping"); - ImGui::TextDisabled("LT / L2 = left trigger. RT / R2 = right trigger."); - ImGui::TextDisabled("LB / L1 = left shoulder. RB / R1 = right shoulder."); - ImGui::TextDisabled("Click a binding, then press an input. No input for 10 seconds clears it."); + ImGui::TextDisabled("Click a binding, then press the input to use. Triggers: LT/L2, RT/R2."); const float bindingWidth = ImGui::CalcTextSize("Right shoulder (RB / R1)").x + ImGui::GetFrameHeight() + ImGui::GetStyle().FramePadding.x * 2.0f; + const float bindingX = ImGui::GetCursorPosX() + ImGui::CalcTextSize("D-pad Right").x + + ImGui::GetStyle().ItemSpacing.x * 2.0f; for (size_t i = 0; i < kControllerButtons.size(); ++i) { auto mappingIt = std::find_if(mappings, mappings + mappingCount, [&](const PADButtonMapping& mapping) { return mapping.padButton == kControllerButtons[i].padButton; @@ -911,8 +836,8 @@ void DrawControllerSettings() { PADAxisButtonIdentity(mapping->nativeButton) | (static_cast(threshold) << 8), mapping->padButton, }; - if (secondary) PADSetAltButtonMapping(selectedGamePort, updated); - else PADSetButtonMapping(selectedGamePort, updated); + if (secondary) PADSetAltButtonMapping(port, updated); + else PADSetButtonMapping(port, updated); } if (ImGui::IsItemDeactivatedAfterEdit()) { writeBinding(i, mappingIt->nativeButton, @@ -920,8 +845,10 @@ void DrawControllerSettings() { PADSerializeMappings(); } }; + ImGui::AlignTextToFramePadding(); + ImGui::TextUnformatted(kControllerButtons[i].label); + ImGui::SameLine(bindingX); ImGui::BeginGroup(); - ImGui::SetNextItemWidth(bindingWidth); const std::string primaryCaption = std::string(current.label) + "##primary"; if (ImGui::Button(primaryCaption.c_str(), ImVec2(bindingWidth, 0.0f))) { BeginRebind(RebindKind::Controller, kControllerButtons[i].padButton, kControllerButtons[i].label); @@ -945,7 +872,6 @@ void DrawControllerSettings() { ImGui::SameLine(); ImGui::BeginGroup(); const char* altLabel = altBound ? NativeButtonForValue(altIt->nativeButton).label : "None"; - ImGui::SetNextItemWidth(bindingWidth); const std::string altCaption = std::string(altLabel) + "##alt"; if (ImGui::Button(altCaption.c_str(), ImVec2(bindingWidth, 0.0f))) { BeginRebind(RebindKind::Controller, kControllerButtons[i].padButton, kControllerButtons[i].label, true); @@ -954,11 +880,113 @@ void DrawControllerSettings() { ImGui::EndGroup(); } } - ImGui::SameLine(); - ImGui::TextUnformatted(kControllerButtons[i].label); ImGui::PopID(); } - DrawExpressionSettings(); +} + +std::string ControllerLabel(uint32_t index) { + const char* name = PADGetNameForControllerIndex(index); + return name != nullptr ? name : "Unknown controller"; +} + +// One row per player: the device combo replaces separate assign/unassign/keyboard controls. +void DrawPlayerRow(uint32_t port) { + const bool keyboard = KeyboardActive(port); + const int32_t assigned = PADGetIndexForPort(port); + std::string preview = "None"; + if (keyboard) { + preview = "Keyboard and mouse"; + } else if (assigned >= 0) { + preview = ControllerLabel(static_cast(assigned)); + } else if (const Wiimote::SlotInfo remote = Wiimote::Slot(port); remote.attached) { + preview = WiiRemoteLabel(remote); + } + + ImGui::PushID(static_cast(port)); + const std::string label = "Player " + std::to_string(port + 1); + ImGui::AlignTextToFramePadding(); + if (ImGui::RadioButton(label.c_str(), g_controllerPort == static_cast(port))) { + g_controllerPort = static_cast(port); + } + ImGui::SameLine(ImGui::CalcTextSize("Player 0").x + ImGui::GetFrameHeight() + 16.0f); + ImGui::SetNextItemWidth(-FLT_MIN); + if (ImGui::BeginCombo("##device", preview.c_str())) { + g_controllerPort = static_cast(port); + if (ImGui::Selectable("None", !keyboard && assigned < 0)) { + SetKeyboardActive(port, false); + PADClearPort(port); + g_configuredControllerIndices.fill(std::numeric_limits::min()); + } + const uint32_t controllerCount = PADCount(); + for (uint32_t index = 0; index < controllerCount; ++index) { + std::string item = ControllerLabel(index); + for (uint32_t other = 0; other < PAD_MAX_CONTROLLERS; ++other) { + if (other != port && PADGetIndexForPort(other) == static_cast(index)) { + item += " (Player " + std::to_string(other + 1) + ")"; + break; + } + } + ImGui::PushID(static_cast(index)); + if (ImGui::Selectable(item.c_str(), !keyboard && assigned == static_cast(index))) { + SetKeyboardActive(port, false); + PADSetPortForIndex(index, port); + g_configuredControllerIndices.fill(std::numeric_limits::min()); + ApplyConfiguredMappings(); + } + ImGui::PopID(); + } + if (ImGui::Selectable("Keyboard and mouse", keyboard)) { + SetKeyboardActive(port, true); + } + ImGui::EndCombo(); + } + ImGui::PopID(); +} + +void DrawControllerSettings() { + ImGui::Dummy(ImVec2(kControllerMenuWidth, 0.0f)); + for (uint32_t port = 0; port < PAD_MAX_CONTROLLERS; ++port) { + DrawPlayerRow(port); + } + bool anyRemote = false; + for (uint32_t player = 0; player < PAD_MAX_CONTROLLERS; ++player) { + anyRemote |= Wiimote::Slot(player).attached; + } + if (PADCount() == 0 && !anyRemote) { + ImGui::TextDisabled("No controller detected. Plug one in, or pair a Wii Remote below."); + } + + const uint32_t port = static_cast(g_controllerPort); + ImGui::SeparatorText(("Player " + std::to_string(port + 1)).c_str()); + const Wiimote::SlotInfo remote = Wiimote::Slot(port); + if (remote.attached) { + DrawWiiRemoteDetails(port, remote); + if (KeyboardActive(port) || PADGetIndexForPort(port) >= 0) { + ImGui::Spacing(); + } + } + if (KeyboardActive(port)) { + DrawKeyboardSettings(port); + } else if (PADGetIndexForPort(port) < 0) { + if (!remote.attached) { + ImGui::TextDisabled("No device. Pick one in the list above."); + } + } else { + ImGui::TextUnformatted("Ready to play."); + if (ImGui::CollapsingHeader("Customize buttons")) { + ImGui::Indent(); + DrawGamepadMapping(port); + if (ImGui::TreeNode("Advanced: Dolphin expressions")) { + DrawExpressionSettings(); + ImGui::TreePop(); + } + ImGui::Unindent(); + } + } + + ImGui::Spacing(); + controller_mapping_wizard::DrawSetupList(); + DrawWiiRemoteSetup(); DrawRumbleSettings(); } @@ -1109,6 +1137,7 @@ void DrawGraphicsSettings() { ImGui::EndCombo(); } if (frameInterpolationModeChanged) { + GX_SYNC_INLINE(); const uint32_t targetFps = kFrameInterpolationTargetFps[static_cast(g_frameInterpolationMode)]; aurora_set_frame_interpolation_fps(targetFps); RuntimeConfigFile::SetFrameInterpolationFps(targetFps); @@ -1152,13 +1181,19 @@ void DrawGraphicsSettings() { } #endif if (ImGui::Checkbox("Disable copy filter", &g_disableCopyFilter)) { + GX_SYNC_INLINE(); aurora_set_disable_copy_filter(g_disableCopyFilter); RuntimeConfigFile::SetDisableCopyFilter(g_disableCopyFilter); } if (ImGui::Checkbox("Skip draws while shaders compile", &g_skipUnreadyPipelines)) { + GX_SYNC_INLINE(); aurora_set_skip_unready_pipelines(g_skipUnreadyPipelines); RuntimeConfigFile::SetSkipUnreadyPipelines(g_skipUnreadyPipelines); } + if (ImGui::Checkbox("VSync", &g_vsync)) { + aurora_enable_vsync(g_vsync); + RuntimeConfigFile::SetVsync(g_vsync); + } if (ImGui::Checkbox("Show FPS", &g_showFps)) { RuntimeConfigFile::SetShowFps(g_showFps); } @@ -1169,7 +1204,12 @@ void DrawGraphicsSettings() { void DrawFpsOverlay() { AuroraPresentTiming presentTiming{}; aurora_get_present_timing(&presentTiming); - if (!g_showFps) { + const uint32_t targetFps = kFrameInterpolationTargetFps[static_cast(g_frameInterpolationMode)]; + const double refreshRate = aurora_get_display_refresh_rate(); + const bool interpolationInactive = targetFps > 60 && !aurora_display_shows_interpolation(); + const bool unevenPacing = + !g_vsync && !interpolationInactive && refreshRate > 0.0 && targetFps > refreshRate + 1.0; + if (!g_showFps && !unevenPacing && !interpolationInactive) { return; } @@ -1186,9 +1226,9 @@ void DrawFpsOverlay() { ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoSavedSettings; if (ImGui::Begin("FPS Overlay", nullptr, kFlags)) { - if (presentTiming.sampleCount == 0) { + if (g_showFps && presentTiming.sampleCount == 0) { ImGui::TextUnformatted("FPS: --"); - } else { + } else if (g_showFps) { // Present timing includes the additional frames produced by // interpolation, so this remains the actual displayed FPS. ImGui::Text("FPS: %.1f", presentTiming.framesPerSecond); @@ -1201,6 +1241,17 @@ void DrawFpsOverlay() { presentTiming.effectiveFramesPerSecond); } } + if (interpolationInactive) { + ImGui::TextColored(ImVec4(1.0f, 0.75f, 0.25f, 1.0f), + "%u FPS interpolation has no effect on a %.0f Hz display.", targetFps, + refreshRate); + } + if (unevenPacing) { + ImGui::TextColored(ImVec4(1.0f, 0.75f, 0.25f, 1.0f), + "%u FPS interpolation on a %.0f Hz display without VSync is not smooth.\n" + "Enable VSync for smooth motion.", + targetFps, refreshRate); + } } ImGui::End(); } @@ -1257,6 +1308,7 @@ void DrawStartupScreen() { const float startY = std::max(0.0f, (viewport->Size.y - titleSize.y) * 0.5f); ImGui::SetCursorPos(ImVec2(titleX, startY)); ImGui::TextUnformatted(kTitle); + float nextY = startY + titleSize.y + 12.0f; if (g_bootShaderNotice && !g_bootShadersReady.load(std::memory_order_relaxed)) { ImGui::SetWindowFontScale(0.9f); char line[96]; @@ -1265,7 +1317,13 @@ void DrawStartupScreen() { const float lineX = std::max(0.0f, (viewport->Size.x - ImGui::CalcTextSize(line).x) * 0.5f); ImGui::SetCursorPos(ImVec2(lineX, startY + titleSize.y * 1.8f)); ImGui::TextUnformatted(line); + nextY = ImGui::GetCursorPosY() + 4.0f; } + constexpr const char* kHint = "Press F10 to open settings"; + ImGui::SetWindowFontScale(0.8f); + const ImVec2 hintSize = ImGui::CalcTextSize(kHint); + ImGui::SetCursorPos(ImVec2(std::max(0.0f, (viewport->Size.x - hintSize.x) * 0.5f), nextY)); + ImGui::TextUnformatted(kHint); } ImGui::End(); ImGui::PopStyleVar(); @@ -1352,6 +1410,7 @@ void DrawTopBar() { ImGui::EndMenu(); } + ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, 0.0f), ImVec2(FLT_MAX, viewport->Size.y * 0.75f)); if (ImGui::BeginMenu("Controller settings")) { DrawControllerSettings(); // Nest capture under this menu so opening/closing the modal preserves @@ -1532,6 +1591,7 @@ void ReleaseControllers() noexcept { constexpr std::array stopAll{ PAD_MOTOR_STOP_HARD, PAD_MOTOR_STOP_HARD, PAD_MOTOR_STOP_HARD, PAD_MOTOR_STOP_HARD}; PADControlAllMotors(stopAll.data()); + Wiimote::Shutdown(); // SDL hands LED and rumble reports to its own HIDAPI sender thread rather // than writing them here, so without this the process dies before the // controller ever receives them. @@ -1539,14 +1599,7 @@ void ReleaseControllers() noexcept { } void Draw() noexcept { - // Wait for the frame worker's DONE phase: it has replayed the previous frame's ImGui draw lists - // and started the next ImGui frame, so all overlay callers can now safely issue ImGui commands. - aurora_wait_for_frame_worker(); - // Also drive the Wii Remote rescan from here: PADRead runs it too, but this - // runs once per presented frame whatever the game is doing (e.g. sitting in - // its "communications interrupted" prompt without polling pads). Same guest - // thread as PADRead, so no concurrent access to the scanner's state. - WiiRemoteInput::Poll(); + // ImGui is only touched on this thread; the render worker replays a frozen copy. ApplyConfiguredMappings(); PersistDisplayModeIfChanged(); UpdateCursorAutoHide(); diff --git a/runtime/src/system_bridge.cpp b/runtime/src/system_bridge.cpp index c67eb8a..99f2abd 100644 --- a/runtime/src/system_bridge.cpp +++ b/runtime/src/system_bridge.cpp @@ -334,8 +334,8 @@ void SystemBridge::Initialize() { // These set up vtables and other critical infrastructure RT_LOG(RT_TAG_RUNTIME) << "Running static constructors for main DOL..." << std::endl; - const uint32_t dolCtorStart = 0x80244DE0; - const uint32_t dolCtorEnd = 0x80244EA0; + const uint32_t dolCtorStart = MKW_GADDR(80244DE0); + const uint32_t dolCtorEnd = MKW_GADDR(80244EA0); int dolCount = 0; for (uint32_t addr = dolCtorStart; addr < dolCtorEnd; addr += 4) { @@ -374,8 +374,8 @@ void SystemBridge::Initialize() { RT_LOG(RT_TAG_RUNTIME) << "Running static constructors for StaticR.rel..." << std::endl; // Define range for StaticR.rel .ctors - const uint32_t ctorStart = 0x8088f400; - const uint32_t ctorEnd = 0x8088f704; + const uint32_t ctorStart = MKW_GADDR(8088f400); + const uint32_t ctorEnd = MKW_GADDR(8088f704); int count = 0; for (uint32_t addr = ctorStart; addr < ctorEnd; addr += 4) { @@ -413,14 +413,18 @@ void SystemBridge::Initialize() { } void SystemBridge::WriteGuestMemorySnapshot(std::ostream& os, const std::filesystem::path& mem1Path) { + auto writeRegion = [&](const char* label, uint32_t base, uint32_t size, + const std::filesystem::path& path) { + std::ofstream dump(path, std::ios::binary | std::ios::trunc); + dump.write(reinterpret_cast(Memory::GetPointer(base, size)), size); + os << "[runtime] " << label << " snapshot written to " << RuntimeConfigFile::PathToUtf8(path) + << (dump.good() ? "" : " (write failed)") << std::endl; + }; + constexpr uint32_t kMem1Base = 0x80000000u; constexpr uint32_t kMem1Size = 0x01800000u; if (Memory::Contains(kMem1Base, kMem1Size)) { - std::ofstream dump(mem1Path, std::ios::binary | std::ios::trunc); - dump.write(reinterpret_cast(Memory::GetPointer(kMem1Base, kMem1Size)), - kMem1Size); - os << "[runtime] MEM1 snapshot written to " << RuntimeConfigFile::PathToUtf8(mem1Path) - << (dump.good() ? "" : " (write failed)") << std::endl; + writeRegion("MEM1", kMem1Base, kMem1Size, mem1Path); } constexpr uint32_t kMem2Base = 0x90000000u; for (uint32_t mem2Size : {0x08000000u, 0x04000000u}) { @@ -429,13 +433,16 @@ void SystemBridge::WriteGuestMemorySnapshot(std::ostream& os, const std::filesys } std::filesystem::path mem2Path = mem1Path; mem2Path += ".mem2"; - std::ofstream dump(mem2Path, std::ios::binary | std::ios::trunc); - dump.write(reinterpret_cast(Memory::GetPointer(kMem2Base, mem2Size)), - mem2Size); - os << "[runtime] MEM2 snapshot written to " << RuntimeConfigFile::PathToUtf8(mem2Path) - << (dump.good() ? "" : " (write failed)") << std::endl; + writeRegion("MEM2", kMem2Base, mem2Size, mem2Path); break; } + constexpr uint32_t kKamekBase = 0x81800000u; + constexpr uint32_t kKamekSize = 0x00200000u; + if (Memory::Contains(kKamekBase, kKamekSize)) { + std::filesystem::path kamekPath = mem1Path; + kamekPath += ".kamek"; + writeRegion("Kamek overlay", kKamekBase, kKamekSize, kamekPath); + } } void SystemBridge::DumpCrashHeuristics(std::ostream& os, const CpuContext* cpu, @@ -484,7 +491,7 @@ void SystemBridge::SeedLowMemDefaults(const Memory::Config& config) { }; std::vector entries; - constexpr uint32_t kMem1ArenaLoDefault = 0x80399180u; + const uint32_t kMem1ArenaLoDefault = ::GuestRegion::CurrentFacts().mem1ArenaLo; uint32_t mem1ArenaHiDefault = 0x817f0520u; constexpr uint32_t kBusClockHz = static_cast(TimeBaseContract::kBusClockHz); @@ -508,10 +515,10 @@ void SystemBridge::SeedLowMemDefaults(const Memory::Config& config) { // Retro Rewind reads the region byte directly from here while building its // Retro-WFC payload URL, and OSGetAppGamename reads the app code mirrors // at 0x80003180/0x80003194 while building NAS auth fields. - entries.push_back({0x80000000u, 0x524D4350u, "Disc game code"}); // RMCP + entries.push_back({0x80000000u, ::GuestRegion::CurrentFacts().gameCode, "Disc game code"}); entries.push_back({0x80000004u, 0x30310100u, "Disc maker/id"}); // 01 + disc 1 - entries.push_back({0x80003180u, 0x524D4350u, "OS app game code"}); // RMCP - entries.push_back({0x80003194u, 0x524D4350u, "OS app gamename"}); // RMCP + entries.push_back({0x80003180u, ::GuestRegion::CurrentFacts().gameCode, "OS app game code"}); + entries.push_back({0x80003194u, ::GuestRegion::CurrentFacts().gameCode, "OS app gamename"}); if (RuntimeProduct::IsRetroRewind()) { entries.push_back({0x800017D8u, 0x00000001u, "Retro Rewind recomp runtime marker", true}); } diff --git a/runtime/src/wii_remote_input.cpp b/runtime/src/wii_remote_input.cpp deleted file mode 100644 index a219c40..0000000 --- a/runtime/src/wii_remote_input.cpp +++ /dev/null @@ -1,1069 +0,0 @@ -#include "wii_remote_input.h" - -#include "runtime_config.h" -#include "runtime_log.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace WiiRemoteInput { -namespace { - -// Dolphin's continuous scanning polls Bluetooth about once a second; SDL's -// enumeration walks every HID device on the main thread, so stay a bit lazier. -constexpr uint64_t kScanIntervalMs = 2000; -// Right after a remote drops it is almost certainly still there, but the first -// re-open attempts tend to fail on timed-out reads, so retry quickly for a while. -constexpr uint64_t kFastScanIntervalMs = 500; -constexpr uint64_t kFastScanWindowMs = 15000; -// How long the Wii driver hint stays at "0" during a rescan; SDL applies hint -// changes on its next joystick update, once per pumped frame. -constexpr uint64_t kRescanDriverOffMs = 100; - -constexpr float kStandardGravity = 9.80665f; - -// SDL's Wii driver posts the remote's own buttons as raw joystick buttons -// starting at SDL_GAMEPAD_BUTTON_MISC1, in this order (SDL_hidapi_wii.c, -// EWiiButtons), whatever the extension. -enum RawWiiButton : int { - kRawA = SDL_GAMEPAD_BUTTON_MISC1, - kRawB, - kRawOne, - kRawTwo, - kRawPlus, - kRawMinus, - kRawHome, - kRawDpadUp, - kRawDpadDown, - kRawDpadLeft, - kRawDpadRight, -}; - -// WPAD_BUTTON_* bits as the game reads them from KPADStatus.hold. -constexpr uint32_t kWpadLeft = 0x0001, kWpadRight = 0x0002, kWpadDown = 0x0004, kWpadUp = 0x0008, - kWpadPlus = 0x0010, kWpadTwo = 0x0100, kWpadOne = 0x0200, kWpadB = 0x0400, kWpadA = 0x0800, - kWpadMinus = 0x1000, kWpadZ = 0x2000, kWpadC = 0x4000, kWpadHome = 0x8000; - -// WPAD_CL_BUTTON_* bits (WPADCLStatus.clButton / KPADStatus.ex_status.cl.hold): -// the Classic Controller's two button bytes, inverted, high byte first. -constexpr uint32_t kClUp = 0x0001, kClLeft = 0x0002, kClZR = 0x0004, kClX = 0x0008, kClA = 0x0010, kClY = 0x0020, - kClB = 0x0040, kClZL = 0x0080, kClR = 0x0200, kClPlus = 0x0400, kClHome = 0x0800, - kClMinus = 0x1000, kClL = 0x2000, kClDown = 0x4000, kClRight = 0x8000; - -constexpr Uint16 kNintendoVendor = 0x057e; - -// How long a vanished remote keeps its channel alive with neutral input. SDL's -// in-place reconnect after an extension change takes well under a second; a -// remote that is really gone shows up as disconnected after this. -constexpr uint64_t kExtensionSwapGraceMs = 3000; -// Rescanning closes and re-opens the Bluetooth HID handle, which some Windows -// stacks answer by dropping the link; leave SDL's own reconnect this long first. -constexpr uint64_t kScanStartDelayMs = 3000; - -// Per-port memory of the last Wii controller seen there, for EffectiveKind. -struct PortMemory { - Kind lastKind = Kind::NotWii; - uint64_t lastSeenMs = 0; -}; -std::array g_ports{}; - -bool g_wiiDriverEnabled = false; -uint64_t g_lastScanMs = 0; -uint32_t g_scanCount = 0; -bool g_scanning = false; -// Non-zero while a rescan has the Wii driver hint switched off (see RescanNow). -uint64_t g_driverOffSinceMs = 0; -// When the current scan started (last Wii controller seen). -uint64_t g_lostAtMs = 0; -bool g_hidrawWarned = false; - -// Instance ids whose accelerometers have been switched on. SDL keeps sensors -// off until asked and forgets that when the gamepad is closed, so a re-paired -// remote gets a fresh id and is enabled again. -std::array g_sensorsEnabledFor{}; - -// Zero-point correction subtracted from a remote's accelerometer, in g and in -// SDL's sensor frame, with the config key it is stored under. Resolved once per -// gamepad instance (a re-created joystick of the same remote resolves to the same -// key) and replaced by a calibration run. The Nunchuk accelerometer is left -// uncorrected. -struct RemoteCalibration { - SDL_JoystickID instance = 0; - std::string key; - std::array offset{}; -}; -std::array g_remoteCalibration{}; - -// Frames sampled by a calibration run (about 1.5 s at 60 Hz) and how far a -// sample may stray from the first one before the run is declared "moved". -constexpr int kCalibrationSamples = 90; -constexpr float kCalibrationMaxDeviationG = 0.15f; -// A resting remote reads about 1 g and lies within 20 degrees of face up. -constexpr double kCalibrationMinGravityG = 0.8; -constexpr double kCalibrationMaxGravityG = 1.2; -constexpr double kCalibrationMinTiltCosine = 0.9396926; - -struct AccelCalibration { - bool active = false; - uint32_t chan = 0; - SDL_JoystickID instance = 0; - int count = 0; - double sum[3] = {}; - float first[3] = {}; -}; -AccelCalibration g_calibration; -char g_calibrationMessage[160] = {}; -uint32_t g_calibrationMessageChan = 0; -SDL_JoystickID g_calibrationMessageRemote = 0; - -// Last accepted KPAD acc per port, for the remote and for the Nunchuk. Reused on -// frames that bring no sample or a glitched one, so the game never sees a jump. -struct LastAcc { - bool valid = false; - float acc[3] = {0.0f, -1.0f, 0.0f}; -}; -std::array g_lastAcc{}; -std::array g_lastNunchukAcc{}; - -// A zeroed remote report decodes to minus its zero-g point, at least this far out on every axis. -constexpr float kZeroReportMinG = 4.0f; - -// Case-sensitive substring test that tolerates a null name. -bool NameContains(const char* name, const char* needle) { - return name != nullptr && std::strstr(name, needle) != nullptr; -} - -// Turns on the remote (and Nunchuk) accelerometers once per gamepad instance. -void EnsureSensors(SDL_Gamepad* gamepad, uint32_t port) { - const SDL_JoystickID id = SDL_GetGamepadID(gamepad); - if (g_sensorsEnabledFor[port] == id) { - return; - } - bool allEnabled = true; - for (SDL_SensorType sensor : {SDL_SENSOR_ACCEL, SDL_SENSOR_ACCEL_L}) { - if (SDL_GamepadHasSensor(gamepad, sensor) && !SDL_SetGamepadSensorEnabled(gamepad, sensor, true)) { - RT_LOG(RT_TAG_CONFIG) << "Wii Remote on port " << (port + 1) - << ": could not enable an accelerometer: " << SDL_GetError() << std::endl; - allEnabled = false; - } - } - // Only remember the instance once every sensor is on, so a failed attempt - // is retried on the next sample instead of leaving the accelerometer off. - if (allEnabled) { - g_sensorsEnabledFor[port] = id; - } -} - -// USB interface number of the HID device at `path`, or -1 when it is not a USB -// interface or cannot be found. A DolphinBar shows each remote slot as one. -int UsbInterfaceForPath(const char* path, Uint16 vendor, Uint16 product) { - if (path == nullptr) { - return -1; - } - int interfaceNumber = -1; - SDL_hid_device_info* list = SDL_hid_enumerate(vendor, product); - for (const SDL_hid_device_info* info = list; info != nullptr; info = info->next) { - if (info->path != nullptr && std::strcmp(info->path, path) == 0) { - interfaceNumber = info->interface_number; - break; - } - } - SDL_hid_free_enumeration(list); - return interfaceNumber; -} - -// Config key identifying the physical remote behind a gamepad: its HID serial -// (the Bluetooth address when paired directly), else its USB interface number -// (a DolphinBar has no serial and one interface per remote slot) and the game -// port, else the game port. Only characters valid in a bare TOML key. -std::string RemoteKey(SDL_Gamepad* gamepad, uint32_t port) { - std::string serial; - if (const char* raw = SDL_GetGamepadSerial(gamepad)) { - for (const char* c = raw; *c != '\0'; ++c) { - if (std::isalnum(static_cast(*c))) { - serial += static_cast(std::tolower(static_cast(*c))); - } - } - } - if (serial.find_first_not_of('0') != std::string::npos) { - return "serial_" + serial; - } - const Uint16 vendor = SDL_GetGamepadVendor(gamepad); - const Uint16 product = SDL_GetGamepadProduct(gamepad); - const int interfaceNumber = UsbInterfaceForPath(SDL_GetGamepadPath(gamepad), vendor, product); - char key[48]; - if (interfaceNumber >= 0) { - std::snprintf(key, sizeof(key), "usb_%04x_%04x_if%d_port%u", vendor, product, interfaceNumber, - port + 1); - } else { - std::snprintf(key, sizeof(key), "port_%u", port + 1); - } - return key; -} - -// Calibration of the remote currently on `port`, resolved on first use per gamepad -// instance. A remote without a stored entry has a zero offset. -RemoteCalibration& CalibrationFor(SDL_Gamepad* gamepad, uint32_t port) { - RemoteCalibration& calibration = g_remoteCalibration[port]; - const SDL_JoystickID id = SDL_GetGamepadID(gamepad); - if (calibration.instance != id) { - static bool s_legacyReported = false; - if (!s_legacyReported && RuntimeConfigFile::Get().hasLegacyWiiAccelOffset) { - s_legacyReported = true; - RT_LOG(RT_TAG_CONFIG) << "Old shared Wii Remote calibration ignored; recalibrate each remote in F10" - << std::endl; - } - calibration.instance = id; - calibration.key = RemoteKey(gamepad, port); - const std::optional> stored = RuntimeConfigFile::WiiAccelOffsetFor(calibration.key); - for (size_t i = 0; i < 3; ++i) calibration.offset[i] = stored ? static_cast((*stored)[i]) : 0.0f; - RT_LOG(RT_TAG_CONFIG) << "Wii Remote on port " << (port + 1) << ": calibration key " << calibration.key - << (stored ? "" : " (no stored offset)") << std::endl; - } - return calibration; -} - -// Raw SDL sample in m/s^2, rejecting anything SDL has not delivered yet. -bool ReadSdlAccel(SDL_Gamepad* gamepad, SDL_SensorType sensor, float* sdl) { - return SDL_GamepadSensorEnabled(gamepad, sensor) && SDL_GetGamepadSensorData(gamepad, sensor, sdl, 3) && - std::isfinite(sdl[0]) && std::isfinite(sdl[1]) && std::isfinite(sdl[2]); -} - -// True for a sample that cannot have come from the sensor. Over Bluetooth on -// Windows the remote delivers, a few times a minute, a report whose -// accelerometer bytes are all zero; SDL decodes that as (+a, -b, -c) g with -// a, b, c the zero-g point over the units per g of each axis: about 5 g for the -// remote (factory calibration) and exactly 2.56 g for the Nunchuk (200 units/g). -// Handed to the game as is, one such frame is a full-lock steer plus a 9 g -// "shake". Single axes past 4 g are real readings of a hard shake. `g` is the -// uncorrected SDL sample. -bool IsGlitchedSample(SDL_SensorType sensor, const float* g) { - // An exact zero vector is SDL's sensor buffer before the first report, not - // a reading (the remote never delivers 0 g on all three axes at once). - if (g[0] == 0.0f && g[1] == 0.0f && g[2] == 0.0f) { - return true; - } - if (sensor == SDL_SENSOR_ACCEL) { - return g[0] > kZeroReportMinG && g[1] < -kZeroReportMinG && g[2] < -kZeroReportMinG; - } - constexpr float zero = 2.56f; - return std::fabs(g[0] - zero) < 0.03f && std::fabs(g[1] + zero) < 0.03f && std::fabs(g[2] + zero) < 0.03f; -} - -// One accelerometer sample in g, SDL's sensor frame. The remote's own axes are -// +x left, +y towards the user, +z out of the button face (wiibrew, Dolphin); -// SDL_hidapi_wii.c posts (-wiiX, wiiZ, wiiY): x right across the face, y out of -// the face (+1 at rest, buttons up), z towards the user, i.e. away from the tip. -// The remote's sample gets the zero-point correction of the remote on `port`; the -// Nunchuk's does not. False when there is no sample yet or the sample is a glitch -// (see above). -bool ReadAccelG(SDL_Gamepad* gamepad, uint32_t port, SDL_SensorType sensor, float* g) { - float sdl[3] = {}; - if (!ReadSdlAccel(gamepad, sensor, sdl)) { - return false; - } - for (int i = 0; i < 3; ++i) g[i] = sdl[i] / kStandardGravity; - if (IsGlitchedSample(sensor, g)) { - return false; - } - if (sensor == SDL_SENSOR_ACCEL) { - const std::array& offset = CalibrationFor(gamepad, port).offset; - for (int i = 0; i < 3; ++i) g[i] -= offset[i]; - } - return true; -} - -// KPAD's acc is the remote reading as (-wiiX, -wiiZ, wiiY): x right across the -// face, y through the back of the remote (rest: -1 with the buttons up), z -// towards the user. That is SDL's frame with y negated. Held sideways as a -// wheel the rest vector is (1, 0, 0) and a turn shows up as z = sin(angle), so -// the sign of z is the direction of the turn; Cemu does the same conversion for -// real remotes on the Wii U. -void AccelGToKpad(const float* g, float* kpad) { - kpad[0] = g[0]; - kpad[1] = -g[1]; - kpad[2] = g[2]; -} - -// Sensor -> KPAD acc for ReadKpadSample. -bool ReadAccelAsKpad(SDL_Gamepad* gamepad, uint32_t port, SDL_SensorType sensor, float* kpad) { - float g[3] = {}; - if (!ReadAccelG(gamepad, port, sensor, g)) { - return false; - } - AccelGToKpad(g, kpad); - return true; -} - -// Debug trace of every remote sample (controller.wii_accel_trace = true): -// milliseconds, port, WPAD hold bits, the uncorrected SDL sample in g and the -// KPAD acc handed to the game. One CSV per run, truncated at startup. -void TraceSample(uint32_t chan, const KpadSample& sample, const float* rawG, bool haveRaw, bool accepted) { - static std::ofstream trace; - static bool opened = false; - if (!opened) { - opened = true; - const std::filesystem::path path = RuntimeConfigFile::ApplicationDataDirectory() / "wii_accel_trace.csv"; - trace.open(path, std::ios::trunc); - if (trace) { - trace << "ms,port,hold,raw_x,raw_y,raw_z,ok,kpad_x,kpad_y,kpad_z\n"; - RT_LOG(RT_TAG_CONFIG) << "Wii Remote accelerometer trace: " << path.string() << std::endl; - } else { - RT_LOG(RT_TAG_CONFIG) << "Wii Remote accelerometer trace: could not open " << path.string() << std::endl; - } - } - if (!trace) { - return; - } - char line[192]; - if (haveRaw) { - std::snprintf(line, sizeof(line), "%llu,%u,%04x,%.4f,%.4f,%.4f,%d,%.4f,%.4f,%.4f\n", - static_cast(SDL_GetTicks()), chan + 1, sample.hold, rawG[0], rawG[1], - rawG[2], accepted ? 1 : 0, sample.acc[0], sample.acc[1], sample.acc[2]); - } else { - std::snprintf(line, sizeof(line), "%llu,%u,%04x,,,,0,%.4f,%.4f,%.4f\n", - static_cast(SDL_GetTicks()), chan + 1, sample.hold, sample.acc[0], - sample.acc[1], sample.acc[2]); - } - trace << line; - // A frame per line; flush so a crash or a killed process keeps the tail. - trace.flush(); -} - -// Gamepad of the Wii Remote on `chan`, or nullptr. -SDL_Gamepad* RemoteGamepad(uint32_t chan) { - if (chan >= PAD_MAX_CONTROLLERS || !IsRemoteChannel(chan)) { - return nullptr; - } - return SDL_GetGamepadFromPlayerIndex(static_cast(chan)); -} - -void SetCalibrationMessage(uint32_t chan, const char* message) { - SDL_Gamepad* gamepad = RemoteGamepad(chan); - g_calibrationMessageChan = chan; - g_calibrationMessageRemote = gamepad != nullptr ? SDL_GetGamepadID(gamepad) : 0; - std::snprintf(g_calibrationMessage, sizeof(g_calibrationMessage), "%s", message); -} - -// Ends a calibration run with a message for the overlay. -void FinishAccelCalibration(uint32_t chan, const char* message) { - g_calibration.active = false; - SetCalibrationMessage(chan, message); - RT_LOG(RT_TAG_CONFIG) << "Wii Remote accelerometer calibration: " << message << std::endl; -} - -// One frame of a calibration run: accumulates the uncorrected sample and, once -// enough frames are in, stores the mean minus the ideal rest vector (0, 1, 0). -void StepAccelCalibration() { - if (!g_calibration.active) { - return; - } - SDL_Gamepad* gamepad = RemoteGamepad(g_calibration.chan); - if (gamepad == nullptr || - SDL_GetGamepadID(gamepad) != g_calibration.instance) { - FinishAccelCalibration(g_calibration.chan, "Cancelled: the Wii Remote went away."); - return; - } - EnsureSensors(gamepad, g_calibration.chan); - float sdl[3] = {}; - if (!ReadSdlAccel(gamepad, SDL_SENSOR_ACCEL, sdl)) { - return; // no sample this frame; keep waiting - } - float g[3]; - for (int i = 0; i < 3; ++i) g[i] = sdl[i] / kStandardGravity; - if (IsGlitchedSample(SDL_SENSOR_ACCEL, g)) { - return; // a zeroed report, not a movement - } - if (g_calibration.count == 0) { - for (int i = 0; i < 3; ++i) g_calibration.first[i] = g[i]; - } else { - for (int i = 0; i < 3; ++i) { - if (std::fabs(g[i] - g_calibration.first[i]) > kCalibrationMaxDeviationG) { - FinishAccelCalibration(g_calibration.chan, "Failed: the remote moved. Put it down, buttons up, and try again."); - return; - } - } - } - for (int i = 0; i < 3; ++i) g_calibration.sum[i] += g[i]; - if (++g_calibration.count < kCalibrationSamples) { - return; - } - std::array mean{}; - for (int i = 0; i < 3; ++i) mean[i] = g_calibration.sum[i] / g_calibration.count; - const double length = std::sqrt(mean[0] * mean[0] + mean[1] * mean[1] + mean[2] * mean[2]); - if (length < kCalibrationMinGravityG || length > kCalibrationMaxGravityG || - mean[1] / length < kCalibrationMinTiltCosine) { - FinishAccelCalibration(g_calibration.chan, "Failed: the remote was not resting flat with the buttons up."); - return; - } - const std::array offset = {mean[0], mean[1] - 1.0, mean[2]}; - RemoteCalibration& calibration = CalibrationFor(gamepad, g_calibration.chan); - for (int i = 0; i < 3; ++i) calibration.offset[i] = static_cast(offset[i]); - const bool saved = RuntimeConfigFile::SetWiiAccelOffsetFor(calibration.key, offset); - char message[160]; - std::snprintf(message, sizeof(message), "%s offset x %+.3f y %+.3f z %+.3f g", - saved ? "Calibrated:" : "Calibrated (could not write Config.toml):", offset[0], offset[1], - offset[2]); - FinishAccelCalibration(g_calibration.chan, message); -} - -// True when any controller aurora knows about is a Wii device. -bool AnyWiiControllerConnected() { - const uint32_t count = PADCount(); - for (uint32_t index = 0; index < count; ++index) { - if (KindForName(PADGetNameForControllerIndex(index)) != Kind::NotWii) { - return true; - } - } - return false; -} - -// True for an evdev node served by the kernel hid-wiimote driver. -bool IsKernelWiiNode(SDL_JoystickID id) { - const char* path = SDL_GetGamepadPathForID(id); - return SDL_GetGamepadVendorForID(id) == kNintendoVendor && path != nullptr && - std::strncmp(path, "/dev/input/", 11) == 0; -} - -bool IsClassicNodeName(const char* name) { - return NameContains(name, "Classic Controller"); -} - -// HID device behind a kernel evdev node; the remote and its extension nodes share it. -std::string KernelParent(SDL_JoystickID id) { - static std::unordered_map s_parents; - if (const auto it = s_parents.find(id); it != s_parents.end()) { - return it->second; - } - const char* path = SDL_GetGamepadPathForID(id); - if (path == nullptr) { - return {}; - } - std::error_code ec; - const auto parent = std::filesystem::canonical( - std::filesystem::path("/sys/class/input") / std::filesystem::path(path).filename() / "device" / "device", ec); - if (ec) { - return {}; - } - return s_parents.emplace(id, parent.string()).first->second; -} - -// The kernel node on the same remote as `gamepad`: its Classic Controller node -// when `wantClassic`, else its remote node. -SDL_Gamepad* KernelSibling(SDL_Gamepad* gamepad, bool wantClassic) { - const SDL_JoystickID self = SDL_GetGamepadID(gamepad); - const std::string parent = KernelParent(self); - if (parent.empty()) { - return nullptr; - } - int count = 0; - SDL_JoystickID* ids = SDL_GetGamepads(&count); - if (ids == nullptr) { - return nullptr; - } - SDL_Gamepad* sibling = nullptr; - for (int i = 0; i < count && sibling == nullptr; ++i) { - if (ids[i] != self && IsKernelWiiNode(ids[i]) && - IsClassicNodeName(SDL_GetGamepadNameForID(ids[i])) == wantClassic && KernelParent(ids[i]) == parent) { - sibling = SDL_GetGamepadFromID(ids[i]); - } - } - SDL_free(ids); - return sibling; -} - -// The kernel exposes a remote and its Classic Controller as separate gamepads. -// The remote's port reads both, as on a Wii; the Classic node's own port stays empty. -Kind KindForGamepad(SDL_Gamepad* gamepad) { - if (gamepad == nullptr) { - return Kind::NotWii; - } - const char* name = SDL_GetGamepadName(gamepad); - const Kind kind = KindForName(name); - if ((kind != Kind::Remote && kind != Kind::RemoteWithClassic) || !IsKernelWiiNode(SDL_GetGamepadID(gamepad))) { - return kind; - } - if (IsClassicNodeName(name)) { - return KernelSibling(gamepad, false) != nullptr ? Kind::NotWii : kind; - } - return KernelSibling(gamepad, true) != nullptr ? Kind::RemoteWithClassic : kind; -} - -// A kernel Classic Controller node whose remote node carries it. -bool IsCarriedKernelNode(SDL_Gamepad* gamepad) { - return gamepad != nullptr && IsKernelWiiNode(SDL_GetGamepadID(gamepad)) && - IsClassicNodeName(SDL_GetGamepadName(gamepad)) && KernelSibling(gamepad, false) != nullptr; -} - -// Logs once when the kernel driver serves a Wii controller SDL's driver could have had. -void WarnIfKernelDriverServing() { - if (g_hidrawWarned || !g_wiiDriverEnabled) { - return; - } - const uint64_t now = SDL_GetTicks(); - static uint64_t s_nextCheckMs = 0; - if (now < s_nextCheckMs) { - return; - } - s_nextCheckMs = now + 2000; - int count = 0; - SDL_JoystickID* ids = SDL_GetGamepads(&count); - if (ids == nullptr) { - return; - } - for (int i = 0; i < count && !g_hidrawWarned; ++i) { - const Uint16 product = SDL_GetGamepadProductForID(ids[i]); - if ((product == 0x0306 || product == 0x0330) && IsKernelWiiNode(ids[i])) { - g_hidrawWarned = true; - RT_LOG(RT_TAG_CONFIG) << "A Wii controller is served by the kernel hid-wiimote driver. For full Wii " - << "Remote support see the Linux udev rule in the README." << std::endl; - } - } - SDL_free(ids); -} - -// Route SDL's input diagnostics (HIDAPI open failures, the Wii driver's -// extension/status messages) into console.log, minus the periodic chatter. -// A sub-warning message is written once: SDL repeats the same line on every -// enumeration (one "couldn't open /dev/hidraw7: Permission denied" per HID -// device per pass), and console.log is unbuffered, so the repeats were a -// per-pass burst of writes on the main thread for no new information. -void SDLCALL LogSdlMessage(void*, int category, SDL_LogPriority priority, const char* message) { - if (message == nullptr) { - return; - } - if (category == SDL_LOG_CATEGORY_INPUT && priority < SDL_LOG_PRIORITY_WARN && - (std::strstr(message, "Motion Plus") != nullptr || std::strstr(message, "Resetting report mode") != nullptr)) { - return; - } - if (category != SDL_LOG_CATEGORY_INPUT && priority < SDL_LOG_PRIORITY_WARN) { - return; - } - if (priority < SDL_LOG_PRIORITY_WARN) { - // Device paths in these messages keep changing (/dev/hidrawN climbs with - // hotplug churn), so cap the set instead of holding one string per line - // for the whole session. - static std::unordered_set s_seen; - if (s_seen.size() >= 256) { - s_seen.clear(); - } - if (!s_seen.insert(message).second) { - return; - } - RT_LOG("sdl") << message << " (further identical messages suppressed)" << std::endl; - return; - } - RT_LOG("sdl") << message << std::endl; -} - -// Whether Poll() drives its own periodic re-enumeration. The 1->0->1 hint -// flip below makes SDL close and re-open every HIDAPI device on the main -// thread, and on Linux that means an open() attempt on every /dev/hidraw node -// (each failing with EACCES until a udev rule grants access), which showed up -// as a frame hitch every scan interval even on an empty menu. It exists for -// Windows Bluetooth stacks, where a remote that drops or is switched on after -// launch is not seen again until the driver re-enumerates. Linux and macOS -// already get hotplug from udev / IOKit: SDL re-enumerates when a device -// appears, so nothing periodic is needed there. The overlay's "Rescan now" -// still works everywhere. -#if defined(_WIN32) -constexpr bool kPeriodicRescan = true; -#else -constexpr bool kPeriodicRescan = false; -#endif - -// Second half of a rescan: re-enables the Wii driver once SDL has seen it off. -void FinishRescan(uint64_t now) { - if (g_driverOffSinceMs == 0 || now - g_driverOffSinceMs < kRescanDriverOffMs) { - return; - } - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_WII, "1"); - g_driverOffSinceMs = 0; - g_lastScanMs = now; - ++g_scanCount; - // The first few and then every tenth, so a remote that never comes back - // leaves a trail in console.log without flooding it. - if (g_scanCount <= 3 || g_scanCount % 10 == 0) { - RT_LOG(RT_TAG_CONFIG) << "Wii Remote rescan #" << g_scanCount << ": HIDAPI Wii driver re-enabled (" - << PADCount() << " controller(s) known to aurora)" << std::endl; - } -} - -} // namespace - -// Enables SDL's HIDAPI Wii driver and player LEDs, and routes SDL's input log. -void ConfigureSdlHints(bool enabled) { - // A rescan may be mid-flight; drop its bookkeeping so Poll() is not left - // waiting for a FinishRescan() that can no longer happen. - g_driverOffSinceMs = 0; - if (!SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_WII, enabled ? "1" : "0")) { - RT_LOG(RT_TAG_CONFIG) << "Failed to set " << SDL_HINT_JOYSTICK_HIDAPI_WII << ": " << SDL_GetError() - << std::endl; - } - // Light the player LED that matches the SDL player index, like the console does. - if (!SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_WII_PLAYER_LED, "1")) { - RT_LOG(RT_TAG_CONFIG) << "Failed to set " << SDL_HINT_JOYSTICK_HIDAPI_WII_PLAYER_LED << ": " - << SDL_GetError() << std::endl; - } - RT_LOG(RT_TAG_CONFIG) << "Bluetooth Wii Remote support " << (enabled ? "enabled" : "disabled") << std::endl; - g_wiiDriverEnabled = enabled; - if (enabled) { - SDL_SetLogPriority(SDL_LOG_CATEGORY_INPUT, SDL_LOG_PRIORITY_DEBUG); - SDL_SetLogOutputFunction(LogSdlMessage, nullptr); - } -} - -// Starts a rescan by disabling the Wii driver hint; Poll() finishes it. -void RescanNow() { - if (!g_wiiDriverEnabled || g_driverOffSinceMs != 0) { - return; - } - // SDL only closes the HID handle of a remote it dropped while the Wii driver - // is disabled, and only re-opens it when the driver is enabled again; both - // must happen on separate joystick updates, so the hint stays at "0" until - // FinishRescan() a few frames later. Flipping 1->0->1 within one frame does - // nothing: SDL only ever sees the final "1". - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_WII, "0"); - g_driverOffSinceMs = SDL_GetTicks(); - if (g_scanCount < 3) { - RT_LOG(RT_TAG_CONFIG) << "Wii Remote rescan #" << (g_scanCount + 1) << ": HIDAPI Wii driver disabled" - << std::endl; - } -} - -// Per-frame scanning state machine: rescans while no Wii controller is present. -// Also advances an accelerometer calibration run, which needs a sample per frame -// whether or not the game is reading KPAD at that moment. -void Poll() { - StepAccelCalibration(); - // Remember what each port had, so EffectiveKind can bridge a swap. - for (uint32_t port = 0; port < PAD_MAX_CONTROLLERS; ++port) { - (void)EffectiveKind(port); - } - WarnIfKernelDriverServing(); - if (!g_wiiDriverEnabled) { - return; - } - // Always complete a rescan in progress so the driver is never left disabled. - FinishRescan(SDL_GetTicks()); - if (g_driverOffSinceMs != 0) { - return; - } - if (AnyWiiControllerConnected()) { - if (g_scanning) { - RT_LOG(RT_TAG_CONFIG) << "Wii Remote found after " << g_scanCount << " rescan(s)" << std::endl; - } - g_scanning = false; - g_scanCount = 0; - g_lastScanMs = SDL_GetTicks(); - return; - } - if (!RuntimeConfigFile::WiiContinuousScanEnabled(false)) { - g_scanning = false; - return; - } - const uint64_t now = SDL_GetTicks(); - if (!g_scanning) { - RT_LOG(RT_TAG_CONFIG) << "No Wii Remote connected; " - << (kPeriodicRescan ? "scanning for one" : "waiting for one to be paired") - << " (press 1+2 on the remote)" << std::endl; - g_scanning = true; - g_lostAtMs = now; - } - if (!kPeriodicRescan || now - g_lostAtMs < kScanStartDelayMs) { - return; - } - const uint64_t interval = now - g_lostAtMs < kFastScanWindowMs ? kFastScanIntervalMs : kScanIntervalMs; - if (now - g_lastScanMs < interval) { - return; - } - RescanNow(); -} - -// True while Poll() is looking for a remote. -bool IsScanning() { - return g_scanning; -} - -// Whether looking for a remote means periodic rescans or waiting for hotplug. -bool PeriodicRescanEnabled() { - return kPeriodicRescan; -} - -// Number of rescans since a Wii controller was last seen. -uint32_t ScanCount() { - return g_scanCount; -} - -// Maps the gamepad name SDL reports to a Kind: "Nintendo Wii Remote", -// "... with Nunchuk", "... with Classic Controller" and "Nintendo Wii U Pro -// Controller" from SDL's Wii driver; the Linux kernel's "Nintendo Wii Remote -// Classic Controller" is read like the Classic Controller. -Kind KindForName(const char* name) { - // The kernel's Pro Controller is a plain gamepad with a built-in SDL mapping. - if (NameContains(name, "Wii Remote Pro Controller")) return Kind::NotWii; - if (NameContains(name, "Wii U Pro Controller")) return Kind::WiiUPro; - if (!NameContains(name, "Wii Remote")) return Kind::NotWii; - if (NameContains(name, "Nunchuk")) return Kind::RemoteWithNunchuk; - if (NameContains(name, "Classic Controller")) return Kind::RemoteWithClassic; - return Kind::Remote; -} - -// Kind of the SDL gamepad assigned to a game port, NotWii when empty. -Kind KindForPort(uint32_t port) { - if (port >= PAD_MAX_CONTROLLERS) return Kind::NotWii; - SDL_Gamepad* gamepad = SDL_GetGamepadFromPlayerIndex(static_cast(port)); - return KindForGamepad(gamepad); -} - -// Human-readable name of a Kind for the settings overlay. -const char* KindLabel(Kind kind) { - switch (kind) { - case Kind::Remote: return "Wii Remote"; - case Kind::RemoteWithNunchuk: return "Wii Remote + Nunchuk"; - case Kind::RemoteWithClassic: return "Wii Remote + Classic Controller"; - case Kind::WiiUPro: return "Wii U Pro Controller"; - default: return "Not a Wii controller"; - } -} - -// True for the kinds the game reads through KPAD. -static bool IsKpadKind(Kind kind) { - return kind == Kind::Remote || kind == Kind::RemoteWithNunchuk || kind == Kind::RemoteWithClassic; -} - -// Live kind of the port, or the remembered one while a swap is in flight. -// Called from the guest thread only (PADRead, KPADRead, WPADProbe and the -// overlay's Draw all run there), so the port memory needs no locking. -Kind EffectiveKind(uint32_t chan) { - if (chan >= PAD_MAX_CONTROLLERS) return Kind::NotWii; - PortMemory& memory = g_ports[chan]; - SDL_Gamepad* gamepad = SDL_GetGamepadFromPlayerIndex(static_cast(chan)); - const Kind live = KindForGamepad(gamepad); - const uint64_t now = SDL_GetTicks(); - if (live != Kind::NotWii) { - memory.lastKind = live; - memory.lastSeenMs = now; - return live; - } - if (gamepad != nullptr) { - // Another controller took the port: the remote is not coming back here. - memory.lastKind = Kind::NotWii; - return Kind::NotWii; - } - if (IsKpadKind(memory.lastKind) && memory.lastSeenMs != 0 && now - memory.lastSeenMs < kExtensionSwapGraceMs) { - return memory.lastKind; - } - return Kind::NotWii; -} - -// True when the game reads the port through KPAD (live or bridging a swap). -bool IsRemoteChannel(uint32_t chan) { - return IsKpadKind(EffectiveKind(chan)); -} - -// Marks KPAD-served ports as "no controller" in the GameCube pad statuses. -void HideRemotesFromPad(PADStatus* statuses, uint32_t count) { - for (uint32_t port = 0; port < count && port < PAD_MAX_CONTROLLERS; ++port) { - if (IsRemoteChannel(port) || - IsCarriedKernelNode(SDL_GetGamepadFromPlayerIndex(static_cast(port)))) { - statuses[port] = {}; - statuses[port].err = PAD_ERR_NO_CONTROLLER; - } - } -} - -// Neutral sample of the remembered kind, for the frames of an extension swap. -void FillGraceSample(uint32_t chan, Kind kind, KpadSample& sample) { - sample = {}; - for (int i = 0; i < 3; ++i) sample.acc[i] = g_lastAcc[chan].acc[i]; - sample.hasNunchuk = kind == Kind::RemoteWithNunchuk; - sample.hasClassic = kind == Kind::RemoteWithClassic; -} - -// The patched SDL Wii driver posts Classic Controller sticks as WPAD's own -// value times 64 (aurora-main/cmake/AuroraSDL3Patches.cmake), so WPADCLStatus -// is the axis divided back: signed, 0 at the centre, -512..511, +y up. -int16_t ClassicStickRaw(Sint16 axis, bool invert) { - const long value = invert ? -static_cast(axis) : axis; - return static_cast(std::clamp(std::lround(value / 64.0), -512L, 511L)); -} - -// The kernel driver's evdev axes span SDL's full range; scaled to WPAD's. -int16_t KernelClassicStickRaw(Sint16 axis, bool invert) { - float value = static_cast(axis) / 32767.0f; - if (invert) value = -value; - value = std::clamp(value, -1.0f, 1.0f); - return static_cast(std::clamp(std::lround(value * 512.0f), -512L, 511L)); -} - -// KPAD's default Classic Controller stick limits; the game uses the cross clamp. -constexpr float kKpadStickMin = 60.0f; -constexpr float kKpadStickMax = 308.0f; - -// KPAD cross clamp: per-axis dead zone and scale, then the unit circle. -void ClassicStickFloat(const int16_t raw[2], float out[2]) { - for (int i = 0; i < 2; ++i) { - const float magnitude = std::fabs(static_cast(raw[i])); - const float scaled = std::clamp((magnitude - kKpadStickMin) / (kKpadStickMax - kKpadStickMin), 0.0f, 1.0f); - out[i] = raw[i] < 0 ? -scaled : scaled; - } - const float length = std::sqrt(out[0] * out[0] + out[1] * out[1]); - if (length > 1.0f) { - out[0] /= length; - out[1] /= length; - } -} - -// Samples buttons, accelerometers and the extension of the remote on a port. -bool ReadKpadSample(uint32_t chan, KpadSample& sample) { - if (chan >= PAD_MAX_CONTROLLERS) { - return false; - } - SDL_Gamepad* gamepad = SDL_GetGamepadFromPlayerIndex(static_cast(chan)); - const Kind kind = KindForGamepad(gamepad); - if (!IsKpadKind(kind)) { - const Kind remembered = EffectiveKind(chan); - if (!IsKpadKind(remembered)) { - return false; - } - FillGraceSample(chan, remembered, sample); - return true; - } - SDL_Joystick* joystick = SDL_GetGamepadJoystick(gamepad); - if (joystick == nullptr) { - return false; - } - EnsureSensors(gamepad, chan); - - sample = {}; - // The kernel's evdev nodes have regular SDL mappings, so they are read as gamepads. - const bool kernel = IsKernelWiiNode(SDL_GetGamepadID(gamepad)); - const bool classicNode = kernel && IsClassicNodeName(SDL_GetGamepadName(gamepad)); - if (kernel) { - const auto mapped = [&](SDL_GamepadButton button, uint32_t bit) { - if (SDL_GetGamepadButton(gamepad, button)) sample.hold |= bit; - }; - if (!classicNode) { - mapped(SDL_GAMEPAD_BUTTON_EAST, kWpadA); - mapped(SDL_GAMEPAD_BUTTON_SOUTH, kWpadB); - mapped(SDL_GAMEPAD_BUTTON_WEST, kWpadOne); - mapped(SDL_GAMEPAD_BUTTON_NORTH, kWpadTwo); - mapped(SDL_GAMEPAD_BUTTON_START, kWpadPlus); - mapped(SDL_GAMEPAD_BUTTON_BACK, kWpadMinus); - mapped(SDL_GAMEPAD_BUTTON_GUIDE, kWpadHome); - mapped(SDL_GAMEPAD_BUTTON_DPAD_UP, kWpadUp); - mapped(SDL_GAMEPAD_BUTTON_DPAD_DOWN, kWpadDown); - mapped(SDL_GAMEPAD_BUTTON_DPAD_LEFT, kWpadLeft); - mapped(SDL_GAMEPAD_BUTTON_DPAD_RIGHT, kWpadRight); - } - } else { - const auto raw = [&](int index, uint32_t bit) { - if (SDL_GetJoystickButton(joystick, index)) sample.hold |= bit; - }; - raw(kRawA, kWpadA); - raw(kRawB, kWpadB); - raw(kRawOne, kWpadOne); - raw(kRawTwo, kWpadTwo); - raw(kRawPlus, kWpadPlus); - raw(kRawMinus, kWpadMinus); - raw(kRawHome, kWpadHome); - raw(kRawDpadUp, kWpadUp); - raw(kRawDpadDown, kWpadDown); - raw(kRawDpadLeft, kWpadLeft); - raw(kRawDpadRight, kWpadRight); - } - - float rawG[3] = {}; - const bool haveRaw = ReadSdlAccel(gamepad, SDL_SENSOR_ACCEL, rawG); - for (float& v : rawG) v /= kStandardGravity; - LastAcc& last = g_lastAcc[chan]; - const bool accepted = ReadAccelAsKpad(gamepad, chan, SDL_SENSOR_ACCEL, sample.acc); - if (accepted) { - last.valid = true; - for (int i = 0; i < 3; ++i) last.acc[i] = sample.acc[i]; - } else { - // No sample this frame or a glitched one: repeat the last good reading - // (rest pose, buttons up, until there is one). - for (int i = 0; i < 3; ++i) sample.acc[i] = last.acc[i]; - } - if (RuntimeConfigFile::WiiAccelTraceEnabled(false)) { - TraceSample(chan, sample, rawG, haveRaw, accepted); - } - - if (kind == Kind::RemoteWithClassic) { - sample.hasClassic = true; - // The driver posts the extension's buttons as joystick buttons numbered - // by SDL_GAMEPAD_BUTTON_*: a/b/x/y by position (a on the east), +/-, - // Home, the L/R clicks as shoulders, the D-pad as buttons 11-14 (never - // through SDL's gamepad mapping, which expects a hat), ZL/ZR as the - // trigger axes. - SDL_Gamepad* classic = gamepad; - if (kernel && !classicNode) { - classic = KernelSibling(gamepad, true); - if (classic == nullptr) { - classic = gamepad; - } - } - const auto cl = [&](SDL_GamepadButton button, uint32_t bit) { - if (kernel ? SDL_GetGamepadButton(classic, button) : SDL_GetJoystickButton(joystick, button)) { - sample.clHold |= bit; - } - }; - cl(SDL_GAMEPAD_BUTTON_EAST, kClA); - cl(SDL_GAMEPAD_BUTTON_SOUTH, kClB); - cl(SDL_GAMEPAD_BUTTON_NORTH, kClX); - cl(SDL_GAMEPAD_BUTTON_WEST, kClY); - cl(SDL_GAMEPAD_BUTTON_START, kClPlus); - cl(SDL_GAMEPAD_BUTTON_BACK, kClMinus); - cl(SDL_GAMEPAD_BUTTON_GUIDE, kClHome); - cl(SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, kClL); - cl(SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, kClR); - cl(SDL_GAMEPAD_BUTTON_DPAD_UP, kClUp); - cl(SDL_GAMEPAD_BUTTON_DPAD_DOWN, kClDown); - cl(SDL_GAMEPAD_BUTTON_DPAD_LEFT, kClLeft); - cl(SDL_GAMEPAD_BUTTON_DPAD_RIGHT, kClRight); - if (SDL_GetGamepadAxis(classic, SDL_GAMEPAD_AXIS_LEFT_TRIGGER) > 0) sample.clHold |= kClZL; - if (SDL_GetGamepadAxis(classic, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) > 0) sample.clHold |= kClZR; - const Sint16 lx = SDL_GetGamepadAxis(classic, SDL_GAMEPAD_AXIS_LEFTX); - const Sint16 ly = SDL_GetGamepadAxis(classic, SDL_GAMEPAD_AXIS_LEFTY); - const Sint16 rx = SDL_GetGamepadAxis(classic, SDL_GAMEPAD_AXIS_RIGHTX); - const Sint16 ry = SDL_GetGamepadAxis(classic, SDL_GAMEPAD_AXIS_RIGHTY); - if (kernel) { - sample.clLStickRaw[0] = KernelClassicStickRaw(lx, false); - sample.clLStickRaw[1] = KernelClassicStickRaw(ly, true); - sample.clRStickRaw[0] = KernelClassicStickRaw(rx, false); - sample.clRStickRaw[1] = KernelClassicStickRaw(ry, true); - sample.clLStick[0] = std::clamp(static_cast(lx) / 32767.0f, -1.0f, 1.0f); - sample.clLStick[1] = std::clamp(-static_cast(ly) / 32767.0f, -1.0f, 1.0f); - sample.clRStick[0] = std::clamp(static_cast(rx) / 32767.0f, -1.0f, 1.0f); - sample.clRStick[1] = std::clamp(-static_cast(ry) / 32767.0f, -1.0f, 1.0f); - } else { - sample.clLStickRaw[0] = ClassicStickRaw(lx, false); - sample.clLStickRaw[1] = ClassicStickRaw(ly, true); - sample.clRStickRaw[0] = ClassicStickRaw(rx, false); - sample.clRStickRaw[1] = ClassicStickRaw(ry, true); - ClassicStickFloat(sample.clLStickRaw, sample.clLStick); - ClassicStickFloat(sample.clRStickRaw, sample.clRStick); - } - // Only the full-press click of L/R reaches SDL; report it as a full pull. - sample.clTriggerL = (sample.clHold & kClL) ? 255 : 0; - sample.clTriggerR = (sample.clHold & kClR) ? 255 : 0; - } - - if (kind == Kind::RemoteWithNunchuk) { - sample.hasNunchuk = true; - if (SDL_GetGamepadButton(gamepad, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER)) sample.hold |= kWpadC; - if (SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFT_TRIGGER) > 0) sample.hold |= kWpadZ; - sample.stick[0] = static_cast(SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTX)) / 32767.0f; - // SDL's y grows downwards; KPAD's stick y is up-positive. - sample.stick[1] = -static_cast(SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTY)) / 32767.0f; - for (float& v : sample.stick) v = std::clamp(v, -1.0f, 1.0f); - LastAcc& lastNunchuk = g_lastNunchukAcc[chan]; - if (ReadAccelAsKpad(gamepad, chan, SDL_SENSOR_ACCEL_L, sample.nunchukAcc)) { - lastNunchuk.valid = true; - for (int i = 0; i < 3; ++i) lastNunchuk.acc[i] = sample.nunchukAcc[i]; - } else { - for (int i = 0; i < 3; ++i) sample.nunchukAcc[i] = lastNunchuk.acc[i]; - } - } - return true; -} - -// Corrected SDL sample and KPAD vector of the remote on a port, for the overlay. -bool ReadAccelDebug(uint32_t chan, float sdlG[3], float kpadAcc[3]) { - if (!IsRemoteChannel(chan)) { - return false; - } - SDL_Gamepad* gamepad = SDL_GetGamepadFromPlayerIndex(static_cast(chan)); - if (gamepad == nullptr) { - return false; - } - EnsureSensors(gamepad, chan); - if (!ReadAccelG(gamepad, chan, SDL_SENSOR_ACCEL, sdlG)) { - return false; - } - AccelGToKpad(sdlG, kpadAcc); - return true; -} - -// Begins collecting rest samples from the remote on `chan`. -void StartAccelCalibration(uint32_t chan) { - SDL_Gamepad* gamepad = RemoteGamepad(chan); - if (gamepad == nullptr) { - FinishAccelCalibration(chan, "No Wii Remote on this port."); - return; - } - g_calibration = {}; - g_calibration.active = true; - g_calibration.chan = chan; - g_calibration.instance = SDL_GetGamepadID(gamepad); - g_calibrationMessage[0] = '\0'; -} - -// Zeroes the stored correction of the remote on `chan`. -void ClearAccelCalibration(uint32_t chan) { - if (g_calibration.chan == chan) { - g_calibration.active = false; - } - SDL_Gamepad* gamepad = RemoteGamepad(chan); - if (gamepad == nullptr) { - SetCalibrationMessage(chan, "No Wii Remote on this port."); - return; - } - RemoteCalibration& calibration = CalibrationFor(gamepad, chan); - calibration.offset = {}; - RuntimeConfigFile::SetWiiAccelOffsetFor(calibration.key, {0.0, 0.0, 0.0}); - SetCalibrationMessage(chan, "Calibration cleared."); -} - -// Correction in effect for the remote on `chan`, for the overlay. -std::optional> ReadAccelOffset(uint32_t chan) { - SDL_Gamepad* gamepad = RemoteGamepad(chan); - if (gamepad == nullptr) { - return std::nullopt; - } - const RemoteCalibration& calibration = CalibrationFor(gamepad, chan); - return std::array{calibration.offset[0], calibration.offset[1], calibration.offset[2]}; -} - -// True while a calibration run is collecting samples from `chan`. -bool IsAccelCalibrating(uint32_t chan) { - return g_calibration.active && g_calibration.chan == chan; -} - -// Share of the calibration samples collected so far, 0..1; 0 when idle. -float AccelCalibrationProgress() { - return g_calibration.active ? static_cast(g_calibration.count) / kCalibrationSamples : 0.0f; -} - -// Outcome of the last calibration run on `chan` for the overlay, or nullptr. -const char* AccelCalibrationMessage(uint32_t chan) { - if (g_calibrationMessage[0] == '\0' || g_calibrationMessageChan != chan) { - return nullptr; - } - SDL_Gamepad* gamepad = RemoteGamepad(chan); - const SDL_JoystickID remote = gamepad != nullptr ? SDL_GetGamepadID(gamepad) : 0; - return remote == g_calibrationMessageRemote ? g_calibrationMessage : nullptr; -} - -} // namespace WiiRemoteInput diff --git a/runtime/src/wiimote/wiimote_ext_crypto.cpp b/runtime/src/wiimote/wiimote_ext_crypto.cpp new file mode 100644 index 0000000..a345f58 --- /dev/null +++ b/runtime/src/wiimote/wiimote_ext_crypto.cpp @@ -0,0 +1,260 @@ +// Wii Remote extension encryption (first-party key schedule). Ported from +// Dolphin (Source/Core/Core/HW/WiimoteEmu/Encryption.cpp, GPL-2.0-or-later), +// based on Hector Martin's reverse engineering. + +#include "wiimote_ext_crypto.h" + +#include +#include + +namespace Wiimote::ExtCrypto { +namespace Detail { + +using SBox = std::array; + +constexpr SBox kKeygenSbox = { + 0x70, 0x51, 0x03, 0x86, 0x40, 0x0d, 0x4f, 0xeb, 0x3e, 0xcc, 0xd1, 0x87, 0x35, 0xbd, 0xf5, 0x0b, + 0x5e, 0xd0, 0xf8, 0xf2, 0xd5, 0xe2, 0x6c, 0x31, 0x0c, 0xad, 0xfc, 0x21, 0xc3, 0x78, 0xc1, 0x06, + 0xc2, 0x4c, 0x55, 0xe6, 0x4a, 0x34, 0x48, 0x11, 0x1e, 0xda, 0xe7, 0x1a, 0x84, 0xa0, 0x96, 0xa7, + 0xe3, 0x7f, 0xaf, 0x63, 0x9c, 0xfa, 0x23, 0x5b, 0x79, 0xc8, 0x9e, 0xba, 0xb2, 0xc9, 0x22, 0x12, + 0x4b, 0xb3, 0xa1, 0xb6, 0x32, 0x49, 0xa2, 0xe1, 0x89, 0x39, 0x10, 0x66, 0xc5, 0x07, 0x8f, 0x54, + 0xea, 0x91, 0xca, 0x3f, 0xf9, 0x19, 0xf0, 0xd7, 0x46, 0xbc, 0x28, 0x1b, 0x61, 0xe8, 0x2f, 0x6a, + 0xae, 0x9d, 0xf6, 0x4e, 0x09, 0x14, 0x77, 0x4d, 0xdb, 0x1f, 0x2e, 0x7b, 0x7c, 0xf1, 0x43, 0xa3, + 0x00, 0xb8, 0x13, 0x8c, 0x85, 0xb9, 0x29, 0x75, 0x88, 0xfd, 0xd2, 0x56, 0x1c, 0x50, 0x97, 0x41, + 0xe5, 0x3b, 0x60, 0xb5, 0xc0, 0x64, 0xee, 0x98, 0xd6, 0x2d, 0x25, 0xa4, 0xaa, 0xcd, 0x7d, 0xa8, + 0x83, 0xc6, 0xab, 0xbe, 0x44, 0x99, 0x26, 0x3c, 0xce, 0x9f, 0xbf, 0xd3, 0xcb, 0x76, 0x7a, 0x7e, + 0x82, 0x01, 0x8a, 0x9a, 0x80, 0x1d, 0x0e, 0xb0, 0x5c, 0xd4, 0x38, 0x62, 0xf4, 0x30, 0xe0, 0x8e, + 0x53, 0xb7, 0x02, 0x57, 0xac, 0xa6, 0x52, 0x0a, 0x6d, 0x92, 0x65, 0x17, 0x24, 0x33, 0x45, 0x72, + 0x74, 0xb1, 0xb4, 0xf7, 0x5d, 0xed, 0x2c, 0xff, 0x47, 0x37, 0x5a, 0x90, 0xbb, 0xdf, 0x2a, 0x16, + 0x59, 0x95, 0xd9, 0xc4, 0x27, 0x67, 0x73, 0xc7, 0x68, 0xfe, 0xa5, 0xdd, 0x6b, 0x5f, 0x93, 0xd8, + 0xec, 0x05, 0x3a, 0x8d, 0x6e, 0xfb, 0x3d, 0xa9, 0x69, 0x36, 0xf3, 0x94, 0xde, 0xef, 0x15, 0x6f, + 0x8b, 0x9b, 0x08, 0x0f, 0xdc, 0x81, 0x18, 0x20, 0x04, 0xe4, 0x71, 0xcf, 0xe9, 0x2b, 0x42, 0x58, +}; + +constexpr std::array kSboxes = {{ + { + 0x01, 0xa0, 0xa9, 0x62, 0xd6, 0x3f, 0x85, 0xa7, 0xb6, 0xd4, 0xfa, 0x15, 0x66, 0x17, 0x09, + 0xbd, 0x5d, 0x14, 0x34, 0x26, 0x59, 0x72, 0x91, 0x54, 0x06, 0x4f, 0xf8, 0xb0, 0x5b, 0x74, + 0x93, 0x99, 0x8c, 0xf2, 0x45, 0xcd, 0xea, 0x4e, 0xad, 0x10, 0x4a, 0xe5, 0xca, 0xee, 0xdf, + 0xc6, 0x6f, 0x9f, 0x88, 0x8e, 0x02, 0xcc, 0x08, 0xa8, 0x77, 0x94, 0x6d, 0x21, 0xb1, 0x28, + 0xe4, 0x39, 0x79, 0x96, 0x60, 0x71, 0x81, 0x16, 0x2e, 0xe6, 0x78, 0xb9, 0xc4, 0x46, 0x9a, + 0x42, 0xae, 0xb7, 0x7c, 0x43, 0xb3, 0x22, 0x1a, 0x86, 0xc2, 0x32, 0x3d, 0x2d, 0x9c, 0xd2, + 0x29, 0xe9, 0x63, 0x9b, 0xd1, 0x31, 0x38, 0x5e, 0x1e, 0x36, 0x41, 0xbb, 0x03, 0x18, 0x2b, + 0x3e, 0xbf, 0x68, 0x61, 0xfc, 0x52, 0xc0, 0xde, 0xe0, 0x0a, 0x58, 0x13, 0x5a, 0x00, 0xbe, + 0x1c, 0x90, 0x0e, 0x53, 0x12, 0xfd, 0xe2, 0x6e, 0xba, 0xce, 0x24, 0x27, 0x44, 0x7f, 0x87, + 0xa3, 0xa1, 0xd5, 0x50, 0x40, 0xe3, 0xf9, 0x83, 0xf7, 0xc7, 0xa2, 0x35, 0xc8, 0xdb, 0x19, + 0xab, 0x2f, 0x11, 0x25, 0xed, 0x33, 0x9e, 0x55, 0xe1, 0x48, 0xaf, 0x73, 0x84, 0xda, 0x2a, + 0xaa, 0x51, 0xeb, 0x9d, 0x95, 0xb2, 0xcb, 0xe7, 0x70, 0x80, 0xfe, 0x4c, 0x65, 0x04, 0xef, + 0xc5, 0xf1, 0xc3, 0x3a, 0xb4, 0xf5, 0x5f, 0x23, 0x89, 0xdd, 0x30, 0xa5, 0x8b, 0xd3, 0xf6, + 0xdc, 0x4d, 0x64, 0xd7, 0xf0, 0x8f, 0xec, 0x56, 0x37, 0x5c, 0xa4, 0x0d, 0x07, 0x76, 0x8a, + 0x2c, 0x0b, 0xb5, 0xd8, 0xc1, 0x1f, 0xe8, 0x3b, 0xf4, 0x4b, 0x1b, 0x47, 0x6c, 0x49, 0x67, + 0x7b, 0x92, 0xcf, 0x75, 0x7e, 0x20, 0xd9, 0x7d, 0x3c, 0x97, 0x7a, 0xd0, 0x05, 0x6b, 0x0f, + 0x1d, 0xfb, 0x82, 0x98, 0x57, 0x8d, 0xf3, 0x6a, 0xbc, 0xac, 0xc9, 0xa6, 0xff, 0xb8, 0x69, + 0x0c, + }, + { + 0x4c, 0x4d, 0x72, 0x07, 0x5a, 0x49, 0x33, 0x8d, 0xa2, 0xab, 0x46, 0x3d, 0x63, 0x0d, 0xa0, + 0x97, 0xff, 0xf0, 0xf5, 0xfa, 0xc0, 0xe9, 0xdb, 0x62, 0xe4, 0xe1, 0x74, 0x43, 0xdc, 0x86, + 0x18, 0x29, 0x37, 0xf4, 0x06, 0xe2, 0xed, 0x6f, 0x90, 0x48, 0x1e, 0x2d, 0x1d, 0xea, 0x73, + 0x94, 0x54, 0xdf, 0x25, 0xf6, 0x47, 0x27, 0xd9, 0x11, 0x77, 0xc9, 0x84, 0x1c, 0x5b, 0x5c, + 0x51, 0x81, 0xa6, 0x22, 0x3e, 0x24, 0x96, 0xc8, 0x8a, 0xec, 0x82, 0x7c, 0x09, 0xb8, 0x45, + 0x4a, 0x57, 0xbb, 0x2f, 0x50, 0x75, 0x8e, 0x61, 0x70, 0x8c, 0x6c, 0xaf, 0xd0, 0xfd, 0xb4, + 0x1b, 0xae, 0xde, 0xfe, 0x3b, 0xb5, 0x36, 0xbd, 0x55, 0x01, 0x0e, 0x9c, 0x41, 0x56, 0x5f, + 0xb3, 0x26, 0x03, 0x83, 0xba, 0x13, 0x4b, 0xca, 0xc5, 0x0a, 0xf8, 0x60, 0xa5, 0xb9, 0xc7, + 0xc3, 0x98, 0x32, 0xfb, 0x12, 0xf9, 0xa7, 0x92, 0xaa, 0x68, 0xf3, 0x78, 0x7e, 0x05, 0x20, + 0x21, 0x02, 0xe8, 0xbf, 0xf2, 0xb0, 0x59, 0x8f, 0xd2, 0xcb, 0x87, 0x65, 0x15, 0xf1, 0x1a, + 0xb2, 0x30, 0xad, 0xee, 0x58, 0xa3, 0x8b, 0x66, 0x1f, 0x2c, 0xd7, 0x5d, 0x19, 0x85, 0xa8, + 0xe6, 0xd3, 0x6b, 0xa1, 0x0c, 0x91, 0x93, 0x6a, 0x5e, 0x0b, 0x79, 0xe3, 0xdd, 0x00, 0x4f, + 0x3c, 0x89, 0x6e, 0x71, 0x69, 0xa9, 0xac, 0x40, 0xe5, 0x99, 0x28, 0xc6, 0x31, 0x4e, 0x7a, + 0xcd, 0x08, 0x9e, 0x7d, 0xef, 0x17, 0xfc, 0x88, 0xd8, 0xa4, 0x6d, 0x44, 0x95, 0xd1, 0xb7, + 0xd4, 0x9b, 0xbe, 0x2a, 0x34, 0x64, 0x2b, 0xcf, 0x2e, 0xeb, 0x38, 0xce, 0x23, 0xe0, 0x3a, + 0x3f, 0xf7, 0x7b, 0x9f, 0x10, 0x53, 0xbc, 0x52, 0x67, 0x16, 0xe7, 0x80, 0x76, 0x04, 0xc4, + 0xb6, 0xc1, 0xc2, 0x7f, 0x9a, 0xda, 0xd5, 0x39, 0x42, 0x14, 0x9d, 0xb1, 0x0f, 0x35, 0xd6, + 0xcc, + }, + { + 0xb9, 0xda, 0x38, 0x0c, 0xa2, 0x9c, 0x09, 0x1f, 0x06, 0xb1, 0xb6, 0xfd, 0x1a, 0x69, 0x23, + 0x30, 0xc4, 0xde, 0x01, 0xd1, 0xf4, 0x58, 0x29, 0x37, 0x1c, 0x7d, 0xd5, 0xbf, 0xff, 0xbd, + 0xc8, 0xc9, 0xcf, 0x65, 0xbe, 0x7b, 0x78, 0x97, 0x98, 0x67, 0x08, 0xb3, 0x26, 0x57, 0xf7, + 0xfa, 0x40, 0xad, 0x8e, 0x75, 0xa6, 0x7c, 0xdb, 0x91, 0x8b, 0x51, 0x99, 0xd4, 0x17, 0x7a, + 0x90, 0x8d, 0xce, 0x63, 0xcb, 0x4e, 0xa0, 0xab, 0x18, 0x3a, 0x5b, 0x50, 0x7f, 0x21, 0x74, + 0xc1, 0xbb, 0xb8, 0xb7, 0xba, 0x0b, 0x35, 0x95, 0x31, 0x59, 0x9a, 0x4d, 0x04, 0x07, 0x1e, + 0x5a, 0x76, 0x13, 0xf3, 0x71, 0x83, 0xf0, 0x86, 0x03, 0xa8, 0x39, 0x42, 0xaa, 0x28, 0xe6, + 0xe4, 0xd8, 0x5d, 0xd3, 0xd0, 0x6e, 0x6f, 0x96, 0xfb, 0x5e, 0xbc, 0x56, 0xc2, 0x5f, 0x85, + 0x9b, 0xe7, 0xaf, 0xd2, 0x3b, 0x84, 0x6a, 0xa7, 0x53, 0xc5, 0x44, 0x49, 0xa5, 0xf9, 0x36, + 0x72, 0x3d, 0x2c, 0xd9, 0x1b, 0xa1, 0xf5, 0x4f, 0x93, 0x9d, 0x68, 0x47, 0x41, 0x16, 0xca, + 0x2a, 0x4c, 0xa3, 0x87, 0xd6, 0xe5, 0x19, 0x2e, 0x77, 0x15, 0x6d, 0x70, 0xc0, 0xdf, 0xb2, + 0x00, 0x46, 0xed, 0xc6, 0x6c, 0x43, 0x60, 0x92, 0x2d, 0xa9, 0x22, 0x45, 0x8f, 0x34, 0x55, + 0xae, 0xa4, 0x0a, 0x66, 0x32, 0xe0, 0xdc, 0x02, 0xac, 0xe8, 0x20, 0x8c, 0x89, 0x62, 0x4a, + 0xfe, 0xee, 0xc3, 0xe3, 0x3c, 0xf1, 0x79, 0x05, 0xe9, 0xf6, 0x27, 0x33, 0xcc, 0xf2, 0x9e, + 0x11, 0x81, 0x7e, 0x80, 0x10, 0x8a, 0x82, 0x9f, 0x48, 0x0d, 0xd7, 0xb4, 0xfc, 0x2f, 0xb5, + 0xc7, 0xdd, 0x88, 0x14, 0x6b, 0x2b, 0x54, 0xea, 0x1d, 0x94, 0x5c, 0xb0, 0xef, 0x12, 0x24, + 0xcd, 0xeb, 0xe1, 0xe2, 0x64, 0x73, 0x3f, 0x0e, 0x52, 0x61, 0x25, 0x3e, 0xf8, 0x0f, 0x4b, + 0xec, + }, + { + 0xc0, 0x00, 0x30, 0xf6, 0x02, 0x49, 0x3d, 0x10, 0x6e, 0x20, 0xc9, 0xa6, 0x2f, 0xfe, 0x2c, + 0x2b, 0x75, 0x2e, 0x45, 0x26, 0xab, 0x48, 0xa9, 0x80, 0xfc, 0x04, 0xcc, 0xd3, 0xb5, 0xba, + 0xa3, 0x38, 0x31, 0x7d, 0x01, 0xd9, 0xa7, 0x7b, 0x96, 0xb6, 0x63, 0x69, 0x4e, 0xf7, 0xde, + 0xe0, 0x78, 0xca, 0x50, 0xaa, 0x41, 0x91, 0x65, 0x88, 0xe4, 0x21, 0x85, 0xda, 0x3a, 0x27, + 0xbe, 0x1c, 0x3e, 0x42, 0x5e, 0x17, 0x52, 0x7f, 0x1f, 0x89, 0x24, 0x6f, 0x8f, 0x5c, 0x67, + 0x74, 0x0e, 0x12, 0x87, 0x8d, 0xe9, 0x34, 0xed, 0x73, 0xc4, 0xf8, 0x61, 0x5b, 0x05, 0xdf, + 0x59, 0x4c, 0x97, 0x79, 0x83, 0x18, 0xa4, 0x55, 0x95, 0xeb, 0xbd, 0x53, 0xf5, 0xf1, 0x57, + 0x66, 0x46, 0x9f, 0xb2, 0x81, 0x09, 0x51, 0x86, 0x22, 0x16, 0xdd, 0x23, 0x93, 0x76, 0x29, + 0xc2, 0xd7, 0x1d, 0xd4, 0xbf, 0x36, 0x3f, 0xea, 0x4b, 0x11, 0x32, 0xb9, 0x62, 0x54, 0x60, + 0xd6, 0x6d, 0x43, 0x9a, 0x0d, 0x92, 0x9c, 0xb0, 0xef, 0x58, 0x6c, 0x9d, 0x77, 0x2d, 0x70, + 0xfa, 0xf3, 0xb3, 0x0b, 0xe2, 0x40, 0x7e, 0xf4, 0x8a, 0xe5, 0x8c, 0x3c, 0x56, 0x71, 0xd1, + 0x64, 0xe1, 0x82, 0x0a, 0xcb, 0x13, 0x15, 0x90, 0xec, 0x03, 0x99, 0xaf, 0x14, 0x5d, 0x0f, + 0x33, 0x4a, 0x94, 0xa5, 0xa8, 0x35, 0x1b, 0xe3, 0x6a, 0xc6, 0x28, 0xff, 0x4d, 0xe7, 0x25, + 0x84, 0xac, 0x08, 0xae, 0xc5, 0xa2, 0x2a, 0xb8, 0x37, 0x0c, 0x7a, 0xa0, 0xc3, 0xce, 0xad, + 0x06, 0x1a, 0x9e, 0x8b, 0xfb, 0xd5, 0xf0, 0xc1, 0x1e, 0xd0, 0xb4, 0x9b, 0xb1, 0x44, 0xf2, + 0x47, 0xc7, 0x68, 0xcf, 0x72, 0xbb, 0x4f, 0x5a, 0xf9, 0xdc, 0x6b, 0xdb, 0xd2, 0xe8, 0x7c, + 0xc8, 0xee, 0x98, 0xa1, 0xe6, 0xd8, 0x39, 0x07, 0x5f, 0xfd, 0x8e, 0x19, 0xb7, 0x3b, 0xbc, + 0xcd, + }, + { + 0x7c, 0xe3, 0x81, 0x73, 0xb2, 0x11, 0xbf, 0x6f, 0x20, 0x98, 0xfe, 0x75, 0x96, 0xef, 0x6c, + 0xda, 0x50, 0xe1, 0x09, 0x72, 0x54, 0x45, 0xba, 0x34, 0x80, 0x5b, 0xed, 0x3e, 0x53, 0x2c, + 0x87, 0xa4, 0x57, 0xf3, 0x33, 0x3f, 0x3c, 0xb7, 0x67, 0xb4, 0xa3, 0x25, 0x60, 0x4f, 0x07, + 0x6b, 0x1b, 0x47, 0x15, 0x0f, 0xe4, 0x0a, 0xea, 0xd1, 0x32, 0x78, 0x36, 0x49, 0x8d, 0x4b, + 0xd2, 0xbc, 0xa5, 0xdc, 0x1d, 0x0d, 0x4d, 0xcd, 0x9a, 0x82, 0x5f, 0xfc, 0x94, 0x65, 0xbe, + 0xe2, 0xf4, 0xc9, 0x1e, 0x44, 0xcb, 0x9e, 0x0c, 0x64, 0x71, 0x26, 0x63, 0xb3, 0x14, 0xe8, + 0x40, 0x70, 0x8a, 0x0e, 0x19, 0x42, 0x6d, 0xac, 0x88, 0x10, 0x5c, 0xdf, 0x41, 0xa9, 0xad, + 0xe5, 0xfb, 0x74, 0xcc, 0xd5, 0x06, 0x8e, 0x59, 0x86, 0xce, 0x1f, 0x3d, 0x76, 0xe0, 0x8f, + 0xb9, 0x77, 0x27, 0x7b, 0xa6, 0xd8, 0x29, 0xd3, 0xec, 0xb8, 0x13, 0xf7, 0xfa, 0xc3, 0x51, + 0x6a, 0xde, 0x4a, 0x5a, 0xeb, 0xc2, 0x8b, 0x23, 0x48, 0x92, 0xcf, 0x62, 0xa8, 0x99, 0xf8, + 0xd0, 0x2e, 0x85, 0x61, 0x43, 0xc8, 0xbd, 0xf0, 0x05, 0x93, 0xca, 0x4e, 0xf1, 0x7d, 0x30, + 0xfd, 0xc4, 0x69, 0x66, 0x2f, 0x08, 0xb1, 0x52, 0xf9, 0x21, 0xe6, 0x7a, 0x2b, 0xdd, 0x39, + 0x84, 0xff, 0xc0, 0x91, 0xd6, 0x37, 0xd4, 0x7f, 0x2d, 0x9b, 0x5d, 0xa1, 0x3b, 0x6e, 0xb5, + 0xc5, 0x46, 0x04, 0xf5, 0x90, 0xee, 0x7e, 0x83, 0x1c, 0x03, 0x56, 0xb6, 0xaa, 0x00, 0x17, + 0x01, 0x35, 0x55, 0x79, 0x0b, 0x12, 0xbb, 0x1a, 0x31, 0xe7, 0x02, 0x28, 0x16, 0xc1, 0xf6, + 0xa2, 0xdb, 0x18, 0x9c, 0x89, 0x68, 0x38, 0x97, 0xab, 0xc7, 0x2a, 0xd7, 0x3a, 0xf2, 0xc6, + 0x24, 0x4c, 0xb0, 0x58, 0xa0, 0x22, 0x5e, 0x9d, 0xd9, 0xa7, 0xe9, 0xae, 0xaf, 0x8c, 0x95, + 0x9f, + }, + { + 0x28, 0xb7, 0x20, 0xd7, 0xb0, 0x30, 0xc3, 0x09, 0x19, 0xc0, 0x67, 0xd6, 0x00, 0x3c, 0x7e, + 0xe7, 0xe9, 0xf4, 0x08, 0x5a, 0xf8, 0xb8, 0x2e, 0x05, 0xa6, 0x25, 0x9e, 0x5c, 0xd8, 0x15, + 0x0d, 0xe1, 0xf6, 0x11, 0x54, 0x6b, 0xcd, 0x21, 0x46, 0x66, 0x5e, 0x84, 0xad, 0x06, 0x38, + 0x29, 0x44, 0xc5, 0xa2, 0xce, 0xf1, 0xaa, 0xc1, 0x40, 0x71, 0x86, 0xb5, 0xef, 0xfc, 0x36, + 0xa8, 0xcb, 0x0a, 0x48, 0x27, 0x45, 0x64, 0xa3, 0xaf, 0x8c, 0xb2, 0xc6, 0x9f, 0x07, 0x89, + 0xdc, 0x17, 0xd3, 0x49, 0x79, 0xfb, 0xfe, 0x1d, 0xd0, 0xb9, 0x88, 0x43, 0x52, 0xbc, 0x01, + 0x78, 0x2b, 0x7d, 0x94, 0xc7, 0x0e, 0xde, 0xa5, 0xd5, 0x9b, 0xcc, 0xf7, 0x61, 0x7a, 0xc2, + 0x74, 0x81, 0x39, 0x03, 0xab, 0x96, 0xa0, 0x37, 0xbd, 0x2d, 0x72, 0x75, 0x3f, 0xc9, 0xd4, + 0x8e, 0x6f, 0xf9, 0x8d, 0xed, 0x62, 0xdb, 0x1c, 0xdf, 0x04, 0xac, 0x1b, 0x6c, 0x14, 0x4b, + 0x63, 0xf0, 0xbf, 0xb4, 0x82, 0xec, 0x7b, 0x1a, 0x59, 0x92, 0xd2, 0x10, 0x60, 0xb6, 0x3d, + 0x5f, 0xe6, 0x80, 0x6e, 0x70, 0xc4, 0xf2, 0x35, 0xd9, 0x7c, 0xee, 0xe5, 0x41, 0xa4, 0x5b, + 0x50, 0xdd, 0xbb, 0x4c, 0xf3, 0x1f, 0x9d, 0x5d, 0x57, 0x55, 0x51, 0x97, 0xe3, 0x58, 0x42, + 0x4d, 0x9c, 0x73, 0xba, 0xc8, 0x77, 0x31, 0x69, 0x26, 0xae, 0xea, 0x8a, 0xda, 0x22, 0xb3, + 0x87, 0x56, 0xfa, 0x93, 0x0b, 0x34, 0x16, 0x33, 0xe8, 0xe4, 0x53, 0xbe, 0xa9, 0xb1, 0x3a, + 0x3e, 0xf5, 0x90, 0x6a, 0xcf, 0x3b, 0x12, 0xfd, 0x8f, 0x9a, 0xa7, 0x47, 0x91, 0x99, 0xeb, + 0x0f, 0x24, 0xff, 0x23, 0x18, 0x85, 0x4e, 0x7f, 0x0c, 0xe0, 0xa1, 0xe2, 0xd1, 0x2c, 0x2a, + 0x4a, 0x02, 0x4f, 0x1e, 0x95, 0x68, 0x8b, 0x98, 0x83, 0x6d, 0x76, 0xca, 0x65, 0x32, 0x13, + 0x2f, + }, + { + 0xc3, 0x82, 0x9a, 0xa4, 0xba, 0x81, 0x60, 0x37, 0x34, 0x35, 0xfc, 0x80, 0xa8, 0x51, 0x65, + 0x67, 0xed, 0x30, 0x5f, 0x10, 0xd3, 0x4a, 0x27, 0x2f, 0x13, 0xb9, 0x2a, 0xd2, 0xcc, 0xe1, + 0xef, 0xae, 0xeb, 0xbe, 0xf4, 0xbd, 0xcf, 0x43, 0xb3, 0xc5, 0x88, 0x84, 0xb7, 0xdd, 0x39, + 0x40, 0xce, 0x48, 0x6d, 0x9b, 0x72, 0x61, 0x7e, 0xe7, 0xa1, 0x4e, 0x53, 0x2e, 0x77, 0x3b, + 0xe2, 0xc9, 0x36, 0x22, 0x1b, 0x6e, 0x73, 0xb1, 0x03, 0xb2, 0x4c, 0x87, 0xa9, 0xd4, 0x4d, + 0x0f, 0xd8, 0x15, 0x6c, 0xaa, 0x18, 0xf6, 0x49, 0x57, 0x5d, 0xfb, 0x7a, 0x14, 0x94, 0x63, + 0xa0, 0x11, 0xb0, 0x9e, 0xde, 0x05, 0x46, 0xc8, 0xee, 0x47, 0xdb, 0xdc, 0x24, 0x89, 0x9c, + 0x91, 0x97, 0x29, 0xe9, 0x7b, 0xc1, 0x07, 0x1e, 0xb8, 0xfd, 0xfe, 0xac, 0xc6, 0x62, 0x98, + 0x4f, 0xf1, 0x79, 0xe0, 0xe8, 0x6b, 0x78, 0x56, 0xb6, 0x8d, 0x04, 0x50, 0x86, 0xca, 0x6f, + 0x20, 0xe6, 0xea, 0xe5, 0x76, 0x17, 0x1c, 0x74, 0x7f, 0xbc, 0x0d, 0x2c, 0x85, 0xf7, 0x66, + 0x96, 0xe4, 0x8b, 0x75, 0x3f, 0x4b, 0xd9, 0x38, 0xaf, 0x7c, 0xda, 0x0b, 0x83, 0x2d, 0x31, + 0x32, 0xa2, 0xf5, 0x1d, 0x59, 0x41, 0x45, 0xbf, 0x3c, 0x1f, 0xf8, 0xf9, 0x8a, 0xd0, 0x16, + 0x25, 0x69, 0x12, 0x99, 0x9d, 0x21, 0x95, 0xab, 0x01, 0xa6, 0xd7, 0xb5, 0xc0, 0x7d, 0xff, + 0x58, 0x0e, 0x3a, 0x92, 0xd1, 0x55, 0xe3, 0x08, 0x9f, 0xd6, 0x3e, 0x52, 0x8e, 0xfa, 0xa3, + 0xc7, 0x02, 0xcd, 0xdf, 0x8f, 0x64, 0x19, 0x8c, 0xf3, 0xa7, 0x0c, 0x5e, 0x0a, 0x6a, 0x09, + 0xf0, 0x93, 0x5b, 0x42, 0xc2, 0x06, 0x23, 0xec, 0x71, 0xad, 0xb4, 0xcb, 0xbb, 0x70, 0x28, + 0xd5, 0x1a, 0x5c, 0x33, 0x68, 0x5a, 0x00, 0x44, 0x90, 0xa5, 0xc4, 0x26, 0x3d, 0x2b, 0xf2, + 0x54, + }, + { + 0x96, 0xad, 0xda, 0x1f, 0xed, 0x33, 0xe1, 0x81, 0x69, 0x08, 0x0d, 0x0a, 0xdb, 0x35, 0x77, + 0x9a, 0x64, 0xd1, 0xfc, 0x78, 0xaa, 0x1b, 0xd0, 0x67, 0xa0, 0xdd, 0xfa, 0x6c, 0x63, 0x71, + 0x05, 0x84, 0x17, 0x6a, 0x89, 0x4f, 0x66, 0x7f, 0xc6, 0x50, 0x55, 0x92, 0x6f, 0xbd, 0xe7, + 0xd2, 0x40, 0x72, 0x8d, 0xbb, 0xec, 0x06, 0x42, 0x8a, 0xe4, 0x88, 0x9d, 0x7e, 0x7a, 0x82, + 0x27, 0x13, 0x41, 0x1a, 0xaf, 0xc8, 0xa4, 0x76, 0xb4, 0xc2, 0xfe, 0x6d, 0x1c, 0xd9, 0x61, + 0x30, 0xb3, 0x7c, 0xea, 0xf7, 0x29, 0x0f, 0xf2, 0x3b, 0x51, 0xc1, 0xde, 0x5f, 0xe5, 0x2a, + 0x2f, 0x99, 0x0b, 0x5d, 0xa3, 0x2b, 0x4a, 0xab, 0x95, 0xa5, 0xd3, 0x58, 0x56, 0xee, 0x28, + 0x31, 0x00, 0xcc, 0x15, 0x46, 0xca, 0xe6, 0x86, 0x38, 0x3c, 0x65, 0xf5, 0xe3, 0x9f, 0xd6, + 0x5b, 0x09, 0x49, 0x83, 0x70, 0x2d, 0x53, 0xa9, 0x7d, 0xe2, 0xc4, 0xac, 0x8e, 0x5e, 0xb8, + 0x25, 0xf4, 0xb9, 0x57, 0xf3, 0xf1, 0x68, 0x47, 0xb2, 0xa2, 0x59, 0x20, 0xce, 0x34, 0x79, + 0x5c, 0x90, 0x0e, 0x1e, 0xbe, 0xd5, 0x22, 0x23, 0xb1, 0xc9, 0x18, 0x62, 0x16, 0x2e, 0x91, + 0x3e, 0x07, 0x8f, 0xd8, 0x3f, 0x93, 0x3d, 0xd4, 0x9b, 0xdf, 0x85, 0x21, 0xfb, 0x11, 0x74, + 0x97, 0xc7, 0xd7, 0xdc, 0x4c, 0x19, 0x45, 0x98, 0xe9, 0x43, 0x02, 0x4b, 0xbc, 0xc3, 0x04, + 0x9c, 0x6b, 0xf0, 0x75, 0x52, 0xa7, 0x26, 0xf6, 0xc5, 0xba, 0xcf, 0xb0, 0xb7, 0xae, 0x5a, + 0xa1, 0xbf, 0x03, 0x8b, 0x80, 0x12, 0x6e, 0x0c, 0xeb, 0xf9, 0xc0, 0x44, 0x24, 0xef, 0x10, + 0xf8, 0xa8, 0x8c, 0xe8, 0x7b, 0xff, 0x9e, 0x2c, 0xcd, 0x60, 0x36, 0x87, 0xb5, 0x94, 0xa6, + 0x54, 0x73, 0x3a, 0x14, 0x4e, 0x01, 0x1d, 0xb6, 0xfd, 0x37, 0x48, 0x4d, 0x39, 0xcb, 0xe0, + 0x32, + }, +}}; + +constexpr uint8_t kAnswers[7][6] = { + {0xa8, 0x77, 0xa6, 0xe0, 0xf7, 0x43}, {0x5a, 0x35, 0x85, 0xe2, 0x72, 0x97}, + {0x8f, 0xb7, 0x1a, 0x62, 0x87, 0x38}, {0x0d, 0x67, 0xc7, 0xbe, 0x4f, 0x3e}, + {0x20, 0x76, 0x37, 0x8f, 0x68, 0xb7}, {0xa9, 0x26, 0x3f, 0x2b, 0x10, 0xe3}, + {0x30, 0x7e, 0x90, 0x0e, 0x85, 0x0a}, +}; + +using Rand = std::array; +using Key = std::array; + +Key KeyFor(const Rand& rand, size_t idx) { + const uint8_t* ans = kAnswers[idx]; + Rand t{}; + for (size_t i = 0; i < t.size(); ++i) t[i] = kKeygenSbox[rand[i]]; + return { + static_cast((std::rotr(ans[0] ^ t[5], t[2]) - t[9]) ^ t[4]), + static_cast((std::rotr(ans[1] ^ t[1], t[0]) - t[5]) ^ t[7]), + static_cast((std::rotr(ans[2] ^ t[6], t[8]) - t[2]) ^ t[0]), + static_cast((std::rotr(ans[3] ^ t[4], t[7]) - t[3]) ^ t[2]), + static_cast((std::rotr(ans[4] ^ t[1], t[6]) - t[3]) ^ t[4]), + static_cast((std::rotr(ans[5] ^ t[7], t[8]) - t[5]) ^ t[9]), + }; +} + +} // namespace Detail + +std::optional FromKey(const std::array& keyData) { + using namespace Detail; + Rand rand{}; + std::copy_n(keyData.begin(), rand.size(), rand.rbegin()); + Key key{}; + std::copy_n(keyData.begin() + rand.size(), key.size(), key.rbegin()); + // The key was derived from "rand" and an index the extension is not told. + for (size_t idx = 0; idx < 7; ++idx) { + if (KeyFor(rand, idx) != key) continue; + const SBox& a = kSboxes[idx]; + const SBox& b = kSboxes[idx + 1]; + Tables t; + t.ft = {static_cast(a[key[4]] ^ b[rand[3]]), static_cast(a[key[2]] ^ b[rand[5]]), + static_cast(a[key[5]] ^ b[rand[7]]), static_cast(a[key[0]] ^ b[rand[2]]), + static_cast(a[key[1]] ^ b[rand[4]]), static_cast(a[key[3]] ^ b[rand[9]]), + static_cast(a[rand[0]] ^ b[rand[6]]), static_cast(a[rand[1]] ^ b[rand[8]])}; + t.sb = {static_cast(a[key[0]] ^ b[rand[1]]), static_cast(a[key[5]] ^ b[rand[4]]), + static_cast(a[key[3]] ^ b[rand[0]]), static_cast(a[key[2]] ^ b[rand[9]]), + static_cast(a[key[4]] ^ b[rand[7]]), static_cast(a[key[1]] ^ b[rand[8]]), + static_cast(a[rand[3]] ^ b[rand[5]]), static_cast(a[rand[2]] ^ b[rand[6]])}; + return t; + } + return std::nullopt; +} + +void Tables::Encrypt(uint8_t* data, uint32_t address, size_t length) const { + for (size_t i = 0; i < length; ++i, ++address) { + data[i] = static_cast((data[i] - ft[address % 8]) ^ sb[address % 8]); + } +} + +void Tables::Decrypt(uint8_t* data, uint32_t address, size_t length) const { + for (size_t i = 0; i < length; ++i, ++address) { + data[i] = static_cast((data[i] ^ sb[address % 8]) + ft[address % 8]); + } +} + +} // namespace Wiimote::ExtCrypto diff --git a/runtime/src/wiimote/wiimote_extension.cpp b/runtime/src/wiimote/wiimote_extension.cpp new file mode 100644 index 0000000..db41252 --- /dev/null +++ b/runtime/src/wiimote/wiimote_extension.cpp @@ -0,0 +1,146 @@ +#include "wiimote_extension.h" + +#include + +namespace Wiimote { +namespace ExtensionDetail { + +constexpr uint8_t kReportStatus = 0x20; +constexpr uint8_t kReportReadReply = 0x21; +constexpr uint8_t kReportWriteMemory = 0x16; +constexpr uint8_t kReportReadMemory = 0x17; +constexpr uint32_t kExtensionRegisters = 0xA40000; +constexpr uint8_t kRegisterCalibration = 0x20; +constexpr uint8_t kRegisterKey = 0x40; +constexpr uint8_t kRegisterEncryption = 0xF0; +constexpr uint8_t kRegisterIdentifier = 0xFA; +constexpr uint8_t kEncryptionOn = 0xAA; +constexpr uint8_t kEncryptionOff = 0x55; + +struct ExtensionSpan { + size_t offset; + size_t length; +}; + +// Where the extension bytes sit in each data report. +std::optional SpanFor(uint8_t id) { + switch (id) { + case 0x32: return ExtensionSpan{3, 8}; + case 0x34: return ExtensionSpan{3, 19}; + case 0x35: return ExtensionSpan{6, 16}; + case 0x36: return ExtensionSpan{13, 9}; + case 0x37: return ExtensionSpan{16, 6}; + case 0x3D: return ExtensionSpan{1, 21}; + default: return std::nullopt; + } +} + +bool InExtensionSpace(uint32_t address) { + return (address & 0xFF0000) == kExtensionRegisters; +} + +} // namespace ExtensionDetail + +void ExtensionState::Reset() { + m_type = Type::Unknown; + m_format = 0; + m_encrypted = false; + m_tables.reset(); + m_haveCalibration = false; +} + +void ExtensionState::ObserveOutput(const uint8_t* report, size_t size) { + using namespace ExtensionDetail; + if (size < 6) return; + const bool registerSpace = (report[1] & 0x04) != 0; + const uint32_t address = (report[2] << 16) | (report[3] << 8) | report[4]; + if (report[0] == kReportReadMemory) { + m_readAddress = registerSpace ? address : 0; + return; + } + if (!registerSpace || report[0] != kReportWriteMemory || !InExtensionSpace(address)) return; + const size_t length = std::min(report[5], size - 6); + bool keyChanged = false; + for (size_t i = 0; i < length; ++i) { + const size_t reg = (address & 0xFF) + i; + const uint8_t value = report[6 + i]; + if (reg >= kRegisterKey && reg < kRegisterKey + m_key.size()) { + m_key[reg - kRegisterKey] = value; + keyChanged = true; + } else if (reg == kRegisterEncryption) { + if (value == kEncryptionOn) m_encrypted = true; + if (value == kEncryptionOff) Reset(); + } + } + if (keyChanged) { + m_tables = ExtCrypto::FromKey(m_key); + } +} + +void ExtensionState::ObserveInput(const uint8_t* report, size_t size) { + using namespace ExtensionDetail; + if (size >= 4 && report[0] == kReportStatus) { + if ((report[3] & 0x02) == 0) Reset(); + return; + } + if (size < 7 || report[0] != kReportReadReply || (report[3] & 0x0F) != 0 || !InExtensionSpace(m_readAddress)) { + return; + } + const size_t length = std::min((report[3] >> 4) + 1, size - 6); + const uint32_t first = ((report[4] << 8) | report[5]) & 0xFF; + for (size_t i = 0; i < length; ++i) { + const uint32_t reg = first + static_cast(i); + uint8_t value = report[6 + i]; + if (reg >= kRegisterIdentifier) { + // The identifier is read before the game turns encryption on. + if (reg == 0xFE) m_format = value; + if (reg == 0xFF) m_type = value == 0x00 ? Type::Nunchuk : value == 0x01 ? Type::Classic : Type::Unknown; + } else if (reg >= kRegisterCalibration && reg < kRegisterCalibration + m_calibration.size()) { + if (m_encrypted) { + if (!m_tables) continue; + m_tables->Decrypt(&value, reg, 1); + } + m_calibration[reg - kRegisterCalibration] = value; + m_haveCalibration = true; + } + } +} + +uint8_t ExtensionState::Calibration(size_t index, uint8_t fallback) const { + return m_haveCalibration ? m_calibration[index] : fallback; +} + +void ExtensionState::Neutralize(std::vector& report) const { + using namespace ExtensionDetail; + if (report.empty() || m_type == Type::Unknown || (m_encrypted && !m_tables)) return; + const auto span = SpanFor(report[0]); + if (!span || report.size() < span->offset + 6) return; + uint8_t* data = report.data() + span->offset; + std::array plain{}; + std::copy_n(data, plain.size(), plain.begin()); + if (m_encrypted) m_tables->Decrypt(plain.data(), 0, plain.size()); + + if (m_type == Type::Nunchuk) { + plain[0] = Calibration(10, 0x80); + plain[1] = Calibration(13, 0x80); + plain[5] |= 0x03; // C and Z are active low + } else if (m_format == 0x01) { + const uint8_t lx = Calibration(2, 0x80) >> 2; + const uint8_t ly = Calibration(5, 0x80) >> 2; + const uint8_t rx = Calibration(8, 0x80) >> 3; + const uint8_t ry = Calibration(11, 0x80) >> 3; + plain[0] = static_cast(((rx >> 3) & 0x03) << 6 | (lx & 0x3F)); + plain[1] = static_cast(((rx >> 1) & 0x03) << 6 | (ly & 0x3F)); + plain[2] = static_cast((rx & 0x01) << 7 | (ry & 0x1F)); + plain[3] = 0x00; + plain[4] = 0xFF; // buttons are active low + plain[5] = 0xFF; + } else { + return; + } + + if (m_encrypted) m_tables->Encrypt(plain.data(), 0, plain.size()); + std::copy(plain.begin(), plain.end(), data); +} + +} // namespace Wiimote diff --git a/runtime/src/wiimote/wiimote_host.cpp b/runtime/src/wiimote/wiimote_host.cpp new file mode 100644 index 0000000..642bb8c --- /dev/null +++ b/runtime/src/wiimote/wiimote_host.cpp @@ -0,0 +1,828 @@ +#include "wiimote_host.h" + +#include "input_bindings.h" +#include "runtime_config.h" +#include "runtime_log.h" +#include "wiimote_extension.h" +#include "wiimote_platform.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" bool PAD_HLE_RumbleEnabled(); + +namespace Wiimote { +namespace HostDetail { + +using Clock = std::chrono::steady_clock; +using Report = std::vector; + +constexpr uint16_t kNintendoVendor = 0x057E; +constexpr uint16_t kProductRemote = 0x0306; +constexpr uint16_t kProductRemotePlus = 0x0330; + +constexpr auto kScanInterval = std::chrono::milliseconds(500); +constexpr auto kEnumerateInterval = std::chrono::seconds(1); +constexpr auto kProbeCooldown = std::chrono::seconds(3); +constexpr auto kKeepAlive = std::chrono::seconds(1); +constexpr auto kBlinkInterval = std::chrono::milliseconds(500); +constexpr auto kPairingWindow = std::chrono::seconds(60); +constexpr auto kGuestSearchTail = std::chrono::seconds(10); +constexpr auto kAutoPairPause = std::chrono::seconds(4); +constexpr int kReadTimeoutMs = 200; +constexpr size_t kInputQueueLimit = 32; +constexpr uint16_t kButtonMask = 0x9F1F; +constexpr uint8_t kReportSpeakerData = 0x18; + +enum class Phase : uint8_t { + Waiting, // connected to the PC, offered to the game + Linked, // the game's HID channels are open + Asleep, // the game let it go and it could not be switched off + PoweringOff, +}; + +// Input report sizes including the id: Windows always reads the longest report. +size_t ReportSize(uint8_t id, size_t read) { + size_t size = 0; + switch (id) { + case 0x20: size = 7; break; + case 0x21: size = 22; break; + case 0x22: size = 5; break; + case 0x30: size = 3; break; + case 0x31: size = 6; break; + case 0x32: size = 11; break; + case 0x33: size = 18; break; + case 0x34: case 0x35: case 0x36: case 0x37: case 0x3D: case 0x3E: case 0x3F: size = 22; break; + default: return 0; + } + return size <= read ? size : 0; +} + +uint16_t Buttons(const Report& report) { + if (report.size() < 3 || report[0] < 0x20 || report[0] == 0x3D) return 0; + return static_cast(((report[1] << 8) | report[2]) & kButtonMask); +} + +// The game's own battery bars (WPAD's status report thresholds). +int BatteryBars(uint8_t level) { + if (level < 0x03) return 0; + if (level < 0x33) return 1; + if (level < 0x44) return 2; + if (level < 0x55) return 3; + return 4; +} + +struct Remote { + std::string path; + std::string address; + std::string name; + bool plus = false; + SDL_hid_device* device = nullptr; + std::thread reader; + std::thread writer; + std::atomic alive{true}; + std::atomic phase{Phase::Waiting}; + std::atomic wake{true}; + std::atomic battery{-1}; + std::atomic extension{-1}; // -1 none, else the extension id byte + std::atomic extensionAttached{false}; + // Rumble bit of the game's last report, before the vibration setting. + std::atomic gameRumble{false}; + + std::mutex writeMutex; + std::condition_variable writeCv; + std::deque writes; + std::mutex inputMutex; + std::deque input; + // Emulation thread only. + ExtensionState extensionState; +}; + +class Manager final : public Bluetooth::RemoteHost { +public: + void Start(); + void Stop(); + + bool IsAttached(size_t slot) const override; + bool ConsumeWake(size_t slot) override; + bool PopInputReport(size_t slot, std::vector& report) override; + void SendOutputReport(size_t slot, const uint8_t* report, size_t size) override; + void OnLinkStateChanged(size_t slot, Bluetooth::LinkState state) override; + void OnGuestDisconnect(size_t slot) override; + void OnGuestInquiry(bool active) override; + const char* DeviceName(size_t slot) const override; + + SlotInfo Slot(size_t slot); + PairingInfo Pairing(); + void StartPairing(); + void Disconnect(size_t slot); + size_t Waiting(); + +private: + std::shared_ptr At(size_t slot) const; + void ScanLoop(); + void DiscoveryLoop(); + void Enumerate(); + void Reap(); + void AssignWaiting(); + void Open(const SDL_hid_device_info& info); + void SetPhase(const std::shared_ptr& remote, Phase phase); + void PowerOff(const std::shared_ptr& remote); + static void ReadLoop(std::shared_ptr remote); + static void WriteLoop(std::shared_ptr remote); + static void Queue(Remote& remote, Report report); + + mutable std::mutex m_mutex; + std::array, Bluetooth::kRemoteSlots> m_slots; + std::array m_links{}; + std::vector> m_waiting; + std::map m_lastSlot; + std::map m_cooldown; + std::set m_refusedLogged; + // Remotes the OS knows but that were off when last seen, by path. + std::map m_dormant; + Clock::time_point m_lastEnumerate{}; + uint32_t m_deviceChanges = 0; + + std::atomic m_running{false}; + std::thread m_scanner; + std::mutex m_scanMutex; + std::condition_variable m_scanCv; + + std::thread m_discovery; + std::mutex m_discoveryMutex; + std::condition_variable m_discoveryCv; + std::atomic m_cancelDiscovery{false}; + std::atomic m_searching{false}; + std::atomic m_guestSearching{false}; + Clock::time_point m_guestSearchUntil{}; + Clock::time_point m_pairingUntil{}; + std::string m_pairingStatus; +}; + +// Never destroyed: its threads may outlive static destruction at exit. +Manager& TheManager() { + static Manager* manager = new Manager(); + return *manager; +} + +std::shared_ptr Manager::At(size_t slot) const { + std::lock_guard lock(m_mutex); + return slot < m_slots.size() ? m_slots[slot] : nullptr; +} + +bool Manager::IsAttached(size_t slot) const { + const auto remote = At(slot); + if (!remote || !remote->alive) return false; + const Phase phase = remote->phase; + return phase == Phase::Waiting || phase == Phase::Linked; +} + +bool Manager::ConsumeWake(size_t slot) { + const auto remote = At(slot); + return remote && remote->phase == Phase::Waiting && remote->wake.exchange(false); +} + +bool Manager::PopInputReport(size_t slot, std::vector& report) { + const auto remote = At(slot); + if (!remote) return false; + { + std::lock_guard lock(remote->inputMutex); + if (remote->input.empty()) return false; + report = std::move(remote->input.front()); + remote->input.pop_front(); + } + remote->extensionState.ObserveInput(report.data(), report.size()); + if (InputBindings::InputBlocked()) { + // The overlay owns input: the game sees the controller at rest. + if (Buttons(report) != 0) { + report[1] &= static_cast(~(kButtonMask >> 8)); + report[2] &= static_cast(~kButtonMask); + } + remote->extensionState.Neutralize(report); + } + return true; +} + +void Manager::Queue(Remote& remote, Report report) { + { + std::lock_guard lock(remote.writeMutex); + remote.writes.push_back(std::move(report)); + } + remote.writeCv.notify_one(); +} + +void Manager::SendOutputReport(size_t slot, const uint8_t* report, size_t size) { + const auto remote = At(slot); + if (!remote || remote->phase != Phase::Linked || size == 0) return; + remote->extensionState.ObserveOutput(report, size); + const bool rumble = size >= 2 && (report[1] & 0x01) != 0; + const bool rumbleChanged = size >= 2 && remote->gameRumble.exchange(rumble) != rumble; + // PC Bluetooth cannot feed the speaker smoothly enough to sound right, but + // WPAD may carry a rumble change only on speaker data. + if (report[0] == kReportSpeakerData) { + if (rumbleChanged) Queue(*remote, {0x10, static_cast(rumble ? 0x01 : 0x00)}); + return; + } + Queue(*remote, Report(report, report + size)); +} + +void Manager::OnLinkStateChanged(size_t slot, Bluetooth::LinkState state) { + std::shared_ptr remote; + { + std::lock_guard lock(m_mutex); + m_links[slot] = state; + remote = m_slots[slot]; + } + if (!remote) return; + if (state == Bluetooth::LinkState::Ready) { + if (remote->phase == Phase::PoweringOff) return; + { + std::lock_guard lock(remote->inputMutex); + remote->input.clear(); + } + SetPhase(remote, Phase::Linked); + RT_LOG(RT_TAG_HLE) << "Wii Remote " << (slot + 1) << " connected to the game" << std::endl; + } else if (state == Bluetooth::LinkState::Down && remote->phase == Phase::Linked) { + // Lost without the game asking (e.g. the controller was reset): offer it again. + SetPhase(remote, Phase::Waiting); + remote->wake = true; + } +} + +void Manager::OnGuestDisconnect(size_t slot) { + const auto remote = At(slot); + if (!remote) return; + RT_LOG(RT_TAG_HLE) << "Wii Remote " << (slot + 1) << " disconnected by the game" << std::endl; + PowerOff(remote); +} + +void Manager::PowerOff(const std::shared_ptr& remote) { + remote->wake = false; + if (Platform::Query().powerOff && !remote->address.empty()) { + SetPhase(remote, Phase::PoweringOff); + std::thread([remote] { + const bool requested = Platform::PowerOff(remote->address); + // The HID device goes away once the remote is off; if it does not, + // keep it asleep so a button press brings it back. + const auto deadline = Clock::now() + std::chrono::seconds(5); + while (requested && remote->alive && Clock::now() < deadline) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + if (remote->alive && remote->phase == Phase::PoweringOff) { + remote->phase = Phase::Asleep; + remote->writeCv.notify_one(); + } + }).detach(); + } else { + SetPhase(remote, Phase::Asleep); + } +} + +void Manager::SetPhase(const std::shared_ptr& remote, Phase phase) { + remote->phase = phase; + remote->gameRumble = false; + if (phase != Phase::Linked) { + std::lock_guard lock(remote->writeMutex); + remote->writes.clear(); + } + remote->writeCv.notify_one(); +} + +void Manager::OnGuestInquiry(bool active) { + if (active) { + std::lock_guard lock(m_discoveryMutex); + m_guestSearching = true; + } else { + std::lock_guard lock(m_discoveryMutex); + m_guestSearching = false; + m_guestSearchUntil = Clock::now() + kGuestSearchTail; + } + m_discoveryCv.notify_all(); +} + +const char* Manager::DeviceName(size_t slot) const { + const auto remote = At(slot); + return remote && remote->plus ? "Nintendo RVL-CNT-01-TR" : "Nintendo RVL-CNT-01"; +} + +void Manager::Start() { + if (m_running.exchange(true)) return; + if (SDL_hid_init() != 0) { + RT_LOG(RT_TAG_HLE) << "Wii Remotes: HID access unavailable: " << SDL_GetError() << std::endl; + m_running = false; + return; + } + m_scanner = std::thread([this] { ScanLoop(); }); + if (Platform::Query().pairing) { + m_discovery = std::thread([this] { DiscoveryLoop(); }); + } + const std::string notice = Platform::Notice(); + if (!notice.empty()) { + RT_LOG(RT_TAG_HLE) << "Wii Remotes: " << notice << std::endl; + } +} + +void Manager::Stop() { + if (!m_running.exchange(false)) return; + m_cancelDiscovery = true; + m_scanCv.notify_all(); + m_discoveryCv.notify_all(); + if (m_scanner.joinable()) m_scanner.join(); + // An inquiry in progress cannot be interrupted; let it finish on its own. + if (m_discovery.joinable()) m_discovery.detach(); + + std::vector> remotes; + { + std::lock_guard lock(m_mutex); + for (auto& remote : m_slots) { + if (remote) remotes.push_back(remote); + remote.reset(); + } + remotes.insert(remotes.end(), m_waiting.begin(), m_waiting.end()); + m_waiting.clear(); + } + for (const auto& remote : remotes) { + remote->alive = false; + remote->writeCv.notify_all(); + } + // A console switches its remotes off when it shuts down. + for (const auto& remote : remotes) { + if (remote->writer.joinable()) remote->writer.join(); + if (remote->reader.joinable()) remote->reader.join(); + if (remote->device != nullptr) { + const uint8_t rumbleOff[] = {0x10, 0x00}; + const uint8_t ledsOff[] = {0x11, 0x00}; + SDL_hid_write(remote->device, rumbleOff, sizeof(rumbleOff)); + SDL_hid_write(remote->device, ledsOff, sizeof(ledsOff)); + SDL_hid_close(remote->device); + remote->device = nullptr; + } + if (Platform::Query().powerOff && !remote->address.empty()) { + Platform::PowerOff(remote->address); + } + } +} + +void Manager::ScanLoop() { + while (m_running) { + Reap(); + Enumerate(); + AssignWaiting(); + std::unique_lock lock(m_scanMutex); + m_scanCv.wait_for(lock, kScanInterval, [this] { return !m_running; }); + } +} + +void Manager::Reap() { + std::vector> dead; + { + std::lock_guard lock(m_mutex); + for (auto& remote : m_slots) { + if (remote && !remote->alive) { + dead.push_back(remote); + remote.reset(); + } + } + for (auto it = m_waiting.begin(); it != m_waiting.end();) { + if (!(*it)->alive) { + dead.push_back(*it); + it = m_waiting.erase(it); + } else { + ++it; + } + } + } + for (const auto& remote : dead) { + remote->writeCv.notify_all(); + if (remote->writer.joinable()) remote->writer.join(); + if (remote->reader.joinable()) remote->reader.join(); + if (remote->device != nullptr) SDL_hid_close(remote->device); + remote->device = nullptr; + RT_LOG(RT_TAG_HLE) << "Wii Remote " << (remote->address.empty() ? remote->path : remote->address) + << " disconnected from the PC" << std::endl; + m_cooldown[remote->path] = Clock::now() + std::chrono::seconds(1); + if (!remote->address.empty()) m_dormant[remote->path] = remote->address; + } +} + +void Manager::Enumerate() { + const Uint32 changes = SDL_hid_device_change_count(); + const auto now = Clock::now(); + bool fullSlots = false; + bool anyRemote = false; + { + std::lock_guard lock(m_mutex); + fullSlots = std::all_of(m_slots.begin(), m_slots.end(), [](const auto& remote) { return remote != nullptr; }); + anyRemote = !m_waiting.empty() || + std::any_of(m_slots.begin(), m_slots.end(), [](const auto& remote) { return remote != nullptr; }); + } + bool pairing = false; + { + std::lock_guard lock(m_discoveryMutex); + pairing = m_guestSearching || now < m_guestSearchUntil || now < m_pairingUntil; + } + if (fullSlots) return; + if (changes == m_deviceChanges) { + if (now - m_lastEnumerate < kEnumerateInterval) return; + // Once a remote is connected, skip HID enumeration unless pairing or a known remote came back. + if (anyRemote && !pairing && + std::none_of(m_dormant.begin(), m_dormant.end(), + [](const auto& entry) { return Platform::MaybeConnected(entry.second); })) { + m_lastEnumerate = now; + return; + } + } + m_deviceChanges = changes; + m_lastEnumerate = now; + + std::set open; + { + std::lock_guard lock(m_mutex); + for (const auto& remote : m_slots) { + if (remote) open.insert(remote->path); + } + for (const auto& remote : m_waiting) open.insert(remote->path); + } + std::set listed; + SDL_hid_device_info* list = SDL_hid_enumerate(kNintendoVendor, 0); + for (const SDL_hid_device_info* info = list; info != nullptr; info = info->next) { + if (info->path == nullptr || (info->product_id != kProductRemote && info->product_id != kProductRemotePlus)) { + continue; + } + listed.insert(info->path); + if (open.count(info->path) != 0) continue; + const auto cooldown = m_cooldown.find(info->path); + if (cooldown != m_cooldown.end() && now < cooldown->second) continue; + open.insert(info->path); + Open(*info); + } + SDL_hid_free_enumeration(list); + for (auto it = m_dormant.begin(); it != m_dormant.end();) { + it = listed.count(it->first) != 0 ? std::next(it) : m_dormant.erase(it); + } +} + +void Manager::Open(const SDL_hid_device_info& info) { + const std::string path = info.path; + const std::string address = Platform::AddressFor(info); + const std::string name = Platform::NameFor(address, info); + // Wii U Pro Controllers share the Wii Remote Plus id; balance boards are not used by the game. + if (name.find("-UC") != std::string::npos || name.find("RVL-WBC") != std::string::npos) { + m_cooldown[path] = Clock::time_point::max(); + return; + } + if (!address.empty() && !Platform::MaybeConnected(address)) { + // Known to the OS but switched off: check again soon, a button press + // reconnects it. + m_cooldown[path] = Clock::now() + kScanInterval; + m_dormant[path] = address; + return; + } + if (!Platform::Usable(info)) { + if (m_refusedLogged.insert(path).second) { + RT_LOG(RT_TAG_HLE) << "Wii Remote " << address << " is held by the system driver: " << Platform::Notice() + << std::endl; + } + m_cooldown[path] = Clock::now() + std::chrono::seconds(10); + return; + } + SDL_hid_device* device = SDL_hid_open_path(path.c_str()); + if (device == nullptr) { + m_cooldown[path] = Clock::now() + kProbeCooldown; + return; + } + // A remote the OS remembers but that is switched off still has a HID device; + // only a write tells. + const uint8_t status[] = {0x15, 0x00}; + if (SDL_hid_write(device, status, sizeof(status)) < 0) { + SDL_hid_close(device); + m_cooldown[path] = Clock::now() + kProbeCooldown; + if (!address.empty()) m_dormant[path] = address; + return; + } + m_dormant.erase(path); + + auto remote = std::make_shared(); + remote->path = path; + remote->address = address; + remote->name = name; + remote->plus = info.product_id == kProductRemotePlus; + remote->device = device; + remote->reader = std::thread(ReadLoop, remote); + remote->writer = std::thread(WriteLoop, remote); + RT_LOG(RT_TAG_HLE) << (remote->plus ? "Wii Remote Plus " : "Wii Remote ") + << (address.empty() ? path : address) << " connected to the PC" << std::endl; + { + std::lock_guard lock(m_mutex); + m_waiting.push_back(remote); + } + AssignWaiting(); +} + +void Manager::AssignWaiting() { + std::lock_guard lock(m_mutex); + for (auto it = m_waiting.begin(); it != m_waiting.end();) { + const std::shared_ptr& remote = *it; + const std::string key = remote->address.empty() ? remote->path : remote->address; + size_t slot = Bluetooth::kRemoteSlots; + const auto last = m_lastSlot.find(key); + // A slot is free once the game has seen its previous remote go. + const auto free = [this](size_t i) { return !m_slots[i] && m_links[i] == Bluetooth::LinkState::Down; }; + if (last != m_lastSlot.end() && free(last->second)) { + slot = last->second; + } else { + for (size_t i = 0; i < m_slots.size(); ++i) { + if (free(i)) { + slot = i; + break; + } + } + } + if (slot == Bluetooth::kRemoteSlots) return; + m_slots[slot] = remote; + m_lastSlot[key] = slot; + it = m_waiting.erase(it); + } +} + +void Manager::ReadLoop(std::shared_ptr remote) { + std::array buffer{}; + while (remote->alive) { + const int read = SDL_hid_read_timeout(remote->device, buffer.data(), buffer.size(), kReadTimeoutMs); + if (read < 0) { + remote->alive = false; + remote->writeCv.notify_all(); + break; + } + if (read == 0) continue; + const size_t size = ReportSize(buffer[0], static_cast(read)); + if (size == 0) continue; + Report report(buffer.begin(), buffer.begin() + static_cast(size)); + + if (report[0] == 0x20) { + remote->battery = BatteryBars(report[6]); + const bool attached = (report[3] & 0x02) != 0; + remote->extensionAttached = attached; + if (!attached) remote->extension = -1; + } else if (report[0] == 0x21 && (report[3] & 0x0F) == 0 && report[4] == 0x00 && report[5] == 0xFA && + (report[3] >> 4) >= 5) { + // The game reading the extension id at 0xA400FA (before encryption). + remote->extension = report[11]; + } + + const Phase phase = remote->phase; + if (phase == Phase::Linked) { + std::lock_guard lock(remote->inputMutex); + if (remote->input.size() >= kInputQueueLimit) { + auto stale = std::find_if(remote->input.begin(), remote->input.end(), + [](const Report& r) { return r[0] >= 0x30; }); + remote->input.erase(stale != remote->input.end() ? stale : remote->input.begin()); + } + remote->input.push_back(std::move(report)); + } else if (Buttons(report) != 0) { + if (phase == Phase::Asleep) { + remote->phase = Phase::Waiting; + remote->writeCv.notify_one(); + } + if (phase == Phase::Asleep || phase == Phase::Waiting) { + remote->wake = true; + } + } + } +} + +void Manager::WriteLoop(std::shared_ptr remote) { + auto lastWrite = Clock::now(); + auto lastBlink = Clock::time_point{}; + bool blinkOn = false; + bool appliedRumble = false; + Phase lastPhase = Phase::Linked; // forces the quiet setup on the first pass + const auto write = [&](const Report& report) { + if (SDL_hid_write(remote->device, report.data(), report.size()) < 0) { + remote->alive = false; + return false; + } + lastWrite = Clock::now(); + return true; + }; + while (remote->alive) { + std::deque batch; + { + std::unique_lock lock(remote->writeMutex); + remote->writeCv.wait_for(lock, std::chrono::milliseconds(100), + [&] { return !remote->alive || !remote->writes.empty(); }); + batch.swap(remote->writes); + } + const bool rumbleAllowed = PAD_HLE_RumbleEnabled(); + const Phase phase = remote->phase; + // Queued just before the game let go of the remote. + if (phase != Phase::Linked) batch.clear(); + for (Report& report : batch) { + if (report.size() >= 2 && !rumbleAllowed) report[1] &= 0xFE; + if (!write(report)) break; + if (report.size() >= 2) appliedRumble = (report[1] & 0x01) != 0; + } + if (!remote->alive) break; + + const auto now = Clock::now(); + if (phase != lastPhase && phase != Phase::Linked && phase != Phase::PoweringOff) { + // Stop streaming and rumbling while the game does not own the remote. + if (!write({0x12, 0x00, 0x30}) || !write({0x11, 0x00})) break; + appliedRumble = false; + blinkOn = false; + lastBlink = now; + } + lastPhase = phase; + if (phase == Phase::Waiting && now - lastBlink >= kBlinkInterval) { + // Like a remote looking for its console. + blinkOn = !blinkOn; + lastBlink = now; + if (!write({0x11, static_cast(blinkOn ? 0xF0 : 0x00)})) break; + } else if (phase == Phase::Linked) { + const bool wanted = remote->gameRumble && rumbleAllowed; + if (wanted != appliedRumble || now - lastWrite >= kKeepAlive) { + // Also how Windows notices a remote that went away. + if (!write({0x10, static_cast(wanted ? 0x01 : 0x00)})) break; + appliedRumble = wanted; + } + } else if (phase == Phase::Asleep && now - lastWrite >= kKeepAlive) { + if (!write({0x10, 0x00})) break; + } + } + remote->writeCv.notify_all(); +} + +void Manager::DiscoveryLoop() { + while (m_running) { + bool search = false; + bool automatic = false; + { + std::unique_lock lock(m_discoveryMutex); + const auto now = Clock::now(); + bool anyRemote = false; + { + std::lock_guard slotLock(m_mutex); + for (const auto& remote : m_slots) anyRemote |= remote != nullptr; + anyRemote |= !m_waiting.empty(); + } + const bool requested = m_guestSearching || now < m_guestSearchUntil || now < m_pairingUntil; + automatic = !requested && !anyRemote && RuntimeConfigFile::WiiAutoPairEnabled(); + search = requested || automatic; + if (!search) { + m_searching = false; + m_discoveryCv.wait_for(lock, std::chrono::seconds(1)); + continue; + } + } + m_searching = true; + std::string status; + const int connected = Platform::DiscoverAndPair(m_cancelDiscovery, status); + { + std::lock_guard lock(m_discoveryMutex); + if (!status.empty()) m_pairingStatus = status; + if (connected > 0) { + m_scanCv.notify_all(); + } + } + if (automatic && connected == 0) { + std::unique_lock lock(m_discoveryMutex); + m_discoveryCv.wait_for(lock, kAutoPairPause, [this] { + return !m_running || m_guestSearching || Clock::now() < m_pairingUntil; + }); + } + } + m_searching = false; +} + +SlotInfo Manager::Slot(size_t slot) { + SlotInfo info; + std::shared_ptr remote; + { + std::lock_guard lock(m_mutex); + if (slot >= m_slots.size()) return info; + remote = m_slots[slot]; + info.link = m_links[slot]; + } + if (!remote || !remote->alive || remote->phase == Phase::PoweringOff) { + info.link = Bluetooth::LinkState::Down; + return info; + } + info.attached = true; + info.asleep = remote->phase == Phase::Asleep; + info.model = remote->plus ? "Wii Remote Plus" : "Wii Remote"; + if (remote->extensionAttached) { + switch (remote->extension.load()) { + case 0x00: info.extension = "Nunchuk"; break; + case 0x01: info.extension = "Classic Controller"; break; + case 0x03: info.extension = "Classic Controller Pro"; break; + default: info.extension = "Extension"; break; + } + } + info.battery = remote->battery; + return info; +} + +PairingInfo Manager::Pairing() { + PairingInfo info; + info.supported = Platform::Query().pairing && m_running; + info.searching = m_searching; + std::lock_guard lock(m_discoveryMutex); + info.status = m_pairingStatus; + return info; +} + +void Manager::StartPairing() { + { + std::lock_guard lock(m_discoveryMutex); + m_pairingUntil = Clock::now() + kPairingWindow; + m_pairingStatus = "Press the red SYNC button (or 1 and 2) on the Wii Remote."; + } + m_discoveryCv.notify_all(); +} + +void Manager::Disconnect(size_t slot) { + if (const auto remote = At(slot)) { + PowerOff(remote); + } +} + +size_t Manager::Waiting() { + std::lock_guard lock(m_mutex); + return m_waiting.size(); +} + +bool g_enabled = false; + +} // namespace HostDetail + +using namespace HostDetail; + +void ConfigureSdlHints(bool enabled) { + g_enabled = enabled; + // The remotes belong to the game's Bluetooth stack: SDL must not open them + // as gamepads (its own Wii driver, or the Linux kernel driver's evdev nodes). + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_WII, enabled ? "0" : "1"); + if (enabled) { + std::string ignored = "0x057e/0x0306,0x057e/0x0330"; + if (const char* existing = SDL_GetHint(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES); existing && *existing) { + ignored = std::string(existing) + "," + ignored; + } + SDL_SetHint(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES, ignored.c_str()); + } +} + +void Initialize() { + if (g_enabled) { + TheManager().Start(); + } +} + +void Shutdown() { + TheManager().Stop(); +} + +Bluetooth::RemoteHost& Host() { + return TheManager(); +} + +SlotInfo Slot(size_t slot) { + return TheManager().Slot(slot); +} + +PairingInfo Pairing() { + return TheManager().Pairing(); +} + +void StartPairing() { + TheManager().StartPairing(); +} + +void Disconnect(size_t slot) { + TheManager().Disconnect(slot); +} + +std::string PlatformNotice() { + return g_enabled ? Platform::Notice() : std::string(); +} + +size_t WaitingRemotes() { + return TheManager().Waiting(); +} + +} // namespace Wiimote diff --git a/runtime/src/wiimote/wiimote_platform_unix.cpp b/runtime/src/wiimote/wiimote_platform_unix.cpp new file mode 100644 index 0000000..970ed13 --- /dev/null +++ b/runtime/src/wiimote/wiimote_platform_unix.cpp @@ -0,0 +1,496 @@ +#if !defined(_WIN32) + +#include "wiimote_platform.h" + +#include "runtime_log.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__linux__) +#include +#include + +#include +#endif + +namespace Wiimote::Platform { +namespace Detail { + +std::string Narrow(const wchar_t* text) { + std::string out; + if (text != nullptr) { + for (const wchar_t* c = text; *c != L'\0'; ++c) out += static_cast(*c < 128 ? *c : '?'); + } + return out; +} + +std::string HexDigits(const std::string& text) { + std::string hex; + for (const char c : text) { + if (std::isxdigit(static_cast(c))) hex += static_cast(std::tolower(static_cast(c))); + } + return hex; +} + +std::mutex g_noticeMutex; +std::string g_notice; + +void SetNotice(const std::string& notice) { + std::lock_guard lock(g_noticeMutex); + g_notice = notice; +} + +#if defined(__linux__) + +// BlueZ over the system bus. libdbus-1 is loaded at run time so a system +// without it still runs (pairing then falls back to the desktop's tools). +extern "C" { +struct BzConnection; +struct BzMessage; +struct BzError { + const char* name; + const char* message; + unsigned int dummy1 : 1; + unsigned int dummy2 : 1; + unsigned int dummy3 : 1; + unsigned int dummy4 : 1; + unsigned int dummy5 : 1; + void* padding1; +}; +// Mirrors DBusMessageIter. +struct BzIter { + void* dummy1; + void* dummy2; + uint32_t dummy3; + int dummy4; + int dummy5; + int dummy6; + int dummy7; + int dummy8; + int dummy9; + int dummy10; + int dummy11; + int pad1; + int pad2; + void* pad3; +}; +} + +constexpr int kBusSystem = 1; +constexpr int kTypeInvalid = 0; +constexpr int kTypeString = 's'; +constexpr int kTypeObjectPath = 'o'; +constexpr int kTypeBoolean = 'b'; +constexpr int kTypeInt16 = 'n'; +constexpr int kTypeArray = 'a'; +constexpr int kTypeVariant = 'v'; +constexpr int kTypeDictEntry = 'e'; +constexpr int kShortTimeoutMs = 2000; +constexpr int kPairTimeoutMs = 30000; +constexpr auto kInquiryTime = std::chrono::milliseconds(3840); + +struct Device { + std::string path; + std::string address; + std::string name; + bool paired = false; + bool connected = false; + bool trusted = false; + bool discovered = false; // has an RSSI: answered the current inquiry +}; + +class BlueZ { +public: + bool Load() { + if (m_loaded) return m_conn != nullptr; + m_loaded = true; + m_handle = dlopen("libdbus-1.so.3", RTLD_NOW | RTLD_LOCAL); + if (m_handle == nullptr) return false; + const bool ok = Bind(bus_get_private, "dbus_bus_get_private") && + Bind(connection_set_exit_on_disconnect, "dbus_connection_set_exit_on_disconnect") && + Bind(error_init, "dbus_error_init") && Bind(error_free, "dbus_error_free") && + Bind(message_new_method_call, "dbus_message_new_method_call") && + Bind(message_append_args, "dbus_message_append_args") && + Bind(send_with_reply_and_block, "dbus_connection_send_with_reply_and_block") && + Bind(message_unref, "dbus_message_unref") && + Bind(message_iter_init, "dbus_message_iter_init") && + Bind(message_iter_init_append, "dbus_message_iter_init_append") && + Bind(message_iter_open_container, "dbus_message_iter_open_container") && + Bind(message_iter_close_container, "dbus_message_iter_close_container") && + Bind(message_iter_append_basic, "dbus_message_iter_append_basic") && + Bind(message_iter_next, "dbus_message_iter_next") && + Bind(message_iter_recurse, "dbus_message_iter_recurse") && + Bind(message_iter_get_arg_type, "dbus_message_iter_get_arg_type") && + Bind(message_iter_get_basic, "dbus_message_iter_get_basic"); + if (!ok) return false; + BzError error; + error_init(&error); + m_conn = bus_get_private(kBusSystem, &error); + error_free(&error); + if (m_conn != nullptr) connection_set_exit_on_disconnect(m_conn, 0); + return m_conn != nullptr; + } + + // org.freedesktop.DBus.ObjectManager.GetManagedObjects on org.bluez. + bool Objects(std::string& adapter, std::vector& devices) { + BzMessage* reply = Call("/", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", kShortTimeoutMs); + if (reply == nullptr) return false; + BzIter root; + BzIter objects; + if (message_iter_init(reply, &root) && message_iter_get_arg_type(&root) == kTypeArray) { + message_iter_recurse(&root, &objects); + while (message_iter_get_arg_type(&objects) == kTypeDictEntry) { + BzIter entry; + message_iter_recurse(&objects, &entry); + const char* path = nullptr; + message_iter_get_basic(&entry, &path); + message_iter_next(&entry); + ReadObject(path != nullptr ? path : "", entry, adapter, devices); + message_iter_next(&objects); + } + } + message_unref(reply); + return true; + } + + bool Simple(const std::string& path, const char* interface, const char* method, int timeoutMs, + std::string* error = nullptr) { + BzMessage* reply = Call(path.c_str(), interface, method, timeoutMs, nullptr, error); + if (reply == nullptr) return false; + message_unref(reply); + return true; + } + + bool RemoveDevice(const std::string& adapter, const std::string& device) { + const char* path = device.c_str(); + BzMessage* reply = Call(adapter.c_str(), "org.bluez.Adapter1", "RemoveDevice", kShortTimeoutMs, + [&](BzMessage* message) { + return message_append_args(message, kTypeObjectPath, &path, kTypeInvalid) != 0; + }); + if (reply == nullptr) return false; + message_unref(reply); + return true; + } + + bool SetTrusted(const std::string& device) { + BzMessage* reply = Call(device.c_str(), "org.freedesktop.DBus.Properties", "Set", kShortTimeoutMs, + [&](BzMessage* message) { + const char* interface = "org.bluez.Device1"; + const char* property = "Trusted"; + if (!message_append_args(message, kTypeString, &interface, kTypeString, &property, + kTypeInvalid)) { + return false; + } + BzIter args; + BzIter variant; + message_iter_init_append(message, &args); + if (!message_iter_open_container(&args, kTypeVariant, "b", &variant)) return false; + const uint32_t value = 1; + message_iter_append_basic(&variant, kTypeBoolean, &value); + return message_iter_close_container(&args, &variant) != 0; + }); + if (reply == nullptr) return false; + message_unref(reply); + return true; + } + +private: + template + bool Bind(Fn& fn, const char* symbol) { + fn = reinterpret_cast(dlsym(m_handle, symbol)); + return fn != nullptr; + } + + template + BzMessage* Call(const char* path, const char* interface, const char* method, int timeoutMs, + Append append = nullptr, std::string* errorText = nullptr) { + BzMessage* message = message_new_method_call("org.bluez", path, interface, method); + if (message == nullptr) return nullptr; + if constexpr (!std::is_same_v) { + if (!append(message)) { + message_unref(message); + return nullptr; + } + } + BzError error; + error_init(&error); + BzMessage* reply = send_with_reply_and_block(m_conn, message, timeoutMs, &error); + message_unref(message); + if (reply == nullptr && errorText != nullptr && error.name != nullptr) { + *errorText = error.name; + } + error_free(&error); + return reply; + } + + // One object's a{sa{sv}} interface map. + void ReadObject(const std::string& path, BzIter& interfaces, std::string& adapter, std::vector& devices) { + if (message_iter_get_arg_type(&interfaces) != kTypeArray) return; + BzIter list; + message_iter_recurse(&interfaces, &list); + while (message_iter_get_arg_type(&list) == kTypeDictEntry) { + BzIter entry; + message_iter_recurse(&list, &entry); + const char* interface = nullptr; + message_iter_get_basic(&entry, &interface); + message_iter_next(&entry); + const std::string name = interface != nullptr ? interface : ""; + if (name == "org.bluez.Adapter1" && adapter.empty()) { + adapter = path; + } else if (name == "org.bluez.Device1") { + Device device; + device.path = path; + ReadDevice(entry, device); + devices.push_back(device); + } + message_iter_next(&list); + } + } + + void ReadDevice(BzIter& properties, Device& device) { + if (message_iter_get_arg_type(&properties) != kTypeArray) return; + BzIter list; + message_iter_recurse(&properties, &list); + while (message_iter_get_arg_type(&list) == kTypeDictEntry) { + BzIter entry; + message_iter_recurse(&list, &entry); + const char* key = nullptr; + message_iter_get_basic(&entry, &key); + message_iter_next(&entry); + BzIter value; + message_iter_recurse(&entry, &value); + const std::string name = key != nullptr ? key : ""; + const int type = message_iter_get_arg_type(&value); + if (type == kTypeString && (name == "Address" || name == "Name")) { + const char* text = nullptr; + message_iter_get_basic(&value, &text); + (name == "Address" ? device.address : device.name) = text != nullptr ? text : ""; + } else if (type == kTypeBoolean) { + uint32_t flag = 0; + message_iter_get_basic(&value, &flag); + if (name == "Paired") device.paired = flag != 0; + if (name == "Connected") device.connected = flag != 0; + if (name == "Trusted") device.trusted = flag != 0; + } else if (type == kTypeInt16 && name == "RSSI") { + device.discovered = true; + } + message_iter_next(&list); + } + } + + bool m_loaded = false; + void* m_handle = nullptr; + BzConnection* m_conn = nullptr; + BzConnection* (*bus_get_private)(int, BzError*) = nullptr; + void (*connection_set_exit_on_disconnect)(BzConnection*, unsigned int) = nullptr; + void (*error_init)(BzError*) = nullptr; + void (*error_free)(BzError*) = nullptr; + BzMessage* (*message_new_method_call)(const char*, const char*, const char*, const char*) = nullptr; + unsigned int (*message_append_args)(BzMessage*, int, ...) = nullptr; + BzMessage* (*send_with_reply_and_block)(BzConnection*, BzMessage*, int, BzError*) = nullptr; + void (*message_unref)(BzMessage*) = nullptr; + unsigned int (*message_iter_init)(BzMessage*, BzIter*) = nullptr; + void (*message_iter_init_append)(BzMessage*, BzIter*) = nullptr; + unsigned int (*message_iter_open_container)(BzIter*, int, const char*, BzIter*) = nullptr; + unsigned int (*message_iter_close_container)(BzIter*, BzIter*) = nullptr; + unsigned int (*message_iter_append_basic)(BzIter*, int, const void*) = nullptr; + unsigned int (*message_iter_next)(BzIter*) = nullptr; + void (*message_iter_recurse)(BzIter*, BzIter*) = nullptr; + int (*message_iter_get_arg_type)(BzIter*) = nullptr; + void (*message_iter_get_basic)(BzIter*, void*) = nullptr; +}; + +// Every call happens on the discovery thread or the power-off worker. +std::timed_mutex g_busMutex; + +BlueZ* Bus() { + static BlueZ bus; + static const bool ok = bus.Load(); + return ok ? &bus : nullptr; +} + +// A remote that was just paired needs a few seconds to connect; until then it +// must not be taken for a stale pairing. +std::vector> g_recent; + +bool RecentlyPaired(const std::string& path) { + const auto now = std::chrono::steady_clock::now(); + g_recent.erase(std::remove_if(g_recent.begin(), g_recent.end(), + [&](const auto& entry) { return now - entry.second > std::chrono::seconds(30); }), + g_recent.end()); + return std::any_of(g_recent.begin(), g_recent.end(), [&](const auto& entry) { return entry.first == path; }); +} + +bool IsRemoteName(const std::string& name) { + return name.rfind("Nintendo RVL-CNT-01", 0) == 0 && name.find("-UC") == std::string::npos; +} + +std::string DriverOf(const std::string& hidrawPath) { + const std::filesystem::path node(hidrawPath); + std::error_code error; + const auto driver = + std::filesystem::read_symlink(std::filesystem::path("/sys/class/hidraw") / node.filename() / "device" / "driver", + error); + return error ? std::string() : driver.filename().string(); +} + +#endif + +} // namespace Detail + +using namespace Detail; + +Capabilities Query() { +#if defined(__linux__) + // Cached: adapters rarely change and this is asked often. + static std::mutex mutex; + static Capabilities cached; + static std::chrono::steady_clock::time_point checked{}; + std::lock_guard cacheLock(mutex); + const auto now = std::chrono::steady_clock::now(); + if (checked == std::chrono::steady_clock::time_point{} || now - checked > std::chrono::seconds(10)) { + // A search holds the bus for seconds; keep the cached answer rather than wait. + std::unique_lock lock(g_busMutex, std::try_to_lock); + if (!lock.owns_lock()) return cached; + checked = now; + std::string adapter; + std::vector devices; + BlueZ* bus = Bus(); + cached.pairing = cached.powerOff = bus != nullptr && bus->Objects(adapter, devices) && !adapter.empty(); + } + return cached; +#else + return {}; +#endif +} + +int DiscoverAndPair(const std::atomic& cancel, std::string& status) { +#if defined(__linux__) + std::lock_guard lock(g_busMutex); + BlueZ* bus = Bus(); + std::string adapter; + std::vector devices; + if (bus == nullptr || !bus->Objects(adapter, devices) || adapter.empty()) { + status = "No Bluetooth adapter found."; + return 0; + } + bus->Simple(adapter, "org.bluez.Adapter1", "StartDiscovery", kShortTimeoutMs); + int connected = 0; + const auto deadline = std::chrono::steady_clock::now() + kInquiryTime; + std::vector handled; + while (!cancel && std::chrono::steady_clock::now() < deadline) { + devices.clear(); + bus->Objects(adapter, devices); + for (const Device& device : devices) { + if (!IsRemoteName(device.name) || device.connected || !device.discovered) continue; + if (std::find(handled.begin(), handled.end(), device.path) != handled.end() || RecentlyPaired(device.path)) { + continue; + } + if (device.paired) { + // In pairing mode while paired: the remote forgot this PC. + bus->RemoveDevice(adapter, device.path); + continue; + } + handled.push_back(device.path); + // BlueZ's wiimote plugin answers the PIN (SYNC or 1+2). + std::string error; + if (bus->Simple(device.path, "org.bluez.Device1", "Pair", kPairTimeoutMs, &error)) { + bus->SetTrusted(device.path); + g_recent.emplace_back(device.path, std::chrono::steady_clock::now()); + if (bus->Simple(device.path, "org.bluez.Device1", "Connect", kPairTimeoutMs, &error)) { + ++connected; + status = "Wii Remote paired. It reconnects with any button from now on."; + RT_LOG(RT_TAG_HLE) << "Wii Remote " << device.address << " paired" << std::endl; + continue; + } + } + status = "Could not pair the Wii Remote. Press its red SYNC button and try again."; + RT_LOG(RT_TAG_HLE) << "Wii Remote " << device.address << ": pairing failed (" << error << ")" << std::endl; + } + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + } + bus->Simple(adapter, "org.bluez.Adapter1", "StopDiscovery", kShortTimeoutMs); + return connected; +#else + (void)cancel; + status = "Pair the Wii Remote in the system's Bluetooth settings."; + return 0; +#endif +} + +bool PowerOff(const std::string& address) { +#if defined(__linux__) + std::unique_lock lock(g_busMutex, std::chrono::milliseconds(kShortTimeoutMs)); + if (!lock.owns_lock()) return false; + BlueZ* bus = Bus(); + std::string adapter; + std::vector devices; + if (bus == nullptr || !bus->Objects(adapter, devices)) return false; + for (const Device& device : devices) { + if (HexDigits(device.address) == address) { + return bus->Simple(device.path, "org.bluez.Device1", "Disconnect", kShortTimeoutMs); + } + } +#else + (void)address; +#endif + return false; +} + +std::string AddressFor(const SDL_hid_device_info& info) { + const std::string hex = HexDigits(Narrow(info.serial_number)); + return hex.size() == 12 && hex != "000000000000" ? hex : std::string(); +} + +std::string NameFor(const std::string& address, const SDL_hid_device_info& info) { + (void)address; + return Narrow(info.product_string); +} + +bool MaybeConnected(const std::string& address) { + (void)address; + return true; +} + +bool Usable(const SDL_hid_device_info& info) { +#if defined(__linux__) + if (info.path == nullptr) return false; + if (DriverOf(info.path) == "wiimote") { + SetNotice("The Linux hid-wiimote driver holds the Wii Remote, so the game cannot use it. Run " + "\"sudo modprobe -r hid_wiimote\" and add \"blacklist hid_wiimote\" to /etc/modprobe.d/wiimote.conf."); + return false; + } + if (access(info.path, R_OK | W_OK) != 0) { + SetNotice("No permission to open the Wii Remote. Add the udev rule " + "KERNEL==\"hidraw*\", KERNELS==\"0005:057E:*\", MODE=\"0666\" and reconnect it."); + return false; + } + SetNotice({}); +#else + (void)info; +#endif + return true; +} + +std::string Notice() { + std::lock_guard lock(g_noticeMutex); +#if defined(__APPLE__) + if (g_notice.empty()) return "Pair Wii Remotes in System Settings > Bluetooth, then press a button on them."; +#endif + return g_notice; +} + +} // namespace Wiimote::Platform + +#endif diff --git a/runtime/src/wiimote/wiimote_platform_windows.cpp b/runtime/src/wiimote/wiimote_platform_windows.cpp new file mode 100644 index 0000000..883294e --- /dev/null +++ b/runtime/src/wiimote/wiimote_platform_windows.cpp @@ -0,0 +1,300 @@ +#if defined(_WIN32) + +#include "wiimote_platform.h" + +#include "runtime_log.h" + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace Wiimote::Platform { +namespace Detail { + +// bthioctl.h IOCTL_BTH_DISCONNECT_DEVICE: CTL_CODE(FILE_DEVICE_BLUETOOTH, 0x03, METHOD_BUFFERED, FILE_ANY_ACCESS). +constexpr DWORD kIoctlBthDisconnectDevice = 0x0041000C; +const GUID kHidServiceClass = {0x00001124, 0x0000, 0x1000, {0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}}; +// Each inquiry lasts this many 1.28 s units. +constexpr UCHAR kInquiryUnits = 3; + +struct Radio { + HANDLE handle = nullptr; + BLUETOOTH_RADIO_INFO info{}; +}; + +class Radios { +public: + Radios() { + BLUETOOTH_FIND_RADIO_PARAMS params{sizeof(params)}; + HANDLE radio = nullptr; + HBLUETOOTH_RADIO_FIND find = BluetoothFindFirstRadio(¶ms, &radio); + if (find == nullptr) return; + do { + Radio entry; + entry.handle = radio; + entry.info.dwSize = sizeof(entry.info); + if (BluetoothGetRadioInfo(radio, &entry.info) == ERROR_SUCCESS) { + m_radios.push_back(entry); + } else { + CloseHandle(radio); + } + } while (BluetoothFindNextRadio(find, &radio)); + BluetoothFindRadioClose(find); + } + ~Radios() { + for (const Radio& radio : m_radios) CloseHandle(radio.handle); + } + Radios(const Radios&) = delete; + Radios& operator=(const Radios&) = delete; + const std::vector& All() const { return m_radios; } + +private: + std::vector m_radios; +}; + +bool IsRemoteName(const WCHAR* name) { + const std::wstring text = name; + return text.rfind(L"Nintendo RVL-CNT-01", 0) == 0 && text.find(L"-UC") == std::wstring::npos; +} + +std::string Hex(const BLUETOOTH_ADDRESS& address) { + char text[13]; + std::snprintf(text, sizeof(text), "%012llx", static_cast(address.ullLong & 0xFFFFFFFFFFFFull)); + return text; +} + +bool ParseHex(const std::string& text, BLUETOOTH_ADDRESS& address) { + if (text.size() != 12) return false; + address.ullLong = std::stoull(text, nullptr, 16); + return true; +} + +ULONGLONG FileTimeOf(const SYSTEMTIME& time) { + FILETIME file{}; + if (!SystemTimeToFileTime(&time, &file)) return 0; + return (static_cast(file.dwHighDateTime) << 32) | file.dwLowDateTime; +} + +ULONGLONG Now() { + SYSTEMTIME now{}; + GetSystemTime(&now); + return FileTimeOf(now); +} + +// The remote takes the host's address as PIN after its SYNC button, its own +// address after 1+2; both as raw bytes, least significant first. +DWORD Authenticate(const Radio& radio, BLUETOOTH_DEVICE_INFO& device, const BLUETOOTH_ADDRESS& pinAddress) { + WCHAR pin[6]; + for (int i = 0; i < 6; ++i) pin[i] = pinAddress.rgBytes[i]; + return BluetoothAuthenticateDevice(nullptr, radio.handle, &device, pin, 6); +} + +// A remote that was just paired needs a few seconds to connect its HID service; +// until then it must not be taken for a stale pairing. +constexpr auto kPairingSettleTime = std::chrono::seconds(30); +std::mutex g_recentMutex; +std::vector> g_recent; + +bool RecentlyPaired(const std::string& address) { + std::lock_guard lock(g_recentMutex); + const auto now = std::chrono::steady_clock::now(); + g_recent.erase(std::remove_if(g_recent.begin(), g_recent.end(), + [&](const auto& entry) { return now - entry.second > kPairingSettleTime; }), + g_recent.end()); + return std::any_of(g_recent.begin(), g_recent.end(), [&](const auto& entry) { return entry.first == address; }); +} + +void MarkPaired(const std::string& address) { + std::lock_guard lock(g_recentMutex); + g_recent.emplace_back(address, std::chrono::steady_clock::now()); +} + +std::vector Devices(const Radio& radio, bool inquiry) { + std::vector devices; + BLUETOOTH_DEVICE_SEARCH_PARAMS params{sizeof(params)}; + params.fReturnAuthenticated = TRUE; + params.fReturnRemembered = TRUE; + params.fReturnUnknown = TRUE; + params.fReturnConnected = TRUE; + params.fIssueInquiry = inquiry ? TRUE : FALSE; + params.cTimeoutMultiplier = inquiry ? kInquiryUnits : 0; + params.hRadio = radio.handle; + BLUETOOTH_DEVICE_INFO device{sizeof(device)}; + HBLUETOOTH_DEVICE_FIND find = BluetoothFindFirstDevice(¶ms, &device); + if (find == nullptr) return devices; + do { + devices.push_back(device); + device = BLUETOOTH_DEVICE_INFO{sizeof(device)}; + } while (BluetoothFindNextDevice(find, &device)); + BluetoothFindDeviceClose(find); + return devices; +} + +} // namespace Detail + +using namespace Detail; + +Capabilities Query() { + // Cached: radios rarely change and this is asked often. + static std::mutex mutex; + static Capabilities cached; + static std::chrono::steady_clock::time_point checked{}; + std::lock_guard lock(mutex); + const auto now = std::chrono::steady_clock::now(); + if (checked == std::chrono::steady_clock::time_point{} || now - checked > std::chrono::seconds(10)) { + checked = now; + const Radios radios; + cached.pairing = cached.powerOff = !radios.All().empty(); + } + return cached; +} + +int DiscoverAndPair(const std::atomic& cancel, std::string& status) { + const Radios radios; + if (radios.All().empty()) { + status = "No Bluetooth adapter found."; + return 0; + } + int connected = 0; + for (const Radio& radio : radios.All()) { + // A remote Windows remembers without a bond can never reconnect. + for (BLUETOOTH_DEVICE_INFO& device : Devices(radio, false)) { + if (IsRemoteName(device.szName) && device.fRemembered && !device.fConnected && !device.fAuthenticated) { + BluetoothRemoveDevice(&device.Address); + } + } + if (cancel) return connected; + const ULONGLONG started = Now(); + std::vector seen; + for (BLUETOOTH_DEVICE_INFO& found : Devices(radio, true)) { + if (cancel) return connected; + if (!IsRemoteName(found.szName) || std::find(seen.begin(), seen.end(), found.Address.ullLong) != seen.end()) { + continue; + } + seen.push_back(found.Address.ullLong); + const std::string address = Hex(found.Address); + if (RecentlyPaired(address)) continue; + // The inquiry results can be seconds old: act on the current state. + BLUETOOTH_DEVICE_INFO device = found; + BluetoothGetDeviceInfo(radio.handle, &device); + if (device.fConnected) continue; + // Only a remote in pairing mode answers an inquiry; remembered ones + // that did not answer keep their old timestamp. + const bool answered = !device.fRemembered || FileTimeOf(found.stLastSeen) >= started; + if (!answered) continue; + if (device.fRemembered) { + // Paired before, but in pairing mode now: it forgot this PC. + BluetoothRemoveDevice(&device.Address); + device.fAuthenticated = FALSE; + device.fRemembered = FALSE; + } + DWORD result = Authenticate(radio, device, radio.info.address); + const bool permanent = result == ERROR_SUCCESS; + if (!permanent) { + result = Authenticate(radio, device, device.Address); + } + if (result == ERROR_SUCCESS) { + // Windows only keeps the pairing once the services were read. + DWORD count = 0; + BluetoothEnumerateInstalledServices(radio.handle, &device, &count, nullptr); + } + const DWORD service = + BluetoothSetServiceState(radio.handle, &device, const_cast(&kHidServiceClass), BLUETOOTH_SERVICE_ENABLE); + if (result == ERROR_SUCCESS || service == ERROR_SUCCESS) { + ++connected; + MarkPaired(address); + status = permanent ? "Wii Remote paired. It reconnects with any button from now on." + : "Wii Remote connected for this session (press SYNC to pair it for good)."; + RT_LOG(RT_TAG_HLE) << "Wii Remote " << address << (permanent ? " paired (SYNC)" : " connected (1+2)") + << std::endl; + } else { + status = "Could not pair the Wii Remote. Press its red SYNC button and try again."; + RT_LOG(RT_TAG_HLE) << "Wii Remote " << address << ": pairing failed (" << result << ", " << service + << ")" << std::endl; + } + } + } + return connected; +} + +bool PowerOff(const std::string& address) { + BLUETOOTH_ADDRESS target{}; + if (!ParseHex(address, target)) return false; + const Radios radios; + for (const Radio& radio : radios.All()) { + ULONGLONG raw = target.ullLong; + DWORD returned = 0; + if (DeviceIoControl(radio.handle, kIoctlBthDisconnectDevice, &raw, sizeof(raw), nullptr, 0, &returned, + nullptr)) { + return true; + } + } + return false; +} + +std::string AddressFor(const SDL_hid_device_info& info) { + // Bluetooth HID devices report the remote's address as their serial number. + std::string hex; + if (info.serial_number != nullptr) { + for (const wchar_t* c = info.serial_number; *c != L'\0'; ++c) { + if (*c < 128 && std::isxdigit(static_cast(*c))) hex += static_cast(std::tolower(*c)); + } + } + return hex.size() == 12 && hex != "000000000000" ? hex : std::string(); +} + +std::string NameFor(const std::string& address, const SDL_hid_device_info& info) { + BLUETOOTH_ADDRESS target{}; + if (ParseHex(address, target)) { + const Radios radios; + for (const Radio& radio : radios.All()) { + BLUETOOTH_DEVICE_INFO device{sizeof(device)}; + device.Address = target; + if (BluetoothGetDeviceInfo(radio.handle, &device) == ERROR_SUCCESS && device.szName[0] != L'\0') { + std::string name; + for (const WCHAR* c = device.szName; *c != L'\0'; ++c) name += static_cast(*c < 128 ? *c : '?'); + return name; + } + } + } + std::string name; + if (info.product_string != nullptr) { + for (const wchar_t* c = info.product_string; *c != L'\0'; ++c) name += static_cast(*c < 128 ? *c : '?'); + } + return name; +} + +bool MaybeConnected(const std::string& address) { + BLUETOOTH_ADDRESS target{}; + if (!ParseHex(address, target)) return true; + const Radios radios; + for (const Radio& radio : radios.All()) { + BLUETOOTH_DEVICE_INFO device{sizeof(device)}; + device.Address = target; + if (BluetoothGetDeviceInfo(radio.handle, &device) == ERROR_SUCCESS) { + return device.fConnected != FALSE; + } + } + return true; +} + +bool Usable(const SDL_hid_device_info&) { + return true; +} + +std::string Notice() { + return Query().pairing ? std::string() : std::string("No Bluetooth adapter found."); +} + +} // namespace Wiimote::Platform + +#endif diff --git a/runtime/tests/bluetooth_controller_tests.cpp b/runtime/tests/bluetooth_controller_tests.cpp new file mode 100644 index 0000000..99e05a2 --- /dev/null +++ b/runtime/tests/bluetooth_controller_tests.cpp @@ -0,0 +1,368 @@ +#include "bluetooth/bt_controller.h" +#include "bluetooth/bt_sdp.h" + +#include +#include +#include +#include +#include + +namespace { + +using Bytes = std::vector; +using Bluetooth::BdAddr; +using Bluetooth::Controller; +using Bluetooth::LinkState; + +int g_failures = 0; + +#define CHECK(cond) \ + do { \ + if (!(cond)) { \ + std::fprintf(stderr, "%s:%d: CHECK failed: %s\n", __FILE__, __LINE__, #cond); \ + ++g_failures; \ + } \ + } while (0) + +struct FakeHost : Bluetooth::RemoteHost { + std::array attached{}; + std::array wake{}; + std::array, Bluetooth::kRemoteSlots> input; + std::vector> output; + std::array states{}; + std::vector guestDisconnects; + bool inquiry = false; + + bool IsAttached(size_t slot) const override { return attached[slot]; } + bool ConsumeWake(size_t slot) override { + const bool w = wake[slot]; + wake[slot] = false; + return w; + } + bool PopInputReport(size_t slot, Bytes& report) override { + if (input[slot].empty()) return false; + report = input[slot].front(); + input[slot].pop_front(); + return true; + } + void SendOutputReport(size_t slot, const uint8_t* report, size_t size) override { + output.emplace_back(slot, Bytes(report, report + size)); + } + void OnLinkStateChanged(size_t slot, LinkState state) override { states[slot] = state; } + void OnGuestDisconnect(size_t slot) override { guestDisconnects.push_back(slot); } + void OnGuestInquiry(bool active) override { inquiry = active; } + const char* DeviceName(size_t) const override { return "Nintendo RVL-CNT-01"; } +}; + +uint16_t Le16(const Bytes& b, size_t i) { + return static_cast(b[i] | (b[i + 1] << 8)); +} + +void PutLe16(Bytes& b, uint16_t v) { + b.push_back(static_cast(v)); + b.push_back(static_cast(v >> 8)); +} + +Bytes Command(uint16_t opcode, Bytes params) { + Bytes packet; + PutLe16(packet, opcode); + packet.push_back(static_cast(params.size())); + packet.insert(packet.end(), params.begin(), params.end()); + return packet; +} + +struct Guest { + Controller& controller; + uint64_t now = 1000; + + std::vector Run(uint16_t opcode, Bytes params = {}) { + const Bytes packet = Command(opcode, std::move(params)); + controller.ExecuteCommand(packet.data(), packet.size(), now); + return Events(); + } + std::vector Events() { + std::vector events; + Bytes event; + while (controller.PopEvent(event)) events.push_back(event); + return events; + } + std::vector Acl() { + std::vector packets; + Bytes packet; + while (controller.PopAcl(packet)) packets.push_back(packet); + return packets; + } + void Tick() { + now += 1000; + controller.Tick(now); + } + void SendL2cap(uint16_t handle, uint16_t cid, const Bytes& payload) { + Bytes packet; + PutLe16(packet, static_cast(handle | 0x2000)); + PutLe16(packet, static_cast(payload.size() + 4)); + PutLe16(packet, static_cast(payload.size())); + PutLe16(packet, cid); + packet.insert(packet.end(), payload.begin(), payload.end()); + controller.ReceiveAcl(packet.data(), packet.size(), now); + } + void Signal(uint16_t handle, uint8_t code, uint8_t ident, const Bytes& data) { + Bytes payload = {code, ident}; + PutLe16(payload, static_cast(data.size())); + payload.insert(payload.end(), data.begin(), data.end()); + SendL2cap(handle, 0x0001, payload); + } +}; + +bool IsCommandComplete(const Bytes& e, uint16_t opcode) { + return e.size() >= 6 && e[0] == 0x0E && Le16(e, 3) == opcode && e[5] == 0x00; +} + +bool IsCommandStatusOk(const Bytes& e, uint16_t opcode) { + return e.size() == 6 && e[0] == 0x0F && e[2] == 0x00 && Le16(e, 4) == opcode; +} + +// Splits a signalling ACL packet from the remote into (code, ident, data). +struct Signal { + uint8_t code = 0; + uint8_t ident = 0; + Bytes data; +}; + +std::vector Signals(const std::vector& acl) { + std::vector out; + for (const Bytes& packet : acl) { + if (packet.size() < 8 || Le16(packet, 6) != 0x0001) continue; + size_t i = 8; + while (i + 4 <= packet.size()) { + Signal s; + s.code = packet[i]; + s.ident = packet[i + 1]; + const uint16_t length = Le16(packet, i + 2); + s.data.assign(packet.begin() + static_cast(i + 4), + packet.begin() + static_cast(i + 4 + length)); + out.push_back(s); + i += 4 + length; + } + } + return out; +} + +// Opens one HID channel the remote requested and completes both configurations. +uint16_t AcceptRemoteChannel(Guest& guest, uint16_t handle, uint16_t psm, uint16_t guestCid) { + guest.Events(); + const auto requests = Signals(guest.Acl()); + CHECK(requests.size() == 1); + if (requests.size() != 1) return 0; + CHECK(requests[0].code == 0x02 && Le16(requests[0].data, 0) == psm); + const uint16_t remoteCid = Le16(requests[0].data, 2); + Bytes rsp; + PutLe16(rsp, guestCid); + PutLe16(rsp, remoteCid); + PutLe16(rsp, 0); + PutLe16(rsp, 0); + guest.Signal(handle, 0x03, requests[0].ident, rsp); + const auto config = Signals(guest.Acl()); + CHECK(config.size() == 1 && config[0].code == 0x04 && Le16(config[0].data, 0) == guestCid); + Bytes cfg; + PutLe16(cfg, remoteCid); + PutLe16(cfg, 0); + cfg.insert(cfg.end(), {0x01, 0x02, 0xA0, 0x02}); + guest.Signal(handle, 0x04, 0x40, cfg); + const auto cfgRsp = Signals(guest.Acl()); + CHECK(cfgRsp.size() == 1 && cfgRsp[0].code == 0x05 && cfgRsp[0].ident == 0x40 && + Le16(cfgRsp[0].data, 0) == guestCid && Le16(cfgRsp[0].data, 4) == 0); + Bytes ourCfgRsp; + PutLe16(ourCfgRsp, remoteCid); + PutLe16(ourCfgRsp, 0); + PutLe16(ourCfgRsp, 0); + if (!config.empty()) guest.Signal(handle, 0x05, config[0].ident, ourCfgRsp); + return remoteCid; +} + +void TestBootAndConnection() { + FakeHost host; + Controller controller(host); + Guest guest{controller}; + controller.Open(guest.now); + + auto e = guest.Run(0x0C03); + CHECK(e.size() == 1 && IsCommandComplete(e[0], 0x0C03)); + e = guest.Run(0x1005); + CHECK(e.size() == 1 && IsCommandComplete(e[0], 0x1005) && Le16(e[0], 6) == 339 && Le16(e[0], 9) == 10); + e = guest.Run(0x1009); + CHECK(e.size() == 1 && IsCommandComplete(e[0], 0x1009) && e[0][11] == 0xFF); + e = guest.Run(0x1001); + CHECK(e.size() == 1 && IsCommandComplete(e[0], 0x1001) && Le16(e[0], 7) == 0x40A7); + e = guest.Run(0x1003); + CHECK(e.size() == 1 && IsCommandComplete(e[0], 0x1003)); + e = guest.Run(0x0C0D, {0, 0, 0, 0, 0, 0, 1}); + CHECK(e.size() == 2 && e[0][0] == 0x15 && e[0][2] == 4 && IsCommandComplete(e[1], 0x0C0D) && + Le16(e[1], 8) == 4); + Bytes slot0Key; + if (!e.empty() && e[0].size() >= 25) slot0Key.assign(e[0].begin() + 9, e[0].begin() + 25); + e = guest.Run(0xFC4F, {0x00}); + CHECK(e.size() == 1 && IsCommandComplete(e[0], 0xFC4F)); + + // Attached remote, page scan off: nothing yet. + host.attached[0] = true; + host.wake[0] = true; + guest.Tick(); + CHECK(guest.Events().empty()); + + e = guest.Run(0x0C1A, {0x02}); + CHECK(e.size() == 1 && IsCommandComplete(e[0], 0x0C1A)); + guest.Tick(); + e = guest.Events(); + CHECK(e.size() == 1 && e[0][0] == 0x04 && e[0][7] == 0x00); + const BdAddr addr = Controller::RemoteAddress(0); + + Bytes accept(addr.begin(), addr.end()); + accept.push_back(0x00); + e = guest.Run(0x0409, accept); + CHECK(e.size() == 3 && IsCommandStatusOk(e[0], 0x0409) && e[1][0] == 0x12 && e[2][0] == 0x03 && + e[2][2] == 0x00 && Le16(e[2], 3) == 0x0100); + CHECK(host.states[0] == LinkState::Connecting); + + // Authentication with the stored key. + e = guest.Run(0x0411, {0x00, 0x01}); + CHECK(e.size() == 2 && IsCommandStatusOk(e[0], 0x0411) && e[1][0] == 0x17); + Bytes reply(addr.begin(), addr.end()); + reply.insert(reply.end(), slot0Key.begin(), slot0Key.end()); + e = guest.Run(0x040B, reply); + CHECK(e.size() == 2 && IsCommandComplete(e[0], 0x040B) && e[1][0] == 0x06 && e[1][2] == 0x00); + + guest.Tick(); + const uint16_t controlCid = AcceptRemoteChannel(guest, 0x0100, 0x0011, 0x0041); + CHECK(host.states[0] == LinkState::Connecting); + guest.Tick(); + const uint16_t interruptCid = AcceptRemoteChannel(guest, 0x0100, 0x0013, 0x0042); + CHECK(controlCid != 0 && interruptCid != 0); + CHECK(host.states[0] == LinkState::Ready); + + // Input passthrough. + host.input[0].push_back({0x30, 0x00, 0x08}); + guest.Tick(); + guest.Events(); + auto acl = guest.Acl(); + CHECK(acl.size() == 1); + if (acl.size() == 1) { + const Bytes& p = acl[0]; + CHECK(Le16(p, 0) == 0x2100 && Le16(p, 6) == 0x0042 && p[8] == 0xA1 && p[9] == 0x30 && p[11] == 0x08); + } + + // Output passthrough on the interrupt channel, and a SET_REPORT on control. + guest.SendL2cap(0x0100, interruptCid, {0xA2, 0x11, 0x10}); + guest.SendL2cap(0x0100, controlCid, {0x52, 0x15, 0x00}); + CHECK(host.output.size() == 2 && host.output[0].second == Bytes({0x11, 0x10}) && + host.output[1].second == Bytes({0x15, 0x00})); + acl = guest.Acl(); + CHECK(acl.size() == 1 && acl[0].size() == 9 && acl[0][8] == 0x00); + guest.Tick(); + e = guest.Events(); + CHECK(e.size() == 1 && e[0][0] == 0x13 && e[0][2] == 1 && Le16(e[0], 3) == 0x0100 && Le16(e[0], 5) == 2); + + // The game drops the remote: a real one powers off. + e = guest.Run(0x0406, {0x00, 0x01, 0x13}); + CHECK(e.size() == 2 && IsCommandStatusOk(e[0], 0x0406) && e[1][0] == 0x05 && e[1][5] == 0x16); + CHECK(host.guestDisconnects.size() == 1 && host.states[0] == LinkState::Down); + guest.Tick(); + CHECK(guest.Events().empty()); +} + +void TestInquiryAndPaging() { + FakeHost host; + Controller controller(host); + Guest guest{controller}; + controller.Open(guest.now); + guest.Run(0x0C45, {0x01}); + host.attached[1] = true; + host.wake[1] = true; + guest.Tick(); // consumes the wake; page scan is off + auto e = guest.Run(0x0401, {0x00, 0x8B, 0x9E, 0x03, 0x01}); + CHECK(e.size() == 1 && IsCommandStatusOk(e[0], 0x0401) && host.inquiry); + guest.Tick(); + e = guest.Events(); + CHECK(e.size() == 1 && e[0][0] == 0x22 && e[0][8] == 0x01); + guest.Tick(); + e = guest.Events(); + CHECK(e.size() == 1 && e[0][0] == 0x01); + CHECK(!host.inquiry); + Bytes create; + const BdAddr addr = Controller::RemoteAddress(1); + create.insert(create.end(), addr.begin(), addr.end()); + create.insert(create.end(), {0x18, 0xCC, 0x01, 0x00, 0x00, 0x00, 0x00}); + e = guest.Run(0x0405, create); + CHECK(e.size() == 2 && IsCommandStatusOk(e[0], 0x0405) && e[1][0] == 0x03 && e[1][2] == 0x00 && + Le16(e[1], 3) == 0x0101); + + // Paging a remote that is not there times out. + const BdAddr missing = Controller::RemoteAddress(2); + Bytes create2(missing.begin(), missing.end()); + create2.insert(create2.end(), {0x18, 0xCC, 0x01, 0x00, 0x00, 0x00, 0x00}); + e = guest.Run(0x0405, create2); + CHECK(e.size() == 1); + guest.now += 6'000'000; + guest.Tick(); + e = guest.Events(); + CHECK(e.size() == 1 && e[0][0] == 0x03 && e[0][2] == 0x04); + + // The guest opens SDP itself on a paged remote. + Bytes sdpReq; + PutLe16(sdpReq, 0x0001); + PutLe16(sdpReq, 0x0050); + guest.Signal(0x0101, 0x02, 0x07, sdpReq); + const auto rsp = Signals(guest.Acl()); + CHECK(rsp.size() == 2 && rsp[0].code == 0x03 && Le16(rsp[0].data, 4) == 0 && rsp[1].code == 0x04); +} + +void TestSdp() { + // ServiceAttributeRequest for the whole HID record. + const Bytes request = {0x04, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x01, 0x00, 0x00, 0xFF, 0xFF, + 0x35, 0x05, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0x00}; + const Bytes response = Bluetooth::Sdp::HandleRequest(request.data(), request.size(), 4096); + CHECK(response.size() > 10 && response[0] == 0x05); + if (response.size() > 10) { + const uint16_t count = static_cast((response[5] << 8) | response[6]); + CHECK(count == 0x01CC + 3 && response[7] == 0x36 && response[8] == 0x01 && response[9] == 0xCC); + CHECK(response.back() == 0x00); + } + CHECK(Bluetooth::Sdp::WiiRemoteHidDescriptor().size() == 0xD9); + + // Continuation with a small MTU reassembles to the same list. + Bytes assembled; + Bytes cont = {0x00}; + for (int guard = 0; guard < 64; ++guard) { + Bytes req = {0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, + 0x35, 0x05, 0x0A, 0x00, 0x00, 0xFF, 0xFF}; + req.insert(req.end(), cont.begin(), cont.end()); + req[4] = static_cast(req.size() - 5); + const Bytes part = Bluetooth::Sdp::HandleRequest(req.data(), req.size(), 48); + CHECK(part.size() <= 48 && part[0] == 0x05); + const uint16_t count = static_cast((part[5] << 8) | part[6]); + assembled.insert(assembled.end(), part.begin() + 7, part.begin() + 7 + count); + cont.assign(part.begin() + 7 + count, part.end()); + if (cont.size() == 1 && cont[0] == 0) break; + } + CHECK(assembled.size() == 0x01CC + 3); + + // Device ID record via ServiceSearchAttribute. + const Bytes search = {0x06, 0x00, 0x03, 0x00, 0x0F, 0x35, 0x03, 0x19, 0x12, 0x00, 0xFF, 0xFF, + 0x35, 0x05, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0x00}; + const Bytes found = Bluetooth::Sdp::HandleRequest(search.data(), search.size(), 4096); + CHECK(found.size() > 12 && found[0] == 0x07 && found[7] == 0x35 && found[9] == 0x36 && found[10] == 0x00 && + found[11] == 0x5A); +} + +} // namespace + +int main() { + TestBootAndConnection(); + TestInquiryAndPaging(); + TestSdp(); + if (g_failures != 0) { + std::fprintf(stderr, "%d check(s) failed\n", g_failures); + return EXIT_FAILURE; + } + std::printf("bluetooth controller tests passed\n"); + return EXIT_SUCCESS; +} diff --git a/runtime/tests/nand_settings_tests.cpp b/runtime/tests/nand_settings_tests.cpp index 3231911..9018a09 100644 --- a/runtime/tests/nand_settings_tests.cpp +++ b/runtime/tests/nand_settings_tests.cpp @@ -91,7 +91,7 @@ int main() { Require(settings && RuntimeNandSettings::HasIdentity(*settings)); Require(settings->at("SERNO") == "987654321" && settings->at("CODE") == "LU"); Require(settings->at("AREA") == "USA" && settings->at("GAME") == "US"); - Require(Ensure(root, error, 1800000123), "Existing imported NAND must work"); + Require(Ensure(root, error, {}, 1800000123), "Existing imported NAND must work"); std::array after{}; { std::ifstream input(path, std::ios::binary); @@ -112,11 +112,11 @@ int main() { std::filesystem::resize_file(path, 128); Require(!RuntimeNandSettings::Read(root)); const auto damaged = ReadBytes(path); - Require(!Ensure(root, error, 1800000123), "Do not replace a truncated identity"); + Require(!Ensure(root, error, {}, 1800000123), "Do not replace a truncated identity"); Require(ReadBytes(path) == damaged, "Damaged file must remain untouched"); const auto fresh = root / "fresh"; - Require(Ensure(fresh, error, 1800000123), "Missing setting.txt must initialize"); + Require(Ensure(fresh, error, {}, 1800000123), "Missing setting.txt must initialize"); const auto generated = Read(fresh); Require(generated && HasIdentity(*generated), "Generated file must be readable"); Require(generated->at("SERNO") == "800000123", "Persist Dolphin-generated serial"); @@ -127,13 +127,23 @@ int main() { "Complete Dolphin boot settings"); const auto firstBoot = ReadBytes(FilePath(fresh)); Require(firstBoot.size() == 256 && firstBoot.back() == 0, "Dolphin buffer size and raw zero padding"); - Require(Ensure(fresh, error, 1900000999), "Second boot"); + Require(Ensure(fresh, error, {}, 1900000999), "Second boot"); Require(ReadBytes(FilePath(fresh)) == firstBoot, "Second boot must not change any bytes"); + const auto freshNtsc = root / "fresh-ntsc"; + const BootDefaults ntscDefaults{"USA", "RVL-001(USA)", "LU", "NTSC", "US"}; + Require(Ensure(freshNtsc, error, ntscDefaults, 1800000123), "Regional setting.txt must initialize"); + const auto generatedNtsc = Read(freshNtsc); + Require(generatedNtsc && HasIdentity(*generatedNtsc), "Generated NTSC file must be readable"); + Require(generatedNtsc->at("CODE") == "LU" && generatedNtsc->at("AREA") == "USA" && + generatedNtsc->at("GAME") == "US", "NTSC first-boot fields"); + Require(generatedNtsc->at("MODEL") == "RVL-001(USA)" && generatedNtsc->at("VIDEO") == "NTSC", + "Complete NTSC boot settings"); + const auto blocked = root / "blocked"; { std::ofstream output(blocked); output << "file obstructing NAND directory"; } - Require(!Ensure(blocked, error, 1800000123), "Write failure must not return an ephemeral identity"); - Require(!Ensure(root / "bad-clock", error, -1), "Clock failure must not initialize"); + Require(!Ensure(blocked, error, {}, 1800000123), "Write failure must not return an ephemeral identity"); + Require(!Ensure(root / "bad-clock", error, {}, -1), "Clock failure must not initialize"); const auto concurrent = root / "concurrent"; std::array results{}; @@ -141,14 +151,14 @@ int main() { for (size_t i = 0; i < results.size(); ++i) { workers.emplace_back([&, i] { std::string detail; - results[i] = Ensure(concurrent, detail, 1800000001 + i); + results[i] = Ensure(concurrent, detail, {}, 1800000001 + i); }); } for (auto& worker : workers) worker.join(); for (const bool result : results) Require(result, "Concurrent boot must read the persisted winner"); const auto winner = ReadBytes(FilePath(concurrent)); Require(Read(concurrent) && HasIdentity(*Read(concurrent)), "Concurrent boot must persist valid settings"); - Require(Ensure(concurrent, error, 1900000999), "Boot after concurrent initialization"); + Require(Ensure(concurrent, error, {}, 1900000999), "Boot after concurrent initialization"); Require(ReadBytes(FilePath(concurrent)) == winner, "Concurrent winner must remain stable"); // Independently decode as Nintendo does: stop at the first encoded NUL. diff --git a/translator/src/Translator.Cli/Program.cs b/translator/src/Translator.Cli/Program.cs index db6ba74..85224e9 100644 --- a/translator/src/Translator.Cli/Program.cs +++ b/translator/src/Translator.Cli/Program.cs @@ -68,8 +68,8 @@ var canonicalIrStore = new CanonicalIrStore(); // recursive ABI cache in one stable pass, exactly like translate-mod does. var inferredGuestAbi = new Lazy(() => new InferredGuestFunctionAbiProvider(image.Value, canonicalIrStore)); -var runtimeNativeIndex = new Lazy(() => RuntimeNativeIndexBuilder.Resolve( - RequireProject().Runtime.NativeRegistrationRoot, RequireProject().Runtime.NativeIndex, Console.Error)); +var runtimeNativeIndex = new Lazy(() => ResolveRegionalNativeIndex( + RequireProject().Runtime.NativeRegistrationRoot, RequireProject().Runtime.NativeIndex)); // Void-stub signatures are only trusted as declared guest ABIs when the stub // lives under runtime.native_abi_directories (the vetted set); everywhere else // the C++ signature is documentation and the inferred ABI stays authoritative. @@ -217,8 +217,26 @@ int RunCheckBaseModAwareness(string[] argsTail) return 0; } +// The runtime registers natives by PAL address; translated code needs the project region's. +RuntimeNativeIndex ResolveRegionalNativeIndex(string nativeSourceDirectory, string? indexPath) +{ + var index = RuntimeNativeIndexBuilder.Resolve(nativeSourceDirectory, indexPath, Console.Error); + var region = GuestRegions.FromGameId(RequireProject().Identity.GameId); + var tablePath = GuestAddressTable.DefaultPath(nativeSourceDirectory); + // A runtime without a table can only be built for PAL. + if (region == GuestRegion.Pal && !File.Exists(tablePath)) + return index; + return index.ForRegion(GuestAddressTable.Load(tablePath), region); +} + int RunEmitBuildShards(string[] argsTail) { + // The project decides the guest region the shards are built for. + if (project is null) + { + Console.Error.WriteLine("emit-build-shards requires --project ."); + return 1; + } var baseMetadata = OptionValue(argsTail, "--base-metadata") ?? Path.Combine(root, "generated", "base_translation_output.json"); var baseFunctions = OptionValue(argsTail, "--base-functions-dir") ?? Path.Combine(root, "generated", "functions"); var output = OptionValue(argsTail, "--out") ?? Path.Combine(root, "generated", "build_shards"); @@ -237,7 +255,7 @@ int RunEmitBuildShards(string[] argsTail) : Path.GetFullPath(nativeIndexOption); if (!Directory.Exists(nativeSourcePath) && !File.Exists(nativeIndexPath)) throw new DirectoryNotFoundException(nativeSourcePath); - var nativeIndex = RuntimeNativeIndexBuilder.Resolve(nativeSourcePath, nativeIndexPath, Console.Error); + var nativeIndex = ResolveRegionalNativeIndex(nativeSourcePath, nativeIndexPath); var result = TranslatedBuildShardEmitter.Emit(new TranslatedBuildShardOptions( Path.GetFullPath(baseMetadata), Path.GetFullPath(baseFunctions), @@ -245,7 +263,8 @@ int RunEmitBuildShards(string[] argsTail) nativeSourcePath, string.IsNullOrWhiteSpace(resolvedProfile) ? null : Path.GetFullPath(resolvedProfile), string.IsNullOrWhiteSpace(retroCpp) ? null : Path.GetFullPath(retroCpp), - NativeIndex: nativeIndex)); + NativeIndex: nativeIndex, + Region: GuestRegions.FromGameId(project.Identity.GameId))); Console.WriteLine("[translator] emitted stable translated build graph"); Console.WriteLine($" base functions: {result.BaseFunctionCount:N0}"); Console.WriteLine($" shared base functions: {result.SharedBaseFunctionCount:N0}"); @@ -402,7 +421,8 @@ int RunValidateRetroWfcPayload(string[] argsTail) try { - WiiCompiled.Setup.Common.RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(directory); + WiiCompiled.Setup.Common.RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(directory, + gameId: OptionValue(argsTail, "--game-id")!); Console.WriteLine("[translator] Retro WFC payload signature validated."); return 0; } @@ -1743,6 +1763,12 @@ int RunTranslateModCore(string[] argsTail, string? outputDirectoryOverride) var modName = OptionValue(argsTail, "--mod-name") ?? (!string.IsNullOrWhiteSpace(modRoot) ? Path.GetFileName(Path.GetFullPath(modRoot)) : "Pulsar Mod"); var region = OptionValue(argsTail, "--region") ?? profile?.Region ?? "P"; + if (project?.Identity.Region is { } projectRegion && + !string.Equals(region, projectRegion, StringComparison.OrdinalIgnoreCase)) + { + Console.Error.WriteLine($"[translator] --region {region} does not match the project's region {projectRegion}."); + return 1; + } var moduleGuestBase = OptionValue(argsTail, "--module-guest-base") is { } moduleBaseText ? ParseAddress(moduleBaseText) : profile?.ModuleGuestBase ?? 0x81700000u; @@ -1754,6 +1780,18 @@ int RunTranslateModCore(string[] argsTail, string? outputDirectoryOverride) var pul = KamekPulFile.Load(codePul); var selected = pul.SelectRegion(region); + if (string.Equals(profile?.Name, "retro-rewind", StringComparison.OrdinalIgnoreCase)) + { + var corrected = pul.IsCombined && !string.Equals(region, "P", StringComparison.OrdinalIgnoreCase) + ? RetroRewindRegionPatches.CorrectUnportedUsHooks(selected, pul.SelectRegion("P"), project?.Identity.GameId, image.Value) + : selected; + if (!ReferenceEquals(corrected, selected)) + Console.WriteLine("[translator] Moved Retro Rewind's unported PAL vtable hooks to their NTSC-U slots."); + var esrb = RetroRewindRegionPatches.ApplyUsEsrbSkip(corrected, project?.Identity.GameId, image.Value); + if (!ReferenceEquals(esrb, corrected)) + Console.WriteLine("[translator] Applied Retro Rewind's NTSC-U ESRB skip statically at 0x80604094."); + selected = esrb; + } if (requestedRetroWfc && profile?.RetroWfcLegacyBootstrapHook is { } legacyBootstrapHook) { selected = RetroWfcBootstrapSuppressor.Suppress(selected, legacyBootstrapHook); @@ -3656,7 +3694,8 @@ static (string? Positional, CommandOption[] Options)? CommandSpec(string command }), "validate-retro-wfc-payload" => (null, new CommandOption[] { - new("--directory", "directory", Required: true) + new("--directory", "directory", Required: true), + new("--game-id", "id", Required: true) }), "emit-base-manifest" => (null, new CommandOption[] { diff --git a/translator/src/Translator.Core/Build/TranslatedBuildShardEmitter.cs b/translator/src/Translator.Core/Build/TranslatedBuildShardEmitter.cs index de8c42a..c8fcd74 100644 --- a/translator/src/Translator.Core/Build/TranslatedBuildShardEmitter.cs +++ b/translator/src/Translator.Core/Build/TranslatedBuildShardEmitter.cs @@ -18,7 +18,8 @@ public sealed record TranslatedBuildShardOptions( int BaseShardCount = 72, int ModShardCount = 48, int RegistrationShardCount = 16, - RuntimeNativeIndex? NativeIndex = null); + RuntimeNativeIndex? NativeIndex = null, + GuestRegion Region = GuestRegion.Pal); /// /// Per-shard compile-cost spread for one partition. Frozen membership does not @@ -247,6 +248,7 @@ public static partial class TranslatedBuildShardEmitter WriteCMakeManifest( cmakeManifestPath, outputRoot, + options.Region, commonBase.Length, portableCommonBase.Length, activeBase.Length, @@ -1039,6 +1041,7 @@ public static partial class TranslatedBuildShardEmitter private static void WriteCMakeManifest( string path, string outputRoot, + GuestRegion region, int sharedBaseCount, int portableSharedBaseCount, int activeBaseCount, @@ -1053,6 +1056,7 @@ public static partial class TranslatedBuildShardEmitter var output = new StringBuilder(); output.AppendLine("# Translator-owned stable shard graph; do not edit."); output.AppendLine($"set(MKW_TRANSLATED_SHARD_ROOT \"{CMakePath(outputRoot)}\")"); + output.AppendLine($"set(MKW_TRANSLATED_GUEST_REGION {(int)region})"); output.AppendLine($"set(MKW_BASE_FUNCTION_COUNT {activeBaseCount})"); output.AppendLine($"set(MKW_SHARED_BASE_FUNCTION_COUNT {sharedBaseCount})"); output.AppendLine($"set(MKW_PORTABLE_SHARED_BASE_FUNCTION_COUNT {portableSharedBaseCount})"); diff --git a/translator/src/Translator.Core/CodeGen/CxxLinearCodeGenerator.EmitInstruction.cs b/translator/src/Translator.Core/CodeGen/CxxLinearCodeGenerator.EmitInstruction.cs index b4874b1..8c35b11 100644 --- a/translator/src/Translator.Core/CodeGen/CxxLinearCodeGenerator.EmitInstruction.cs +++ b/translator/src/Translator.Core/CodeGen/CxxLinearCodeGenerator.EmitInstruction.cs @@ -93,6 +93,13 @@ public sealed partial class CxxLinearCodeGenerator { sb.AppendLine($"{pad}{dest} = {GuestLoadHelper(8, isFloat: true)}({RemapAddress(load.Address, types, localConstants, linkedAddressRemap)});"); } + else if (TryGetKnownEffectiveAddress(load.Address, knownConstants, out var knownLoadAddress) && + FlatWriteNeedsPolicy(knownLoadAddress)) + { + // The flat view maps the MMIO window no-access, so a hardware register read would fault + // without knowing its width. The checked read reaches the runtime's register HLE. + sb.AppendLine($"{pad}{dest} = {CheckedMmioLoadHelper(load.SizeBytes)}({RemapAddress(load.Address, types, localConstants, linkedAddressRemap)});"); + } else { sb.AppendLine($"{pad}{dest} = {GuestLoadHelper(load.SizeBytes, isFloat: false)}({RemapAddress(load.Address, types, localConstants, linkedAddressRemap)});"); diff --git a/translator/src/Translator.Core/CodeGen/CxxLinearCodeGenerator.FlatGuestMemory.cs b/translator/src/Translator.Core/CodeGen/CxxLinearCodeGenerator.FlatGuestMemory.cs index ed2317f..72b2124 100644 --- a/translator/src/Translator.Core/CodeGen/CxxLinearCodeGenerator.FlatGuestMemory.cs +++ b/translator/src/Translator.Core/CodeGen/CxxLinearCodeGenerator.FlatGuestMemory.cs @@ -84,6 +84,14 @@ public sealed partial class CxxLinearCodeGenerator private static string GuestLoadHelper(int sizeBytes, bool isFloat) => FlatReadHelper(Bits(sizeBytes), isFloat); + private static string CheckedMmioLoadHelper(int sizeBytes) => Bits(sizeBytes) switch + { + 8 => "Memory::Read8", + 16 => "Memory::Read16", + 64 => "Memory::Read64", + _ => "Memory::Read32" + }; + private static string GuestStoreHelper(int sizeBytes, bool isFloat) => FlatWriteHelper(Bits(sizeBytes), isFloat); diff --git a/translator/src/Translator.Core/CodeGen/CxxLinearCodeGenerator.Locals.cs b/translator/src/Translator.Core/CodeGen/CxxLinearCodeGenerator.Locals.cs index 6aac3df..abf54e5 100644 --- a/translator/src/Translator.Core/CodeGen/CxxLinearCodeGenerator.Locals.cs +++ b/translator/src/Translator.Core/CodeGen/CxxLinearCodeGenerator.Locals.cs @@ -253,6 +253,12 @@ public sealed partial class CxxLinearCodeGenerator ? index : -1; + private static uint ClearPairedBit(uint mask, string destination) + { + var bit = PairedFloatRegisterBit(destination); + return bit >= 0 ? mask & ~(1u << bit) : mask; + } + private static HashSet MaterializePairedFloatSet(uint mask, StringComparer comparer) { var set = new HashSet(comparer); @@ -454,11 +460,21 @@ public sealed partial class CxxLinearCodeGenerator break; } case IrLoad load: + newOut = ClearPairedBit(newOut, load.Destination); + break; + case IrResolvedLoad load: + newOut = ClearPairedBit(newOut, load.Destination); + break; + case IrResolvedLoadPair pair: + newOut = ClearPairedBit(newOut, pair.FirstDestination); + newOut = ClearPairedBit(newOut, pair.SecondDestination); + break; + case IrResolvedPsqLoad load: { var destBit = PairedFloatRegisterBit(load.Destination); if (destBit >= 0) { - newOut &= ~(1u << destBit); + newOut |= 1u << destBit; } break; } diff --git a/translator/src/Translator.Core/Disassembly/JumpTableDetector.cs b/translator/src/Translator.Core/Disassembly/JumpTableDetector.cs index 73a0eb6..6c319c5 100644 --- a/translator/src/Translator.Core/Disassembly/JumpTableDetector.cs +++ b/translator/src/Translator.Core/Disassembly/JumpTableDetector.cs @@ -70,7 +70,7 @@ internal static class JumpTableDetector } entriesAreRelative = HasRelativeEntryAdd(ordered, loadIndex, mtctrIndex, targetRegister, baseReg.Name); - if (!TryFindUpperBound(ordered, loadIndex, indexReg.Name, out var upperBound) || upperBound < 0 || upperBound >= MaxEntryCount) + if (!TryFindUpperBound(ordered, loadIndex, indexReg, out var upperBound) || upperBound < 0 || upperBound >= MaxEntryCount) { return false; } @@ -381,47 +381,60 @@ internal static class JumpTableDetector return false; } - private static bool TryFindUpperBound(IReadOnlyList ordered, int startIndex, string register, out int upperBound) + private static bool TryFindUpperBound(IReadOnlyList ordered, int startIndex, PpcRegisterOperand register, out int upperBound) { - // Preferred: compare directly on the same register used for lwzx indexing. + // Preferred: the compare on the lwzx index, followed back through the copies and + // shifts that derived it. A compare older than the value's definition bounds + // something else. + var tracked = register.Number; for (var i = startIndex - 1; i >= 0 && startIndex - i <= MaxBacktrackInstructions; i--) { var ins = ordered[i]; - if (ins.Operands.Count < 2 || ins.Operands[0] is not PpcRegisterOperand reg || - !string.Equals(reg.Name, register, StringComparison.OrdinalIgnoreCase) || - ins.Operands[1] is not PpcImmediateOperand imm) + if (TryGetCompareImmediate(ins, out var compared, out var bound)) + { + if (compared == tracked) + { + upperBound = bound; + return true; + } + continue; + } + + if (ins.IsCall) + { + break; + } + + if (!DefinesGpr(ins, tracked)) { continue; } - if (ins.Mnemonic is "cmplwi" or "cmpwi") + if (IsIndexDerivation(ins) && + ins.Operands[0] is PpcRegisterOperand dest && dest.Number == tracked && + ins.Operands[1] is PpcRegisterOperand source) { - upperBound = imm.Value; - return true; + tracked = source.Number; + continue; } + + break; } // Fallback: some loops compare a logical counter (e.g. r18) distinct from the byte-offset // register (e.g. r30) that feeds lwzx, so the bound check may not target the index register. for (var i = startIndex - 1; i >= 0 && startIndex - i <= MaxBacktrackInstructions; i--) { - var ins = ordered[i]; - if (ins.Operands.Count < 2 || ins.Operands[1] is not PpcImmediateOperand imm) + if (ordered[i].Operands.Count > 0 && ordered[i].Operands[0] is PpcConditionRegisterOperand) + { + continue; + } + if (!TryGetCompareImmediate(ordered[i], out _, out var bound) || bound < 0 || bound >= MaxEntryCount) { continue; } - if (ins.Mnemonic is not ("cmplwi" or "cmpwi")) - { - continue; - } - - if (imm.Value < 0 || imm.Value >= MaxEntryCount) - { - continue; - } - - upperBound = imm.Value; + upperBound = bound; return true; } @@ -429,6 +442,70 @@ internal static class JumpTableDetector return false; } + // Copies, sign extensions and left shifts (slwi, clrlwi, clrlslwi) keep a bound on + // the source a bound on the result's entry index. + private static bool IsIndexDerivation(PpcInstruction ins) => ins.Mnemonic switch + { + "mr" or "extsb" or "extsh" => ins.Operands.Count >= 2, + "rlwinm" => ins.Operands.Count == 5 && + ins.Operands[2] is PpcImmediateOperand sh && + ins.Operands[4] is PpcImmediateOperand me && + me.Value == 31 - sh.Value, + _ => false, + }; + + // MayWriteGpr treats both register fields of an X-form as written, which also + // counts sources (or, extsb, stwx, cmpw); read the decoded destination instead. + private static bool DefinesGpr(PpcInstruction ins, int register) + { + if (ins.Word >> 26 != 31) + { + return PpcRegisterEffects.MayWriteGpr(ins.Word, register); + } + + var mnemonic = ins.Mnemonic; + if (mnemonic.EndsWith("ux", StringComparison.Ordinal) && + ins.Operands.Count > 1 && ins.Operands[1] is PpcRegisterOperand updated && updated.Number == register) + { + return true; + } + + if (mnemonic.StartsWith("st", StringComparison.Ordinal) || + mnemonic.StartsWith("cmp", StringComparison.Ordinal) || + mnemonic.StartsWith("mt", StringComparison.Ordinal) || + mnemonic.StartsWith("dcb", StringComparison.Ordinal) || + mnemonic.StartsWith("icb", StringComparison.Ordinal) || + mnemonic.StartsWith("tw", StringComparison.Ordinal)) + { + return false; + } + + return ins.Operands.Count > 0 && ins.Operands[0] is PpcRegisterOperand dest && dest.Number == register; + } + + private static bool TryGetCompareImmediate(PpcInstruction ins, out int register, out int immediate) + { + register = -1; + immediate = 0; + if (ins.Mnemonic is not ("cmplwi" or "cmpwi")) + { + return false; + } + + var operands = ins.Operands; + var first = operands.Count > 0 && operands[0] is PpcConditionRegisterOperand ? 1 : 0; + if (operands.Count < first + 2 || + operands[first] is not PpcRegisterOperand reg || + operands[first + 1] is not PpcImmediateOperand imm) + { + return false; + } + + register = reg.Number; + immediate = imm.Value; + return true; + } + private static bool TryReadWord(ProgramImage image, uint address, out uint value) { if (!image.Contains(address, sizeof(uint))) diff --git a/translator/src/Translator.Core/GuestAddressTable.cs b/translator/src/Translator.Core/GuestAddressTable.cs new file mode 100644 index 0000000..871ee97 --- /dev/null +++ b/translator/src/Translator.Core/GuestAddressTable.cs @@ -0,0 +1,111 @@ +using System.Text.RegularExpressions; + +namespace Translator.Core; + +/// Region index the runtime uses (GuestRegion::Id in guest_abi/guest_region.h). +public enum GuestRegion +{ + Pal = 0, + NtscU = 1, + NtscJ = 2, +} + +public static class GuestRegions +{ + /// + /// The runtime region for a project's game id. Mario Kart Wii releases without a column in + /// the address table are rejected; any other game has no region-specific runtime addresses. + /// + public static GuestRegion FromGameId(string? gameId) => gameId?.ToUpperInvariant() switch + { + "RMCE01" => GuestRegion.NtscU, + "RMCJ01" => GuestRegion.NtscJ, + "RMCP01" => GuestRegion.Pal, + { } id when id.StartsWith("RMC", StringComparison.Ordinal) => + throw new InvalidDataException($"Mario Kart Wii release '{gameId}' is not supported."), + _ => GuestRegion.Pal, + }; +} + +/// +/// The runtime names guest addresses by their PAL address. This is the range map it resolves +/// them through (Retro Rewind versions.txt style), read from the same file the C++ includes. +/// +public sealed partial class GuestAddressTable +{ + private readonly Dictionary _ranges; + + private readonly record struct Range(uint First, uint Last, int Delta); + + private GuestAddressTable(Dictionary ranges, string sourcePath) + { + _ranges = ranges; + SourcePath = sourcePath; + } + + public string SourcePath { get; } + + public int Count => _ranges.Values.Sum(static ranges => ranges.Length); + + /// The map beside a runtime whose native sources live in . + public static string DefaultPath(string nativeSourceDirectory) => + Path.GetFullPath(Path.Combine(nativeSourceDirectory, "..", "include", "guest_abi", "guest_versions.inc")); + + public static GuestAddressTable Load(string path) + { + if (!File.Exists(path)) + throw new FileNotFoundException("The runtime's guest address map was not found.", path); + var ranges = new Dictionary>(); + foreach (var line in File.ReadLines(path)) + { + if (!line.TrimStart().StartsWith("MKW_REGION_RANGE", StringComparison.Ordinal)) continue; + var match = RangePattern().Match(line); + if (!match.Success) + throw new InvalidDataException($"{path} has a malformed range: {line.Trim()}"); + var regionName = match.Groups["region"].Value; + if (!Enum.TryParse(regionName, out var region) || !Enum.IsDefined(region) || + region == GuestRegion.Pal || char.IsDigit(regionName[0])) + throw new InvalidDataException($"{path} has a range for unknown region '{regionName}'."); + var magnitude = Convert.ToInt64(match.Groups["delta"].Value, 16); + if (magnitude > int.MaxValue) + throw new InvalidDataException($"{path} has an out-of-range delta: {line.Trim()}"); + var range = new Range( + Convert.ToUInt32(match.Groups["first"].Value, 16), + Convert.ToUInt32(match.Groups["last"].Value, 16), + (match.Groups["sign"].Value == "-" ? -1 : 1) * (int)magnitude); + if (range.First > range.Last) + throw new InvalidDataException($"{path} has an empty range at 0x{range.First:X8}."); + if (!ranges.TryGetValue(region, out var list)) + ranges[region] = list = []; + if (list.Count != 0 && list[^1].Last >= range.First) + throw new InvalidDataException($"{path} ranges for {region} overlap or are unsorted at 0x{range.First:X8}."); + list.Add(range); + } + if (ranges.Count == 0) + throw new InvalidDataException($"{path} has no MKW_REGION_RANGE rows."); + return new GuestAddressTable(ranges.ToDictionary(static pair => pair.Key, static pair => pair.Value.ToArray()), path); + } + + public uint Map(uint pal, GuestRegion region) + { + if (region == GuestRegion.Pal) + return pal; + if (_ranges.TryGetValue(region, out var ranges)) + { + var lo = 0; + var hi = ranges.Length; + while (lo < hi) + { + var mid = lo + (hi - lo) / 2; + if (pal < ranges[mid].First) hi = mid; + else lo = mid + 1; + } + if (lo > 0 && pal <= ranges[lo - 1].Last) + return (uint)(pal + (long)ranges[lo - 1].Delta); + } + throw new InvalidDataException($"PAL address 0x{pal:X8} has no {region} address in {SourcePath}."); + } + + [GeneratedRegex(@"^\s*MKW_REGION_RANGE\(\s*(?\w+)\s*,\s*(?[0-9A-Fa-f]{8})\s*,\s*(?[0-9A-Fa-f]{8})\s*,\s*(?[+-])0x(?[0-9A-Fa-f]{1,8})\s*\)\s*(//.*)?$", RegexOptions.CultureInvariant)] + private static partial Regex RangePattern(); +} diff --git a/translator/src/Translator.Core/Mods/Mkwii/RetroRewindRegionPatches.cs b/translator/src/Translator.Core/Mods/Mkwii/RetroRewindRegionPatches.cs new file mode 100644 index 0000000..04f7572 --- /dev/null +++ b/translator/src/Translator.Core/Mods/Mkwii/RetroRewindRegionPatches.cs @@ -0,0 +1,103 @@ +using System.Buffers.Binary; +using Translator.Core.Loading; +using Translator.Core.Parsing.Kamek; + +namespace Translator.Core.Mods.Mkwii; + +public static class RetroRewindRegionPatches +{ + private const uint PalRelStart = 0x805102E0; + + // Hooks the pack writes at PAL vtable slots that its NTSC-U port map leaves unported: + // PAL slot, NTSC-U slot, and the function that NTSC-U slot holds in the clean StaticR.rel. + private static readonly (uint Pal, uint Us, uint UsTarget)[] UnportedUsHooks = + [ + (0x808B4D48, 0x808B0698, 0x80563BE8), // Kart::Damage::ApplyBananaDamage + (0x808B4DFC, 0x808B074C, 0x80563CD8), // Kart::Damage::ApplyZapperDamage + (0x808B4E14, 0x808B0764, 0x80563CCC), // Kart::Damage::ApplyShockDamage + (0x808CB02C, 0x808C5D24, 0x8072E068), // AI::EnemyRouteController::Update + (0x808DBCD8, 0x808D7580, 0x806FAB44), // Audio::RaceActor::HoldSoundLimited + ]; + + /// + /// Moves the NTSC-U chunk's unported PAL vtable hooks to their NTSC-U slots. A StaticR.rel + /// address the NTSC-U chunk shares with the PAL chunk is always unported, so an unknown one fails. + /// + public static KamekChunk CorrectUnportedUsHooks(KamekChunk usChunk, KamekChunk palChunk, string? gameId, + ProgramImage image) + { + if (!string.Equals(gameId, "RMCE01", StringComparison.OrdinalIgnoreCase)) + return usChunk; + if (usChunk.Commands.Count != palChunk.Commands.Count) + throw new InvalidDataException("Retro Rewind's PAL and NTSC-U chunks have different command lists."); + + var commands = usChunk.Commands.ToArray(); + var changed = false; + for (var i = 0; i < commands.Length; i++) + { + var us = commands[i]; + var pal = palChunk.Commands[i]; + if (!us.AddressIsAbsolute || !pal.AddressIsAbsolute || us.Address != pal.Address || us.Address < PalRelStart) + continue; + var hook = UnportedUsHooks.FirstOrDefault(h => h.Pal == us.Address); + if (hook.Pal == 0) + throw new InvalidDataException($"Retro Rewind's NTSC-U chunk patches unported PAL address 0x{us.Address:X8}."); + if (us.Id != KamekCommandId.Addr32 || us.Arguments.Count != 1 || us.Arguments[0] >= usChunk.CodeSize) + throw new InvalidDataException($"Unexpected Retro Rewind command at PAL address 0x{us.Address:X8}."); + if (!image.Contains(hook.Us, 4) || + BinaryPrimitives.ReadUInt32BigEndian(image.Memory.AsSpan(image.GetOffset(hook.Us, 4), 4)) != hook.UsTarget) + throw new InvalidDataException($"NTSC-U vtable slot check failed at 0x{hook.Us:X8}."); + commands[i] = us with { Address = hook.Us }; + changed = true; + } + return changed + ? new KamekChunk(usChunk.Index, usChunk.FileOffset, usChunk.BssSize, usChunk.CodeSize, + usChunk.CtorStart, usChunk.CtorEnd, usChunk.ChunkSize, usChunk.CodeBlob, commands) + : usChunk; + } + + private const uint EsrbBranchSite = 0x80604094; + private const uint EsrbOriginalInstruction = 0x3C608038; + private const uint EsrbSkipBranch = 0x4800001C; + private const int EsrbStoreIndex = 7; + + // PulsarSystem.cpp's removeESRB boot hook: if (region == 'E') *(u32*)0x80604094 = 0x4800001C. + private static readonly uint[] EsrbBootHook = + [ + 0x3C608000, 0x88030003, 0x2C000045, 0x4C820020, 0x3C804800, 0x3C608060, 0x3804001C, 0x90034094, 0x4E800020 + ]; + + /// + /// Translated code cannot be rewritten at run time, so the pack's NTSC-U ESRB skip becomes a + /// static patch and its run-time store a nop. + /// + public static KamekChunk ApplyUsEsrbSkip(KamekChunk chunk, string? gameId, ProgramImage image) + { + if (!string.Equals(gameId, "RMCE01", StringComparison.OrdinalIgnoreCase)) + return chunk; + + var sites = new List(); + for (var offset = 0; offset + EsrbBootHook.Length * 4 <= chunk.CodeBlob.Length; offset += 4) + { + var match = true; + for (var i = 0; i < EsrbBootHook.Length && match; i++) + match = BinaryPrimitives.ReadUInt32BigEndian(chunk.CodeBlob.AsSpan(offset + i * 4, 4)) == EsrbBootHook[i]; + if (match) + sites.Add(offset); + } + if (sites.Count == 0) + return chunk; + if (sites.Count != 1 || chunk.Commands.Any(c => c.AddressIsAbsolute && c.Address == EsrbBranchSite)) + throw new InvalidDataException("Unexpected Retro Rewind ESRB skip; cannot apply it statically."); + if (!image.Contains(EsrbBranchSite, 4) || + BinaryPrimitives.ReadUInt32BigEndian(image.Memory.AsSpan(image.GetOffset(EsrbBranchSite, 4), 4)) != EsrbOriginalInstruction) + throw new InvalidDataException($"Retro Rewind ESRB skip target check failed at 0x{EsrbBranchSite:X8}."); + + var code = chunk.CodeBlob.ToArray(); + BinaryPrimitives.WriteUInt32BigEndian(code.AsSpan(sites[0] + EsrbStoreIndex * 4, 4), 0x60000000); + var branch = new KamekCommand(-1, ((uint)KamekCommandId.Write32 << 24) | 0xFFFFFE, KamekCommandId.Write32, + true, EsrbBranchSite, [EsrbSkipBranch]); + return new KamekChunk(chunk.Index, chunk.FileOffset, chunk.BssSize, chunk.CodeSize, + chunk.CtorStart, chunk.CtorEnd, chunk.ChunkSize, code, chunk.Commands.Append(branch).ToArray()); + } +} diff --git a/translator/src/Translator.Core/RuntimeNativeIndex.cs b/translator/src/Translator.Core/RuntimeNativeIndex.cs index 2575d08..74c6fee 100644 --- a/translator/src/Translator.Core/RuntimeNativeIndex.cs +++ b/translator/src/Translator.Core/RuntimeNativeIndex.cs @@ -43,6 +43,22 @@ public sealed record RuntimeNativeIndex( .Select(static entry => entry.Address).ToHashSet(); return new RuntimeNativeGuestEffectSet(contracts, precise, conservative); } + + /// + /// The index is keyed by the PAL addresses the runtime sources name; this is the same index + /// keyed by 's addresses. Every address must have a counterpart in that region. + /// + public RuntimeNativeIndex ForRegion(GuestAddressTable table, GuestRegion region) => new( + Registrations.Select(entry => entry with { Address = table.Map(entry.Address, region) }).ToArray(), + VoidStubAbis.Select(entry => entry with { Address = table.Map(entry.Address, region) }).ToArray(), + Effects.Select(entry => entry with + { + Address = table.Map(entry.Address, region), + Contract = entry.Contract with + { + DirectCallTargets = entry.Contract.DirectCallTargets.Select(target => table.Map(target, region)).ToArray() + } + }).ToArray()); } public static class RuntimeNativeIndexBuilder diff --git a/translator/tests/Translator.Tests/CodeGenTests.cs b/translator/tests/Translator.Tests/CodeGenTests.cs index 2051006..d52f402 100644 --- a/translator/tests/Translator.Tests/CodeGenTests.cs +++ b/translator/tests/Translator.Tests/CodeGenTests.cs @@ -480,6 +480,41 @@ public class CodeGenTests Assert.Contains("MemoryInline::FlatWrite8((ctx->gpr[6] + -32768), static_cast(ctx->gpr[3]));", code, StringComparison.Ordinal); } + [Fact] + public void CodeGenerator_ReadsKnownMmioAddressesThroughCheckedHelper() + { + var function = new IrFunction( + "known_mmio_load", + "entry", + new[] + { + new IrBasicBlock("entry", new IrInstruction[] + { + new IrAssign("r4", IrValue.Imm(unchecked((int)0xCD000000))), + new IrLoad("r0", new IrAddress("r4", 0xC0), 4), + new IrLoad("r5", new IrAddress("r3", 8), 4), + new IrReturn(null) + }) + }); + + var types = new RepresentationEnvironment(new Dictionary + { + ["r0"] = ValueRepresentation.UInt32, + ["r3"] = ValueRepresentation.UInt32, + ["r4"] = ValueRepresentation.UInt32, + ["r5"] = ValueRepresentation.UInt32 + }); + var signature = new FunctionAbiClassification( + "known_mmio_load", + ValueRepresentation.Void); + + var ssa = new SsaTransformer().Convert(function); + var code = new CxxLinearCodeGenerator().Emit(0x80008020, ssa, signature, types); + + Assert.Contains("= Memory::Read32(", code, StringComparison.Ordinal); + Assert.Contains("= MemoryInline::FlatRead32((ctx->gpr[3] + 8));", code, StringComparison.Ordinal); + } + [Fact] public void CodeGenerator_ReusesFctiwzStackLowWordForMatchingLoad() { diff --git a/translator/tests/Translator.Tests/FunctionTranslatorCoverageTests.cs b/translator/tests/Translator.Tests/FunctionTranslatorCoverageTests.cs index 9f2f229..ae9c617 100644 --- a/translator/tests/Translator.Tests/FunctionTranslatorCoverageTests.cs +++ b/translator/tests/Translator.Tests/FunctionTranslatorCoverageTests.cs @@ -538,4 +538,122 @@ public class FunctionTranslatorCoverageTests Assert.Equal("// generated", result.CxxCode); Assert.Same(metrics, result.Metrics); } + + [Fact] + public void Translate_JumpTableBoundFollowsShiftedIndexPastStaleCompare() + { + const uint entry = 0x80000000; + const uint table = 0x80000100; + const uint case0 = entry + 0x20; + const uint case1 = entry + 0x28; + const uint case2 = entry + 0x30; + + var image = TranslatorCppTestHarness.CreateImage( + (entry + 0x00, 0x2C040001), // cmpwi r4, 1 + (entry + 0x04, 0x28030002), // cmplwi r3, 2 + (entry + 0x08, 0x5464103A), // slwi r4, r3, 2 + (entry + 0x0C, 0x3D808000), // lis r12, 0x8000 + (entry + 0x10, 0x398C0100), // addi r12, r12, 0x100 + (entry + 0x14, 0x7C0C202E), // lwzx r0, r12, r4 + (entry + 0x18, 0x7C0903A6), // mtctr r0 + (entry + 0x1C, 0x4E800420), // bctr + (case0 + 0x00, 0x38600007), // li r3, 7 + (case0 + 0x04, 0x4E800020), // blr + (case1 + 0x00, 0x38600009), // li r3, 9 + (case1 + 0x04, 0x4E800020), // blr + (case2 + 0x00, 0x3860000B), // li r3, 11 + (case2 + 0x04, 0x4E800020), // blr + (table + 0x00, case0), + (table + 0x04, case1), + (table + 0x08, case2)); + var result = new FunctionTranslator(image).Translate( + entry, + TranslationOptions.Default with + { + MaxBytes = 0x80, + AllowUnsupportedInstructions = true, + KnownFunctionEntryPoints = new HashSet { entry } + }); + + Assert.Contains("case 0x80000030u:", result.CxxCode, StringComparison.Ordinal); + } + + [Fact] + public void Translate_JumpTableBoundSurvivesCopyOfIndex() + { + const uint entry = 0x80000000; + const uint table = 0x80000100; + const uint case0 = entry + 0x28; + const uint case1 = entry + 0x30; + const uint case2 = entry + 0x38; + + var image = TranslatorCppTestHarness.CreateImage( + (entry + 0x00, 0x28030002), // cmplwi r3, 2 + (entry + 0x04, 0x7C7F1B78), // mr r31, r3 + (entry + 0x08, 0x2C040001), // cmpwi r4, 1 + (entry + 0x0C, 0x5460103A), // slwi r0, r3, 2 + (entry + 0x10, 0x3D808000), // lis r12, 0x8000 + (entry + 0x14, 0x398C0100), // addi r12, r12, 0x100 + (entry + 0x18, 0x7C0C002E), // lwzx r0, r12, r0 + (entry + 0x1C, 0x7C0903A6), // mtctr r0 + (entry + 0x20, 0x4E800420), // bctr + (entry + 0x24, 0x4E800020), // blr + (case0 + 0x00, 0x38600007), // li r3, 7 + (case0 + 0x04, 0x4E800020), // blr + (case1 + 0x00, 0x38600009), // li r3, 9 + (case1 + 0x04, 0x4E800020), // blr + (case2 + 0x00, 0x3860000B), // li r3, 11 + (case2 + 0x04, 0x4E800020), // blr + (table + 0x00, case0), + (table + 0x04, case1), + (table + 0x08, case2)); + var result = new FunctionTranslator(image).Translate( + entry, + TranslationOptions.Default with + { + MaxBytes = 0x80, + AllowUnsupportedInstructions = true, + KnownFunctionEntryPoints = new HashSet { entry } + }); + + Assert.Contains("case 0x80000038u:", result.CxxCode, StringComparison.Ordinal); + } + + [Fact] + public void Translate_JumpTableBoundAcceptsNonCr0Compare() + { + const uint entry = 0x80000000; + const uint table = 0x80000100; + const uint case0 = entry + 0x1C; + const uint case1 = entry + 0x24; + const uint case2 = entry + 0x2C; + + var image = TranslatorCppTestHarness.CreateImage( + (entry + 0x00, 0x28830002), // cmplwi cr1, r3, 2 + (entry + 0x04, 0x5463103A), // slwi r3, r3, 2 + (entry + 0x08, 0x3D808000), // lis r12, 0x8000 + (entry + 0x0C, 0x398C0100), // addi r12, r12, 0x100 + (entry + 0x10, 0x7C0C182E), // lwzx r0, r12, r3 + (entry + 0x14, 0x7C0903A6), // mtctr r0 + (entry + 0x18, 0x4E800420), // bctr + (case0 + 0x00, 0x38600007), // li r3, 7 + (case0 + 0x04, 0x4E800020), // blr + (case1 + 0x00, 0x38600009), // li r3, 9 + (case1 + 0x04, 0x4E800020), // blr + (case2 + 0x00, 0x3860000B), // li r3, 11 + (case2 + 0x04, 0x4E800020), // blr + (table + 0x00, case0), + (table + 0x04, case1), + (table + 0x08, case2)); + var result = new FunctionTranslator(image).Translate( + entry, + TranslationOptions.Default with + { + MaxBytes = 0x80, + AllowUnsupportedInstructions = true, + KnownFunctionEntryPoints = new HashSet { entry } + }); + + Assert.Contains("case 0x8000002Cu:", result.CxxCode, StringComparison.Ordinal); + } } diff --git a/translator/tests/Translator.Tests/GuestAddressTableTests.cs b/translator/tests/Translator.Tests/GuestAddressTableTests.cs new file mode 100644 index 0000000..4e972aa --- /dev/null +++ b/translator/tests/Translator.Tests/GuestAddressTableTests.cs @@ -0,0 +1,191 @@ +using System.Text.RegularExpressions; +using Translator.Core; +using Translator.Core.Analysis; +using Xunit; + +namespace Translator.Tests; + +public sealed class GuestAddressTableTests +{ + [Theory] + [InlineData("RMCP01", GuestRegion.Pal)] + [InlineData("RMCE01", GuestRegion.NtscU)] + [InlineData("rmcj01", GuestRegion.NtscJ)] + [InlineData("RECOMPGEN", GuestRegion.Pal)] + [InlineData(null, GuestRegion.Pal)] + public void RegionFollowsTheGameId(string? gameId, GuestRegion expected) => + Assert.Equal(expected, GuestRegions.FromGameId(gameId)); + + [Theory] + [InlineData("RMCK01")] + [InlineData("RMCP02")] + public void UnsupportedMarioKartReleasesAreRejected(string gameId) => + Assert.Throws(() => GuestRegions.FromGameId(gameId)); + + [Fact] + public void MapsRangesAndRejectsUnknownAndOverlappingRanges() + { + WithTable(""" + // comment + MKW_REGION_RANGE(NtscU, 801A9000, 801A9FFF, -0xA0) + MKW_REGION_RANGE(NtscU, 80386000, 80386FFF, -0x4360) + MKW_REGION_RANGE(NtscJ, 801A9000, 801A9FFF, -0xE0) + MKW_REGION_RANGE(NtscJ, 80386000, 80386FFF, -0x680) + """, table => + { + Assert.Equal(4, table.Count); + Assert.Equal(0x801A9E84u, table.Map(0x801A9E84, GuestRegion.Pal)); + Assert.Equal(0x801A9DE4u, table.Map(0x801A9E84, GuestRegion.NtscU)); + Assert.Equal(0x80385FE4u, table.Map(0x80386664, GuestRegion.NtscJ)); + Assert.Equal(0x80000000u, table.Map(0x80000000, GuestRegion.Pal)); + Assert.Throws(() => table.Map(0x80000000, GuestRegion.NtscU)); + Assert.Throws(() => table.Map(0x801AA000, GuestRegion.NtscJ)); + }); + WithTable(""" + MKW_REGION_RANGE(NtscU, 801A9000, 801A9FFF, -0xA0) + MKW_REGION_RANGE(NtscU, 801A9FFF, 801AAFFF, -0xA0) + """, _ => { }, expectFailure: true); + WithTable("MKW_REGION_RANGE(Pal, 801A9000, 801A9FFF, +0x0)\n", _ => { }, expectFailure: true); + WithTable("MKW_REGION_RANGE(1, 801A9000, 801A9FFF, +0x0)\n", _ => { }, expectFailure: true); + WithTable("MKW_REGION_RANGE(NtscU, 801A9000, 801A9FFF, 0xA0)\n", _ => { }, expectFailure: true); + WithTable("MKW_REGION_RANGE(NtscU, 801A9000, 801A9FFF, -0x80000000)\n", _ => { }, expectFailure: true); + WithTable("// no rows\n", _ => { }, expectFailure: true); + } + + [Fact] + public void IndexForRegionRekeysEveryEntry() + { + var contract = new GuestAbiContract(0, 0, 0, 0, 0, 0, 0, 0, false, false, false, false, false, false, + GuestCallBoundaryFlags.None, [0x80386664u]); + var index = new RuntimeNativeIndex( + [new RuntimeNativeRegistration(0x801A9E84, "OSCreateThread_HLE", "os.cpp", false, true)], + [new RuntimeNativeAbiEntry(0x801A9E84, ["r3"], [])], + [new RuntimeNativeEffectEntry(0x801A9E84, contract, true)]); + WithTable(""" + MKW_REGION_RANGE(NtscU, 801A9000, 801A9FFF, -0xA0) + MKW_REGION_RANGE(NtscU, 80386000, 80386FFF, -0x4360) + """, table => + { + var ntscU = index.ForRegion(table, GuestRegion.NtscU); + Assert.Equal(0x801A9DE4u, ntscU.Registrations.Single().Address); + Assert.Equal("OSCreateThread_HLE", ntscU.Registrations.Single().Symbol); + Assert.Equal(0x801A9DE4u, ntscU.VoidStubAbis.Single().Address); + Assert.Equal(0x801A9DE4u, ntscU.Effects.Single().Address); + Assert.Equal([0x80382304u], ntscU.Effects.Single().Contract.DirectCallTargets); + Assert.Equal(0x801A9E84u, index.ForRegion(table, GuestRegion.Pal).Registrations.Single().Address); + }); + } + + // Every address the runtime registers must have a counterpart, or a regional build cannot place it. + [Fact] + public void RepositoryMapCoversEveryRuntimeRegistration() + { + var root = ProjectPathsForTests.FindRepositoryRoot(); + var sources = Path.Combine(root, "runtime", "src"); + var table = GuestAddressTable.Load(GuestAddressTable.DefaultPath(sources)); + var index = RuntimeNativeIndexBuilder.Build(sources); + Assert.NotEmpty(index.Registrations); + foreach (var region in Enum.GetValues()) + Assert.Equal(index.Registrations.Length, index.ForRegion(table, region).Registrations.Length); + } + + // Every function both MAPs name uniquely, and every verified data address, must port exactly. + [Theory] + [InlineData(GuestRegion.NtscU, "mkwii-ntsc-u")] + [InlineData(GuestRegion.NtscJ, "mkwii-ntsc-j")] + public void RepositoryMapAgreesWithRegionMapsAndDataAnchors(GuestRegion region, string project) + { + var root = ProjectPathsForTests.FindRepositoryRoot(); + var table = GuestAddressTable.Load(GuestAddressTable.DefaultPath(Path.Combine(root, "runtime", "src"))); + var pal = UniqueNames(Path.Combine(root, "projects", "mkwii", "MAP.txt")); + var target = UniqueNames(Path.Combine(root, "projects", project, "MAP.txt")); + var compared = 0; + foreach (var (name, address) in pal) + { + if (!target.TryGetValue(name, out var expected)) + continue; + Assert.True(expected == table.Map(address, region), $"{name} 0x{address:X8} should port to 0x{expected:X8}"); + compared++; + } + Assert.True(compared > 15000, $"only {compared} functions compared"); + + foreach (var line in File.ReadLines(Path.Combine(root, "projects", project, "data_addresses.txt"))) + { + var parts = line.Split('#')[0].Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries); + if (parts.Length < 2 || parts[1] == "?" || parts[0].Length != 8) + continue; + var address = Convert.ToUInt32(parts[0], 16); + Assert.Equal(Convert.ToUInt32(parts[1], 16), table.Map(address, region)); + } + } + + // Guest functions the runtime calls directly must be real functions in every region. + [Fact] + public void RuntimeGuestCallsAreFunctionEntriesInEveryRegion() + { + var root = ProjectPathsForTests.FindRepositoryRoot(); + var table = GuestAddressTable.Load(GuestAddressTable.DefaultPath(Path.Combine(root, "runtime", "src"))); + var thirdParty = $"{Path.DirectorySeparatorChar}third_party{Path.DirectorySeparatorChar}"; + var calls = Directory.EnumerateFiles(Path.Combine(root, "runtime"), "*.*", SearchOption.AllDirectories) + .Where(path => (path.EndsWith(".cpp", StringComparison.Ordinal) || path.EndsWith(".h", StringComparison.Ordinal)) && + !path.Contains(thirdParty, StringComparison.Ordinal)) + .SelectMany(static path => Regex.Matches(File.ReadAllText(path), @"MKW_GUEST_FUNC\(\s*([0-9A-Fa-f]{8})\s*\)") + .Select(static match => Convert.ToUInt32(match.Groups[1].Value, 16))) + .Distinct() + .ToArray(); + Assert.NotEmpty(calls); + var entries = new Dictionary> + { + [GuestRegion.Pal] = MapEntries(Path.Combine(root, "projects", "mkwii", "MAP.txt")), + [GuestRegion.NtscU] = MapEntries(Path.Combine(root, "projects", "mkwii-ntsc-u", "MAP.txt")), + [GuestRegion.NtscJ] = MapEntries(Path.Combine(root, "projects", "mkwii-ntsc-j", "MAP.txt")), + }; + foreach (var pal in calls) + { + foreach (var (region, starts) in entries) + { + var address = table.Map(pal, region); + Assert.True(starts.Contains(address), $"MKW_GUEST_FUNC({pal:X8}) is not a {region} function entry (0x{address:X8})"); + } + } + } + + private static HashSet MapEntries(string mapPath) => + File.ReadLines(mapPath) + .Select(static line => line.Trim()) + .Where(static line => line.Length >= 8 && !line.StartsWith('#')) + .Select(static line => Convert.ToUInt32(line[..8], 16)) + .ToHashSet(); + + private static Dictionary UniqueNames(string mapPath) + { + var entries = File.ReadLines(mapPath) + .Select(static line => line.Trim()) + .Where(static line => line.Length > 9 && !line.StartsWith('#')) + .Select(static line => (Address: Convert.ToUInt32(line[..8], 16), Name: line[9..].Trim())) + .Where(static entry => !entry.Name.StartsWith("0x", StringComparison.Ordinal) && + !entry.Name.StartsWith("FUN_", StringComparison.Ordinal) && + !entry.Name.StartsWith("fn_", StringComparison.Ordinal)) + .ToArray(); + return entries.GroupBy(static entry => entry.Name) + .Where(static group => group.Count() == 1) + .ToDictionary(static group => group.Key, static group => group.Single().Address); + } + + private static void WithTable(string contents, Action check, bool expectFailure = false) + { + var path = Path.Combine(Path.GetTempPath(), $"mkw-guest-versions-{Guid.NewGuid():N}.inc"); + File.WriteAllText(path, contents); + try + { + if (expectFailure) + Assert.Throws(() => GuestAddressTable.Load(path)); + else + check(GuestAddressTable.Load(path)); + } + finally + { + File.Delete(path); + } + } +} diff --git a/translator/tests/Translator.Tests/KamekPulFileTests.cs b/translator/tests/Translator.Tests/KamekPulFileTests.cs index 7444651..1cb187c 100644 --- a/translator/tests/Translator.Tests/KamekPulFileTests.cs +++ b/translator/tests/Translator.Tests/KamekPulFileTests.cs @@ -1,4 +1,5 @@ using System.Buffers.Binary; +using Translator.Core.Mods.Mkwii; using Translator.Core.Parsing.Kamek; using Xunit; @@ -78,8 +79,11 @@ public class KamekPulFileTests Assert.Throws(() => KamekPpcEncoding.EncodeBranch(0x8053369C, 0x8053369D, link: false)); } - [Fact] - public void ParsesBundledRetroRewindCodePulWhenPresent() + [Theory] + [InlineData("P", 0x800ED6E8u)] + [InlineData("E", 0x800ED648u)] + [InlineData("J", 0x800ED608u)] + public void ParsesBundledRetroRewindCodePulWhenPresent(string region, uint bootstrapHook) { var repoRoot = ProjectPathsForTests.FindRepositoryRoot(); var codePul = Path.Combine(repoRoot, "PulsarPacks", "completed", "RetroRewind", "RetroRewind6", "Binaries", "Code.pul"); @@ -89,7 +93,7 @@ public class KamekPulFileTests } var pul = KamekPulFile.Load(codePul); - var chunk = pul.SelectRegion("P"); + var chunk = pul.SelectRegion(region); Assert.True(pul.IsCombined); Assert.Equal(3, pul.Chunks.Count); @@ -102,6 +106,9 @@ public class KamekPulFileTests Assert.NotEmpty(chunk.Commands); Assert.Equal(chunk.Commands.Count, chunk.RelativeCommandCount + chunk.AbsoluteCommandCount); Assert.Equal(chunk.Commands.Count, chunk.CommandCounts.Values.Sum()); + var lowered = RetroWfcBootstrapSuppressor.Suppress(chunk, bootstrapHook); + Assert.Equal(chunk.Commands.Count - 1, lowered.Commands.Count); + Assert.DoesNotContain(lowered.Commands, command => command.AddressIsAbsolute && command.Address == bootstrapHook); } private static byte[] BuildChunk(uint bssSize, byte[] code, byte[][] commands, diff --git a/translator/tests/Translator.Tests/PairedFlowCodeGenTests.cs b/translator/tests/Translator.Tests/PairedFlowCodeGenTests.cs index 0279a63..59e1891 100644 --- a/translator/tests/Translator.Tests/PairedFlowCodeGenTests.cs +++ b/translator/tests/Translator.Tests/PairedFlowCodeGenTests.cs @@ -152,4 +152,69 @@ public sealed class PairedFlowCodeGenTests Assert.Contains("SetCRFloatResident(cr, 0, f31.d, f1.d);", code, StringComparison.Ordinal); Assert.DoesNotContain("SetCRFloatResident(cr, 0, PPC_PsToScalarInline(f31.d)", code, StringComparison.Ordinal); } + + [Fact] + public void ResolvedScalarLoadEndsPairedStateAcrossEdge() + { + var function = new IrFunction("resolved_load_clears_paired", "entry", new[] + { + new IrBasicBlock("entry", new IrInstruction[] + { + new IrCall("f5", "PPC_PsMul", new[] { IrValue.Register("f1"), IrValue.Register("f2") }), + new IrResolveGuestMemoryRange("range", IrValue.Register("r3"), 0, 8, true, false), + new IrResolvedLoad("f5", "range", new IrAddress("r3", 0), 0, 8), + new IrJump("next") + }), + new IrBasicBlock("next", new IrInstruction[] + { + new IrSetCrField(0, IrValue.Register("f5"), IrValue.Register("f1"), false), + new IrReturn(null) + }) + }); + var types = new RepresentationEnvironment(new Dictionary + { + ["f1"] = ValueRepresentation.Float64, + ["f2"] = ValueRepresentation.Float64, + ["f5"] = ValueRepresentation.Float64, + ["r3"] = ValueRepresentation.UInt32 + }); + var signature = new FunctionAbiClassification("resolved_load_clears_paired", ValueRepresentation.Void); + + var code = new CxxLinearCodeGenerator().Emit( + 0x80006008, new SsaTransformer().Convert(function), signature, types); + + Assert.Contains("SetCRFloatResident(cr, 0, f5.d, f1.d);", code, StringComparison.Ordinal); + Assert.DoesNotContain("PPC_PsToScalarInline(f5.d)", code, StringComparison.Ordinal); + } + + [Fact] + public void ResolvedPsqLoadStaysPairedAcrossEdge() + { + var function = new IrFunction("resolved_psq_load_paired", "entry", new[] + { + new IrBasicBlock("entry", new IrInstruction[] + { + new IrResolveGuestMemoryRange("range", IrValue.Register("r3"), 0, 8, true, false), + new IrResolvedPsqLoad("f5", "range", IrValue.Register("r3"), 0, 0, 0, 0u), + new IrJump("next") + }), + new IrBasicBlock("next", new IrInstruction[] + { + new IrSetCrField(0, IrValue.Register("f5"), IrValue.Register("f1"), false), + new IrReturn(null) + }) + }); + var types = new RepresentationEnvironment(new Dictionary + { + ["f1"] = ValueRepresentation.Float64, + ["f5"] = ValueRepresentation.Float64, + ["r3"] = ValueRepresentation.UInt32 + }); + var signature = new FunctionAbiClassification("resolved_psq_load_paired", ValueRepresentation.Void); + + var code = new CxxLinearCodeGenerator().Emit( + 0x8000600C, new SsaTransformer().Convert(function), signature, types); + + Assert.Contains("SetCRFloatResident(cr, 0, PPC_PsToScalarInline(f5.d), f1.d);", code, StringComparison.Ordinal); + } } diff --git a/translator/tests/Translator.Tests/RegionalRetroRewindTests.cs b/translator/tests/Translator.Tests/RegionalRetroRewindTests.cs new file mode 100644 index 0000000..08d1226 --- /dev/null +++ b/translator/tests/Translator.Tests/RegionalRetroRewindTests.cs @@ -0,0 +1,114 @@ +using System.Buffers.Binary; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using Translator.Cli.Configuration; +using Translator.Core.Mods.Mkwii; +using Translator.Core.Parsing.Kamek; +using PayloadFiles = WiiCompiled.Setup.Common.RetroWfcPayload; + +namespace Translator.Tests; + +public sealed class RegionalRetroRewindTests +{ + [Theory] + [InlineData("mkwii", "RMCP01", "P", 0x800ED6E8u, 0x80601C60u, 0x4BD977A4u)] + [InlineData("mkwii-ntsc-u", "RMCE01", "E", 0x800ED648u, 0x805DD380u, 0x4BDB7D04u)] + [InlineData("mkwii-ntsc-j", "RMCJ01", "J", 0x800ED608u, 0x806013D4u, 0x4BD979B0u)] + public void RetailProfileUsesMatchingRegionAndSuppressesItsBootstrap( + string directory, string gameId, string region, uint hook, uint integritySite, uint expectedBranch) + { + var root = ProjectPathsForTests.FindRepositoryRoot(); + var source = File.ReadAllText(Path.Combine(root, "projects", directory, "recomp.yml")); + var expectedDolHash = Regex.Match(source, @"sha256: ([0-9a-f]{64})").Groups[1].Value; + var scratch = Path.Combine(Path.GetTempPath(), $"retro-profile-{Guid.NewGuid():N}"); + Directory.CreateDirectory(scratch); + TranslationProjectConfig project; + try + { + // Keep this suite binary-free: substitute only the retail input paths and hashes. + // The profile block, including its original compatibility pins, is read unchanged. + var input = Path.Combine(scratch, "input.bin"); + File.WriteAllBytes(input, new byte[0x100]); + var hash = Convert.ToHexString(SHA256.HashData(File.ReadAllBytes(input))).ToLowerInvariant(); + source = source.Replace("workspace_root: ../..", $"workspace_root: {root}") + .Replace("path: Assets/main.dol", $"path: {input}") + .Replace("path: Assets/StaticR.rel", $"path: {input}"); + source = Regex.Replace(source, @"(?m)^ sha256: [0-9a-f]{64}\r?$", $" sha256: {hash}"); + var manifest = Path.Combine(scratch, "recomp.yml"); + File.WriteAllText(manifest, source); + project = TranslationProjectConfig.Load(manifest); + } + finally { Directory.Delete(scratch, true); } + var profile = project.Profiles["retro-rewind"]; + Assert.True(profile.Enabled); + Assert.Equal(gameId, profile.RequiresGameId); + Assert.Equal(expectedDolHash, profile.RequiresDolSha256); + Assert.Equal(region, profile.Region); + Assert.Equal(PayloadFiles.PayloadUri(gameId), profile.RetroWfcPayload); + Assert.Equal(hook, profile.RetroWfcLegacyBootstrapHook); + + // The pack checks the static branch bytes at Page::IncrementDuration + 0x18. + // Its hook is module offset 0x124. A PAL link base in an NTSC profile translates + // successfully but fails this check at boot, so pin the actual expected opcode. + Assert.Equal(expectedBranch, KamekPpcEncoding.EncodeBranch( + integritySite, profile.ModuleLinkBase!.Value + 0x124u, link: false)); + + // A combined pack has a different absolute hook in each regional chunk. + // Selecting a region and suppressing a PAL hook in it must not succeed. + var bootstrap = new KamekCommand(0, 0, KamekCommandId.Branch, true, hook, [0x100u]); + var chunk = new KamekChunk(0, 0, 0, 4, 0, 0, 4, new byte[4], [bootstrap]); + Assert.Empty(RetroWfcBootstrapSuppressor.Suppress(chunk, profile.RetroWfcLegacyBootstrapHook!.Value).Commands); + if (region != "P") + Assert.Throws(() => RetroWfcBootstrapSuppressor.Suppress(chunk, 0x800ED6E8u)); + } + + [Theory] + [InlineData("RMCP01")] + [InlineData("RMCE01")] + [InlineData("RMCJ01")] + public void StagedPayloadRequiresValidSignatureAndMatchingGame(string gameId) + { + var root = Path.Combine(Path.GetTempPath(), $"retro-region-{Guid.NewGuid():N}"); + try + { + var path = Path.Combine(root, PayloadFiles.PayloadRelativePath(gameId)); + Directory.CreateDirectory(Path.GetDirectoryName(path)!); + using var rsa = RSA.Create(2048); + var key = rsa.ExportParameters(false); + var image = new byte[0x150]; + "WWFC/Payload"u8.CopyTo(image); + BinaryPrimitives.WriteUInt32BigEndian(image.AsSpan(0x0C), (uint)image.Length); + Encoding.ASCII.GetBytes(PayloadFiles.PayloadGame(gameId)).CopyTo(image, 0x138); + Sign(); + Assert.Equal(path, PayloadFiles.ResolveRetroWfcPayloadFile(root, gameId, key)); + + image[^1] ^= 1; + File.WriteAllBytes(path, image); + Assert.Throws(() => PayloadFiles.ResolveRetroWfcPayloadFile(root, gameId, key)); + + // Even a correctly signed payload renamed to this region's filename is rejected. + Encoding.ASCII.GetBytes(gameId == "RMCP01" ? "RMCED00" : "RMCPD00").CopyTo(image, 0x138); + Sign(); + Assert.Throws(() => PayloadFiles.ResolveRetroWfcPayloadFile(root, gameId, key)); + + void Sign() + { + rsa.SignData(image.AsSpan(0x110), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1) + .CopyTo(image.AsSpan(0x10)); + File.WriteAllBytes(path, image); + } + } + finally { if (Directory.Exists(root)) Directory.Delete(root, true); } + } + + [Theory] + [InlineData("https://rwfc.net/api/wfc/payload?g=RMCED00")] + [InlineData("https://rwfc.net/api/wfc/payload?g=RMCJD00")] + public void OnlyExactRegionalDownloadEndpointsAreAccepted(string uri) + { + PayloadFiles.ValidateRetroWfcPayloadUri(uri); + Assert.Throws(() => PayloadFiles.ValidateRetroWfcPayloadUri(uri + "&extra=1")); + Assert.Throws(() => PayloadFiles.ValidateRetroWfcPayloadUri(uri.Replace("https:", "http:"))); + } +} diff --git a/translator/tests/Translator.Tests/RetroRewindRegionPatchesTests.cs b/translator/tests/Translator.Tests/RetroRewindRegionPatchesTests.cs new file mode 100644 index 0000000..feb1ece --- /dev/null +++ b/translator/tests/Translator.Tests/RetroRewindRegionPatchesTests.cs @@ -0,0 +1,162 @@ +using System.Buffers.Binary; +using Translator.Core.Loading; +using Translator.Core.Mods.Mkwii; +using Translator.Core.Parsing.Kamek; + +namespace Translator.Tests; + +public sealed class RetroRewindRegionPatchesTests +{ + private static readonly (uint Pal, uint Us, uint Target)[] UnportedHooks = + [ + (0x808B4D48, 0x808B0698, 0x80563BE8), + (0x808B4DFC, 0x808B074C, 0x80563CD8), + (0x808B4E14, 0x808B0764, 0x80563CCC), + (0x808CB02C, 0x808C5D24, 0x8072E068), + (0x808DBCD8, 0x808D7580, 0x806FAB44), + ]; + + [Fact] + public void MovesEveryUnportedHookToItsUsSlotAndKeepsPortedOnes() + { + var pal = Chunk([.. UnportedHooks.Select(h => Command(KamekCommandId.Addr32, h.Pal)), + Command(KamekCommandId.Branch, 0x807C8994)]); + var us = Chunk([.. UnportedHooks.Select(h => Command(KamekCommandId.Addr32, h.Pal)), + Command(KamekCommandId.Branch, 0x807B9F34)]); + var corrected = RetroRewindRegionPatches.CorrectUnportedUsHooks(us, pal, "RMCE01", SlotImage()); + + for (var i = 0; i < UnportedHooks.Length; i++) + { + Assert.Equal(UnportedHooks[i].Us, corrected.Commands[i].Address); + Assert.Equal(us.Commands[i].Arguments, corrected.Commands[i].Arguments); + } + Assert.Same(us.Commands[^1], corrected.Commands[^1]); + Assert.Same(us.CodeBlob, corrected.CodeBlob); + } + + [Theory] + [InlineData("RMCP01")] + [InlineData("RMCJ01")] + public void LeavesOtherRegionsUntouched(string gameId) + { + var chunk = Chunk(Command(KamekCommandId.Addr32, 0x808DBCD8)); + Assert.Same(chunk, RetroRewindRegionPatches.CorrectUnportedUsHooks(chunk, chunk, gameId, SlotImage())); + } + + [Fact] + public void AcceptsAPackWhosePortMapCoversTheHooks() + { + var pal = Chunk(Command(KamekCommandId.Addr32, 0x808DBCD8)); + var us = Chunk(Command(KamekCommandId.Addr32, 0x808D7580)); + Assert.Same(us, RetroRewindRegionPatches.CorrectUnportedUsHooks(us, pal, "RMCE01", SlotImage())); + } + + [Fact] + public void RejectsAnUnknownUnportedRelAddress() + { + var chunk = Chunk(Command(KamekCommandId.Addr32, 0x808B4D60)); + Assert.Throws(() => + RetroRewindRegionPatches.CorrectUnportedUsHooks(chunk, chunk, "RMCE01", SlotImage())); + } + + [Fact] + public void IgnoresSharedAddressesOutsideStaticR() + { + var chunk = Chunk(Command(KamekCommandId.Write32, 0x80001A80)); + Assert.Same(chunk, RetroRewindRegionPatches.CorrectUnportedUsHooks(chunk, chunk, "RMCE01", SlotImage())); + } + + [Fact] + public void RejectsAMismatchedSlotOrCommand() + { + var hook = Chunk(Command(KamekCommandId.Addr32, 0x808DBCD8)); + var image = SlotImage(); + image.Memory[image.GetOffset(0x808D7580)] ^= 1; + Assert.Throws(() => + RetroRewindRegionPatches.CorrectUnportedUsHooks(hook, hook, "RMCE01", image)); + var write = Chunk(Command(KamekCommandId.Write32, 0x808DBCD8)); + Assert.Throws(() => + RetroRewindRegionPatches.CorrectUnportedUsHooks(write, write, "RMCE01", SlotImage())); + Assert.Throws(() => RetroRewindRegionPatches.CorrectUnportedUsHooks( + hook, Chunk(Command(KamekCommandId.Addr32, 0x808DBCD8), Command(KamekCommandId.Branch, 0x80000100)), + "RMCE01", SlotImage())); + } + + private static readonly uint[] EsrbHook = + [0x3C608000, 0x88030003, 0x2C000045, 0x4C820020, 0x3C804800, 0x3C608060, 0x3804001C, 0x90034094, 0x4E800020]; + + [Fact] + public void AppliesTheUsEsrbSkipStaticallyAndDropsTheStore() + { + var chunk = EsrbChunk(0x40); + var patched = RetroRewindRegionPatches.ApplyUsEsrbSkip(chunk, "RMCE01", EsrbImage(0x3C608038)); + + var write = Assert.Single(patched.Commands); + Assert.Equal(KamekCommandId.Write32, write.Id); + Assert.True(write.AddressIsAbsolute); + Assert.Equal(0x80604094u, write.Address); + Assert.Equal([0x4800001Cu], write.Arguments); + Assert.Equal(0x60000000u, BinaryPrimitives.ReadUInt32BigEndian(patched.CodeBlob.AsSpan(0x40 + 7 * 4, 4))); + Assert.Equal(0x90034094u, BinaryPrimitives.ReadUInt32BigEndian(chunk.CodeBlob.AsSpan(0x40 + 7 * 4, 4))); + } + + [Theory] + [InlineData("RMCP01")] + [InlineData("RMCJ01")] + public void LeavesTheEsrbHookAloneOutsideNtscU(string gameId) + { + var chunk = EsrbChunk(0x40); + Assert.Same(chunk, RetroRewindRegionPatches.ApplyUsEsrbSkip(chunk, gameId, EsrbImage(0x3C608038))); + } + + [Fact] + public void LeavesAPackWithoutTheEsrbHookAlone() + { + var chunk = Chunk(); + Assert.Same(chunk, RetroRewindRegionPatches.ApplyUsEsrbSkip(chunk, "RMCE01", EsrbImage(0x3C608038))); + } + + [Fact] + public void RejectsAnUnexpectedEsrbTargetOrDuplicateHook() + { + Assert.Throws(() => + RetroRewindRegionPatches.ApplyUsEsrbSkip(EsrbChunk(0x40), "RMCE01", EsrbImage(0x4800001C))); + var twice = EsrbChunk(0x40); + for (var i = 0; i < EsrbHook.Length; i++) + BinaryPrimitives.WriteUInt32BigEndian(twice.CodeBlob.AsSpan(0x100 + i * 4, 4), EsrbHook[i]); + Assert.Throws(() => + RetroRewindRegionPatches.ApplyUsEsrbSkip(twice, "RMCE01", EsrbImage(0x3C608038))); + } + + private static KamekChunk EsrbChunk(int offset) + { + var chunk = Chunk(); + for (var i = 0; i < EsrbHook.Length; i++) + BinaryPrimitives.WriteUInt32BigEndian(chunk.CodeBlob.AsSpan(offset + i * 4, 4), EsrbHook[i]); + return chunk; + } + + private static ProgramImage EsrbImage(uint instruction) + { + var memory = new byte[4]; + BinaryPrimitives.WriteUInt32BigEndian(memory, instruction); + var range = AddressRange.FromStartAndSize(0x80604094, 4); + return new ProgramImage(memory, range, default, range, "fixture", range.Start); + } + + private static KamekCommand Command(KamekCommandId id, uint address) => + new(0, 0, id, true, address, [0x100u]); + + private static KamekChunk Chunk(params KamekCommand[] commands) => + new(1, 0, 0x20, 0x200, 0, 0, 0x220, new byte[0x200], commands); + + private static ProgramImage SlotImage() + { + const uint start = 0x808B0000; + var memory = new byte[0x28000]; + foreach (var (_, us, target) in UnportedHooks) + BinaryPrimitives.WriteUInt32BigEndian(memory.AsSpan((int)(us - start), 4), target); + var range = AddressRange.FromStartAndSize(start, (uint)memory.Length); + return new ProgramImage(memory, range, default, range, "fixture", range.Start); + } +} diff --git a/translator/tests/Translator.Tests/RetroWfcPayloadLoweringTests.cs b/translator/tests/Translator.Tests/RetroWfcPayloadLoweringTests.cs index e5fe310..b66684e 100644 --- a/translator/tests/Translator.Tests/RetroWfcPayloadLoweringTests.cs +++ b/translator/tests/Translator.Tests/RetroWfcPayloadLoweringTests.cs @@ -8,6 +8,25 @@ namespace Translator.Tests; public class RetroWfcPayloadLoweringTests { + [Theory] + [InlineData("RMCP01", "P", "RMCPD00")] + [InlineData("RMCE01", "E", "RMCED00")] + [InlineData("RMCJ01", "J", "RMCJD00")] + public void PayloadMustMatchBaseDiscRegion(string gameId, string region, string payloadGame) + { + var payload = BuildSharedPayloadFixture(); + payload.AsSpan(0x138, 12).Clear(); + Encoding.ASCII.GetBytes(payloadGame).CopyTo(payload, 0x138); + var manifest = TestManifest() with { GameId = gameId, Region = region }; + var result = RetroWfcPayload.Parse(payload, manifest, 0x81800000u, 0x2000u); + Assert.Equal(payloadGame, result.Summary.Game); + Assert.True(result.LoweringPlan.IsPlannable); + + var wrongRegion = manifest with { GameId = gameId == "RMCP01" ? "RMCE01" : "RMCP01" }; + Assert.Throws(() => + RetroWfcPayload.Parse(payload, wrongRegion, 0x81800000u, 0x2000u)); + } + [Fact] public void SharedPayloadDescriptorDrivesRelocationAndStaticLowering() { @@ -35,28 +54,32 @@ public class RetroWfcPayloadLoweringTests Assert.Equal("moduleFunction", pointer.TargetKind); } - [Fact] - public void ProductionPayloadValidatesAndTranslatesEverySupportedPatch() + [Theory] + [InlineData("RMCP01", "P", "RMCPD00")] + [InlineData("RMCE01", "E", "RMCED00")] + [InlineData("RMCJ01", "J", "RMCJD00")] + public void ProductionPayloadValidatesAndTranslatesEverySupportedPatch( + string gameId, string region, string payloadGame) { var payloadRoot = Path.Combine( AppContext.BaseDirectory, "TestAssets", "RetroWfcPayload"); - WiiCompiled.Setup.Common.RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(payloadRoot); + WiiCompiled.Setup.Common.RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(payloadRoot, gameId: gameId); var payloadPath = Path.Combine( payloadRoot, "binary", - "payload.RMCPD00.bin"); + $"payload.{payloadGame}.bin"); var payload = File.ReadAllBytes(payloadPath); var result = RetroWfcPayload.Parse( payload, - ProductionPayloadManifest(), + ProductionPayloadManifest() with { GameId = gameId, Region = region }, 0x81800000u, 0x00200000u, - "TestAssets/RetroWfcPayload/binary/payload.RMCPD00.bin"); + $"TestAssets/RetroWfcPayload/binary/payload.{payloadGame}.bin"); - Assert.Equal("RMCPD00", result.Summary.Game); + Assert.Equal(payloadGame, result.Summary.Game); Assert.Equal(payload.Length, result.Summary.PayloadImageSize); Assert.True(result.LoweringPlan.IsPlannable); Assert.Empty(result.LoweringPlan.Issues); diff --git a/translator/tests/Translator.Tests/TestAssets/RetroWfcPayload/binary/payload.RMCED00.bin b/translator/tests/Translator.Tests/TestAssets/RetroWfcPayload/binary/payload.RMCED00.bin new file mode 100644 index 0000000000000000000000000000000000000000..19ef7caa5da3cc7803a3b3990f2047bdf6132e17 GIT binary patch literal 28992 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 literal 0 HcmV?d00001 diff --git a/translator/tests/Translator.Tests/TranslatedBuildShardEmitterTests.cs b/translator/tests/Translator.Tests/TranslatedBuildShardEmitterTests.cs index 384c742..b8b1a27 100644 --- a/translator/tests/Translator.Tests/TranslatedBuildShardEmitterTests.cs +++ b/translator/tests/Translator.Tests/TranslatedBuildShardEmitterTests.cs @@ -100,8 +100,10 @@ public sealed class TranslatedBuildShardEmitterTests var options = new TranslatedBuildShardOptions( metadataPath, functions, output, native, - resolvedPath, mod, BaseShardCount: 2, ModShardCount: 1, RegistrationShardCount: 1); + resolvedPath, mod, BaseShardCount: 2, ModShardCount: 1, RegistrationShardCount: 1, + Region: GuestRegion.NtscJ); var first = TranslatedBuildShardEmitter.Emit(options); + Assert.Contains("set(MKW_TRANSLATED_GUEST_REGION 2)", File.ReadAllText(first.CMakeManifestPath)); Assert.Equal(1, first.SharedBaseFunctionCount); Assert.Equal(1, first.ProfileSensitiveTargetCount); Assert.Equal(1, first.ProfileSensitiveCallerCount); diff --git a/translator/tests/Translator.Tests/Translator.Tests.csproj b/translator/tests/Translator.Tests/Translator.Tests.csproj index dccdafe..ea97250 100644 --- a/translator/tests/Translator.Tests/Translator.Tests.csproj +++ b/translator/tests/Translator.Tests/Translator.Tests.csproj @@ -30,7 +30,7 @@ - +