From 05b13b3b28fe8a9a762b845977cdd58771a62794 Mon Sep 17 00:00:00 2001 From: comboship-bot Date: Mon, 24 Aug 2026 07:01:01 +0000 Subject: [PATCH 1/3] vendor base: libultraship 7cb10226e --- libultraship/.clang-format | 23 + libultraship/.clang-tidy | 30 + libultraship/.github/workflows/apt-deps.txt | 1 + libultraship/.github/workflows/brew-deps.txt | 1 + .../.github/workflows/build-validation.yml | 246 + .../.github/workflows/test-validation.yml | 106 + .../workflows/tidy-format-validation.yml | 65 + .../.github/workflows/tidy-result-publish.yml | 74 + libultraship/.gitignore | 376 ++ libultraship/CMakeLists.txt | 88 + libultraship/CODE_OF_CONDUCT.md | 134 + libultraship/CONTRIBUTING.md | 50 + libultraship/LICENSE | 21 + libultraship/README.md | 107 + libultraship/cmake/Default.cmake | 65 + libultraship/cmake/DefaultCXX.cmake | 16 + libultraship/cmake/HandleCompilerRT.cmake | 123 + libultraship/cmake/Utils.cmake | 248 + libultraship/cmake/automate-vcpkg.cmake | 193 + libultraship/cmake/cvars.cmake | 49 + libultraship/cmake/dependencies/android.cmake | 73 + libultraship/cmake/dependencies/common.cmake | 310 + .../cmake/dependencies/git-patch.cmake | 61 + libultraship/cmake/dependencies/ios.cmake | 90 + libultraship/cmake/dependencies/linux.cmake | 10 + libultraship/cmake/dependencies/mac.cmake | 42 + libultraship/cmake/dependencies/openbsd.cmake | 20 + .../patches/imgui-fixes-and-config.patch | 112 + .../patches/stormlib-optimizations.patch | 123 + .../cmake/dependencies/windows-vcpkg.cmake | 17 + libultraship/cmake/dependencies/windows.cmake | 12 + .../cmake/ios-toolchain-populate.cmake | 15 + libultraship/docs/PORTING.md | 124 + libultraship/docs/SCRIPTING.md | 447 ++ libultraship/include/fast/Fast3dGui.h | 177 + libultraship/include/fast/Fast3dWindow.h | 105 + .../include/fast/FastMouseStateManager.h | 15 + libultraship/include/fast/LICENSE.txt | 21 + libultraship/include/fast/README.md | 24 + libultraship/include/fast/WindowEvent.h | 32 + .../include/fast/backends/gfx_direct3d11.h | 11 + .../fast/backends/gfx_direct3d_common.h | 199 + libultraship/include/fast/backends/gfx_dxgi.h | 123 + .../include/fast/backends/gfx_metal.h | 245 + .../include/fast/backends/gfx_metal_shader.h | 20 + .../include/fast/backends/gfx_opengl.h | 144 + .../include/fast/backends/gfx_rendering_api.h | 94 + .../include/fast/backends/gfx_screen_config.h | 4 + libultraship/include/fast/backends/gfx_sdl.h | 70 + .../fast/backends/gfx_window_manager_api.h | 55 + libultraship/include/fast/debug/GfxDebugger.h | 33 + libultraship/include/fast/f3dex.h | 153 + libultraship/include/fast/f3dex2.h | 149 + libultraship/include/fast/interpreter.h | 576 ++ libultraship/include/fast/lus_gbi.h | 1380 +++++ .../include/fast/resource/ResourceType.h | 14 + .../resource/factory/DisplayListFactory.h | 24 + .../fast/resource/factory/LightFactory.h | 12 + .../fast/resource/factory/MatrixFactory.h | 12 + .../fast/resource/factory/TextureFactory.h | 18 + .../fast/resource/factory/VertexFactory.h | 19 + .../include/fast/resource/type/DisplayList.h | 23 + .../include/fast/resource/type/Light.h | 65 + .../include/fast/resource/type/Matrix.h | 18 + .../include/fast/resource/type/Texture.h | 45 + .../include/fast/resource/type/Vertex.h | 20 + libultraship/include/fast/types.h | 25 + libultraship/include/fast/ucodehandlers.h | 11 + libultraship/include/libultraship/bridge.h | 11 + .../include/libultraship/bridge/audiobridge.h | 44 + .../bridge/consolevariablebridge.h | 165 + .../libultraship/bridge/controllerbridge.h | 31 + .../libultraship/bridge/crashhandlerbridge.h | 32 + .../libultraship/bridge/eventsbridge.h | 55 + .../include/libultraship/bridge/gfxbridge.h | 42 + .../libultraship/bridge/gfxdebuggerbridge.h | 40 + .../libultraship/bridge/resourcebridge.h | 157 + .../libultraship/bridge/scriptingbridge.h | 29 + .../libultraship/bridge/windowbridge.h | 33 + libultraship/include/libultraship/classes.h | 37 + libultraship/include/libultraship/color.h | 71 + .../controller/controldeck/ControlDeck.h | 79 + .../controldevice/controller/Controller.h | 56 + .../mapping/ControllerDefaultMappings.h | 78 + libultraship/include/libultraship/libultra.h | 27 + .../include/libultraship/libultra/abi.h | 471 ++ .../libultraship/libultra/controller.h | 162 + .../include/libultraship/libultra/convert.h | 15 + .../include/libultraship/libultra/eeprom.h | 18 + .../include/libultraship/libultra/exception.h | 42 + .../include/libultraship/libultra/gbi.h | 4311 +++++++++++++ .../include/libultraship/libultra/gs2dex.h | 384 ++ .../include/libultraship/libultra/gu.h | 201 + .../include/libultraship/libultra/internal.h | 27 + .../include/libultraship/libultra/interrupt.h | 5 + .../include/libultraship/libultra/mbi.h | 42 + .../include/libultraship/libultra/message.h | 66 + .../include/libultraship/libultra/motor.h | 22 + .../include/libultraship/libultra/os.h | 152 + .../include/libultraship/libultra/pfs.h | 134 + .../include/libultraship/libultra/pi.h | 79 + .../include/libultraship/libultra/printf.h | 30 + .../include/libultraship/libultra/r4300.h | 364 ++ .../include/libultraship/libultra/rcp.h | 269 + .../include/libultraship/libultra/rdp.h | 48 + .../include/libultraship/libultra/sptask.h | 65 + .../include/libultraship/libultra/thread.h | 61 + .../include/libultraship/libultra/time.h | 14 + .../include/libultraship/libultra/types.h | 33 + .../include/libultraship/libultra/vi.h | 134 + .../include/libultraship/libultraship.h | 10 + .../include/libultraship/log/luslog.h | 65 + libultraship/include/libultraship/luslog.h | 3 + .../window/gui/GfxDebuggerWindow.h | 58 + .../window/gui/InputEditorWindow.h | 253 + libultraship/include/ship/Api.h | 38 + libultraship/include/ship/Context.h | 302 + libultraship/include/ship/audio/Audio.h | 99 + .../include/ship/audio/AudioChannelsSetting.h | 32 + libultraship/include/ship/audio/AudioPlayer.h | 166 + .../include/ship/audio/CoreAudioAudioPlayer.h | 82 + .../include/ship/audio/NullAudioPlayer.h | 40 + .../include/ship/audio/SDLAudioPlayer.h | 55 + .../include/ship/audio/SoundMatrixDecoder.h | 183 + .../include/ship/audio/WasapiAudioPlayer.h | 120 + libultraship/include/ship/config/Config.h | 235 + .../include/ship/config/ConsoleVariable.h | 213 + .../ship/controller/controldeck/ControlDeck.h | 148 + .../ship/controller/controldeck/ControlPort.h | 56 + .../controller/controldevice/ControlDevice.h | 27 + .../controldevice/controller/Controller.h | 167 + .../controller/ControllerButton.h | 149 + .../controldevice/controller/ControllerGyro.h | 68 + .../controldevice/controller/ControllerLED.h | 95 + .../controller/ControllerRumble.h | 102 + .../controller/ControllerStick.h | 226 + .../mapping/ControllerAxisDirectionMapping.h | 79 + .../mapping/ControllerButtonMapping.h | 72 + .../mapping/ControllerDefaultMappings.h | 155 + .../mapping/ControllerGyroMapping.h | 89 + .../mapping/ControllerInputMapping.h | 31 + .../controller/mapping/ControllerLEDMapping.h | 87 + .../controller/mapping/ControllerMapping.h | 44 + .../mapping/ControllerRumbleMapping.h | 103 + .../factories/AxisDirectionMappingFactory.h | 67 + .../mapping/factories/ButtonMappingFactory.h | 63 + .../mapping/factories/GyroMappingFactory.h | 32 + .../mapping/factories/LEDMappingFactory.h | 33 + .../mapping/factories/RumbleMappingFactory.h | 42 + .../keyboard/KeyboardKeyToAnyMapping.h | 44 + .../KeyboardKeyToAxisDirectionMapping.h | 45 + .../keyboard/KeyboardKeyToButtonMapping.h | 46 + .../mapping/keyboard/KeyboardScancodes.h | 167 + .../mapping/mouse/MouseButtonToAnyMapping.h | 44 + .../mouse/MouseButtonToAxisDirectionMapping.h | 47 + .../mouse/MouseButtonToButtonMapping.h | 49 + .../mapping/mouse/MouseWheelToAnyMapping.h | 35 + .../mouse/MouseWheelToAxisDirectionMapping.h | 48 + .../mapping/mouse/MouseWheelToButtonMapping.h | 49 + .../controller/mapping/mouse/WheelHandler.h | 79 + .../sdl/SDLAxisDirectionToAnyMapping.h | 48 + .../SDLAxisDirectionToAxisDirectionMapping.h | 47 + .../sdl/SDLAxisDirectionToButtonMapping.h | 48 + .../mapping/sdl/SDLButtonToAnyMapping.h | 38 + .../sdl/SDLButtonToAxisDirectionMapping.h | 45 + .../mapping/sdl/SDLButtonToButtonMapping.h | 46 + .../controller/mapping/sdl/SDLGyroMapping.h | 51 + .../controller/mapping/sdl/SDLLEDMapping.h | 40 + .../controller/mapping/sdl/SDLMapping.h | 13 + .../controller/mapping/sdl/SDLRumbleMapping.h | 57 + .../ConnectedPhysicalDeviceManager.h | 90 + .../physicaldevice/GlobalSDLDeviceSettings.h | 54 + .../physicaldevice/PhysicalDeviceType.h | 18 + .../SDLAddRemoveDeviceEventHandler.h | 30 + libultraship/include/ship/debug/Console.h | 125 + .../include/ship/debug/CrashHandler.h | 109 + libultraship/include/ship/events/CoreEvents.h | 10 + .../include/ship/events/EventSystem.h | 130 + libultraship/include/ship/events/EventTypes.h | 179 + .../include/ship/port/mobile/MobileImpl.h | 14 + libultraship/include/ship/resource/File.h | 67 + libultraship/include/ship/resource/Resource.h | 88 + .../include/ship/resource/ResourceFactory.h | 56 + .../ship/resource/ResourceFactoryBinary.h | 24 + .../ship/resource/ResourceFactoryXML.h | 24 + .../include/ship/resource/ResourceLoader.h | 186 + .../include/ship/resource/ResourceManager.h | 433 ++ .../include/ship/resource/ResourceType.h | 22 + .../include/ship/resource/archive/Archive.h | 211 + .../ship/resource/archive/ArchiveManager.h | 241 + .../ship/resource/archive/FolderArchive.h | 85 + .../ship/resource/archive/O2rArchive.h | 82 + .../ship/resource/archive/OtrArchive.h | 81 + .../ship/resource/factory/BlobFactory.h | 23 + .../ship/resource/factory/JsonFactory.h | 23 + .../ship/resource/factory/ShaderFactory.h | 24 + .../include/ship/resource/type/Blob.h | 35 + .../include/ship/resource/type/Json.h | 39 + .../include/ship/resource/type/Shader.h | 37 + .../include/ship/scripting/LibraryLoader.h | 87 + .../include/ship/scripting/ScriptLoader.h | 109 + libultraship/include/ship/security/Keystore.h | 96 + .../include/ship/utils/AppleFolderManager.h | 123 + .../include/ship/utils/HResultException.h | 43 + libultraship/include/ship/utils/StrHash64.h | 129 + .../include/ship/utils/StringHelper.h | 166 + libultraship/include/ship/utils/Utils.h | 66 + .../ship/utils/binarytools/BinaryReader.h | 159 + .../ship/utils/binarytools/BinaryWriter.h | 143 + .../ship/utils/binarytools/BitConverter.h | 256 + .../ship/utils/binarytools/MemoryStream.h | 117 + .../include/ship/utils/binarytools/Stream.h | 101 + .../ship/utils/binarytools/endianness.h | 92 + libultraship/include/ship/utils/color.h | 35 + .../ship/utils/filesystemtools/Directory.h | 84 + .../ship/utils/filesystemtools/DiskFile.h | 136 + .../ship/utils/filesystemtools/FileHelper.h | 154 + .../include/ship/utils/filesystemtools/Path.h | 80 + .../ship/utils/filesystemtools/PathHelper.h | 85 + libultraship/include/ship/utils/glob.h | 22 + libultraship/include/ship/utils/macUtils.h | 23 + libultraship/include/ship/utils/stox.h | 45 + .../include/ship/window/FileDropMgr.h | 71 + .../include/ship/window/MouseStateManager.h | 82 + libultraship/include/ship/window/Window.h | 298 + .../include/ship/window/gui/ConsoleWindow.h | 170 + .../ship/window/gui/EventDebuggerWindow.h | 29 + .../ship/window/gui/FileBrowserWindow.h | 138 + libultraship/include/ship/window/gui/Fonts.h | 2304 +++++++ .../include/ship/window/gui/GameOverlay.h | 137 + libultraship/include/ship/window/gui/Gui.h | 246 + .../include/ship/window/gui/GuiElement.h | 99 + .../include/ship/window/gui/GuiMenuBar.h | 52 + .../include/ship/window/gui/GuiWindow.h | 130 + .../ship/window/gui/IconsFontAwesome4.h | 694 +++ .../include/ship/window/gui/StatsWindow.h | 30 + .../include/ship/window/gui/resource/Font.h | 44 + .../ship/window/gui/resource/FontFactory.h | 22 + .../ship/window/gui/resource/GuiTexture.h | 60 + .../window/gui/resource/GuiTextureFactory.h | 22 + libultraship/keys/script/HM64.pem | 3 + libultraship/keys/script/Kenix1.pem | 3 + libultraship/keys/script/Kenix2.pem | 3 + libultraship/keys/script/Kenix3.pem | 3 + libultraship/keys/script/Kenix4.pem | 3 + libultraship/keys/script/Kenix5.pem | 3 + libultraship/requirements.txt | 2 + libultraship/run-clang-format.ps1 | 101 + libultraship/src/CMakeLists.txt | 261 + libultraship/src/fast/CMakeLists.txt | 43 + libultraship/src/fast/Fast3dGui.cpp | 773 +++ libultraship/src/fast/Fast3dWindow.cpp | 447 ++ .../src/fast/FastMouseStateManager.cpp | 21 + libultraship/src/fast/LICENSE.txt | 21 + libultraship/src/fast/README.md | 24 + .../src/fast/backends/gfx_direct3d11.cpp | 1469 +++++ .../src/fast/backends/gfx_direct3d_common.cpp | 5 + libultraship/src/fast/backends/gfx_dxgi.cpp | 1144 ++++ libultraship/src/fast/backends/gfx_metal.cpp | 1298 ++++ .../src/fast/backends/gfx_metal_shader.cpp | 285 + libultraship/src/fast/backends/gfx_opengl.cpp | 1111 ++++ libultraship/src/fast/backends/gfx_sdl2.cpp | 796 +++ libultraship/src/fast/debug/GfxDebugger.cpp | 54 + libultraship/src/fast/interpreter.cpp | 5512 +++++++++++++++++ .../resource/factory/DisplayListFactory.cpp | 1198 ++++ .../fast/resource/factory/LightFactory.cpp | 17 + .../fast/resource/factory/MatrixFactory.cpp | 28 + .../fast/resource/factory/TextureFactory.cpp | 49 + .../fast/resource/factory/VertexFactory.cpp | 75 + .../src/fast/resource/type/DisplayList.cpp | 21 + libultraship/src/fast/resource/type/Light.cpp | 11 + .../src/fast/resource/type/Matrix.cpp | 14 + .../src/fast/resource/type/Texture.cpp | 20 + .../src/fast/resource/type/Vertex.cpp | 15 + .../fast/shaders/directx/default.shader.hlsl | 354 ++ .../fast/shaders/metal/default.shader.metal | 305 + .../fast/shaders/opengl/default.shader.glsl | 297 + libultraship/src/libultraship/CMakeLists.txt | 52 + .../src/libultraship/bridge/audiobridge.cpp | 74 + .../bridge/consolevariablebridge.cpp | 88 + .../libultraship/bridge/controllerbridge.cpp | 14 + .../bridge/crashhandlerbridge.cpp | 7 + .../src/libultraship/bridge/eventsbridge.cpp | 23 + .../src/libultraship/bridge/gfxbridge.cpp | 31 + .../libultraship/bridge/gfxdebuggerbridge.cpp | 27 + .../libultraship/bridge/resourcebridge.cpp | 172 + .../libultraship/bridge/scriptingbridge.cpp | 12 + .../src/libultraship/bridge/windowbridge.cpp | 34 + .../controller/controldeck/ControlDeck.cpp | 74 + .../controldevice/controller/Controller.cpp | 75 + .../mapping/ControllerDefaultMappings.cpp | 104 + .../libultra/AudioDmaRegistry.cpp | 39 + .../libultraship/libultra/AudioDmaRegistry.h | 21 + libultraship/src/libultraship/libultra/os.cpp | 91 + .../src/libultraship/libultra/os_cache.cpp | 16 + .../src/libultraship/libultra/os_eeprom.cpp | 51 + .../src/libultraship/libultra/os_mesg.cpp | 59 + .../src/libultraship/libultra/os_pi.cpp | 29 + .../src/libultraship/libultra/os_time.cpp | 0 .../src/libultraship/libultra/os_vi.cpp | 52 + .../src/libultraship/libultra/os_vm.cpp | 11 + libultraship/src/libultraship/log/luslog.cpp | 23 + .../window/gui/GfxDebuggerWindow.cpp | 749 +++ .../window/gui/InputEditorWindow.cpp | 1429 +++++ libultraship/src/ship/CMakeLists.txt | 120 + libultraship/src/ship/Context.cpp | 612 ++ libultraship/src/ship/audio/Audio.cpp | 164 + libultraship/src/ship/audio/AudioPlayer.cpp | 108 + .../src/ship/audio/CoreAudioAudioPlayer.cpp | 212 + .../src/ship/audio/NullAudioPlayer.cpp | 26 + .../src/ship/audio/SDLAudioPlayer.cpp | 62 + .../src/ship/audio/SoundMatrixDecoder.cpp | 284 + .../src/ship/audio/WasapiAudioPlayer.cpp | 214 + libultraship/src/ship/config/Config.cpp | 258 + .../src/ship/config/ConsoleVariable.cpp | 383 ++ .../controller/controldeck/ControlDeck.cpp | 136 + .../controller/controldeck/ControlPort.cpp | 30 + .../controldevice/ControlDevice.cpp | 10 + .../controldevice/controller/Controller.cpp | 202 + .../controller/ControllerButton.cpp | 256 + .../controller/ControllerGyro.cpp | 97 + .../controller/ControllerLED.cpp | 141 + .../controller/ControllerRumble.cpp | 157 + .../controller/ControllerStick.cpp | 476 ++ .../ControllerAxisDirectionMapping.cpp | 27 + .../mapping/ControllerButtonMapping.cpp | 26 + .../mapping/ControllerDefaultMappings.cpp | 133 + .../mapping/ControllerGyroMapping.cpp | 38 + .../mapping/ControllerInputMapping.cpp | 14 + .../mapping/ControllerLEDMapping.cpp | 42 + .../controller/mapping/ControllerMapping.cpp | 17 + .../mapping/ControllerRumbleMapping.cpp | 50 + .../factories/AxisDirectionMappingFactory.cpp | 221 + .../factories/ButtonMappingFactory.cpp | 181 + .../mapping/factories/GyroMappingFactory.cpp | 83 + .../mapping/factories/LEDMappingFactory.cpp | 77 + .../factories/RumbleMappingFactory.cpp | 89 + .../keyboard/KeyboardKeyToAnyMapping.cpp | 46 + .../KeyboardKeyToAxisDirectionMapping.cpp | 66 + .../keyboard/KeyboardKeyToButtonMapping.cpp | 66 + .../mapping/mouse/MouseButtonToAnyMapping.cpp | 31 + .../MouseButtonToAxisDirectionMapping.cpp | 66 + .../mouse/MouseButtonToButtonMapping.cpp | 65 + .../mapping/mouse/MouseWheelToAnyMapping.cpp | 22 + .../MouseWheelToAxisDirectionMapping.cpp | 72 + .../mouse/MouseWheelToButtonMapping.cpp | 66 + .../controller/mapping/mouse/WheelHandler.cpp | 103 + .../sdl/SDLAxisDirectionToAnyMapping.cpp | 56 + ...SDLAxisDirectionToAxisDirectionMapping.cpp | 98 + .../sdl/SDLAxisDirectionToButtonMapping.cpp | 92 + .../mapping/sdl/SDLButtonToAnyMapping.cpp | 72 + .../sdl/SDLButtonToAxisDirectionMapping.cpp | 78 + .../mapping/sdl/SDLButtonToButtonMapping.cpp | 70 + .../controller/mapping/sdl/SDLGyroMapping.cpp | 115 + .../controller/mapping/sdl/SDLLEDMapping.cpp | 65 + .../mapping/sdl/SDLRumbleMapping.cpp | 78 + .../ConnectedPhysicalDeviceManager.cpp | 108 + .../GlobalSDLDeviceSettings.cpp | 59 + .../SDLAddRemoveDeviceEventHandler.cpp | 50 + libultraship/src/ship/debug/Console.cpp | 77 + libultraship/src/ship/debug/CrashHandler.cpp | 452 ++ libultraship/src/ship/events/EventSystem.cpp | 75 + libultraship/src/ship/install_config.h.in | 3 + .../src/ship/port/mobile/MobileImpl.cpp | 26 + libultraship/src/ship/resource/Resource.cpp | 23 + .../ship/resource/ResourceFactoryBinary.cpp | 20 + .../src/ship/resource/ResourceFactoryXML.cpp | 19 + .../src/ship/resource/ResourceLoader.cpp | 342 + .../src/ship/resource/ResourceManager.cpp | 533 ++ .../src/ship/resource/archive/Archive.cpp | 300 + .../ship/resource/archive/ArchiveManager.cpp | 319 + .../ship/resource/archive/FolderArchive.cpp | 75 + .../src/ship/resource/archive/O2rArchive.cpp | 196 + .../src/ship/resource/archive/OtrArchive.cpp | 115 + .../src/ship/resource/factory/BlobFactory.cpp | 32 + .../src/ship/resource/factory/JsonFactory.cpp | 20 + .../ship/resource/factory/ShaderFactory.cpp | 18 + libultraship/src/ship/resource/type/Blob.cpp | 14 + libultraship/src/ship/resource/type/Json.cpp | 14 + .../src/ship/resource/type/Shader.cpp | 14 + .../src/ship/scripting/LibraryLoader.cpp | 206 + .../src/ship/scripting/ScriptLoader.cpp | 363 ++ libultraship/src/ship/security/Keystore.cpp | 89 + .../src/ship/utils/AppleFolderManager.mm | 64 + libultraship/src/ship/utils/StrHash64.cpp | 183 + libultraship/src/ship/utils/StringHelper.cpp | 187 + libultraship/src/ship/utils/Utils.cpp | 72 + .../ship/utils/binarytools/BinaryReader.cpp | 205 + .../ship/utils/binarytools/BinaryWriter.cpp | 150 + .../ship/utils/binarytools/MemoryStream.cpp | 95 + .../src/ship/utils/binarytools/Stream.cpp | 5 + libultraship/src/ship/utils/glob.c | 125 + libultraship/src/ship/utils/macUtils.mm | 28 + libultraship/src/ship/utils/stox.cpp | 62 + libultraship/src/ship/window/FileDropMgr.cpp | 118 + .../src/ship/window/MouseStateManager.cpp | 88 + libultraship/src/ship/window/Window.cpp | 153 + .../src/ship/window/gui/ConsoleWindow.cpp | 717 +++ .../ship/window/gui/EventDebuggerWindow.cpp | 126 + .../src/ship/window/gui/FileBrowserWindow.cpp | 441 ++ .../src/ship/window/gui/GameOverlay.cpp | 270 + libultraship/src/ship/window/gui/Gui.cpp | 421 ++ .../src/ship/window/gui/GuiElement.cpp | 51 + .../src/ship/window/gui/GuiMenuBar.cpp | 54 + .../src/ship/window/gui/GuiWindow.cpp | 207 + .../src/ship/window/gui/StatsWindow.cpp | 37 + .../src/ship/window/gui/resource/Font.cpp | 20 + .../ship/window/gui/resource/FontFactory.cpp | 22 + .../ship/window/gui/resource/GuiTexture.cpp | 20 + .../window/gui/resource/GuiTextureFactory.cpp | 30 + libultraship/tests/CMakeLists.txt | 50 + libultraship/tests/archive_resource_tests.cpp | 753 +++ libultraship/tests/archive_self_tests.cpp | 227 + libultraship/tests/binary_io_tests.cpp | 412 ++ libultraship/tests/bitconverter_tests.cpp | 199 + libultraship/tests/crc64_tests.cpp | 75 + libultraship/tests/event_system_tests.cpp | 252 + libultraship/tests/glob_tests.cpp | 211 + libultraship/tests/path_diskfile_tests.cpp | 252 + libultraship/tests/path_file_helper_tests.cpp | 267 + libultraship/tests/resource_type_tests.cpp | 408 ++ libultraship/tests/script_test.cpp | 156 + .../tests/sound_matrix_decoder_tests.cpp | 164 + libultraship/tests/splittext_tests.cpp | 116 + libultraship/tests/stox_tests.cpp | 112 + libultraship/tests/string_helper_tests.cpp | 347 ++ libultraship/tests/utils_tests.cpp | 103 + libultraship/tools/generate_keys.py | 31 + libultraship/tools/generate_keys_header.py | 62 + libultraship/tools/sign.py | 98 + 430 files changed, 67265 insertions(+) create mode 100644 libultraship/.clang-format create mode 100644 libultraship/.clang-tidy create mode 100644 libultraship/.github/workflows/apt-deps.txt create mode 100644 libultraship/.github/workflows/brew-deps.txt create mode 100644 libultraship/.github/workflows/build-validation.yml create mode 100644 libultraship/.github/workflows/test-validation.yml create mode 100644 libultraship/.github/workflows/tidy-format-validation.yml create mode 100644 libultraship/.github/workflows/tidy-result-publish.yml create mode 100644 libultraship/.gitignore create mode 100644 libultraship/CMakeLists.txt create mode 100644 libultraship/CODE_OF_CONDUCT.md create mode 100644 libultraship/CONTRIBUTING.md create mode 100644 libultraship/LICENSE create mode 100644 libultraship/README.md create mode 100644 libultraship/cmake/Default.cmake create mode 100644 libultraship/cmake/DefaultCXX.cmake create mode 100644 libultraship/cmake/HandleCompilerRT.cmake create mode 100644 libultraship/cmake/Utils.cmake create mode 100644 libultraship/cmake/automate-vcpkg.cmake create mode 100644 libultraship/cmake/cvars.cmake create mode 100644 libultraship/cmake/dependencies/android.cmake create mode 100644 libultraship/cmake/dependencies/common.cmake create mode 100644 libultraship/cmake/dependencies/git-patch.cmake create mode 100644 libultraship/cmake/dependencies/ios.cmake create mode 100644 libultraship/cmake/dependencies/linux.cmake create mode 100644 libultraship/cmake/dependencies/mac.cmake create mode 100644 libultraship/cmake/dependencies/openbsd.cmake create mode 100644 libultraship/cmake/dependencies/patches/imgui-fixes-and-config.patch create mode 100644 libultraship/cmake/dependencies/patches/stormlib-optimizations.patch create mode 100644 libultraship/cmake/dependencies/windows-vcpkg.cmake create mode 100644 libultraship/cmake/dependencies/windows.cmake create mode 100644 libultraship/cmake/ios-toolchain-populate.cmake create mode 100644 libultraship/docs/PORTING.md create mode 100644 libultraship/docs/SCRIPTING.md create mode 100644 libultraship/include/fast/Fast3dGui.h create mode 100644 libultraship/include/fast/Fast3dWindow.h create mode 100644 libultraship/include/fast/FastMouseStateManager.h create mode 100644 libultraship/include/fast/LICENSE.txt create mode 100644 libultraship/include/fast/README.md create mode 100644 libultraship/include/fast/WindowEvent.h create mode 100644 libultraship/include/fast/backends/gfx_direct3d11.h create mode 100644 libultraship/include/fast/backends/gfx_direct3d_common.h create mode 100644 libultraship/include/fast/backends/gfx_dxgi.h create mode 100644 libultraship/include/fast/backends/gfx_metal.h create mode 100644 libultraship/include/fast/backends/gfx_metal_shader.h create mode 100644 libultraship/include/fast/backends/gfx_opengl.h create mode 100644 libultraship/include/fast/backends/gfx_rendering_api.h create mode 100644 libultraship/include/fast/backends/gfx_screen_config.h create mode 100644 libultraship/include/fast/backends/gfx_sdl.h create mode 100644 libultraship/include/fast/backends/gfx_window_manager_api.h create mode 100644 libultraship/include/fast/debug/GfxDebugger.h create mode 100644 libultraship/include/fast/f3dex.h create mode 100644 libultraship/include/fast/f3dex2.h create mode 100644 libultraship/include/fast/interpreter.h create mode 100644 libultraship/include/fast/lus_gbi.h create mode 100644 libultraship/include/fast/resource/ResourceType.h create mode 100644 libultraship/include/fast/resource/factory/DisplayListFactory.h create mode 100644 libultraship/include/fast/resource/factory/LightFactory.h create mode 100644 libultraship/include/fast/resource/factory/MatrixFactory.h create mode 100644 libultraship/include/fast/resource/factory/TextureFactory.h create mode 100644 libultraship/include/fast/resource/factory/VertexFactory.h create mode 100644 libultraship/include/fast/resource/type/DisplayList.h create mode 100644 libultraship/include/fast/resource/type/Light.h create mode 100644 libultraship/include/fast/resource/type/Matrix.h create mode 100644 libultraship/include/fast/resource/type/Texture.h create mode 100644 libultraship/include/fast/resource/type/Vertex.h create mode 100644 libultraship/include/fast/types.h create mode 100644 libultraship/include/fast/ucodehandlers.h create mode 100644 libultraship/include/libultraship/bridge.h create mode 100644 libultraship/include/libultraship/bridge/audiobridge.h create mode 100644 libultraship/include/libultraship/bridge/consolevariablebridge.h create mode 100644 libultraship/include/libultraship/bridge/controllerbridge.h create mode 100644 libultraship/include/libultraship/bridge/crashhandlerbridge.h create mode 100644 libultraship/include/libultraship/bridge/eventsbridge.h create mode 100644 libultraship/include/libultraship/bridge/gfxbridge.h create mode 100644 libultraship/include/libultraship/bridge/gfxdebuggerbridge.h create mode 100644 libultraship/include/libultraship/bridge/resourcebridge.h create mode 100644 libultraship/include/libultraship/bridge/scriptingbridge.h create mode 100644 libultraship/include/libultraship/bridge/windowbridge.h create mode 100644 libultraship/include/libultraship/classes.h create mode 100644 libultraship/include/libultraship/color.h create mode 100644 libultraship/include/libultraship/controller/controldeck/ControlDeck.h create mode 100644 libultraship/include/libultraship/controller/controldevice/controller/Controller.h create mode 100644 libultraship/include/libultraship/controller/controldevice/controller/mapping/ControllerDefaultMappings.h create mode 100644 libultraship/include/libultraship/libultra.h create mode 100644 libultraship/include/libultraship/libultra/abi.h create mode 100644 libultraship/include/libultraship/libultra/controller.h create mode 100644 libultraship/include/libultraship/libultra/convert.h create mode 100644 libultraship/include/libultraship/libultra/eeprom.h create mode 100644 libultraship/include/libultraship/libultra/exception.h create mode 100644 libultraship/include/libultraship/libultra/gbi.h create mode 100644 libultraship/include/libultraship/libultra/gs2dex.h create mode 100644 libultraship/include/libultraship/libultra/gu.h create mode 100644 libultraship/include/libultraship/libultra/internal.h create mode 100644 libultraship/include/libultraship/libultra/interrupt.h create mode 100644 libultraship/include/libultraship/libultra/mbi.h create mode 100644 libultraship/include/libultraship/libultra/message.h create mode 100644 libultraship/include/libultraship/libultra/motor.h create mode 100644 libultraship/include/libultraship/libultra/os.h create mode 100644 libultraship/include/libultraship/libultra/pfs.h create mode 100644 libultraship/include/libultraship/libultra/pi.h create mode 100644 libultraship/include/libultraship/libultra/printf.h create mode 100644 libultraship/include/libultraship/libultra/r4300.h create mode 100644 libultraship/include/libultraship/libultra/rcp.h create mode 100644 libultraship/include/libultraship/libultra/rdp.h create mode 100644 libultraship/include/libultraship/libultra/sptask.h create mode 100644 libultraship/include/libultraship/libultra/thread.h create mode 100644 libultraship/include/libultraship/libultra/time.h create mode 100644 libultraship/include/libultraship/libultra/types.h create mode 100644 libultraship/include/libultraship/libultra/vi.h create mode 100644 libultraship/include/libultraship/libultraship.h create mode 100644 libultraship/include/libultraship/log/luslog.h create mode 100644 libultraship/include/libultraship/luslog.h create mode 100644 libultraship/include/libultraship/window/gui/GfxDebuggerWindow.h create mode 100644 libultraship/include/libultraship/window/gui/InputEditorWindow.h create mode 100644 libultraship/include/ship/Api.h create mode 100644 libultraship/include/ship/Context.h create mode 100644 libultraship/include/ship/audio/Audio.h create mode 100644 libultraship/include/ship/audio/AudioChannelsSetting.h create mode 100644 libultraship/include/ship/audio/AudioPlayer.h create mode 100644 libultraship/include/ship/audio/CoreAudioAudioPlayer.h create mode 100644 libultraship/include/ship/audio/NullAudioPlayer.h create mode 100644 libultraship/include/ship/audio/SDLAudioPlayer.h create mode 100644 libultraship/include/ship/audio/SoundMatrixDecoder.h create mode 100644 libultraship/include/ship/audio/WasapiAudioPlayer.h create mode 100644 libultraship/include/ship/config/Config.h create mode 100644 libultraship/include/ship/config/ConsoleVariable.h create mode 100644 libultraship/include/ship/controller/controldeck/ControlDeck.h create mode 100644 libultraship/include/ship/controller/controldeck/ControlPort.h create mode 100644 libultraship/include/ship/controller/controldevice/ControlDevice.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/Controller.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/ControllerButton.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/ControllerGyro.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/ControllerLED.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/ControllerRumble.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/ControllerStick.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/ControllerAxisDirectionMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/ControllerButtonMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/ControllerDefaultMappings.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/ControllerGyroMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/ControllerInputMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/ControllerLEDMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/ControllerMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/ControllerRumbleMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/factories/AxisDirectionMappingFactory.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/factories/ButtonMappingFactory.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/factories/GyroMappingFactory.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/factories/LEDMappingFactory.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/factories/RumbleMappingFactory.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/keyboard/KeyboardKeyToAnyMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/keyboard/KeyboardKeyToAxisDirectionMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/keyboard/KeyboardKeyToButtonMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/keyboard/KeyboardScancodes.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/mouse/MouseButtonToAnyMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/mouse/MouseButtonToAxisDirectionMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/mouse/MouseButtonToButtonMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/mouse/MouseWheelToAnyMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/mouse/MouseWheelToAxisDirectionMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/mouse/MouseWheelToButtonMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/mouse/WheelHandler.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/sdl/SDLAxisDirectionToAnyMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/sdl/SDLAxisDirectionToAxisDirectionMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/sdl/SDLAxisDirectionToButtonMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/sdl/SDLButtonToAnyMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/sdl/SDLButtonToAxisDirectionMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/sdl/SDLButtonToButtonMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/sdl/SDLGyroMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/sdl/SDLLEDMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/sdl/SDLMapping.h create mode 100644 libultraship/include/ship/controller/controldevice/controller/mapping/sdl/SDLRumbleMapping.h create mode 100644 libultraship/include/ship/controller/physicaldevice/ConnectedPhysicalDeviceManager.h create mode 100644 libultraship/include/ship/controller/physicaldevice/GlobalSDLDeviceSettings.h create mode 100644 libultraship/include/ship/controller/physicaldevice/PhysicalDeviceType.h create mode 100644 libultraship/include/ship/controller/physicaldevice/SDLAddRemoveDeviceEventHandler.h create mode 100644 libultraship/include/ship/debug/Console.h create mode 100644 libultraship/include/ship/debug/CrashHandler.h create mode 100644 libultraship/include/ship/events/CoreEvents.h create mode 100644 libultraship/include/ship/events/EventSystem.h create mode 100644 libultraship/include/ship/events/EventTypes.h create mode 100644 libultraship/include/ship/port/mobile/MobileImpl.h create mode 100644 libultraship/include/ship/resource/File.h create mode 100644 libultraship/include/ship/resource/Resource.h create mode 100644 libultraship/include/ship/resource/ResourceFactory.h create mode 100644 libultraship/include/ship/resource/ResourceFactoryBinary.h create mode 100644 libultraship/include/ship/resource/ResourceFactoryXML.h create mode 100644 libultraship/include/ship/resource/ResourceLoader.h create mode 100644 libultraship/include/ship/resource/ResourceManager.h create mode 100644 libultraship/include/ship/resource/ResourceType.h create mode 100644 libultraship/include/ship/resource/archive/Archive.h create mode 100644 libultraship/include/ship/resource/archive/ArchiveManager.h create mode 100644 libultraship/include/ship/resource/archive/FolderArchive.h create mode 100644 libultraship/include/ship/resource/archive/O2rArchive.h create mode 100644 libultraship/include/ship/resource/archive/OtrArchive.h create mode 100644 libultraship/include/ship/resource/factory/BlobFactory.h create mode 100644 libultraship/include/ship/resource/factory/JsonFactory.h create mode 100644 libultraship/include/ship/resource/factory/ShaderFactory.h create mode 100644 libultraship/include/ship/resource/type/Blob.h create mode 100644 libultraship/include/ship/resource/type/Json.h create mode 100644 libultraship/include/ship/resource/type/Shader.h create mode 100644 libultraship/include/ship/scripting/LibraryLoader.h create mode 100644 libultraship/include/ship/scripting/ScriptLoader.h create mode 100644 libultraship/include/ship/security/Keystore.h create mode 100644 libultraship/include/ship/utils/AppleFolderManager.h create mode 100644 libultraship/include/ship/utils/HResultException.h create mode 100644 libultraship/include/ship/utils/StrHash64.h create mode 100644 libultraship/include/ship/utils/StringHelper.h create mode 100644 libultraship/include/ship/utils/Utils.h create mode 100644 libultraship/include/ship/utils/binarytools/BinaryReader.h create mode 100644 libultraship/include/ship/utils/binarytools/BinaryWriter.h create mode 100644 libultraship/include/ship/utils/binarytools/BitConverter.h create mode 100644 libultraship/include/ship/utils/binarytools/MemoryStream.h create mode 100644 libultraship/include/ship/utils/binarytools/Stream.h create mode 100644 libultraship/include/ship/utils/binarytools/endianness.h create mode 100644 libultraship/include/ship/utils/color.h create mode 100644 libultraship/include/ship/utils/filesystemtools/Directory.h create mode 100644 libultraship/include/ship/utils/filesystemtools/DiskFile.h create mode 100644 libultraship/include/ship/utils/filesystemtools/FileHelper.h create mode 100644 libultraship/include/ship/utils/filesystemtools/Path.h create mode 100644 libultraship/include/ship/utils/filesystemtools/PathHelper.h create mode 100644 libultraship/include/ship/utils/glob.h create mode 100644 libultraship/include/ship/utils/macUtils.h create mode 100644 libultraship/include/ship/utils/stox.h create mode 100644 libultraship/include/ship/window/FileDropMgr.h create mode 100644 libultraship/include/ship/window/MouseStateManager.h create mode 100644 libultraship/include/ship/window/Window.h create mode 100644 libultraship/include/ship/window/gui/ConsoleWindow.h create mode 100644 libultraship/include/ship/window/gui/EventDebuggerWindow.h create mode 100644 libultraship/include/ship/window/gui/FileBrowserWindow.h create mode 100644 libultraship/include/ship/window/gui/Fonts.h create mode 100644 libultraship/include/ship/window/gui/GameOverlay.h create mode 100644 libultraship/include/ship/window/gui/Gui.h create mode 100644 libultraship/include/ship/window/gui/GuiElement.h create mode 100644 libultraship/include/ship/window/gui/GuiMenuBar.h create mode 100644 libultraship/include/ship/window/gui/GuiWindow.h create mode 100644 libultraship/include/ship/window/gui/IconsFontAwesome4.h create mode 100644 libultraship/include/ship/window/gui/StatsWindow.h create mode 100644 libultraship/include/ship/window/gui/resource/Font.h create mode 100644 libultraship/include/ship/window/gui/resource/FontFactory.h create mode 100644 libultraship/include/ship/window/gui/resource/GuiTexture.h create mode 100644 libultraship/include/ship/window/gui/resource/GuiTextureFactory.h create mode 100644 libultraship/keys/script/HM64.pem create mode 100644 libultraship/keys/script/Kenix1.pem create mode 100644 libultraship/keys/script/Kenix2.pem create mode 100644 libultraship/keys/script/Kenix3.pem create mode 100644 libultraship/keys/script/Kenix4.pem create mode 100644 libultraship/keys/script/Kenix5.pem create mode 100644 libultraship/requirements.txt create mode 100644 libultraship/run-clang-format.ps1 create mode 100644 libultraship/src/CMakeLists.txt create mode 100644 libultraship/src/fast/CMakeLists.txt create mode 100644 libultraship/src/fast/Fast3dGui.cpp create mode 100644 libultraship/src/fast/Fast3dWindow.cpp create mode 100644 libultraship/src/fast/FastMouseStateManager.cpp create mode 100644 libultraship/src/fast/LICENSE.txt create mode 100644 libultraship/src/fast/README.md create mode 100644 libultraship/src/fast/backends/gfx_direct3d11.cpp create mode 100644 libultraship/src/fast/backends/gfx_direct3d_common.cpp create mode 100644 libultraship/src/fast/backends/gfx_dxgi.cpp create mode 100644 libultraship/src/fast/backends/gfx_metal.cpp create mode 100644 libultraship/src/fast/backends/gfx_metal_shader.cpp create mode 100644 libultraship/src/fast/backends/gfx_opengl.cpp create mode 100644 libultraship/src/fast/backends/gfx_sdl2.cpp create mode 100644 libultraship/src/fast/debug/GfxDebugger.cpp create mode 100644 libultraship/src/fast/interpreter.cpp create mode 100644 libultraship/src/fast/resource/factory/DisplayListFactory.cpp create mode 100644 libultraship/src/fast/resource/factory/LightFactory.cpp create mode 100644 libultraship/src/fast/resource/factory/MatrixFactory.cpp create mode 100644 libultraship/src/fast/resource/factory/TextureFactory.cpp create mode 100644 libultraship/src/fast/resource/factory/VertexFactory.cpp create mode 100644 libultraship/src/fast/resource/type/DisplayList.cpp create mode 100644 libultraship/src/fast/resource/type/Light.cpp create mode 100644 libultraship/src/fast/resource/type/Matrix.cpp create mode 100644 libultraship/src/fast/resource/type/Texture.cpp create mode 100644 libultraship/src/fast/resource/type/Vertex.cpp create mode 100644 libultraship/src/fast/shaders/directx/default.shader.hlsl create mode 100644 libultraship/src/fast/shaders/metal/default.shader.metal create mode 100644 libultraship/src/fast/shaders/opengl/default.shader.glsl create mode 100644 libultraship/src/libultraship/CMakeLists.txt create mode 100644 libultraship/src/libultraship/bridge/audiobridge.cpp create mode 100644 libultraship/src/libultraship/bridge/consolevariablebridge.cpp create mode 100644 libultraship/src/libultraship/bridge/controllerbridge.cpp create mode 100644 libultraship/src/libultraship/bridge/crashhandlerbridge.cpp create mode 100644 libultraship/src/libultraship/bridge/eventsbridge.cpp create mode 100644 libultraship/src/libultraship/bridge/gfxbridge.cpp create mode 100644 libultraship/src/libultraship/bridge/gfxdebuggerbridge.cpp create mode 100644 libultraship/src/libultraship/bridge/resourcebridge.cpp create mode 100644 libultraship/src/libultraship/bridge/scriptingbridge.cpp create mode 100644 libultraship/src/libultraship/bridge/windowbridge.cpp create mode 100644 libultraship/src/libultraship/controller/controldeck/ControlDeck.cpp create mode 100644 libultraship/src/libultraship/controller/controldevice/controller/Controller.cpp create mode 100644 libultraship/src/libultraship/controller/controldevice/controller/mapping/ControllerDefaultMappings.cpp create mode 100644 libultraship/src/libultraship/libultra/AudioDmaRegistry.cpp create mode 100644 libultraship/src/libultraship/libultra/AudioDmaRegistry.h create mode 100644 libultraship/src/libultraship/libultra/os.cpp create mode 100644 libultraship/src/libultraship/libultra/os_cache.cpp create mode 100644 libultraship/src/libultraship/libultra/os_eeprom.cpp create mode 100644 libultraship/src/libultraship/libultra/os_mesg.cpp create mode 100644 libultraship/src/libultraship/libultra/os_pi.cpp create mode 100644 libultraship/src/libultraship/libultra/os_time.cpp create mode 100644 libultraship/src/libultraship/libultra/os_vi.cpp create mode 100644 libultraship/src/libultraship/libultra/os_vm.cpp create mode 100644 libultraship/src/libultraship/log/luslog.cpp create mode 100644 libultraship/src/libultraship/window/gui/GfxDebuggerWindow.cpp create mode 100644 libultraship/src/libultraship/window/gui/InputEditorWindow.cpp create mode 100644 libultraship/src/ship/CMakeLists.txt create mode 100644 libultraship/src/ship/Context.cpp create mode 100644 libultraship/src/ship/audio/Audio.cpp create mode 100644 libultraship/src/ship/audio/AudioPlayer.cpp create mode 100644 libultraship/src/ship/audio/CoreAudioAudioPlayer.cpp create mode 100644 libultraship/src/ship/audio/NullAudioPlayer.cpp create mode 100644 libultraship/src/ship/audio/SDLAudioPlayer.cpp create mode 100644 libultraship/src/ship/audio/SoundMatrixDecoder.cpp create mode 100644 libultraship/src/ship/audio/WasapiAudioPlayer.cpp create mode 100644 libultraship/src/ship/config/Config.cpp create mode 100644 libultraship/src/ship/config/ConsoleVariable.cpp create mode 100644 libultraship/src/ship/controller/controldeck/ControlDeck.cpp create mode 100644 libultraship/src/ship/controller/controldeck/ControlPort.cpp create mode 100644 libultraship/src/ship/controller/controldevice/ControlDevice.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/Controller.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/ControllerButton.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/ControllerGyro.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/ControllerLED.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/ControllerRumble.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/ControllerStick.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/ControllerAxisDirectionMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/ControllerButtonMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/ControllerDefaultMappings.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/ControllerGyroMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/ControllerInputMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/ControllerLEDMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/ControllerMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/ControllerRumbleMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/factories/AxisDirectionMappingFactory.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/factories/ButtonMappingFactory.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/factories/GyroMappingFactory.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/factories/LEDMappingFactory.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/factories/RumbleMappingFactory.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/keyboard/KeyboardKeyToAnyMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/keyboard/KeyboardKeyToAxisDirectionMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/keyboard/KeyboardKeyToButtonMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/mouse/MouseButtonToAnyMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/mouse/MouseButtonToAxisDirectionMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/mouse/MouseButtonToButtonMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/mouse/MouseWheelToAnyMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/mouse/MouseWheelToAxisDirectionMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/mouse/MouseWheelToButtonMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/mouse/WheelHandler.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/sdl/SDLAxisDirectionToAnyMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/sdl/SDLAxisDirectionToAxisDirectionMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/sdl/SDLAxisDirectionToButtonMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/sdl/SDLButtonToAnyMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/sdl/SDLButtonToAxisDirectionMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/sdl/SDLButtonToButtonMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/sdl/SDLGyroMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/sdl/SDLLEDMapping.cpp create mode 100644 libultraship/src/ship/controller/controldevice/controller/mapping/sdl/SDLRumbleMapping.cpp create mode 100644 libultraship/src/ship/controller/physicaldevice/ConnectedPhysicalDeviceManager.cpp create mode 100644 libultraship/src/ship/controller/physicaldevice/GlobalSDLDeviceSettings.cpp create mode 100644 libultraship/src/ship/controller/physicaldevice/SDLAddRemoveDeviceEventHandler.cpp create mode 100644 libultraship/src/ship/debug/Console.cpp create mode 100644 libultraship/src/ship/debug/CrashHandler.cpp create mode 100644 libultraship/src/ship/events/EventSystem.cpp create mode 100644 libultraship/src/ship/install_config.h.in create mode 100644 libultraship/src/ship/port/mobile/MobileImpl.cpp create mode 100644 libultraship/src/ship/resource/Resource.cpp create mode 100644 libultraship/src/ship/resource/ResourceFactoryBinary.cpp create mode 100644 libultraship/src/ship/resource/ResourceFactoryXML.cpp create mode 100644 libultraship/src/ship/resource/ResourceLoader.cpp create mode 100644 libultraship/src/ship/resource/ResourceManager.cpp create mode 100644 libultraship/src/ship/resource/archive/Archive.cpp create mode 100644 libultraship/src/ship/resource/archive/ArchiveManager.cpp create mode 100644 libultraship/src/ship/resource/archive/FolderArchive.cpp create mode 100644 libultraship/src/ship/resource/archive/O2rArchive.cpp create mode 100644 libultraship/src/ship/resource/archive/OtrArchive.cpp create mode 100644 libultraship/src/ship/resource/factory/BlobFactory.cpp create mode 100644 libultraship/src/ship/resource/factory/JsonFactory.cpp create mode 100644 libultraship/src/ship/resource/factory/ShaderFactory.cpp create mode 100644 libultraship/src/ship/resource/type/Blob.cpp create mode 100644 libultraship/src/ship/resource/type/Json.cpp create mode 100644 libultraship/src/ship/resource/type/Shader.cpp create mode 100644 libultraship/src/ship/scripting/LibraryLoader.cpp create mode 100644 libultraship/src/ship/scripting/ScriptLoader.cpp create mode 100644 libultraship/src/ship/security/Keystore.cpp create mode 100644 libultraship/src/ship/utils/AppleFolderManager.mm create mode 100644 libultraship/src/ship/utils/StrHash64.cpp create mode 100644 libultraship/src/ship/utils/StringHelper.cpp create mode 100644 libultraship/src/ship/utils/Utils.cpp create mode 100644 libultraship/src/ship/utils/binarytools/BinaryReader.cpp create mode 100644 libultraship/src/ship/utils/binarytools/BinaryWriter.cpp create mode 100644 libultraship/src/ship/utils/binarytools/MemoryStream.cpp create mode 100644 libultraship/src/ship/utils/binarytools/Stream.cpp create mode 100644 libultraship/src/ship/utils/glob.c create mode 100644 libultraship/src/ship/utils/macUtils.mm create mode 100644 libultraship/src/ship/utils/stox.cpp create mode 100644 libultraship/src/ship/window/FileDropMgr.cpp create mode 100644 libultraship/src/ship/window/MouseStateManager.cpp create mode 100644 libultraship/src/ship/window/Window.cpp create mode 100644 libultraship/src/ship/window/gui/ConsoleWindow.cpp create mode 100644 libultraship/src/ship/window/gui/EventDebuggerWindow.cpp create mode 100644 libultraship/src/ship/window/gui/FileBrowserWindow.cpp create mode 100644 libultraship/src/ship/window/gui/GameOverlay.cpp create mode 100644 libultraship/src/ship/window/gui/Gui.cpp create mode 100644 libultraship/src/ship/window/gui/GuiElement.cpp create mode 100644 libultraship/src/ship/window/gui/GuiMenuBar.cpp create mode 100644 libultraship/src/ship/window/gui/GuiWindow.cpp create mode 100644 libultraship/src/ship/window/gui/StatsWindow.cpp create mode 100644 libultraship/src/ship/window/gui/resource/Font.cpp create mode 100644 libultraship/src/ship/window/gui/resource/FontFactory.cpp create mode 100644 libultraship/src/ship/window/gui/resource/GuiTexture.cpp create mode 100644 libultraship/src/ship/window/gui/resource/GuiTextureFactory.cpp create mode 100644 libultraship/tests/CMakeLists.txt create mode 100644 libultraship/tests/archive_resource_tests.cpp create mode 100644 libultraship/tests/archive_self_tests.cpp create mode 100644 libultraship/tests/binary_io_tests.cpp create mode 100644 libultraship/tests/bitconverter_tests.cpp create mode 100644 libultraship/tests/crc64_tests.cpp create mode 100644 libultraship/tests/event_system_tests.cpp create mode 100644 libultraship/tests/glob_tests.cpp create mode 100644 libultraship/tests/path_diskfile_tests.cpp create mode 100644 libultraship/tests/path_file_helper_tests.cpp create mode 100644 libultraship/tests/resource_type_tests.cpp create mode 100644 libultraship/tests/script_test.cpp create mode 100644 libultraship/tests/sound_matrix_decoder_tests.cpp create mode 100644 libultraship/tests/splittext_tests.cpp create mode 100644 libultraship/tests/stox_tests.cpp create mode 100644 libultraship/tests/string_helper_tests.cpp create mode 100644 libultraship/tests/utils_tests.cpp create mode 100644 libultraship/tools/generate_keys.py create mode 100644 libultraship/tools/generate_keys_header.py create mode 100644 libultraship/tools/sign.py diff --git a/libultraship/.clang-format b/libultraship/.clang-format new file mode 100644 index 000000000..c7b900f06 --- /dev/null +++ b/libultraship/.clang-format @@ -0,0 +1,23 @@ +IndentWidth: 4 +Language: Cpp +UseTab: Never +ColumnLimit: 120 +PointerAlignment: Left +BreakBeforeBraces: Attach +SpaceAfterCStyleCast: false +Cpp11BracedListStyle: false +IndentCaseLabels: true +BinPackArguments: true +BinPackParameters: true +AlignAfterOpenBracket: Align +AlignOperands: true +BreakBeforeTernaryOperators: true +BreakBeforeBinaryOperators: None +AllowShortBlocksOnASingleLine: true +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +AlignEscapedNewlines: Left +AlignTrailingComments: true +SortIncludes: false diff --git a/libultraship/.clang-tidy b/libultraship/.clang-tidy new file mode 100644 index 000000000..516584aca --- /dev/null +++ b/libultraship/.clang-tidy @@ -0,0 +1,30 @@ +Checks: '-*,readability-braces-around-statements,readability-inconsistent-declaration-parameter-name,readability-identifier-naming' +WarningsAsErrors: '' +HeaderFilterRegex: '(src|include)\/.*\.h$' +FormatStyle: 'file' +CheckOptions: + - { key: readability-identifier-naming.NamespaceCase, value: CamelCase } + - { key: readability-identifier-naming.ClassCase, value: CamelCase } + - { key: readability-identifier-naming.PrivateMemberPrefix, value: m } + - { key: readability-identifier-naming.ProtectedMemberPrefix, value: m } + - { key: readability-identifier-naming.PrivateMemberCase, value: CamelCase } + - { key: readability-identifier-naming.ProtectedMemberCase, value: CamelCase } + - { key: readability-identifier-naming.PublicMemberCase, value: CamelCase } + - { key: readability-identifier-naming.MemberCase, value: CamelCase } + - { key: readability-identifier-naming.StructCase, value: CamelCase } + #- { key: readability-identifier-naming.EnumCase, value: CamelCase } + #- { key: readability-identifier-naming.EnumConstantCase, value: UPPER_CASE } + - { key: readability-identifier-naming.VariableCase, value: CamelCase } + - { key: readability-identifier-naming.StaticVariableCase, value: CamelCase } + - { key: readability-identifier-naming.StaticVariablePrefix, value: s } + - { key: readability-identifier-naming.GlobalConstantCase, value: CamelCase } + - { key: readability-identifier-naming.GlobalConstantPrefix, value: g } + - { key: readability-identifier-naming.MethodCase, value: CamelCase } + - { key: readability-identifier-naming.FunctionCase, value: CamelCase } + - { key: readability-identifier-naming.VariableCase, value: camelBack } + - { key: readability-identifier-naming.LocalVariableCase, value: camelBack } + - { key: readability-identifier-naming.ParameterCase, value: camelBack } + # Require argument names to match exactly (instead of allowing a name to be a prefix/suffix of another) + # Note: 'true' is expected by clang-tidy 12+ but '1' is used for compatibility with older versions + - key: readability-inconsistent-declaration-parameter-name.Strict + value: 1 diff --git a/libultraship/.github/workflows/apt-deps.txt b/libultraship/.github/workflows/apt-deps.txt new file mode 100644 index 000000000..7ff48e9a4 --- /dev/null +++ b/libultraship/.github/workflows/apt-deps.txt @@ -0,0 +1 @@ +libsdl2-dev libpng-dev libglew-dev libzip-dev zipcmp zipmerge ziptool ninja-build nlohmann-json3-dev libtinyxml2-dev libspdlog-dev tcc libtcc-dev \ No newline at end of file diff --git a/libultraship/.github/workflows/brew-deps.txt b/libultraship/.github/workflows/brew-deps.txt new file mode 100644 index 000000000..6c3248f9b --- /dev/null +++ b/libultraship/.github/workflows/brew-deps.txt @@ -0,0 +1 @@ +sdl2 libpng glew ninja libzip nlohmann-json tinyxml2 spdlog \ No newline at end of file diff --git a/libultraship/.github/workflows/build-validation.yml b/libultraship/.github/workflows/build-validation.yml new file mode 100644 index 000000000..362710505 --- /dev/null +++ b/libultraship/.github/workflows/build-validation.yml @@ -0,0 +1,246 @@ +name: build-validation +on: + push: + pull_request: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +jobs: + build-macos: + runs-on: macos-14 + steps: + - uses: actions/checkout@v4 + - name: Install dependencies + run: | + brew install $(cat .github/workflows/brew-deps.txt) + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2.14 + with: + key: ${{ runner.os }}-mac-ccache-${{ github.ref }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-mac-ccache-${{ github.ref }} + ${{ runner.os }}-mac-ccache- + - name: Install Python dependencies + run: python3 -m pip install -r requirements.txt --break-system-packages || python3 -m pip install -r requirements.txt + - name: Build libultraship + run: | + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release + cmake --build build-cmake --config Release --parallel 10 + - name: Upload build + uses: actions/upload-artifact@v4 + with: + name: soh-mac + path: build-cmake/src/*.a + if-no-files-found: error + build-ios: + runs-on: macos-14 + steps: + - uses: actions/checkout@v4 + - name: Cache build folder + uses: actions/cache@v4 + with: + save-always: true + key: ${{ runner.os }}-14-ios-build-${{ github.ref }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-14-ios-build-${{ github.ref }} + ${{ runner.os }}-14-ios-build- + path: | + build-cmake + - name: Install Python dependencies + run: python3 -m pip install -r requirements.txt --break-system-packages || python3 -m pip install -r requirements.txt + - name: Build libultraship + run: | + cmake --no-warn-unused-cli -H. -Bbuild-cmake -GXcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 -DCMAKE_BUILD_TYPE:STRING=Release + cmake --build build-cmake --config Release --parallel 10 + - name: Upload build + uses: actions/upload-artifact@v4 + with: + name: soh-ios + path: build-cmake/src/*/*.a + if-no-files-found: error + build-linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y $(cat .github/workflows/apt-deps.txt) + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2.14 + with: + key: ${{ matrix.os }}-ccache-${{ github.ref }}-${{ github.sha }} + restore-keys: | + ${{ matrix.os }}-ccache-${{ github.ref }} + ${{ matrix.os }}-ccache- + - name: Install latest SDL + run: | + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + wget https://www.libsdl.org/release/SDL2-2.24.1.tar.gz + tar -xzf SDL2-2.24.1.tar.gz + cd SDL2-2.24.1 + ./configure + make -j 10 + sudo make install + - name: Install latest tinyxml2 + run: | + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + wget https://github.com/leethomason/tinyxml2/archive/refs/tags/10.0.0.tar.gz + tar -xzf 10.0.0.tar.gz + cd tinyxml2-10.0.0 + mkdir build + cd build + cmake .. + make + sudo make install + - name: Install Python dependencies + run: python3 -m pip install -r requirements.txt + - name: Build libultraship + run: | + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release + cmake --build build-cmake --config Release --parallel 10 + env: + CC: gcc-12 + CXX: g++-12 + - name: Upload build + uses: actions/upload-artifact@v4 + with: + name: soh-linux + path: build-cmake/src/*.a + if-no-files-found: error + build-android: + runs-on: ubuntu-latest + env: + ANDROID_NDK_HOME: ${{ github.workspace }}/android-ndk/android-ndk-r29 + steps: + - uses: actions/checkout@v4 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y $(cat .github/workflows/apt-deps.txt) unzip curl + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2.14 + with: + key: ${{ runner.os }}-android-ccache-${{ github.ref }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-android-ccache-${{ github.ref }} + ${{ runner.os }}-android-ccache- + - name: Install Android NDK + run: | + curl -L https://dl.google.com/android/repository/android-ndk-r29-linux.zip -o android-ndk.zip + unzip -q android-ndk.zip + mkdir -p android-ndk + mv android-ndk-r29 android-ndk/ + - name: Install Python dependencies + run: python3 -m pip install -r requirements.txt + - name: Configure libultraship for Android + run: | + cmake --no-warn-unused-cli -S . -Bbuild-cmake-android -GNinja \ + -DCMAKE_BUILD_TYPE:STRING=Release \ + -DCMAKE_SYSTEM_NAME=Android \ + -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake \ + -DANDROID_NDK=${ANDROID_NDK_HOME} \ + -DANDROID_ABI=arm64-v8a \ + -DANDROID_PLATFORM=latest \ + -DANDROID_STL=c++_static + - name: Build libultraship for Android + run: | + cmake --build build-cmake-android --config Release --parallel 10 + - name: Upload build + uses: actions/upload-artifact@v4 + with: + name: soh-android + path: build-cmake-android/src/*.a + if-no-files-found: error + build-windows-x64: + runs-on: windows-latest + steps: + - name: Install dependencies + run: | + choco install ninja + Remove-Item -Path "C:\ProgramData\Chocolatey\bin\ccache.exe" -Force -ErrorAction SilentlyContinue + - uses: actions/checkout@v4 + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2.14 + with: + variant: sccache + key: ${{ runner.os }}-ccache-${{ github.ref }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-ccache-${{ github.ref }} + ${{ runner.os }}-ccache- + - name: Cache build folder + uses: actions/cache@v4 + with: + save-always: true + key: ${{ runner.os }}-build-${{ github.ref }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-build-${{ github.ref }} + ${{ runner.os }}-build- + path: | + build-cmake + D:/a/vcpkg + - name: Setup MSVC + uses: ilammy/msvc-dev-cmd@v1 + - name: Install Python dependencies + run: python -m pip install -r requirements.txt + - name: Build libultraship + env: + VCPKG_ROOT: D:/a/vcpkg + run: | + $env:PATH = "$env:USERPROFILE\.cargo\bin;$env:PATH" + $PY_EXE = (Get-Command python).Definition + cmake --no-warn-unused-cli -S. -Bbuild-cmake-x64 -GNinja -DCMAKE_MAKE_PROGRAM=ninja -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DUSE_AUTO_VCPKG=ON -DCMAKE_VS_PLATFORM_NAME=x64 "-DPython3_EXECUTABLE=$PY_EXE" -DPython3_FIND_REGISTRY=NEVER + cmake --build build-cmake-x64 --config Release --parallel 10 + - name: Upload build + uses: actions/upload-artifact@v4 + with: + name: soh-windows-x64 + path: build-cmake-x64/src/**/*.lib + if-no-files-found: error + build-windows-arm64: + runs-on: windows-2022 + steps: + - name: Install dependencies + run: | + choco install ninja + Remove-Item -Path "C:\ProgramData\Chocolatey\bin\ccache.exe" -Force -ErrorAction SilentlyContinue + - uses: actions/checkout@v4 + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2.14 + with: + variant: sccache + key: ${{ runner.os }}-ccache-${{ github.ref }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-ccache-${{ github.ref }} + ${{ runner.os }}-ccache- + - name: Cache build folder + uses: actions/cache@v4 + with: + save-always: true + key: ${{ runner.os }}-build-${{ github.ref }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-build-${{ github.ref }} + ${{ runner.os }}-build- + path: | + build-cmake + D:/a/vcpkg + - name: Setup MSVC + uses: ilammy/msvc-dev-cmd@v1 + - name: Install Python dependencies + run: python -m pip install -r requirements.txt + - name: Build libultraship + env: + VCPKG_ROOT: D:/a/vcpkg + run: | + $env:PATH = "$env:USERPROFILE\.cargo\bin;$env:PATH" + $PY_EXE = (Get-Command python).Definition + cmake --no-warn-unused-cli -S. -Bbuild-cmake-arm64 -G "Visual Studio 17 2022" -T v143 -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DUSE_AUTO_VCPKG=ON -DCMAKE_VS_PLATFORM_NAME=arm64 "-DPython3_EXECUTABLE=$PY_EXE" -DPython3_FIND_REGISTRY=NEVER + cmake --build build-cmake-arm64 --config Release --parallel 10 + - name: Upload build + uses: actions/upload-artifact@v4 + with: + name: soh-windows-arm64 + path: x64/**/*.lib + if-no-files-found: error diff --git a/libultraship/.github/workflows/test-validation.yml b/libultraship/.github/workflows/test-validation.yml new file mode 100644 index 000000000..2330be7f0 --- /dev/null +++ b/libultraship/.github/workflows/test-validation.yml @@ -0,0 +1,106 @@ +name: test-validation +on: + push: + pull_request: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +jobs: + test-linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y $(cat .github/workflows/apt-deps.txt) + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2.14 + with: + key: ${{ runner.os }}-test-ccache-${{ github.ref }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-test-ccache-${{ github.ref }} + ${{ runner.os }}-test-ccache- + - name: Install latest SDL + run: | + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + wget https://www.libsdl.org/release/SDL2-2.24.1.tar.gz + tar -xzf SDL2-2.24.1.tar.gz + cd SDL2-2.24.1 + ./configure + make -j $(nproc) + sudo make install + - name: Install latest tinyxml2 + run: | + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + wget https://github.com/leethomason/tinyxml2/archive/refs/tags/10.0.0.tar.gz + tar -xzf 10.0.0.tar.gz + cd tinyxml2-10.0.0 + mkdir build + cd build + cmake .. + make + sudo make install + - name: Install Python dependencies + run: python3 -m pip install -r requirements.txt + - name: Configure + run: | + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + cmake --no-warn-unused-cli -H. -Bbuild-test -GNinja \ + -DCMAKE_BUILD_TYPE:STRING=Debug \ + -DLUS_BUILD_TESTS=ON + env: + CC: gcc-12 + CXX: g++-12 + - name: Build + run: cmake --build build-test --config Debug --parallel $(nproc) + - name: Run tests + run: ctest --test-dir build-test --output-on-failure + env: + SDL_VIDEODRIVER: dummy + SDL_AUDIODRIVER: dummy + test-windows: + runs-on: windows-latest + permissions: + contents: read + steps: + - name: Install dependencies + run: | + choco install ninja + Remove-Item -Path "C:\ProgramData\Chocolatey\bin\ccache.exe" -Force -ErrorAction SilentlyContinue + - uses: actions/checkout@v4 + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2.14 + with: + variant: sccache + key: ${{ runner.os }}-test-ccache-${{ github.ref }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-test-ccache-${{ github.ref }} + ${{ runner.os }}-test-ccache- + - name: Cache vcpkg + uses: actions/cache@v4 + with: + save-always: true + key: ${{ runner.os }}-test-vcpkg-${{ github.ref }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-test-vcpkg-${{ github.ref }} + ${{ runner.os }}-test-vcpkg- + path: D:/a/vcpkg + - name: Setup MSVC + uses: ilammy/msvc-dev-cmd@v1 + - name: Install Python dependencies + run: python -m pip install -r requirements.txt + - name: Configure + env: + VCPKG_ROOT: D:/a/vcpkg + run: | + $env:PATH = "$env:USERPROFILE\.cargo\bin;$env:PATH" + $PY_EXE = (Get-Command python).Definition + cmake --no-warn-unused-cli -S. -Bbuild-test -GNinja -DCMAKE_MAKE_PROGRAM=ninja -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=Embedded -DUSE_AUTO_VCPKG=ON -DCMAKE_VS_PLATFORM_NAME=x64 "-DPython3_EXECUTABLE=$PY_EXE" -DPython3_FIND_REGISTRY=NEVER -DLUS_BUILD_TESTS=ON + - name: Build + run: cmake --build build-test --config Debug --parallel 10 + - name: Run tests + run: ctest --test-dir build-test --output-on-failure + env: + SDL_VIDEODRIVER: dummy + SDL_AUDIODRIVER: dummy diff --git a/libultraship/.github/workflows/tidy-format-validation.yml b/libultraship/.github/workflows/tidy-format-validation.yml new file mode 100644 index 000000000..a607d34c4 --- /dev/null +++ b/libultraship/.github/workflows/tidy-format-validation.yml @@ -0,0 +1,65 @@ +name: tidy-format-validation +on: [pull_request] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +jobs: + tidy-format: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 2 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y $(cat .github/workflows/apt-deps.txt) clang-tidy clang-format-14 + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: ${{ runner.os }}-ccache + - name: Run clang-format + run: | + find src include -name "*.cpp" -o -name "*.h" | sed 's| |\\ |g' | xargs clang-format-14 -i + git diff --exit-code + - name: Install latest SDL + run: | + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + wget https://www.libsdl.org/release/SDL2-2.24.1.tar.gz + tar -xzf SDL2-2.24.1.tar.gz + cd SDL2-2.24.1 + ./configure + make -j 10 + sudo make install + - name: Install latest tinyxml2 + run: | + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + wget https://github.com/leethomason/tinyxml2/archive/refs/tags/10.0.0.tar.gz + tar -xzf 10.0.0.tar.gz + cd tinyxml2-10.0.0 + mkdir build + cd build + cmake .. + make + sudo make install + - name: Install Python dependencies + run: python3 -m pip install -r requirements.txt + - name: Prepare compile_commands.json + run: | + cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DENABLE_SCRIPTING=ON + cmake --build build --target GenerateScriptKeys + - name: Create results directory + run: | + mkdir clang-tidy-result + - name: Analyze + run: | + git diff -U0 HEAD^ -- 'src' 'include' ':!include/libultraship/color.h' ':!include/ship/utils/color.h' ':!include/libultraship/libultra/*' ':!src/libultraship/libultra/*' ':!src/fast/*' ':!include/fast/*' ':!src/ship/utils/AppleFolderManager.mm' | clang-tidy-diff -p1 -path build -export-fixes clang-tidy-result/fixes.yml + - name: Save PR metadata + run: | + echo ${{ github.event.number }} > clang-tidy-result/pr-id.txt + echo ${{ github.event.pull_request.head.repo.full_name }} > clang-tidy-result/pr-head-repo.txt + echo ${{ github.event.pull_request.head.ref }} > clang-tidy-result/pr-head-ref.txt + - uses: actions/upload-artifact@v4 + with: + name: clang-tidy-result + path: clang-tidy-result/ diff --git a/libultraship/.github/workflows/tidy-result-publish.yml b/libultraship/.github/workflows/tidy-result-publish.yml new file mode 100644 index 000000000..29226acd5 --- /dev/null +++ b/libultraship/.github/workflows/tidy-result-publish.yml @@ -0,0 +1,74 @@ +name: tidy-result-publish +on: + workflow_run: + workflows: [ tidy-format-validation ] + types: [ completed ] +jobs: + clang-tidy-results: + # Trigger the job only if the previous (insecure) workflow completed successfully + if: ${{ github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' }} + runs-on: ubuntu-22.04 + steps: + - name: Download analysis results + uses: actions/github-script@v7.0.1 + with: + script: | + let artifacts = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: ${{github.event.workflow_run.id }}, + }); + let matchArtifact = artifacts.data.artifacts.filter((artifact) => { + return artifact.name == "clang-tidy-result" + })[0]; + let download = await github.rest.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: matchArtifact.id, + archive_format: "zip", + }); + let fs = require("fs"); + fs.writeFileSync("${{github.workspace}}/clang-tidy-result.zip", Buffer.from(download.data)); + - name: Set environment variables + run: | + mkdir clang-tidy-result + unzip clang-tidy-result.zip -d clang-tidy-result + echo "pr_id=$(cat clang-tidy-result/pr-id.txt)" >> $GITHUB_ENV + echo "pr_head_repo=$(cat clang-tidy-result/pr-head-repo.txt)" >> $GITHUB_ENV + echo "pr_head_ref=$(cat clang-tidy-result/pr-head-ref.txt)" >> $GITHUB_ENV + - uses: actions/checkout@v4 + with: + repository: ${{ env.pr_head_repo }} + ref: ${{ env.pr_head_ref }} + persist-credentials: false + - name: Redownload analysis results + uses: actions/github-script@v7.0.1 + with: + script: | + let artifacts = await github.rest.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: ${{github.event.workflow_run.id }}, + }); + let matchArtifact = artifacts.data.artifacts.filter((artifact) => { + return artifact.name == "clang-tidy-result" + })[0]; + let download = await github.rest.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: matchArtifact.id, + archive_format: "zip", + }); + let fs = require("fs"); + fs.writeFileSync("${{github.workspace}}/clang-tidy-result.zip", Buffer.from(download.data)); + - name: Extract analysis results + run: | + mkdir clang-tidy-result + unzip clang-tidy-result.zip -d clang-tidy-result + - name: Run clang-tidy-pr-comments action + uses: platisd/clang-tidy-pr-comments@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + clang_tidy_fixes: clang-tidy-result/fixes.yml + pull_request_id: ${{ env.pr_id }} + request_changes: true diff --git a/libultraship/.gitignore b/libultraship/.gitignore new file mode 100644 index 000000000..842e80a41 --- /dev/null +++ b/libultraship/.gitignore @@ -0,0 +1,376 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +!libultraship/Lib/** +libultraship/DebugObj/* +build/ +build-cmake/ +libultraship.a +libultraship.lib +ZAPDUtils.lib +.DS_Store +.vscode/ +.vs/ +.idea/ +cmake-build-** +cmake_install.cmake +tcc_c2str +tcc_c2str.exe +*.a +*.o +*.so +*.pc +*.vcxproj +*.sln +*.filters +*.stamp +*.depend +*.lib +*.exp +*.dll +*.dylib +*.tlog +*.recipe +src/ship/install_config.h +src/ship/DefaultKeys.h +# Removed jsonConfig and jsonConfigVersion +extern/nlohmann-json/*_jsonConfig* +*.pbxproj +*.xcworkspace +*.xcsettings +build* +# clang-format.exe fetched by run-clang-format.ps1 +/clang-format.exe \ No newline at end of file diff --git a/libultraship/CMakeLists.txt b/libultraship/CMakeLists.txt new file mode 100644 index 000000000..08cc7915c --- /dev/null +++ b/libultraship/CMakeLists.txt @@ -0,0 +1,88 @@ +cmake_minimum_required(VERSION 3.24.0) + +# Enable /Z7 (embedded debug info) instead of /Zi (shared PDB) on MSVC so that +# sccache can cache object files without racing over a shared .pdb file. +# CMP0141 was introduced in CMake 3.25, so guard it for older versions. +if(POLICY CMP0141) + cmake_policy(SET CMP0141 NEW) +endif() + +option(NON_PORTABLE "Build a non-portable version" OFF) +option(DISABLE_DLL_LOADER "Disable dynamic library loading support" OFF) +option(ENABLE_SCRIPTING "Enable TCC-based C mod compilation and scripting system" OFF) + +if(CMAKE_SYSTEM_NAME STREQUAL "iOS") + option(SIGN_LIBRARY "Enable xcode signing" OFF) + option(BUNDLE_ID "Bundle ID for xcode signing" "com.example.libultraship") + set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) +endif() + +project(libultraship LANGUAGES C CXX) + +if (CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR CMAKE_SYSTEM_NAME STREQUAL "iOS") + enable_language(OBJCXX) + set(CMAKE_OBJC_FLAGS "${CMAKE_OBJC_FLAGS} -fobjc-arc") + set(CMAKE_OBJCXX_FLAGS "${CMAKE_OBJCXX_FLAGS} -fobjc-arc") +endif() + +if (CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + # Default to embedded debug info (/Z7) so sccache can cache object files + # without multiple CL.EXE processes racing over a shared .pdb file. + if(POLICY CMP0141) + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$,$>:Embedded>") + endif() +endif() + +include(cmake/Utils.cmake) +set(ADDITIONAL_LIB_INCLUDES "") + +# ========= Configuration Options ========= +option(INCLUDE_MPQ_SUPPORT "Enable StormLib and MPQ archive support" OFF) +option(GBI_UCODE "Specify the GBI ucode version" F3DEX_GBI_2) + +# =========== Dependencies ============= +if (CMAKE_SYSTEM_NAME STREQUAL "Windows") + include(cmake/dependencies/windows-vcpkg.cmake) +endif() + +include(cmake/dependencies/common.cmake) + +if (CMAKE_SYSTEM_NAME STREQUAL "Android") + include(cmake/dependencies/android.cmake) +endif() + +if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") + include(cmake/dependencies/mac.cmake) +endif() + +if (CMAKE_SYSTEM_NAME STREQUAL "iOS") + include(cmake/dependencies/ios.cmake) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + include(cmake/dependencies/linux.cmake) +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") + include(cmake/dependencies/openbsd.cmake) +endif() + +if (CMAKE_SYSTEM_NAME STREQUAL "Windows") + include(cmake/dependencies/windows.cmake) +endif() + +# === Platform Specific Configuration === +if(CMAKE_SYSTEM_NAME STREQUAL "iOS") + include(cmake/ios-toolchain-populate.cmake) +endif() + +# =========== Sources ============= +add_subdirectory("src") + +# =========== Tests ============= +option(LUS_BUILD_TESTS "Build unit tests" OFF) +if(LUS_BUILD_TESTS) + enable_testing() + add_subdirectory("tests") +endif() diff --git a/libultraship/CODE_OF_CONDUCT.md b/libultraship/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..e893f1ac2 --- /dev/null +++ b/libultraship/CODE_OF_CONDUCT.md @@ -0,0 +1,134 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +kenixwhisperwind@gmail.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations + diff --git a/libultraship/CONTRIBUTING.md b/libultraship/CONTRIBUTING.md new file mode 100644 index 000000000..18dae3268 --- /dev/null +++ b/libultraship/CONTRIBUTING.md @@ -0,0 +1,50 @@ +# Preface +LUS accepts any and all contributions. You can interact with the project via PRs, issues, email (kenixwhisperwind@gmail.com), or [Discord](https://discord.gg/shipofharkinian). + +# Code of Conduct +Please review and abide by our [code of conduct](https://github.com/Kenix3/libultraship/blob/main/CODE_OF_CONDUCT.md). + +# Building +Please see the [readme](https://github.com/Kenix3/libultraship/blob/main/README.md) for building instructions. + +# Pull Requests +## Procedures +Our CI system will automatically check your PR to ensure that it fits [formatting guidelines](https://github.com/Kenix3/libultraship/blob/main/.clang-format), [linter guidelines](https://github.com/Kenix3/libultraship/blob/main/.clang-tidy), and that the code builds. The submitter of a PR is required to ensure their PR passes all CI checks. The submitter of the PR is encouraged to address all PR review comments in a timely manner to ensure a timely merge of the PR. +### Troubleshooting CI Errors +#### tidy-format-validation +If the tidy-format-validation check fails, then you need to run clang-format. Below is a command that can be used on Linux. Most modern IDEs have a clang-format plugin that can be used. The [.clang-format file can be found here](https://github.com/Kenix3/libultraship/blob/main/.clang-format) +##### Running clang-format +###### From within the LUS directory. +Ensure clang-format-14 is installed and available through your system path. + +Bash: +``` +find src include -name "*.cpp" -o -name "*.h" | sed 's| |\\ |g' | xargs clang-format-14 -i +``` + +Powershell: +``` +Get-ChildItem -Recurse -Path .\src -Include *.cpp, *.h -File | ForEach-Object { clang-format-14.exe -i $_.FullName } +``` + +##### Running clang-tidy +###### From within the LUS directory. +Ensure `clang-tidy` is installed and available through your system path. + +First, generate a `compile_commands.json` so clang-tidy can resolve includes: +``` +cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON +cmake --build build --target GenerateScriptKeys +``` + +Then run clang-tidy-diff on your local changes: + +Bash: +``` +git diff -U0 HEAD -- src include | clang-tidy-diff -p1 -path build +``` + +To check a specific file: +``` +clang-tidy -p build src/path/to/file.cpp +``` \ No newline at end of file diff --git a/libultraship/LICENSE b/libultraship/LICENSE new file mode 100644 index 000000000..90e752ce6 --- /dev/null +++ b/libultraship/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 kenix3 kenixwhisperwind@gmail.com + +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/libultraship/README.md b/libultraship/README.md new file mode 100644 index 000000000..404e9e565 --- /dev/null +++ b/libultraship/README.md @@ -0,0 +1,107 @@ +# libultraship +libultraship (LUS) is a library meant to provide reimplementations of libultra (n64 sdk) functions that run on modern hardware. + +LUS uses an asset loading system where data is stored separately from the executable in an archive file ending in `.otr` or `.o2r`. `.otr` files are [`.mpq`](http://www.zezula.net/en/mpq/main.html) compatible files. `.o2r` files are `.zip` compatible files. This separation of data from executable follows modern design practices which are more mod friendly. All one needs to do is supply a patch `.otr` or `.o2r` and the system will automatically replace the data. + +## Contributing +LUS accepts any and all contributions. You can interact with the project via PRs, issues, email (kenixwhisperwind@gmail.com), or [Discord](https://discord.gg/shipofharkinian). +Please see [CONTRIBUTING.md](https://github.com/Kenix3/libultraship/blob/main/CONTRIBUTING.md) file for more information. + +## Versioning +We use semantic versioning. We have defined the API as: every C linkage function, variable, struct, class, public class method, or enum included from libultraship.h. + +## Building + +### Prerequisites +Install system dependencies before building. + +**Linux (Debian/Ubuntu):** +``` +sudo apt-get install $(cat .github/workflows/apt-deps.txt) +``` + +**macOS:** +``` +brew install $(cat .github/workflows/brew-deps.txt) +``` + +Then install the required Python packages (needed to generate asset keys): +``` +pip install -r requirements.txt +``` + +### Linux / macOS +``` +cmake -H. -Bbuild +cmake --build build +``` + +### Windows + +On Windows, LUS uses [vcpkg](https://vcpkg.io) to manage C++ dependencies. Pass `-DUSE_AUTO_VCPKG=ON` to have CMake download and bootstrap vcpkg automatically. Alternatively, install the required ports manually with an existing vcpkg installation and pass `-DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%/scripts/buildsystems/vcpkg.cmake` instead. + +#### Generating a Visual Studio solution (x64) +```powershell +& 'C:\Program Files\CMake\bin\cmake' -DUSE_AUTO_VCPKG=ON -S . -B "build/x64" -G "Visual Studio 17 2022" -T v143 -A x64 +``` + +#### Building +```powershell +& 'C:\Program Files\CMake\bin\cmake' --build .\build\x64 +``` + +### iOS + +Requires Xcode on macOS. Set `CMAKE_OSX_DEPLOYMENT_TARGET` to the minimum iOS version you wish to support. + +``` +cmake -H. -Bbuild -GXcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 +cmake --build build --config Release +``` + +### Android + +Requires the [Android NDK](https://developer.android.com/ndk/downloads). Set `ANDROID_NDK_HOME` to the path of the extracted NDK directory. + +``` +cmake -S . -Bbuild-android -GNinja \ + -DCMAKE_SYSTEM_NAME=Android \ + -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake \ + -DANDROID_NDK=$ANDROID_NDK_HOME \ + -DANDROID_ABI=arm64-v8a \ + -DANDROID_PLATFORM=latest \ + -DANDROID_STL=c++_static \ + -DCMAKE_BUILD_TYPE=Release +cmake --build build-android +``` + +## Sponsors +Thank you to JetBrains for providing their IDE [CLion](https://www.jetbrains.com/clion/) to me for free! + +## License +LUS is licensed under the [MIT](https://github.com/Kenix3/libultraship/blob/main/LICENSE) license. + +LUS makes use of the following third party libraries and resources: +- [Fast3D](https://github.com/Kenix3/libultraship/blob/main/src/fast/LICENSE.txt) (MIT) render display lists. +- [prism-processor](https://github.com/KiritoDv/prism-processor/blob/main/LICENSE) (MIT) shader preprocessor. +- [ImGui](https://github.com/ocornut/imgui/blob/master/LICENSE.txt) (MIT) display UI. + - [SDL2](https://github.com/libsdl-org/SDL/blob/main/LICENSE.txt) (zlib) windowing and input backend. + - [glew](https://github.com/nigels-com/glew/blob/master/LICENSE.txt) (modified BSD-3-Clause and MIT) OpenGL extension loading backend (Windows/macOS). + - [metal-cpp](https://github.com/briaguya-ai/single-header-metal-cpp/blob/macOS13_iOS16/LICENSE) (Apache 2.0) Apple Metal rendering backend (macOS/iOS). +- [StormLib](https://github.com/ladislav-zezula/StormLib/blob/master/LICENSE) (MIT) create and read `.mpq` compatible archive files. + - [zlib](https://github.com/madler/zlib/blob/develop/LICENSE) (zlib) compression. + - [bzip2](https://github.com/libarchive/bzip2?tab=License-1-ov-file#readme) (bzip2) compression. +- [libzip](https://github.com/nih-at/libzip/blob/main/LICENSE) (BSD-3-Clause) create and read `.zip` compatible archives. + - [zlib](https://github.com/madler/zlib/blob/develop/LICENSE) (zlib) compression. +- [StrHash64](https://github.com/Kenix3/libultraship/blob/main/src/ship/utils/StrHash64.cpp) (MIT, zlib, BSD-3-Clause) provide crc64 implementation. +- [nlohmann-json](https://github.com/nlohmann/json/blob/develop/LICENSE.MIT) (MIT) json parsing and saving. +- [spdlog](https://github.com/gabime/spdlog/blob/v1.x/LICENSE) (MIT) logging. + - [{fmt}](https://github.com/fmtlib/fmt/blob/master/LICENSE) (MIT) text formatting (bundled). +- [stb](https://github.com/nothings/stb/blob/master/LICENSE) (MIT) image conversion. +- [thread-pool](https://github.com/bshoshany/thread-pool/blob/master/LICENSE.txt) (MIT) thread pool for the resource manager. +- [tinyxml2](https://github.com/leethomason/tinyxml2/blob/master/LICENSE.txt) (zlib) parse XML files for resource loaders. +- [sdl2](https://github.com/libsdl-org/SDL/blob/main/LICENSE.txt) (zlib) window manager, controllers, and audio player. +- [glob_match](https://github.com/torvalds/linux/blob/d1bd5fa07667fcc3e38996ec42aef98761f23039/lib/glob.c) (Dual MIT/GPL) Glob pattern matching. +- [libgfxd](https://github.com/glankk/libgfxd/blob/master/LICENSE) (MIT) display list disassembler. +- [libtcc](https://repo.or.cz/tinycc.git/blob/HEAD:/COPYING) (LGPL-2.1) C compiler used for the script system. +- [monocypher](https://github.com/LoupVaillant/Monocypher/blob/master/LICENSE) (CC-0) cryptography library used for the modding system. \ No newline at end of file diff --git a/libultraship/cmake/Default.cmake b/libultraship/cmake/Default.cmake new file mode 100644 index 000000000..70bfa9038 --- /dev/null +++ b/libultraship/cmake/Default.cmake @@ -0,0 +1,65 @@ +################################################################################ +# Command for variable_watch. This command issues error message, if a variable +# is changed. If variable PROPERTY_READER_GUARD_DISABLED is TRUE nothing happens +# variable_watch( property_reader_guard) +################################################################################ +function(property_reader_guard VARIABLE ACCESS VALUE CURRENT_LIST_FILE STACK) + if("${PROPERTY_READER_GUARD_DISABLED}") + return() + endif() + + if("${ACCESS}" STREQUAL "MODIFIED_ACCESS") + message(FATAL_ERROR + " Variable ${VARIABLE} is not supposed to be changed.\n" + " It is used only for reading target property ${VARIABLE}.\n" + " Use\n" + " set_target_properties(\"\" PROPERTIES \"${VARIABLE}\" \"\")\n" + " or\n" + " set_target_properties(\"\" PROPERTIES \"${VARIABLE}_\" \"\")\n" + " instead.\n") + endif() +endfunction() + +################################################################################ +# Create variable with generator expression that expands to value of +# target property _. If property is empty or not set then property +# is used instead. Variable has watcher property_reader_guard that +# doesn't allow to edit it. +# create_property_reader() +# Input: +# name - Name of watched property and output variable +################################################################################ +function(create_property_reader NAME) + set(PROPERTY_READER_GUARD_DISABLED TRUE) + set(CONFIG_VALUE "$>>>") + set(IS_CONFIG_VALUE_EMPTY "$") + set(GENERAL_VALUE "$>") + set("${NAME}" "$" PARENT_SCOPE) + variable_watch("${NAME}" property_reader_guard) +endfunction() + +################################################################################ +# Set property $_${PROPS_CONFIG_U} of ${PROPS_TARGET} to +# set_config_specific_property( ) +# Input: +# name - Prefix of property name +# value - New value +################################################################################ +function(set_config_specific_property NAME VALUE) + set_target_properties("${PROPS_TARGET}" PROPERTIES "${NAME}_${PROPS_CONFIG_U}" "${VALUE}") +endfunction() + +################################################################################ + +create_property_reader("TARGET_NAME") +create_property_reader("OUTPUT_DIRECTORY") + +set_config_specific_property("TARGET_NAME" "${PROPS_TARGET}") +set_config_specific_property("OUTPUT_NAME" "${TARGET_NAME}") +set_config_specific_property("ARCHIVE_OUTPUT_NAME" "${TARGET_NAME}") +set_config_specific_property("LIBRARY_OUTPUT_NAME" "${TARGET_NAME}") +set_config_specific_property("RUNTIME_OUTPUT_NAME" "${TARGET_NAME}") + +set_config_specific_property("ARCHIVE_OUTPUT_DIRECTORY" "${OUTPUT_DIRECTORY}") +set_config_specific_property("LIBRARY_OUTPUT_DIRECTORY" "${OUTPUT_DIRECTORY}") +set_config_specific_property("RUNTIME_OUTPUT_DIRECTORY" "${OUTPUT_DIRECTORY}") \ No newline at end of file diff --git a/libultraship/cmake/DefaultCXX.cmake b/libultraship/cmake/DefaultCXX.cmake new file mode 100644 index 000000000..0d3984f29 --- /dev/null +++ b/libultraship/cmake/DefaultCXX.cmake @@ -0,0 +1,16 @@ +include("${CMAKE_CURRENT_LIST_DIR}/Default.cmake") + +set_config_specific_property("OUTPUT_DIRECTORY" "${CMAKE_SOURCE_DIR}$<$>:/${CMAKE_VS_PLATFORM_NAME}>/${PROPS_CONFIG}") + +if(MSVC) + create_property_reader("DEFAULT_CXX_EXCEPTION_HANDLING") + create_property_reader("DEFAULT_CXX_DEBUG_INFORMATION_FORMAT") + + # set_target_properties("${PROPS_TARGET}" PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") + set_config_specific_property("DEFAULT_CXX_EXCEPTION_HANDLING" "/EHsc") + if (CMAKE_C_COMPILER_LAUNCHER STREQUAL "sccache") + set_config_specific_property("DEFAULT_CXX_DEBUG_INFORMATION_FORMAT" "/Z7") + else() + set_config_specific_property("DEFAULT_CXX_DEBUG_INFORMATION_FORMAT" "/Zi") + endif() +endif() \ No newline at end of file diff --git a/libultraship/cmake/HandleCompilerRT.cmake b/libultraship/cmake/HandleCompilerRT.cmake new file mode 100644 index 000000000..dad263487 --- /dev/null +++ b/libultraship/cmake/HandleCompilerRT.cmake @@ -0,0 +1,123 @@ +# Check if the compiler-rt library file path exists. +# If found, cache the path in: +# COMPILER_RT_LIBRARY-- +# If err_flag is true OR path not found, emit a message and set: +# COMPILER_RT_LIBRARY-- to NOTFOUND +function(cache_compiler_rt_library err_flag name target library_file) + if(err_flag OR NOT EXISTS "${library_file}") + message(STATUS "Failed to find compiler-rt ${name} library for ${target}") + set(COMPILER_RT_LIBRARY_${name}_${target} "NOTFOUND" CACHE INTERNAL + "compiler-rt ${name} library for ${target}") + else() + message(STATUS "Found compiler-rt ${name} library: ${library_file}") + set(COMPILER_RT_LIBRARY_${name}_${target} "${library_file}" CACHE INTERNAL + "compiler-rt ${name} library for ${target}") + endif() +endfunction() + +function(get_component_name name variable) + if(APPLE) + if(NOT name MATCHES "builtins.*") + set(component_name "${name}_") + endif() + if (CMAKE_OSX_SYSROOT MATCHES ".+MacOSX.+") + set(component_name "${component_name}osx") + + elseif (CMAKE_OSX_SYSROOT MATCHES ".+iPhoneOS.+") + set(component_name "${component_name}ios") + elseif (CMAKE_OSX_SYSROOT MATCHES ".+iPhoneSimulator.+") + set(component_name "${component_name}iossim") + + elseif (CMAKE_OSX_SYSROOT MATCHES ".+AppleTVOS.+") + set(component_name "${component_name}tvos") + elseif (CMAKE_OSX_SYSROOT MATCHES ".+AppleTVSimulator.+") + set(component_name "${component_name}tvossim") + + elseif (CMAKE_OSX_SYSROOT MATCHES ".+WatchOS.+") + set(component_name "${component_name}watchos") + elseif (CMAKE_OSX_SYSROOT MATCHES ".+WatchSimulator.+") + set(component_name "${component_name}watchossim") + else() + message(WARNING "Unknown Apple SDK ${CMAKE_OSX_SYSROOT}, we don't know which compiler-rt library suffix to use.") + endif() + else() + set(component_name "${name}") + endif() + set(${variable} "${component_name}" PARENT_SCOPE) +endfunction() + +# Find the path to compiler-rt library `name` (e.g. "builtins") for the +# specified `TARGET` (e.g. "x86_64-linux-gnu") and return it in `variable`. +# This calls cache_compiler_rt_library that caches the path to speed up +# repeated invocations with the same `name` and `target`. +function(find_compiler_rt_library name variable) + cmake_parse_arguments(ARG "" "TARGET;FLAGS" "" ${ARGN}) + # While we can use compiler-rt runtimes with other compilers, we need to + # query the compiler for runtime location and thus we require Clang. + if(NOT CMAKE_CXX_COMPILER_ID MATCHES Clang) + set(${variable} "NOTFOUND" PARENT_SCOPE) + return() + endif() + set(target "${ARG_TARGET}") + if(NOT target AND CMAKE_CXX_COMPILER_TARGET) + set(target "${CMAKE_CXX_COMPILER_TARGET}") + endif() + if(NOT DEFINED COMPILER_RT_LIBRARY_builtins_${target}) + # If the cache variable is not defined, invoke Clang and then + # set it with cache_compiler_rt_library. + set(clang_command ${CMAKE_CXX_COMPILER} "${ARG_FLAGS}") + if(target) + list(APPEND clang_command "--target=${target}") + endif() + get_property(cxx_flags CACHE CMAKE_CXX_FLAGS PROPERTY VALUE) + string(REPLACE " " ";" cxx_flags "${cxx_flags}") + list(APPEND clang_command ${cxx_flags}) + set(cmd_prefix "") + if(MSVC AND ${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") + set(cmd_prefix "/clang:") + endif() + execute_process( + COMMAND ${clang_command} "${cmd_prefix}--rtlib=compiler-rt" "${cmd_prefix}-print-libgcc-file-name" + RESULT_VARIABLE had_error + OUTPUT_VARIABLE library_file + ) + string(STRIP "${library_file}" library_file) + file(TO_CMAKE_PATH "${library_file}" library_file) + get_filename_component(dirname ${library_file} DIRECTORY) + if(APPLE) + execute_process( + COMMAND ${clang_command} "--print-resource-dir" + RESULT_VARIABLE had_error + OUTPUT_VARIABLE resource_dir + ) + string(STRIP "${resource_dir}" resource_dir) + set(dirname "${resource_dir}/lib/darwin") + endif() + get_filename_component(basename ${library_file} NAME) + if(basename MATCHES ".*clang_rt\.([a-z0-9_\-]+)\.(a|lib)") + set(from_name ${CMAKE_MATCH_1}) + get_component_name(${CMAKE_MATCH_1} to_name) + string(REPLACE "${from_name}" "${to_name}" basename "${basename}") + set(library_file "${dirname}/${basename}") + cache_compiler_rt_library(${had_error} builtins "${target}" "${library_file}") + endif() + endif() + if(NOT COMPILER_RT_LIBRARY_builtins_${target}) + set(${variable} "NOTFOUND" PARENT_SCOPE) + return() + endif() + if(NOT DEFINED COMPILER_RT_LIBRARY_${name}_${target}) + # Clang gives only the builtins library path. Other library paths are + # obtained by substituting "builtins" with ${name} in the builtins + # path and then checking if the resultant path exists. The result of + # this check is also cached by cache_compiler_rt_library. + set(library_file "${COMPILER_RT_LIBRARY_builtins_${target}}") + if(library_file MATCHES ".*clang_rt\.([a-z0-9_\-]+)\.(a|lib)") + set(from_name ${CMAKE_MATCH_0}) + get_component_name(${name} to_name) + string(REPLACE "${from_name}" "${to_name}" library_file "${library_file}") + cache_compiler_rt_library(FALSE "${name}" "${target}" "${library_file}") + endif() + endif() + set(${variable} "${COMPILER_RT_LIBRARY_${name}_${target}}" PARENT_SCOPE) +endfunction() \ No newline at end of file diff --git a/libultraship/cmake/Utils.cmake b/libultraship/cmake/Utils.cmake new file mode 100644 index 000000000..c691eefc6 --- /dev/null +++ b/libultraship/cmake/Utils.cmake @@ -0,0 +1,248 @@ +# utils file for projects came from visual studio solution with cmake-converter. + +################################################################################ +# Wrap each token of the command with condition +################################################################################ +cmake_policy(PUSH) +cmake_policy(SET CMP0054 NEW) +macro(prepare_commands) + unset(TOKEN_ROLE) + unset(COMMANDS) + foreach(TOKEN ${ARG_COMMANDS}) + if("${TOKEN}" STREQUAL "COMMAND") + set(TOKEN_ROLE "KEYWORD") + elseif("${TOKEN_ROLE}" STREQUAL "KEYWORD") + set(TOKEN_ROLE "CONDITION") + elseif("${TOKEN_ROLE}" STREQUAL "CONDITION") + set(TOKEN_ROLE "COMMAND") + elseif("${TOKEN_ROLE}" STREQUAL "COMMAND") + set(TOKEN_ROLE "ARG") + endif() + + if("${TOKEN_ROLE}" STREQUAL "KEYWORD") + list(APPEND COMMANDS "${TOKEN}") + elseif("${TOKEN_ROLE}" STREQUAL "CONDITION") + set(CONDITION ${TOKEN}) + elseif("${TOKEN_ROLE}" STREQUAL "COMMAND") + list(APPEND COMMANDS "$<$:${DUMMY}>$<${CONDITION}:${TOKEN}>") + elseif("${TOKEN_ROLE}" STREQUAL "ARG") + list(APPEND COMMANDS "$<${CONDITION}:${TOKEN}>") + endif() + endforeach() +endmacro() +cmake_policy(POP) + +################################################################################ +# Transform all the tokens to absolute paths +################################################################################ +macro(prepare_output) + unset(OUTPUT) + foreach(TOKEN ${ARG_OUTPUT}) + if(IS_ABSOLUTE ${TOKEN}) + list(APPEND OUTPUT "${TOKEN}") + else() + list(APPEND OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/${TOKEN}") + endif() + endforeach() +endmacro() + +################################################################################ +# Parse add_custom_command_if args. +# +# Input: +# PRE_BUILD - Pre build event option +# PRE_LINK - Pre link event option +# POST_BUILD - Post build event option +# TARGET - Target +# OUTPUT - List of output files +# DEPENDS - List of files on which the command depends +# COMMANDS - List of commands(COMMAND condition1 commannd1 args1 COMMAND +# condition2 commannd2 args2 ...) +# Output: +# OUTPUT - Output files +# DEPENDS - Files on which the command depends +# COMMENT - Comment +# PRE_BUILD - TRUE/FALSE +# PRE_LINK - TRUE/FALSE +# POST_BUILD - TRUE/FALSE +# TARGET - Target name +# COMMANDS - Prepared commands(every token is wrapped in CONDITION) +# NAME - Unique name for custom target +# STEP - PRE_BUILD/PRE_LINK/POST_BUILD +################################################################################ +function(add_custom_command_if_parse_arguments) + cmake_parse_arguments("ARG" "PRE_BUILD;PRE_LINK;POST_BUILD" "TARGET;COMMENT" "DEPENDS;OUTPUT;COMMANDS" ${ARGN}) + + if(WIN32) + set(DUMMY "cd.") + elseif(UNIX) + set(DUMMY "true") + endif() + + prepare_commands() + prepare_output() + + set(DEPENDS "${ARG_DEPENDS}") + set(COMMENT "${ARG_COMMENT}") + set(PRE_BUILD "${ARG_PRE_BUILD}") + set(PRE_LINK "${ARG_PRE_LINK}") + set(POST_BUILD "${ARG_POST_BUILD}") + set(TARGET "${ARG_TARGET}") + if(PRE_BUILD) + set(STEP "PRE_BUILD") + elseif(PRE_LINK) + set(STEP "PRE_LINK") + elseif(POST_BUILD) + set(STEP "POST_BUILD") + endif() + set(NAME "${TARGET}_${STEP}") + + set(OUTPUT "${OUTPUT}" PARENT_SCOPE) + set(DEPENDS "${DEPENDS}" PARENT_SCOPE) + set(COMMENT "${COMMENT}" PARENT_SCOPE) + set(PRE_BUILD "${PRE_BUILD}" PARENT_SCOPE) + set(PRE_LINK "${PRE_LINK}" PARENT_SCOPE) + set(POST_BUILD "${POST_BUILD}" PARENT_SCOPE) + set(TARGET "${TARGET}" PARENT_SCOPE) + set(COMMANDS "${COMMANDS}" PARENT_SCOPE) + set(STEP "${STEP}" PARENT_SCOPE) + set(NAME "${NAME}" PARENT_SCOPE) +endfunction() + +################################################################################ +# Add conditional custom command +# +# Generating Files +# The first signature is for adding a custom command to produce an output: +# add_custom_command_if( +# +# +# +# [COMMAND condition command2 [args2...]] +# [DEPENDS [depends...]] +# [COMMENT comment] +# +# Build Events +# add_custom_command_if( +# +# +# +# [COMMAND condition command2 [args2...]] +# [COMMENT comment] +# +# Input: +# output - Output files the command is expected to produce +# condition - Generator expression for wrapping the command +# command - Command-line(s) to execute at build time. +# args - Command`s args +# depends - Files on which the command depends +# comment - Display the given message before the commands are executed at +# build time. +# PRE_BUILD - Run before any other rules are executed within the target +# PRE_LINK - Run after sources have been compiled but before linking the +# binary +# POST_BUILD - Run after all other rules within the target have been +# executed +################################################################################ +function(add_custom_command_if) + add_custom_command_if_parse_arguments(${ARGN}) + + if(OUTPUT AND TARGET) + message(FATAL_ERROR "Wrong syntax. A TARGET and OUTPUT can not both be specified.") + endif() + + if(OUTPUT) + add_custom_command(OUTPUT ${OUTPUT} + ${COMMANDS} + DEPENDS ${DEPENDS} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT ${COMMENT}) + elseif(TARGET) + if(PRE_BUILD AND NOT ${CMAKE_GENERATOR} MATCHES "Visual Studio") + add_custom_target( + ${NAME} + ${COMMANDS} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT ${COMMENT}) + add_dependencies(${TARGET} ${NAME}) + else() + add_custom_command( + TARGET ${TARGET} + ${STEP} + ${COMMANDS} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT ${COMMENT}) + endif() + else() + message(FATAL_ERROR "Wrong syntax. A TARGET or OUTPUT must be specified.") + endif() +endfunction() + +################################################################################ +# Use props file for a target and configs +# use_props( ) +# Inside there are following variables: +# PROPS_TARGET - +# PROPS_CONFIG - One of +# PROPS_CONFIG_U - Uppercase PROPS_CONFIG +# Input: +# target - Target to apply props file +# configs - Build configurations to apply props file +# props_file - CMake script +################################################################################ +macro(use_props TARGET CONFIGS PROPS_FILE) + set(PROPS_TARGET "${TARGET}") + foreach(PROPS_CONFIG ${CONFIGS}) + string(TOUPPER "${PROPS_CONFIG}" PROPS_CONFIG_U) + + get_filename_component(ABSOLUTE_PROPS_FILE "${PROPS_FILE}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_LIST_DIR}") + if(EXISTS "${ABSOLUTE_PROPS_FILE}") + include("${ABSOLUTE_PROPS_FILE}") + else() + message(WARNING "Corresponding cmake file from props \"${ABSOLUTE_PROPS_FILE}\" doesn't exist") + endif() + endforeach() +endmacro() + +################################################################################ +# Add compile options to source file +# source_file_compile_options( [compile_options...]) +# Input: +# source_file - Source file +# compile_options - Options to add to COMPILE_FLAGS property +################################################################################ +function(source_file_compile_options SOURCE_FILE) + if("${ARGC}" LESS_EQUAL "1") + return() + endif() + + get_source_file_property(COMPILE_OPTIONS "${SOURCE_FILE}" COMPILE_OPTIONS) + + if(COMPILE_OPTIONS) + list(APPEND COMPILE_OPTIONS ${ARGN}) + else() + set(COMPILE_OPTIONS "${ARGN}") + endif() + + set_source_files_properties("${SOURCE_FILE}" PROPERTIES COMPILE_OPTIONS "${COMPILE_OPTIONS}") +endfunction() + +################################################################################ +# Default properties of visual studio projects +################################################################################ +set(DEFAULT_CXX_PROPS "${CMAKE_CURRENT_LIST_DIR}/DefaultCXX.cmake") + +function(get_linux_lsb_release_information) + find_program(LSB_RELEASE_EXEC lsb_release) + if(NOT LSB_RELEASE_EXEC) + message(FATAL_ERROR "Could not detect lsb_release executable, can not gather required information") + endif() + + execute_process(COMMAND "${LSB_RELEASE_EXEC}" --short --id OUTPUT_VARIABLE LSB_RELEASE_ID_SHORT OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND "${LSB_RELEASE_EXEC}" --short --release OUTPUT_VARIABLE LSB_RELEASE_VERSION_SHORT OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND "${LSB_RELEASE_EXEC}" --short --codename OUTPUT_VARIABLE LSB_RELEASE_CODENAME_SHORT OUTPUT_STRIP_TRAILING_WHITESPACE) + + set(LSB_RELEASE_ID_SHORT "${LSB_RELEASE_ID_SHORT}" PARENT_SCOPE) + set(LSB_RELEASE_VERSION_SHORT "${LSB_RELEASE_VERSION_SHORT}" PARENT_SCOPE) + set(LSB_RELEASE_CODENAME_SHORT "${LSB_RELEASE_CODENAME_SHORT}" PARENT_SCOPE) +endfunction() diff --git a/libultraship/cmake/automate-vcpkg.cmake b/libultraship/cmake/automate-vcpkg.cmake new file mode 100644 index 000000000..4764c6428 --- /dev/null +++ b/libultraship/cmake/automate-vcpkg.cmake @@ -0,0 +1,193 @@ +#------------------------------------------------------------------------------------------------------------ +# +# Automate-VCPKG by Andre Taulien +# =============================== +# +# Project Repository: https://github.com/REGoth-project/Automate-VCPKG +# License ..........: MIT, see end of file. +# +# Based on: https://github.com/sutambe/cpptruths/blob/vcpkg_cmake_blog/cpp0x/vcpkg_test/CMakeLists.txt +# +# +# While [Vcpkg](https://github.com/microsoft/vcpkg) on it's own is awesome, it does add +# a little bit of complexity to getting a project to build. Even more if the one trying +# to compile your application is not too fond of the commandline. Additionally, CMake +# commands tend to get rather long with the toolchain path. +# +# To keep things simple for new users who just want to get the project to build, this +# script offers a solution. +# +# Lets assume your main `CMakelists.txt` looks something like this: +# +# cmake_minimum_required (VERSION 3.12.0) +# project (MyProject) +# +# add_executable(MyExecutable main.c) +# +# To integrate Vcpkg into that `CMakelists.txt`, simple put the following lines before the +# call to `project(MyProject)`: +# +# include(cmake/automate-vcpkg.cmake) +# +# vcpkg_bootstrap() +# vcpkg_install_packages(libsquish physfs) +# +# The call to `vcpkg_bootstrap()` will clone the official Vcpkg repository and bootstrap it. +# If it detected an existing environment variable defining a valid `VCPKG_ROOT`, it will +# update the existing installation of Vcpkg. +# +# Arguments to `vcpkg_install_packages()` are the packages you want to install using Vcpkg. +# +# If you want to keep the possibility for users to chose their own copy of Vcpkg, you can +# simply not run the code snippet mentioned above, something like this will work: +# +# option(SKIP_AUTOMATE_VCPKG "When ON, you will need to built the packages +# required by MyProject on your own or supply your own vcpkg toolchain.") +# +# if (NOT SKIP_AUTOMATE_VCPKG) +# include(cmake/automate-vcpkg.cmake) +# +# vcpkg_bootstrap() +# vcpkg_install_packages(libsquish physfs) +# endif() +# +# Then, the user has to supply the packages on their own, be it through Vcpkg or manually +# specifying their locations. +#------------------------------------------------------------------------------------------------------------ + +cmake_minimum_required (VERSION 3.12) + +if(WIN32) + set(VCPKG_FALLBACK_ROOT ${CMAKE_CURRENT_BINARY_DIR}/vcpkg CACHE STRING "vcpkg configuration directory to use if vcpkg was not installed on the system before") +else() + set(VCPKG_FALLBACK_ROOT ${CMAKE_CURRENT_BINARY_DIR}/.vcpkg CACHE STRING "vcpkg configuration directory to use if vcpkg was not installed on the system before") +endif() + +# On Windows, Vcpkg defaults to x86, even on x64 systems. If we're +# doing a 64-bit build, we need to fix that. +if (WIN32) + + # Since the compiler checks haven't run yet, we need to figure + # out the value of CMAKE_SIZEOF_VOID_P ourselfs. + # We also need to make sure the triplet isn't already set because + # ARM64 will be overriden by the 64bit check + + include(CheckTypeSize) + enable_language(C) + check_type_size("void*" SIZEOF_VOID_P BUILTIN_TYPES_ONLY) + + if (SIZEOF_VOID_P EQUAL 8 AND NOT DEFINED ${CMAKE_VS_PLATFORM_NAME}) + message(STATUS "Using Vcpkg triplet 'x64-windows'") + + set(VCPKG_TRIPLET x64-windows) + endif() +endif() + +if(NOT DEFINED VCPKG_ROOT) + if(NOT DEFINED ENV{VCPKG_ROOT}) + set(VCPKG_ROOT ${VCPKG_FALLBACK_ROOT}) + else() + set(VCPKG_ROOT $ENV{VCPKG_ROOT}) + endif() +endif() + +# Installs a new copy of Vcpkg or updates an existing one +macro(vcpkg_bootstrap) + _install_or_update_vcpkg() + + # Find out whether the user supplied their own VCPKG toolchain file + if(NOT DEFINED ${CMAKE_TOOLCHAIN_FILE}) + # We know this wasn't set before so we need point the toolchain file to the newly found VCPKG_ROOT + set(CMAKE_TOOLCHAIN_FILE ${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake CACHE STRING "") + + # Just setting vcpkg.cmake as toolchain file does not seem to actually pull in the code + include(${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake) + + set(AUTOMATE_VCPKG_USE_SYSTEM_VCPKG OFF) + else() + # VCPKG_ROOT has been defined by the toolchain file already + set(AUTOMATE_VCPKG_USE_SYSTEM_VCPKG ON) + endif() + + message(STATUS "Automate VCPKG status:") + message(STATUS " VCPKG_ROOT.....: ${VCPKG_ROOT}") + message(STATUS " VCPKG_EXEC.....: ${VCPKG_EXEC}") + message(STATUS " VCPKG_BOOTSTRAP: ${VCPKG_BOOTSTRAP}") +endmacro() + +macro(_install_or_update_vcpkg) + if(NOT EXISTS ${VCPKG_ROOT}) + message(STATUS "Cloning vcpkg in ${VCPKG_ROOT}") + execute_process(COMMAND git clone https://github.com/Microsoft/vcpkg.git ${VCPKG_ROOT} --depth 1) + + # If a reproducible build is desired (and potentially old libraries are # ok), uncomment the + # following line and pin the vcpkg repository to a specific githash. + # execute_process(COMMAND git checkout 745a0aea597771a580d0b0f4886ea1e3a94dbca6 WORKING_DIRECTORY ${VCPKG_ROOT}) + else() + # The following command has no effect if the vcpkg repository is in a detached head state. + message(STATUS "Auto-updating vcpkg in ${VCPKG_ROOT}") + execute_process(COMMAND git pull WORKING_DIRECTORY ${VCPKG_ROOT}) + endif() + + if(NOT EXISTS ${VCPKG_ROOT}/README.md) + message(FATAL_ERROR "***** FATAL ERROR: Could not clone vcpkg *****") + endif() + + if(WIN32) + set(VCPKG_EXEC ${VCPKG_ROOT}/vcpkg.exe) + set(VCPKG_BOOTSTRAP ${VCPKG_ROOT}/bootstrap-vcpkg.bat) + else() + set(VCPKG_EXEC ${VCPKG_ROOT}/vcpkg) + set(VCPKG_BOOTSTRAP ${VCPKG_ROOT}/bootstrap-vcpkg.sh) + endif() + + if(NOT EXISTS ${VCPKG_EXEC}) + message("Bootstrapping vcpkg in ${VCPKG_ROOT}") + execute_process(COMMAND ${VCPKG_BOOTSTRAP} WORKING_DIRECTORY ${VCPKG_ROOT}) + endif() + + if(NOT EXISTS ${VCPKG_EXEC}) + message(FATAL_ERROR "***** FATAL ERROR: Could not bootstrap vcpkg *****") + endif() + +endmacro() + +# Installs the list of packages given as parameters using Vcpkg +macro(vcpkg_install_packages) + + # Need the given list to be space-separated + #string (REPLACE ";" " " PACKAGES_LIST_STR "${ARGN}") + + message(STATUS "Installing/Updating the following vcpkg-packages: ${PACKAGES_LIST_STR}") + + if (VCPKG_TRIPLET) + set(ENV{VCPKG_DEFAULT_TRIPLET} "${VCPKG_TRIPLET}") + endif() + + execute_process( + COMMAND ${VCPKG_EXEC} install ${ARGN} + WORKING_DIRECTORY ${VCPKG_ROOT} + ) +endmacro() + +# MIT License +# +# Copyright (c) 2019 REGoth-project +# +# 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/libultraship/cmake/cvars.cmake b/libultraship/cmake/cvars.cmake new file mode 100644 index 000000000..f16e810a0 --- /dev/null +++ b/libultraship/cmake/cvars.cmake @@ -0,0 +1,49 @@ +set(CVAR_VSYNC_ENABLED "gVsyncEnabled" CACHE STRING "") +set(CVAR_Z_FIGHTING_MODE "gZFightingMode" CACHE STRING "") +set(CVAR_INTERNAL_RESOLUTION "gInternalResolution" CACHE STRING "") +set(CVAR_MSAA_VALUE "gMSAAValue" CACHE STRING "") +set(CVAR_SDL_WINDOWED_FULLSCREEN "gSdlWindowedFullscreen" CACHE STRING "") +set(CVAR_TEXTURE_FILTER "gTextureFilter" CACHE STRING "") +set(CVAR_IMGUI_CONTROLLER_NAV "gControlNav" CACHE STRING "") +set(CVAR_CONSOLE_WINDOW_OPEN "gConsoleEnabled" CACHE STRING "") +set(CVAR_CONTROLLER_CONFIGURATION_WINDOW_OPEN "gControllerConfigurationEnabled" CACHE STRING "") +set(CVAR_CONTROLLER_DISCONNECTED_WINDOW_OPEN "gControllerDisconnectedWindowEnabled" CACHE STRING "") +set(CVAR_CONTROLLER_REORDERING_WINDOW_OPEN "gControllerReorderingWindowEnabled" CACHE STRING "") +set(CVAR_GFX_DEBUGGER_WINDOW_OPEN "gGfxDebuggerEnabled" CACHE STRING "") +set(CVAR_STATS_WINDOW_OPEN "gStatsEnabled" CACHE STRING "") +set(CVAR_ENABLE_MULTI_VIEWPORTS "gEnableMultiViewports" CACHE STRING "") +set(CVAR_LOW_RES_MODE "gLowResMode" CACHE STRING "") +set(CVAR_SIMULATED_INPUT_LAG "gSimulatedInputLag" CACHE STRING "") +set(CVAR_GAME_OVERLAY_FONT "gOverlayFont" CACHE STRING "") +set(CVAR_MENU_BAR_OPEN "gOpenMenuBar" CACHE STRING "") +set(CVAR_PREFIX_CONTROLLERS "gControllers" CACHE STRING "") +set(CVAR_PREFIX_ADVANCED_RESOLUTION "gAdvancedResolution" CACHE STRING "") +set(CVAR_AUDIO_CHANNELS_SETTING "gAudioChannelsSetting" CACHE STRING "") +set(CVAR_ALLOW_BACKGROUND_INPUTS "gAllowBackgroundInputs" CACHE STRING "") +set(CVAR_SCRIPT_SAFE_LEVEL "gScriptSafeLevel" CACHE STRING "") + +add_compile_definitions( + CVAR_VSYNC_ENABLED="${CVAR_VSYNC_ENABLED}" + CVAR_Z_FIGHTING_MODE="${CVAR_Z_FIGHTING_MODE}" + CVAR_INTERNAL_RESOLUTION="${CVAR_INTERNAL_RESOLUTION}" + CVAR_MSAA_VALUE="${CVAR_MSAA_VALUE}" + CVAR_SDL_WINDOWED_FULLSCREEN="${CVAR_SDL_WINDOWED_FULLSCREEN}" + CVAR_TEXTURE_FILTER="${CVAR_TEXTURE_FILTER}" + CVAR_IMGUI_CONTROLLER_NAV="${CVAR_IMGUI_CONTROLLER_NAV}" + CVAR_CONSOLE_WINDOW_OPEN="${CVAR_CONSOLE_WINDOW_OPEN}" + CVAR_CONTROLLER_CONFIGURATION_WINDOW_OPEN="${CVAR_CONTROLLER_CONFIGURATION_WINDOW_OPEN}" + CVAR_CONTROLLER_DISCONNECTED_WINDOW_OPEN="${CVAR_CONTROLLER_DISCONNECTED_WINDOW_OPEN}" + CVAR_CONTROLLER_REORDERING_WINDOW_OPEN="${CVAR_CONTROLLER_REORDERING_WINDOW_OPEN}" + CVAR_GFX_DEBUGGER_WINDOW_OPEN="${CVAR_GFX_DEBUGGER_WINDOW_OPEN}" + CVAR_STATS_WINDOW_OPEN="${CVAR_STATS_WINDOW_OPEN}" + CVAR_ENABLE_MULTI_VIEWPORTS="${CVAR_ENABLE_MULTI_VIEWPORTS}" + CVAR_LOW_RES_MODE="${CVAR_LOW_RES_MODE}" + CVAR_SIMULATED_INPUT_LAG="${CVAR_SIMULATED_INPUT_LAG}" + CVAR_GAME_OVERLAY_FONT="${CVAR_GAME_OVERLAY_FONT}" + CVAR_MENU_BAR_OPEN="${CVAR_MENU_BAR_OPEN}" + CVAR_PREFIX_CONTROLLERS="${CVAR_PREFIX_CONTROLLERS}" + CVAR_PREFIX_ADVANCED_RESOLUTION="${CVAR_PREFIX_ADVANCED_RESOLUTION}" + CVAR_AUDIO_CHANNELS_SETTING="${CVAR_AUDIO_CHANNELS_SETTING}" + CVAR_ALLOW_BACKGROUND_INPUTS="${CVAR_ALLOW_BACKGROUND_INPUTS}" + CVAR_SCRIPT_SAFE_LEVEL="${CVAR_SCRIPT_SAFE_LEVEL}" +) diff --git a/libultraship/cmake/dependencies/android.cmake b/libultraship/cmake/dependencies/android.cmake new file mode 100644 index 000000000..36666a0fb --- /dev/null +++ b/libultraship/cmake/dependencies/android.cmake @@ -0,0 +1,73 @@ +include(FetchContent) + +#=================== SDL2 =================== +find_package(SDL2 QUIET) +if (NOT ${SDL2_FOUND}) + FetchContent_Declare( + SDL2 + GIT_REPOSITORY https://github.com/libsdl-org/SDL.git + GIT_TAG release-2.32.10 + ) + message("SDL2 not found. Downloading now...") + FetchContent_MakeAvailable(SDL2) + message("SDL2 downloaded to " ${FETCHCONTENT_BASE_DIR}/sdl2-src) +endif() + +#=================== nlohmann-json =================== +find_package(nlohmann_json QUIET) +if (NOT ${nlohmann_json_FOUND}) + FetchContent_Declare( + nlohmann_json + GIT_REPOSITORY https://github.com/nlohmann/json.git + GIT_TAG v3.12.0 + OVERRIDE_FIND_PACKAGE + ) + FetchContent_MakeAvailable(nlohmann_json) +endif() + +#=================== tinyxml2 =================== +find_package(tinyxml2 QUIET) +if (NOT ${tinyxml2_FOUND}) + set(tinyxml2_BUILD_TESTING OFF) + FetchContent_Declare( + tinyxml2 + GIT_REPOSITORY https://github.com/leethomason/tinyxml2.git + GIT_TAG 11.0.0 + OVERRIDE_FIND_PACKAGE + ) + FetchContent_MakeAvailable(tinyxml2) +endif() + +#=================== spdlog =================== +find_package(spdlog QUIET) +if (NOT ${spdlog_FOUND}) + FetchContent_Declare( + spdlog + GIT_REPOSITORY https://github.com/gabime/spdlog.git + GIT_TAG v1.16.0 + OVERRIDE_FIND_PACKAGE + ) + FetchContent_MakeAvailable(spdlog) +endif() + +#=================== libzip =================== +find_package(libzip QUIET) +if (NOT ${libzip_FOUND}) + set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) + set(BUILD_TOOLS OFF) + set(BUILD_REGRESS OFF) + set(BUILD_EXAMPLES OFF) + set(BUILD_DOC OFF) + set(BUILD_OSSFUZZ OFF) + set(BUILD_SHARED_LIBS OFF) + FetchContent_Declare( + libzip + GIT_REPOSITORY https://github.com/nih-at/libzip.git + GIT_TAG v1.11.4 + OVERRIDE_FIND_PACKAGE + ) + FetchContent_MakeAvailable(libzip) + list(APPEND ADDITIONAL_LIB_INCLUDES ${libzip_SOURCE_DIR}/lib ${libzip_BINARY_DIR}) +endif() + +target_link_libraries(ImGui PUBLIC SDL2::SDL2) diff --git a/libultraship/cmake/dependencies/common.cmake b/libultraship/cmake/dependencies/common.cmake new file mode 100644 index 000000000..80dec56ed --- /dev/null +++ b/libultraship/cmake/dependencies/common.cmake @@ -0,0 +1,310 @@ +include(FetchContent) + +find_package(OpenGL QUIET) + +#=================== ImGui =================== +set(imgui_fixes_and_config_patch_file ${CMAKE_CURRENT_SOURCE_DIR}/cmake/dependencies/patches/imgui-fixes-and-config.patch) +set(imgui_apply_patch_command ${CMAKE_COMMAND} -Dpatch_file=${imgui_fixes_and_config_patch_file} -Dwith_reset=TRUE -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/dependencies/git-patch.cmake) + +FetchContent_Declare( + ImGui + GIT_REPOSITORY https://github.com/ocornut/imgui.git + GIT_TAG v1.91.9b-docking + PATCH_COMMAND ${imgui_apply_patch_command} +) +FetchContent_MakeAvailable(ImGui) +list(APPEND ADDITIONAL_LIB_INCLUDES ${imgui_SOURCE_DIR} ${imgui_SOURCE_DIR}/backends) + +add_library(ImGui STATIC) +set_property(TARGET ImGui PROPERTY CXX_STANDARD 20) + +target_sources(ImGui + PRIVATE + ${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}/imgui.cpp +) + +target_sources(ImGui + PRIVATE + ${imgui_SOURCE_DIR}/backends/imgui_impl_opengl3.cpp + ${imgui_SOURCE_DIR}/backends/imgui_impl_sdl2.cpp +) + +target_include_directories(ImGui PUBLIC ${imgui_SOURCE_DIR} ${imgui_SOURCE_DIR}/backends PRIVATE ${SDL2_INCLUDE_DIRS}) + +# ========= StormLib ============= +if(INCLUDE_MPQ_SUPPORT) + set(stormlib_patch_file ${CMAKE_CURRENT_SOURCE_DIR}/cmake/dependencies/patches/stormlib-optimizations.patch) + set(stormlib_apply_patch_command ${CMAKE_COMMAND} -Dpatch_file=${stormlib_patch_file} -Dwith_reset=TRUE -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/dependencies/git-patch.cmake) + + FetchContent_Declare( + StormLib + GIT_REPOSITORY https://github.com/ladislav-zezula/StormLib.git + GIT_TAG v9.25 + PATCH_COMMAND ${stormlib_apply_patch_command} + ) + FetchContent_MakeAvailable(StormLib) + list(APPEND ADDITIONAL_LIB_INCLUDES ${stormlib_SOURCE_DIR}/src) +endif() + +#=================== STB =================== +set(STB_DIR ${CMAKE_BINARY_DIR}/_deps/stb) +file(DOWNLOAD "https://github.com/nothings/stb/raw/0bc88af4de5fb022db643c2d8e549a0927749354/stb_image.h" "${STB_DIR}/stb_image.h") +file(WRITE "${STB_DIR}/stb_impl.c" "#define STB_IMAGE_IMPLEMENTATION\n#include \"stb_image.h\"") + +add_library(stb STATIC) + +target_sources(stb PRIVATE + ${STB_DIR}/stb_image.h + ${STB_DIR}/stb_impl.c +) + +target_include_directories(stb PUBLIC ${STB_DIR}) +list(APPEND ADDITIONAL_LIB_INCLUDES ${STB_DIR}) + +#=================== libgfxd =================== +if (GFX_DEBUG_DISASSEMBLER) + FetchContent_Declare( + libgfxd + GIT_REPOSITORY https://github.com/glankk/libgfxd.git + GIT_TAG 008f73dca8ebc9151b205959b17773a19c5bd0da + ) + FetchContent_MakeAvailable(libgfxd) + + add_library(libgfxd STATIC) + set_property(TARGET libgfxd PROPERTY C_STANDARD 11) + + target_sources(libgfxd PRIVATE + ${libgfxd_SOURCE_DIR}/gbi.h + ${libgfxd_SOURCE_DIR}/gfxd.h + ${libgfxd_SOURCE_DIR}/priv.h + ${libgfxd_SOURCE_DIR}/gfxd.c + ${libgfxd_SOURCE_DIR}/uc.c + ${libgfxd_SOURCE_DIR}/uc_f3d.c + ${libgfxd_SOURCE_DIR}/uc_f3db.c + ${libgfxd_SOURCE_DIR}/uc_f3dex.c + ${libgfxd_SOURCE_DIR}/uc_f3dex2.c + ${libgfxd_SOURCE_DIR}/uc_f3dexb.c + ) + + target_include_directories(libgfxd PUBLIC ${libgfxd_SOURCE_DIR}) +endif() + +#======== thread-pool ======== +FetchContent_Declare( + ThreadPool + GIT_REPOSITORY https://github.com/bshoshany/thread-pool.git + GIT_TAG v4.1.0 +) +FetchContent_MakeAvailable(ThreadPool) + +list(APPEND ADDITIONAL_LIB_INCLUDES ${threadpool_SOURCE_DIR}/include) + +#=========== prism =========== +option(PRISM_STANDALONE "Build prism as a standalone library" OFF) +FetchContent_Declare( + prism + GIT_REPOSITORY https://github.com/KiritoDv/prism-processor.git + GIT_TAG 1de054450e7b3c5f777d2e3dfcb228ad120c329d +) +FetchContent_MakeAvailable(prism) + +# prism's CMakeLists.txt calls cmake_minimum_required(VERSION <3.10), which causes +# CMake to explicitly set CMP0141=OLD in prism's scope (cmake_policy(VERSION) disables +# all policies newer than the specified version). With CMP0141=OLD the compile +# template always appends "/Fd .pdb /FS" to every compile command. sccache +# parses the command line, sees "/Fd prism.pdb", and expects that file to exist after +# compilation. When our /Z7 override wins (no PDB written) sccache aborts with +# "failed to open file prism.pdb". +# +# The simplest fix is to compile prism without sccache at all (clear the launcher). +# With the launcher cleared, cl.exe compiles prism directly; /Z7 (embedded debug info) +# is still applied so no PDB file is written and no race over a shared .pdb occurs. +if(MSVC AND TARGET prism) + set_target_properties(prism PROPERTIES + C_COMPILER_LAUNCHER "" + CXX_COMPILER_LAUNCHER "" + ) + target_compile_options(prism PRIVATE $<$:/Z7>) +endif() + +#=========== monocypher =========== +FetchContent_Declare( + monocypher + GIT_REPOSITORY https://github.com/LoupVaillant/Monocypher.git + GIT_TAG 0d85f98c9d9b0227e42cf795cb527dff372b40a4 +) +FetchContent_MakeAvailable(monocypher) + +add_library(monocypher STATIC) +set_property(TARGET monocypher PROPERTY C_STANDARD 11) + +target_sources(monocypher PRIVATE + ${monocypher_SOURCE_DIR}/src/monocypher.c + ${monocypher_SOURCE_DIR}/src/optional/monocypher-ed25519.c +) + +target_include_directories(monocypher PUBLIC + ${monocypher_SOURCE_DIR}/src + ${monocypher_SOURCE_DIR}/src/optional +) + +#=========== libtcc =========== +if(ENABLE_SCRIPTING) + +FetchContent_Declare( + tinycc + GIT_REPOSITORY https://github.com/TinyCC/tinycc.git + GIT_TAG mob +) + +FetchContent_MakeAvailable(tinycc) +if(NOT TARGET libtcc) + if(NOT EXISTS "${tinycc_SOURCE_DIR}/config.h") + message(STATUS "Configuring TinyCC to generate config.h...") + if(WIN32) + execute_process( + COMMAND cmd /c build-tcc.bat -c cl + WORKING_DIRECTORY "${tinycc_SOURCE_DIR}/win32" + RESULT_VARIABLE tcc_config_result + ) + else() + execute_process( + COMMAND ./configure + WORKING_DIRECTORY "${tinycc_SOURCE_DIR}" + RESULT_VARIABLE tcc_config_result + ) + endif() + + if(NOT tcc_config_result EQUAL 0) + message(WARNING "TinyCC configuration script returned non-zero. The build might fail.") + endif() + + if(CMAKE_SYSTEM_NAME STREQUAL "iOS") + message(STATUS "iOS target detected: Disabling CONFIG_CODESIGN...") + file(APPEND "${tinycc_SOURCE_DIR}/config.h" "\n/* Force disable code signing for iOS cross-compilation */\n#undef CONFIG_CODESIGN\n") + endif() + endif() + + if(CMAKE_CROSSCOMPILING) + find_program(HOST_C_COMPILER NAMES cc clang gcc REQUIRED) + set(C2STR_EXE "${tinycc_BINARY_DIR}/tcc_c2str_host") + if(CMAKE_HOST_WIN32) + set(C2STR_EXE "${C2STR_EXE}.exe") + endif() + + set(SIGN_COMMAND "") + if(CMAKE_HOST_APPLE) + set(SIGN_COMMAND COMMAND codesign -f -s - "${C2STR_EXE}") + endif() + + add_custom_command( + OUTPUT "${C2STR_EXE}" + COMMAND ${CMAKE_COMMAND} -E env --unset=SDKROOT --unset=IPHONEOS_DEPLOYMENT_TARGET --unset=TVOS_DEPLOYMENT_TARGET + ${HOST_C_COMPILER} -DC2STR -o "${C2STR_EXE}" "${tinycc_SOURCE_DIR}/conftest.c" + ${SIGN_COMMAND} + DEPENDS "${tinycc_SOURCE_DIR}/conftest.c" + COMMENT "Compiling host tool c2str natively..." + ) + + add_custom_command( + OUTPUT "${tinycc_BINARY_DIR}/tccdefs_.h" + COMMAND "${C2STR_EXE}" "${tinycc_SOURCE_DIR}/include/tccdefs.h" "${tinycc_BINARY_DIR}/tccdefs_.h" + DEPENDS "${tinycc_SOURCE_DIR}/include/tccdefs.h" "${C2STR_EXE}" + COMMENT "Generating tccdefs_.h for TinyCC (Cross-compiling)..." + ) + else() + add_executable(tcc_c2str "${tinycc_SOURCE_DIR}/conftest.c") + target_compile_definitions(tcc_c2str PRIVATE C2STR) + target_include_directories(tcc_c2str PRIVATE "${tinycc_SOURCE_DIR}") + + if(APPLE) + set_target_properties(tcc_c2str PROPERTIES + CODE_SIGNING_ALLOWED NO + CODE_SIGNING_REQUIRED NO + XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO" + XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO" + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "" + XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "" + ) + endif() + + add_custom_command( + OUTPUT "${tinycc_BINARY_DIR}/tccdefs_.h" + COMMAND tcc_c2str "${tinycc_SOURCE_DIR}/include/tccdefs.h" "${tinycc_BINARY_DIR}/tccdefs_.h" + DEPENDS "${tinycc_SOURCE_DIR}/include/tccdefs.h" tcc_c2str + COMMENT "Generating tccdefs_.h for TinyCC..." + ) + endif() + + # libtcc is LGPL; keep it as a shared library so consumers link against it + # dynamically rather than incorporating it into their binary. + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) + add_library(libtcc SHARED + "${tinycc_SOURCE_DIR}/libtcc.c" + "${tinycc_BINARY_DIR}/tccdefs_.h" + ) + + add_library(libtcc1 STATIC + "${tinycc_SOURCE_DIR}/lib/libtcc1.c" + ) + + target_include_directories(libtcc1 PRIVATE + "${tinycc_SOURCE_DIR}" + "${tinycc_BINARY_DIR}" + ) + + if(MSVC) + if(CMAKE_GENERATOR_PLATFORM MATCHES "ARM64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|aarch64") + target_compile_definitions(libtcc1 PRIVATE __aarch64__ _WIN64) + target_compile_definitions(libtcc PRIVATE __aarch64__ TCC_TARGET_ARM64 _WIN64) + else() + target_compile_definitions(libtcc1 PRIVATE __x86_64__ _WIN64) + target_compile_definitions(libtcc PRIVATE __x86_64__ TCC_TARGET_X86_64 _WIN64) + endif() + target_compile_definitions(libtcc1 PRIVATE "__faststorefence=__faststorefence_tcc_unused") + # MSVC's defines `__assert`, which collides with TCC's internal + # `__assert` symbol. Rename TCC's use the same way `__faststorefence` is above. + target_compile_definitions(libtcc PRIVATE "__assert=__assert_tcc_unused") + endif() + + set(TCC_SAFE_INCLUDE_DIR "${tinycc_BINARY_DIR}/safe_include") + configure_file( + "${tinycc_SOURCE_DIR}/libtcc.h" + "${TCC_SAFE_INCLUDE_DIR}/libtcc.h" + COPYONLY + ) + + target_include_directories(libtcc PRIVATE + "${tinycc_SOURCE_DIR}" + "${tinycc_BINARY_DIR}" + ) + target_include_directories(libtcc PUBLIC + $ + ) + + if(ANDROID) + target_link_libraries(libtcc PRIVATE dl m) + elseif(UNIX AND NOT APPLE) + target_link_libraries(libtcc PRIVATE dl m pthread) + endif() + + set_target_properties(libtcc PROPERTIES OUTPUT_NAME "tcc") + set_target_properties(libtcc1 PROPERTIES OUTPUT_NAME "tcc1") + + if(APPLE) + set_target_properties(libtcc libtcc1 PROPERTIES + CODE_SIGNING_ALLOWED NO + CODE_SIGNING_REQUIRED NO + XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO" + XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO" + XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "" + XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "" + ) + endif() +endif() + +endif() # ENABLE_SCRIPTING \ No newline at end of file diff --git a/libultraship/cmake/dependencies/git-patch.cmake b/libultraship/cmake/dependencies/git-patch.cmake new file mode 100644 index 000000000..deb3e35da --- /dev/null +++ b/libultraship/cmake/dependencies/git-patch.cmake @@ -0,0 +1,61 @@ +# In variables: patch_file, with_reset + +function(patch) + execute_process( + COMMAND git apply ${patch_file} + RESULT_VARIABLE ret + ERROR_QUIET + ) + set(ret ${ret} PARENT_SCOPE) +endfunction() + +function(check_patch) + execute_process( + COMMAND git apply --reverse --check ${patch_file} + RESULT_VARIABLE ret + ERROR_QUIET + ) + set(ret ${ret} PARENT_SCOPE) +endfunction() + +# Applies the patch or checks if it has already been applied successfully previously. Will error otherwise. +function(patch_if_needed) + patch() + if(NOT ret EQUAL 0) + check_patch() + endif() + set(ret ${ret} PARENT_SCOPE) +endfunction() + +# Resets code and reapply patch, if old (potentially incompatible) patch applied +function(patch_if_needed_with_reset) + patch_if_needed() + if(NOT ret EQUAL 0) + message(STATUS "Failed to patch in current state, clearing changes to reapply") + execute_process( + COMMAND git status --porcelain + RESULT_VARIABLE is_changed + ) + if(NOT is_changed EQUAL 0) + message(WARNING "Patch inapplyable in clean state") + set(ret 1) + else() + execute_process(COMMAND git reset --hard) + patch_if_needed() + endif() + endif() + set(ret ${ret} PARENT_SCOPE) +endfunction() + +message(STATUS "Trying to apply patch ${patch_file}") +if(with_reset) + patch_if_needed_with_reset() +else() + patch_if_needed() +endif() + +if(NOT ret EQUAL 0) + message(FATAL_ERROR "Failed to apply patch ${patch_file}") +else() + message(STATUS "Successfully patched with ${patch_file}") +endif() diff --git a/libultraship/cmake/dependencies/ios.cmake b/libultraship/cmake/dependencies/ios.cmake new file mode 100644 index 000000000..aad5c5868 --- /dev/null +++ b/libultraship/cmake/dependencies/ios.cmake @@ -0,0 +1,90 @@ +include(FetchContent) + +#=================== SDL2 =================== +find_package(SDL2 QUIET) +if (NOT ${SDL2_FOUND}) + FetchContent_Declare( + SDL2 + GIT_REPOSITORY https://github.com/libsdl-org/SDL.git + GIT_TAG release-2.32.10 + OVERRIDE_FIND_PACKAGE + ) + FetchContent_MakeAvailable(SDL2) +endif() + +#=================== nlohmann-json =================== +find_package(nlohmann_json QUIET) +if (NOT ${nlohmann_json_FOUND}) + FetchContent_Declare( + nlohmann_json + GIT_REPOSITORY https://github.com/nlohmann/json.git + GIT_TAG v3.12.0 + OVERRIDE_FIND_PACKAGE + ) + FetchContent_MakeAvailable(nlohmann_json) +endif() + +#=================== tinyxml2 =================== +find_package(tinyxml2 QUIET) +if (NOT ${tinyxml2_FOUND}) + set(tinyxml2_BUILD_TESTING OFF) + FetchContent_Declare( + tinyxml2 + GIT_REPOSITORY https://github.com/leethomason/tinyxml2.git + GIT_TAG 11.0.0 + OVERRIDE_FIND_PACKAGE + ) + FetchContent_MakeAvailable(tinyxml2) +endif() + +#=================== spdlog =================== +find_package(spdlog QUIET) +if (NOT ${spdlog_FOUND}) + FetchContent_Declare( + spdlog + GIT_REPOSITORY https://github.com/gabime/spdlog.git + GIT_TAG v1.16.0 + OVERRIDE_FIND_PACKAGE + ) + FetchContent_MakeAvailable(spdlog) +endif() + +#=================== libzip =================== +find_package(libzip QUIET) +if (NOT ${libzip_FOUND}) + set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) + set(BUILD_TOOLS OFF) + set(BUILD_REGRESS OFF) + set(BUILD_EXAMPLES OFF) + set(BUILD_DOC OFF) + set(BUILD_OSSFUZZ OFF) + set(BUILD_SHARED_LIBS OFF) + FetchContent_Declare( + libzip + GIT_REPOSITORY https://github.com/nih-at/libzip.git + GIT_TAG v1.11.4 + OVERRIDE_FIND_PACKAGE + ) + FetchContent_MakeAvailable(libzip) + list(APPEND ADDITIONAL_LIB_INCLUDES ${libzip_SOURCE_DIR}/lib ${libzip_BINARY_DIR}) +endif() + +#=================== Metal-cpp =================== +FetchContent_Declare( + metalcpp + GIT_REPOSITORY https://github.com/briaguya-ai/single-header-metal-cpp.git + GIT_TAG macOS13_iOS16 +) +FetchContent_MakeAvailable(metalcpp) +list(APPEND ADDITIONAL_LIB_INCLUDES ${metalcpp_SOURCE_DIR}) + +#=================== ImGui =================== +target_sources(ImGui + PRIVATE + ${imgui_SOURCE_DIR}/backends/imgui_impl_metal.mm +) + +target_include_directories(ImGui PRIVATE ${metalcpp_SOURCE_DIR}) +target_compile_definitions(ImGui PUBLIC IMGUI_IMPL_METAL_CPP) + +target_link_libraries(ImGui PUBLIC SDL2::SDL2-static SDL2::SDL2main) diff --git a/libultraship/cmake/dependencies/linux.cmake b/libultraship/cmake/dependencies/linux.cmake new file mode 100644 index 000000000..02301f130 --- /dev/null +++ b/libultraship/cmake/dependencies/linux.cmake @@ -0,0 +1,10 @@ +#=================== ImGui =================== +find_package(SDL2 REQUIRED) +target_link_libraries(ImGui PUBLIC SDL2::SDL2) + +if (USE_OPENGLES) + target_link_libraries(ImGui PUBLIC ${OPENGL_GLESv2_LIBRARY}) + add_compile_definitions(IMGUI_IMPL_OPENGL_ES3) +else() + target_link_libraries(ImGui PUBLIC ${OPENGL_opengl_LIBRARY}) +endif() diff --git a/libultraship/cmake/dependencies/mac.cmake b/libultraship/cmake/dependencies/mac.cmake new file mode 100644 index 000000000..6da8e7e8c --- /dev/null +++ b/libultraship/cmake/dependencies/mac.cmake @@ -0,0 +1,42 @@ +include(FetchContent) + +#=================== spdlog =================== +# macports has issues with this because of fmt +# brew doesn't support building multiarch +find_package(spdlog QUIET) +if (NOT ${spdlog_FOUND}) + FetchContent_Declare( + spdlog + GIT_REPOSITORY https://github.com/gabime/spdlog.git + GIT_TAG v1.16.0 + OVERRIDE_FIND_PACKAGE + ) + FetchContent_MakeAvailable(spdlog) +endif() + +#=================== Metal-cpp =================== +FetchContent_Declare( + metalcpp + GIT_REPOSITORY https://github.com/briaguya-ai/single-header-metal-cpp.git + GIT_TAG macOS13_iOS16 +) +FetchContent_MakeAvailable(metalcpp) +list(APPEND ADDITIONAL_LIB_INCLUDES ${metalcpp_SOURCE_DIR}) + +#=================== ImGui =================== +target_sources(ImGui + PRIVATE + ${imgui_SOURCE_DIR}/backends/imgui_impl_metal.mm +) + +target_include_directories(ImGui PRIVATE ${metalcpp_SOURCE_DIR}) +target_compile_definitions(ImGui PUBLIC IMGUI_IMPL_METAL_CPP) + +find_package(SDL2 REQUIRED) +target_link_libraries(ImGui PUBLIC SDL2::SDL2) + +find_package(GLEW REQUIRED) +target_link_libraries(ImGui PUBLIC ${OPENGL_opengl_LIBRARY} GLEW::GLEW) +set_target_properties(ImGui PROPERTIES + XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES +) diff --git a/libultraship/cmake/dependencies/openbsd.cmake b/libultraship/cmake/dependencies/openbsd.cmake new file mode 100644 index 000000000..585f4bb0b --- /dev/null +++ b/libultraship/cmake/dependencies/openbsd.cmake @@ -0,0 +1,20 @@ +#=================== ImGui =================== + +find_package(SDL2 REQUIRED) + +# XXX sdl2-config.cmake doesn't include /usr/X11R6/include but sdl2-config does +# ideally this could be fixed from sdl2 port +# set(SDL2_INCLUDE_DIRS "${SDL2_INCLUDE_DIRS};/usr/X11R6/include") +# note this is a central place to bundle such hacks for libultraship consumers +# otherwise each game may need its own fix as we are not in the same scope +include_directories("/usr/X11R6/include") + +target_link_libraries(ImGui PUBLIC SDL2::SDL2) + +if (USE_OPENGLES) + # XXX copy linux.cmake but maybe this actually need gles3_LIBRARY + target_link_libraries(ImGui PUBLIC ${OPENGL_gles2_LIBRARY}) + add_compile_definitions(IMGUI_IMPL_OPENGL_ES3) +else() + target_link_libraries(ImGui PUBLIC ${OPENGL_gl_LIBRARY}) +endif() diff --git a/libultraship/cmake/dependencies/patches/imgui-fixes-and-config.patch b/libultraship/cmake/dependencies/patches/imgui-fixes-and-config.patch new file mode 100644 index 000000000..6d890e900 --- /dev/null +++ b/libultraship/cmake/dependencies/patches/imgui-fixes-and-config.patch @@ -0,0 +1,112 @@ +From 28c317c55769110b4f83003aa9e868f66157b3fe Mon Sep 17 00:00:00 2001 +From: briaguya <70942617+briaguya-ai@users.noreply.github.com> +Date: Sat, 17 May 2025 04:41:55 -0400 +Subject: [PATCH 1/3] Revert "Backends: Metal: Fixed memory leaks. (#8276, + #8166)" + +This reverts commit e6a7c7689f57038b2519fe43e55e3d57103ad0f7. +--- + backends/imgui_impl_metal.mm | 8 -------- + docs/CHANGELOG.txt | 1 - + 2 files changed, 9 deletions(-) + +diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm +index 9ab4a342adfd..388c4f3984e1 100644 +--- a/backends/imgui_impl_metal.mm ++++ b/backends/imgui_impl_metal.mm +@@ -18,7 +18,6 @@ + // (minor and older changes stripped away, please see git history for details) + // 2025-XX-XX: Metal: Added support for multiple windows via the ImGuiPlatformIO interface. + // 2025-02-03: Metal: Crash fix. (#8367) +-// 2025-01-08: Metal: Fixed memory leaks when using metal-cpp (#8276, #8166) or when using multiple contexts (#7419). + // 2022-08-23: Metal: Update deprecated property 'sampleCount'->'rasterSampleCount'. + // 2022-07-05: Metal: Add dispatch synchronization. + // 2022-06-30: Metal: Use __bridge for ARC based systems. +@@ -171,11 +170,7 @@ void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor) + { + ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); + IM_ASSERT(bd != nil && "Context or backend not initialized! Did you call ImGui_ImplMetal_Init()?"); +-#ifdef IMGUI_IMPL_METAL_CPP +- bd->SharedMetalContext.framebufferDescriptor = [[[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor]autorelease]; +-#else + bd->SharedMetalContext.framebufferDescriptor = [[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor]; +-#endif + if (bd->SharedMetalContext.depthStencilState == nil) + ImGui_ImplMetal_CreateDeviceObjects(bd->SharedMetalContext.device); + } +@@ -383,9 +378,6 @@ bool ImGui_ImplMetal_CreateDeviceObjects(id device) + depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways; + bd->SharedMetalContext.depthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDescriptor]; + ImGui_ImplMetal_CreateDeviceObjectsForPlatformWindows(); +-#ifdef IMGUI_IMPL_METAL_CPP +- [depthStencilDescriptor release]; +-#endif + ImGui_ImplMetal_CreateFontsTexture(device); + return true; + } +diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt +index 6c4f19cfef02..e4a4cbf98ef6 100644 +--- a/docs/CHANGELOG.txt ++++ b/docs/CHANGELOG.txt +@@ -355,7 +355,6 @@ Other changes: + though it is currently not doing anything particular. (#8163, #7998, #7988) + - Backends: Allegro5: Avoid calling al_set_mouse_cursor() repeatedly since it appears + to leak on on X11 (#8256). [@Helodity] +-- Backends: Metal: Fixed leaks when using metal-cpp. (#8276, #8166) [@selimsandal] + - Backends: Metal: Fixed resource leak when using multiple contexts. (#7419) [@anszom] + - Backends: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for + platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) [@Zer0xFF] + +From 56f5907cf5224e1a2f64289029cc2b46e51d3b6c Mon Sep 17 00:00:00 2001 +From: briaguya <70942617+briaguya-ai@users.noreply.github.com> +Date: Sat, 17 May 2025 04:42:41 -0400 +Subject: [PATCH 2/3] gamepad fix + +--- + backends/imgui_impl_sdl2.cpp | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp +index f3a31c5c3c5e..2e6a1ad9d1f1 100644 +--- a/backends/imgui_impl_sdl2.cpp ++++ b/backends/imgui_impl_sdl2.cpp +@@ -845,9 +845,6 @@ static void ImGui_ImplSDL2_UpdateGamepads() + bd->WantUpdateGamepadsList = false; + } + +- // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. +- if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) +- return; + io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; + if (bd->Gamepads.Size == 0) + return; + +From 90c4297624a0fe993f1ac0e538bccdc80a0fc5f2 Mon Sep 17 00:00:00 2001 +From: briaguya <70942617+briaguya-ai@users.noreply.github.com> +Date: Sat, 17 May 2025 04:42:56 -0400 +Subject: [PATCH 3/3] config + +--- + imconfig.h | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/imconfig.h b/imconfig.h +index a1e29e849bc8..ee64116ff0cf 100644 +--- a/imconfig.h ++++ b/imconfig.h +@@ -110,7 +110,7 @@ + operator MyVec4() const { return MyVec4(x,y,z,w); } + */ + //---- ...Or use Dear ImGui's own very basic math operators. +-//#define IMGUI_DEFINE_MATH_OPERATORS ++#define IMGUI_DEFINE_MATH_OPERATORS + + //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. + // Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices). +@@ -139,3 +139,6 @@ namespace ImGui + void MyFunction(const char* name, MyMatrix44* mtx); + } + */ ++ ++// handle https://github.com/ocornut/imgui/issues/1641 the old way ++#define ImTextureID void* diff --git a/libultraship/cmake/dependencies/patches/stormlib-optimizations.patch b/libultraship/cmake/dependencies/patches/stormlib-optimizations.patch new file mode 100644 index 000000000..1e70cdf10 --- /dev/null +++ b/libultraship/cmake/dependencies/patches/stormlib-optimizations.patch @@ -0,0 +1,123 @@ +From ff338b230544f8b2bb68d2fbe075175ed2fd758c Mon Sep 17 00:00:00 2001 +From: briaguya <70942617+briaguya-ai@users.noreply.github.com> +Date: Wed, 8 May 2024 02:44:49 -0400 +Subject: [PATCH] bring back optimizations + +Co-authored-by: GaryOderNichts <12049776+GaryOderNichts@users.noreply.github.com> +--- + src/SBaseCommon.cpp | 6 +++++- + src/SFileCreateArchive.cpp | 2 ++ + src/SFileListFile.cpp | 35 ++++++++++++++++++----------------- + src/StormLib.h | 3 +++ + 4 files changed, 28 insertions(+), 18 deletions(-) + +diff --git a/src/SBaseCommon.cpp b/src/SBaseCommon.cpp +index 77590d6..6fed00e 100644 +--- a/src/SBaseCommon.cpp ++++ b/src/SBaseCommon.cpp +@@ -884,8 +884,10 @@ ULONGLONG FindFreeMpqSpace(TMPQArchive * ha) + ULONGLONG FreeSpacePos = ha->pHeader->dwHeaderSize; + DWORD dwChunkCount; + ++ TFileEntry* startEntry = (ha->useFreeSpaceOptimization && ha->lastFreeSpaceEntry != nullptr) ? ha->lastFreeSpaceEntry : ha->pFileTable; ++ + // Parse the entire block table +- for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) ++ for(pFileEntry = startEntry; pFileEntry < pFileTableEnd; pFileEntry++) + { + // Only take existing files with nonzero size + if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) && (pFileEntry->dwCmpSize != 0)) +@@ -906,6 +908,8 @@ ULONGLONG FindFreeMpqSpace(TMPQArchive * ha) + dwChunkCount = ((pFileEntry->dwCmpSize - 1) / pHeader->dwRawChunkSize) + 1; + FreeSpacePos += dwChunkCount * MD5_DIGEST_SIZE; + } ++ ++ ha->lastFreeSpaceEntry = pFileEntry; + } + } + } +diff --git a/src/SFileCreateArchive.cpp b/src/SFileCreateArchive.cpp +index c0ea367..d392a83 100644 +--- a/src/SFileCreateArchive.cpp ++++ b/src/SFileCreateArchive.cpp +@@ -224,6 +224,8 @@ bool WINAPI SFileCreateArchive2(const TCHAR * szMpqName, PSFILE_CREATE_MPQ pCrea + ha->dwFileFlags3 = pCreateInfo->dwFileFlags3 ? MPQ_FILE_EXISTS : 0; + ha->dwAttrFlags = pCreateInfo->dwAttrFlags; + ha->dwFlags = dwMpqFlags | MPQ_FLAG_CHANGED; ++ ha->useFreeSpaceOptimization = true; ++ ha->lastFreeSpaceEntry = nullptr; + pStream = NULL; + + // Fill the MPQ header +diff --git a/src/SFileListFile.cpp b/src/SFileListFile.cpp +index b2a3a3c..d0c3c67 100644 +--- a/src/SFileListFile.cpp ++++ b/src/SFileListFile.cpp +@@ -409,6 +409,7 @@ static LPBYTE CreateListFile(TMPQArchive * ha, DWORD * pcbListFile) + static DWORD SListFileCreateNodeForAllLocales(TMPQArchive * ha, const char * szFileName) + { + TFileEntry * pFileEntry; ++ TMPQHash * pFirstHash; + TMPQHash * pHashEnd; + TMPQHash * pHash; + DWORD dwName1; +@@ -443,25 +444,25 @@ static DWORD SListFileCreateNodeForAllLocales(TMPQArchive * ha, const char * szF + pHashEnd = ha->pHashTable + (ha->dwRealHashTableSize / sizeof(TMPQHash)); + + // Go through the hash table and put the name in each item that has the same name pair +- for(pHash = ha->pHashTable; pHash < pHashEnd; pHash++) +- { +- if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize) +- { +- // Allocate file name for the file entry +- AllocateFileName(ha, ha->pFileTable + MPQ_BLOCK_INDEX(pHash), szFileName); +- } +- } ++ // for(pHash = ha->pHashTable; pHash < pHashEnd; pHash++) ++ // { ++ // if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize) ++ // { ++ // // Allocate file name for the file entry ++ // AllocateFileName(ha, ha->pFileTable + MPQ_BLOCK_INDEX(pHash), szFileName); ++ // } ++ // } + + // Go while we found something +- //pFirstHash = pHash = GetFirstHashEntry(ha, szFileName); +- //while(pHash != NULL) +- //{ +- // // Allocate file name for the file entry +- // AllocateFileName(ha, ha->pFileTable + MPQ_BLOCK_INDEX(pHash), szFileName); +- +- // // Now find the next language version of the file +- // pHash = GetNextHashEntry(ha, pFirstHash, pHash); +- //} ++ pFirstHash = pHash = GetFirstHashEntry(ha, szFileName); ++ while(pHash != NULL) ++ { ++ // Allocate file name for the file entry ++ AllocateFileName(ha, ha->pFileTable + MPQ_BLOCK_INDEX(pHash), szFileName); ++ ++ // Now find the next language version of the file ++ pHash = GetNextHashEntry(ha, pFirstHash, pHash); ++ } + + return ERROR_SUCCESS; + } +diff --git a/src/StormLib.h b/src/StormLib.h +index 4aa51c1..bda11d3 100644 +--- a/src/StormLib.h ++++ b/src/StormLib.h +@@ -860,6 +860,9 @@ typedef struct _TMPQArchive + ULONGLONG CompactBytesProcessed; // Amount of bytes that have been processed during a particular compact call + ULONGLONG CompactTotalBytes; // Total amount of bytes to be compacted + void * pvCompactUserData; // User data thats passed to the callback ++ ++ TFileEntry* lastFreeSpaceEntry; ++ bool useFreeSpaceOptimization; + } TMPQArchive; + + // File handle structure +-- +2.43.0 + diff --git a/libultraship/cmake/dependencies/windows-vcpkg.cmake b/libultraship/cmake/dependencies/windows-vcpkg.cmake new file mode 100644 index 000000000..4f6465bc0 --- /dev/null +++ b/libultraship/cmake/dependencies/windows-vcpkg.cmake @@ -0,0 +1,17 @@ +if (USE_AUTO_VCPKG) + include(cmake/automate-vcpkg.cmake) + +if ("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32") + set(VCPKG_TRIPLET x86-windows-static) + set(VCPKG_TARGET_TRIPLET x86-windows-static) +elseif ("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64") + set(VCPKG_TRIPLET x64-windows-static) + set(VCPKG_TARGET_TRIPLET x64-windows-static) +elseif ("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "arm64") + set(VCPKG_TRIPLET arm64-windows-static) + set(VCPKG_TARGET_TRIPLET arm64-windows-static) +endif() + + vcpkg_bootstrap() + vcpkg_install_packages(zlib bzip2 sdl2 glew libzip nlohmann-json tinyxml2 spdlog) +endif() diff --git a/libultraship/cmake/dependencies/windows.cmake b/libultraship/cmake/dependencies/windows.cmake new file mode 100644 index 000000000..6b3b7b237 --- /dev/null +++ b/libultraship/cmake/dependencies/windows.cmake @@ -0,0 +1,12 @@ +#=================== ImGui =================== +target_sources(ImGui + PRIVATE + ${imgui_SOURCE_DIR}/backends/imgui_impl_dx11.cpp + ${imgui_SOURCE_DIR}/backends/imgui_impl_win32.cpp +) + +find_package(SDL2 CONFIG REQUIRED) +target_link_libraries(ImGui PUBLIC SDL2::SDL2 SDL2::SDL2main) + +find_package(GLEW REQUIRED) +target_link_libraries(ImGui PUBLIC opengl32 GLEW::GLEW) diff --git a/libultraship/cmake/ios-toolchain-populate.cmake b/libultraship/cmake/ios-toolchain-populate.cmake new file mode 100644 index 000000000..eb93fea4d --- /dev/null +++ b/libultraship/cmake/ios-toolchain-populate.cmake @@ -0,0 +1,15 @@ +set(PLATFORM "OS64COMBINED") +include(FetchContent) +FetchContent_Declare(iostoolchain + GIT_REPOSITORY https://github.com/leetal/ios-cmake + GIT_TAG 06465b27698424cf4a04a5ca4904d50a3c966c45 + CONFIGURE_COMMAND "" + BUILD_COMMAND "" +) +FetchContent_GetProperties(iostoolchain) +if(NOT iostoolchain_POPULATED) + FetchContent_Populate(iostoolchain) +endif() +set(CMAKE_IOS_TOOLCHAIN_FILE ${iostoolchain_SOURCE_DIR}/ios.toolchain.cmake) +set_property(GLOBAL PROPERTY IOS_TOOLCHAIN_FILE ${CMAKE_IOS_TOOLCHAIN_FILE}) +include(${CMAKE_IOS_TOOLCHAIN_FILE}) \ No newline at end of file diff --git a/libultraship/docs/PORTING.md b/libultraship/docs/PORTING.md new file mode 100644 index 000000000..7992c7a8b --- /dev/null +++ b/libultraship/docs/PORTING.md @@ -0,0 +1,124 @@ +# Libultraship (LUS) Porting Guide + +**Libultraship (LUS)** is a library designed to facilitate PC ports of Nintendo 64 games. It is not a recompilation tool; rather, it allows developers to build a game's original source code (derived from decompilation) on modern hardware by providing a header-compatible wrapper around modern reimplementations of N64 SDK functions. + +In essence, LUS acts as **"compile-time WINE"** for the N64. + +--- + +## Supported Platforms + +LUS supports the following platforms and rendering backends: + +| Platform | Rendering Backends | +| :--- | :--- | +| **Windows** | OpenGL, Direct3D 11 | +| **macOS** | OpenGL, Metal | +| **Linux** | OpenGL | +| **iOS** | OpenGL, Metal | +| **Android** | OpenGL ES | +| **OpenBSD** | OpenGL | + +--- + +## Prerequisites + +1. **A Game Decompilation:** You must have the source code of the game (e.g., *Star Fox 64*, *Banjo-Kazooie*) ready to build. +2. **Template Project:** Use [**Ghostship**](https://github.com/HarbourMasters/Ghostship) as your reference. This is the standard example project used by existing ports to handle CMake configurations and asset management. Ghostship is a separate repository and is not included in this one. + +--- + +## The Porting Process + +### Phase 1: The "Stub" Build +The initial goal is not a playable game, but simply a functional executable that links against LUS. + +1. **Setup:** + * Copy the CMake files from the [**Ghostship**](https://github.com/HarbourMasters/Ghostship) template into your decompilation directory. + * Ensure `libultraship` is added as a submodule. + +2. **Header Replacement:** + * Replace N64 SDK includes (e.g., `#include `) in the source code with LUS includes: + ```c + #include + ``` + * Use the public include path shown above unless you have explicitly configured your project's include directories to support a different form. + +3. **Compile & Fix:** + * Attempt to build. You will encounter thousands of errors. + * **Stubbing:** Comment out or stub functions that LUS handles automatically (e.g., `osCreateThread` for rumble, as LUS manages threads differently than the N64 CPU). + * **Disable Systems:** Temporarily disable complex systems like Audio to simplify the build. + * **64-bit Fixes:** Address pointer size differences and other architecture-specific issues. + * **Iterate:** Rinse and repeat until you successfully generate an executable (`.exe` or binary). + +### Phase 2: Runtime & Logic +Once the executable exists, the game will likely crash immediately or behave erratically. + +1. **Debugging:** Use breakpoints to trace the logic and fix crashes as they arise. +2. **Microcode (UCode):** Verify the game's graphics microcode. + * LUS supports the following GBI microcode variants via the `GBI_UCODE` CMake option: `F3DEX_GBI_2` (default), `F3DEX_GBI`, and `F3DLP_GBI`. Set this to match your game's microcode. + * Custom UCodes (e.g., specific Rareware implementations) may need manual implementation or adjustments in the renderer. + +### Phase 3: Assets (The Fork in the Road) +You have two options for handling game assets (textures, models, etc.): + +#### Option A: OTR/O2R (The "Torch" Method) *Recommended* +* **Description:** Convert assets to the archive format used by LUS. +* **Archive Formats:** + * **O2R** (`.o2r`): ZIP-based archive format, the modern default. No additional CMake options needed. + * **OTR** (`.otr`): MPQ-based archive format (legacy). Requires enabling `INCLUDE_MPQ_SUPPORT` in CMake. + * **Folder Archive**: For development, assets can be loaded directly from a folder without packaging. +* **Tools:** Use [**Torch**](https://github.com/HarbourMasters/Torch), an external tool designed to swap C files to path references and regenerate headers automatically. Torch is not included in this repository. +* **Pros:** Significantly faster workflow (e.g., enabled a *Star Fox 64* mini-build in one day). +* **Process:** Write exporters for Torch and importers for LUS to handle the specific game's asset types. + +#### Option B: The Simple Method +* **Description:** Use the raw assets without OTR/O2R conversion. +* **Requirements:** You must manually "massage" the assets to handle endianness (byte order) and bit-width differences between N64 and PC. +* **Note:** It is a myth that OTR/O2R is required immediately. You can start testing a port without it, though it may be "illegal" or messy depending on the context. + +### Phase 4: Audio +Audio is generally the last step. It requires significant effort to hook into LUS's audio system once the rest of the game is stable. + +LUS only exposes PC audio drivers — it does not interface with N64 audio. The available audio backends are: +* **SDL** — cross-platform (Linux, Windows, macOS, etc.) +* **CoreAudio** — macOS / iOS +* **WASAPI** — Windows +* **Null** — silent backend for testing + +Your port is responsible for implementing the game's audio pipeline and routing its output through one of these drivers. + +--- + +## Build Configuration Options + +Key CMake options that porters should be aware of: + +| Option | Default | Description | +| :--- | :--- | :--- | +| `GBI_UCODE` | `F3DEX_GBI_2` | Graphics microcode variant (`F3DEX_GBI_2`, `F3DEX_GBI`, `F3DLP_GBI`) | +| `INCLUDE_MPQ_SUPPORT` | `OFF` | Enable OTR/MPQ archive support (via StormLib) | +| `NON_PORTABLE` | `OFF` | Build a non-portable version | +| `DISABLE_DLL_LOADER` | `OFF` | Disable dynamic library/script loading | +| `LUS_BUILD_TESTS` | `OFF` | Build unit tests | + +--- + +## LUS Architecture + +### Bridge Pattern + +LUS uses a "bridge" pattern to connect N64 SDK function calls to modern implementations. Bridge modules exist for audio, graphics, controllers, resources, events, scripting, console variables, crash handling, and window management. When porting, you interact with these bridges through the standard N64 SDK API — LUS routes calls to the appropriate modern backend automatically. + +The bridge implementations live in `src/libultraship/bridge/`. + +### Directory Structure + +Understanding the LUS codebase is helpful for debugging and contribution: + +| Directory | Description | +| :--- | :--- | +| **`src/libultraship/`** | Contains N64-specific code including the libultra reimplementation (`libultra/`), bridge layers to modern backends (`bridge/`), controller support, window management, and logging. | +| **`src/ship/`** | Platform-agnostic code: resource/archive management, audio backends (SDL, CoreAudio, WASAPI), controller abstractions, configuration, scripting/DLL loading, security/keystore, and utility functions. | +| **`src/fast/`** | The Fast3D Renderer. Interprets N64 display lists as commands for modern GPUs. Supports OpenGL, Direct3D 11, and Metal backends. | +| **`include/`** | Public headers mirroring the `src/` structure. The main entry point is `libultraship/libultraship.h`. | \ No newline at end of file diff --git a/libultraship/docs/SCRIPTING.md b/libultraship/docs/SCRIPTING.md new file mode 100644 index 000000000..f13fdd149 --- /dev/null +++ b/libultraship/docs/SCRIPTING.md @@ -0,0 +1,447 @@ +# Scripting System + +This document covers the C-based mod scripting system — how archives are structured, how the manifest is parsed, how signing and integrity verification work, and how to write a mod using the event system. + +--- + +## Table of Contents + +1. [Overview](#overview) +2. [Archive Format (.o2r)](#archive-format-o2r) +3. [manifest.json Reference](#manifestjson-reference) +4. [Signing and Integrity Verification](#signing-and-integrity-verification) + - [How Verification Works](#how-verification-works) + - [Generating a Key Pair](#generating-a-key-pair) + - [Signing an Archive](#signing-an-archive) + - [Trust Levels](#trust-levels) +5. [Writing a C Mod](#writing-a-c-mod) + - [Project Structure](#project-structure) + - [Entry and Exit Points](#entry-and-exit-points) + - [The Build Pipeline (Amalgamation)](#the-build-pipeline-amalgamation) + - [build.gen](#buildgen) +6. [C API Reference](#c-api-reference) + - [mod.h Macros](#modh-macros) + - [Memory Allocation](#memory-allocation) + - [Calling Functions from Other Mods](#calling-functions-from-other-mods) +7. [Event System](#event-system) + - [Defining Events](#defining-events) + - [Registering and Unregistering Listeners](#registering-and-unregistering-listeners) + - [Event Priority](#event-priority) + - [Cancellable Events](#cancellable-events) +8. [Dependencies Between Mods](#dependencies-between-mods) +9. [Pre-compiled Binaries](#pre-compiled-binaries) + +--- + +## Overview + +Mods are packaged as `.o2r` files, which are standard ZIP archives containing game assets, a `manifest.json` metadata file, and optionally C source files or pre-compiled shared libraries. When the engine loads a mod, the scripting system JIT-compiles the C sources using [TCC (Tiny C Compiler)](https://bellard.org/tcc/) or loads the pre-built binary for the current platform, then calls the mod's `ModInit` entry point. + +--- + +## Archive Format (.o2r) + +An `.o2r` file is a ZIP archive. Plain `.zip` files are also accepted. The internal layout is: + +``` +my-mod.o2r +├── manifest.json # Required: mod metadata +├── build.gen # Optional: list of C source files to JIT-compile +├── dist/ +│ └── mod.c # Amalgamated C source (referenced by build.gen) +├── binaries/ +│ ├── linux_x64.so # Optional pre-compiled binaries per platform +│ ├── windows_x64.dll +│ └── darwin.dylib +└── # Any other resource files the mod needs +``` + +`manifest.json` and `build.gen` are the only files the loader looks for by name. Everything else is up to the mod author. + +--- + +## manifest.json Reference + +The `manifest.json` file lives at the root of the archive. All fields are optional except `name`. + +```json +{ + "name": "My Mod", + "version": "1.0.0", + "author": "Your Name", + "description": "A short description of what this mod does.", + "website": "https://example.com", + "license": "MIT", + "icon": "icon.png", + "code_version": 1, + "game_version": 4294967295, + "main": "build.gen", + "binaries": { + "linux_x64": "binaries/linux_x64.so", + "windows_x64": "binaries/windows_x64.dll", + "darwin": "binaries/darwin.dylib" + }, + "dependencies": ["other-mod-name"], + "checksum": "", + "signature": "", + "public_key": "" +} +``` + +### Fields + +| Field | Type | Default | Description | +|---|---|---|---| +| `name` | string | **required** | Display name of the mod. | +| `version` | string | `"1.0"` | Mod version string. | +| `author` | string | `"Unknown"` | Author name. Used in keystore trust prompts. | +| `description` | string | `"No description provided."` | Short human-readable description. | +| `website` | string | `""` | Homepage or repository URL. | +| `license` | string | `"All rights reserved"` | License identifier (e.g. `"MIT"`, `"GPL-3.0"`). | +| `icon` | string | `""` | Path inside the archive to an icon image. | +| `code_version` | integer | `1` | Must match the engine's compiled code version. Mismatches prevent loading. | +| `game_version` | integer | `0xFFFFFFFF` | Required game version. `0xFFFFFFFF` means any version is accepted. | +| `main` | string | `""` | Path to the `build.gen` file listing C sources to JIT-compile. | +| `binaries` | object | `{}` | Map of platform key → path to a pre-compiled shared library inside the archive. See [Pre-compiled Binaries](#pre-compiled-binaries) for platform keys. | +| `dependencies` | array of strings | `[]` | Names of other mods this mod depends on. They will be initialized before this mod. | +| `checksum` | string | `""` | BLAKE2b-512 hex digest injected by `tools/sign.py`. Do not set manually. | +| `signature` | string | `""` | Ed25519 hex signature injected by `tools/sign.py`. Do not set manually. | +| `public_key` | string | `""` | Author's Ed25519 raw public key (hex) injected by `tools/sign.py`. Do not set manually. | + +> **Note on `code_version`:** The engine enforces that `code_version` in the manifest matches the version it was compiled against. If they differ, the mod will not be loaded. Increment this value when your mod's compiled interface changes. + +--- + +## Signing and Integrity Verification + +### How Verification Works + +Archive validation is performed in `Archive::Validate()` and proceeds in two stages: + +**1. Checksum verification** + +A BLAKE2b-512 digest is computed over all non-manifest files in the archive, processed in sorted path order. Both the file path and the file contents are fed into the hash. The result is compared against the `checksum` field in `manifest.json`. If they do not match, the archive is rejected. + +**2. Signature verification** + +The raw BLAKE2b digest bytes are verified against the Ed25519 `signature` using the `public_key` from the manifest. The engine checks the public key against its internal **Keystore** (a set of trusted Ed25519 public keys). If the key is not already trusted: + +- If an `UntrustedArchiveHandler` callback is registered by the host application, the user is prompted to trust the key. On approval, the key is added to the keystore for future sessions. +- If no handler is registered, the archive is rejected. + +System keys (hard-coded trusted publisher keys bundled with the engine) are always accepted without a prompt. + +An archive that has no `checksum` field is treated as unsigned. It can still be loaded depending on the configured [Trust Level](#trust-levels), but `IsSigned()` and `IsChecksumValid()` will both return `false`. + +### Generating a Key Pair + +Use `tools/generate_keys.py` to create an Ed25519 key pair: + +```sh +# Install the dependency first +pip install cryptography + +# Generate keys (no passphrase) +python tools/generate_keys.py + +# The script writes: +# private_key.pem — keep this secret +# public_key.pem — can be distributed +``` + +To protect the private key with a passphrase, edit the script and pass a password string to `generate_keypair(password="your-passphrase")`. + +### Signing an Archive + +Use `tools/sign.py` to sign a built `.o2r` / `.zip`: + +```sh +# Sign without passphrase +python tools/sign.py my-mod.o2r private_key.pem + +# Sign with passphrase +python tools/sign.py my-mod.o2r private_key.pem +``` + +The script: +1. Computes a BLAKE2b-512 checksum over all non-manifest files (sorted by path). +2. Signs the raw checksum bytes with the Ed25519 private key. +3. Injects `checksum`, `signature`, and `public_key` (all hex-encoded) into `manifest.json` inside the zip in-place. + +You must re-sign the archive any time you change its contents. + +### Trust Levels + +The engine exposes a `SafeLevel` setting that controls how unsigned or untrusted archives are handled: + +| Level | Behavior | +|---|---| +| `DISABLE_SCRIPTS` | No scripts are loaded at all. | +| `ONLY_TRUSTED_SCRIPTS` | Only archives with a valid checksum **and** a known-trusted signature are loaded. Unsigned archives are rejected. | +| `WARN_UNTRUSTED_SCRIPTS` | *(default)* Unsigned archives log a warning but still load. | +| `ALLOW_ALL_SCRIPTS` | All archives load silently regardless of signing status. | + +--- + +## Writing a C Mod + +### Project Structure + +The recommended layout for a mod project: + +``` +my-mod/ +├── include/ +│ └── mod.h # Core macros (MOD_INIT, MOD_EXIT, HM_API) +├── src/ +│ └── main.c # Your mod logic +├── manifest.json # Mod metadata +└── CMakeLists.txt # Build configuration (amalgamation pipeline) +``` + +After building, the output goes to: + +``` +output/ +├── dist/ +│ └── main.c # Amalgamated single-file output +├── build.gen # Auto-generated list of output paths +└── manifest.json # Your manifest (copied here for packaging) +``` + +Package the contents of `output/` into a zip and rename it to `.o2r`. + +### Entry and Exit Points + +Every mod must export two functions. Use the macros from `mod.h`: + +```c +#include "mod.h" + +MOD_INIT() { + // Called once when the mod is loaded. + // Register event listeners here. +} + +MOD_EXIT() { + // Called once when the mod is unloaded or the engine shuts down. + // Unregister listeners and free resources here. +} +``` + +`MOD_INIT` expands to `HM_API void ModInit` and `MOD_EXIT` to `HM_API void ModExit`. `HM_API` resolves to `__declspec(dllexport)` on Windows and `__attribute__((visibility("default")))` on other platforms, ensuring the dynamic linker can find the symbols. + +### The Build Pipeline (Amalgamation) + +Because mods are JIT-compiled by TCC at runtime, they must be packaged as self-contained C translation units — no separate object files or link steps are available at runtime. + +The build system runs `tools/merge.py` on each `.c` file in `src/`. `merge.py` recursively inlines all `#include` directives that resolve to local header files, producing a single amalgamated `.c` file per source file in `output/dist/`. System headers (``, etc.) are left as-is. + +**Important:** Because all source files ultimately share a single global namespace when loaded, any helper function that should not be visible outside your file must be declared `static`. Failing to do so risks symbol collisions with the engine or other mods. + +### build.gen + +`build.gen` is a plain text file listing the paths to amalgamated `.c` files to compile, one per line: + +``` +dist/main.c +dist/utils.c +``` + +Paths are relative to the root of the archive. The `main` field in `manifest.json` points to this file. + +--- + +## C API Reference + +### mod.h Macros + +| Macro / Symbol | Expands To | Description | +|---|---|---| +| `HM_API` | `__declspec(dllexport)` / `__attribute__((visibility("default")))` | Marks a symbol as exported from the shared library. | +| `MOD_INIT()` | `HM_API void ModInit` | Declares the mod initialization entry point. | +| `MOD_EXIT()` | `HM_API void ModExit` | Declares the mod shutdown entry point. | +| `CALL_FUNC(mod, func, ...)` | `((func##Func)ScriptGetFunction(mod, func##Symbol))(...)` | Calls an exported function from another loaded mod by name. | +| `malloc(size)` | `GameEngine_Malloc(size)` | Routes heap allocation through the engine allocator. | +| `free(ptr)` | `GameEngine_Free(ptr)` | Routes heap deallocation through the engine allocator. | + +> **Note:** `malloc` and `free` are redefined by `mod.h` to use engine-managed allocators. Do not include `` after including `mod.h`, or the redefinition will conflict. + +### Memory Allocation + +Always use `malloc`/`free` as provided by `mod.h`. These route through `GameEngine_Malloc` and `GameEngine_Free`, ensuring allocations are tracked by the engine and freed correctly when the mod is unloaded. + +### Calling Functions from Other Mods + +To call an exported function from another mod or from the engine's scripting bridge, use `ScriptGetFunction`: + +```c +// Prototype of the function you want to call +typedef void (*MyFuncType)(int value); + +// Look up the function from module "other-mod" +MyFuncType fn = (MyFuncType)ScriptGetFunction("other-mod", "MyExportedFunction"); +if (fn != NULL) { + fn(42); +} +``` + +Or use the `CALL_FUNC` macro if you define the function type and symbol name with the expected naming convention. + +--- + +## Event System + +The event system lets mods hook into points in the engine and game loop without modifying source code. Events are identified by a global `EventID` that is registered at startup and dispatched via `EventSystemCallEvent`. + +### Defining Events + +Events are defined using the `DEFINE_EVENT` macro from `include/ship/events/EventTypes.h`. This generates a struct type and declares its global `EventID`: + +```c +// An event with no extra data +DEFINE_EVENT(MySimpleEvent); + +// An event that carries additional fields +DEFINE_EVENT(MyDataEvent, + int someValue; + float otherValue; +); +``` + +The first member of every generated struct is always `IEvent Event`, which holds the `Cancelled` flag. When dispatching, use the corresponding `CALL_EVENT` or `CALL_CANCELLABLE_EVENT` macros: + +```c +// Fire a simple event +CALL_EVENT(MySimpleEvent); + +// Fire a data event +CALL_EVENT(MyDataEvent, .someValue = 42, .otherValue = 3.14f); + +// Fire a cancellable event — code after the macro only runs if not cancelled +CALL_CANCELLABLE_EVENT(MyDataEvent, .someValue = 1, .otherValue = 0.0f) { + // only reached if no listener cancelled the event +} +``` + +Events must be registered once at engine startup using `REGISTER_EVENT` before they can be dispatched or listened to: + +```c +REGISTER_EVENT(MySimpleEvent); +REGISTER_EVENT(MyDataEvent); +``` + +### Registering and Unregistering Listeners + +```c +#include "mod.h" +// Include the header that declares the events you want to listen to +#include "your/events/header.h" + +ListenerID gMyListenerID; + +void OnMyEvent(IEvent* event) { + // Cast to the concrete event type to access its fields + MyDataEvent* e = (MyDataEvent*)event; + // ... +} + +MOD_INIT() { + gMyListenerID = REGISTER_LISTENER(MyDataEvent, EVENT_PRIORITY_NORMAL, OnMyEvent); +} + +MOD_EXIT() { + UNREGISTER_LISTENER(MyDataEvent, gMyListenerID); +} +``` + +Always store the returned `ListenerID` globally so you can unregister in `MOD_EXIT`. Failing to unregister will cause a use-after-free when the mod is unloaded. + +**Macros:** + +| Macro | Description | +|---|---| +| `REGISTER_LISTENER(eventType, priority, callback)` | Registers `callback` for `eventType` at `priority`. Returns a `ListenerID`. | +| `UNREGISTER_LISTENER(eventType, listenerID)` | Removes the listener identified by `listenerID` from `eventType`. | + +### Event Priority + +Listeners for the same event are called in descending priority order. + +| Priority | Description | +|---|---| +| `EVENT_PRIORITY_LOW` | Called after normal-priority listeners. | +| `EVENT_PRIORITY_NORMAL` | Default priority for most use cases. | +| `EVENT_PRIORITY_HIGH` | Called before normal-priority listeners. | + +### Cancellable Events + +Events fired with `CALL_CANCELLABLE_EVENT` or `CALL_CANCELLABLE_RETURN_EVENT` can be cancelled by any listener. To cancel, set `Cancelled` on the base `IEvent`: + +```c +void OnMyEvent(IEvent* event) { + MyDataEvent* e = (MyDataEvent*)event; + if (/* some condition */) { + e->Event.Cancelled = true; + } +} +``` + +Once cancelled: +- Remaining lower-priority listeners still receive the event but can check `event->Cancelled`. +- The engine code block gated by `CALL_CANCELLABLE_EVENT` is skipped. +- `CALL_CANCELLABLE_RETURN_EVENT` causes an immediate `return` in the calling function. + +--- + +## Dependencies Between Mods + +List the `name` values of mods your mod requires in the `dependencies` array: + +```json +{ + "name": "my-mod", + "dependencies": ["base-library-mod"] +} +``` + +The scripting system performs a topological sort (Kahn's algorithm) across all loaded mods before calling `ModInit`, ensuring dependencies are always initialized first and uninitialized last. + +Circular dependencies are detected and will prevent loading. + +--- + +## Pre-compiled Binaries + +If you want to ship a pre-compiled shared library instead of (or in addition to) C sources, populate the `binaries` map with platform keys pointing to paths inside the archive: + +```json +{ + "binaries": { + "linux_x64": "binaries/linux_x64.so", + "linux_arm64": "binaries/linux_arm64.so", + "windows_x64": "binaries/windows_x64.dll", + "windows_arm64": "binaries/windows_arm64.dll", + "darwin": "binaries/darwin.dylib", + "android": "binaries/android.so", + "ios": "binaries/ios.dylib" + } +} +``` + +The loader checks `binaries` before attempting JIT compilation. If a matching entry is found for the current platform, the pre-built library is extracted to a temporary file and loaded directly. If no match is found and `main` is set, the C sources are JIT-compiled instead. + +### Platform Keys + +| Key | Platform | +|---|---| +| `windows_x64` | Windows, x86-64 | +| `windows_arm64` | Windows, ARM64 | +| `darwin` | macOS (any arch) | +| `linux_x64` | Linux, x86-64 | +| `linux_x86` | Linux, x86 (32-bit) | +| `linux_arm64` | Linux, ARM64 / AArch64 | +| `linux_generic` | Linux, other architectures | +| `android` | Android | +| `ios` | iOS | +| `bsd` | BSD variants | diff --git a/libultraship/include/fast/Fast3dGui.h b/libultraship/include/fast/Fast3dGui.h new file mode 100644 index 000000000..80d02317a --- /dev/null +++ b/libultraship/include/fast/Fast3dGui.h @@ -0,0 +1,177 @@ +#pragma once +#include + +#include "Fast3dWindow.h" +#include "ship/window/gui/Gui.h" +#include "fast/WindowEvent.h" +#include "fast/resource/type/Texture.h" +#include "ship/window/gui/resource/GuiTexture.h" + +// Fixes issue #926: HandleWindowEvents is only ever called from Fast3D backend code +// (gfx_sdl2.cpp, gfx_dxgi.cpp) and must not be a virtual method on Ship::Gui. +// The WindowEvent type has been moved to the Fast namespace so that ship code does +// not depend on any Fast3D or platform-specific types. + +namespace Fast { +class Interpreter; + +/** + * @brief Backend-specific data required to initialise the ImGui rendering context. + * + * The active union member is selected based on the graphics backend: + * - Dx11 for DirectX 11 (Windows). + * - Opengl for OpenGL (Linux/macOS via SDL). + * - Metal for Metal (macOS via SDL). + * - Gx2 for the GX2 API (Wii U / Café OS). + */ +typedef struct { + union { + struct { + void* Window; ///< HWND + void* DeviceContext; ///< ID3D11DeviceContext* + void* Device; ///< ID3D11Device* + } Dx11; + struct { + void* Window; ///< SDL_Window* + void* Context; ///< SDL_GLContext + } Opengl; + struct { + void* Window; ///< SDL_Window* + SDL_Renderer* Renderer; ///< SDL_Renderer* (for Metal layer) + } Metal; + struct { + uint32_t Width; ///< Framebuffer width in pixels. + uint32_t Height; ///< Framebuffer height in pixels. + } Gx2; + }; + WindowBackend Backend; +} GuiWindowInitData; + +/** + * @brief Concrete Gui subclass for the Fast3D rendering backend. + * + * Overrides the virtual ImGui backend methods defined by Ship::Gui with + * implementations that dispatch to the appropriate platform/renderer backend + * (SDL+OpenGL, SDL+Metal, or DXGI+DX11) based on the active WindowBackend. + * + * Also owns the Fast3D-specific rendering resources: texture cache and the + * Interpreter weak reference used for viewport and resolution calculations. + */ +class Fast3dGui : public Ship::Gui { + public: + Fast3dGui(); + Fast3dGui(std::vector> guiWindows); + ~Fast3dGui() override = default; + + bool SupportsViewports() override; + + /** + * @brief Initialises the ImGui context with the given backend-specific handles. + * @param windowImpl Backend-specific handles required by the ImGui backend. + */ + void Init(GuiWindowInitData windowImpl); + + /** + * @brief Forwards a platform window event to the active ImGui backend. + * + * Only Fast3D backends (gfx_sdl2, gfx_dxgi) construct and dispatch WindowEvents. + * Callers retrieve the Gui via Window::GetGui() and dynamic_cast to Fast3dGui. + * @param event Platform event (SDL or Win32) wrapped in a Fast::WindowEvent. + */ + void HandleWindowEvents(Fast::WindowEvent event); + + /** + * @brief Loads an image from an archive path and caches it under the given name. + * @param name Path/texture name used to reference the texture in GetTextureByName(). + * @param path Virtual resource path of the source image. + * @param tint RGBA tint multiplied over the image (use ImVec4(1,1,1,1) for no tint). + */ + void LoadGuiTexture(const std::string& name, const std::string& path, const std::string& palettePath = "", + const ImVec4& tint = ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); + + /** + * @brief Returns true if a texture with the given name is already cached. + * @param name Texture cache key. + */ + bool HasTextureByName(const std::string& name); + + /** + * @brief Uploads a Fast::Texture object to the GPU and caches it under @p name. + * @param name Texture cache key. + * @param tex Source texture data. + * @param tint RGBA tint. + */ + void LoadGuiTexture(const std::string& name, const Fast::Texture& tex, const std::string& palettePath = "", + const ImVec4& tint = ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); + + /** + * @brief Removes the texture with the given name from the cache and frees GPU resources. + * @param name Texture cache key to remove. + */ + void UnloadTexture(const std::string& name); + + /** + * @brief Returns the ImGui texture handle for the given cache key. + * @param name Texture cache key. + * @return ImTextureID suitable for ImGui::Image(), or nullptr if not found. + */ + ImTextureID GetTextureByName(const std::string& name); + + /** + * @brief Returns the pixel dimensions of the cached texture. + * @param name Texture cache key. + * @return ImVec2 with the texture's width and height, or (0, 0) if not found. + */ + ImVec2 GetTextureSize(const std::string& name); + + /** + * @brief Loads a raw image file from the filesystem (not the archive) and caches it. + * @param name Cache key. + * @param path Absolute filesystem path to the image file (e.g. a PNG). + */ + void LoadTextureFromRawImage(const std::string& name, const std::string& path); + + /** + * @brief Uploads a pre-loaded GuiTexture resource to the GPU and caches it. + * @param name Cache key. + * @param texture Loaded GuiTexture resource. + */ + void LoadTextureFromResource(const std::string& name, std::shared_ptr texture); + + void RefreshImGuiGamepads() override; + + protected: + void ImGuiWMInit() override; + void ImGuiWMShutdown() override; + void ImGuiBackendInit() override; + void ImGuiBackendShutdown() override; + void ImGuiBackendNewFrame() override; + void ImGuiWMNewFrame() override; + void ImGuiRenderDrawData(ImDrawData* data) override; + void DrawFloatingWindows() override; + void CalculateGameViewport() override; + void DrawGame() override; + + /** + * @brief Returns the ImTextureID for a texture identified by its integer ID. + * @param id Internal texture registry ID. + * @return ImTextureID for use with ImGui::Image(). + */ + ImTextureID GetTextureById(int32_t id); + + std::weak_ptr mInterpreter; ///< Weak reference to the Fast3D scripting interpreter. + GuiWindowInitData mImpl; ///< Backend-specific window/context handles passed to Init(). + + private: + /** @brief Applies any pending resolution or MSAA changes to the render target. */ + void ApplyResolutionChanges(); + + /** + * @brief Returns the integer scaling factor applied to the game viewport. + * @return Scaling multiplier (1 = native, 2 = 2×, etc.). + */ + int16_t GetIntegerScaleFactor(); + + std::unordered_map mGuiTextures; ///< Cached GPU texture registry. +}; +} // namespace Fast diff --git a/libultraship/include/fast/Fast3dWindow.h b/libultraship/include/fast/Fast3dWindow.h new file mode 100644 index 000000000..7c16ca1f0 --- /dev/null +++ b/libultraship/include/fast/Fast3dWindow.h @@ -0,0 +1,105 @@ +#pragma once +#include "ship/window/Window.h" +#include "ship/window/gui/Gui.h" +#include "ship/controller/controldevice/controller/mapping/keyboard/KeyboardScancodes.h" +#include "FastMouseStateManager.h" +#include "fast/debug/GfxDebugger.h" + +union Gfx; +#include "interpreter.h" + +namespace Fast { + +/** + * @brief Identifies the graphics/windowing backend used by Fast3dWindow. + * + * These are the positive backend IDs registered by Fast3dWindow. + * The general convention for window backend IDs (int32_t) is: + * negative — no Window backend available (e.g. Window is not initialized) + * zero — no Window backend in use + * positive — backend defined by the Window subclass + */ +enum WindowBackend { + FAST3D_DXGI_DX11 = 1, + FAST3D_SDL_OPENGL = 2, + FAST3D_SDL_METAL = 3, +}; + +class Fast3dWindow : public Ship::Window { + public: + Fast3dWindow(); + Fast3dWindow(std::vector> guiWindows); + Fast3dWindow(std::shared_ptr gui); + Fast3dWindow(std::shared_ptr gui, std::shared_ptr mouseStateManager); + ~Fast3dWindow(); + + void Init() override; + void Close() override; + void RunGuiOnly() override; + void StartFrame() override; + void EndFrame() override; + bool IsFrameReady() override; + void HandleEvents() override; + void SetCursorVisibility(bool visible) override; + uint32_t GetWidth() override; + uint32_t GetHeight() override; + int32_t GetPosX() override; + int32_t GetPosY() override; + float GetAspectRatio() override; + void SetMousePos(Ship::Coords pos) override; + Ship::Coords GetMousePos() override; + Ship::Coords GetMouseDelta() override; + Ship::CoordsF GetMouseWheel() override; + bool GetMouseState(Ship::MouseBtn btn) override; + void SetMouseCapture(bool capture) override; + bool IsMouseCaptured() override; + uint32_t GetCurrentRefreshRate() override; + bool SupportsWindowedFullscreen() override; + bool CanDisableVerticalSync() override; + void SetResolutionMultiplier(float multiplier) override; + void SetMsaaLevel(uint32_t value) override; + void SetFullscreen(bool isFullscreen) override; + bool IsFullscreen() override; + bool IsRunning() override; + uintptr_t GetGfxFrameBuffer() override; + const char* GetKeyName(int32_t scancode) override; + + std::string GetWindowBackendName() override; + + void SetCurrentDimensions(uint32_t width, uint32_t height) override; + void SetCurrentDimensions(uint32_t width, uint32_t height, int32_t posX, int32_t posY) override; + void SetCurrentDimensions(bool isFullscreen, uint32_t width, uint32_t height) override; + void SetCurrentDimensions(bool isFullscreen, uint32_t width, uint32_t height, int32_t posX, int32_t posY) override; + Ship::WindowRect GetPrimaryMonitorRect() override; + + void InitWindowManager(); + int32_t GetTargetFps(); + void SetTargetFps(int32_t fps); + void SetMaximumFrameLatency(int32_t latency); + void GetPixelDepthPrepare(float x, float y); + uint16_t GetPixelDepth(float x, float y); + void SetTextureFilter(FilteringMode filteringMode); + void SetRendererUCode(UcodeHandlers ucode); + void EnableSRGBMode(); + bool DrawAndRunGraphicsCommands(Gfx* commands, const std::unordered_map& mtxReplacements); + + std::weak_ptr GetInterpreterWeak() const; + + /** @brief Returns the graphics debugger for this Fast3D window. */ + std::shared_ptr GetGfxDebugger() const; + + protected: + static bool KeyDown(int32_t scancode); + static bool KeyUp(int32_t scancode); + static void AllKeysUp(); + static bool MouseButtonDown(int button); + static bool MouseButtonUp(int button); + static void OnFullscreenChanged(bool isNowFullscreen); + + private: + GfxRenderingAPI* mRenderingApi; + GfxWindowBackend* mWindowManagerApi; + std::shared_ptr mInterpreter = nullptr; + std::shared_ptr mGfxDebugger; +}; +} // namespace Fast diff --git a/libultraship/include/fast/FastMouseStateManager.h b/libultraship/include/fast/FastMouseStateManager.h new file mode 100644 index 000000000..6631791f5 --- /dev/null +++ b/libultraship/include/fast/FastMouseStateManager.h @@ -0,0 +1,15 @@ +#pragma once + +#include "ship/window/MouseStateManager.h" + +namespace Fast { +class FastMouseStateManager : public Ship::MouseStateManager { + public: + void ResetCursorVisibilityTimer() override; + void SetCursorVisibilityTime(uint32_t seconds); + uint32_t GetCursorVisibilityTime(); + + private: + uint32_t mCursorVisibleSeconds = 3; +}; +} // namespace Fast diff --git a/libultraship/include/fast/LICENSE.txt b/libultraship/include/fast/LICENSE.txt new file mode 100644 index 000000000..2857b7eaf --- /dev/null +++ b/libultraship/include/fast/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Emill, MaikelChan + +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/libultraship/include/fast/README.md b/libultraship/include/fast/README.md new file mode 100644 index 000000000..b55975ab8 --- /dev/null +++ b/libultraship/include/fast/README.md @@ -0,0 +1,24 @@ +# Nintendo 64 Fast3D renderer + +Implementation of a Fast3D renderer for games built originally for the Nintendo 64 platform. + +For rendering, OpenGL, Direct3D 11, and Metal are supported. + +Supported windowing systems are DXGI (used on Windows) and SDL (generic). + +# Usage + +See `interpreter.h` and the GBI headers in `include/libultraship/libultra/gbi.h`. + +Each game main loop iteration should look like this: + +```C +gfx_start_frame(); // Handles input events such as keyboard and window events +// perform game logic here +gfx_run(cmds); // submit display list and render a frame +// do more expensive work here, such as play audio +gfx_end_frame(); // this just waits until the frame is shown on the screen (vsync), to provide correct game timing +``` + +For the best experience, please change the Vtx and Mtx structures to use floats instead of fixed point arithmetic (`GBI_FLOATS`). + diff --git a/libultraship/include/fast/WindowEvent.h b/libultraship/include/fast/WindowEvent.h new file mode 100644 index 000000000..dd2766863 --- /dev/null +++ b/libultraship/include/fast/WindowEvent.h @@ -0,0 +1,32 @@ +#pragma once + +// Fixes issue #926: ship/window/gui/Gui.h previously defined WindowEvent in the Ship namespace, +// but this type is only ever constructed and consumed by Fast3D backend code (gfx_sdl2.cpp, +// gfx_dxgi.cpp) and processed by Fast3dGui::HandleWindowEvents. Moving it to the Fast namespace +// enforces the correct include hierarchy: fast can include fast, ship cannot include fast. + +namespace Fast { + +/** + * @brief Platform-agnostic wrapper around a window system event. + * + * Constructed by the Fast3D backends (gfx_sdl2, gfx_dxgi) and passed to + * Fast3dGui::HandleWindowEvents() so that the ImGui backend can process input + * events without the ship layer depending on any Fast3D or platform-specific type. + */ +typedef union { + struct { + void* Handle; ///< HWND + int Msg; ///< Windows message ID. + int Param1; ///< WPARAM + int Param2; ///< LPARAM + } Win32; + struct { + void* Event; ///< SDL_Event* + } Sdl; + struct { + void* Input; ///< GX2 input structure pointer. + } Gx2; +} WindowEvent; + +} // namespace Fast diff --git a/libultraship/include/fast/backends/gfx_direct3d11.h b/libultraship/include/fast/backends/gfx_direct3d11.h new file mode 100644 index 000000000..6585d8014 --- /dev/null +++ b/libultraship/include/fast/backends/gfx_direct3d11.h @@ -0,0 +1,11 @@ +#ifdef ENABLE_DX11 + +#ifndef GFX_DIRECT3D11_H +#define GFX_DIRECT3D11_H + +#include "gfx_rendering_api.h" +#include + +#endif + +#endif diff --git a/libultraship/include/fast/backends/gfx_direct3d_common.h b/libultraship/include/fast/backends/gfx_direct3d_common.h new file mode 100644 index 000000000..d5215c2a1 --- /dev/null +++ b/libultraship/include/fast/backends/gfx_direct3d_common.h @@ -0,0 +1,199 @@ +#pragma once + +#if defined(ENABLE_DX11) || defined(ENABLE_DX12) + +#ifdef __cplusplus +#include "../interpreter.h" +#include +#include +#include "gfx_rendering_api.h" +#include "d3d11.h" +#include "d3dcompiler.h" + +namespace Fast { + +struct PerFrameCB { + uint32_t noise_frame; + float noise_scale; + uint32_t padding[2]; // constant buffers must be multiples of 16 bytes in size +}; + +struct PerDrawCB { + struct Texture { + uint32_t width; + uint32_t height; + uint32_t linear_filtering; + uint32_t padding; + } mTextures[SHADER_MAX_TEXTURES]; +}; + +struct PerPrimDepthCB { + float prim_depth; + float _pad[3]; // 16-byte CB alignment +}; + +struct Coord { + int x, y; +}; + +struct TextureData { + Microsoft::WRL::ComPtr texture; + Microsoft::WRL::ComPtr resource_view; + Microsoft::WRL::ComPtr sampler_state; + uint32_t width; + uint32_t height; + bool linear_filtering; +}; + +struct FramebufferDX11 { + Microsoft::WRL::ComPtr render_target_view; + Microsoft::WRL::ComPtr depth_stencil_view; + Microsoft::WRL::ComPtr depth_stencil_srv; + uint32_t texture_id; + bool has_depth_buffer; + uint32_t msaa_level; +}; + +struct ShaderProgramD3D11 { + Microsoft::WRL::ComPtr vertex_shader; + Microsoft::WRL::ComPtr pixel_shader; + Microsoft::WRL::ComPtr input_layout; + Microsoft::WRL::ComPtr blend_state; + + uint64_t shader_id0; + uint64_t shader_id1; + uint8_t numInputs; + uint8_t numFloats; + bool usedTextures[SHADER_MAX_TEXTURES]; +}; + +class GfxWindowBackendDXGI; + +class GfxRenderingAPIDX11 final : public GfxRenderingAPI { + public: + GfxRenderingAPIDX11() = default; + ~GfxRenderingAPIDX11() override; + GfxRenderingAPIDX11(GfxWindowBackendDXGI* backend); + const char* GetName() override; + int GetMaxTextureSize() override; + GfxClipParameters GetClipParameters() override; + void UnloadShader(struct ShaderProgram* oldPrg) override; + void LoadShader(struct ShaderProgram* newPrg) override; + struct ShaderProgram* CreateAndLoadNewShader(uint64_t shaderId0, uint64_t shaderId1) override; + struct ShaderProgram* LookupShader(uint64_t shaderId0, uint64_t shaderId1) override; + void ShaderGetInfo(struct ShaderProgram* prg, uint8_t* numInputs, bool usedTextures[2]) override; + void ClearShaderCache() override; + uint32_t NewTexture() override; + void SelectTexture(int tile, uint32_t textureId) override; + void UploadTexture(const uint8_t* rgba32Buf, uint32_t width, uint32_t height) override; + void SetSamplerParameters(int sampler, bool linear_filter, uint32_t cms, uint32_t cmt) override; + void SetDepthTestAndMask(bool depth_test, bool z_upd) override; + void SetCurrentPrimDepth(float depth) override; + void SetZmodeDecal(bool decal) override; + void SetViewport(int x, int y, int width, int height) override; + void SetScissor(int x, int y, int width, int height) override; + void SetUseAlpha(bool useAlpha) override; + void DrawTriangles(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris) override; + void Init() override; + void OnResize() override; + void StartFrame() override; + void EndFrame() override; + void FinishRender() override; + int CreateFramebuffer() override; + void UpdateFramebufferParameters(int fb_id, uint32_t width, uint32_t height, uint32_t msaa_level, + bool opengl_invertY, bool render_target, bool has_depth_buffer, + bool can_extract_depth) override; + void StartDrawToFramebuffer(int fbId, float noiseScale) override; + void CopyFramebuffer(int fbDstId, int fbSrcId, int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, + int dstX1, int dstY1) override; + void ClearFramebuffer(bool color, bool depth) override; + void ReadFramebufferToCPU(int fbId, uint32_t width, uint32_t height, uint16_t* rgba16Buf) override; + void ResolveMSAAColorBuffer(int fbIdTarger, int fbIdSrc) override; + std::unordered_map, uint16_t, hash_pair_ff> + GetPixelDepth(int fb_id, const std::set>& coordinates) override; + void* GetFramebufferTextureId(int fbId) override; + void SelectTextureFb(int fbId) override; + void DeleteTexture(uint32_t texId) override; + void SetTextureFilter(FilteringMode mode) override; + FilteringMode GetTextureFilter() override; + void SetSrgbMode() override; + ImTextureID GetTextureById(int id) override; + + PFN_D3D11_CREATE_DEVICE mDX11CreateDevice; + Microsoft::WRL::ComPtr mContext; + Microsoft::WRL::ComPtr mDevice; + GfxWindowBackendDXGI* mWindowBackend = nullptr; + D3D_FEATURE_LEVEL mFeatureLevel; + + private: + void CreateDepthStencilObjects(uint32_t width, uint32_t height, uint32_t msaa_count, ID3D11DepthStencilView** view, + ID3D11ShaderResourceView** srv); + + HMODULE mDX11Module; + + HMODULE mCompilerModule; + pD3DCompile mD3dCompile; + + uint32_t mMsaaNumQualityLevels[D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT]; + + Microsoft::WRL::ComPtr mRasterizerState; + Microsoft::WRL::ComPtr mDepthStencilState; + Microsoft::WRL::ComPtr mVertexBuffer; + Microsoft::WRL::ComPtr mPerFrameCb; + Microsoft::WRL::ComPtr mPerDrawCb; + Microsoft::WRL::ComPtr mPerPrimDepthCb; + Microsoft::WRL::ComPtr mCoordBuffer; + Microsoft::WRL::ComPtr mCoordBufferSrv; + Microsoft::WRL::ComPtr mDepthValueOutputBuffer; + Microsoft::WRL::ComPtr mDepthValueOutputBufferCopy; + Microsoft::WRL::ComPtr mDepthValueOutputUav; + Microsoft::WRL::ComPtr mComputeShader; + Microsoft::WRL::ComPtr mComputeShaderMsaa; + Microsoft::WRL::ComPtr mComputeShaderMsaaBlob; + size_t mCoordBufferSize; + +#if DEBUG_D3D + Microsoft::WRL::ComPtr debug; +#endif + + PerFrameCB mPerFrameCbData; + PerDrawCB mPerDrawCbData; + PerPrimDepthCB mPerPrimDepthCbData; + + std::map, struct ShaderProgramD3D11> mShaderProgramPool; + + std::vector mTextures; + int mCurrentTile; + uint32_t mCurrentTextureIds[SHADER_MAX_TEXTURES] = {}; + + std::vector mFrameBuffers; + + // Current state + + struct ShaderProgramD3D11* mShaderProgram; + + int32_t mRenderTargetHeight; + int mCurrentFramebuffer; + FilteringMode mCurrentFilterMode = FILTER_NONE; + + // Previous states (to prevent setting states needlessly) + + struct ShaderProgramD3D11* mLastShaderProgram = nullptr; + uint32_t mLastVertexBufferStride = 0; + Microsoft::WRL::ComPtr mLastBlendState = nullptr; + Microsoft::WRL::ComPtr mLastResourceViews[SHADER_MAX_TEXTURES] = { nullptr, nullptr }; + Microsoft::WRL::ComPtr mLastSamplerStates[SHADER_MAX_TEXTURES] = { nullptr, nullptr }; + + D3D_PRIMITIVE_TOPOLOGY mLastPrimitaveTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; + + // Cached staging texture for ReadFramebufferToCPU — avoids CreateTexture2D/Release per frame + Microsoft::WRL::ComPtr mReadbackStaging; + uint32_t mReadbackStagingW = 0; + uint32_t mReadbackStagingH = 0; +}; + +std::string gfx_direct3d_common_build_shader(size_t& numFloats, const CCFeatures& cc_features, + bool include_root_signature, bool three_point_filtering, bool use_srgb); +} // namespace Fast +#endif +#endif diff --git a/libultraship/include/fast/backends/gfx_dxgi.h b/libultraship/include/fast/backends/gfx_dxgi.h new file mode 100644 index 000000000..2be987d7a --- /dev/null +++ b/libultraship/include/fast/backends/gfx_dxgi.h @@ -0,0 +1,123 @@ +#pragma once +#if defined(ENABLE_DX11) || defined(ENABLE_DX12) + +#include "gfx_rendering_api.h" +#include "ship/utils/HResultException.h" + +#include + +#include + +namespace Fast { + +class GfxWindowBackendDXGI final : public GfxWindowBackend { + public: + GfxWindowBackendDXGI() = default; + ~GfxWindowBackendDXGI() override; + + void Init(const char* gameName, const char* apiName, bool startFullScreen, uint32_t width, uint32_t height, + int32_t posX, int32_t posY) override; + void Close() override; + void SetKeyboardCallbacks(bool (*onKeyDown)(int scancode), bool (*onKeyUp)(int scancode), + void (*onnAllKeysUp)()) override; + void SetMouseCallbacks(bool (*onMouseButtonDown)(int btn), bool (*onnMouseButtonUp)(int btn)) override; + void SetFullscreenChangedCallback(void (*onnFullscreenChanged)(bool is_now_fullscreen)) override; + void SetFullscreen(bool fullscreen) override; + void GetActiveWindowRefreshRate(uint32_t* refreshRate) override; + void SetCursorVisibility(bool visability) override; + void SetMousePos(int32_t posX, int32_t posY) override; + void GetMousePos(int32_t* x, int32_t* y) override; + void GetMouseDelta(int32_t* x, int32_t* y) override; + void GetMouseWheel(float* x, float* y) override; + bool GetMouseState(uint32_t btn) override; + void SetMouseCapture(bool capture) override; + bool IsMouseCaptured() override; + void GetDimensions(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY) override; + void SetDimensions(uint32_t width, uint32_t height, int32_t posX, int32_t posY) override; + Ship::WindowRect GetPrimaryMonitorRect() override; + void HandleEvents() override; + bool IsFrameReady() override; + void SwapBuffersBegin() override; + void SwapBuffersEnd() override; + double GetTime() override; + int GetTargetFps(); + void SetTargetFps(int fps) override; + void SetMaxFrameLatency(int latency) override; + const char* GetKeyName(int scancode) override; + bool CanDisableVsync() override; + bool IsRunning() override; + void Destroy() override; + bool IsFullscreen() override; + + HWND GetWindowHandle(); + IDXGISwapChain1* GetSwapChain(); + // These need to be public to be accessible in the window callback + void CreateSwapChain(IUnknown* mDevice, std::function&& before_destroy_fn); + void CreateFactoryAndDevice(bool debug, int d3d_version, class GfxRenderingAPIDX11* self, + bool (*createFunc)(class GfxRenderingAPIDX11* self, bool SoftwareRenderer)); + void OnKeydown(WPARAM wParam, LPARAM lParam); + void OnKeyup(WPARAM wParam, LPARAM lParam); + void OnMouseButtonDown(int btn); + void OnMouseButtonUp(int btn); + void HandleRawInputBuffered(); + void UpdateMousePrevPos(); + void ApplyMouseCaptureClip(); + + std::tuple mMonitor; // 0: Handle, 1: Display Monitor Rect, 2: Is_Primary + uint32_t current_width, current_height; // Width and height of client areas + std::vector> monitor_list; + int32_t mPosX, mPosY; // Screen coordinates + double mDetectedHz; + double mDisplayPeriod; // (1000 / dxgi.mDetectedHz) in ms + void (*mOnAllKeysUp)(void); + POINT mRawMouseDeltaBuf; + float mMouseWheel[2]; + bool mIsMouseCaptured; + bool mIsMouseHovered; + bool mInFocus; + bool mHasMousePosition; + + private: + void LoadDxgi(); + void ApplyMaxFrameLatency(bool first); + void ToggleBorderlessWindowFullScreen(bool enable, bool callCallback); + + HWND h_wnd; + // These four only apply in windowed mode. + + HMODULE dxgi_module; + HRESULT(__stdcall* CreateDXGIFactory1)(REFIID riid, void** factory); + HRESULT(__stdcall* CreateDXGIFactory2)(UINT flags, REFIID iid, void** factory); + + bool mLastMaximizedState; + + bool mDXGI11_4; + Microsoft::WRL::ComPtr mFactory; + Microsoft::WRL::ComPtr swap_chain; + HANDLE mWaitableObject; + Microsoft::WRL::ComPtr mSwapChainDevice; // D3D11 Device or D3D12 Command Queue + std::function mBeforeDestroySwapChainFn; + uint64_t mFrameTimeStamp; // in units of 1/FRAME_INTERVAL_NS_DENOMINATOR nanoseconds + std::map mFrameStats; + std::set> mPendingFrameStats; + bool mDroppedFrame; + bool mZeroLatency; + uint32_t mMaxFrameLatency; + uint32_t mAppliedMaxFrameLatency; + HANDLE mTimer; + bool mTearingSupport; + bool mMousePressed[5]; + LARGE_INTEGER mPreviousPresentTime; + + RAWINPUTDEVICE mRawInputDevice[1]; + POINT mPrevMouseCursorPos; +}; + +} // namespace Fast + +#ifdef DECLARE_GFX_DXGI_FUNCTIONS +void ThrowIfFailed(HRESULT res); +void ThrowIfFailed(HRESULT res, HWND h_wnd, const char* message); +#endif + +#endif diff --git a/libultraship/include/fast/backends/gfx_metal.h b/libultraship/include/fast/backends/gfx_metal.h new file mode 100644 index 000000000..1d4521025 --- /dev/null +++ b/libultraship/include/fast/backends/gfx_metal.h @@ -0,0 +1,245 @@ +// +// gfx_metal.h +// libultraship +// +// Created by David Chavez on 16.08.22. +// +#pragma once +#ifdef __APPLE__ + +#include "gfx_rendering_api.h" +#include "../interpreter.h" + +#include +#include + +static constexpr size_t kMaxVertexBufferPoolSize = 3; +static constexpr size_t METAL_MAX_MULTISAMPLE_SAMPLE_COUNT = 8; +static constexpr size_t MAX_PIXEL_DEPTH_COORDS = 1024; + +namespace MTL { +class Texture; +class SamplerState; +class CommandBuffer; +class RenderPassDescriptor; +class RenderCommandEncoder; +class SamplerState; +class ScissorRect; +class Device; +class Function; +class Buffer; +class RenderPipelineState; +class ComputePipelineState; +class CommandQueue; +class Viewport; +} // namespace MTL + +namespace CA { +class MetalDrawable; +class MetalLayer; +} // namespace CA + +namespace NS { +class AutoreleasePool; +} + +static size_t cantor(uint64_t a, uint64_t b) { + return (a + b) * (a + b + 1) / 2 + b; +} + +struct hash_pair_shader_ids { + size_t operator()(const std::pair& p) const { + auto value1 = p.first; + auto value2 = p.second; + return cantor(value1, value2); + } +}; + +namespace Fast { + +struct ShaderProgramMetal { + uint64_t shader_id0; + uint64_t shader_id1; + + uint8_t numInputs; + uint8_t numFloats; + bool usedTextures[SHADER_MAX_TEXTURES]; + bool markedForDeletion = false; + + // hashed by msaa_level + MTL::RenderPipelineState* pipeline_state_variants[9]; +}; + +struct TextureDataMetal { + MTL::Texture* texture; + MTL::Texture* msaaTexture; + MTL::SamplerState* sampler; + uint32_t width; + uint32_t height; + uint32_t filtering; + bool linear_filtering; +}; + +struct FramebufferMetal { + MTL::CommandBuffer* mCommandBuffer; + MTL::RenderPassDescriptor* mRenderPassDescriptor; + MTL::RenderCommandEncoder* mCommandEncoder; + + MTL::Texture* mDepthTexture; + MTL::Texture* mMsaaDepthTexture; + uint32_t mTextureId; + bool mHasDepthBuffer; + uint32_t mMsaaLevel; + bool mRenderTarget; + + // State + bool mHasEndedEncoding; + bool mHasBoundVertexShader; + bool mHasBoundFragShader; + + struct ShaderProgramMetal* mLastShaderProgram; + MTL::Texture* mLastBoundTextures[SHADER_MAX_TEXTURES]; + MTL::SamplerState* mLastBoundSamplers[SHADER_MAX_TEXTURES]; + MTL::ScissorRect* mScissorRect; + MTL::Viewport* mViewport; + + int8_t mLastDepthTest = -1; + int8_t mLastDepthMask = -1; + int8_t mLastZmodeDecal = -1; + + // When true, command buffer is created on the readback queue (no enqueue ordering). + // First ReadFramebufferToCPU returns zeros and flips this; real data from frame 2+. + bool mUseReadbackQueue = false; +}; + +struct FrameUniforms { + simd::int1 frameCount; + simd::float1 noiseScale; +}; + +struct DrawUniforms { + simd::int1 textureFiltering[SHADER_MAX_TEXTURES]; + simd::float1 prim_depth; +}; + +struct CoordUniforms { + simd::uint2 coords[MAX_PIXEL_DEPTH_COORDS]; +}; + +class GfxRenderingAPIMetal final : public GfxRenderingAPI { + public: + ~GfxRenderingAPIMetal() override = default; + const char* GetName() override; + int GetMaxTextureSize() override; + GfxClipParameters GetClipParameters() override; + void UnloadShader(ShaderProgram* oldPrg) override; + void LoadShader(ShaderProgram* newPrg) override; + ShaderProgram* CreateAndLoadNewShader(uint64_t shaderId0, uint64_t shaderId1) override; + ShaderProgram* LookupShader(uint64_t shaderId0, uint64_t shaderId1) override; + void ShaderGetInfo(ShaderProgram* prg, uint8_t* numInputs, bool usedTextures[2]) override; + void ClearShaderCache() override; + uint32_t NewTexture() override; + void SelectTexture(int tile, uint32_t textureId) override; + void UploadTexture(const uint8_t* rgba32Buf, uint32_t width, uint32_t height) override; + void SetSamplerParameters(int sampler, bool linear_filter, uint32_t cms, uint32_t cmt) override; + void SetDepthTestAndMask(bool depth_test, bool z_upd) override; + void SetCurrentPrimDepth(float depth) override; + void SetZmodeDecal(bool decal) override; + void SetViewport(int x, int y, int width, int height) override; + void SetScissor(int x, int y, int width, int height) override; + void SetUseAlpha(bool useAlpha) override; + void DrawTriangles(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris) override; + void Init() override; + void OnResize() override; + void StartFrame() override; + void EndFrame() override; + void FinishRender() override; + int CreateFramebuffer() override; + void UpdateFramebufferParameters(int fb_id, uint32_t width, uint32_t height, uint32_t msaa_level, + bool opengl_invertY, bool render_target, bool has_depth_buffer, + bool can_extract_depth) override; + void StartDrawToFramebuffer(int fbId, float noiseScale) override; + void CopyFramebuffer(int fbDstId, int fbSrcId, int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, + int dstX1, int dstY1) override; + void ClearFramebuffer(bool color, bool depth) override; + void ReadFramebufferToCPU(int fbId, uint32_t width, uint32_t height, uint16_t* rgba16Buf) override; + void ResolveMSAAColorBuffer(int fbIdTarger, int fbIdSrc) override; + std::unordered_map, uint16_t, hash_pair_ff> + GetPixelDepth(int fb_id, const std::set>& coordinates) override; + void* GetFramebufferTextureId(int fbId) override; + void SelectTextureFb(int fbId) override; + void DeleteTexture(uint32_t texId) override; + void SetTextureFilter(FilteringMode mode) override; + FilteringMode GetTextureFilter() override; + void SetSrgbMode() override; + ImTextureID GetTextureById(int id) override; + + void NewFrame(); + void SetupFloatingFrame(); + void RenderDrawData(ImDrawData* drawData); + bool MetalInit(SDL_Renderer* renderer); + + private: + bool NonUniformThreadGroupSupported(); + void SetupScreenFramebuffer(uint32_t width, uint32_t height); + // Elements that only need to be setup once + SDL_Renderer* mRenderer; + CA::MetalLayer* mLayer; // CA::MetalLayer* + MTL::Device* mDevice; + MTL::CommandQueue* mCommandQueue; + MTL::CommandQueue* mReadbackQueue; + + int mCurrentVertexBufferPoolIndex = 0; + MTL::Buffer* mVertexBufferPool[kMaxVertexBufferPoolSize]; + std::unordered_map, struct ShaderProgramMetal, hash_pair_shader_ids> + mShaderProgramPool; + + std::vector mTextures; + std::vector mFramebuffers; + FrameUniforms mFrameUniforms; + CoordUniforms mCoordUniforms; + DrawUniforms mDrawUniforms; + MTL::Buffer* mFrameUniformBuffer; + + uint32_t mMsaaNumQualityLevels[METAL_MAX_MULTISAMPLE_SAMPLE_COUNT]; + + // Depth querying + MTL::Buffer* mCoordUniformBuffer; + MTL::Buffer* mDepthValueOutputBuffer; + size_t mCoordBufferSize; + MTL::Function* mDepthComputeFunction; + MTL::Function* mConvertToRgb5a1Function; + MTL::ComputePipelineState* mConvertToRgb5a1PipelineState = nullptr; + + // Screen FB deferred readback: blit in EndFrame, CPU conversion next frame. + // mScreenReadbackCmdBuf retains the command buffer that encoded the blit so + // we can waitUntilCompleted before reading the shared buffer contents. + MTL::CommandBuffer* mScreenReadbackCmdBuf = nullptr; + MTL::Buffer* mScreenReadbackBuffer = nullptr; + uint32_t mScreenReadbackWidth = 0; + uint32_t mScreenReadbackHeight = 0; + bool mScreenReadbackDataReady = false; + bool mScreenReadbackRequested = false; + + // Current state + struct ShaderProgramMetal* mShaderProgram; + CA::MetalDrawable* mCurrentDrawable; + std::set mDrawnFramebuffers; + NS::AutoreleasePool* mFrameAutoreleasePool; + + int mCurrentTile; + uint32_t mCurrentTextureIds[SHADER_MAX_TEXTURES]; + + int32_t mRenderTargetHeight; + int mCurrentFramebuffer; + size_t mCurrentVertexBufferOffset; + FilteringMode mCurrentFilterMode = FILTER_THREE_POINT; + + bool mNonUniformThreadgroupSupported; +}; + +} // namespace Fast + +bool Metal_IsSupported(); + +#endif diff --git a/libultraship/include/fast/backends/gfx_metal_shader.h b/libultraship/include/fast/backends/gfx_metal_shader.h new file mode 100644 index 000000000..fd17a39f6 --- /dev/null +++ b/libultraship/include/fast/backends/gfx_metal_shader.h @@ -0,0 +1,20 @@ +// +// gfx_metal_shader.h +// libultraship +// +// Created by David Chavez on 16.08.22. +// + +#ifdef __APPLE__ +#ifdef __cplusplus +#pragma once +#include +#include + +struct CCFeatures; + +MTL::VertexDescriptor* gfx_metal_build_shader(std::string& result, size_t& numFloats, const CCFeatures& cc_features, + bool three_point_filtering); + +#endif +#endif diff --git a/libultraship/include/fast/backends/gfx_opengl.h b/libultraship/include/fast/backends/gfx_opengl.h new file mode 100644 index 000000000..af24c702f --- /dev/null +++ b/libultraship/include/fast/backends/gfx_opengl.h @@ -0,0 +1,144 @@ +#ifdef ENABLE_OPENGL +#pragma once + +#include "gfx_rendering_api.h" +#include "../interpreter.h" + +#ifdef _MSC_VER +#include +// #define GL_GLEXT_PROTOTYPES 1 +#include +#elif FOR_WINDOWS +#include +#include "SDL.h" +#define GL_GLEXT_PROTOTYPES 1 +#include "SDL_opengl.h" +#elif __APPLE__ +#include +#include +#elif USE_OPENGLES +#include +#include +#else +#include +#define GL_GLEXT_PROTOTYPES 1 +#include +#endif +namespace Fast { +struct ShaderProgram { + GLuint openglProgramId; + uint8_t numInputs; + bool usedTextures[SHADER_MAX_TEXTURES]; + uint8_t numFloats; + GLint attribLocations[16]; + uint8_t attribSizes[16]; + uint8_t numAttribs; + GLint frameCountLocation; + GLint noiseScaleLocation; + GLint prim_depth_location; + GLint texture_width_location; + GLint texture_height_location; + GLint texture_filtering_location; +}; + +struct FramebufferOGL { + uint32_t width, height; + bool has_depth_buffer; + uint32_t msaa_level; + bool invertY; + + GLuint fbo, clrbuf, clrbufMsaa, rbo; +}; + +struct TextureInfo { + uint16_t width; + uint16_t height; + uint16_t filtering; +}; + +class GfxRenderingAPIOGL final : public GfxRenderingAPI { + public: + ~GfxRenderingAPIOGL() override = default; + const char* GetName() override; + int GetMaxTextureSize() override; + GfxClipParameters GetClipParameters() override; + void UnloadShader(ShaderProgram* oldPrg) override; + void LoadShader(ShaderProgram* newPrg) override; + ShaderProgram* CreateAndLoadNewShader(uint64_t shaderId0, uint64_t shaderId1) override; + ShaderProgram* LookupShader(uint64_t shaderId0, uint64_t shaderId1) override; + void ShaderGetInfo(ShaderProgram* prg, uint8_t* numInputs, bool usedTextures[2]) override; + void ClearShaderCache() override; + uint32_t NewTexture() override; + void SelectTexture(int tile, uint32_t textureId) override; + void UploadTexture(const uint8_t* rgba32Buf, uint32_t width, uint32_t height) override; + void SetSamplerParameters(int sampler, bool linear_filter, uint32_t cms, uint32_t cmt) override; + void SetDepthTestAndMask(bool depth_test, bool z_upd) override; + void SetCurrentPrimDepth(float depth) override; + void SetZmodeDecal(bool decal) override; + void SetViewport(int x, int y, int width, int height) override; + void SetScissor(int x, int y, int width, int height) override; + void SetUseAlpha(bool useAlpha) override; + void DrawTriangles(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris) override; + void Init() override; + void OnResize() override; + void StartFrame() override; + void EndFrame() override; + void FinishRender() override; + int CreateFramebuffer() override; + void UpdateFramebufferParameters(int fb_id, uint32_t width, uint32_t height, uint32_t msaa_level, + bool opengl_invertY, bool render_target, bool has_depth_buffer, + bool can_extract_depth) override; + void StartDrawToFramebuffer(int fbId, float noiseScale) override; + void CopyFramebuffer(int fbDstId, int fbSrcId, int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, + int dstX1, int dstY1) override; + void ClearFramebuffer(bool color, bool depth) override; + void ClearDepthRegion(int x, int y, int w, int h) override; + void ReadFramebufferToCPU(int fbId, uint32_t width, uint32_t height, uint16_t* rgba16Buf) override; + void ResolveMSAAColorBuffer(int fbIdTarger, int fbIdSrc) override; + std::unordered_map, uint16_t, hash_pair_ff> + GetPixelDepth(int fb_id, const std::set>& coordinates) override; + void* GetFramebufferTextureId(int fbId) override; + void SelectTextureFb(int fbId) override; + void DeleteTexture(uint32_t texId) override; + void SetTextureFilter(FilteringMode mode) override; + FilteringMode GetTextureFilter() override; + void SetSrgbMode() override; + ImTextureID GetTextureById(int id) override; + + private: + void SetUniforms(ShaderProgram* prg) const; + std::string BuildFsShader(const CCFeatures& cc_features); + void SetPerDrawUniforms(); + + std::vector textures; + GLuint mCurrentTextureIds[SHADER_MAX_TEXTURES] = {}; + GLuint mLastBoundTextures[SHADER_MAX_TEXTURES] = {}; + uint8_t mCurrentTile; + int8_t mLastActiveTexture = -1; + int8_t mLastBlendEnabled = -1; + int8_t mLastScissorEnabled = -1; + + std::map, ShaderProgram> mShaderProgramPool; + ShaderProgram* mCurrentShaderProgram; + ShaderProgram* mLastLoadedShader = nullptr; + + GLuint mOpenglVbo = 0; +#if defined(__APPLE__) || defined(USE_OPENGLES) + GLuint mOpenglVao; +#endif + + uint32_t mFrameCount = 0; + + std::vector mFrameBuffers; + size_t mCurrentFrameBuffer = 0; + float mCurrentNoiseScale = 0.0f; + FilteringMode mCurrentFilterMode = FILTER_THREE_POINT; + + GLint mMaxMsaaLevel = 1; + GLuint mPixelDepthRb = 0; + GLuint mPixelDepthFb = 0; + size_t mPixelDepthRbSize = 0; +}; + +} // namespace Fast +#endif diff --git a/libultraship/include/fast/backends/gfx_rendering_api.h b/libultraship/include/fast/backends/gfx_rendering_api.h new file mode 100644 index 000000000..3eb099619 --- /dev/null +++ b/libultraship/include/fast/backends/gfx_rendering_api.h @@ -0,0 +1,94 @@ +#pragma once + +#include + +#include +#include +#include "imconfig.h" + +namespace Fast { +struct ShaderProgram; + +struct GfxClipParameters { + bool z_is_from_0_to_1; + bool invertY; +}; + +enum FilteringMode { FILTER_THREE_POINT, FILTER_LINEAR, FILTER_NONE }; + +// A hash function used to hash a: pair +struct hash_pair_ff { + size_t operator()(const std::pair& p) const { + const auto hash1 = std::hash{}(p.first); + const auto hash2 = std::hash{}(p.second); + + // If hash1 == hash2, their XOR is zero. + return (hash1 != hash2) ? hash1 ^ hash2 : hash1; + } +}; + +class GfxRenderingAPI { + public: + virtual ~GfxRenderingAPI() = default; + virtual const char* GetName() = 0; + virtual int GetMaxTextureSize() = 0; + virtual GfxClipParameters GetClipParameters() = 0; + virtual void UnloadShader(ShaderProgram* oldPrg) = 0; + virtual void LoadShader(ShaderProgram* newPrg) = 0; + virtual void ClearShaderCache() = 0; + virtual ShaderProgram* CreateAndLoadNewShader(uint64_t shaderId0, uint64_t shaderId1) = 0; + virtual ShaderProgram* LookupShader(uint64_t shaderId0, uint64_t shaderId1) = 0; + virtual void ShaderGetInfo(ShaderProgram* prg, uint8_t* numInputs, bool usedTextures[2]) = 0; + virtual uint32_t NewTexture() = 0; + virtual void SelectTexture(int tile, uint32_t textureId) = 0; + virtual void UploadTexture(const uint8_t* rgba32Buf, uint32_t width, uint32_t height) = 0; + virtual void SetSamplerParameters(int sampler, bool linear_filter, uint32_t cms, uint32_t cmt) = 0; + virtual void SetDepthTestAndMask(bool depth_test, bool z_upd) = 0; + virtual void SetZmodeDecal(bool decal) = 0; + virtual void SetViewport(int x, int y, int width, int height) = 0; + virtual void SetScissor(int x, int y, int width, int height) = 0; + virtual void SetUseAlpha(bool useAlpha) = 0; + virtual void DrawTriangles(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris) = 0; + virtual void Init() = 0; + virtual void OnResize() = 0; + virtual void StartFrame() = 0; + virtual void EndFrame() = 0; + virtual void FinishRender() = 0; + virtual int CreateFramebuffer() = 0; + virtual void UpdateFramebufferParameters(int fb_id, uint32_t width, uint32_t height, uint32_t msaa_level, + bool opengl_invertY, bool render_target, bool has_depth_buffer, + bool can_extract_depth) = 0; + virtual void StartDrawToFramebuffer(int fbId, float noiseScale) = 0; + virtual void CopyFramebuffer(int fbDstId, int fbSrcId, int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, + int dstY0, int dstX1, int dstY1) = 0; + virtual void ClearFramebuffer(bool color, bool depth) = 0; + virtual void ClearDepthRegion(int x, int y, int w, int h) { + // Default: full depth clear. Backends that support scissored depth clears + // (e.g. OpenGL) should override for a more precise partial clear. + ClearFramebuffer(false, true); + } + virtual void ReadFramebufferToCPU(int fbId, uint32_t width, uint32_t height, uint16_t* rgba16Buf) = 0; + virtual void ResolveMSAAColorBuffer(int fbIdTarger, int fbIdSrc) = 0; + virtual std::unordered_map, uint16_t, hash_pair_ff> + GetPixelDepth(int fb_id, const std::set>& coordinates) = 0; + virtual void* GetFramebufferTextureId(int fbId) = 0; + virtual void SelectTextureFb(int fbId) = 0; + virtual void DeleteTexture(uint32_t texId) = 0; + virtual void SetTextureFilter(FilteringMode mode) = 0; + virtual FilteringMode GetTextureFilter() = 0; + virtual void SetSrgbMode() = 0; + virtual ImTextureID GetTextureById(int id) = 0; + virtual void SetCurrentPrimDepth(float depth) = 0; + + protected: + int8_t mCurrentDepthTest = 0; + int8_t mCurrentDepthMask = 0; + int8_t mCurrentZmodeDecal = 0; + int8_t mLastDepthTest = -1; + int8_t mLastDepthMask = -1; + int8_t mLastZmodeDecal = -1; + bool mSrgbMode = false; + float mCurrentPrimDepth = 0.0f; + bool mPrimDepthDirty = true; +}; +} // namespace Fast diff --git a/libultraship/include/fast/backends/gfx_screen_config.h b/libultraship/include/fast/backends/gfx_screen_config.h new file mode 100644 index 000000000..30cac0e27 --- /dev/null +++ b/libultraship/include/fast/backends/gfx_screen_config.h @@ -0,0 +1,4 @@ +#pragma once + +#define DESIRED_SCREEN_WIDTH 640 +#define DESIRED_SCREEN_HEIGHT 480 diff --git a/libultraship/include/fast/backends/gfx_sdl.h b/libultraship/include/fast/backends/gfx_sdl.h new file mode 100644 index 000000000..79042f4ed --- /dev/null +++ b/libultraship/include/fast/backends/gfx_sdl.h @@ -0,0 +1,70 @@ +#pragma once + +#include "gfx_window_manager_api.h" +namespace Fast { +class GfxWindowBackendSDL2 final : public GfxWindowBackend { + public: + GfxWindowBackendSDL2() = default; + ~GfxWindowBackendSDL2() override; + + void Init(const char* gameName, const char* apiName, bool startFullScreen, uint32_t width, uint32_t height, + int32_t posX, int32_t posY) override; + void Close() override; + void SetKeyboardCallbacks(bool (*onKeyDown)(int scancode), bool (*onKeyUp)(int scancode), + void (*onAllKeysUp)()) override; + void SetMouseCallbacks(bool (*onMouseButtonDown)(int btn), bool (*onMouseButtonUp)(int btn)) override; + void SetFullscreenChangedCallback(void (*onFullscreenChanged)(bool is_now_fullscreen)) override; + void SetFullscreen(bool fullscreen) override; + void GetActiveWindowRefreshRate(uint32_t* refreshRate) override; + void SetCursorVisibility(bool visability) override; + void SetMousePos(int32_t posX, int32_t posY) override; + void GetMousePos(int32_t* x, int32_t* y) override; + void GetMouseDelta(int32_t* x, int32_t* y) override; + void GetMouseWheel(float* x, float* y) override; + bool GetMouseState(uint32_t btn) override; + void SetMouseCapture(bool capture) override; + bool IsMouseCaptured() override; + void GetDimensions(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY) override; + void SetDimensions(uint32_t width, uint32_t height, int32_t posX, int32_t posY) override; + Ship::WindowRect GetPrimaryMonitorRect() override; + void HandleEvents() override; + bool IsFrameReady() override; + void SwapBuffersBegin() override; + void SwapBuffersEnd() override; + double GetTime() override; + int GetTargetFps(); + void SetTargetFps(int fps) override; + void SetMaxFrameLatency(int latency) override; + const char* GetKeyName(int scancode) override; + bool CanDisableVsync() override; + bool IsRunning() override; + void Destroy() override; + bool IsFullscreen() override; + + private: + void SetFullscreenImpl(bool on, bool call_callback); + void HandleSingleEvent(SDL_Event& event); + int TranslateScancode(int scancode) const; + int UntranslateScancode(int translatedScancode) const; + void OnKeydown(int scancode) const; + void OnKeyup(int scancode) const; + void OnMouseButtonDown(int btn) const; + void OnMouseButtonUp(int btn) const; + void SyncFramerateWithTime() const; + + SDL_Window* mWnd; + SDL_Rect mCursorClip; + SDL_GLContext mCtx; + SDL_Renderer* mRenderer; + int mSdlToLusTable[512]; + float mMouseWheelX = 0.0f; + float mMouseWheelY = 0.0f; +#ifdef __OpenBSD__ + int mBsdTick; // store kern.clockrate's tick (microseconds) to adjust sleep timing +#endif + // OTRTODO: These are redundant. Info can be queried from SDL. + int mWindowWidth = 640; + int mWindowHeight = 480; + void (*mOnAllKeysUp)(); +}; +} // namespace Fast diff --git a/libultraship/include/fast/backends/gfx_window_manager_api.h b/libultraship/include/fast/backends/gfx_window_manager_api.h new file mode 100644 index 000000000..3759991cb --- /dev/null +++ b/libultraship/include/fast/backends/gfx_window_manager_api.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include "ship/window/Window.h" +namespace Fast { +class GfxWindowBackend { + public: + virtual ~GfxWindowBackend() = default; + virtual void Init(const char* gameName, const char* apiName, bool startFullScreen, uint32_t width, uint32_t height, + int32_t posX, int32_t posY) = 0; + virtual void Close() = 0; + virtual void SetKeyboardCallbacks(bool (*mOnKeyDown)(int scancode), bool (*mOnKeyUp)(int scancode), + void (*mOnAllKeysUp)()) = 0; + virtual void SetMouseCallbacks(bool (*mOnMouseButtonDown)(int btn), bool (*mOnMouseButtonUp)(int btn)) = 0; + virtual void SetFullscreenChangedCallback(void (*mOnFullscreenChanged)(bool is_now_fullscreen)) = 0; + virtual void SetFullscreen(bool fullscreen) = 0; + virtual void GetActiveWindowRefreshRate(uint32_t* refreshRate) = 0; + virtual void SetCursorVisibility(bool visability) = 0; + virtual void SetMousePos(int32_t posX, int32_t posY) = 0; + virtual void GetMousePos(int32_t* x, int32_t* y) = 0; + virtual void GetMouseDelta(int32_t* x, int32_t* y) = 0; + virtual void GetMouseWheel(float* x, float* y) = 0; + virtual bool GetMouseState(uint32_t btn) = 0; + virtual void SetMouseCapture(bool capture) = 0; + virtual bool IsMouseCaptured() = 0; + virtual void GetDimensions(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY) = 0; + virtual void SetDimensions(uint32_t width, uint32_t height, int32_t posX, int32_t posY) = 0; + virtual Ship::WindowRect GetPrimaryMonitorRect() = 0; + virtual void HandleEvents() = 0; + virtual bool IsFrameReady() = 0; + virtual void SwapBuffersBegin() = 0; + virtual void SwapBuffersEnd() = 0; + virtual double GetTime() = 0; + virtual int GetTargetFps() = 0; + virtual void SetTargetFps(int fps) = 0; + virtual void SetMaxFrameLatency(int latency) = 0; + virtual const char* GetKeyName(int scancode) = 0; + virtual bool CanDisableVsync() = 0; + virtual bool IsRunning() = 0; + virtual void Destroy() = 0; + virtual bool IsFullscreen() = 0; + + protected: + void (*mOnFullscreenChanged)(bool isNowFullscreen); + bool (*mOnKeyDown)(int scancode); + bool (*mOnKeyUp)(int scancode); + bool (*mOnMouseButtonDown)(int btn); + bool (*mOnMouseButtonUp)(int btn); + uint32_t mTargetFps = 60; + bool mFullScreen; + bool mIsRunning = true; + bool mVsyncEnabled = true; +}; +} // namespace Fast diff --git a/libultraship/include/fast/debug/GfxDebugger.h b/libultraship/include/fast/debug/GfxDebugger.h new file mode 100644 index 000000000..8be65c160 --- /dev/null +++ b/libultraship/include/fast/debug/GfxDebugger.h @@ -0,0 +1,33 @@ +#pragma once + +#include + +namespace Fast { +union F3DGfx; + +class GfxDebugger { + public: + void RequestDebugging(); + bool IsDebugging() const; + bool IsDebuggingRequested() const; + + void DebugDisplayList(F3DGfx* cmds); + + void ResumeGame(); + + const F3DGfx* GetDisplayList() const; + + const std::vector& GetBreakPoint() const; + + bool HasBreakPoint(const std::vector& path) const; + + void SetBreakPoint(const std::vector& bp); + + private: + bool mIsDebugging = false; + bool mIsDebuggingRequested = false; + F3DGfx* mDlist = nullptr; + std::vector mBreakPoint = {}; +}; + +} // namespace Fast diff --git a/libultraship/include/fast/f3dex.h b/libultraship/include/fast/f3dex.h new file mode 100644 index 000000000..894d236ae --- /dev/null +++ b/libultraship/include/fast/f3dex.h @@ -0,0 +1,153 @@ +#pragma once + +#define G_IMMFIRST -65 + +constexpr int8_t F3DEX_G_SPNOOP = OPCODE(0x0); +constexpr int8_t F3DEX_G_MTX = OPCODE(0x1); +constexpr int8_t F3DEX_G_RESERVED0 = OPCODE(0x2); +constexpr int8_t F3DEX_G_MOVEMEM = OPCODE(0x3); +constexpr int8_t F3DEX_G_VTX = OPCODE(0x4); +constexpr int8_t F3DEX_G_RESERVED1 = OPCODE(0x5); +constexpr int8_t F3DEX_G_DL = OPCODE(0x6); +constexpr int8_t F3DEX_G_RESERVED2 = OPCODE(0x7); +constexpr int8_t F3DEX_G_RESERVED3 = OPCODE(0x8); +constexpr int8_t F3DEX_G_TRI1 = OPCODE(G_IMMFIRST - 0); +constexpr int8_t F3DEX_G_CULLDL = OPCODE(G_IMMFIRST - 1); +constexpr int8_t F3DEX_G_POPMTX = OPCODE(G_IMMFIRST - 2); +constexpr int8_t F3DEX_G_MOVEWORD = OPCODE(G_IMMFIRST - 3); +constexpr int8_t F3DEX_G_TEXTURE = OPCODE(G_IMMFIRST - 4); +constexpr int8_t F3DEX_G_SETOTHERMODE_H = OPCODE(G_IMMFIRST - 5); +constexpr int8_t F3DEX_G_SETOTHERMODE_L = OPCODE(G_IMMFIRST - 6); +constexpr int8_t F3DEX_G_ENDDL = OPCODE(G_IMMFIRST - 7); +constexpr int8_t F3DEX_G_SETGEOMETRYMODE = OPCODE(G_IMMFIRST - 8); +constexpr int8_t F3DEX_G_CLEARGEOMETRYMODE = OPCODE(G_IMMFIRST - 9); +constexpr int8_t F3DEX_G_LINE3D = OPCODE(G_IMMFIRST - 10); +constexpr int8_t F3DEX_G_RDPHALF_1 = OPCODE(G_IMMFIRST - 11); +constexpr int8_t F3DEX_G_RDPHALF_2 = OPCODE(G_IMMFIRST - 12); +constexpr int8_t F3DEX_G_MODIFYVTX = OPCODE(G_IMMFIRST - 13); +constexpr int8_t F3DEX_G_RDPHALF_CONT = OPCODE(G_IMMFIRST - 13); +constexpr int8_t F3DEX_G_TRI2 = OPCODE(G_IMMFIRST - 14); +constexpr int8_t F3DEX_G_BRANCH_Z = OPCODE(G_IMMFIRST - 15); +constexpr int8_t F3DEX_G_LOAD_UCODE = OPCODE(G_IMMFIRST - 16); +constexpr int8_t F3DEX_G_QUAD = OPCODE(G_IMMFIRST - 10); + +// S2DEX +constexpr int8_t F3DEX_G_SPRITE2D_BASE = OPCODE(9); +constexpr int8_t F3DEX_G_SPRITE2D_SCALEFLIP = OPCODE(G_IMMFIRST - 1); +constexpr int8_t F3DEX_G_SPRITE2D_DRAW = OPCODE(G_IMMFIRST - 2); +constexpr int8_t F3DEX_G_NOOP = OPCODE(0xc0); + +/* + * G_MTX: parameter flags + */ +constexpr int8_t F3DEX_G_MTX_MODELVIEW = 0x00; +constexpr int8_t F3DEX_G_MTX_PROJECTION = 0x01; +constexpr int8_t F3DEX_G_MTX_MUL = 0x00; +constexpr int8_t F3DEX_G_MTX_LOAD = 0x02; +constexpr int8_t F3DEX_G_MTX_NOPUSH = 0x00; +constexpr int8_t F3DEX_G_MTX_PUSH = 0x04; + +/* + * flags for G_SETGEOMETRYMODE + * (this rendering state is maintained in RSP) + * + * DO NOT USE THE LOW 8 BITS OF GEOMETRYMODE: + * The weird bit-ordering is for the micro-code: the lower byte + * can be OR'd in with G_TRI_SHADE (11001100) to construct + * the triangle command directly. Don't break it... + * + * DO NOT USE THE HIGH 8 BITS OF GEOMETRYMODE: + * The high byte is OR'd with 0x703 to form the clip code mask. + * If it is set to 0x04, this will cause near clipping to occur. + * If it is zero, near clipping will not occur. + * + * Further explanation: + * G_SHADE is necessary in order to see the color that you passed + * down with the vertex. If G_SHADE isn't set, you need to set the DP + * appropriately and use primcolor to see anything. + * + * G_SHADING_SMOOTH enabled means use all 3 colors of the triangle. + * If it is not set, then do 'flat shading', where only one vertex color + * is used (and all 3 vertices are set to that same color by the ucode) + * See the man page for gSP1Triangle(). + * + */ + +constexpr uint32_t F3DEX_G_CLIPPING = 0x00800000; +constexpr uint32_t F3DEX_G_TEXTURE_ENABLE = 0x00000002; +constexpr uint32_t F3DEX_G_SHADING_SMOOTH = 0x00000200; +constexpr uint32_t F3DEX_G_CULL_FRONT = 0x00001000; +constexpr uint32_t F3DEX_G_CULL_BACK = 0x00002000; +constexpr uint32_t F3DEX_G_CULL_BOTH = 0x00003000; + +/* + * MOVEMEM indices + * + * Each of these indexes an entry in a dmem table + * which points to a 1-4 word block of dmem in + * which to store a 1-4 word DMA. + * + */ +constexpr uint8_t F3DEX_G_MV_VIEWPORT = 0x80; +constexpr uint8_t F3DEX_G_MV_LOOKATY = 0x82; +constexpr uint8_t F3DEX_G_MV_LOOKATX = 0x84; +constexpr uint8_t F3DEX_G_MV_L0 = 0x86; +constexpr uint8_t F3DEX_G_MV_L1 = 0x88; +constexpr uint8_t F3DEX_G_MV_L2 = 0x8a; +constexpr uint8_t F3DEX_G_MV_L3 = 0x8c; +constexpr uint8_t F3DEX_G_MV_L4 = 0x8e; +constexpr uint8_t F3DEX_G_MV_L5 = 0x90; +constexpr uint8_t F3DEX_G_MV_L6 = 0x92; +constexpr uint8_t F3DEX_G_MV_L7 = 0x94; +constexpr uint8_t F3DEX_G_MV_TXTATT = 0x96; +constexpr uint8_t F3DEX_G_MV_MATRIX_1 = 0x9e; +constexpr uint8_t F3DEX_G_MV_MATRIX_2 = 0x98; +constexpr uint8_t F3DEX_G_MV_MATRIX_3 = 0x9a; +constexpr uint8_t F3DEX_G_MV_MATRIX_4 = 0x9c; + +/* + * MOVEWORD indices + * + * Each of these indexes an entry in a dmem table + * which points to a word in dmem in dmem where + * an immediate word will be stored. + * + */ +constexpr int8_t F3DEX_G_MW_POINTS = 0x0c; + +/* + * These are offsets from the address in the dmem table + */ + +constexpr int8_t F3DEX_G_MWO_aLIGHT_2 = OPCODE(0x20); +constexpr int8_t F3DEX_G_MWO_bLIGHT_2 = OPCODE(0x24); +constexpr int8_t F3DEX_G_MWO_aLIGHT_3 = OPCODE(0x40); +constexpr int8_t F3DEX_G_MWO_bLIGHT_3 = OPCODE(0x44); +constexpr int8_t F3DEX_G_MWO_aLIGHT_4 = OPCODE(0x60); +constexpr int8_t F3DEX_G_MWO_bLIGHT_4 = OPCODE(0x64); +constexpr int8_t F3DEX_G_MWO_aLIGHT_5 = OPCODE(0x80); +constexpr int8_t F3DEX_G_MWO_bLIGHT_5 = OPCODE(0x84); +constexpr int8_t F3DEX_G_MWO_aLIGHT_6 = OPCODE(0xa0); +constexpr int8_t F3DEX_G_MWO_bLIGHT_6 = OPCODE(0xa4); +constexpr int8_t F3DEX_G_MWO_aLIGHT_7 = OPCODE(0xc0); +constexpr int8_t F3DEX_G_MWO_bLIGHT_7 = OPCODE(0xc4); +constexpr int8_t F3DEX_G_MWO_aLIGHT_8 = OPCODE(0xe0); +constexpr int8_t F3DEX_G_MWO_bLIGHT_8 = OPCODE(0xe4); + +/*===========================================================================* + * GBI Commands for S2DEX microcode + *===========================================================================*/ +/* GBI Header */ +constexpr int8_t F3DEX_G_BG_1CYC = OPCODE(0x01); +constexpr int8_t F3DEX_G_BG_COPY = OPCODE(0x02); +constexpr int8_t F3DEX_G_OBJ_RECTANGLE = OPCODE(0x03); +constexpr int8_t F3DEX_G_OBJ_SPRITE = OPCODE(0x04); +constexpr int8_t F3DEX_G_OBJ_MOVEMEM = OPCODE(0x05); +constexpr int8_t F3DEX_G_SELECT_DL = OPCODE(0xb0); +constexpr int8_t F3DEX_G_OBJ_RENDERMODE = OPCODE(0xb1); +constexpr int8_t F3DEX_G_OBJ_RECTANGLE_R = OPCODE(0xb2); +constexpr int8_t F3DEX_G_OBJ_LOADTXTR = OPCODE(0xc1); +constexpr int8_t F3DEX_G_OBJ_LDTX_SPRITE = OPCODE(0xc2); +constexpr int8_t F3DEX_G_OBJ_LDTX_RECT = OPCODE(0xc3); +constexpr int8_t F3DEX_G_OBJ_LDTX_RECT_R = OPCODE(0xc4); +constexpr int8_t F3DEX_G_RDPHALF_0 = OPCODE(0xe4); diff --git a/libultraship/include/fast/f3dex2.h b/libultraship/include/fast/f3dex2.h new file mode 100644 index 000000000..e47d391dd --- /dev/null +++ b/libultraship/include/fast/f3dex2.h @@ -0,0 +1,149 @@ +#pragma once + +constexpr int8_t F3DEX2_G_NOOP = OPCODE(0x00); +constexpr int8_t F3DEX2_G_RDPHALF_2 = OPCODE(0xf1); +constexpr int8_t F3DEX2_G_SETOTHERMODE_H = OPCODE(0xe3); +constexpr int8_t F3DEX2_G_SETOTHERMODE_L = OPCODE(0xe2); +constexpr int8_t F3DEX2_G_RDPHALF_1 = OPCODE(0xe1); +constexpr int8_t F3DEX2_G_SPNOOP = OPCODE(0xe0); +constexpr int8_t F3DEX2_G_ENDDL = OPCODE(0xdf); +constexpr int8_t F3DEX2_G_DL = OPCODE(0xde); +constexpr int8_t F3DEX2_G_LOAD_UCODE = OPCODE(0xdd); +constexpr int8_t F3DEX2_G_MOVEMEM = OPCODE(0xdc); +constexpr int8_t F3DEX2_G_MOVEWORD = OPCODE(0xdb); +constexpr int8_t F3DEX2_G_MTX = OPCODE(0xda); +constexpr int8_t F3DEX2_G_GEOMETRYMODE = OPCODE(0xd9); +constexpr int8_t F3DEX2_G_POPMTX = OPCODE(0xd8); +constexpr int8_t F3DEX2_G_TEXTURE = OPCODE(0xd7); +constexpr int8_t F3DEX2_G_DMA_IO = OPCODE(0xd6); +constexpr int8_t F3DEX2_G_SPECIAL_1 = OPCODE(0xd5); +constexpr int8_t F3DEX2_G_SPECIAL_2 = OPCODE(0xd4); +constexpr int8_t F3DEX2_G_SPECIAL_3 = OPCODE(0xd3); + +constexpr int8_t F3DEX2_G_VTX = OPCODE(0x01); +constexpr int8_t F3DEX2_G_MODIFYVTX = OPCODE(0x02); +constexpr int8_t F3DEX2_G_CULLDL = OPCODE(0x03); +constexpr int8_t F3DEX2_G_BRANCH_Z = OPCODE(0x04); +constexpr int8_t F3DEX2_G_TRI1 = OPCODE(0x05); +constexpr int8_t F3DEX2_G_TRI2 = OPCODE(0x06); +constexpr int8_t F3DEX2_G_QUAD = OPCODE(0x07); +constexpr int8_t F3DEX2_G_LINE3D = OPCODE(0x08); + +/* + * G_MTX: parameter flags + */ +constexpr int8_t F3DEX2_G_MTX_MODELVIEW = OPCODE(0x00); +constexpr int8_t F3DEX2_G_MTX_PROJECTION = OPCODE(0x04); +constexpr int8_t F3DEX2_G_MTX_MUL = OPCODE(0x00); +constexpr int8_t F3DEX2_G_MTX_LOAD = OPCODE(0x02); +constexpr int8_t F3DEX2_G_MTX_NOPUSH = OPCODE(0x00); +constexpr int8_t F3DEX2_G_MTX_PUSH = OPCODE(0x01); + +/* + * flags for G_SETGEOMETRYMODE + * (this rendering state is maintained in RSP) + * + * DO NOT USE THE LOW 8 BITS OF GEOMETRYMODE: + * The weird bit-ordering is for the micro-code: the lower byte + * can be OR'd in with G_TRI_SHADE (11001100) to construct + * the triangle command directly. Don't break it... + * + * DO NOT USE THE HIGH 8 BITS OF GEOMETRYMODE: + * The high byte is OR'd with 0x703 to form the clip code mask. + * If it is set to 0x04, this will cause near clipping to occur. + * If it is zero, near clipping will not occur. + * + * Further explanation: + * G_SHADE is necessary in order to see the color that you passed + * down with the vertex. If G_SHADE isn't set, you need to set the DP + * appropriately and use primcolor to see anything. + * + * G_SHADING_SMOOTH enabled means use all 3 colors of the triangle. + * If it is not set, then do 'flat shading', where only one vertex color + * is used (and all 3 vertices are set to that same color by the ucode) + * See the man page for gSP1Triangle(). + * + */ +constexpr uint32_t F3DEX2_G_CLIPPING = 0x00800000; +constexpr uint32_t F3DEX2_G_TEXTURE_ENABLE = 0x00000000; +constexpr uint32_t F3DEX2_G_SHADING_SMOOTH = 0x00200000; +constexpr uint32_t F3DEX2_G_CULL_FRONT = 0x00000200; +constexpr uint32_t F3DEX2_G_CULL_BACK = 0x00000400; +constexpr uint32_t F3DEX2_G_CULL_BOTH = 0x00000600; + +/* + * MOVEMEM indices + * + * Each of these indexes an entry in a dmem table + * which points to a 1-4 word block of dmem in + * which to store a 1-4 word DMA. + * + */ +constexpr int8_t F3DEX2_G_MV_MMTX = OPCODE(2); +constexpr int8_t F3DEX2_G_MV_PMTX = OPCODE(6); +constexpr int8_t F3DEX2_G_MV_VIEWPORT = OPCODE(8); +constexpr int8_t F3DEX2_G_MV_LIGHT = OPCODE(10); +constexpr int8_t F3DEX2_G_MV_POINT = OPCODE(12); +constexpr int8_t F3DEX2_G_MV_MATRIX = OPCODE(14); +constexpr int8_t F3DEX2_G_MVO_LOOKATX = OPCODE(0 * 24); +constexpr int8_t F3DEX2_G_MVO_LOOKATY = OPCODE(1 * 24); +constexpr int8_t F3DEX2_G_MVO_L0 = OPCODE(2 * 24); +constexpr int8_t F3DEX2_G_MVO_L1 = OPCODE(3 * 24); +constexpr int8_t F3DEX2_G_MVO_L2 = OPCODE(4 * 24); +constexpr int8_t F3DEX2_G_MVO_L3 = OPCODE(5 * 24); +constexpr int8_t F3DEX2_G_MVO_L4 = OPCODE(6 * 24); +constexpr int8_t F3DEX2_G_MVO_L5 = OPCODE(7 * 24); +constexpr int8_t F3DEX2_G_MVO_L6 = OPCODE(8 * 24); +constexpr int8_t F3DEX2_G_MVO_L7 = OPCODE(9 * 24); + +/* + * MOVEWORD indices + * + * Each of these indexes an entry in a dmem table + * which points to a word in dmem in dmem where + * an immediate word will be stored. + * + */ +constexpr int8_t F3DEX2_G_MW_FORCEMTX = 0x0c; + +/* + * MOVEWORD indices + * + * Each of these indexes an entry in a dmem table + * which points to a word in dmem in dmem where + * an immediate word will be stored. + * + * These are offsets from the address in the dmem table + */ +constexpr int8_t F3DEX2_G_MWO_aLIGHT_2 = OPCODE(0x18); +constexpr int8_t F3DEX2_G_MWO_bLIGHT_2 = OPCODE(0x1c); +constexpr int8_t F3DEX2_G_MWO_aLIGHT_3 = OPCODE(0x30); +constexpr int8_t F3DEX2_G_MWO_bLIGHT_3 = OPCODE(0x34); +constexpr int8_t F3DEX2_G_MWO_aLIGHT_4 = OPCODE(0x48); +constexpr int8_t F3DEX2_G_MWO_bLIGHT_4 = OPCODE(0x4c); +constexpr int8_t F3DEX2_G_MWO_aLIGHT_5 = OPCODE(0x60); +constexpr int8_t F3DEX2_G_MWO_bLIGHT_5 = OPCODE(0x64); +constexpr int8_t F3DEX2_G_MWO_aLIGHT_6 = OPCODE(0x78); +constexpr int8_t F3DEX2_G_MWO_bLIGHT_6 = OPCODE(0x7c); +constexpr int8_t F3DEX2_G_MWO_aLIGHT_7 = OPCODE(0x90); +constexpr int8_t F3DEX2_G_MWO_bLIGHT_7 = OPCODE(0x94); +constexpr int8_t F3DEX2_G_MWO_aLIGHT_8 = OPCODE(0xa8); +constexpr int8_t F3DEX2_G_MWO_bLIGHT_8 = OPCODE(0xac); + +/*===========================================================================* + * GBI Commands for S2DEX microcode + *===========================================================================*/ +/* GBI Header */ +constexpr int8_t F3DEX2_G_OBJ_RECTANGLE_R = OPCODE(0xda); +constexpr int8_t F3DEX2_G_OBJ_MOVEMEM = OPCODE(0xdc); +constexpr int8_t F3DEX2_G_RDPHALF_0 = OPCODE(0xe4); +constexpr int8_t F3DEX2_G_OBJ_RECTANGLE = OPCODE(0x01); +constexpr int8_t F3DEX2_G_OBJ_SPRITE = OPCODE(0x02); +constexpr int8_t F3DEX2_G_SELECT_DL = OPCODE(0x04); +constexpr int8_t F3DEX2_G_OBJ_LOADTXTR = OPCODE(0x05); +constexpr int8_t F3DEX2_G_OBJ_LDTX_SPRITE = OPCODE(0x06); +constexpr int8_t F3DEX2_G_OBJ_LDTX_RECT = OPCODE(0x07); +constexpr int8_t F3DEX2_G_OBJ_LDTX_RECT_R = OPCODE(0x08); +constexpr int8_t F3DEX2_G_BG_1CYC = OPCODE(0x09); +constexpr int8_t F3DEX2_G_BG_COPY = OPCODE(0x0a); +constexpr int8_t F3DEX2_G_OBJ_RENDERMODE = OPCODE(0x0b); \ No newline at end of file diff --git a/libultraship/include/fast/interpreter.h b/libultraship/include/fast/interpreter.h new file mode 100644 index 000000000..4c6a705c3 --- /dev/null +++ b/libultraship/include/fast/interpreter.h @@ -0,0 +1,576 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fast/lus_gbi.h" +#include "fast/types.h" +#include "fast/ucodehandlers.h" +#include "backends/gfx_rendering_api.h" +#include "fast/debug/GfxDebugger.h" + +#include "fast/resource/type/Texture.h" +#include "ship/resource/Resource.h" + +// TODO figure out why changing these to 640x480 makes the game only render in a quarter of the window +#define SCREEN_WIDTH 320 +#define SCREEN_HEIGHT 240 + +#include +#include + +#ifdef __cplusplus +#include +#endif + +/*enum { + CC_0, + CC_TEXEL0, + CC_TEXEL1, + CC_PRIM, + CC_SHADE, + CC_ENV, + CC_TEXEL0A, + CC_LOD +};*/ + +enum { + SHADER_0, + SHADER_INPUT_1, + SHADER_INPUT_2, + SHADER_INPUT_3, + SHADER_INPUT_4, + SHADER_INPUT_5, + SHADER_INPUT_6, + SHADER_INPUT_7, + SHADER_TEXEL0, + SHADER_TEXEL0A, + SHADER_TEXEL1, + SHADER_TEXEL1A, + SHADER_1, + SHADER_COMBINED, + SHADER_NOISE +}; + +#ifdef __cplusplus +enum class ShaderOpts { + ALPHA, + FOG, + TEXTURE_EDGE, + NOISE, + _2CYC, + ALPHA_THRESHOLD, + INVISIBLE, + GRAYSCALE, + TEXEL0_CLAMP_S, + TEXEL0_CLAMP_T, + TEXEL1_CLAMP_S, + TEXEL1_CLAMP_T, + TEXEL0_MASK, + TEXEL1_MASK, + TEXEL0_BLEND, + TEXEL1_BLEND, + PRIM_DEPTH, + PRISM_SHADER, // 16-bit width + MAX +}; + +#define SHADER_OPT(opt) ((uint64_t)(1 << static_cast(ShaderOpts::opt))) +#endif + +struct ColorCombinerKey { + uint64_t combine_mode; + uint64_t options; + uint64_t shader_id; + +#ifdef __cplusplus + auto operator<=>(const ColorCombinerKey&) const = default; +#endif +}; + +#define SHADER_MAX_TEXTURES 6 +#define SHADER_FIRST_TEXTURE 0 +#define SHADER_FIRST_MASK_TEXTURE 2 +#define SHADER_FIRST_REPLACEMENT_TEXTURE 4 + +struct CCFeatures { + int c[2][2][4]; + bool opt_alpha; + bool opt_fog; + bool opt_texture_edge; + bool opt_noise; + bool opt_2cyc; + bool opt_alpha_threshold; + bool opt_invisible; + bool opt_grayscale; + bool opt_prim_depth; + bool usedTextures[2]; + bool used_masks[2]; + bool used_blend[2]; + bool clamp[2][2]; + int numInputs; + bool do_single[2][2]; + bool do_multiply[2][2]; + bool do_mix[2][2]; + bool color_alpha_same[2]; + int16_t shader_id; +}; + +void gfx_cc_get_features(uint64_t shader_id0, uint64_t shader_id1, struct CCFeatures* cc_features); + +union Gfx; + +namespace Fast { + +class GfxRenderingAPI; +class GfxWindowBackend; + +constexpr size_t MAX_SEGMENT_POINTERS = 16; +constexpr size_t SHADER_ID_SHIFT = 17; +constexpr int16_t ShaderIdUnmask(int id) { + return (id >> SHADER_ID_SHIFT) & 0xFFFF; +} + +struct GfxExecStack { + // This is a dlist stack used to handle dlist calls. + std::stack cmd_stack = {}; + // This is also a dlist stack but a std::vector is used to make it possible + // to iterate on the elements. + // The purpose of this is to identify an instruction at a poin in time + // which would not be possible with just a F3DGfx* because a dlist can be called multiple times + // what we do instead is store the call path that leads to the instruction (including branches) + std::vector gfx_path = {}; + struct CodeDisp { + const char* file; + int line; + }; + // stack for OpenDisp/CloseDisps + std::vector disp_stack{}; + + void start(F3DGfx* dlist); + void stop(); + F3DGfx*& currCmd(); + void openDisp(const char* file, int line); + void closeDisp(); + const std::vector& getDisp() const; + void branch(F3DGfx* caller); + void call(F3DGfx* caller, F3DGfx* callee); + F3DGfx* ret(); +}; + +struct XYWidthHeight { + int16_t x, y; + uint32_t width, height; +}; + +struct GfxDimensions { + float internal_mul; + uint32_t width, height; + float aspect_ratio; +}; + +struct TextureCacheKey { + const uint8_t* texture_addr; + const uint8_t* palette_addrs[2]; + uint8_t fmt, siz; + uint8_t palette_index; + uint32_t size_bytes; + + bool operator==(const TextureCacheKey&) const noexcept = default; + + struct Hasher { + size_t operator()(const TextureCacheKey& key) const noexcept { + uintptr_t addr = (uintptr_t)key.texture_addr; + return (size_t)(addr ^ (addr >> 5)); + } + }; +}; + +typedef std::unordered_map TextureCacheMap; +typedef std::pair TextureCacheNode; + +struct TextureCacheValue { + uint32_t texture_id; + uint8_t cms, cmt; + bool linear_filter; + + std::list::iterator lru_location; +}; + +struct TextureCacheMapIter { + TextureCacheMap::iterator it; +}; + +struct RGBA { + uint8_t r, g, b, a; +}; + +struct LoadedVertex { + float x, y, z, w; + float u, v; + struct RGBA color; + uint8_t clip_rej; +}; + +struct RawTexMetadata { + uint16_t width, height; + float h_byte_scale = 1, v_pixel_scale = 1; + std::shared_ptr resource; + Fast::TextureType type; +}; + +#define MAX_LIGHTS 32 +#define MAX_VERTICES 64 + +struct RSP { + float modelview_matrix_stack[11][4][4]; + uint8_t modelview_matrix_stack_size; + + float MP_matrix[4][4]; + float P_matrix[4][4]; + + F3DLight_t lookat[2]; + F3DLight current_lights[MAX_LIGHTS + 1]; + float current_lights_coeffs[MAX_LIGHTS][3]; + float current_lookat_coeffs[2][3]; // lookat_x, lookat_y + uint8_t current_num_lights; // includes ambient light + bool lights_changed; + + uint32_t geometry_mode; + int16_t fog_mul, fog_offset; + + uint32_t extra_geometry_mode; + + struct { + // U0.16 + uint16_t s, t; + } texture_scaling_factor; + + struct LoadedVertex loaded_vertices[MAX_VERTICES + 4]; +}; + +struct RDP { + const uint8_t* palettes[2]; + // Original DRAM source address of the most recent TLUT load per palette half. + // Used in texture cache keys instead of palettes[] (which always points to staging). + const uint8_t* palette_dram_addr[2]; + // CI4 palette staging buffer: N64 TMEM holds up to 16 CI4 palettes (16 entries x 2 bytes each = 32 bytes per + // palette). palettes[0] covers indices 0-7 (256 bytes), palettes[1] covers 8-15 (256 bytes). GfxDpLoadTlut copies + // TLUT data here at the correct offset so multi-palette CI4 models work. + uint8_t palette_staging[2][256]; + struct { + const uint8_t* addr; + uint8_t siz; + uint32_t width; + uint32_t tex_flags; + struct RawTexMetadata raw_tex_metadata; + } texture_to_load; + struct { + const uint8_t* addr; + uint32_t orig_size_bytes; + uint32_t size_bytes; + uint32_t full_image_line_size_bytes; + uint32_t line_size_bytes; + uint32_t tex_flags; + struct RawTexMetadata raw_tex_metadata; + bool masked; + bool blended; + } loaded_texture[2]; + struct { + uint8_t fmt; + uint8_t siz; + uint8_t cms, cmt; + uint8_t masks, maskt; // mask exponents from SetTile; 2^mask is the WRAP/MIRROR period + uint8_t shifts, shiftt; + float uls, ult, lrs, lrt; + uint16_t tmem; // 0-511, in 64-bit word units + uint32_t line_size_bytes; + uint8_t palette; + uint8_t tmem_index; // 0 or 1 for offset 0 kB or offset 2 kB, respectively + } texture_tile[8]; + bool textures_changed[2]; + + uint8_t first_tile_index; + + uint32_t other_mode_l, other_mode_h; + uint64_t combine_mode; + bool grayscale; + + uint8_t prim_lod_fraction; + uint16_t prim_depth; + struct RGBA env_color, prim_color, fog_color, blend_color, fill_color, grayscale_color; + + // Chroma key parameters (G_SETKEYR / G_SETKEYGB) + struct RGBA key_center; + struct RGBA key_scale; + int16_t convert_k[6]; // YUV convert coefficients (G_SETCONVERT) — K0-K5 + + struct XYWidthHeight viewport, scissor; + bool viewport_or_scissor_changed; + void* z_buf_address; + void* color_image_address; +}; + +typedef enum Attribute { + MTX_PROJECTION, + MTX_LOAD, + MTX_PUSH, + MTX_NOPUSH, + CULL_FRONT, + CULL_BACK, + CULL_BOTH, + MV_VIEWPORT, + MV_LIGHT, +} Attribute; + +extern GfxExecStack g_exec_stack; + +struct GfxTextureCache { + TextureCacheMap map; + std::list lru; + std::vector free_texture_ids; +}; + +struct ColorCombiner { + uint64_t shader_id0; + uint64_t shader_id1; + bool usedTextures[2]; + struct ShaderProgram* prg[16]; + uint8_t shader_input_mapping[2][7]; +}; + +struct RenderingState { + uint8_t depth_test_and_mask; // 1: depth test, 2: depth mask + bool decal_mode; + bool alpha_blend; + struct XYWidthHeight viewport, scissor; + struct ShaderProgram* mShaderProgram; + TextureCacheNode* mTextures[SHADER_MAX_TEXTURES]; +}; + +struct FBInfo { + uint32_t orig_width, orig_height; // Original shape + uint32_t applied_width, applied_height; // Up-scaled for the viewport + uint32_t native_width, native_height; // Max "native" size of the screen, used for up-scaling + bool resize; // Scale to match the viewport + bool forceFixedAspect; // Preserve aspect ratio even if resize is true +}; + +struct MaskedTextureEntry { + uint8_t* mask; + uint8_t* replacementData; +}; + +class Interpreter { + public: + Interpreter(); + ~Interpreter(); + + void Init(GfxWindowBackend* wapi, class GfxRenderingAPI* rapi, const char* game_name, bool start_in_fullscreen, + uint32_t width, uint32_t height, uint32_t posX, uint32_t posY); + void Destroy(); + void SetGfxDebugger(std::shared_ptr debugger); + std::shared_ptr GetGfxDebugger() const; + void GetDimensions(uint32_t* width, uint32_t* height, int32_t* posX, int32_t* posY); + GfxRenderingAPI* GetCurrentRenderingAPI(); + void StartFrame(); + void RunGuiOnly(); + void Run(Gfx* commands, const std::unordered_map& mtx_replacements); + void EndFrame(); + void HandleWindowEvents(); + bool IsFrameReady(); + bool ViewportMatchesRendererResolution(); + int GetTargetFps(); + void SetTargetFps(int fps); + void SetMaxFrameLatency(int latency); + int CreateFrameBuffer(uint32_t width, uint32_t height, uint32_t native_width, uint32_t native_height, + uint8_t resize, bool forceFixedAspect = false); + void SetFrameBuffer(int fb, float noiseScale); + void CopyFrameBuffer(int fb_dst_id, int fb_src_id, bool copyOnce, bool* hasCopiedPtr); + void ResetFrameBuffer(); + void AdjustPixelDepthCoordinates(float& x, float& y); + void GetPixelDepthPrepare(float x, float y); + uint16_t GetPixelDepth(float x, float y); + void RegisterBlendedTexture(const char* name, uint8_t* mask, uint8_t* replacement); + void UnregisterBlendedTexture(const char* name); + + // Register a CPU address as a mirror of a GPU framebuffer texture. + // When ImportTexture encounters this address, it uses SelectTextureFb instead + // of reading from CPU memory — giving full GPU resolution with no readback. + void RegisterFbTexture(const void* cpuAddr, int fbId); + void UnregisterFbTexture(const void* cpuAddr); + + void SetNativeDimensions(float width, float height); + void SetResolutionMultiplier(float multiplier); + void SetMsaaLevel(uint32_t level); + void GetCurDimensions(uint32_t* width, uint32_t* height); + + // private: TODO make these private + void Flush(); + ShaderProgram* LookupOrCreateShaderProgram(uint64_t id0, uint64_t id1); + ColorCombiner* LookupOrCreateColorCombiner(const ColorCombinerKey& key); + void ShaderCacheClear(); + void TextureCacheClear(); + std::shared_ptr ResolveResourceCached(const char* path); + bool TextureCacheLookup(int i, const TextureCacheKey& key); + void TextureCacheDelete(const uint8_t* origAddr); + void ImportTextureRgba16(int tile, bool importReplacement); + void ImportTextureRgba32(int tile, bool importReplacement); + void ImportTextureIA4(int tile, bool importReplacement); + void ImportTextureIA8(int tile, bool importReplacement); + void ImportTextureIA16(int tile, bool importReplacement); + void ImportTextureI4(int tile, bool importReplacement); + void ImportTextureI8(int tile, bool importReplacement); + void ImportTextureCi4(int tile, bool importReplacement); + void ImportTextureCi8(int tile, bool importReplacement); + void ImportTextureRaw(int tile, bool importReplacement); + void ImportTextureImg(int tile, bool importReplacement); + void ImportTexture(int i, int tile, bool importReplacement); + void ImportTextureMask(int i, int tile); + void CalculateNormalDir(const F3DLight_t*, float coeffs[3]); + // Opt-in memoization of OTR texture-path resolution, keyed by display-list + // pointer and dropped with the texture cache. Safe for ports whose display + // lists carry stable path pointers; off by default. + void SetResolvedResourceCacheEnabled(bool enabled); + + void GfxSpMatrix(uint8_t params, const int32_t* addr); + void GfxSpPopMatrix(uint32_t count); + void GfxSpVertex(size_t numVertices, size_t destIndex, const F3DVtx* vertices); + void GfxSpModifyVertex(uint16_t vtxIdx, uint8_t where, uint32_t val); + void GfxSpTri1(uint8_t vtx1Idx, uint8_t vtx2Idx, uint8_t vtx3Idx, bool isRect); + void GfxSpGeometryMode(uint32_t clear, uint32_t set); + void GfxSpExtraGeometryMode(uint32_t clear, uint32_t set); + void GfxSpMovememF3dex2(uint8_t index, uint8_t offset, const void* data); + void GfxSpMovememF3d(uint8_t index, uint8_t offset, const void* data); + void GfxSpMovewordF3dex2(uint8_t index, uint16_t offset, uintptr_t data); + void GfxSpMovewordF3d(uint8_t index, uint16_t offset, uintptr_t data); + void GfxSpTexture(uint16_t sc, uint16_t tc, uint8_t level, uint8_t tile, uint8_t on); + void GfxDpSetScissor(uint32_t mode, uint32_t ulx, uint32_t uly, uint32_t lrx, uint32_t lry); + void GfxDpSetTextureImage(uint32_t format, uint32_t size, uint32_t width, const char* texPath, uint32_t texFlags, + RawTexMetadata rawTexMetdata, const void* addr); + void GfxDpSetTile(uint8_t fmt, uint32_t siz, uint32_t line, uint32_t tmem, uint8_t tile, uint32_t palette, + uint32_t cmt, uint32_t maskt, uint32_t shiftt, uint32_t cms, uint32_t masks, uint32_t shifts); + void GfxDpSetTileSize(uint8_t tile, uint16_t uls, uint16_t ult, uint16_t lrs, uint16_t lrt); + void GfxDpLoadTlut(uint8_t tile, uint32_t high_index); + void GfxDpLoadBlock(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t lrs, uint32_t dxt); + void GfxDpLoadTile(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t lrs, uint32_t lrt); + void GfxDpSetCombineMode(uint32_t rgb, uint32_t alpha, uint32_t rgb_cyc2, uint32_t alpha_cyc2); + void GfxDpSetGrayscaleColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a); + void GfxDpSetEnvColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a); + void GfxDpSetPrimColor(uint8_t m, uint8_t r, uint8_t l, uint8_t g, uint8_t b, uint8_t a); + void GfxDpSetFogColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a); + void GfxDpSetBlendColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a); + void GfxDpSetFillColor(uint32_t pickedColor); + void GfxDrawRectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry); + void GfxDpTextureRectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry, uint8_t tile, int16_t uls, + int16_t ult, int16_t dsdx, int16_t dtdy, bool flip); + void GfxDpImageRectangle(int32_t tile, int32_t w, int32_t h, int32_t ulx, int32_t uly, int16_t uls, int16_t ult, + int32_t lrx, int32_t lry, int16_t lrs, int16_t lrt); + void GfxDpFillRectangle(int32_t ulx, int32_t uly, int32_t lrx, int32_t lry); + void GfxDpSetZImage(void* zBufAddr); + void GfxDpSetColorImage(uint32_t format, uint32_t size, uint32_t width, void* address); + void GfxSpSetOtherMode(uint32_t shift, uint32_t num_bits, uint64_t mode); + void GfxDpSetOtherMode(uint32_t h, uint32_t l); + + void Gfxs2dexBgCopy(F3DuObjBg* bg); + void Gfxs2dexBg1cyc(F3DuObjBg* bg); + void Gfxs2dexRecyCopy(F3DuObjSprite* spr); + + void AdjustWidthHeightForScale(uint32_t& width, uint32_t& height, uint32_t nativeWidth, + uint32_t nativeHeight) const; + float AdjXForAspectRatio(float x) const; + void AdjustVIewportOrScissor(XYWidthHeight* area); + void CalcAndSetViewport(const F3DVp_t* viewport); + + void SpReset(); + void* SegAddr(uintptr_t w1); + + static const char* CCMUXtoStr(uint32_t ccmux); + static const char* ACMUXtoStr(uint32_t acmux); + static void GenerateCC(ColorCombiner* comb, const ColorCombinerKey& key); + static std::string_view GetBaseTexturePath(std::string_view path); + static void NormalizeVector(float v[3]); + static void TransposedMatrixMul(float res[3], const float a[3], const float b[4][4]); + static void MatrixMul(float res[4][4], const float a[4][4], const float b[4][4]); + + RSP* mRsp; + RDP* mRdp; + RenderingState mRenderingState{}; + + GfxTextureCache mTextureCache{}; + std::unordered_map> mResolvedResourceCache; + bool mResolvedResourceCacheEnabled = false; + std::map mColorCombinerPool; // color_combiner_pool; + std::map::iterator mPrevCombiner = mColorCombinerPool.end(); + uint8_t* mTexUploadBuffer = nullptr; + + GfxDimensions mGfxCurrentWindowDimensions{}; // gfx_current_window_dimensions; + int32_t mCurWindowPosX{}; + int32_t mCurWindowPosY{}; + GfxDimensions mCurDimensions{}; // gfx_current_dimensions; + GfxDimensions mPrvDimensions{}; // gfx_prev_dimensions; + XYWidthHeight mGameWindowViewport{}; // gfx_current_game_window_viewport; + XYWidthHeight mNativeDimensions{}; // gfx_native_dimensions; + XYWidthHeight mPrevNativeDimensions{}; // gfx_prev_native_dimensions; + uintptr_t mGfxFrameBuffer{}; + + unsigned int mMsaaLevel = 1; + bool mDroppedFrame{}; + float* mBufVbo; // 3 vertices in a triangle and 32 floats per vtx + size_t mBufVboLen{}; + size_t mBufVboNumTris{}; + GfxWindowBackend* mWapi = nullptr; + GfxRenderingAPI* mRapi = nullptr; + std::shared_ptr mGfxDebugger; + + uintptr_t mSegmentPointers[MAX_SEGMENT_POINTERS]{}; + + bool mFbActive{}; + bool mRendersToFb{}; // game_renders_to_framebuffer; + std::map::iterator mActiveFrameBuffer; + std::map mFrameBuffers; + + int mGameFb{}; // game_framebuffer; + int mGameFbMsaaResolved{}; // game_framebuffer_msaa_resolved; + + std::set> mGetPixelDepthPending; // get_pixel_depth_pending; + std::unordered_map, uint16_t, hash_pair_ff> mGetPixelDepthCached; // get_pixel_depth_cached; + std::map> mMaskedTextures; + std::unordered_map mFbTextures; // CPU addr -> GPU FB id + + const std::unordered_map* mCurMtxReplacements; + bool mMarkerOn; // This was originally a debug feature. Now it seems to control s2dex? + std::unordered_map mShaders; + + typedef size_t ShaderId; + std::stack mShaderStack; + size_t mShadersIndex; + int mInterpolationIndex; + int mInterpolationIndexTarget; + // Interpolation factor for the current rendered frame within a game tick: + // 0 = previous tick, 1 = current tick. Set by the port before each + // DrawAndRunGraphicsCommands call, like mInterpolationIndex. + float mInterpolationT = 1.0f; +}; + +void gfx_set_target_ucode(UcodeHandlers ucode); +void gfx_push_current_dir(char* path); +int32_t gfx_check_image_signature(const char* imgData); +const char* gfx_get_shader(int16_t id); +const char* GfxGetOpcodeName(int8_t opcode); + +} // namespace Fast + +extern "C" void gfx_texture_cache_clear(); +extern "C" void gfx_shader_cache_clear(); +extern "C" int gfx_create_framebuffer(uint32_t width, uint32_t height, uint32_t native_width, uint32_t native_height, + uint8_t resize, bool forceFixedAspect = false); \ No newline at end of file diff --git a/libultraship/include/fast/lus_gbi.h b/libultraship/include/fast/lus_gbi.h new file mode 100644 index 000000000..77bdf8bed --- /dev/null +++ b/libultraship/include/fast/lus_gbi.h @@ -0,0 +1,1380 @@ +#pragma once +#include +namespace Fast { +#define OPCODE(x) (int8_t)(x) + +#include "f3dex.h" +#include "f3dex2.h" + +/* RDP commands: */ +constexpr int8_t RDP_G_SETCIMG = OPCODE(0xff); /* -1 */ +constexpr int8_t RDP_G_SETZIMG = OPCODE(0xfe); /* -2 */ +constexpr int8_t RDP_G_SETTIMG = OPCODE(0xfd); /* -3 */ +constexpr int8_t RDP_G_SETCOMBINE = OPCODE(0xfc); /* -4 */ +constexpr int8_t RDP_G_SETENVCOLOR = OPCODE(0xfb); /* -5 */ +constexpr int8_t RDP_G_SETPRIMCOLOR = OPCODE(0xfa); /* -6 */ +constexpr int8_t RDP_G_SETBLENDCOLOR = OPCODE(0xf9); /* -7 */ +constexpr int8_t RDP_G_SETFOGCOLOR = OPCODE(0xf8); /* -8 */ +constexpr int8_t RDP_G_SETFILLCOLOR = OPCODE(0xf7); /* -9 */ +constexpr int8_t RDP_G_FILLRECT = OPCODE(0xf6); /* -10 */ +constexpr int8_t RDP_G_SETTILE = OPCODE(0xf5); /* -11 */ +constexpr int8_t RDP_G_LOADTILE = OPCODE(0xf4); /* -12 */ +constexpr int8_t RDP_G_LOADBLOCK = OPCODE(0xf3); /* -13 */ +constexpr int8_t RDP_G_SETTILESIZE = OPCODE(0xf2); /* -14 */ +constexpr int8_t RDP_G_LOADTLUT = OPCODE(0xf0); /* -16 */ +constexpr int8_t RDP_G_RDPSETOTHERMODE = OPCODE(0xef); /* -17 */ +constexpr int8_t RDP_G_SETPRIMDEPTH = OPCODE(0xee); /* -18 */ +constexpr int8_t RDP_G_SETSCISSOR = OPCODE(0xed); /* -19 */ +constexpr int8_t RDP_G_SETCONVERT = OPCODE(0xec); /* -20 */ +constexpr int8_t RDP_G_SETKEYR = OPCODE(0xeb); /* -21 */ +constexpr int8_t RDP_G_SETKEYGB = OPCODE(0xea); /* -22 */ +constexpr int8_t RDP_G_RDPFULLSYNC = OPCODE(0xe9); /* -23 */ +constexpr int8_t RDP_G_RDPTILESYNC = OPCODE(0xe8); /* -24 */ +constexpr int8_t RDP_G_RDPPIPESYNC = OPCODE(0xe7); /* -25 */ +constexpr int8_t RDP_G_RDPLOADSYNC = OPCODE(0xe6); /* -26 */ +constexpr int8_t RDP_G_TEXRECTFLIP = OPCODE(0xe5); /* -27 */ +constexpr int8_t RDP_G_TEXRECT = OPCODE(0xe4); /* -28 */ + +// CUSTOM OTR COMMANDS +constexpr int8_t OTR_G_SETTIMG_OTR_HASH = OPCODE(0x20); +constexpr int8_t OTR_G_SETFB = OPCODE(0x21); +constexpr int8_t OTR_G_RESETFB = OPCODE(0x22); +constexpr int8_t OTR_G_SETTIMG_FB = OPCODE(0x23); +constexpr int8_t OTR_G_VTX_OTR_FILEPATH = OPCODE(0x24); +constexpr int8_t OTR_G_SETTIMG_OTR_FILEPATH = OPCODE(0x25); +constexpr int8_t OTR_G_TRI1_OTR = OPCODE(0x26); +constexpr int8_t OTR_G_DL_OTR_FILEPATH = OPCODE(0x27); +constexpr int8_t OTR_G_PUSHCD = OPCODE(0x28); +constexpr int8_t OTR_G_MTX_OTR_FILEPATH = OPCODE(0x29); +constexpr int8_t OTR_G_DL_OTR_HASH = OPCODE(0x31); +constexpr int8_t OTR_G_VTX_OTR_HASH = OPCODE(0x32); +constexpr int8_t OTR_G_MARKER = OPCODE(0x33); +constexpr int8_t OTR_G_INVALTEXCACHE = OPCODE(0x34); +constexpr int8_t OTR_G_BRANCH_Z_OTR = OPCODE(0x35); +constexpr int8_t OTR_G_MTX_OTR = OPCODE(0x36); +constexpr int8_t OTR_G_TEXRECT_WIDE = OPCODE(0x37); +constexpr int8_t OTR_G_FILLWIDERECT = OPCODE(0x38); + +/* GFX Effects */ + +// RDP Cmd +constexpr int8_t OTR_G_SETGRAYSCALE = OPCODE(0x39); +constexpr int8_t OTR_G_EXTRAGEOMETRYMODE = OPCODE(0x3a); +constexpr int8_t OTR_G_COPYFB = OPCODE(0x3b); +constexpr int8_t OTR_G_IMAGERECT = OPCODE(0x3c); +constexpr int8_t OTR_G_DL_INDEX = OPCODE(0x3d); +constexpr int8_t OTR_G_READFB = OPCODE(0x3e); +constexpr int8_t OTR_G_REGBLENDEDTEX = OPCODE(0x3f); +constexpr int8_t OTR_G_SETINTENSITY = OPCODE(0x40); +constexpr int8_t OTR_G_MOVEMEM_HASH = OPCODE(0x42); +constexpr int8_t OTR_G_PUSH_SHADER = OPCODE(0x43); +constexpr int8_t OTR_G_POP_SHADER = OPCODE(0x44); +constexpr int8_t RDP_G_SETTILESIZE_INTERP = OPCODE(0x45); +constexpr int8_t RDP_G_SETTARGETINTERPINDEX = OPCODE(0x46); +constexpr int8_t RDP_G_LOADBLOCK_WIDE = OPCODE(0x47); +constexpr int8_t RDP_G_VTX_WIDE = OPCODE(0x48); +constexpr int8_t RDP_G_TRI1_WIDE = OPCODE(0x49); +constexpr int8_t RDP_G_SETTILESIZE_LERP = OPCODE(0x4a); + +/* + * The following commands are the "generated" RDP commands; the user + * never sees them, the RSP microcode generates them. + * + * The layout of the bits is magical, to save work in the ucode. + * These id's are -56, -52, -54, -50, -55, -51, -53, -49, ... + * edge, shade, texture, zbuff bits: estz + */ +#define G_TRI_FILL 0xc8 /* fill triangle: 11001000 */ +#define G_TRI_SHADE 0xcc /* shade triangle: 11001100 */ +#define G_TRI_TXTR 0xca /* texture triangle: 11001010 */ +#define G_TRI_SHADE_TXTR 0xce /* shade, texture triangle: 11001110 */ +#define G_TRI_FILL_ZBUFF 0xc9 /* fill, zbuff triangle: 11001001 */ +#define G_TRI_SHADE_ZBUFF 0xcd /* shade, zbuff triangle: 11001101 */ +#define G_TRI_TXTR_ZBUFF 0xcb /* texture, zbuff triangle: 11001011 */ +#define G_TRI_SHADE_TXTR_ZBUFF 0xcf /* shade, txtr, zbuff trngl: 11001111 */ + +/* + * A TRI_FILL triangle is just the edges. You need to set the DP + * to use primcolor, in order to see anything. (it is NOT a triangle + * that gets rendered in 'fill mode'. Triangles can't be rendered + * in 'fill mode') + * + * A TRI_SHADE is a gouraud triangle that has colors interpolated. + * Flat-shaded triangles (from the software) are still gouraud shaded, + * it's just the colors are all the same and the deltas are 0. + * + * Other triangle types, and combinations are more obvious. + */ + +/* masks to build RDP triangle commands: */ +#define G_RDP_TRI_FILL_MASK 0x08 +#define G_RDP_TRI_SHADE_MASK 0x04 +#define G_RDP_TRI_TXTR_MASK 0x02 +#define G_RDP_TRI_ZBUFF_MASK 0x01 + +/* + * HACK: + * This is a dreadful hack. For version 1.0 hardware, there are still + * some 'bowtie' hangs. This parameter can be increased to avoid + * the hangs. Every increase of 4 chops one scanline off of every + * triangle. Values of 4,8,12 should be sufficient to avoid any + * bowtie hang. + * + * Change this value, then recompile ALL of your program (including static + * display lists!) + * + * THIS WILL BE REMOVED FOR HARDWARE VERSION 2.0! + */ +#define BOWTIE_VAL 0 + +/* gets added to RDP command, in order to test for addres fixup: */ +#define G_RDP_ADDR_FIXUP 3 /* |RDP cmds| <= this, do addr fixup */ +#ifdef _LANGUAGE_ASSEMBLY +#define G_RDP_TEXRECT_CHECK ((-1 * G_TEXRECTFLIP) & 0xff) +#endif + +/* macros for command parsing: */ +#define GDMACMD(x) (x) +#ifdef GIMMCMD +#undef GIMMCMD +#endif +#define GIMMCMD(x) = OPCODE(G_IMMFIRST - (x)) +#define GRDPCMD(x) (0xff - (x)) + +#define G_DMACMDSIZ 128 +#define G_IMMCMDSIZ 64 +#define G_RDPCMDSIZ 64 + +/* + * Coordinate shift values, number of bits of fraction + */ +#define G_TEXTURE_IMAGE_FRAC 2 +#define G_TEXTURE_SCALE_FRAC 16 +#define G_SCALE_FRAC 8 +#define G_ROTATE_FRAC 16 + +/* + * Parameters to graphics commands + */ + +/* + * Data packing macros + */ + +/* + * Maximum z-buffer value, used to initialize the z-buffer. + * Note : this number is NOT the viewport z-scale constant. + * See the comment next to G_MAXZ for more info. + */ +#define G_MAXFBZ 0x3fff /* 3b exp, 11b mantissa */ + +#define GPACK_RGBA5551(r, g, b, a) ((((r) << 8) & 0xf800) | (((g) << 3) & 0x7c0) | (((b) >> 2) & 0x3e) | ((a)&0x1)) +#define GPACK_ZDZ(z, dz) ((z) << 2 | (dz)) + +/* + * flags for G_SETGEOMETRYMODE + * (this rendering state is maintained in RSP) + * + * DO NOT USE THE LOW 8 BITS OF GEOMETRYMODE: + * The weird bit-ordering is for the micro-code: the lower byte + * can be OR'd in with G_TRI_SHADE (11001100) to construct + * the triangle command directly. Don't break it... + * + * DO NOT USE THE HIGH 8 BITS OF GEOMETRYMODE: + * The high byte is OR'd with 0x703 to form the clip code mask. + * If it is set to 0x04, this will cause near clipping to occur. + * If it is zero, near clipping will not occur. + * + * Further explanation: + * G_SHADE is necessary in order to see the color that you passed + * down with the vertex. If G_SHADE isn't set, you need to set the DP + * appropriately and use primcolor to see anything. + * + * G_SHADING_SMOOTH enabled means use all 3 colors of the triangle. + * If it is not set, then do 'flat shading', where only one vertex color + * is used (and all 3 vertices are set to that same color by the ucode) + * See the man page for gSP1Triangle(). + * + */ + +#define G_ZBUFFER 0x00000001 +#define G_SHADE 0x00000004 +#define G_FOG 0x00010000 +#define G_LIGHTING 0x00020000 +#define G_TEXTURE_GEN 0x00040000 +#define G_TEXTURE_GEN_LINEAR 0x00080000 +#define G_LOD 0x00100000 +#define G_LIGHTING_POSITIONAL 0x00400000 + +/* + * G_EXTRAGEOMETRY flags: set extra custom geometry modes + */ +#define G_EX_INVERT_CULLING 0x00000001 +#define G_EX_ALWAYS_EXECUTE_BRANCH 0x00000002 + +/* + * G_SETIMG fmt: set image formats + */ +#define G_IM_FMT_RGBA 0 +#define G_IM_FMT_YUV 1 +#define G_IM_FMT_CI 2 +#define G_IM_FMT_IA 3 +#define G_IM_FMT_I 4 + +/* + * G_SETIMG siz: set image pixel size + */ +#define G_IM_SIZ_4b 0 +#define G_IM_SIZ_8b 1 +#define G_IM_SIZ_16b 2 +#define G_IM_SIZ_32b 3 +#define G_IM_SIZ_DD 5 + +#define G_IM_SIZ_4b_BYTES 0 +#define G_IM_SIZ_4b_TILE_BYTES G_IM_SIZ_4b_BYTES +#define G_IM_SIZ_4b_LINE_BYTES G_IM_SIZ_4b_BYTES + +#define G_IM_SIZ_8b_BYTES 1 +#define G_IM_SIZ_8b_TILE_BYTES G_IM_SIZ_8b_BYTES +#define G_IM_SIZ_8b_LINE_BYTES G_IM_SIZ_8b_BYTES + +#define G_IM_SIZ_16b_BYTES 2 +#define G_IM_SIZ_16b_TILE_BYTES G_IM_SIZ_16b_BYTES +#define G_IM_SIZ_16b_LINE_BYTES G_IM_SIZ_16b_BYTES + +#define G_IM_SIZ_32b_BYTES 4 +#define G_IM_SIZ_32b_TILE_BYTES 2 +#define G_IM_SIZ_32b_LINE_BYTES 2 + +#define G_IM_SIZ_4b_LOAD_BLOCK G_IM_SIZ_16b +#define G_IM_SIZ_8b_LOAD_BLOCK G_IM_SIZ_16b +#define G_IM_SIZ_16b_LOAD_BLOCK G_IM_SIZ_16b +#define G_IM_SIZ_32b_LOAD_BLOCK G_IM_SIZ_32b + +#define G_IM_SIZ_4b_SHIFT 2 +#define G_IM_SIZ_8b_SHIFT 1 +#define G_IM_SIZ_16b_SHIFT 0 +#define G_IM_SIZ_32b_SHIFT 0 + +#define G_IM_SIZ_4b_INCR 3 +#define G_IM_SIZ_8b_INCR 1 +#define G_IM_SIZ_16b_INCR 0 +#define G_IM_SIZ_32b_INCR 0 + +/* + * Texturing macros + */ + +/* These are also defined defined above for Sprite Microcode */ + +#define G_TX_LOADTILE 7 +#define G_TX_RENDERTILE 0 + +#define G_TX_NOMIRROR 0 +#define G_TX_WRAP 0 +#define G_TX_MIRROR 0x1 +#define G_TX_CLAMP 0x2 +#define G_TX_NOMASK 0 +#define G_TX_NOLOD 0 + +/* + * G_SETCOMBINE: color combine modes + */ +/* Color combiner constants: */ +#define G_CCMUX_COMBINED 0 +#define G_CCMUX_TEXEL0 1 +#define G_CCMUX_TEXEL1 2 +#define G_CCMUX_PRIMITIVE 3 +#define G_CCMUX_SHADE 4 +#define G_CCMUX_ENVIRONMENT 5 +#define G_CCMUX_CENTER 6 +#define G_CCMUX_SCALE 6 +#define G_CCMUX_COMBINED_ALPHA 7 +#define G_CCMUX_TEXEL0_ALPHA 8 +#define G_CCMUX_TEXEL1_ALPHA 9 +#define G_CCMUX_PRIMITIVE_ALPHA 10 +#define G_CCMUX_SHADE_ALPHA 11 +#define G_CCMUX_ENV_ALPHA 12 +#define G_CCMUX_LOD_FRACTION 13 +#define G_CCMUX_PRIM_LOD_FRAC 14 +#define G_CCMUX_NOISE 7 +#define G_CCMUX_K4 7 +#define G_CCMUX_K5 15 +#define G_CCMUX_1 6 +#define G_CCMUX_0 31 +/* Chroma-key center/scale and YUV-convert K4/K5 combiner inputs. */ +#define G_CCMUX_KEY_CENTER 20 +#define G_CCMUX_KEY_SCALE 21 +#define G_CCMUX_CONVERT_K4 22 +#define G_CCMUX_CONVERT_K5 23 + +/* Alpha combiner constants: */ +#define G_ACMUX_COMBINED 0 +#define G_ACMUX_TEXEL0 1 +#define G_ACMUX_TEXEL1 2 +#define G_ACMUX_PRIMITIVE 3 +#define G_ACMUX_SHADE 4 +#define G_ACMUX_ENVIRONMENT 5 +#define G_ACMUX_LOD_FRACTION 0 +#define G_ACMUX_PRIM_LOD_FRAC 6 +#define G_ACMUX_1 6 +#define G_ACMUX_0 7 + +/* typical CC cycle 1 modes */ +#define G_CC_PRIMITIVE 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE +#define G_CC_SHADE 0, 0, 0, SHADE, 0, 0, 0, SHADE +#define G_CC_MODULATEI TEXEL0, 0, SHADE, 0, 0, 0, 0, SHADE +#define G_CC_MODULATEIA TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0 +#define G_CC_MODULATEIDECALA TEXEL0, 0, SHADE, 0, 0, 0, 0, TEXEL0 +#define G_CC_MODULATERGB G_CC_MODULATEI +#define G_CC_MODULATERGBA G_CC_MODULATEIA +#define G_CC_MODULATERGBDECALA G_CC_MODULATEIDECALA +#define G_CC_MODULATEI_PRIM TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE +#define G_CC_MODULATEIA_PRIM TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, PRIMITIVE, 0 +#define G_CC_MODULATEIDECALA_PRIM TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, TEXEL0 +#define G_CC_MODULATERGB_PRIM G_CC_MODULATEI_PRIM +#define G_CC_MODULATERGBA_PRIM G_CC_MODULATEIA_PRIM +#define G_CC_MODULATERGBDECALA_PRIM G_CC_MODULATEIDECALA_PRIM +#define G_CC_DECALRGB 0, 0, 0, TEXEL0, 0, 0, 0, SHADE +#define G_CC_DECALRGBA 0, 0, 0, TEXEL0, 0, 0, 0, TEXEL0 +#define G_CC_BLENDI ENVIRONMENT, SHADE, TEXEL0, SHADE, 0, 0, 0, SHADE +#define G_CC_BLENDIA ENVIRONMENT, SHADE, TEXEL0, SHADE, TEXEL0, 0, SHADE, 0 +#define G_CC_BLENDIDECALA ENVIRONMENT, SHADE, TEXEL0, SHADE, 0, 0, 0, TEXEL0 +#define G_CC_BLENDRGBA TEXEL0, SHADE, TEXEL0_ALPHA, SHADE, 0, 0, 0, SHADE +#define G_CC_BLENDRGBDECALA TEXEL0, SHADE, TEXEL0_ALPHA, SHADE, 0, 0, 0, TEXEL0 +#define G_CC_ADDRGB 1, 0, TEXEL0, SHADE, 0, 0, 0, SHADE +#define G_CC_ADDRGBDECALA 1, 0, TEXEL0, SHADE, 0, 0, 0, TEXEL0 +#define G_CC_REFLECTRGB ENVIRONMENT, 0, TEXEL0, SHADE, 0, 0, 0, SHADE +#define G_CC_REFLECTRGBDECALA ENVIRONMENT, 0, TEXEL0, SHADE, 0, 0, 0, TEXEL0 +#define G_CC_HILITERGB PRIMITIVE, SHADE, TEXEL0, SHADE, 0, 0, 0, SHADE +#define G_CC_HILITERGBA PRIMITIVE, SHADE, TEXEL0, SHADE, PRIMITIVE, SHADE, TEXEL0, SHADE +#define G_CC_HILITERGBDECALA PRIMITIVE, SHADE, TEXEL0, SHADE, 0, 0, 0, TEXEL0 +#define G_CC_SHADEDECALA 0, 0, 0, SHADE, 0, 0, 0, TEXEL0 +#define G_CC_BLENDPE PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, SHADE, 0 +#define G_CC_BLENDPEDECALA PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, 0, 0, 0, TEXEL0 + +/* oddball modes */ +#define _G_CC_BLENDPE ENVIRONMENT, PRIMITIVE, TEXEL0, PRIMITIVE, TEXEL0, 0, SHADE, 0 +#define _G_CC_BLENDPEDECALA ENVIRONMENT, PRIMITIVE, TEXEL0, PRIMITIVE, 0, 0, 0, TEXEL0 +#define _G_CC_TWOCOLORTEX PRIMITIVE, SHADE, TEXEL0, SHADE, 0, 0, 0, SHADE +/* used for 1-cycle sparse mip-maps, primitive color has color of lowest LOD */ +#define _G_CC_SPARSEST PRIMITIVE, TEXEL0, LOD_FRACTION, TEXEL0, PRIMITIVE, TEXEL0, LOD_FRACTION, TEXEL0 +#define G_CC_TEMPLERP TEXEL1, TEXEL0, PRIM_LOD_FRAC, TEXEL0, TEXEL1, TEXEL0, PRIM_LOD_FRAC, TEXEL0 + +/* typical CC cycle 1 modes, usually followed by other cycle 2 modes */ +#define G_CC_TRILERP TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0 +#define G_CC_INTERFERENCE TEXEL0, 0, TEXEL1, 0, TEXEL0, 0, TEXEL1, 0 + +/* + * One-cycle color convert operation + */ +#define G_CC_1CYUV2RGB TEXEL0, K4, K5, TEXEL0, 0, 0, 0, SHADE + +/* + * NOTE: YUV2RGB expects TF step1 color conversion to occur in 2nd clock. + * Therefore, CC looks for step1 results in TEXEL1 + */ +#define G_CC_YUV2RGB TEXEL1, K4, K5, TEXEL1, 0, 0, 0, 0 + +/* typical CC cycle 2 modes */ +#define G_CC_PASS2 0, 0, 0, COMBINED, 0, 0, 0, COMBINED +#define G_CC_MODULATEI2 COMBINED, 0, SHADE, 0, 0, 0, 0, SHADE +#define G_CC_MODULATEIA2 COMBINED, 0, SHADE, 0, COMBINED, 0, SHADE, 0 +#define G_CC_MODULATERGB2 G_CC_MODULATEI2 +#define G_CC_MODULATERGBA2 G_CC_MODULATEIA2 +#define G_CC_MODULATEI_PRIM2 COMBINED, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE +#define G_CC_MODULATEIA_PRIM2 COMBINED, 0, PRIMITIVE, 0, COMBINED, 0, PRIMITIVE, 0 +#define G_CC_MODULATERGB_PRIM2 G_CC_MODULATEI_PRIM2 +#define G_CC_MODULATERGBA_PRIM2 G_CC_MODULATEIA_PRIM2 +#define G_CC_DECALRGB2 0, 0, 0, COMBINED, 0, 0, 0, SHADE +/* + * ? +#define G_CC_DECALRGBA2 COMBINED, SHADE, COMBINED_ALPHA, SHADE, 0, 0, 0, SHADE +*/ +#define G_CC_BLENDI2 ENVIRONMENT, SHADE, COMBINED, SHADE, 0, 0, 0, SHADE +#define G_CC_BLENDIA2 ENVIRONMENT, SHADE, COMBINED, SHADE, COMBINED, 0, SHADE, 0 +#define G_CC_CHROMA_KEY2 TEXEL0, CENTER, SCALE, 0, 0, 0, 0, 0 +#define G_CC_HILITERGB2 ENVIRONMENT, COMBINED, TEXEL0, COMBINED, 0, 0, 0, SHADE +#define G_CC_HILITERGBA2 ENVIRONMENT, COMBINED, TEXEL0, COMBINED, ENVIRONMENT, COMBINED, TEXEL0, COMBINED +#define G_CC_HILITERGBDECALA2 ENVIRONMENT, COMBINED, TEXEL0, COMBINED, 0, 0, 0, TEXEL0 +#define G_CC_HILITERGBPASSA2 ENVIRONMENT, COMBINED, TEXEL0, COMBINED, 0, 0, 0, COMBINED + +/* + * G_SETOTHERMODE_L sft: shift count + */ +#define G_MDSFT_ALPHACOMPARE 0 +#define G_MDSFT_ZSRCSEL 2 +#define G_MDSFT_RENDERMODE 3 +#define G_MDSFT_BLENDER 16 + +/* + * G_SETOTHERMODE_H sft: shift count + */ +#define G_MDSFT_BLENDMASK 0 /* unsupported */ +#define G_MDSFT_ALPHADITHER 4 +#define G_MDSFT_RGBDITHER 6 + +#define G_MDSFT_COMBKEY 8 +#define G_MDSFT_TEXTCONV 9 +#define G_MDSFT_TEXTFILT 12 +#define G_MDSFT_TEXTLUT 14 +#define G_MDSFT_TEXTLOD 16 +#define G_MDSFT_TEXTDETAIL 17 +#define G_MDSFT_TEXTPERSP 19 +#define G_MDSFT_CYCLETYPE 20 +#define G_MDSFT_COLORDITHER 22 /* unsupported in HW 2.0 */ +#define G_MDSFT_PIPELINE 23 + +/* G_SETOTHERMODE_H gPipelineMode */ +#define G_PM_1PRIMITIVE (1 << G_MDSFT_PIPELINE) +#define G_PM_NPRIMITIVE (0 << G_MDSFT_PIPELINE) + +/* G_SETOTHERMODE_H gSetCycleType */ +#define G_CYC_1CYCLE (0 << G_MDSFT_CYCLETYPE) +#define G_CYC_2CYCLE (1 << G_MDSFT_CYCLETYPE) +#define G_CYC_COPY (2 << G_MDSFT_CYCLETYPE) +#define G_CYC_FILL (3 << G_MDSFT_CYCLETYPE) + +/* G_SETOTHERMODE_H gSetTexturePersp */ +#define G_TP_NONE (0 << G_MDSFT_TEXTPERSP) +#define G_TP_PERSP (1 << G_MDSFT_TEXTPERSP) + +/* G_SETOTHERMODE_H gSetTextureDetail */ +#define G_TD_CLAMP (0 << G_MDSFT_TEXTDETAIL) +#define G_TD_SHARPEN (1 << G_MDSFT_TEXTDETAIL) +#define G_TD_DETAIL (2 << G_MDSFT_TEXTDETAIL) + +/* G_SETOTHERMODE_H gSetTextureLOD */ +#define G_TL_TILE (0 << G_MDSFT_TEXTLOD) +#define G_TL_LOD (1 << G_MDSFT_TEXTLOD) + +/* G_SETOTHERMODE_H gSetTextureLUT */ +#define G_TT_NONE (0 << G_MDSFT_TEXTLUT) +#define G_TT_RGBA16 (2 << G_MDSFT_TEXTLUT) +#define G_TT_IA16 (3 << G_MDSFT_TEXTLUT) + +/* G_SETOTHERMODE_H gSetTextureFilter */ +#define G_TF_POINT (0 << G_MDSFT_TEXTFILT) +#define G_TF_AVERAGE (3 << G_MDSFT_TEXTFILT) +#define G_TF_BILERP (2 << G_MDSFT_TEXTFILT) + +/* G_SETOTHERMODE_H gSetTextureConvert */ +#define G_TC_CONV (0 << G_MDSFT_TEXTCONV) +#define G_TC_FILTCONV (5 << G_MDSFT_TEXTCONV) +#define G_TC_FILT (6 << G_MDSFT_TEXTCONV) + +/* G_SETOTHERMODE_H gSetCombineKey */ +#define G_CK_NONE (0 << G_MDSFT_COMBKEY) +#define G_CK_KEY (1 << G_MDSFT_COMBKEY) + +/* G_SETOTHERMODE_H gSetColorDither */ +#define G_CD_MAGICSQ (0 << G_MDSFT_RGBDITHER) +#define G_CD_BAYER (1 << G_MDSFT_RGBDITHER) +#define G_CD_NOISE (2 << G_MDSFT_RGBDITHER) + +#ifndef _HW_VERSION_1 +#define G_CD_DISABLE (3 << G_MDSFT_RGBDITHER) +#define G_CD_ENABLE G_CD_NOISE /* HW 1.0 compatibility mode */ +#else +#define G_CD_ENABLE (1 << G_MDSFT_COLORDITHER) +#define G_CD_DISABLE (0 << G_MDSFT_COLORDITHER) +#endif + +/* G_SETOTHERMODE_H gSetAlphaDither */ +#define G_AD_PATTERN (0 << G_MDSFT_ALPHADITHER) +#define G_AD_NOTPATTERN (1 << G_MDSFT_ALPHADITHER) +#define G_AD_NOISE (2 << G_MDSFT_ALPHADITHER) +#define G_AD_DISABLE (3 << G_MDSFT_ALPHADITHER) + +/* G_SETOTHERMODE_L gSetAlphaCompare */ +#define G_AC_NONE (0 << G_MDSFT_ALPHACOMPARE) +#define G_AC_THRESHOLD (1 << G_MDSFT_ALPHACOMPARE) +#define G_AC_DITHER (3 << G_MDSFT_ALPHACOMPARE) + +/* G_SETOTHERMODE_L gSetDepthSource */ +#define G_ZS_PIXEL (0 << G_MDSFT_ZSRCSEL) +#define G_ZS_PRIM (1 << G_MDSFT_ZSRCSEL) + +/* G_SETOTHERMODE_L gSetRenderMode */ +#define AA_EN 0x8 +#define Z_CMP 0x10 +#define Z_UPD 0x20 +#define IM_RD 0x40 +#define CLR_ON_CVG 0x80 +#define CVG_DST_CLAMP 0 +#define CVG_DST_WRAP 0x100 +#define CVG_DST_FULL 0x200 +#define CVG_DST_SAVE 0x300 +#define ZMODE_OPA 0 +#define ZMODE_INTER 0x400 +#define ZMODE_XLU 0x800 +#define ZMODE_DEC 0xc00 +#define CVG_X_ALPHA 0x1000 +#define ALPHA_CVG_SEL 0x2000 +#define FORCE_BL 0x4000 +#define TEX_EDGE 0x0000 /* used to be 0x8000 */ + +#define G_BL_CLR_IN 0 +#define G_BL_CLR_MEM 1 +#define G_BL_CLR_BL 2 +#define G_BL_CLR_FOG 3 +#define G_BL_1MA 0 +#define G_BL_A_MEM 1 +#define G_BL_A_IN 0 +#define G_BL_A_FOG 1 +#define G_BL_A_SHADE 2 +#define G_BL_1 2 +#define G_BL_0 3 + +#define GBL_c1(m1a, m1b, m2a, m2b) (uint32_t)(m1a) << 30 | (m1b) << 26 | (m2a) << 22 | (m2b) << 18 +#define GBL_c2(m1a, m1b, m2a, m2b) (m1a) << 28 | (m1b) << 24 | (m2a) << 20 | (m2b) << 16 + +#define RM_AA_ZB_OPA_SURF(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_RA_ZB_OPA_SURF(clk) \ + AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_ZB_XLU_SURF(clk) \ + AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | FORCE_BL | ZMODE_XLU | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_OPA_DECAL(clk) \ + AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | ALPHA_CVG_SEL | ZMODE_DEC | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_RA_ZB_OPA_DECAL(clk) \ + AA_EN | Z_CMP | CVG_DST_WRAP | ALPHA_CVG_SEL | ZMODE_DEC | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_ZB_XLU_DECAL(clk) \ + AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | FORCE_BL | ZMODE_DEC | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_OPA_INTER(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ALPHA_CVG_SEL | ZMODE_INTER | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_RA_ZB_OPA_INTER(clk) \ + AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP | ALPHA_CVG_SEL | ZMODE_INTER | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_ZB_XLU_INTER(clk) \ + AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | FORCE_BL | ZMODE_INTER | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_XLU_LINE(clk) \ + AA_EN | Z_CMP | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | FORCE_BL | ZMODE_XLU | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_DEC_LINE(clk) \ + AA_EN | Z_CMP | IM_RD | CVG_DST_SAVE | CVG_X_ALPHA | ALPHA_CVG_SEL | FORCE_BL | ZMODE_DEC | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_TEX_EDGE(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_ZB_TEX_INTER(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_INTER | TEX_EDGE | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_ZB_SUB_SURF(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_ZB_PCL_SURF(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | G_AC_DITHER | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_OPA_TERR(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_TEX_TERR(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_SUB_TERR(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_OPA_SURF(clk) \ + AA_EN | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_RA_OPA_SURF(clk) \ + AA_EN | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_XLU_SURF(clk) \ + AA_EN | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | FORCE_BL | ZMODE_OPA | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_XLU_LINE(clk) \ + AA_EN | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_DEC_LINE(clk) \ + AA_EN | IM_RD | CVG_DST_FULL | CVG_X_ALPHA | ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_TEX_EDGE(clk) \ + AA_EN | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_SUB_SURF(clk) \ + AA_EN | IM_RD | CVG_DST_FULL | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_PCL_SURF(clk) \ + AA_EN | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | G_AC_DITHER | GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_OPA_TERR(clk) \ + AA_EN | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_TEX_TERR(clk) \ + AA_EN | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_SUB_TERR(clk) \ + AA_EN | IM_RD | CVG_DST_FULL | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_ZB_OPA_SURF(clk) \ + Z_CMP | Z_UPD | CVG_DST_FULL | ALPHA_CVG_SEL | ZMODE_OPA | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_ZB_XLU_SURF(clk) \ + Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_XLU | GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_ZB_OPA_DECAL(clk) \ + Z_CMP | CVG_DST_FULL | ALPHA_CVG_SEL | ZMODE_DEC | GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_ZB_XLU_DECAL(clk) \ + Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_DEC | GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_ZB_CLD_SURF(clk) \ + Z_CMP | IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_XLU | GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_ZB_OVL_SURF(clk) \ + Z_CMP | IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_DEC | GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_ZB_PCL_SURF(clk) \ + Z_CMP | Z_UPD | CVG_DST_FULL | ZMODE_OPA | G_AC_DITHER | GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + +#define RM_OPA_SURF(clk) CVG_DST_CLAMP | FORCE_BL | ZMODE_OPA | GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + +#define RM_XLU_SURF(clk) \ + IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_OPA | GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_TEX_EDGE(clk) \ + CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA | TEX_EDGE | AA_EN | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + +#define RM_CLD_SURF(clk) \ + IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_OPA | GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_PCL_SURF(clk) \ + CVG_DST_FULL | FORCE_BL | ZMODE_OPA | G_AC_DITHER | GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + +#define RM_ADD(clk) \ + IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_OPA | GBL_c##clk(G_BL_CLR_IN, G_BL_A_FOG, G_BL_CLR_MEM, G_BL_1) + +#define RM_NOOP(clk) GBL_c##clk(0, 0, 0, 0) + +#define RM_VISCVG(clk) IM_RD | FORCE_BL | GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_BL, G_BL_A_MEM) + +/* for rendering to an 8-bit framebuffer */ +#define RM_OPA_CI(clk) CVG_DST_CLAMP | ZMODE_OPA | GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + +#define G_RM_AA_ZB_OPA_SURF RM_AA_ZB_OPA_SURF(1) +#define G_RM_AA_ZB_OPA_SURF2 RM_AA_ZB_OPA_SURF(2) +#define G_RM_AA_ZB_XLU_SURF RM_AA_ZB_XLU_SURF(1) +#define G_RM_AA_ZB_XLU_SURF2 RM_AA_ZB_XLU_SURF(2) +#define G_RM_AA_ZB_OPA_DECAL RM_AA_ZB_OPA_DECAL(1) +#define G_RM_AA_ZB_OPA_DECAL2 RM_AA_ZB_OPA_DECAL(2) +#define G_RM_AA_ZB_XLU_DECAL RM_AA_ZB_XLU_DECAL(1) +#define G_RM_AA_ZB_XLU_DECAL2 RM_AA_ZB_XLU_DECAL(2) +#define G_RM_AA_ZB_OPA_INTER RM_AA_ZB_OPA_INTER(1) +#define G_RM_AA_ZB_OPA_INTER2 RM_AA_ZB_OPA_INTER(2) +#define G_RM_AA_ZB_XLU_INTER RM_AA_ZB_XLU_INTER(1) +#define G_RM_AA_ZB_XLU_INTER2 RM_AA_ZB_XLU_INTER(2) +#define G_RM_AA_ZB_XLU_LINE RM_AA_ZB_XLU_LINE(1) +#define G_RM_AA_ZB_XLU_LINE2 RM_AA_ZB_XLU_LINE(2) +#define G_RM_AA_ZB_DEC_LINE RM_AA_ZB_DEC_LINE(1) +#define G_RM_AA_ZB_DEC_LINE2 RM_AA_ZB_DEC_LINE(2) +#define G_RM_AA_ZB_TEX_EDGE RM_AA_ZB_TEX_EDGE(1) +#define G_RM_AA_ZB_TEX_EDGE2 RM_AA_ZB_TEX_EDGE(2) +#define G_RM_AA_ZB_TEX_INTER RM_AA_ZB_TEX_INTER(1) +#define G_RM_AA_ZB_TEX_INTER2 RM_AA_ZB_TEX_INTER(2) +#define G_RM_AA_ZB_SUB_SURF RM_AA_ZB_SUB_SURF(1) +#define G_RM_AA_ZB_SUB_SURF2 RM_AA_ZB_SUB_SURF(2) +#define G_RM_AA_ZB_PCL_SURF RM_AA_ZB_PCL_SURF(1) +#define G_RM_AA_ZB_PCL_SURF2 RM_AA_ZB_PCL_SURF(2) +#define G_RM_AA_ZB_OPA_TERR RM_AA_ZB_OPA_TERR(1) +#define G_RM_AA_ZB_OPA_TERR2 RM_AA_ZB_OPA_TERR(2) +#define G_RM_AA_ZB_TEX_TERR RM_AA_ZB_TEX_TERR(1) +#define G_RM_AA_ZB_TEX_TERR2 RM_AA_ZB_TEX_TERR(2) +#define G_RM_AA_ZB_SUB_TERR RM_AA_ZB_SUB_TERR(1) +#define G_RM_AA_ZB_SUB_TERR2 RM_AA_ZB_SUB_TERR(2) + +#define G_RM_RA_ZB_OPA_SURF RM_RA_ZB_OPA_SURF(1) +#define G_RM_RA_ZB_OPA_SURF2 RM_RA_ZB_OPA_SURF(2) +#define G_RM_RA_ZB_OPA_DECAL RM_RA_ZB_OPA_DECAL(1) +#define G_RM_RA_ZB_OPA_DECAL2 RM_RA_ZB_OPA_DECAL(2) +#define G_RM_RA_ZB_OPA_INTER RM_RA_ZB_OPA_INTER(1) +#define G_RM_RA_ZB_OPA_INTER2 RM_RA_ZB_OPA_INTER(2) + +#define G_RM_AA_OPA_SURF RM_AA_OPA_SURF(1) +#define G_RM_AA_OPA_SURF2 RM_AA_OPA_SURF(2) +#define G_RM_AA_XLU_SURF RM_AA_XLU_SURF(1) +#define G_RM_AA_XLU_SURF2 RM_AA_XLU_SURF(2) +#define G_RM_AA_XLU_LINE RM_AA_XLU_LINE(1) +#define G_RM_AA_XLU_LINE2 RM_AA_XLU_LINE(2) +#define G_RM_AA_DEC_LINE RM_AA_DEC_LINE(1) +#define G_RM_AA_DEC_LINE2 RM_AA_DEC_LINE(2) +#define G_RM_AA_TEX_EDGE RM_AA_TEX_EDGE(1) +#define G_RM_AA_TEX_EDGE2 RM_AA_TEX_EDGE(2) +#define G_RM_AA_SUB_SURF RM_AA_SUB_SURF(1) +#define G_RM_AA_SUB_SURF2 RM_AA_SUB_SURF(2) +#define G_RM_AA_PCL_SURF RM_AA_PCL_SURF(1) +#define G_RM_AA_PCL_SURF2 RM_AA_PCL_SURF(2) +#define G_RM_AA_OPA_TERR RM_AA_OPA_TERR(1) +#define G_RM_AA_OPA_TERR2 RM_AA_OPA_TERR(2) +#define G_RM_AA_TEX_TERR RM_AA_TEX_TERR(1) +#define G_RM_AA_TEX_TERR2 RM_AA_TEX_TERR(2) +#define G_RM_AA_SUB_TERR RM_AA_SUB_TERR(1) +#define G_RM_AA_SUB_TERR2 RM_AA_SUB_TERR(2) + +#define G_RM_RA_OPA_SURF RM_RA_OPA_SURF(1) +#define G_RM_RA_OPA_SURF2 RM_RA_OPA_SURF(2) + +#define G_RM_ZB_OPA_SURF RM_ZB_OPA_SURF(1) +#define G_RM_ZB_OPA_SURF2 RM_ZB_OPA_SURF(2) +#define G_RM_ZB_XLU_SURF RM_ZB_XLU_SURF(1) +#define G_RM_ZB_XLU_SURF2 RM_ZB_XLU_SURF(2) +#define G_RM_ZB_OPA_DECAL RM_ZB_OPA_DECAL(1) +#define G_RM_ZB_OPA_DECAL2 RM_ZB_OPA_DECAL(2) +#define G_RM_ZB_XLU_DECAL RM_ZB_XLU_DECAL(1) +#define G_RM_ZB_XLU_DECAL2 RM_ZB_XLU_DECAL(2) +#define G_RM_ZB_CLD_SURF RM_ZB_CLD_SURF(1) +#define G_RM_ZB_CLD_SURF2 RM_ZB_CLD_SURF(2) +#define G_RM_ZB_OVL_SURF RM_ZB_OVL_SURF(1) +#define G_RM_ZB_OVL_SURF2 RM_ZB_OVL_SURF(2) +#define G_RM_ZB_PCL_SURF RM_ZB_PCL_SURF(1) +#define G_RM_ZB_PCL_SURF2 RM_ZB_PCL_SURF(2) + +#define G_RM_OPA_SURF RM_OPA_SURF(1) +#define G_RM_OPA_SURF2 RM_OPA_SURF(2) +#define G_RM_XLU_SURF RM_XLU_SURF(1) +#define G_RM_XLU_SURF2 RM_XLU_SURF(2) +#define G_RM_CLD_SURF RM_CLD_SURF(1) +#define G_RM_CLD_SURF2 RM_CLD_SURF(2) +#define G_RM_TEX_EDGE RM_TEX_EDGE(1) +#define G_RM_TEX_EDGE2 RM_TEX_EDGE(2) +#define G_RM_PCL_SURF RM_PCL_SURF(1) +#define G_RM_PCL_SURF2 RM_PCL_SURF(2) +#define G_RM_ADD RM_ADD(1) +#define G_RM_ADD2 RM_ADD(2) +#define G_RM_NOOP RM_NOOP(1) +#define G_RM_NOOP2 RM_NOOP(2) +#define G_RM_VISCVG RM_VISCVG(1) +#define G_RM_VISCVG2 RM_VISCVG(2) +#define G_RM_OPA_CI RM_OPA_CI(1) +#define G_RM_OPA_CI2 RM_OPA_CI(2) + +#define G_RM_FOG_SHADE_A GBL_c1(G_BL_CLR_FOG, G_BL_A_SHADE, G_BL_CLR_IN, G_BL_1MA) +#define G_RM_FOG_PRIM_A GBL_c1(G_BL_CLR_FOG, G_BL_A_FOG, G_BL_CLR_IN, G_BL_1MA) +#define G_RM_PASS GBL_c1(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + +/* + * G_SETCONVERT: K0-5 + */ +#define G_CV_K0 175 +#define G_CV_K1 -43 +#define G_CV_K2 -89 +#define G_CV_K3 222 +#define G_CV_K4 114 +#define G_CV_K5 42 + +/* + * G_SETSCISSOR: interlace mode + */ +#define G_SC_NON_INTERLACE 0 +#define G_SC_ODD_INTERLACE 3 +#define G_SC_EVEN_INTERLACE 2 + +/* flags to inhibit pushing of the display list (on branch) */ +#define G_DL_PUSH 0x00 +#define G_DL_NOPUSH 0x01 + +#if defined(_MSC_VER) || defined(__GNUC__) +#define _LANGUAGE_C +#endif + +/* + * BEGIN C-specific section: (typedef's) + */ +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* + * Data Structures + * + * NOTE: + * The DMA transfer hardware requires 64-bit aligned, 64-bit multiple- + * sized transfers. This important hardware optimization is unfortunately + * reflected in the programming interface, with some structures + * padded and alignment enforced. + * + * Since structures are aligned to the boundary of the "worst-case" + * element, we can't depend on the C compiler to align things + * properly. + * + * 64-bit structure alignment is enforced by wrapping structures with + * unions that contain a dummy "long long int". Why this works is + * explained in the ANSI C Spec, or on page 186 of the second edition + * of K&R, "The C Programming Language". + * + * The price we pay for this is a little awkwardness referencing the + * structures through the union. There is no memory penalty, since + * all the structures are at least 64-bits the dummy alignment field + * does not increase the size of the union. + * + * Static initialization of these union structures works because + * the ANSI C spec states that static initialization for unions + * works by using the first union element. We put the dummy alignment + * field last for this reason. + * + * (it's possible a newer 64-bit compiler from MIPS might make this + * easier with a flag, but we can't wait for it...) + * + */ + +/* + * Vertex (set up for use with colors) + */ +typedef struct { +#ifndef GBI_FLOATS + short ob[3]; /* x, y, z */ +#else + float ob[3]; /* x, y, z */ +#endif + unsigned short flag; + short tc[2]; /* texture coord */ + unsigned char cn[4]; /* color & alpha */ +} F3DVtx_t; + +/* + * Vertex (set up for use with normals) + */ +typedef struct { +#ifndef GBI_FLOATS + short ob[3]; /* x, y, z */ +#else + float ob[3]; /* x, y, z */ +#endif + unsigned short flag; + short tc[2]; /* texture coord */ + signed char n[3]; /* normal */ + unsigned char a; /* alpha */ +} F3DVtx_tn; + +typedef union F3DVtx { + F3DVtx_t v; /* Use this one for colors */ + F3DVtx_tn n; /* Use this one for normals */ + long long int force_structure_alignment; +} F3DVtx; + +/* + * Sprite structure + */ + +typedef struct F3DuSprite_t { + void* SourceImagePointer; + void* TlutPointer; + short Stride; + short SubImageWidth; + short SubImageHeight; + char SourceImageType; + char SourceImageBitSize; + short SourceImageOffsetS; + short SourceImageOffsetT; + /* 20 bytes for above */ + + /* padding to bring structure size to 64 bit allignment */ + char dummy[4]; + +} F3DuSprite_t; + +typedef union { + F3DuSprite_t s; + + /* Need to make sure this is 64 bit aligned */ + long long int force_structure_allignment[3]; +} F3DuSprite; + +/* + * Triangle face + */ +typedef struct { + unsigned char flag; + unsigned char v[3]; +} F3DTri; + +/* + * Viewport + */ + +/* + * + * This magic value is the maximum INTEGER z-range of the hardware + * (there are also 16-bits of fraction, which are introduced during + * any transformations). This is not just a good idea, it's the law. + * Feeding the hardware eventual z-coordinates (after any transforms + * or scaling) bigger than this, will not work. + * + * This number is DIFFERENT than G_MAXFBZ, which is the maximum value + * you want to use to initialize the z-buffer. + * + * The reason these are different is mildly interesting, but too long + * to explain here. It is basically the result of optimizations in the + * hardware. A more generic API might hide this detail from the users, + * but we don't have the ucode to do that... + * + */ +#define G_MAXZ 0x03ff /* 10 bits of integer screen-Z precision */ + +/* + * The viewport structure elements have 2 bits of fraction, necessary + * to accomodate the sub-pixel positioning scaling for the hardware. + * This can also be exploited to handle odd-sized viewports. + * + * Accounting for these fractional bits, using the default projection + * and viewing matrices, the viewport structure is initialized thusly: + * + * (SCREEN_WD/2)*4, (SCREEN_HT/2)*4, G_MAXZ, 0, + * (SCREEN_WD/2)*4, (SCREEN_HT/2)*4, 0, 0, + */ +typedef struct { + short vscale[4]; /* scale, 2 bits fraction */ + short vtrans[4]; /* translate, 2 bits fraction */ + /* both the above arrays are padded to 64-bit boundary */ +} F3DVp_t; + +typedef union { + F3DVp_t vp; + long long int force_structure_alignment; +} F3DVp; + +/* + * MOVEWORD indices + * + * Each of these indexes an entry in a dmem table + * which points to a word in dmem in dmem where + * an immediate word will be stored. + * + */ +#define G_MW_MATRIX 0x00 /* NOTE: also used by movemem */ +#define G_MW_NUMLIGHT 0x02 +#define G_MW_CLIP 0x04 +#define G_MW_SEGMENT 0x06 +#define G_MW_SEGMENT_INTERP 0x07 +#define G_MW_FOG 0x08 +#define G_MW_LIGHTCOL 0x0a +#define G_MW_PERSPNORM 0x0e + +/* + * These are offsets from the address in the dmem table + */ +#define G_MWO_NUMLIGHT 0x00 +#define G_MWO_CLIP_RNX 0x04 +#define G_MWO_CLIP_RNY 0x0c +#define G_MWO_CLIP_RPX 0x14 +#define G_MWO_CLIP_RPY 0x1c +#define G_MWO_SEGMENT_0 0x00 +#define G_MWO_SEGMENT_1 0x01 +#define G_MWO_SEGMENT_2 0x02 +#define G_MWO_SEGMENT_3 0x03 +#define G_MWO_SEGMENT_4 0x04 +#define G_MWO_SEGMENT_5 0x05 +#define G_MWO_SEGMENT_6 0x06 +#define G_MWO_SEGMENT_7 0x07 +#define G_MWO_SEGMENT_8 0x08 +#define G_MWO_SEGMENT_9 0x09 +#define G_MWO_SEGMENT_A 0x0a +#define G_MWO_SEGMENT_B 0x0b +#define G_MWO_SEGMENT_C 0x0c +#define G_MWO_SEGMENT_D 0x0d +#define G_MWO_SEGMENT_E 0x0e +#define G_MWO_SEGMENT_F 0x0f +#define G_MWO_FOG 0x00 +#define G_MWO_aLIGHT_1 0x00 +#define G_MWO_bLIGHT_1 0x04 +#define G_MWO_MATRIX_XX_XY_I 0x00 +#define G_MWO_MATRIX_XZ_XW_I 0x04 +#define G_MWO_MATRIX_YX_YY_I 0x08 +#define G_MWO_MATRIX_YZ_YW_I 0x0c +#define G_MWO_MATRIX_ZX_ZY_I 0x10 +#define G_MWO_MATRIX_ZZ_ZW_I 0x14 +#define G_MWO_MATRIX_WX_WY_I 0x18 +#define G_MWO_MATRIX_WZ_WW_I 0x1c +#define G_MWO_MATRIX_XX_XY_F 0x20 +#define G_MWO_MATRIX_XZ_XW_F 0x24 +#define G_MWO_MATRIX_YX_YY_F 0x28 +#define G_MWO_MATRIX_YZ_YW_F 0x2c +#define G_MWO_MATRIX_ZX_ZY_F 0x30 +#define G_MWO_MATRIX_ZZ_ZW_F 0x34 +#define G_MWO_MATRIX_WX_WY_F 0x38 +#define G_MWO_MATRIX_WZ_WW_F 0x3c +#define G_MWO_POINT_RGBA 0x10 +#define G_MWO_POINT_ST 0x14 +#define G_MWO_POINT_XYSCREEN 0x18 +#define G_MWO_POINT_ZSCREEN 0x1c + +/* + * Light structure. + * + * Note: only directional (infinite) lights are currently supported. + * + * Note: the weird order is for the DMEM alignment benefit of + * the microcode. + * + */ + +typedef struct { + unsigned char col[3]; /* diffuse light value (rgba) */ + char pad1; + unsigned char colc[3]; /* copy of diffuse light value (rgba) */ + char pad2; + signed char dir[3]; /* direction of light (normalized) */ + char pad3; +} F3DLight_t; + +typedef struct { + unsigned char col[3]; + unsigned char unk3; + unsigned char colc[3]; + unsigned char unk7; + short pos[3]; + unsigned char unkE; +} F3DPointLight_t; + +typedef struct { + unsigned char col[3]; /* ambient light value (rgba) */ + char pad1; + unsigned char colc[3]; /* copy of ambient light value (rgba) */ + char pad2; +} F3DAmbient_t; + +typedef struct { + int x1, y1, x2, y2; /* texture offsets for highlight 1/2 */ +} F3DHilite_t; + +typedef union { + F3DLight_t l; + F3DPointLight_t p; + long long int force_structure_alignment[2]; +} F3DLight; + +typedef union { + F3DAmbient_t l; + long long int force_structure_alignment[1]; +} F3DAmbient; + +typedef struct { + F3DAmbient a; + F3DLight l[7]; +} F3DLightsn; + +typedef struct { + F3DAmbient a; + F3DLight l[1]; +} F3DLights0; + +typedef struct { + F3DAmbient a; + F3DLight l[1]; +} F3DLights1; + +typedef struct { + F3DAmbient a; + F3DLight l[2]; +} F3DLights2; + +typedef struct { + F3DAmbient a; + F3DLight l[3]; +} F3DLights3; + +typedef struct { + F3DAmbient a; + F3DLight l[4]; +} F3DLights4; + +typedef struct { + F3DAmbient a; + F3DLight l[5]; +} F3DLights5; + +typedef struct { + F3DAmbient a; + F3DLight l[6]; +} F3DLights6; + +typedef struct { + F3DAmbient a; + F3DLight l[7]; +} F3DLights7; + +typedef struct { + F3DLight l[2]; +} F3DLookAt; + +typedef union { + F3DHilite_t h; + long int force_structure_alignment[4]; +} F3DHilite; + +#ifdef USE_GBI_TRACE +/* + * Trace structure + */ +typedef struct { + const char* file; + int idx; + bool valid; +} F3DTrace; +#endif + +/* + * Generic Gfx Packet + */ +typedef struct { + uintptr_t w0; + uintptr_t w1; +#ifdef USE_GBI_TRACE + F3DTrace trace; +#endif +} F3DGwords; + +#ifdef __cplusplus +#ifdef USE_GBI_TRACE +static_assert(sizeof(F3DGwords) == 2 * sizeof(void*) + sizeof(F3DTrace), "Display list size is bad"); +#else +static_assert(sizeof(F3DGwords) == 2 * sizeof(void*), "Display list size is bad"); +#endif +#endif + +/* + * This union is the fundamental type of the display list. + * It is, by law, exactly 64 bits in size. + */ +typedef union F3DGfx { + F3DGwords words; + long long int force_structure_alignment; +} F3DGfx; + +/*===========================================================================* + * GBI Commands for S2DEX microcode + *===========================================================================*/ +/* GBI Header */ +#define G_BGLT_LOADBLOCK 0x0033 +#define G_BGLT_LOADTILE 0xfff4 + +#define G_BG_FLAG_FLIPS 0x01 +#define G_BG_FLAG_FLIPT 0x10 + +/* Non scalable background plane */ +typedef struct { + unsigned short imageX; /* x-coordinate of upper-left position of texture (u10.5) */ + unsigned short imageW; /* width of the texture (u10.2) */ + short frameX; /* upper-left position of transferred frame (s10.2) */ + unsigned short frameW; /* width of transferred frame (u10.2) */ + + unsigned short imageY; /* y-coordinate of upper-left position of texture (u10.5) */ + unsigned short imageH; /* height of the texture (u10.2) */ + short frameY; /* upper-left position of transferred frame (s10.2) */ + unsigned short frameH; /* height of transferred frame (u10.2) */ + + unsigned long long int* imagePtr; /* texture source address on DRAM */ + unsigned short imageLoad; /* which to use, LoadBlock or LoadTile */ + unsigned char imageFmt; /* format of texel - G_IM_FMT_* */ + unsigned char imageSiz; /* size of texel - G_IM_SIZ_* */ + unsigned short imagePal; /* pallet number */ + unsigned short imageFlip; /* right & left image inversion (Inverted by G_BG_FLAG_FLIPS) */ + + /* The following is set in the initialization routine guS2DInitBg(). There is no need for the user to set it. */ + unsigned short tmemW; /* TMEM width and Word size of frame 1 line. + At LoadBlock, GS_PIX2TMEM(imageW/4,imageSiz) + At LoadTile GS_PIX2TMEM(frameW/4,imageSiz)+1 */ + unsigned short tmemH; /* height of TMEM loadable at a time (s13.2) 4 times value + When the normal texture, 512/tmemW*4 + When the CI texture, 256/tmemW*4 */ + unsigned short tmemLoadSH; /* SH value + At LoadBlock, tmemSize/2-1 + At LoadTile, tmemW*16-1 */ + unsigned short tmemLoadTH; /* TH value or Stride value + At LoadBlock, GS_CALC_DXT(tmemW) + At LoadTile, tmemH-1 */ + unsigned short tmemSizeW; /* skip value of imagePtr for image 1-line + At LoadBlock, tmemW*2 + At LoadTile, GS_PIX2TMEM(imageW/4,imageSiz)*2 */ + unsigned short tmemSize; /* skip value of imagePtr for 1-loading + = tmemSizeW*tmemH */ +} F3DuObjBg_t; /* 40 bytes */ + +/* Scalable background plane */ +typedef struct { + unsigned short imageX; /* x-coordinate of upper-left position of texture (u10.5) */ + unsigned short imageW; /* width of texture (u10.2) */ + short frameX; /* upper-left position of transferred frame (s10.2) */ + unsigned short frameW; /* width of transferred frame (u10.2) */ + + unsigned short imageY; /* y-coordinate of upper-left position of texture (u10.5) */ + unsigned short imageH; /* height of texture (u10.2) */ + short frameY; /* upper-left position of transferred frame (s10.2) */ + unsigned short frameH; /* height of transferred frame (u10.2) */ + + unsigned long long int* imagePtr; /* texture source address on DRAM */ + unsigned short imageLoad; /* Which to use, LoadBlock or LoadTile? */ + unsigned char imageFmt; /* format of texel - G_IM_FMT_* */ + unsigned char imageSiz; /* size of texel - G_IM_SIZ_* */ + unsigned short imagePal; /* pallet number */ + unsigned short imageFlip; /* right & left image inversion (Inverted by G_BG_FLAG_FLIPS) */ + + unsigned short scaleW; /* scale value of X-direction (u5.10) */ + unsigned short scaleH; /* scale value of Y-direction (u5.10) */ + int imageYorig; /* start point of drawing on image (s20.5) */ + + unsigned char padding[4]; + +} F3DuObjScaleBg_t; /* 40 bytes */ + +typedef union { + F3DuObjBg_t b; + F3DuObjScaleBg_t s; + long long int force_structure_alignment; +} F3DuObjBg; + +/*---------------------------------------------------------------------------* + * 2D Objects + *---------------------------------------------------------------------------*/ +#define G_OBJ_FLAG_FLIPS 1 << 0 /* inversion to S-direction */ +#define G_OBJ_FLAG_FLIPT 1 << 4 /* nversion to T-direction */ + +typedef struct { + short objX; /* s10.2 OBJ x-coordinate of upper-left end */ + unsigned short scaleW; /* u5.10 Scaling of u5.10 width direction */ + unsigned short imageW; /* u10.5 width of u10.5 texture (length of S-direction) */ + unsigned short paddingX; /* Unused - Always 0 */ + short objY; /* s10.2 OBJ y-coordinate of s10.2 OBJ upper-left end */ + unsigned short scaleH; /* u5.10 Scaling of u5.10 height direction */ + unsigned short imageH; /* u10.5 height of u10.5 texture (length of T-direction) */ + unsigned short paddingY; /* Unused - Always 0 */ + unsigned short imageStride; /* folding width of texel (In units of 64bit word) */ + unsigned short imageAdrs; /* texture header position in TMEM (In units of 64bit word) */ + unsigned char imageFmt; /* format of texel - G_IM_FMT_* */ + unsigned char imageSiz; /* size of texel - G_IM_SIZ_* */ + unsigned char imagePal; /* pallet number (0-7) */ + unsigned char imageFlags; /* The display flag - G_OBJ_FLAG_FLIP* */ +} F3DuObjSprite_t; /* 24 bytes */ + +typedef union { + F3DuObjSprite_t s; + long long int force_structure_alignment; +} F3DuObjSprite; + +/*---------------------------------------------------------------------------* + * 2D Matrix + *---------------------------------------------------------------------------*/ +typedef struct { + int A, B, C, D; /* s15.16 */ + short X, Y; /* s10.2 */ + unsigned short BaseScaleX; /* u5.10 */ + unsigned short BaseScaleY; /* u5.10 */ +} F3DuObjMtx_t; /* 24 bytes */ + +typedef union { + F3DuObjMtx_t m; + long long int force_structure_alignment; +} F3DuObjMtx; + +typedef struct { + short X, Y; /* s10.2 */ + unsigned short BaseScaleX; /* u5.10 */ + unsigned short BaseScaleY; /* u5.10 */ +} F3DuObjSubMtx_t; /* 8 bytes */ + +typedef union { + F3DuObjSubMtx_t m; + long long int force_structure_alignment; +} F3DuObjSubMtx; + +/*---------------------------------------------------------------------------* + * Loading into TMEM + *---------------------------------------------------------------------------*/ +#define G_OBJLT_TXTRBLOCK 0x00001033 +#define G_OBJLT_TXTRTILE 0x00fc1034 +#define G_OBJLT_TLUT 0x00000030 + +#define GS_TB_TSIZE(pix, siz) (GS_PIX2TMEM((pix), (siz)) - 1) +#define GS_TB_TLINE(pix, siz) (GS_CALC_DXT(GS_PIX2TMEM((pix), (siz)))) + +typedef struct { + unsigned int type; /* G_OBJLT_TXTRBLOCK divided into types */ + unsigned long long int* image; /* texture source address on DRAM */ + unsigned short tmem; /* loaded TMEM word address (8byteWORD) */ + unsigned short tsize; /* Texture size, Specified by macro GS_TB_TSIZE() */ + unsigned short tline; /* width of Texture 1-line, Specified by macro GS_TB_TLINE() */ + unsigned short sid; /* STATE ID Multipled by 4 (Either one of 0, 4, 8 and 12) */ + unsigned int flag; /* STATE flag */ + unsigned int mask; /* STATE mask */ +} F3DuObjTxtrBlock_t; /* 24 bytes */ + +#define GS_TT_TWIDTH(pix, siz) ((GS_PIX2TMEM((pix), (siz)) << 2) - 1) +#define GS_TT_THEIGHT(pix, siz) (((pix) << 2) - 1) + +typedef struct { + unsigned int type; /* G_OBJLT_TXTRTILE divided into types */ + unsigned long long int* image; /* texture source address on DRAM */ + unsigned short tmem; /* loaded TMEM word address (8byteWORD)*/ + unsigned short twidth; /* width of Texture (Specified by macro GS_TT_TWIDTH()) */ + unsigned short theight; /* height of Texture (Specified by macro GS_TT_THEIGHT()) */ + unsigned short sid; /* STATE ID Multipled by 4 (Either one of 0, 4, 8 and 12) */ + unsigned int flag; /* STATE flag */ + unsigned int mask; /* STATE mask */ +} F3DuObjTxtrTile_t; /* 24 bytes */ + +#define GS_PAL_HEAD(head) ((head) + 256) +#define GS_PAL_NUM(num) ((num)-1) + +typedef struct { + unsigned int type; /* G_OBJLT_TLUT divided into types */ + unsigned long long int* image; /* texture source address on DRAM */ + unsigned short phead; /* pallet number of load header (Between 256 and 511) */ + unsigned short pnum; /* loading pallet number -1 */ + unsigned short zero; /* Assign 0 all the time */ + unsigned short sid; /* STATE ID Multipled by 4 (Either one of 0, 4, 8 and 12)*/ + unsigned int flag; /* STATE flag */ + unsigned int mask; /* STATE mask */ +} F3DuObjTxtrTLUT_t; /* 24 bytes */ + +typedef union { + F3DuObjTxtrBlock_t block; + F3DuObjTxtrTile_t tile; + F3DuObjTxtrTLUT_t tlut; + long long int force_structure_alignment; +} F3DuObjTxtr; + +/*---------------------------------------------------------------------------* + * Loading into TMEM & 2D Objects + *---------------------------------------------------------------------------*/ +typedef struct { + F3DuObjTxtr txtr; + F3DuObjSprite sprite; +} F3DuObjTxSprite; /* 48 bytes */ +} +#endif diff --git a/libultraship/include/fast/resource/ResourceType.h b/libultraship/include/fast/resource/ResourceType.h new file mode 100644 index 000000000..a00fe30f0 --- /dev/null +++ b/libultraship/include/fast/resource/ResourceType.h @@ -0,0 +1,14 @@ +#pragma once + +namespace Fast { + +enum class ResourceType { + None = 0x00000000, + + DisplayList = 0x4F444C54, // ODLT + Light = 0x46669697, // LGTS + Matrix = 0x4F4D5458, // OMTX + Texture = 0x4F544558, // OTEX + Vertex = 0x4F565458, // OVTX +}; +} // namespace Fast diff --git a/libultraship/include/fast/resource/factory/DisplayListFactory.h b/libultraship/include/fast/resource/factory/DisplayListFactory.h new file mode 100644 index 000000000..05afcb751 --- /dev/null +++ b/libultraship/include/fast/resource/factory/DisplayListFactory.h @@ -0,0 +1,24 @@ +#pragma once + +#include "ship/resource/Resource.h" +#include "ship/resource/ResourceFactoryBinary.h" +#include "ship/resource/ResourceFactoryXML.h" + +namespace Fast { +class ResourceFactoryDisplayList { + protected: + uint32_t GetCombineLERPValue(const char* valStr); +}; + +class ResourceFactoryBinaryDisplayListV0 final : public ResourceFactoryDisplayList, public Ship::ResourceFactoryBinary { + public: + std::shared_ptr ReadResource(std::shared_ptr file, + std::shared_ptr initData) override; +}; + +class ResourceFactoryXMLDisplayListV0 final : public ResourceFactoryDisplayList, public Ship::ResourceFactoryXML { + public: + std::shared_ptr ReadResource(std::shared_ptr file, + std::shared_ptr initData) override; +}; +} // namespace Fast diff --git a/libultraship/include/fast/resource/factory/LightFactory.h b/libultraship/include/fast/resource/factory/LightFactory.h new file mode 100644 index 000000000..acf699f50 --- /dev/null +++ b/libultraship/include/fast/resource/factory/LightFactory.h @@ -0,0 +1,12 @@ +#pragma once + +#include "ship/resource/Resource.h" +#include "ship/resource/ResourceFactoryBinary.h" + +namespace Fast { +class ResourceFactoryBinaryLightV0 final : public Ship::ResourceFactoryBinary { + public: + std::shared_ptr ReadResource(std::shared_ptr file, + std::shared_ptr initData) override; +}; +} // namespace Fast \ No newline at end of file diff --git a/libultraship/include/fast/resource/factory/MatrixFactory.h b/libultraship/include/fast/resource/factory/MatrixFactory.h new file mode 100644 index 000000000..45425dadb --- /dev/null +++ b/libultraship/include/fast/resource/factory/MatrixFactory.h @@ -0,0 +1,12 @@ +#pragma once + +#include "ship/resource/Resource.h" +#include "ship/resource/ResourceFactoryBinary.h" + +namespace Fast { +class ResourceFactoryBinaryMatrixV0 final : public Ship::ResourceFactoryBinary { + public: + std::shared_ptr ReadResource(std::shared_ptr file, + std::shared_ptr initData) override; +}; +} // namespace Fast diff --git a/libultraship/include/fast/resource/factory/TextureFactory.h b/libultraship/include/fast/resource/factory/TextureFactory.h new file mode 100644 index 000000000..f561fda7b --- /dev/null +++ b/libultraship/include/fast/resource/factory/TextureFactory.h @@ -0,0 +1,18 @@ +#pragma once + +#include "ship/resource/Resource.h" +#include "ship/resource/ResourceFactoryBinary.h" + +namespace Fast { +class ResourceFactoryBinaryTextureV0 final : public Ship::ResourceFactoryBinary { + public: + std::shared_ptr ReadResource(std::shared_ptr file, + std::shared_ptr initData) override; +}; + +class ResourceFactoryBinaryTextureV1 final : public Ship::ResourceFactoryBinary { + public: + std::shared_ptr ReadResource(std::shared_ptr file, + std::shared_ptr initData) override; +}; +} // namespace Fast diff --git a/libultraship/include/fast/resource/factory/VertexFactory.h b/libultraship/include/fast/resource/factory/VertexFactory.h new file mode 100644 index 000000000..6333dbff4 --- /dev/null +++ b/libultraship/include/fast/resource/factory/VertexFactory.h @@ -0,0 +1,19 @@ +#pragma once + +#include "ship/resource/Resource.h" +#include "ship/resource/ResourceFactoryBinary.h" +#include "ship/resource/ResourceFactoryXML.h" + +namespace Fast { +class ResourceFactoryBinaryVertexV0 final : public Ship::ResourceFactoryBinary { + public: + std::shared_ptr ReadResource(std::shared_ptr file, + std::shared_ptr initData) override; +}; + +class ResourceFactoryXMLVertexV0 final : public Ship::ResourceFactoryXML { + public: + std::shared_ptr ReadResource(std::shared_ptr file, + std::shared_ptr initData) override; +}; +} // namespace Fast diff --git a/libultraship/include/fast/resource/type/DisplayList.h b/libultraship/include/fast/resource/type/DisplayList.h new file mode 100644 index 000000000..b356534c8 --- /dev/null +++ b/libultraship/include/fast/resource/type/DisplayList.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include "ship/resource/Resource.h" +#include "fast/ucodehandlers.h" +#include + +namespace Fast { +class DisplayList final : public Ship::Resource { + public: + using Resource::Resource; + + DisplayList(); + ~DisplayList(); + + Gfx* GetPointer() override; + size_t GetPointerSize() override; + + UcodeHandlers UCode; + std::vector Instructions; + std::vector Strings; +}; +} // namespace Fast diff --git a/libultraship/include/fast/resource/type/Light.h b/libultraship/include/fast/resource/type/Light.h new file mode 100644 index 000000000..12052589b --- /dev/null +++ b/libultraship/include/fast/resource/type/Light.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include "ship/resource/Resource.h" + +namespace Fast { + +/* + We have to keep the Pads since its probably an + issue from the sdk, because the documentation expects + RGBA, but 'Color' has space for RGB only. + https://ultra64.ca/files/documentation/online-manuals/functions_reference_manual_2.0i/gsp/gSPLight.html +*/ + +struct LightN64 { + uint8_t Color[3]; + int8_t Pad1; + uint8_t ColorCopy[3]; + int8_t Pad2; + uint8_t Direction[3]; + int8_t Pad3; +}; + +struct PointLightN64 { + uint8_t Color[3]; + uint8_t Unk0; + uint8_t ColorCopy[3]; + uint8_t Unk1; + int16_t Position[3]; + uint8_t Unk2; +}; + +union LightData { + LightN64 Light; + PointLightN64 PointLight; + long long int ForceAlignment[2]; +}; + +union AmbientData { + uint8_t Color[3]; + int8_t Pad1; + uint8_t ColorCopy[3]; + int8_t Pad2; +}; + +struct LightEntry { + AmbientData Ambient; + LightData Light; +}; + +class Light final : public Ship::Resource { + public: + using Resource::Resource; + + Light() : Resource(std::shared_ptr()) { + } + + LightEntry* GetPointer(); + size_t GetPointerSize(); + + private: + LightEntry mLight; + std::vector mLightData; +}; +} // namespace Fast \ No newline at end of file diff --git a/libultraship/include/fast/resource/type/Matrix.h b/libultraship/include/fast/resource/type/Matrix.h new file mode 100644 index 000000000..a820351bf --- /dev/null +++ b/libultraship/include/fast/resource/type/Matrix.h @@ -0,0 +1,18 @@ +#pragma once + +#include "ship/resource/Resource.h" +#include "fast/types.h" + +namespace Fast { +class Matrix final : public Ship::Resource { + public: + using Resource::Resource; + + Matrix(); + + Mtx* GetPointer() override; + size_t GetPointerSize() override; + + Mtx Matrx; +}; +} // namespace Fast diff --git a/libultraship/include/fast/resource/type/Texture.h b/libultraship/include/fast/resource/type/Texture.h new file mode 100644 index 000000000..f8575be06 --- /dev/null +++ b/libultraship/include/fast/resource/type/Texture.h @@ -0,0 +1,45 @@ +#pragma once + +#include "ship/resource/Resource.h" +#include +#include + +#define TEX_FLAG_LOAD_AS_RAW (1 << 0) +#define TEX_FLAG_LOAD_AS_IMG (1 << 1) + +namespace Fast { +enum class TextureType { + Error = 0, + RGBA32bpp = 1, + RGBA16bpp = 2, + Palette4bpp = 3, + Palette8bpp = 4, + Grayscale4bpp = 5, + Grayscale8bpp = 6, + GrayscaleAlpha4bpp = 7, + GrayscaleAlpha8bpp = 8, + GrayscaleAlpha16bpp = 9, +}; + +class Texture final : public Ship::Resource { + public: + using Resource::Resource; + + Texture(); + + uint8_t* GetPointer() override; + size_t GetPointerSize() override; + + TextureType Type; + uint16_t Width, Height; + uint32_t Flags = 0; + float HByteScale = 1.0; + float VPixelScale = 1.0; + uint32_t ImageDataSize; + uint8_t* ImageData = nullptr; + // When set, ImageData points into this buffer and must not be delete[]-ed. + std::shared_ptr> mImageBuffer; + + ~Texture(); +}; +} // namespace Fast diff --git a/libultraship/include/fast/resource/type/Vertex.h b/libultraship/include/fast/resource/type/Vertex.h new file mode 100644 index 000000000..3fec39a8f --- /dev/null +++ b/libultraship/include/fast/resource/type/Vertex.h @@ -0,0 +1,20 @@ +#pragma once + +#include "ship/resource/Resource.h" +#include + +union Vtx; + +namespace Fast { +class Vertex final : public Ship::Resource { + public: + using Resource::Resource; + + Vertex(); + + Vtx* GetPointer() override; + size_t GetPointerSize() override; + + std::vector VertexList; +}; +} // namespace Fast diff --git a/libultraship/include/fast/types.h b/libultraship/include/fast/types.h new file mode 100644 index 000000000..a60cca0af --- /dev/null +++ b/libultraship/include/fast/types.h @@ -0,0 +1,25 @@ +#pragma once + +typedef int Mtx_t[4][4]; +typedef union { + Mtx_t m; + struct { + unsigned short int intPart[4][4]; + unsigned short int fracPart[4][4]; + }; + long long int forc_structure_alignment; +} MtxS; + +typedef float MtxF_t[4][4]; +typedef union { + MtxF_t mf; + struct { + float xx, yx, zx, wx, xy, yy, zy, wy, xz, yz, zz, wz, xw, yw, zw, ww; + }; +} MtxF; + +#ifndef GBI_FLOATS +typedef MtxS Mtx; +#else +typedef MtxF Mtx; +#endif diff --git a/libultraship/include/fast/ucodehandlers.h b/libultraship/include/fast/ucodehandlers.h new file mode 100644 index 000000000..330375e43 --- /dev/null +++ b/libultraship/include/fast/ucodehandlers.h @@ -0,0 +1,11 @@ +#pragma once + +typedef enum UcodeHandlers { + ucode_f3db, + ucode_f3d, + ucode_f3dex, + ucode_f3dexb, + ucode_f3dex2, + ucode_s2dex, + ucode_max, +} UcodeHandlers; diff --git a/libultraship/include/libultraship/bridge.h b/libultraship/include/libultraship/bridge.h new file mode 100644 index 000000000..37d70041f --- /dev/null +++ b/libultraship/include/libultraship/bridge.h @@ -0,0 +1,11 @@ +#pragma once + +#include "libultraship/bridge/resourcebridge.h" +#include "libultraship/bridge/audiobridge.h" +#include "libultraship/bridge/controllerbridge.h" +#include "libultraship/bridge/windowbridge.h" +#include "libultraship/bridge/consolevariablebridge.h" +#include "libultraship/bridge/crashhandlerbridge.h" +#include "libultraship/bridge/gfxdebuggerbridge.h" +#include "libultraship/bridge/gfxbridge.h" +#include "libultraship/bridge/eventsbridge.h" \ No newline at end of file diff --git a/libultraship/include/libultraship/bridge/audiobridge.h b/libultraship/include/libultraship/bridge/audiobridge.h new file mode 100644 index 000000000..eef355d41 --- /dev/null +++ b/libultraship/include/libultraship/bridge/audiobridge.h @@ -0,0 +1,44 @@ +#pragma once + +#include "stdint.h" +#include "stddef.h" +#include "ship/Api.h" +#include "ship/audio/AudioChannelsSetting.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Returns the number of audio frames currently queued in the audio device buffer. */ +API_EXPORT int32_t AudioPlayerBuffered(); + +/** @brief Returns the configured target number of buffered audio frames. */ +API_EXPORT int32_t AudioPlayerGetDesiredBuffered(); + +/** @brief Returns the current audio channel mode (stereo / 5.1 matrix / 5.1 raw). */ +API_EXPORT AudioChannelsSetting GetAudioChannels(); + +/** @brief Returns the number of output channels active on the current audio device (2 or 6). */ +API_EXPORT int32_t GetNumAudioChannels(); + +/** + * @brief Submits a frame of PCM audio to the audio output device. + * + * @param buf Interleaved sample data (stereo: L,R,… or surround: FL,FR,C,LFE,SL,SR,…). + * @param len Length of @p buf in bytes. + */ +API_EXPORT void AudioPlayerPlayFrame(const uint8_t* buf, size_t len); + +/** + * @brief Changes the audio channel configuration at runtime. + * + * Reinitialises the audio backend with the new channel mode without requiring a + * game restart. Stereo and 5.1 surround (matrix or raw) are supported. + * + * @param channels New channel mode to apply. + */ +API_EXPORT void SetAudioChannels(AudioChannelsSetting channels); + +#ifdef __cplusplus +}; +#endif diff --git a/libultraship/include/libultraship/bridge/consolevariablebridge.h b/libultraship/include/libultraship/bridge/consolevariablebridge.h new file mode 100644 index 000000000..6c930b6f3 --- /dev/null +++ b/libultraship/include/libultraship/bridge/consolevariablebridge.h @@ -0,0 +1,165 @@ +#pragma once + +#include "stdint.h" +#include "libultraship/color.h" +#include "ship/Api.h" + +#ifdef __cplusplus +#include +#include "ship/config/ConsoleVariable.h" + +/** + * @brief Returns a shared pointer to the CVar with the given name, or nullptr if it does not exist. + * @param name CVar name (e.g. "gMyOption"). + */ +std::shared_ptr CVarGet(const char* name); + +extern "C" { +#endif + +/** + * @brief Returns the integer value of the named CVar, or @p defaultValue if it is not set. + * @param name CVar name. + * @param defaultValue Value returned when the CVar does not exist. + */ +API_EXPORT int32_t CVarGetInteger(const char* name, int32_t defaultValue); + +/** + * @brief Returns the float value of the named CVar, or @p defaultValue if it is not set. + * @param name CVar name. + * @param defaultValue Value returned when the CVar does not exist. + */ +API_EXPORT float CVarGetFloat(const char* name, float defaultValue); + +/** + * @brief Returns the string value of the named CVar, or @p defaultValue if it is not set. + * @param name CVar name. + * @param defaultValue Value returned when the CVar does not exist (must outlive the call). + */ +API_EXPORT const char* CVarGetString(const char* name, const char* defaultValue); + +/** + * @brief Returns the RGBA colour value of the named CVar, or @p defaultValue if it is not set. + * @param name CVar name. + * @param defaultValue Default RGBA colour. + */ +API_EXPORT Color_RGBA8 CVarGetColor(const char* name, Color_RGBA8 defaultValue); + +/** + * @brief Returns the RGB colour value of the named CVar, or @p defaultValue if it is not set. + * @param name CVar name. + * @param defaultValue Default RGB colour. + */ +API_EXPORT Color_RGB8 CVarGetColor24(const char* name, Color_RGB8 defaultValue); + +/** + * @brief Sets the named CVar to an integer value (creates it if it does not exist). + * @param name CVar name. + * @param value New integer value. + */ +API_EXPORT void CVarSetInteger(const char* name, int32_t value); + +/** + * @brief Sets the named CVar to a float value (creates it if it does not exist). + * @param name CVar name. + * @param value New float value. + */ +API_EXPORT void CVarSetFloat(const char* name, float value); + +/** + * @brief Sets the named CVar to a string value (creates it if it does not exist). + * @param name CVar name. + * @param value New string value (copied internally). + */ +API_EXPORT void CVarSetString(const char* name, const char* value); + +/** + * @brief Sets the named CVar to an RGBA colour value (creates it if it does not exist). + * @param name CVar name. + * @param value New RGBA colour. + */ +API_EXPORT void CVarSetColor(const char* name, Color_RGBA8 value); + +/** + * @brief Sets the named CVar to an RGB colour value (creates it if it does not exist). + * @param name CVar name. + * @param value New RGB colour. + */ +API_EXPORT void CVarSetColor24(const char* name, Color_RGB8 value); + +/** + * @brief Registers an integer CVar with a default value if it has not been set before. + * + * Unlike CVarSetInteger(), this is a no-op when the CVar already has a value. + * + * @param name CVar name. + * @param defaultValue Default value to use when the CVar is absent. + */ +API_EXPORT void CVarRegisterInteger(const char* name, int32_t defaultValue); + +/** + * @brief Registers a float CVar with a default value if it has not been set before. + * @param name CVar name. + * @param defaultValue Default float value. + */ +API_EXPORT void CVarRegisterFloat(const char* name, float defaultValue); + +/** + * @brief Registers a string CVar with a default value if it has not been set before. + * @param name CVar name. + * @param defaultValue Default string value. + */ +API_EXPORT void CVarRegisterString(const char* name, const char* defaultValue); + +/** + * @brief Registers an RGBA colour CVar with a default value if it has not been set before. + * @param name CVar name. + * @param defaultValue Default RGBA colour. + */ +API_EXPORT void CVarRegisterColor(const char* name, Color_RGBA8 defaultValue); + +/** + * @brief Registers an RGB colour CVar with a default value if it has not been set before. + * @param name CVar name. + * @param defaultValue Default RGB colour. + */ +API_EXPORT void CVarRegisterColor24(const char* name, Color_RGB8 defaultValue); + +/** + * @brief Removes the named CVar from the runtime store (does not affect persisted config). + * @param name CVar name to remove. + */ +API_EXPORT void CVarClear(const char* name); + +/** + * @brief Returns true if the named CVar currently has a value in the runtime store. + * @param name CVar name. + */ +API_EXPORT bool CVarExists(const char* name); + +/** + * @brief Removes all CVars whose names begin with the given prefix. + * @param name Prefix string (e.g. "gMod."). + */ +API_EXPORT void CVarClearBlock(const char* name); + +/** + * @brief Copies the value of the CVar named @p from to a new CVar named @p to. + * @param from Source CVar name. + * @param to Destination CVar name (created if it does not exist). + */ +API_EXPORT void CVarCopy(const char* from, const char* to); + +/** + * @brief Loads all CVar values from the persisted config file into the runtime store. + */ +API_EXPORT void CVarLoad(); + +/** + * @brief Saves all runtime CVar values to the persisted config file. + */ +API_EXPORT void CVarSave(); + +#ifdef __cplusplus +}; +#endif diff --git a/libultraship/include/libultraship/bridge/controllerbridge.h b/libultraship/include/libultraship/bridge/controllerbridge.h new file mode 100644 index 000000000..3abd58864 --- /dev/null +++ b/libultraship/include/libultraship/bridge/controllerbridge.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include "ship/Api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Prevents controller gamepad input from being processed by the game. + * + * Multiple callers can independently block input; each must supply a unique @p inputBlockId + * and must call ControllerUnblockGameInput() with the same ID to release its block. + * + * @param inputBlockId Caller-chosen identifier that distinguishes this blocker. + */ +API_EXPORT void ControllerBlockGameInput(uint16_t inputBlockId); + +/** + * @brief Releases a previously established game input block. + * + * Input is only fully unblocked once all outstanding blockers have called this function. + * + * @param inputBlockId The same ID passed to ControllerBlockGameInput(). + */ +API_EXPORT void ControllerUnblockGameInput(uint16_t inputBlockId); + +#ifdef __cplusplus +}; +#endif diff --git a/libultraship/include/libultraship/bridge/crashhandlerbridge.h b/libultraship/include/libultraship/bridge/crashhandlerbridge.h new file mode 100644 index 000000000..919a7fd4a --- /dev/null +++ b/libultraship/include/libultraship/bridge/crashhandlerbridge.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include "ship/Api.h" + +/** + * @brief Callback type invoked by the crash handler when a crash is detected. + * + * The callback receives a mutable character buffer (@p char*) and the current + * write offset within that buffer (@p size_t*). Implementations should append + * any game-specific crash context and update the offset accordingly. + */ +typedef void (*CrashHandlerCallback)(char*, size_t*); + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Registers an application callback to be invoked on crash. + * + * The callback is called after the CrashHandler has written the platform crash + * report, giving the application an opportunity to append additional information + * (e.g. current game state) before the process exits. + * + * @param callback Function to invoke on crash. Pass nullptr to clear the callback. + */ +API_EXPORT void CrashHandlerRegisterCallback(CrashHandlerCallback callback); + +#ifdef __cplusplus +} +#endif diff --git a/libultraship/include/libultraship/bridge/eventsbridge.h b/libultraship/include/libultraship/bridge/eventsbridge.h new file mode 100644 index 000000000..995fcca95 --- /dev/null +++ b/libultraship/include/libultraship/bridge/eventsbridge.h @@ -0,0 +1,55 @@ +#pragma once + +#include "stdint.h" +#include "ship/events/EventTypes.h" +#include "ship/Api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Registers a new event type under the given name and returns its unique ID. + * + * If an event with @p name has already been registered the existing ID is returned. + * + * @param name Human-readable event name (e.g. "OnLoadGame"). + * @return EventID that can be passed to EventSystemRegisterListener() and EventSystemCallEvent(). + */ +API_EXPORT EventID EventSystemRegisterEvent(const char* name); + +/** + * @brief Registers a listener callback for the given event. + * + * @param id Event to listen to (obtained from EventSystemRegisterEvent()). + * @param callback Function invoked when the event fires. + * @param priority Relative priority; higher-priority listeners are called first. + * @param file Source file of the caller (use the @c __FILE__ macro). + * @param line Source line of the caller (use the @c __LINE__ macro). + * @return ListenerID that can be passed to EventSystemUnregisterListener() to remove this listener. + */ +API_EXPORT ListenerID EventSystemRegisterListener(EventID id, EventCallback callback, EventPriority priority, + const char* file, int line); + +/** + * @brief Removes a previously registered listener. + * + * @param ev Event the listener was registered for. + * @param id ListenerID returned by EventSystemRegisterListener(). + */ +API_EXPORT void EventSystemUnregisterListener(EventID ev, ListenerID id); + +/** + * @brief Fires an event synchronously, invoking all registered listeners in priority order. + * + * @param id Event to fire. + * @param event Pointer to event-specific data passed to each listener callback. + * @param file Source file of the caller (use the @c __FILE__ macro). + * @param line Source line of the caller (use the @c __LINE__ macro). + * @param key Optional de-duplication key; pass nullptr for unconditional dispatch. + */ +API_EXPORT void EventSystemCallEvent(EventID id, void* event, const char* file, int line, const char* key); + +#ifdef __cplusplus +} +#endif diff --git a/libultraship/include/libultraship/bridge/gfxbridge.h b/libultraship/include/libultraship/bridge/gfxbridge.h new file mode 100644 index 000000000..d414f08a5 --- /dev/null +++ b/libultraship/include/libultraship/bridge/gfxbridge.h @@ -0,0 +1,42 @@ +#pragma once + +#include "stdint.h" +#include "fast/ucodehandlers.h" +#include "ship/Api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Sets the native (un-scaled) rendering resolution used by the graphics backend. + * + * @param width Native framebuffer width in pixels. + * @param height Native framebuffer height in pixels. + */ +API_EXPORT void GfxSetNativeDimensions(uint32_t width, uint32_t height); + +/** + * @brief Prepares the graphics backend to sample the pixel depth at screen coordinate (@p x, @p y). + * + * Call this before GfxGetPixelDepth() to ensure the depth value is ready. + * + * @param x Screen X coordinate in pixels. + * @param y Screen Y coordinate in pixels. + */ +API_EXPORT void GfxGetPixelDepthPrepare(float x, float y); + +/** + * @brief Returns the pixel depth at screen coordinate (@p x, @p y). + * + * Must be called after GfxGetPixelDepthPrepare() for the same coordinates. + * + * @param x Screen X coordinate in pixels. + * @param y Screen Y coordinate in pixels. + * @return Depth value in the range [0, 65535] (16-bit fixed-point). + */ +API_EXPORT uint16_t GfxGetPixelDepth(float x, float y); + +#ifdef __cplusplus +} +#endif diff --git a/libultraship/include/libultraship/bridge/gfxdebuggerbridge.h b/libultraship/include/libultraship/bridge/gfxdebuggerbridge.h new file mode 100644 index 000000000..ae3e2dfe0 --- /dev/null +++ b/libultraship/include/libultraship/bridge/gfxdebuggerbridge.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include "ship/Api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Requests that the graphics debugger begin capturing the next display list. + * + * Sets an internal flag that is checked at the start of the next frame. Once capture + * begins, GfxDebuggerIsDebugging() returns true until the capture is complete. + */ +API_EXPORT void GfxDebuggerRequestDebugging(); + +/** + * @brief Returns true while the graphics debugger is actively capturing a display list. + */ +API_EXPORT bool GfxDebuggerIsDebugging(); + +/** + * @brief Returns true if a debug capture has been requested but has not yet started. + */ +API_EXPORT bool GfxDebuggerIsDebuggingRequested(); + +/** + * @brief Passes a display list to the graphics debugger for inspection. + * + * Should be called once per frame while GfxDebuggerIsDebugging() is true. + * + * @param cmds Pointer to the head of the display list command buffer. + */ +API_EXPORT void GfxDebuggerDebugDisplayList(void* cmds); + +#ifdef __cplusplus +}; +#endif diff --git a/libultraship/include/libultraship/bridge/resourcebridge.h b/libultraship/include/libultraship/bridge/resourcebridge.h new file mode 100644 index 000000000..f9b837a9f --- /dev/null +++ b/libultraship/include/libultraship/bridge/resourcebridge.h @@ -0,0 +1,157 @@ +#pragma once + +#include "stdint.h" +#include "stddef.h" +#include "ship/Api.h" + +#ifdef __cplusplus +#include "ship/resource/Resource.h" +#include + +/** + * @brief Loads a resource by its virtual path and returns a type-erased shared pointer. + * @param name Virtual path of the resource within the archive (e.g. "textures/foo.png"). + * @return Shared pointer to the loaded IResource, or nullptr on failure. + */ +std::shared_ptr ResourceLoad(const char* name); + +/** + * @brief Loads a resource by its 64-bit CRC and returns a type-erased shared pointer. + * @param crc 64-bit CRC of the resource path. + * @return Shared pointer to the loaded IResource, or nullptr on failure. + */ +std::shared_ptr ResourceLoad(uint64_t crc); + +/** + * @brief Loads a resource by its virtual path and casts it to the requested type. + * @tparam T Expected resource type (e.g. Fast::Texture). + * @param name Virtual resource path. + * @return Shared pointer to @p T, or nullptr if the resource could not be loaded or cast. + */ +template std::shared_ptr ResourceLoad(const char* name) { + return std::static_pointer_cast(ResourceLoad(name)); +} + +/** + * @brief Loads a resource by CRC and casts it to the requested type. + * @tparam T Expected resource type. + * @param crc 64-bit CRC of the resource path. + * @return Shared pointer to @p T, or nullptr on failure. + */ +template std::shared_ptr ResourceLoad(uint64_t crc) { + return std::static_pointer_cast(ResourceLoad(crc)); +} + +extern "C" { +#endif + +/** @brief Returns the 64-bit CRC that corresponds to the given resource path. */ +API_EXPORT uint64_t ResourceGetCrcByName(const char* name); + +/** @brief Returns the virtual path string that corresponds to the given 64-bit CRC. */ +API_EXPORT const char* ResourceGetNameByCrc(uint64_t crc); + +/** @brief Returns the raw data size in bytes of the resource with the given path. */ +API_EXPORT size_t ResourceGetSizeByName(const char* name); + +/** @brief Returns the raw data size in bytes of the resource with the given CRC. */ +API_EXPORT size_t ResourceGetSizeByCrc(uint64_t crc); + +/** + * @brief Returns non-zero if the resource at @p name originates from a custom/mod archive. + */ +API_EXPORT uint8_t ResourceGetIsCustomByName(const char* name); + +/** + * @brief Returns non-zero if the resource at @p crc originates from a custom/mod archive. + */ +API_EXPORT uint8_t ResourceGetIsCustomByCrc(uint64_t crc); + +/** + * @brief Returns a raw pointer to the resource's data buffer by path. + * + * The pointer is valid as long as the resource remains loaded; do not cache it + * across frames without also holding a reference to the resource. + */ +API_EXPORT void* ResourceGetDataByName(const char* name); + +/** @brief Returns a raw pointer to the resource's data buffer by CRC. */ +API_EXPORT void* ResourceGetDataByCrc(uint64_t crc); + +/** @brief Returns the texture width in pixels for the texture resource at @p name. */ +API_EXPORT uint16_t ResourceGetTexWidthByName(const char* name); + +/** @brief Returns the texture width in pixels for the texture resource at @p crc. */ +API_EXPORT uint16_t ResourceGetTexWidthByCrc(uint64_t crc); + +/** @brief Returns the texture height in pixels for the texture resource at @p name. */ +API_EXPORT uint16_t ResourceGetTexHeightByName(const char* name); + +/** @brief Returns the texture height in pixels for the texture resource at @p crc. */ +API_EXPORT uint16_t ResourceGetTexHeightByCrc(uint64_t crc); + +/** @brief Returns the total texture data size in bytes for the texture at @p name. */ +API_EXPORT size_t ResourceGetTexSizeByName(const char* name); + +/** @brief Returns the total texture data size in bytes for the texture at @p crc. */ +API_EXPORT size_t ResourceGetTexSizeByCrc(uint64_t crc); + +/** + * @brief Synchronously loads all resources whose paths begin with @p name. + * @param name Directory prefix (e.g. "textures/") or exact path. + */ +API_EXPORT void ResourceLoadDirectory(const char* name); + +/** + * @brief Queues all resources under @p name for background loading. + * @param name Directory prefix or exact path. + */ +API_EXPORT void ResourceLoadDirectoryAsync(const char* name); + +/** + * @brief Marks all resources under @p name as dirty so they are reloaded on next access. + * @param name Directory prefix or exact path. + */ +API_EXPORT void ResourceDirtyDirectory(const char* name); + +/** @brief Marks the resource at @p name as dirty so it is reloaded on next access. */ +API_EXPORT void ResourceDirtyByName(const char* name); + +/** @brief Marks the resource at @p crc as dirty so it is reloaded on next access. */ +API_EXPORT void ResourceDirtyByCrc(uint64_t crc); + +/** @brief Evicts the resource with the given path from the resource cache. */ +API_EXPORT void ResourceUnloadByName(const char* name); + +/** @brief Evicts the resource with the given CRC from the resource cache. */ +API_EXPORT void ResourceUnloadByCrc(uint64_t crc); + +/** + * @brief Evicts all resources whose paths begin with @p name from the resource cache. + * @param name Directory prefix or exact path. + */ +API_EXPORT void ResourceUnloadDirectory(const char* name); + +/** @brief Evicts all resources from the resource cache. */ +API_EXPORT void ResourceClearCache(); + +/** + * @brief Retrieves the list of game version hashes present in the loaded archives. + * @param versions Caller-supplied array to receive the version hashes. + * @param versionsSize Capacity of @p versions (number of elements). + * @param versionsCount Set to the actual number of versions written to @p versions. + */ +API_EXPORT void ResourceGetGameVersions(uint32_t* versions, size_t versionsSize, size_t* versionsCount); + +/** + * @brief Returns non-zero if the given version hash is present in the loaded archives. + * @param hash Version hash to search for. + */ +API_EXPORT uint32_t ResourceHasGameVersion(uint32_t hash); + +/** @brief Returns non-zero if the ResourceManager has been fully initialised and is ready. */ +API_EXPORT uint32_t IsResourceManagerLoaded(); + +#ifdef __cplusplus +}; +#endif diff --git a/libultraship/include/libultraship/bridge/scriptingbridge.h b/libultraship/include/libultraship/bridge/scriptingbridge.h new file mode 100644 index 000000000..fcdda8902 --- /dev/null +++ b/libultraship/include/libultraship/bridge/scriptingbridge.h @@ -0,0 +1,29 @@ +#pragma once + +#ifdef ENABLE_SCRIPTING + +#include "stdint.h" +#include "ship/Api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Looks up and returns a function pointer exported from the scripting runtime. + * + * The scripting bridge exposes compiled script functions to native C/C++ code via + * this single entry point. The caller is responsible for casting the returned pointer + * to the correct function signature before calling it. + * + * @param module Name of the scripting module that exports the function. + * @param function Name of the function to look up within @p module. + * @return Opaque function pointer, or nullptr if the module or function is not found. + */ +API_EXPORT void* ScriptGetFunction(const char* module, const char* function); + +#ifdef __cplusplus +} +#endif + +#endif // ENABLE_SCRIPTING diff --git a/libultraship/include/libultraship/bridge/windowbridge.h b/libultraship/include/libultraship/bridge/windowbridge.h new file mode 100644 index 000000000..e1a1f017d --- /dev/null +++ b/libultraship/include/libultraship/bridge/windowbridge.h @@ -0,0 +1,33 @@ +#pragma once + +#include "stdint.h" +#include "ship/Api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Returns true if the application window is running (has not been closed). */ +API_EXPORT bool WindowIsRunning(); + +/** @brief Returns the current width of the game window in pixels. */ +API_EXPORT uint32_t WindowGetWidth(); + +/** @brief Returns the current height of the game window in pixels. */ +API_EXPORT uint32_t WindowGetHeight(); + +/** @brief Returns the current aspect ratio of the game window (width / height). */ +API_EXPORT float WindowGetAspectRatio(); + +/** @brief Returns the X position of the game window's top-left corner in screen coordinates. */ +API_EXPORT int32_t WindowGetPosX(); + +/** @brief Returns the Y position of the game window's top-left corner in screen coordinates. */ +API_EXPORT int32_t WindowGetPosY(); + +/** @brief Returns true if the game window is currently in fullscreen mode. */ +API_EXPORT bool WindowIsFullscreen(); + +#ifdef __cplusplus +}; +#endif diff --git a/libultraship/include/libultraship/classes.h b/libultraship/include/libultraship/classes.h new file mode 100644 index 000000000..ae7f30095 --- /dev/null +++ b/libultraship/include/libultraship/classes.h @@ -0,0 +1,37 @@ +#pragma once +#ifdef __cplusplus + +#include "ship/resource/archive/ArchiveManager.h" +#include "ship/resource/archive/Archive.h" +#include "ship/resource/archive/OtrArchive.h" +#include "ship/resource/archive/O2rArchive.h" +#include "ship/resource/ResourceManager.h" +#include "ship/Context.h" +#include "ship/window/Window.h" +#include "ship/debug/Console.h" +#include "ship/debug/CrashHandler.h" +#include "ship/config/ConsoleVariable.h" +#include "ship/config/Config.h" +#include "ship/window/gui/ConsoleWindow.h" +#include "ship/window/gui/GameOverlay.h" +#include "ship/window/gui/Gui.h" +#include "ship/window/gui/GuiMenuBar.h" +#include "ship/window/gui/GuiElement.h" +#include "ship/window/gui/GuiWindow.h" +#include "ship/window/gui/StatsWindow.h" +#include "ship/controller/controldevice/controller/mapping/keyboard/KeyboardScancodes.h" +#include "ship/controller/controldevice/controller/Controller.h" +#include "ship/controller/controldeck/ControlDeck.h" +#include "ship/utils/binarytools/BinaryReader.h" +#include "ship/utils/binarytools/MemoryStream.h" +#include "ship/utils/binarytools/BinaryWriter.h" +#include "ship/audio/Audio.h" +#include "ship/audio/AudioPlayer.h" +#if defined(_WIN32) +#include "ship/audio/WasapiAudioPlayer.h" +#endif +#include "ship/audio/SDLAudioPlayer.h" +#ifdef __APPLE__ +#include "ship/utils/AppleFolderManager.h" +#endif +#endif diff --git a/libultraship/include/libultraship/color.h b/libultraship/include/libultraship/color.h new file mode 100644 index 000000000..bb2ac7879 --- /dev/null +++ b/libultraship/include/libultraship/color.h @@ -0,0 +1,71 @@ +#pragma once + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief 32-bit RGBA colour stored in a union that allows component and packed-integer access. + * + * The byte order of the components within @c rgba depends on whether the target is big-endian + * (IS_BIGENDIAN defined) or little-endian. Use the named struct members for portable access + * and the @c rgba field only when a packed 32-bit representation is required (e.g. GPU uploads). + * + * @note Only use the @c rgba field when alignment requirements demand it. + */ +typedef union { + struct { +#ifdef IS_BIGENDIAN + uint8_t r; ///< Red channel (big-endian layout). + uint8_t g; ///< Green channel (big-endian layout). + uint8_t b; ///< Blue channel (big-endian layout). + uint8_t a; ///< Alpha channel (big-endian layout). +#else + uint8_t a; ///< Alpha channel (little-endian layout — lowest address byte). + uint8_t b; ///< Blue channel (little-endian layout). + uint8_t g; ///< Green channel (little-endian layout). + uint8_t r; ///< Red channel (little-endian layout — highest address byte). +#endif + }; + uint32_t rgba; ///< All four channels packed into a single 32-bit integer. +} Color_RGBA8_u32; + +/** + * @brief Single-precision floating-point RGBA colour. + * + * Each component is in the range [0.0f, 1.0f]: + * - 0.0f represents the minimum intensity (black / transparent). + * - 1.0f represents the maximum intensity (white / fully opaque). + */ +typedef struct { + float r; ///< Red channel [0.0, 1.0]. + float g; ///< Green channel [0.0, 1.0]. + float b; ///< Blue channel [0.0, 1.0]. + float a; ///< Alpha channel [0.0, 1.0] (0 = transparent, 1 = opaque). +} Color_RGBAf; + +/** + * @brief 16-bit RGBA colour using 5-5-5-1 bit packing. + * + * - r, g, b: 5 bits each (range 0–31). + * - a: 1 bit (0 = transparent, 1 = opaque). + * + * The @c rgba field gives the complete packed 16-bit value. + */ +typedef union { + struct { + uint16_t r : 5; ///< Red channel (5 bits, range 0–31). + uint16_t g : 5; ///< Green channel (5 bits, range 0–31). + uint16_t b : 5; ///< Blue channel (5 bits, range 0–31). + uint16_t a : 1; ///< Alpha channel (1 bit, 0 = transparent, 1 = opaque). + }; + uint16_t rgba; ///< All four channels packed into a single 16-bit integer. +} Color_RGBA16; + +#ifdef __cplusplus +}; +#endif diff --git a/libultraship/include/libultraship/controller/controldeck/ControlDeck.h b/libultraship/include/libultraship/controller/controldeck/ControlDeck.h new file mode 100644 index 000000000..d39b0fe0e --- /dev/null +++ b/libultraship/include/libultraship/controller/controldeck/ControlDeck.h @@ -0,0 +1,79 @@ +#pragma once + +#include "ship/controller/controldeck/ControlDeck.h" +#include "ship/controller/controldeck/ControlPort.h" +#include +#include "ship/config/Config.h" +#include "ship/controller/controldevice/controller/mapping/keyboard/KeyboardScancodes.h" +#include "ship/controller/physicaldevice/ConnectedPhysicalDeviceManager.h" +#include "ship/controller/physicaldevice/GlobalSDLDeviceSettings.h" +#include "ship/controller/controldevice/controller/mapping/ControllerDefaultMappings.h" +#include "libultraship/libultra/controller.h" + +namespace LUS { +/** + * @brief Ship's N64-compatible ControlDeck implementation. + * + * LUS::ControlDeck is the concrete ControlDeck subclass used by libultraship. It + * owns an OSContPad buffer (one entry per port) and implements WriteToPad() to copy + * the aggregated controller state from each Ship::Controller into that buffer for + * consumption by the emulated game. + * + * The default constructor registers the standard N64 button set. The two-argument + * and three-argument constructors allow a game to extend the button set with custom + * bitmasks and to provide its own default mapping tables. + * + * Obtain the instance from Context::GetControlDeck(), cast to LUS::ControlDeck if + * you need access to GetPads(). + */ +class ControlDeck final : public Ship::ControlDeck { + public: + /** + * @brief Constructs a ControlDeck with the standard N64 button set and default mappings. + */ + ControlDeck(); + + /** + * @brief Constructs a ControlDeck with the standard N64 buttons plus extra bitmasks. + * @param additionalBitmasks Extra button bitmasks beyond the standard N64 set. + */ + ControlDeck(std::vector additionalBitmasks); + + /** + * @brief Full constructor: extra bitmasks, custom default mappings, and custom button names. + * @param additionalBitmasks Extra button bitmasks. + * @param controllerDefaultMappings Default mappings applied to new devices. + * @param buttonNames Human-readable names for each button bitmask. + */ + ControlDeck(std::vector additionalBitmasks, + std::shared_ptr controllerDefaultMappings, + std::unordered_map buttonNames); + + /** + * @brief Returns a pointer to the OSContPad buffer (one pad per port). + * + * The buffer should be updated by WriteToPad() at the start of each game frame. + * The lifetime of the returned pointer is tied to this ControlDeck. + */ + OSContPad* GetPads(); + + /** + * @brief Reads each connected controller and writes the result to the game's pad buffer. + * + * @p pad must point to an array of OSContPad structures large enough to hold one + * entry per port (i.e. at least MAXCONTROLLERS * sizeof(OSContPad) bytes). + * + * @param pad Pointer to the game's OSContPad buffer. + */ + void WriteToPad(void* pad) override; + + private: + /** + * @brief Translates a single port's Ship::Controller state to one OSContPad entry. + * @param pad Pointer to the OSContPad entry for this port. + */ + void WriteToOSContPad(OSContPad* pad); + + OSContPad* mPads; ///< OSContPad array (one entry per port), owned by this class. +}; +} // namespace LUS diff --git a/libultraship/include/libultraship/controller/controldevice/controller/Controller.h b/libultraship/include/libultraship/controller/controldevice/controller/Controller.h new file mode 100644 index 000000000..0bf0b91e3 --- /dev/null +++ b/libultraship/include/libultraship/controller/controldevice/controller/Controller.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include "libultraship/libultra/controller.h" +#include "ship/utils/color.h" +#include +#include "ship/controller/controldevice/controller/Controller.h" + +namespace LUS { +/** + * @brief Ship's N64-compatible Controller implementation. + * + * LUS::Controller is the concrete Controller subclass used by libultraship. It + * stores a rolling buffer of OSContPad states and implements ReadToPad() to convert + * the aggregated Ship::Controller input state into a single OSContPad entry. + * + * The pad buffer allows the game to read back previous frames of input if needed + * (e.g. for input prediction or replay). + * + * Instances are created automatically by LUS::ControlDeck when a port is configured; + * access them via ControlDeck::GetControllerByPort(). + */ +class Controller : public Ship::Controller { + public: + /** + * @brief Constructs a Controller for the given port with the specified button bitmasks. + * @param portIndex Zero-based port index (0 = port 1). + * @param bitmasks All button bitmasks this controller should track. + */ + Controller(uint8_t portIndex, std::vector bitmasks); + + /** + * @brief Reads the current Ship::Controller state and writes it to the game's pad structure. + * + * @p pad must point to the OSContPad entry for this port within the deck's pad buffer. + * + * @param pad Pointer to the OSContPad entry to fill. + */ + void ReadToPad(void* pad) override; + + private: + /** + * @brief Converts the current Ship input state into one OSContPad entry. + * @param pad Pointer to the OSContPad entry to fill. + */ + void ReadToOSContPad(OSContPad* pad); + + std::deque mPadBuffer; ///< Rolling history of pad states (newest at front). +}; +} // namespace LUS diff --git a/libultraship/include/libultraship/controller/controldevice/controller/mapping/ControllerDefaultMappings.h b/libultraship/include/libultraship/controller/controldevice/controller/mapping/ControllerDefaultMappings.h new file mode 100644 index 000000000..ca9a5d22d --- /dev/null +++ b/libultraship/include/libultraship/controller/controldevice/controller/mapping/ControllerDefaultMappings.h @@ -0,0 +1,78 @@ +#pragma once + +#include "ship/controller/controldevice/controller/mapping/ControllerDefaultMappings.h" + +namespace LUS { + +/** + * @brief N64-specific controller default mapping configuration. + * + * LUS::ControllerDefaultMappings is the concrete ControllerDefaultMappings + * subclass used by libultraship. It provides the standard N64 button layout for + * keyboard, SDL gamepad buttons, and SDL axis-to-button mappings so that newly + * connected devices receive sensible default bindings out of the box. + * + * Pass an instance to LUS::ControlDeck (or Ship::ControlDeck) to customise the + * default mappings applied when a new physical device is detected. + */ +class ControllerDefaultMappings : public Ship::ControllerDefaultMappings { + public: + /** + * @brief Full constructor — supply all default mapping tables explicitly. + * + * @param defaultKeyboardKeyToButtonMappings Button → keyboard key default bindings. + * @param defaultKeyboardKeyToAxisDirectionMappings Stick direction → keyboard key default bindings. + * @param defaultSDLButtonToButtonMappings Button → SDL gamepad button default bindings. + * @param defaultSDLButtonToAxisDirectionMappings Stick direction → SDL button default bindings. + * @param defaultSDLAxisDirectionToButtonMappings Button → SDL axis default bindings. + * @param defaultSDLAxisDirectionToAxisDirectionMappings Stick direction → SDL axis default bindings. + */ + ControllerDefaultMappings( + std::unordered_map> + defaultKeyboardKeyToButtonMappings, + std::unordered_map>> + defaultKeyboardKeyToAxisDirectionMappings, + std::unordered_map> + defaultSDLButtonToButtonMappings, + std::unordered_map>> + defaultSDLButtonToAxisDirectionMappings, + std::unordered_map>> + defaultSDLAxisDirectionToButtonMappings, + std::unordered_map>>> + defaultSDLAxisDirectionToAxisDirectionMappings); + + /** + * @brief Constructs with an empty mapping table (all defaults are unset). + * + * Use this when you want to build defaults incrementally via the base-class setters. + */ + ControllerDefaultMappings(); + ~ControllerDefaultMappings(); + + private: + /** + * @brief Applies the given keyboard-to-button mapping table as the default. + * @param defaultKeyboardKeyToButtonMappings Map from button bitmask to keyboard scan codes. + */ + void + SetDefaultKeyboardKeyToButtonMappings(std::unordered_map> + defaultKeyboardKeyToButtonMappings) override; + + /** + * @brief Applies the given SDL-button-to-button mapping table as the default. + * @param defaultSDLButtonToButtonMappings Map from button bitmask to SDL gamepad buttons. + */ + void SetDefaultSDLButtonToButtonMappings( + std::unordered_map> + defaultSDLButtonToButtonMappings) override; + + /** + * @brief Applies the given SDL-axis-to-button mapping table as the default. + * @param defaultSDLAxisDirectionToButtonMappings Map from button bitmask to (SDL axis, direction) pairs. + */ + void SetDefaultSDLAxisDirectionToButtonMappings( + std::unordered_map>> + defaultSDLAxisDirectionToButtonMappings) override; +}; +} // namespace LUS diff --git a/libultraship/include/libultraship/libultra.h b/libultraship/include/libultraship/libultra.h new file mode 100644 index 000000000..59df02a6a --- /dev/null +++ b/libultraship/include/libultraship/libultra.h @@ -0,0 +1,27 @@ +#pragma once + +#include "libultra/abi.h" +#include "libultra/controller.h" +#include "libultra/convert.h" +#include "libultra/eeprom.h" +#include "libultra/exception.h" +#include "libultra/gbi.h" +#include "libultra/gs2dex.h" +#include "libultra/gu.h" +#include "libultra/os.h" +#include "libultra/internal.h" +#include "libultra/interrupt.h" +#include "libultra/mbi.h" +#include "libultra/message.h" +#include "libultra/motor.h" +#include "libultra/pfs.h" +#include "libultra/pi.h" +#include "libultra/printf.h" +#include "libultra/r4300.h" +#include "libultra/rcp.h" +#include "libultra/rdp.h" +#include "libultra/sptask.h" +#include "libultra/thread.h" +#include "libultra/time.h" +#include "libultra/types.h" +#include "libultra/vi.h" diff --git a/libultraship/include/libultraship/libultra/abi.h b/libultraship/include/libultraship/libultra/abi.h new file mode 100644 index 000000000..3258dd11d --- /dev/null +++ b/libultraship/include/libultraship/libultra/abi.h @@ -0,0 +1,471 @@ +#pragma once + +typedef unsigned int u32; + +/* Audio commands: */ +#define A_SPNOOP 0 +#define A_ADPCM 1 +#define A_CLEARBUFF 2 +#define A_UNK3 3f +#define A_ADDMIXER 4 +#define A_RESAMPLE 5 +#define A_RESAMPLE_ZOH 6 +#define A_FILTER 7 +#define A_SETBUFF 8 +#define A_DUPLICATE 9 +#define A_DMEMMOVE 10 +#define A_LOADADPCM 11 +#define A_MIXER 12 +#define A_INTERLEAVE 13 +#define A_HILOGAIN 14 +#define A_SETLOOP 15 +#define A_INTERL 17 +#define A_ENVSETUP1 18 +#define A_ENVMIXER 19 +#define A_LOADBUFF 20 +#define A_SAVEBUFF 21 +#define A_ENVSETUP2 22 +#define A_S8DEC 23 +#define A_UNK19 25 + +#define ACMD_SIZE 32 + +/* + * Audio flags + */ +#define A_INIT 0x01 +#define A_CONTINUE 0x00 +#define A_LOOP 0x02 +#define A_ADPCM_SHORT 0x04 +#define A_OUT 0x02 +#define A_LEFT 0x02 +#define A_RIGHT 0x00 +#define A_VOL 0x04 +#define A_RATE 0x00 +#define A_AUX 0x08 +#define A_NOAUX 0x00 +#define A_MAIN 0x00 +#define A_MIX 0x10 + +/* + * Data Structures. + */ + +typedef struct { + u32 cmd : 8; + u32 flags : 8; + u32 gain : 16; + u32 addr; +} Aadpcm; + +typedef struct { + u32 cmd : 8; + u32 flags : 8; + u32 gain : 16; + u32 addr; +} Apolef; + +typedef struct { + u32 cmd : 8; + u32 flags : 8; + u32 pad1 : 16; + u32 addr; +} Aenvelope; + +typedef struct { + u32 cmd : 8; + u32 pad1 : 8; + u32 dmem : 16; + u32 pad2 : 16; + u32 count : 16; +} Aclearbuff; + +typedef struct { + u32 cmd : 8; + u32 pad1 : 8; + u32 pad2 : 16; + u32 inL : 16; + u32 inR : 16; +} Ainterleave; + +typedef struct { + u32 cmd : 8; + u32 pad1 : 24; + u32 addr; +} Aloadbuff; + +typedef struct { + u32 cmd : 8; + u32 flags : 8; + u32 pad1 : 16; + u32 addr; +} Aenvmixer; + +typedef struct { + u32 cmd : 8; + u32 flags : 8; + u32 gain : 16; + u32 dmemi : 16; + u32 dmemo : 16; +} Amixer; + +typedef struct { + u32 cmd : 8; + u32 flags : 8; + u32 dmem2 : 16; + u32 addr; +} Apan; + +typedef struct { + u32 cmd : 8; + u32 flags : 8; + u32 pitch : 16; + u32 addr; +} Aresample; + +typedef struct { + u32 cmd : 8; + u32 flags : 8; + u32 pad1 : 16; + u32 addr; +} Areverb; + +typedef struct { + u32 cmd : 8; + u32 pad1 : 24; + u32 addr; +} Asavebuff; + +typedef struct { + u32 cmd : 8; + u32 pad1 : 24; + u32 pad2 : 2; + u32 number : 4; + u32 base : 24; +} Asegment; + +typedef struct { + u32 cmd : 8; + u32 flags : 8; + u32 dmemin : 16; + u32 dmemout : 16; + u32 count : 16; +} Asetbuff; + +typedef struct { + u32 cmd : 8; + u32 flags : 8; + u32 vol : 16; + u32 voltgt : 16; + u32 volrate : 16; +} Asetvol; + +typedef struct { + u32 cmd : 8; + u32 pad1 : 8; + u32 dmemin : 16; + u32 dmemout : 16; + u32 count : 16; +} Admemmove; + +typedef struct { + u32 cmd : 8; + u32 pad1 : 8; + u32 count : 16; + u32 addr; +} Aloadadpcm; + +typedef struct { + u32 cmd : 8; + u32 pad1 : 8; + u32 pad2 : 16; + u32 addr; +} Asetloop; + +/* + * Generic Acmd Packet + */ + +typedef struct { + u32 w0; + u32 w1; +} Awords; + +typedef union { + Awords words; + Aadpcm adpcm; + Apolef polef; + Aclearbuff clearbuff; + Aenvelope envelope; + Ainterleave interleave; + Aloadbuff loadbuff; + Aenvmixer envmixer; + Aresample resample; + Areverb reverb; + Asavebuff savebuff; + Asegment segment; + Asetbuff setbuff; + Asetvol setvol; + Admemmove dmemmove; + Aloadadpcm loadadpcm; + Amixer mixer; + Asetloop setloop; + long long int force_union_align; /* dummy, force alignment */ +} Acmd; + +/* + * ADPCM State + */ +#define ADPCMVSIZE 8 +#define ADPCMFSIZE 16 +typedef short ADPCM_STATE[ADPCMFSIZE]; + +/* + * Pole filter state + */ +typedef short POLEF_STATE[4]; + +/* + * Resampler state + */ +typedef short RESAMPLE_STATE[16]; + +/* + * Resampler constants + */ +#define UNITY_PITCH 0x8000 +#define MAX_RATIO 1.99996 /* within .03 cents of +1 octave */ + +/* + * Enveloper/Mixer state + */ +typedef short ENVMIX_STATE[40]; + +/* + * Macros to assemble the audio command list + */ + +#define aADPCMdec(pkt, f, s) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_ADPCM, 24, 8) | _SHIFTL(f, 16, 8); \ + _a->words.w1 = (u32)(s); \ + } + +#define aPoleFilter(pkt, f, g, s) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_POLEF, 24, 8) | _SHIFTL(f, 16, 8) | _SHIFTL(g, 0, 16)); \ + _a->words.w1 = (u32)(s); \ + } + +#define aHiLoGain(pkt, gain, count, dmem, a4) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_HILOGAIN, 24, 8) | _SHIFTL(gain, 16, 8) | _SHIFTL(count, 0, 16)); \ + _a->words.w1 = _SHIFTL(dmem, 16, 16) | _SHIFTL(a4, 0, 16); \ + } + +#define aUnkCmd3(pkt, a1, a2, a3) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_UNK3, 24, 8) | _SHIFTL(a3, 0, 16); \ + _a->words.w1 = _SHIFTL(a1, 16, 16) | _SHIFTL(a2, 0, 16); \ + } + +#define aUnkCmd19(pkt, a1, a2, a3, a4) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_UNK19, 24, 8) | _SHIFTL(a1, 16, 8) | _SHIFTL(a2, 0, 16)); \ + _a->words.w1 = _SHIFTL(a3, 16, 16) | _SHIFTL(a4, 0, 16); \ + } + +#define aS8Dec(pkt, a1, a2) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_S8DEC, 24, 8) | _SHIFTL(a1, 16, 8); \ + _a->words.w1 = (u32)(a2); \ + } + +#define aClearBuffer(pkt, d, c) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_CLEARBUFF, 24, 8) | _SHIFTL(d, 0, 24); \ + _a->words.w1 = (u32)(c); \ + } + +#define aEnvMixer(pkt, dmemi, count, swapLR, x0, x1, x2, x3, m, bits) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = (bits | _SHIFTL(dmemi >> 4, 16, 8) | _SHIFTL(count, 8, 8) | _SHIFTL(swapLR, 4, 1) | \ + _SHIFTL(x0, 3, 1) | _SHIFTL(x1, 2, 1) | _SHIFTL(x2, 1, 1) | _SHIFTL(x3, 0, 1)); \ + _a->words.w1 = (u32)(m); \ + } + +#define aInterleave(pkt, o, l, r, c) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_INTERLEAVE, 24, 8) | _SHIFTL(c >> 4, 16, 8) | _SHIFTL(o, 0, 16)); \ + _a->words.w1 = _SHIFTL(l, 16, 16) | _SHIFTL(r, 0, 16); \ + } + +#define aInterl(pkt, dmemi, dmemo, count) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_INTERL, 24, 8) | _SHIFTL(count, 0, 16)); \ + _a->words.w1 = _SHIFTL(dmemi, 16, 16) | _SHIFTL(dmemo, 0, 16); \ + } + +#define aLoadBuffer(pkt, s, d, c) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_LOADBUFF, 24, 8) | _SHIFTL((c) >> 4, 16, 8) | _SHIFTL(d, 0, 16)); \ + _a->words.w1 = (u32)(s); \ + } + +#define aMix(pkt, f, g, i, o) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_MIXER, 24, 8) | _SHIFTL(f, 16, 8) | _SHIFTL(g, 0, 16)); \ + _a->words.w1 = _SHIFTL(i, 16, 16) | _SHIFTL(o, 0, 16); \ + } + +#define aPan(pkt, f, d, s) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_PAN, 24, 8) | _SHIFTL(f, 16, 8) | _SHIFTL(d, 0, 16)); \ + _a->words.w1 = (u32)(s); \ + } + +#define aResample(pkt, f, p, s) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_RESAMPLE, 24, 8) | _SHIFTL(f, 16, 8) | _SHIFTL(p, 0, 16)); \ + _a->words.w1 = (u32)(s); \ + } + +#define aSaveBuffer(pkt, s, d, c) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_SAVEBUFF, 24, 8) | _SHIFTL((c) >> 4, 16, 8) | _SHIFTL(s, 0, 16)); \ + _a->words.w1 = (u32)(d); \ + } + +#define aSegment(pkt, s, b) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_SEGMENT, 24, 8); \ + _a->words.w1 = _SHIFTL(s, 24, 8) | _SHIFTL(b, 0, 24); \ + } + +#define aSetBuffer(pkt, f, i, o, c) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_SETBUFF, 24, 8) | _SHIFTL(f, 16, 8) | _SHIFTL(i, 0, 16)); \ + _a->words.w1 = _SHIFTL(o, 16, 16) | _SHIFTL(c, 0, 16); \ + } + +#define aSetVolume(pkt, f, v, t, r) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_SETVOL, 24, 8) | _SHIFTL(f, 16, 16) | _SHIFTL(v, 0, 16)); \ + _a->words.w1 = _SHIFTL(r, 0, 16) | _SHIFTL(t, 16, 16); \ + } + +#define aSetVolume32(pkt, f, v, tr) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_SETVOL, 24, 8) | _SHIFTL(f, 16, 16) | _SHIFTL(v, 0, 16)); \ + _a->words.w1 = (u32)(tr); \ + } + +#define aSetLoop(pkt, a) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_SETLOOP, 24, 8); \ + _a->words.w1 = (u32)(a); \ + } + +#define aDMEMMove(pkt, i, o, c) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_DMEMMOVE, 24, 8) | _SHIFTL(i, 0, 24); \ + _a->words.w1 = _SHIFTL(o, 16, 16) | _SHIFTL(c, 0, 16); \ + } + +#define aLoadADPCM(pkt, c, d) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_LOADADPCM, 24, 8) | _SHIFTL(c, 0, 24); \ + _a->words.w1 = (u32)d; \ + } + +#define aEnvSetup1(pkt, a, b, c, d) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_ENVSETUP1, 24, 8) | _SHIFTL(a, 16, 8) | _SHIFTL(b, 0, 16)); \ + _a->words.w1 = _SHIFTL(c, 16, 16) | _SHIFTL(d, 0, 16); \ + } + +#define aEnvSetup2(pkt, volLeft, volRight) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = _SHIFTL(A_ENVSETUP2, 24, 8); \ + _a->words.w1 = (_SHIFTL(volLeft, 16, 16) | _SHIFTL(volRight, 0, 16)); \ + } + +#define aFilter(pkt, f, countOrBuf, addr) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_FILTER, 24, 8) | _SHIFTL(f, 16, 8) | _SHIFTL(countOrBuf, 0, 16)); \ + _a->words.w1 = (u32)(addr); \ + } + +#define aDuplicate(pkt, numCopies, dmemSrc, dmemDest) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_DUPLICATE, 24, 8) | _SHIFTL(numCopies, 16, 8) | _SHIFTL(dmemSrc, 0, 16)); \ + _a->words.w1 = _SHIFTL(dmemDest, 16, 16) | _SHIFTL(0x80, 0, 16); \ + } + +#define aAddMixer(pkt, count, dmemi, dmemo, a4) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_ADDMIXER, 24, 8) | _SHIFTL(count >> 4, 16, 8) | _SHIFTL(a4, 0, 16)); \ + _a->words.w1 = _SHIFTL(dmemi, 16, 16) | _SHIFTL(dmemo, 0, 16); \ + } + +#define aResampleZoh(pkt, pitch, pitchAccu) \ + { \ + Acmd* _a = (Acmd*)pkt; \ + \ + _a->words.w0 = (_SHIFTL(A_RESAMPLE_ZOH, 24, 8) | _SHIFTL(pitch, 0, 16)); \ + _a->words.w1 = _SHIFTL(pitchAccu, 0, 16); \ + } diff --git a/libultraship/include/libultraship/libultra/controller.h b/libultraship/include/libultraship/libultra/controller.h new file mode 100644 index 000000000..a82cb3dd3 --- /dev/null +++ b/libultraship/include/libultraship/libultra/controller.h @@ -0,0 +1,162 @@ +#pragma once + +#include "stdint.h" + +#define SIAccessQueueSize 2 +#define BLOCKSIZE 32 +#define PFS_ONE_PAGE 8 + +#define PFS_PAGE_SIZE (BLOCKSIZE * PFS_ONE_PAGE) + +#define CONT_CMD_REQUEST_STATUS 0 +#define CONT_CMD_READ_BUTTON 1 +#define CONT_CMD_READ_MEMPACK 2 +#define CONT_CMD_WRITE_MEMPACK 3 +#define CONT_CMD_READ_EEPROM 4 +#define CONT_CMD_WRITE_EEPROM 5 +#define CONT_CMD_RESET 0xFF + +#define CONT_CMD_REQUEST_STATUS_TX 1 +#define CONT_CMD_READ_BUTTON_TX 1 +#define CONT_CMD_READ_MEMPACK_TX 3 +#define CONT_CMD_WRITE_MEMPACK_TX 35 +#define CONT_CMD_READ_EEPROM_TX 2 +#define CONT_CMD_WRITE_EEPROM_TX 10 +#define CONT_CMD_RESET_TX 1 + +#define CONT_CMD_REQUEST_STATUS_RX 3 +#define CONT_CMD_READ_BUTTON_RX 4 +#define CONT_CMD_READ_MEMPACK_RX 33 +#define CONT_CMD_WRITE_MEMPACK_RX 1 +#define CONT_CMD_READ_EEPROM_RX 8 +#define CONT_CMD_WRITE_EEPROM_RX 1 +#define CONT_CMD_RESET_RX 3 + +#define CONT_CMD_NOP 0xFF +#define CONT_CMD_END 0xFE // Indicates end of a command +#define CONT_CMD_EXE 1 // Set pif ram status byte to this to do a command + +#define CONT_ERR_NO_CONTROLLER PFS_ERR_NOPACK /* 1 */ +#define CONT_ERR_CONTRFAIL CONT_OVERRUN_ERROR /* 4 */ +#define CONT_ERR_INVALID PFS_ERR_INVALID /* 5 */ +#define CONT_ERR_DEVICE PFS_ERR_DEVICE /* 11 */ +#define CONT_ERR_NOT_READY 12 +#define CONT_ERR_VOICE_MEMORY 13 +#define CONT_ERR_VOICE_WORD 14 +#define CONT_ERR_VOICE_NO_RESPONSE 15 + +#define DIR_STATUS_EMPTY 0 +#define DIR_STATUS_UNKNOWN 1 +#define DIR_STATUS_OCCUPIED 2 + +#define PFS_FORCE 1 +#define PFS_DELETE 1 + +#define PFS_LABEL_AREA 7 + +#define PFS_ERR_NOPACK 1 + +#ifndef CONTROLLERBUTTONS_T +#define CONTROLLERBUTTONS_T uint16_t +#endif + +/* Buttons */ +#define BTN_CRIGHT 0x00001 +#define BTN_CLEFT 0x00002 +#define BTN_CDOWN 0x00004 +#define BTN_CUP 0x00008 +#define BTN_R 0x00010 +#define BTN_L 0x00020 +#define BTN_DRIGHT 0x00100 +#define BTN_DLEFT 0x00200 +#define BTN_DDOWN 0x00400 +#define BTN_DUP 0x00800 +#define BTN_START 0x01000 +#define BTN_Z 0x02000 +#define BTN_B 0x04000 +#define BTN_A 0x08000 +#define BTN_STICKLEFT 0x10000 +#define BTN_STICKRIGHT 0x20000 +#define BTN_STICKDOWN 0x40000 +#define BTN_STICKUP 0x80000 +#define BTN_VSTICKUP 0x100000 +#define BTN_VSTICKDOWN 0x200000 +#define BTN_VSTICKLEFT 0x400000 +#define BTN_VSTICKRIGHT 0x800000 + +typedef struct { + /* 0x00 */ int32_t ram[15]; + /* 0x3C */ int32_t status; +} OSPifRam; // size = 0x40 + +typedef struct { + /* 0x00 */ uint16_t type; + /* 0x02 */ uint8_t status; + /* 0x03 */ uint8_t err_no; +} OSContStatus; // size = 0x04 + +typedef struct { + /* 0x00 */ CONTROLLERBUTTONS_T button; + /* 0x02 */ int8_t stick_x; + /* 0x03 */ int8_t stick_y; + /* 0x04 */ uint8_t err_no; + /* 0x05 */ float gyro_x; + /* 0x09 */ float gyro_y; + /* 0x1C */ int8_t right_stick_x; + /* 0x20 */ int8_t right_stick_y; +} OSContPad; // size = 0x24 + +typedef struct { + /* 0x00 */ void* address; + /* 0x04 */ uint8_t databuffer[32]; + /* 0x24 */ uint8_t addressCrc; + /* 0x25 */ uint8_t dataCrc; + /* 0x26 */ uint8_t err_no; +} OSContRamIo; // size = 0x28 + +// Original name: __OSContRequesFormat +typedef struct { + /* 0x00 */ uint8_t align; + /* 0x01 */ uint8_t txsize; + /* 0x02 */ uint8_t rxsize; + /* 0x03 */ uint8_t poll; + /* 0x04 */ uint8_t typeh; + /* 0x05 */ uint8_t typel; + /* 0x06 */ uint8_t status; + /* 0x07 */ uint8_t align1; +} __OSContRequestHeader; // size = 0x8 + +// Original name: __OSContRequesHeaderFormatShort +typedef struct { + /* 0x00 */ uint8_t txsize; + /* 0x01 */ uint8_t rxsize; + /* 0x02 */ uint8_t poll; + /* 0x03 */ uint8_t typeh; + /* 0x04 */ uint8_t typel; + /* 0x05 */ uint8_t status; +} __OSContRequestHeaderAligned; // size = 0x6 + +// Original Name: __OSContRamReadFormat +typedef struct { + /* 0x00 */ uint8_t unk_00; + /* 0x01 */ uint8_t txsize; + /* 0x02 */ uint8_t rxsize; + /* 0x03 */ uint8_t poll; + /* 0x04 */ uint8_t hi; + /* 0x05 */ uint8_t lo; + /* 0x06 */ uint8_t data[BLOCKSIZE]; + /* 0x26 */ uint8_t datacrc; +} __OSContRamHeader; // size = 0x27 + +// Original name: __OSContReadFormat +typedef struct { + /* 0x00 */ uint8_t align; + /* 0x01 */ uint8_t txsize; + /* 0x02 */ uint8_t rxsize; + /* 0x03 */ uint8_t poll; + /* 0x04 */ uint16_t button; + /* 0x06 */ int8_t joyX; + /* 0x07 */ int8_t joyY; +} __OSContReadHeader; // size = 0x8 + +#include "os.h" diff --git a/libultraship/include/libultraship/libultra/convert.h b/libultraship/include/libultraship/libultra/convert.h new file mode 100644 index 000000000..48dd06f69 --- /dev/null +++ b/libultraship/include/libultraship/libultra/convert.h @@ -0,0 +1,15 @@ +#pragma once + +#define OS_CLOCK_RATE 62500000LL +#define OS_CPU_COUNTER (OS_CLOCK_RATE * 3 / 4) + +#define OS_NSEC_TO_CYCLES(n) (((u64)(n) * (OS_CPU_COUNTER / 15625000LL)) / (1000000000LL / 15625000LL)) +#define OS_USEC_TO_CYCLES(n) (((u64)(n) * (OS_CPU_COUNTER / 15625LL)) / (1000000LL / 15625LL)) +#define OS_CYCLES_TO_NSEC(c) (((u64)(c) * (1000000000LL / 15625000LL)) / (OS_CPU_COUNTER / 15625000LL)) +#define OS_CYCLES_TO_USEC(c) (((u64)(c) * (1000000LL / 15625LL)) / (OS_CPU_COUNTER / 15625LL)) + +#define OS_K0_TO_PHYSICAL(x) (x) +#define OS_K1_TO_PHYSICAL(x) (x) + +#define OS_PHYSICAL_TO_K0(x) (x) +#define OS_PHYSICAL_TO_K1(x) (x) diff --git a/libultraship/include/libultraship/libultra/eeprom.h b/libultraship/include/libultraship/libultra/eeprom.h new file mode 100644 index 000000000..b64c87e5c --- /dev/null +++ b/libultraship/include/libultraship/libultra/eeprom.h @@ -0,0 +1,18 @@ +#pragma once + +#include "message.h" + +#define EEPROM_TYPE_4K 0x01 +#define EEPROM_TYPE_16K 0x02 + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t osEepromProbe(OSMesgQueue*); +int32_t osEepromLongRead(OSMesgQueue*, uint8_t, uint8_t*, int32_t); +int32_t osEepromLongWrite(OSMesgQueue*, uint8_t, uint8_t*, int32_t); + +#ifdef __cplusplus +} +#endif diff --git a/libultraship/include/libultraship/libultra/exception.h b/libultraship/include/libultraship/libultra/exception.h new file mode 100644 index 000000000..7442b8073 --- /dev/null +++ b/libultraship/include/libultraship/libultra/exception.h @@ -0,0 +1,42 @@ +#pragma once + +#include "types.h" + +// Interrupt masks +#define OS_IM_NONE 0x00000001 +#define OS_IM_SW1 0x00000501 +#define OS_IM_SW2 0x00000601 +#define OS_IM_CART 0x00000C01 +#define OS_IM_PRENMI 0x00001401 +#define OS_IM_RDBWRITE 0x00002401 +#define OS_IM_RDBREAD 0x00004401 +#define OS_IM_COUNTER 0x00008401 +#define OS_IM_CPU 0x0000FF01 +#define OS_IM_SP 0x00010401 +#define OS_IM_SI 0x00020401 +#define OS_IM_AI 0x00040401 +#define OS_IM_VI 0x00080401 +#define OS_IM_PI 0x00100401 +#define OS_IM_DP 0x00200401 +#define OS_IM_ALL 0x003FFF01 + +#define RCP_IMASK 0x003F0000 +#define RCP_IMASKSHIFT 16 + +typedef u32 OSIntMask; +typedef u32 OSHWIntr; + +typedef struct { + /* 0x00 */ void* callback; + /* 0x04 */ void* sp; +} __osHwInt; // size = 0x08 + +OSIntMask osSetIntMask(OSIntMask); + +void __osSetHWIntrRoutine(OSHWIntr interrupt, s32 (*callback)(void), void* sp); +void __osGetHWIntrRoutine(OSHWIntr interrupt, s32 (**callbackOut)(void), void** spOut); + +void __osSetGlobalIntMask(OSHWIntr mask); +void __osResetGlobalIntMask(OSHWIntr mask); + +extern __osHwInt __osHwIntTable[]; diff --git a/libultraship/include/libultraship/libultra/gbi.h b/libultraship/include/libultraship/libultra/gbi.h new file mode 100644 index 000000000..6beda75f2 --- /dev/null +++ b/libultraship/include/libultraship/libultra/gbi.h @@ -0,0 +1,4311 @@ +#pragma once + +#include "mbi.h" + +#ifdef _MSC_VER +#ifndef u8 +#define u8 uint8_t +#endif + +#ifndef u16 +#define u16 uint16_t +#endif + +#ifndef u32 +#define u32 uint32_t +#endif + +#ifndef u64 +#define u64 uint64_t +#endif + +#ifndef s8 +#define s8 int8_t +#endif + +#ifndef s16 +#define s16 int16_t +#endif + +#ifndef s32 +#define s32 int32_t +#endif + +#ifndef s64 +#define s64 int64_t +#endif +#endif + +/* To enable Fast3DEX grucode support, define F3DEX_GBI. */ + +/* Types */ + +/* Private macro to wrap other macros in do {...} while (0) */ +#define _DW(macro) \ + do { \ + macro \ + } while (0) + +#ifdef F3DEX_GBI_2 +#ifndef F3DEX_GBI +#define F3DEX_GBI +#endif +#define G_NOOP 0x00 +#define G_RDPHALF_2 0xf1 +#define G_SETOTHERMODE_H 0xe3 +#define G_SETOTHERMODE_L 0xe2 +#define G_RDPHALF_1 0xe1 +#define G_SPNOOP 0xe0 +#define G_ENDDL 0xdf +#define G_DL 0xde +#define G_LOAD_UCODE 0xdd +#define G_MOVEMEM 0xdc +#define G_MOVEWORD 0xdb +#define G_MTX 0xda +#define G_GEOMETRYMODE 0xd9 +#define G_POPMTX 0xd8 +#define G_TEXTURE 0xd7 +#define G_DMA_IO 0xd6 +#define G_SPECIAL_1 0xd5 +#define G_SPECIAL_2 0xd4 +#define G_SPECIAL_3 0xd3 + +#define G_VTX 0x01 +#define G_MODIFYVTX 0x02 +#define G_CULLDL 0x03 +#define G_BRANCH_Z 0x04 +#define G_TRI1 0x05 +#define G_TRI2 0x06 +#define G_QUAD 0x07 +#define G_LINE3D 0x08 +#else /* F3DEX_GBI_2 */ + +/* DMA commands: */ +#define G_SPNOOP 0 /* handle 0 gracefully */ +#define G_MTX 1 +#define G_RESERVED0 2 /* not implemeted */ +#define G_MOVEMEM 3 /* move a block of memory (up to 4 words) to dmem */ +#define G_VTX 4 +#define G_RESERVED1 5 /* not implemeted */ +#define G_DL 6 +#define G_RESERVED2 7 /* not implemeted */ +#define G_RESERVED3 8 /* not implemeted */ +#define G_SPRITE2D_BASE 9 /* sprite command */ + +/* IMMEDIATE commands: */ +#define G_IMMFIRST -65 +#define G_TRI1 (G_IMMFIRST - 0) +#define G_CULLDL (G_IMMFIRST - 1) +#define G_POPMTX (G_IMMFIRST - 2) +#define G_MOVEWORD (G_IMMFIRST - 3) +#define G_TEXTURE (G_IMMFIRST - 4) +#define G_SETOTHERMODE_H (G_IMMFIRST - 5) +#define G_SETOTHERMODE_L (G_IMMFIRST - 6) +#define G_ENDDL (G_IMMFIRST - 7) +#define G_SETGEOMETRYMODE (G_IMMFIRST - 8) +#define G_CLEARGEOMETRYMODE (G_IMMFIRST - 9) +#define G_LINE3D (G_IMMFIRST - 10) +#define G_RDPHALF_1 (G_IMMFIRST - 11) +#define G_RDPHALF_2 (G_IMMFIRST - 12) +#if (defined(F3DEX_GBI) || defined(F3DLP_GBI)) +#define G_MODIFYVTX (G_IMMFIRST - 13) +#define G_TRI2 (G_IMMFIRST - 14) +#define G_BRANCH_Z (G_IMMFIRST - 15) +#define G_LOAD_UCODE (G_IMMFIRST - 16) +#define G_QUAD (G_IMMFIRST - 10) +#else +#define G_RDPHALF_CONT (G_IMMFIRST - 13) +#endif + +/* We are overloading 2 of the immediate commands + to keep the byte alignment of dmem the same */ + +#define G_SPRITE2D_SCALEFLIP (G_IMMFIRST - 1) +#define G_SPRITE2D_DRAW (G_IMMFIRST - 2) + +/* RDP commands: */ +#define G_NOOP 0xc0 /* 0 */ + +#endif /* F3DEX_GBI_2 */ + +/* RDP commands: */ +#define G_SETCIMG 0xff /* -1 */ +#define G_SETZIMG 0xfe /* -2 */ +#define G_SETTIMG 0xfd /* -3 */ +#define G_SETCOMBINE 0xfc /* -4 */ +#define G_SETENVCOLOR 0xfb /* -5 */ +#define G_SETPRIMCOLOR 0xfa /* -6 */ +#define G_SETBLENDCOLOR 0xf9 /* -7 */ +#define G_SETFOGCOLOR 0xf8 /* -8 */ +#define G_SETFILLCOLOR 0xf7 /* -9 */ +#define G_FILLRECT 0xf6 /* -10 */ +#define G_SETTILE 0xf5 /* -11 */ +#define G_LOADTILE 0xf4 /* -12 */ +#define G_LOADBLOCK 0xf3 /* -13 */ +#define G_SETTILESIZE 0xf2 /* -14 */ +#define G_LOADTLUT 0xf0 /* -16 */ +#define G_RDPSETOTHERMODE 0xef /* -17 */ +#define G_SETPRIMDEPTH 0xee /* -18 */ +#define G_SETSCISSOR 0xed /* -19 */ +#define G_SETCONVERT 0xec /* -20 */ +#define G_SETKEYR 0xeb /* -21 */ +#define G_SETKEYGB 0xea /* -22 */ +#define G_RDPFULLSYNC 0xe9 /* -23 */ +#define G_RDPTILESYNC 0xe8 /* -24 */ +#define G_RDPPIPESYNC 0xe7 /* -25 */ +#define G_RDPLOADSYNC 0xe6 /* -26 */ +#define G_TEXRECTFLIP 0xe5 /* -27 */ +#define G_TEXRECT 0xe4 /* -28 */ + +// CUSTOM OTR COMMANDS +#define G_SETTIMG_OTR_HASH 0x20 +#define G_SETFB 0x21 +#define G_RESETFB 0x22 +#define G_SETTIMG_FB 0x23 +#define G_VTX_OTR_FILEPATH 0x24 +#define G_SETTIMG_OTR_FILEPATH 0x25 +#define G_TRI1_OTR 0x26 +#define G_DL_OTR_FILEPATH 0x27 +#define G_PUSHCD 0x28 +#define G_MTX_OTR_FILEPATH 0x29 +#define G_DL_OTR_HASH 0x31 +#define G_VTX_OTR_HASH 0x32 +#define G_MARKER 0x33 +#define G_INVALTEXCACHE 0x34 +#define G_BRANCH_Z_OTR 0x35 +#define G_MTX_OTR 0x36 +#define G_TEXRECT_WIDE 0x37 +#define G_FILLWIDERECT 0x38 +#define G_REGBLENDEDTEX 0x3f +#define G_MOVEMEM_OTR 0x42 +#define G_LOADBLOCK_WIDE 0x47 +#define G_VTX_WIDE 0x48 +#define G_TRI1_WIDE 0x49 + +/* GFX Effects */ + +// RDP Cmd +#define G_SETGRAYSCALE 0x39 +#define G_EXTRAGEOMETRYMODE 0x3a +#define G_COPYFB 0x3b +#define G_IMAGERECT 0x3c +#define G_DL_INDEX 0x3d +#define G_READFB 0x3e +#define G_SETINTENSITY 0x40 +#define G_PUSH_SHADER 0x43 +#define G_POP_SHADER 0x44 +#define G_SETTILESIZE_INTERP 0x45 +#define G_SETTARGETINTERPINDEX 0x46 +#define G_SETTILESIZE_LERP 0x4a + +/* + * The following commands are the "generated" RDP commands; the user + * never sees them, the RSP microcode generates them. + * + * The layout of the bits is magical, to save work in the ucode. + * These id's are -56, -52, -54, -50, -55, -51, -53, -49, ... + * edge, shade, texture, zbuff bits: estz + */ +#define G_TRI_FILL 0xc8 /* fill triangle: 11001000 */ +#define G_TRI_SHADE 0xcc /* shade triangle: 11001100 */ +#define G_TRI_TXTR 0xca /* texture triangle: 11001010 */ +#define G_TRI_SHADE_TXTR 0xce /* shade, texture triangle: 11001110 */ +#define G_TRI_FILL_ZBUFF 0xc9 /* fill, zbuff triangle: 11001001 */ +#define G_TRI_SHADE_ZBUFF 0xcd /* shade, zbuff triangle: 11001101 */ +#define G_TRI_TXTR_ZBUFF 0xcb /* texture, zbuff triangle: 11001011 */ +#define G_TRI_SHADE_TXTR_ZBUFF 0xcf /* shade, txtr, zbuff trngl: 11001111 */ + +/* + * A TRI_FILL triangle is just the edges. You need to set the DP + * to use primcolor, in order to see anything. (it is NOT a triangle + * that gets rendered in 'fill mode'. Triangles can't be rendered + * in 'fill mode') + * + * A TRI_SHADE is a gouraud triangle that has colors interpolated. + * Flat-shaded triangles (from the software) are still gouraud shaded, + * it's just the colors are all the same and the deltas are 0. + * + * Other triangle types, and combinations are more obvious. + */ + +/* masks to build RDP triangle commands: */ +#define G_RDP_TRI_FILL_MASK 0x08 +#define G_RDP_TRI_SHADE_MASK 0x04 +#define G_RDP_TRI_TXTR_MASK 0x02 +#define G_RDP_TRI_ZBUFF_MASK 0x01 + +/* + * HACK: + * This is a dreadful hack. For version 1.0 hardware, there are still + * some 'bowtie' hangs. This parameter can be increased to avoid + * the hangs. Every increase of 4 chops one scanline off of every + * triangle. Values of 4,8,12 should be sufficient to avoid any + * bowtie hang. + * + * Change this value, then recompile ALL of your program (including static + * display lists!) + * + * THIS WILL BE REMOVED FOR HARDWARE VERSION 2.0! + */ +#define BOWTIE_VAL 0 + +/* gets added to RDP command, in order to test for addres fixup: */ +#define G_RDP_ADDR_FIXUP 3 /* |RDP cmds| <= this, do addr fixup */ +#ifdef _LANGUAGE_ASSEMBLY +#define G_RDP_TEXRECT_CHECK ((-1 * G_TEXRECTFLIP) & 0xff) +#endif + +/* macros for command parsing: */ +#define GDMACMD(x) (x) +#define GIMMCMD(x) (G_IMMFIRST - (x)) +#define GRDPCMD(x) (0xff - (x)) + +#define G_DMACMDSIZ 128 +#define G_IMMCMDSIZ 64 +#define G_RDPCMDSIZ 64 + +/* + * Coordinate shift values, number of bits of fraction + */ +#define G_TEXTURE_IMAGE_FRAC 2 +#define G_TEXTURE_SCALE_FRAC 16 +#define G_SCALE_FRAC 8 +#define G_ROTATE_FRAC 16 + +/* + * Parameters to graphics commands + */ + +/* + * Data packing macros + */ + +/* + * Maximum z-buffer value, used to initialize the z-buffer. + * Note : this number is NOT the viewport z-scale constant. + * See the comment next to G_MAXZ for more info. + */ +#define G_MAXFBZ 0x3fff /* 3b exp, 11b mantissa */ + +#define GPACK_RGBA5551(r, g, b, a) ((((r) << 8) & 0xf800) | (((g) << 3) & 0x7c0) | (((b) >> 2) & 0x3e) | ((a)&0x1)) +#define GPACK_ZDZ(z, dz) ((z) << 2 | (dz)) + +/* + * G_MTX: parameter flags + */ +#ifdef F3DEX_GBI_2 +#define G_MTX_MODELVIEW 0x00 /* matrix types */ +#define G_MTX_PROJECTION 0x04 +#define G_MTX_MUL 0x00 /* concat or load */ +#define G_MTX_LOAD 0x02 +#define G_MTX_NOPUSH 0x00 /* push or not */ +#define G_MTX_PUSH 0x01 +#else /* F3DEX_GBI_2 */ +#define G_MTX_MODELVIEW 0x00 /* matrix types */ +#define G_MTX_PROJECTION 0x01 +#define G_MTX_MUL 0x00 /* concat or load */ +#define G_MTX_LOAD 0x02 +#define G_MTX_NOPUSH 0x00 /* push or not */ +#define G_MTX_PUSH 0x04 +#endif /* F3DEX_GBI_2 */ + +/* + * flags for G_SETGEOMETRYMODE + * (this rendering state is maintained in RSP) + * + * DO NOT USE THE LOW 8 BITS OF GEOMETRYMODE: + * The weird bit-ordering is for the micro-code: the lower byte + * can be OR'd in with G_TRI_SHADE (11001100) to construct + * the triangle command directly. Don't break it... + * + * DO NOT USE THE HIGH 8 BITS OF GEOMETRYMODE: + * The high byte is OR'd with 0x703 to form the clip code mask. + * If it is set to 0x04, this will cause near clipping to occur. + * If it is zero, near clipping will not occur. + * + * Further explanation: + * G_SHADE is necessary in order to see the color that you passed + * down with the vertex. If G_SHADE isn't set, you need to set the DP + * appropriately and use primcolor to see anything. + * + * G_SHADING_SMOOTH enabled means use all 3 colors of the triangle. + * If it is not set, then do 'flat shading', where only one vertex color + * is used (and all 3 vertices are set to that same color by the ucode) + * See the man page for gSP1Triangle(). + * + */ +#define G_ZBUFFER 0x00000001 +#define G_SHADE 0x00000004 /* enable Gouraud interp */ + /* rest of low byte reserved for setup ucode */ +#ifdef F3DEX_GBI_2 +#define G_TEXTURE_ENABLE 0x00000000 /* Ignored */ +#define G_SHADING_SMOOTH 0x00200000 /* flat or smooth shaded */ +#define G_CULL_FRONT 0x00000200 +#define G_CULL_BACK 0x00000400 +#define G_CULL_BOTH 0x00000600 /* To make code cleaner */ +#else +#define G_TEXTURE_ENABLE 0x00000002 /* Microcode use only */ +#define G_SHADING_SMOOTH 0x00000200 /* flat or smooth shaded */ +#define G_CULL_FRONT 0x00001000 +#define G_CULL_BACK 0x00002000 +#define G_CULL_BOTH 0x00003000 /* To make code cleaner */ +#endif +#define G_FOG 0x00010000 +#define G_LIGHTING 0x00020000 +#define G_TEXTURE_GEN 0x00040000 +#define G_TEXTURE_GEN_LINEAR 0x00080000 +#define G_LOD 0x00100000 /* NOT IMPLEMENTED */ +#define G_LIGHTING_POSITIONAL 0x00400000 +#if (defined(F3DEX_GBI) || defined(F3DLP_GBI)) +#define G_CLIPPING 0x00800000 +#else +#define G_CLIPPING 0x00000000 +#endif + +#ifdef _LANGUAGE_ASSEMBLY +#define G_FOG_H (G_FOG / 0x10000) +#define G_LIGHTING_H (G_LIGHTING / 0x10000) +#define G_TEXTURE_GEN_H (G_TEXTURE_GEN / 0x10000) +#define G_TEXTURE_GEN_LINEAR_H (G_TEXTURE_GEN_LINEAR / 0x10000) +#define G_LOD_H (G_LOD / 0x10000) /* NOT IMPLEMENTED */ +#if (defined(F3DEX_GBI) || defined(F3DLP_GBI)) +#define G_CLIPPING_H (G_CLIPPING / 0x10000) +#endif +#endif + +/* + * G_EXTRAGEOMETRY flags: set extra custom geometry modes + */ +#define G_EX_INVERT_CULLING 0x00000001 +#define G_EX_ALWAYS_EXECUTE_BRANCH 0x00000002 + +/* Need these defined for Sprite Microcode */ +#ifdef _LANGUAGE_ASSEMBLY +#define G_TX_LOADTILE 7 +#define G_TX_RENDERTILE 0 + +#define G_TX_NOMIRROR 0 +#define G_TX_WRAP 0 +#define G_TX_MIRROR 0x1 +#define G_TX_CLAMP 0x2 +#define G_TX_NOMASK 0 +#define G_TX_NOLOD 0 +#endif + +/* + * G_SETIMG fmt: set image formats + */ +#define G_IM_FMT_RGBA 0 +#define G_IM_FMT_YUV 1 +#define G_IM_FMT_CI 2 +#define G_IM_FMT_IA 3 +#define G_IM_FMT_I 4 + +/* + * G_SETIMG siz: set image pixel size + */ +#define G_IM_SIZ_4b 0 +#define G_IM_SIZ_8b 1 +#define G_IM_SIZ_16b 2 +#define G_IM_SIZ_32b 3 +#define G_IM_SIZ_DD 5 + +#define G_IM_SIZ_4b_BYTES 0 +#define G_IM_SIZ_4b_TILE_BYTES G_IM_SIZ_4b_BYTES +#define G_IM_SIZ_4b_LINE_BYTES G_IM_SIZ_4b_BYTES + +#define G_IM_SIZ_8b_BYTES 1 +#define G_IM_SIZ_8b_TILE_BYTES G_IM_SIZ_8b_BYTES +#define G_IM_SIZ_8b_LINE_BYTES G_IM_SIZ_8b_BYTES + +#define G_IM_SIZ_16b_BYTES 2 +#define G_IM_SIZ_16b_TILE_BYTES G_IM_SIZ_16b_BYTES +#define G_IM_SIZ_16b_LINE_BYTES G_IM_SIZ_16b_BYTES + +#define G_IM_SIZ_32b_BYTES 4 +#define G_IM_SIZ_32b_TILE_BYTES 2 +#define G_IM_SIZ_32b_LINE_BYTES 2 + +#define G_IM_SIZ_4b_LOAD_BLOCK G_IM_SIZ_16b +#define G_IM_SIZ_8b_LOAD_BLOCK G_IM_SIZ_16b +#define G_IM_SIZ_16b_LOAD_BLOCK G_IM_SIZ_16b +#define G_IM_SIZ_32b_LOAD_BLOCK G_IM_SIZ_32b + +#define G_IM_SIZ_4b_SHIFT 2 +#define G_IM_SIZ_8b_SHIFT 1 +#define G_IM_SIZ_16b_SHIFT 0 +#define G_IM_SIZ_32b_SHIFT 0 + +#define G_IM_SIZ_4b_INCR 3 +#define G_IM_SIZ_8b_INCR 1 +#define G_IM_SIZ_16b_INCR 0 +#define G_IM_SIZ_32b_INCR 0 + +/* + * G_SETCOMBINE: color combine modes + */ +/* Color combiner constants: */ +#define G_CCMUX_COMBINED 0 +#define G_CCMUX_TEXEL0 1 +#define G_CCMUX_TEXEL1 2 +#define G_CCMUX_PRIMITIVE 3 +#define G_CCMUX_SHADE 4 +#define G_CCMUX_ENVIRONMENT 5 +#define G_CCMUX_CENTER 6 +#define G_CCMUX_SCALE 6 +#define G_CCMUX_COMBINED_ALPHA 7 +#define G_CCMUX_TEXEL0_ALPHA 8 +#define G_CCMUX_TEXEL1_ALPHA 9 +#define G_CCMUX_PRIMITIVE_ALPHA 10 +#define G_CCMUX_SHADE_ALPHA 11 +#define G_CCMUX_ENV_ALPHA 12 +#define G_CCMUX_LOD_FRACTION 13 +#define G_CCMUX_PRIM_LOD_FRAC 14 +#define G_CCMUX_NOISE 7 +#define G_CCMUX_K4 7 +#define G_CCMUX_K5 15 +#define G_CCMUX_1 6 +#define G_CCMUX_0 31 + +/* Alpha combiner constants: */ +#define G_ACMUX_COMBINED 0 +#define G_ACMUX_TEXEL0 1 +#define G_ACMUX_TEXEL1 2 +#define G_ACMUX_PRIMITIVE 3 +#define G_ACMUX_SHADE 4 +#define G_ACMUX_ENVIRONMENT 5 +#define G_ACMUX_LOD_FRACTION 0 +#define G_ACMUX_PRIM_LOD_FRAC 6 +#define G_ACMUX_1 6 +#define G_ACMUX_0 7 + +/* typical CC cycle 1 modes */ +#define G_CC_PRIMITIVE 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE +#define G_CC_SHADE 0, 0, 0, SHADE, 0, 0, 0, SHADE +#define G_CC_MODULATEI TEXEL0, 0, SHADE, 0, 0, 0, 0, SHADE +#define G_CC_MODULATEIA TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0 +#define G_CC_MODULATEIDECALA TEXEL0, 0, SHADE, 0, 0, 0, 0, TEXEL0 +#define G_CC_MODULATERGB G_CC_MODULATEI +#define G_CC_MODULATERGBA G_CC_MODULATEIA +#define G_CC_MODULATERGBDECALA G_CC_MODULATEIDECALA +#define G_CC_MODULATEI_PRIM TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE +#define G_CC_MODULATEIA_PRIM TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, PRIMITIVE, 0 +#define G_CC_MODULATEIDECALA_PRIM TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, TEXEL0 +#define G_CC_MODULATERGB_PRIM G_CC_MODULATEI_PRIM +#define G_CC_MODULATERGBA_PRIM G_CC_MODULATEIA_PRIM +#define G_CC_MODULATERGBDECALA_PRIM G_CC_MODULATEIDECALA_PRIM +#define G_CC_DECALRGB 0, 0, 0, TEXEL0, 0, 0, 0, SHADE +#define G_CC_DECALRGBA 0, 0, 0, TEXEL0, 0, 0, 0, TEXEL0 +#define G_CC_BLENDI ENVIRONMENT, SHADE, TEXEL0, SHADE, 0, 0, 0, SHADE +#define G_CC_BLENDIA ENVIRONMENT, SHADE, TEXEL0, SHADE, TEXEL0, 0, SHADE, 0 +#define G_CC_BLENDIDECALA ENVIRONMENT, SHADE, TEXEL0, SHADE, 0, 0, 0, TEXEL0 +#define G_CC_BLENDRGBA TEXEL0, SHADE, TEXEL0_ALPHA, SHADE, 0, 0, 0, SHADE +#define G_CC_BLENDRGBDECALA TEXEL0, SHADE, TEXEL0_ALPHA, SHADE, 0, 0, 0, TEXEL0 +#define G_CC_ADDRGB 1, 0, TEXEL0, SHADE, 0, 0, 0, SHADE +#define G_CC_ADDRGBDECALA 1, 0, TEXEL0, SHADE, 0, 0, 0, TEXEL0 +#define G_CC_REFLECTRGB ENVIRONMENT, 0, TEXEL0, SHADE, 0, 0, 0, SHADE +#define G_CC_REFLECTRGBDECALA ENVIRONMENT, 0, TEXEL0, SHADE, 0, 0, 0, TEXEL0 +#define G_CC_HILITERGB PRIMITIVE, SHADE, TEXEL0, SHADE, 0, 0, 0, SHADE +#define G_CC_HILITERGBA PRIMITIVE, SHADE, TEXEL0, SHADE, PRIMITIVE, SHADE, TEXEL0, SHADE +#define G_CC_HILITERGBDECALA PRIMITIVE, SHADE, TEXEL0, SHADE, 0, 0, 0, TEXEL0 +#define G_CC_SHADEDECALA 0, 0, 0, SHADE, 0, 0, 0, TEXEL0 +#define G_CC_BLENDPE PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, SHADE, 0 +#define G_CC_BLENDPEDECALA PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, 0, 0, 0, TEXEL0 + +/* oddball modes */ +#define _G_CC_BLENDPE ENVIRONMENT, PRIMITIVE, TEXEL0, PRIMITIVE, TEXEL0, 0, SHADE, 0 +#define _G_CC_BLENDPEDECALA ENVIRONMENT, PRIMITIVE, TEXEL0, PRIMITIVE, 0, 0, 0, TEXEL0 +#define _G_CC_TWOCOLORTEX PRIMITIVE, SHADE, TEXEL0, SHADE, 0, 0, 0, SHADE +/* used for 1-cycle sparse mip-maps, primitive color has color of lowest LOD */ +#define _G_CC_SPARSEST PRIMITIVE, TEXEL0, LOD_FRACTION, TEXEL0, PRIMITIVE, TEXEL0, LOD_FRACTION, TEXEL0 +#define G_CC_TEMPLERP TEXEL1, TEXEL0, PRIM_LOD_FRAC, TEXEL0, TEXEL1, TEXEL0, PRIM_LOD_FRAC, TEXEL0 + +/* typical CC cycle 1 modes, usually followed by other cycle 2 modes */ +#define G_CC_TRILERP TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0 +#define G_CC_INTERFERENCE TEXEL0, 0, TEXEL1, 0, TEXEL0, 0, TEXEL1, 0 + +/* + * One-cycle color convert operation + */ +#define G_CC_1CYUV2RGB TEXEL0, K4, K5, TEXEL0, 0, 0, 0, SHADE + +/* + * NOTE: YUV2RGB expects TF step1 color conversion to occur in 2nd clock. + * Therefore, CC looks for step1 results in TEXEL1 + */ +#define G_CC_YUV2RGB TEXEL1, K4, K5, TEXEL1, 0, 0, 0, 0 + +/* typical CC cycle 2 modes */ +#define G_CC_PASS2 0, 0, 0, COMBINED, 0, 0, 0, COMBINED +#define G_CC_MODULATEI2 COMBINED, 0, SHADE, 0, 0, 0, 0, SHADE +#define G_CC_MODULATEIA2 COMBINED, 0, SHADE, 0, COMBINED, 0, SHADE, 0 +#define G_CC_MODULATERGB2 G_CC_MODULATEI2 +#define G_CC_MODULATERGBA2 G_CC_MODULATEIA2 +#define G_CC_MODULATEI_PRIM2 COMBINED, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE +#define G_CC_MODULATEIA_PRIM2 COMBINED, 0, PRIMITIVE, 0, COMBINED, 0, PRIMITIVE, 0 +#define G_CC_MODULATERGB_PRIM2 G_CC_MODULATEI_PRIM2 +#define G_CC_MODULATERGBA_PRIM2 G_CC_MODULATEIA_PRIM2 +#define G_CC_DECALRGB2 0, 0, 0, COMBINED, 0, 0, 0, SHADE +/* + * ? +#define G_CC_DECALRGBA2 COMBINED, SHADE, COMBINED_ALPHA, SHADE, 0, 0, 0, SHADE +*/ +#define G_CC_BLENDI2 ENVIRONMENT, SHADE, COMBINED, SHADE, 0, 0, 0, SHADE +#define G_CC_BLENDIA2 ENVIRONMENT, SHADE, COMBINED, SHADE, COMBINED, 0, SHADE, 0 +#define G_CC_CHROMA_KEY2 TEXEL0, CENTER, SCALE, 0, 0, 0, 0, 0 +#define G_CC_HILITERGB2 ENVIRONMENT, COMBINED, TEXEL0, COMBINED, 0, 0, 0, SHADE +#define G_CC_HILITERGBA2 ENVIRONMENT, COMBINED, TEXEL0, COMBINED, ENVIRONMENT, COMBINED, TEXEL0, COMBINED +#define G_CC_HILITERGBDECALA2 ENVIRONMENT, COMBINED, TEXEL0, COMBINED, 0, 0, 0, TEXEL0 +#define G_CC_HILITERGBPASSA2 ENVIRONMENT, COMBINED, TEXEL0, COMBINED, 0, 0, 0, COMBINED + +/* + * G_SETOTHERMODE_L sft: shift count + */ +#define G_MDSFT_ALPHACOMPARE 0 +#define G_MDSFT_ZSRCSEL 2 +#define G_MDSFT_RENDERMODE 3 +#define G_MDSFT_BLENDER 16 + +/* + * G_SETOTHERMODE_H sft: shift count + */ +#define G_MDSFT_BLENDMASK 0 /* unsupported */ +#define G_MDSFT_ALPHADITHER 4 +#define G_MDSFT_RGBDITHER 6 + +#define G_MDSFT_COMBKEY 8 +#define G_MDSFT_TEXTCONV 9 +#define G_MDSFT_TEXTFILT 12 +#define G_MDSFT_TEXTLUT 14 +#define G_MDSFT_TEXTLOD 16 +#define G_MDSFT_TEXTDETAIL 17 +#define G_MDSFT_TEXTPERSP 19 +#define G_MDSFT_CYCLETYPE 20 +#define G_MDSFT_COLORDITHER 22 /* unsupported in HW 2.0 */ +#define G_MDSFT_PIPELINE 23 + +/* G_SETOTHERMODE_H gPipelineMode */ +#define G_PM_1PRIMITIVE (1 << G_MDSFT_PIPELINE) +#define G_PM_NPRIMITIVE (0 << G_MDSFT_PIPELINE) + +/* G_SETOTHERMODE_H gSetCycleType */ +#define G_CYC_1CYCLE (0 << G_MDSFT_CYCLETYPE) +#define G_CYC_2CYCLE (1 << G_MDSFT_CYCLETYPE) +#define G_CYC_COPY (2 << G_MDSFT_CYCLETYPE) +#define G_CYC_FILL (3 << G_MDSFT_CYCLETYPE) + +/* G_SETOTHERMODE_H gSetTexturePersp */ +#define G_TP_NONE (0 << G_MDSFT_TEXTPERSP) +#define G_TP_PERSP (1 << G_MDSFT_TEXTPERSP) + +/* G_SETOTHERMODE_H gSetTextureDetail */ +#define G_TD_CLAMP (0 << G_MDSFT_TEXTDETAIL) +#define G_TD_SHARPEN (1 << G_MDSFT_TEXTDETAIL) +#define G_TD_DETAIL (2 << G_MDSFT_TEXTDETAIL) + +/* G_SETOTHERMODE_H gSetTextureLOD */ +#define G_TL_TILE (0 << G_MDSFT_TEXTLOD) +#define G_TL_LOD (1 << G_MDSFT_TEXTLOD) + +/* G_SETOTHERMODE_H gSetTextureLUT */ +#define G_TT_NONE (0 << G_MDSFT_TEXTLUT) +#define G_TT_RGBA16 (2 << G_MDSFT_TEXTLUT) +#define G_TT_IA16 (3 << G_MDSFT_TEXTLUT) + +/* G_SETOTHERMODE_H gSetTextureFilter */ +#define G_TF_POINT (0 << G_MDSFT_TEXTFILT) +#define G_TF_AVERAGE (3 << G_MDSFT_TEXTFILT) +#define G_TF_BILERP (2 << G_MDSFT_TEXTFILT) + +/* G_SETOTHERMODE_H gSetTextureConvert */ +#define G_TC_CONV (0 << G_MDSFT_TEXTCONV) +#define G_TC_FILTCONV (5 << G_MDSFT_TEXTCONV) +#define G_TC_FILT (6 << G_MDSFT_TEXTCONV) + +/* G_SETOTHERMODE_H gSetCombineKey */ +#define G_CK_NONE (0 << G_MDSFT_COMBKEY) +#define G_CK_KEY (1 << G_MDSFT_COMBKEY) + +/* G_SETOTHERMODE_H gSetColorDither */ +#define G_CD_MAGICSQ (0 << G_MDSFT_RGBDITHER) +#define G_CD_BAYER (1 << G_MDSFT_RGBDITHER) +#define G_CD_NOISE (2 << G_MDSFT_RGBDITHER) + +#ifndef _HW_VERSION_1 +#define G_CD_DISABLE (3 << G_MDSFT_RGBDITHER) +#define G_CD_ENABLE G_CD_NOISE /* HW 1.0 compatibility mode */ +#else +#define G_CD_ENABLE (1 << G_MDSFT_COLORDITHER) +#define G_CD_DISABLE (0 << G_MDSFT_COLORDITHER) +#endif + +/* G_SETOTHERMODE_H gSetAlphaDither */ +#define G_AD_PATTERN (0 << G_MDSFT_ALPHADITHER) +#define G_AD_NOTPATTERN (1 << G_MDSFT_ALPHADITHER) +#define G_AD_NOISE (2 << G_MDSFT_ALPHADITHER) +#define G_AD_DISABLE (3 << G_MDSFT_ALPHADITHER) + +/* G_SETOTHERMODE_L gSetAlphaCompare */ +#define G_AC_NONE (0 << G_MDSFT_ALPHACOMPARE) +#define G_AC_THRESHOLD (1 << G_MDSFT_ALPHACOMPARE) +#define G_AC_DITHER (3 << G_MDSFT_ALPHACOMPARE) + +/* G_SETOTHERMODE_L gSetDepthSource */ +#define G_ZS_PIXEL (0 << G_MDSFT_ZSRCSEL) +#define G_ZS_PRIM (1 << G_MDSFT_ZSRCSEL) + +/* G_SETOTHERMODE_L gSetRenderMode */ +#define AA_EN 0x8 +#define Z_CMP 0x10 +#define Z_UPD 0x20 +#define IM_RD 0x40 +#define CLR_ON_CVG 0x80 +#define CVG_DST_CLAMP 0 +#define CVG_DST_WRAP 0x100 +#define CVG_DST_FULL 0x200 +#define CVG_DST_SAVE 0x300 +#define ZMODE_OPA 0 +#define ZMODE_INTER 0x400 +#define ZMODE_XLU 0x800 +#define ZMODE_DEC 0xc00 +#define CVG_X_ALPHA 0x1000 +#define ALPHA_CVG_SEL 0x2000 +#define FORCE_BL 0x4000 +#define TEX_EDGE 0x0000 /* used to be 0x8000 */ + +#define G_BL_CLR_IN 0 +#define G_BL_CLR_MEM 1 +#define G_BL_CLR_BL 2 +#define G_BL_CLR_FOG 3 +#define G_BL_1MA 0 +#define G_BL_A_MEM 1 +#define G_BL_A_IN 0 +#define G_BL_A_FOG 1 +#define G_BL_A_SHADE 2 +#define G_BL_1 2 +#define G_BL_0 3 + +#define GBL_c1(m1a, m1b, m2a, m2b) (uint32_t)(m1a) << 30 | (m1b) << 26 | (m2a) << 22 | (m2b) << 18 +#define GBL_c2(m1a, m1b, m2a, m2b) (m1a) << 28 | (m1b) << 24 | (m2a) << 20 | (m2b) << 16 + +#define RM_AA_ZB_OPA_SURF(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_RA_ZB_OPA_SURF(clk) \ + AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_ZB_XLU_SURF(clk) \ + AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | FORCE_BL | ZMODE_XLU | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_OPA_DECAL(clk) \ + AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | ALPHA_CVG_SEL | ZMODE_DEC | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_RA_ZB_OPA_DECAL(clk) \ + AA_EN | Z_CMP | CVG_DST_WRAP | ALPHA_CVG_SEL | ZMODE_DEC | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_ZB_XLU_DECAL(clk) \ + AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | FORCE_BL | ZMODE_DEC | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_OPA_INTER(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ALPHA_CVG_SEL | ZMODE_INTER | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_RA_ZB_OPA_INTER(clk) \ + AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP | ALPHA_CVG_SEL | ZMODE_INTER | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_ZB_XLU_INTER(clk) \ + AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | FORCE_BL | ZMODE_INTER | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_XLU_LINE(clk) \ + AA_EN | Z_CMP | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | FORCE_BL | ZMODE_XLU | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_DEC_LINE(clk) \ + AA_EN | Z_CMP | IM_RD | CVG_DST_SAVE | CVG_X_ALPHA | ALPHA_CVG_SEL | FORCE_BL | ZMODE_DEC | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_TEX_EDGE(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_ZB_TEX_INTER(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_INTER | TEX_EDGE | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_ZB_SUB_SURF(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_ZB_PCL_SURF(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | G_AC_DITHER | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_OPA_TERR(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_TEX_TERR(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_ZB_SUB_TERR(clk) \ + AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_OPA_SURF(clk) \ + AA_EN | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_RA_OPA_SURF(clk) \ + AA_EN | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_XLU_SURF(clk) \ + AA_EN | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | FORCE_BL | ZMODE_OPA | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_XLU_LINE(clk) \ + AA_EN | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_DEC_LINE(clk) \ + AA_EN | IM_RD | CVG_DST_FULL | CVG_X_ALPHA | ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_TEX_EDGE(clk) \ + AA_EN | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_SUB_SURF(clk) \ + AA_EN | IM_RD | CVG_DST_FULL | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_AA_PCL_SURF(clk) \ + AA_EN | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | G_AC_DITHER | GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_OPA_TERR(clk) \ + AA_EN | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_TEX_TERR(clk) \ + AA_EN | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_AA_SUB_TERR(clk) \ + AA_EN | IM_RD | CVG_DST_FULL | ZMODE_OPA | ALPHA_CVG_SEL | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_ZB_OPA_SURF(clk) \ + Z_CMP | Z_UPD | CVG_DST_FULL | ALPHA_CVG_SEL | ZMODE_OPA | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_ZB_XLU_SURF(clk) \ + Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_XLU | GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_ZB_OPA_DECAL(clk) \ + Z_CMP | CVG_DST_FULL | ALPHA_CVG_SEL | ZMODE_DEC | GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + +#define RM_ZB_XLU_DECAL(clk) \ + Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_DEC | GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_ZB_CLD_SURF(clk) \ + Z_CMP | IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_XLU | GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_ZB_OVL_SURF(clk) \ + Z_CMP | IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_DEC | GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_ZB_PCL_SURF(clk) \ + Z_CMP | Z_UPD | CVG_DST_FULL | ZMODE_OPA | G_AC_DITHER | GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + +#define RM_OPA_SURF(clk) CVG_DST_CLAMP | FORCE_BL | ZMODE_OPA | GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + +#define RM_XLU_SURF(clk) \ + IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_OPA | GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_TEX_EDGE(clk) \ + CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA | TEX_EDGE | AA_EN | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + +#define RM_CLD_SURF(clk) \ + IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_OPA | GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define RM_PCL_SURF(clk) \ + CVG_DST_FULL | FORCE_BL | ZMODE_OPA | G_AC_DITHER | GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + +#define RM_ADD(clk) \ + IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_OPA | GBL_c##clk(G_BL_CLR_IN, G_BL_A_FOG, G_BL_CLR_MEM, G_BL_1) + +#define RM_NOOP(clk) GBL_c##clk(0, 0, 0, 0) + +#define RM_VISCVG(clk) IM_RD | FORCE_BL | GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_BL, G_BL_A_MEM) + +/* for rendering to an 8-bit framebuffer */ +#define RM_OPA_CI(clk) CVG_DST_CLAMP | ZMODE_OPA | GBL_c##clk(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + +#define G_RM_AA_ZB_OPA_SURF RM_AA_ZB_OPA_SURF(1) +#define G_RM_AA_ZB_OPA_SURF2 RM_AA_ZB_OPA_SURF(2) +#define G_RM_AA_ZB_XLU_SURF RM_AA_ZB_XLU_SURF(1) +#define G_RM_AA_ZB_XLU_SURF2 RM_AA_ZB_XLU_SURF(2) +#define G_RM_AA_ZB_OPA_DECAL RM_AA_ZB_OPA_DECAL(1) +#define G_RM_AA_ZB_OPA_DECAL2 RM_AA_ZB_OPA_DECAL(2) +#define G_RM_AA_ZB_XLU_DECAL RM_AA_ZB_XLU_DECAL(1) +#define G_RM_AA_ZB_XLU_DECAL2 RM_AA_ZB_XLU_DECAL(2) +#define G_RM_AA_ZB_OPA_INTER RM_AA_ZB_OPA_INTER(1) +#define G_RM_AA_ZB_OPA_INTER2 RM_AA_ZB_OPA_INTER(2) +#define G_RM_AA_ZB_XLU_INTER RM_AA_ZB_XLU_INTER(1) +#define G_RM_AA_ZB_XLU_INTER2 RM_AA_ZB_XLU_INTER(2) +#define G_RM_AA_ZB_XLU_LINE RM_AA_ZB_XLU_LINE(1) +#define G_RM_AA_ZB_XLU_LINE2 RM_AA_ZB_XLU_LINE(2) +#define G_RM_AA_ZB_DEC_LINE RM_AA_ZB_DEC_LINE(1) +#define G_RM_AA_ZB_DEC_LINE2 RM_AA_ZB_DEC_LINE(2) +#define G_RM_AA_ZB_TEX_EDGE RM_AA_ZB_TEX_EDGE(1) +#define G_RM_AA_ZB_TEX_EDGE2 RM_AA_ZB_TEX_EDGE(2) +#define G_RM_AA_ZB_TEX_INTER RM_AA_ZB_TEX_INTER(1) +#define G_RM_AA_ZB_TEX_INTER2 RM_AA_ZB_TEX_INTER(2) +#define G_RM_AA_ZB_SUB_SURF RM_AA_ZB_SUB_SURF(1) +#define G_RM_AA_ZB_SUB_SURF2 RM_AA_ZB_SUB_SURF(2) +#define G_RM_AA_ZB_PCL_SURF RM_AA_ZB_PCL_SURF(1) +#define G_RM_AA_ZB_PCL_SURF2 RM_AA_ZB_PCL_SURF(2) +#define G_RM_AA_ZB_OPA_TERR RM_AA_ZB_OPA_TERR(1) +#define G_RM_AA_ZB_OPA_TERR2 RM_AA_ZB_OPA_TERR(2) +#define G_RM_AA_ZB_TEX_TERR RM_AA_ZB_TEX_TERR(1) +#define G_RM_AA_ZB_TEX_TERR2 RM_AA_ZB_TEX_TERR(2) +#define G_RM_AA_ZB_SUB_TERR RM_AA_ZB_SUB_TERR(1) +#define G_RM_AA_ZB_SUB_TERR2 RM_AA_ZB_SUB_TERR(2) + +#define G_RM_RA_ZB_OPA_SURF RM_RA_ZB_OPA_SURF(1) +#define G_RM_RA_ZB_OPA_SURF2 RM_RA_ZB_OPA_SURF(2) +#define G_RM_RA_ZB_OPA_DECAL RM_RA_ZB_OPA_DECAL(1) +#define G_RM_RA_ZB_OPA_DECAL2 RM_RA_ZB_OPA_DECAL(2) +#define G_RM_RA_ZB_OPA_INTER RM_RA_ZB_OPA_INTER(1) +#define G_RM_RA_ZB_OPA_INTER2 RM_RA_ZB_OPA_INTER(2) + +#define G_RM_AA_OPA_SURF RM_AA_OPA_SURF(1) +#define G_RM_AA_OPA_SURF2 RM_AA_OPA_SURF(2) +#define G_RM_AA_XLU_SURF RM_AA_XLU_SURF(1) +#define G_RM_AA_XLU_SURF2 RM_AA_XLU_SURF(2) +#define G_RM_AA_XLU_LINE RM_AA_XLU_LINE(1) +#define G_RM_AA_XLU_LINE2 RM_AA_XLU_LINE(2) +#define G_RM_AA_DEC_LINE RM_AA_DEC_LINE(1) +#define G_RM_AA_DEC_LINE2 RM_AA_DEC_LINE(2) +#define G_RM_AA_TEX_EDGE RM_AA_TEX_EDGE(1) +#define G_RM_AA_TEX_EDGE2 RM_AA_TEX_EDGE(2) +#define G_RM_AA_SUB_SURF RM_AA_SUB_SURF(1) +#define G_RM_AA_SUB_SURF2 RM_AA_SUB_SURF(2) +#define G_RM_AA_PCL_SURF RM_AA_PCL_SURF(1) +#define G_RM_AA_PCL_SURF2 RM_AA_PCL_SURF(2) +#define G_RM_AA_OPA_TERR RM_AA_OPA_TERR(1) +#define G_RM_AA_OPA_TERR2 RM_AA_OPA_TERR(2) +#define G_RM_AA_TEX_TERR RM_AA_TEX_TERR(1) +#define G_RM_AA_TEX_TERR2 RM_AA_TEX_TERR(2) +#define G_RM_AA_SUB_TERR RM_AA_SUB_TERR(1) +#define G_RM_AA_SUB_TERR2 RM_AA_SUB_TERR(2) + +#define G_RM_RA_OPA_SURF RM_RA_OPA_SURF(1) +#define G_RM_RA_OPA_SURF2 RM_RA_OPA_SURF(2) + +#define G_RM_ZB_OPA_SURF RM_ZB_OPA_SURF(1) +#define G_RM_ZB_OPA_SURF2 RM_ZB_OPA_SURF(2) +#define G_RM_ZB_XLU_SURF RM_ZB_XLU_SURF(1) +#define G_RM_ZB_XLU_SURF2 RM_ZB_XLU_SURF(2) +#define G_RM_ZB_OPA_DECAL RM_ZB_OPA_DECAL(1) +#define G_RM_ZB_OPA_DECAL2 RM_ZB_OPA_DECAL(2) +#define G_RM_ZB_XLU_DECAL RM_ZB_XLU_DECAL(1) +#define G_RM_ZB_XLU_DECAL2 RM_ZB_XLU_DECAL(2) +#define G_RM_ZB_CLD_SURF RM_ZB_CLD_SURF(1) +#define G_RM_ZB_CLD_SURF2 RM_ZB_CLD_SURF(2) +#define G_RM_ZB_OVL_SURF RM_ZB_OVL_SURF(1) +#define G_RM_ZB_OVL_SURF2 RM_ZB_OVL_SURF(2) +#define G_RM_ZB_PCL_SURF RM_ZB_PCL_SURF(1) +#define G_RM_ZB_PCL_SURF2 RM_ZB_PCL_SURF(2) + +#define G_RM_OPA_SURF RM_OPA_SURF(1) +#define G_RM_OPA_SURF2 RM_OPA_SURF(2) +#define G_RM_XLU_SURF RM_XLU_SURF(1) +#define G_RM_XLU_SURF2 RM_XLU_SURF(2) +#define G_RM_CLD_SURF RM_CLD_SURF(1) +#define G_RM_CLD_SURF2 RM_CLD_SURF(2) +#define G_RM_TEX_EDGE RM_TEX_EDGE(1) +#define G_RM_TEX_EDGE2 RM_TEX_EDGE(2) +#define G_RM_PCL_SURF RM_PCL_SURF(1) +#define G_RM_PCL_SURF2 RM_PCL_SURF(2) +#define G_RM_ADD RM_ADD(1) +#define G_RM_ADD2 RM_ADD(2) +#define G_RM_NOOP RM_NOOP(1) +#define G_RM_NOOP2 RM_NOOP(2) +#define G_RM_VISCVG RM_VISCVG(1) +#define G_RM_VISCVG2 RM_VISCVG(2) +#define G_RM_OPA_CI RM_OPA_CI(1) +#define G_RM_OPA_CI2 RM_OPA_CI(2) + +#define G_RM_FOG_SHADE_A GBL_c1(G_BL_CLR_FOG, G_BL_A_SHADE, G_BL_CLR_IN, G_BL_1MA) +#define G_RM_FOG_PRIM_A GBL_c1(G_BL_CLR_FOG, G_BL_A_FOG, G_BL_CLR_IN, G_BL_1MA) +#define G_RM_PASS GBL_c1(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + +/* + * G_SETCONVERT: K0-5 + */ +#define G_CV_K0 175 +#define G_CV_K1 -43 +#define G_CV_K2 -89 +#define G_CV_K3 222 +#define G_CV_K4 114 +#define G_CV_K5 42 + +/* + * G_SETSCISSOR: interlace mode + */ +#define G_SC_NON_INTERLACE 0 +#define G_SC_ODD_INTERLACE 3 +#define G_SC_EVEN_INTERLACE 2 + +/* flags to inhibit pushing of the display list (on branch) */ +#define G_DL_PUSH 0x00 +#define G_DL_NOPUSH 0x01 + +#if defined(_MSC_VER) || defined(__GNUC__) +#ifndef _LANGUAGE_C +#define _LANGUAGE_C +#endif +#endif + +/* + * BEGIN C-specific section: (typedef's) + */ +#if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) + +/* + * Data Structures + * + * NOTE: + * The DMA transfer hardware requires 64-bit aligned, 64-bit multiple- + * sized transfers. This important hardware optimization is unfortunately + * reflected in the programming interface, with some structures + * padded and alignment enforced. + * + * Since structures are aligned to the boundary of the "worst-case" + * element, we can't depend on the C compiler to align things + * properly. + * + * 64-bit structure alignment is enforced by wrapping structures with + * unions that contain a dummy "long long int". Why this works is + * explained in the ANSI C Spec, or on page 186 of the second edition + * of K&R, "The C Programming Language". + * + * The price we pay for this is a little awkwardness referencing the + * structures through the union. There is no memory penalty, since + * all the structures are at least 64-bits the dummy alignment field + * does not increase the size of the union. + * + * Static initialization of these union structures works because + * the ANSI C spec states that static initialization for unions + * works by using the first union element. We put the dummy alignment + * field last for this reason. + * + * (it's possible a newer 64-bit compiler from MIPS might make this + * easier with a flag, but we can't wait for it...) + * + */ + +/* + * Vertex (set up for use with colors) + */ +typedef struct { +#ifndef GBI_FLOATS + short ob[3]; /* x, y, z */ +#else + float ob[3]; /* x, y, z */ +#endif + unsigned short flag; + short tc[2]; /* texture coord */ + unsigned char cn[4]; /* color & alpha */ +} Vtx_t; + +/* + * Vertex (set up for use with normals) + */ +typedef struct { +#ifndef GBI_FLOATS + short ob[3]; /* x, y, z */ +#else + float ob[3]; /* x, y, z */ +#endif + unsigned short flag; + short tc[2]; /* texture coord */ + signed char n[3]; /* normal */ + unsigned char a; /* alpha */ +} Vtx_tn; + +typedef union Vtx { + Vtx_t v; /* Use this one for colors */ + Vtx_tn n; /* Use this one for normals */ + long long int force_structure_alignment; +} Vtx; + +/* + * Sprite structure + */ + +typedef struct { + void* SourceImagePointer; + void* TlutPointer; + short Stride; + short SubImageWidth; + short SubImageHeight; + char SourceImageType; + char SourceImageBitSize; + short SourceImageOffsetS; + short SourceImageOffsetT; + /* 20 bytes for above */ + + /* padding to bring structure size to 64 bit allignment */ + char dummy[4]; + +} uSprite_t; + +typedef union { + uSprite_t s; + + /* Need to make sure this is 64 bit aligned */ + long long int force_structure_allignment[3]; +} uSprite; + +/* + * Triangle face + */ +typedef struct { + unsigned char flag; + unsigned char v[3]; +} Tri; + +/* + * Viewport + */ + +/* + * + * This magic value is the maximum INTEGER z-range of the hardware + * (there are also 16-bits of fraction, which are introduced during + * any transformations). This is not just a good idea, it's the law. + * Feeding the hardware eventual z-coordinates (after any transforms + * or scaling) bigger than this, will not work. + * + * This number is DIFFERENT than G_MAXFBZ, which is the maximum value + * you want to use to initialize the z-buffer. + * + * The reason these are different is mildly interesting, but too long + * to explain here. It is basically the result of optimizations in the + * hardware. A more generic API might hide this detail from the users, + * but we don't have the ucode to do that... + * + */ +#define G_MAXZ 0x03ff /* 10 bits of integer screen-Z precision */ + +/* + * The viewport structure elements have 2 bits of fraction, necessary + * to accomodate the sub-pixel positioning scaling for the hardware. + * This can also be exploited to handle odd-sized viewports. + * + * Accounting for these fractional bits, using the default projection + * and viewing matrices, the viewport structure is initialized thusly: + * + * (SCREEN_WD/2)*4, (SCREEN_HT/2)*4, G_MAXZ, 0, + * (SCREEN_WD/2)*4, (SCREEN_HT/2)*4, 0, 0, + */ +typedef struct { + short vscale[4]; /* scale, 2 bits fraction */ + short vtrans[4]; /* translate, 2 bits fraction */ + /* both the above arrays are padded to 64-bit boundary */ +} Vp_t; + +typedef union { + Vp_t vp; + long long int force_structure_alignment; +} Vp; + +/* + * MOVEMEM indices + * + * Each of these indexes an entry in a dmem table + * which points to a 1-4 word block of dmem in + * which to store a 1-4 word DMA. + * + */ +#ifdef F3DEX_GBI_2 +/* 0,4 are reserved by G_MTX */ +#define G_MV_MMTX 2 +#define G_MV_PMTX 6 +#define G_MV_VIEWPORT 8 +#define G_MV_LIGHT 10 +#define G_MV_POINT 12 +#define G_MV_MATRIX 14 /* NOTE: this is in moveword table */ +#define G_MVO_LOOKATX (0 * 24) +#define G_MVO_LOOKATY (1 * 24) +#define G_MVO_L0 (2 * 24) +#define G_MVO_L1 (3 * 24) +#define G_MVO_L2 (4 * 24) +#define G_MVO_L3 (5 * 24) +#define G_MVO_L4 (6 * 24) +#define G_MVO_L5 (7 * 24) +#define G_MVO_L6 (8 * 24) +#define G_MVO_L7 (9 * 24) +#else /* F3DEX_GBI_2 */ +#define G_MV_VIEWPORT 0x80 +#define G_MV_LOOKATY 0x82 +#define G_MV_LOOKATX 0x84 +#define G_MV_L0 0x86 +#define G_MV_L1 0x88 +#define G_MV_L2 0x8a +#define G_MV_L3 0x8c +#define G_MV_L4 0x8e +#define G_MV_L5 0x90 +#define G_MV_L6 0x92 +#define G_MV_L7 0x94 +#define G_MV_TXTATT 0x96 +#define G_MV_MATRIX_1 0x9e /* NOTE: this is in moveword table */ +#define G_MV_MATRIX_2 0x98 +#define G_MV_MATRIX_3 0x9a +#define G_MV_MATRIX_4 0x9c +#endif /* F3DEX_GBI_2 */ + +/* + * MOVEWORD indices + * + * Each of these indexes an entry in a dmem table + * which points to a word in dmem in dmem where + * an immediate word will be stored. + * + */ +#define G_MW_MATRIX 0x00 /* NOTE: also used by movemem */ +#define G_MW_NUMLIGHT 0x02 +#define G_MW_CLIP 0x04 +#define G_MW_SEGMENT 0x06 +#define G_MW_SEGMENT_INTERP 0x07 +#define G_MW_FOG 0x08 +#define G_MW_LIGHTCOL 0x0a +#ifdef F3DEX_GBI_2 +#define G_MW_FORCEMTX 0x0c +#else /* F3DEX_GBI_2 */ +#define G_MW_POINTS 0x0c +#endif /* F3DEX_GBI_2 */ +#define G_MW_PERSPNORM 0x0e + +/* + * These are offsets from the address in the dmem table + */ +#define G_MWO_NUMLIGHT 0x00 +#define G_MWO_CLIP_RNX 0x04 +#define G_MWO_CLIP_RNY 0x0c +#define G_MWO_CLIP_RPX 0x14 +#define G_MWO_CLIP_RPY 0x1c +#define G_MWO_SEGMENT_0 0x00 +#define G_MWO_SEGMENT_1 0x01 +#define G_MWO_SEGMENT_2 0x02 +#define G_MWO_SEGMENT_3 0x03 +#define G_MWO_SEGMENT_4 0x04 +#define G_MWO_SEGMENT_5 0x05 +#define G_MWO_SEGMENT_6 0x06 +#define G_MWO_SEGMENT_7 0x07 +#define G_MWO_SEGMENT_8 0x08 +#define G_MWO_SEGMENT_9 0x09 +#define G_MWO_SEGMENT_A 0x0a +#define G_MWO_SEGMENT_B 0x0b +#define G_MWO_SEGMENT_C 0x0c +#define G_MWO_SEGMENT_D 0x0d +#define G_MWO_SEGMENT_E 0x0e +#define G_MWO_SEGMENT_F 0x0f +#define G_MWO_FOG 0x00 +#define G_MWO_aLIGHT_1 0x00 +#define G_MWO_bLIGHT_1 0x04 +#ifdef F3DEX_GBI_2 +#define G_MWO_aLIGHT_2 0x18 +#define G_MWO_bLIGHT_2 0x1c +#define G_MWO_aLIGHT_3 0x30 +#define G_MWO_bLIGHT_3 0x34 +#define G_MWO_aLIGHT_4 0x48 +#define G_MWO_bLIGHT_4 0x4c +#define G_MWO_aLIGHT_5 0x60 +#define G_MWO_bLIGHT_5 0x64 +#define G_MWO_aLIGHT_6 0x78 +#define G_MWO_bLIGHT_6 0x7c +#define G_MWO_aLIGHT_7 0x90 +#define G_MWO_bLIGHT_7 0x94 +#define G_MWO_aLIGHT_8 0xa8 +#define G_MWO_bLIGHT_8 0xac +#else +#define G_MWO_aLIGHT_2 0x20 +#define G_MWO_bLIGHT_2 0x24 +#define G_MWO_aLIGHT_3 0x40 +#define G_MWO_bLIGHT_3 0x44 +#define G_MWO_aLIGHT_4 0x60 +#define G_MWO_bLIGHT_4 0x64 +#define G_MWO_aLIGHT_5 0x80 +#define G_MWO_bLIGHT_5 0x84 +#define G_MWO_aLIGHT_6 0xa0 +#define G_MWO_bLIGHT_6 0xa4 +#define G_MWO_aLIGHT_7 0xc0 +#define G_MWO_bLIGHT_7 0xc4 +#define G_MWO_aLIGHT_8 0xe0 +#define G_MWO_bLIGHT_8 0xe4 +#endif +#define G_MWO_MATRIX_XX_XY_I 0x00 +#define G_MWO_MATRIX_XZ_XW_I 0x04 +#define G_MWO_MATRIX_YX_YY_I 0x08 +#define G_MWO_MATRIX_YZ_YW_I 0x0c +#define G_MWO_MATRIX_ZX_ZY_I 0x10 +#define G_MWO_MATRIX_ZZ_ZW_I 0x14 +#define G_MWO_MATRIX_WX_WY_I 0x18 +#define G_MWO_MATRIX_WZ_WW_I 0x1c +#define G_MWO_MATRIX_XX_XY_F 0x20 +#define G_MWO_MATRIX_XZ_XW_F 0x24 +#define G_MWO_MATRIX_YX_YY_F 0x28 +#define G_MWO_MATRIX_YZ_YW_F 0x2c +#define G_MWO_MATRIX_ZX_ZY_F 0x30 +#define G_MWO_MATRIX_ZZ_ZW_F 0x34 +#define G_MWO_MATRIX_WX_WY_F 0x38 +#define G_MWO_MATRIX_WZ_WW_F 0x3c +#define G_MWO_POINT_RGBA 0x10 +#define G_MWO_POINT_ST 0x14 +#define G_MWO_POINT_XYSCREEN 0x18 +#define G_MWO_POINT_ZSCREEN 0x1c + +/* + * Light structure. + * + * Note: only directional (infinite) lights are currently supported. + * + * Note: the weird order is for the DMEM alignment benefit of + * the microcode. + * + */ + +typedef struct { + unsigned char col[3]; /* diffuse light value (rgba) */ + char pad1; + unsigned char colc[3]; /* copy of diffuse light value (rgba) */ + char pad2; + signed char dir[3]; /* direction of light (normalized) */ + char pad3; +} Light_t; + +typedef struct { + unsigned char col[3]; + unsigned char unk3; + unsigned char colc[3]; + unsigned char unk7; + short pos[3]; + unsigned char unkE; +} PointLight_t; + +typedef struct { + unsigned char col[3]; /* ambient light value (rgba) */ + char pad1; + unsigned char colc[3]; /* copy of ambient light value (rgba) */ + char pad2; +} Ambient_t; + +typedef struct { + int x1, y1, x2, y2; /* texture offsets for highlight 1/2 */ +} Hilite_t; + +typedef union { + Light_t l; + PointLight_t p; + long long int force_structure_alignment[2]; +} Light; + +typedef union { + Ambient_t l; + long long int force_structure_alignment[1]; +} Ambient; + +typedef struct { + Ambient a; + Light l[7]; +} Lightsn; + +typedef struct { + Ambient a; + Light l[1]; +} Lights0; + +typedef struct { + Ambient a; + Light l[1]; +} Lights1; + +typedef struct { + Ambient a; + Light l[2]; +} Lights2; + +typedef struct { + Ambient a; + Light l[3]; +} Lights3; + +typedef struct { + Ambient a; + Light l[4]; +} Lights4; + +typedef struct { + Ambient a; + Light l[5]; +} Lights5; + +typedef struct { + Ambient a; + Light l[6]; +} Lights6; + +typedef struct { + Ambient a; + Light l[7]; +} Lights7; + +typedef struct { + Light l[2]; +} LookAt; + +typedef union { + Hilite_t h; + long int force_structure_alignment[4]; +} Hilite; + +#define gdSPDefLights0(ar, ag, ab) \ + { \ + { { { ar, ag, ab }, 0, { ar, ag, ab }, 0 } }, { \ + { \ + { { 0, 0, 0 }, 0, { 0, 0, 0 }, 0, { 0, 0, 0 }, 0 } \ + } \ + } \ + } +#define gdSPDefLights1(ar, ag, ab, r1, g1, b1, x1, y1, z1) \ + { \ + { { { ar, ag, ab }, 0, { ar, ag, ab }, 0 } }, { \ + { \ + { { r1, g1, b1 }, 0, { r1, g1, b1 }, 0, { x1, y1, z1 }, 0 } \ + } \ + } \ + } +#define gdSPDefLights2(ar, ag, ab, r1, g1, b1, x1, y1, z1, r2, g2, b2, x2, y2, z2) \ + { \ + { { { ar, ag, ab }, 0, { ar, ag, ab }, 0 } }, { \ + { { { r1, g1, b1 }, 0, { r1, g1, b1 }, 0, { x1, y1, z1 }, 0 } }, { \ + { { r2, g2, b2 }, 0, { r2, g2, b2 }, 0, { x2, y2, z2 }, 0 } \ + } \ + } \ + } +#define gdSPDefLights3(ar, ag, ab, r1, g1, b1, x1, y1, z1, r2, g2, b2, x2, y2, z2, r3, g3, b3, x3, y3, z3) \ + { \ + { { { ar, ag, ab }, 0, { ar, ag, ab }, 0 } }, { \ + { { { r1, g1, b1 }, 0, { r1, g1, b1 }, 0, { x1, y1, z1 }, 0 } }, \ + { { { r2, g2, b2 }, 0, { r2, g2, b2 }, 0, { x2, y2, z2 }, 0 } }, { \ + { { r3, g3, b3 }, 0, { r3, g3, b3 }, 0, { x3, y3, z3 }, 0 } \ + } \ + } \ + } +#define gdSPDefLights4(ar, ag, ab, r1, g1, b1, x1, y1, z1, r2, g2, b2, x2, y2, z2, r3, g3, b3, x3, y3, z3, r4, g4, b4, \ + x4, y4, z4) \ + { \ + { { { ar, ag, ab }, 0, { ar, ag, ab }, 0 } }, { \ + { { { r1, g1, b1 }, 0, { r1, g1, b1 }, 0, { x1, y1, z1 }, 0 } }, \ + { { { r2, g2, b2 }, 0, { r2, g2, b2 }, 0, { x2, y2, z2 }, 0 } }, \ + { { { r3, g3, b3 }, 0, { r3, g3, b3 }, 0, { x3, y3, z3 }, 0 } }, { \ + { { r4, g4, b4 }, 0, { r4, g4, b4 }, 0, { x4, y4, z4 }, 0 } \ + } \ + } \ + } +#define gdSPDefLights5(ar, ag, ab, r1, g1, b1, x1, y1, z1, r2, g2, b2, x2, y2, z2, r3, g3, b3, x3, y3, z3, r4, g4, b4, \ + x4, y4, z4, r5, g5, b5, x5, y5, z5) \ + { \ + { { { ar, ag, ab }, 0, { ar, ag, ab }, 0 } }, { \ + { { { r1, g1, b1 }, 0, { r1, g1, b1 }, 0, { x1, y1, z1 }, 0 } }, \ + { { { r2, g2, b2 }, 0, { r2, g2, b2 }, 0, { x2, y2, z2 }, 0 } }, \ + { { { r3, g3, b3 }, 0, { r3, g3, b3 }, 0, { x3, y3, z3 }, 0 } }, \ + { { { r4, g4, b4 }, 0, { r4, g4, b4 }, 0, { x4, y4, z4 }, 0 } }, { \ + { { r5, g5, b5 }, 0, { r5, g5, b5 }, 0, { x5, y5, z5 }, 0 } \ + } \ + } \ + } + +#define gdSPDefLights6(ar, ag, ab, r1, g1, b1, x1, y1, z1, r2, g2, b2, x2, y2, z2, r3, g3, b3, x3, y3, z3, r4, g4, b4, \ + x4, y4, z4, r5, g5, b5, x5, y5, z5, r6, g6, b6, x6, y6, z6) \ + { \ + { { { ar, ag, ab }, 0, { ar, ag, ab }, 0 } }, { \ + { { { r1, g1, b1 }, 0, { r1, g1, b1 }, 0, { x1, y1, z1 }, 0 } }, \ + { { { r2, g2, b2 }, 0, { r2, g2, b2 }, 0, { x2, y2, z2 }, 0 } }, \ + { { { r3, g3, b3 }, 0, { r3, g3, b3 }, 0, { x3, y3, z3 }, 0 } }, \ + { { { r4, g4, b4 }, 0, { r4, g4, b4 }, 0, { x4, y4, z4 }, 0 } }, \ + { { { r5, g5, b5 }, 0, { r5, g5, b5 }, 0, { x5, y5, z5 }, 0 } }, { \ + { { r6, g6, b6 }, 0, { r6, g6, b6 }, 0, { x6, y6, z6 }, 0 } \ + } \ + } \ + } + +#define gdSPDefLights7(ar, ag, ab, r1, g1, b1, x1, y1, z1, r2, g2, b2, x2, y2, z2, r3, g3, b3, x3, y3, z3, r4, g4, b4, \ + x4, y4, z4, r5, g5, b5, x5, y5, z5, r6, g6, b6, x6, y6, z6, r7, g7, b7, x7, y7, z7) \ + { \ + { { { ar, ag, ab }, 0, { ar, ag, ab }, 0 } }, { \ + { { { r1, g1, b1 }, 0, { r1, g1, b1 }, 0, { x1, y1, z1 }, 0 } }, \ + { { { r2, g2, b2 }, 0, { r2, g2, b2 }, 0, { x2, y2, z2 }, 0 } }, \ + { { { r3, g3, b3 }, 0, { r3, g3, b3 }, 0, { x3, y3, z3 }, 0 } }, \ + { { { r4, g4, b4 }, 0, { r4, g4, b4 }, 0, { x4, y4, z4 }, 0 } }, \ + { { { r5, g5, b5 }, 0, { r5, g5, b5 }, 0, { x5, y5, z5 }, 0 } }, \ + { { { r6, g6, b6 }, 0, { r6, g6, b6 }, 0, { x6, y6, z6 }, 0 } }, { \ + { { r7, g7, b7 }, 0, { r7, g7, b7 }, 0, { x7, y7, z7 }, 0 } \ + } \ + } \ + } + +#define gdSPDefLookAt(rightx, righty, rightz, upx, upy, upz) \ + { \ + { \ + { { { 0, 0, 0 }, 0, { 0, 0, 0 }, 0, { rightx, righty, rightz }, 0 } }, { \ + { { 0, 0x80, 0 }, 0, { 0, 0x80, 0 }, 0, { upx, upy, upz }, 0 } \ + } \ + } \ + } + +/* + * Graphics DMA Packet + */ +typedef struct { + int cmd : 8; + unsigned int par : 8; + unsigned int len : 16; + unsigned int addr; +} Gdma; + +/* + * Graphics Immediate Mode Packet types + */ +typedef struct { + int cmd : 8; + int pad : 24; + Tri tri; +} Gtri; + +typedef struct { + int cmd : 8; + int pad1 : 24; + int pad2 : 24; + unsigned char param : 8; +} Gpopmtx; + +/* + * typedef struct { + * int cmd:8; + * int pad0:24; + * int pad1:4; + * int number:4; + * int base:24; + * } Gsegment; + */ +typedef struct { + int cmd : 8; + int pad0 : 8; + int mw_index : 8; + int number : 8; + int pad1 : 8; + int base : 24; +} Gsegment; + +typedef struct { + int cmd : 8; + int pad0 : 8; + int sft : 8; + int len : 8; + unsigned int data : 32; +} GsetothermodeL; + +typedef struct { + int cmd : 8; + int pad0 : 8; + int sft : 8; + int len : 8; + unsigned int data : 32; +} GsetothermodeH; + +typedef struct { + unsigned char cmd; + unsigned char lodscale; + unsigned char tile; + unsigned char on; + unsigned short s; + unsigned short t; +} Gtexture; + +typedef struct { + int cmd : 8; + int pad : 24; + Tri line; +} Gline3D; + +typedef struct { + int cmd : 8; + int pad1 : 24; + short int pad2; + short int scale; +} Gperspnorm; + +/* + * RDP Packet types + */ +typedef struct { + int cmd : 8; + unsigned int fmt : 3; + unsigned int siz : 2; + unsigned int pad : 7; + unsigned int wd : 12; /* really only 10 bits, extra */ + unsigned int dram; /* to account for 1024 */ +} Gsetimg; + +typedef struct { + int cmd : 8; + unsigned int muxs0 : 24; + unsigned int muxs1 : 32; +} Gsetcombine; + +typedef struct { + int cmd : 8; + unsigned char pad; + unsigned char prim_min_level; + unsigned char prim_level; + unsigned long color; +} Gsetcolor; + +typedef struct { + int cmd : 8; + int x0 : 10; + int x0frac : 2; + int y0 : 10; + int y0frac : 2; + unsigned int pad : 8; + int x1 : 10; + int x1frac : 2; + int y1 : 10; + int y1frac : 2; +} Gfillrect; + +typedef struct { + int cmd : 8; + unsigned int fmt : 3; + unsigned int siz : 2; + unsigned int pad0 : 1; + unsigned int line : 9; + unsigned int tmem : 9; + unsigned int pad1 : 5; + unsigned int tile : 3; + unsigned int palette : 4; + unsigned int ct : 1; + unsigned int mt : 1; + unsigned int maskt : 4; + unsigned int shiftt : 4; + unsigned int cs : 1; + unsigned int ms : 1; + unsigned int masks : 4; + unsigned int shifts : 4; +} Gsettile; + +typedef struct { + int cmd : 8; + unsigned int sl : 12; + unsigned int tl : 12; + int pad : 5; + unsigned int tile : 3; + unsigned int sh : 12; + unsigned int th : 12; +} Gloadtile; + +typedef Gloadtile Gloadblock; + +typedef Gloadtile Gsettilesize; + +typedef Gloadtile Gloadtlut; + +typedef struct { + unsigned int cmd : 8; /* command */ + unsigned int xl : 12; /* X coordinate of upper left */ + unsigned int yl : 12; /* Y coordinate of upper left */ + unsigned int pad1 : 5; /* Padding */ + unsigned int tile : 3; /* Tile descriptor index */ + unsigned int xh : 12; /* X coordinate of lower right */ + unsigned int yh : 12; /* Y coordinate of lower right */ + unsigned int s : 16; /* S texture coord at top left */ + unsigned int t : 16; /* T texture coord at top left */ + unsigned int dsdx : 16; /* Change in S per change in X */ + unsigned int dtdy : 16; /* Change in T per change in Y */ +} Gtexrect; + +#define MakeTexRect(xh, yh, flip, tile, xl, yl, s, t, dsdx, dtdy) \ + G_TEXRECT, xh, yh, 0, flip, 0, tile, xl, yl, s, t, dsdx, dtdy + +/* + * Textured rectangles are 128 bits not 64 bits + */ +typedef struct { + unsigned long w0; + unsigned long w1; + unsigned long w2; + unsigned long w3; +} TexRect; + +#ifdef USE_GBI_TRACE +/* + * Trace structure + */ +typedef struct { + const char* file; + int idx; + bool valid; +} Trace; + +#define MakeTrace() \ + , { \ + __FILE__, __LINE__, true \ + } +#else +#define MakeTrace() +#endif +/* + * Generic Gfx Packet + */ +typedef struct { + uintptr_t w0; + uintptr_t w1; +#ifdef USE_GBI_TRACE + Trace trace; +#endif +} Gwords; + +#ifdef __cplusplus +#ifdef USE_GBI_TRACE +static_assert((sizeof(Gwords) == 2 * sizeof(void*) + sizeof(Trace)), "Display list size is bad"); +#else +static_assert((sizeof(Gwords) == 2 * sizeof(void*)), "Display list size is bad"); +#endif +#endif + +/* + * This union is the fundamental type of the display list. + * It is, by law, exactly 64 bits in size. + */ +typedef union Gfx { + Gwords words; +#if !defined(F3D_OLD) && IS_BIG_ENDIAN && !IS_64_BIT + Gdma dma; + Gtri tri; + Gline3D line; + Gpopmtx popmtx; + Gsegment segment; + GsetothermodeH setothermodeH; + GsetothermodeL setothermodeL; + Gtexture texture; + Gperspnorm perspnorm; + Gsetimg setimg; + Gsetcombine setcombine; + Gsetcolor setcolor; + Gfillrect fillrect; /* use for setscissor also */ + Gsettile settile; + Gloadtile loadtile; /* use for loadblock also, th is dxt */ + Gsettilesize settilesize; + Gloadtlut loadtlut; +#endif + long long int force_structure_alignment; +} Gfx; + +/* + * Macros to assemble the graphics display list + */ + +/* + * OTR macros + */ + +#define gsSP1TriangleOTR(v0, v1, v2, flag) \ + { _SHIFTL(G_TRI1_OTR, 24, 8) | __gsSP1Triangle_w1f(v0, v1, v2, flag), 0 } + +/* + * DMA macros + */ +#define gDma0p(pkt, c, s, l) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24); \ + _g->words.w1 = (uintptr_t)(s); \ + }) + +#define gsDma0p(c, s, l) \ + { _SHIFTL((c), 24, 8) | _SHIFTL((l), 0, 24), (uintptr_t)(s) } + +#ifdef USE_GBI_TRACE +#define gDma1p(pkt, c, s, l, p) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | _SHIFTL((l), 0, 16)); \ + _g->words.w1 = (uintptr_t)(s); \ + _g->words.trace.file = __FILE__; \ + _g->words.trace.idx = __LINE__; \ + _g->words.trace.valid = true; \ + }) +#else +#define gDma1p(pkt, c, s, l, p) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | _SHIFTL((l), 0, 16)); \ + _g->words.w1 = (uintptr_t)(s); \ + }) +#endif +#define gsDma1p(c, s, l, p) \ + { (_SHIFTL((c), 24, 8) | _SHIFTL((p), 16, 8) | _SHIFTL((l), 0, 16)), (uintptr_t)(s)MakeTrace() } + +#ifdef USE_GBI_TRACE +#define gDma2p(pkt, c, adrs, len, idx, ofs) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + _g->words.w0 = \ + (_SHIFTL((c), 24, 8) | _SHIFTL(((len)-1) / 8, 19, 5) | _SHIFTL((ofs) / 8, 8, 8) | _SHIFTL((idx), 0, 8)); \ + _g->words.w1 = (uintptr_t)(adrs); \ + _g->words.trace.file = __FILE__; \ + _g->words.trace.idx = __LINE__; \ + _g->words.trace.valid = true; \ + }) +#else +#define gDma2p(pkt, c, adrs, len, idx, ofs) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + _g->words.w0 = \ + (_SHIFTL((c), 24, 8) | _SHIFTL(((len)-1) / 8, 19, 5) | _SHIFTL((ofs) / 8, 8, 8) | _SHIFTL((idx), 0, 8)); \ + _g->words.w1 = (uintptr_t)(adrs); \ + }) +#endif + +#define gsDma2p(c, adrs, len, idx, ofs) \ + { \ + (_SHIFTL((c), 24, 8) | _SHIFTL(((len)-1) / 8, 19, 5) | _SHIFTL((ofs) / 8, 8, 8) | _SHIFTL((idx), 0, 8)), \ + (uintptr_t)(adrs)MakeTrace() \ + } + +#define gSPNoOp(pkt) gDma0p(pkt, G_SPNOOP, 0, 0) +#define gsSPNoOp() gsDma0p(G_SPNOOP, 0, 0) + +#ifdef F3DEX_GBI_2 +#define gSPMatrix(pkt, m, p) gDma2p((pkt), G_MTX, (m), sizeof(Mtx), (p) ^ G_MTX_PUSH, 0) +#define gsSPMatrix(m, p) gsDma2p(G_MTX, (m), sizeof(Mtx), (p) ^ G_MTX_PUSH, 0) +#else /* F3DEX_GBI_2 */ +#define gSPMatrix(pkt, m, p) gDma1p(pkt, G_MTX, m, sizeof(Mtx), p) +#define gsSPMatrix(m, p) gsDma1p(G_MTX, m, sizeof(Mtx), p) +#endif /* F3DEX_GBI_2 */ + +#if defined(F3DEX_GBI_2) +/* + * F3DEX_GBI_2: G_VTX GBI format was changed. + * + * +--------+----+---+---+----+------+-+ + * G_VTX | cmd:8 |0000| n:8 |0000|v0+n:7|0| + * +-+---+--+----+---+---+----+------+-+ + * | |seg| address | + * +-+---+-----------------------------+ + */ +#ifdef USE_GBI_TRACE +#define __gSPVertex(pkt, v, n, v0) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + _g->words.w0 = _SHIFTL(G_VTX, 24, 8) | _SHIFTL((n), 12, 8) | _SHIFTL((v0) + (n), 1, 7); \ + _g->words.w1 = (uintptr_t)(v); \ + _g->words.trace.file = __FILE__; \ + _g->words.trace.idx = __LINE__; \ + _g->words.trace.valid = true; \ + }) +#else +#define __gSPVertex(pkt, v, n, v0) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + _g->words.w0 = _SHIFTL(G_VTX, 24, 8) | _SHIFTL((n), 12, 8) | _SHIFTL((v0) + (n), 1, 7); \ + _g->words.w1 = (uintptr_t)(v); \ + }) +#endif +#define gsSPVertex(v, n, v0) \ + { (_SHIFTL(G_VTX, 24, 8) | _SHIFTL((n), 12, 8) | _SHIFTL((v0) + (n), 1, 7)), (uintptr_t)(v)MakeTrace() } + +#elif (defined(F3DEX_GBI) || defined(F3DLP_GBI)) + /* + * F3DEX_GBI: G_VTX GBI format was changed to support 64 vertice. + * + * +--------+--------+------+----------+ + * G_VTX | cmd:8 | v0:8 | n:6 |length:10 | + * +-+---+--+--------+------+----------+ + * | |seg| address | + * +-+---+-----------------------------+ + */ +#define __gSPVertex(pkt, v, n, v0) gDma1p((pkt), G_VTX, (v), ((n) << 10) | (sizeof(Vtx) * (n)-1), (v0)*2) +#define gsSPVertex(v, n, v0) gsDma1p(G_VTX, (v), ((n) << 10) | (sizeof(Vtx) * (n)-1), (v0)*2) +#else +#define __gSPVertex(pkt, v, n, v0) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + _g->words.w0 = _SHIFTL(G_VTX_WIDE, 24, 8) | _SHIFTL((n), 12, 8) | _SHIFTL((v0) + (n), 1, 7); \ + _g->words.w1 = (uintptr_t)(v); \ + }) +#define gsSPVertex(v, n, v0) \ + { (_SHIFTL(G_VTX_WIDE, 24, 8) | _SHIFTL((n), 12, 8) | _SHIFTL((v0) + (n), 1, 7)), (uintptr_t)(v)MakeTrace() } +#endif + +#ifdef F3DEX_GBI_2 +#define gSPViewport(pkt, v) gDma2p((pkt), G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT, 0) +#define gsSPViewport(v) gsDma2p(G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT, 0) +#else /* F3DEX_GBI_2 */ +#define gSPViewport(pkt, v) gDma1p((pkt), G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT) +#define gsSPViewport(v) gsDma1p(G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT) +#endif /* F3DEX_GBI_2 */ + +#define gsSPPushCD(pkt, dl) gDma1p(pkt, G_PUSHCD, dl, 0, G_DL_PUSH) +#define __gSPDisplayList(pkt, dl) gDma1p(pkt, G_DL, dl, 0, G_DL_PUSH) +#define gsSPDisplayList(dl) gsDma1p(G_DL, dl, 0, G_DL_PUSH) +#define gsSPDisplayListOTRHash(dl) gsDma1p(G_DL_OTR_HASH, dl, 0, G_DL_PUSH) +#define gsSPDisplayListOTRFilePath(dl) gsDma1p(G_DL_OTR_FILEPATH, dl, 0, G_DL_PUSH) +#define gsSPDisplayListIndex(dl) gsDma1p(G_DL_INDEX, dl, 0, G_DL_PUSH) + +#define gSPBranchList(pkt, dl) gDma1p(pkt, G_DL, dl, 0, G_DL_NOPUSH) +#define gsSPBranchList(dl) gsDma1p(G_DL, dl, 0, G_DL_NOPUSH) +#define gsSPBranchListOTRHash(dl) gsDma1p(G_DL_OTR_HASH, dl, 0, G_DL_NOPUSH) +#define gsSPBranchListOTRFilePath(dl) gsDma1p(G_DL_OTR_FILEPATH, dl, 0, G_DL_NOPUSH) +#define gsSPBranchListIndex(dl) gsDma1p(G_DL_INDEX, dl, 0, G_DL_NOPUSH) + +#define gSPSprite2DBase(pkt, s) gDma1p(pkt, G_SPRITE2D_BASE, s, sizeof(uSprite), 0) +#define gsSPSprite2DBase(s) gsDma1p(G_SPRITE2D_BASE, s, sizeof(uSprite), 0) + +/* + * RSP short command (no DMA required) macros + */ +#define gImmp0(pkt, c) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL((c), 24, 8); \ + }) + +#define gsImmp0(c) \ + { _SHIFTL((c), 24, 8) } + +#define gImmp1(pkt, c, p0) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL((c), 24, 8); \ + _g->words.w1 = (uintptr_t)(p0); \ + }) + +#define gsImmp1(c, p0) \ + { _SHIFTL((c), 24, 8), (uintptr_t)(p0) } + +#define gImmp2(pkt, c, p0, p1) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL((c), 24, 8); \ + _g->words.w1 = _SHIFTL((p0), 16, 16) | _SHIFTL((p1), 8, 8); \ + }) + +#define gsImmp2(c, p0, p1) \ + { _SHIFTL((c), 24, 8), _SHIFTL((p0), 16, 16) | _SHIFTL((p1), 8, 8) } + +#define gImmp3(pkt, c, p0, p1, p2) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL((c), 24, 8); \ + _g->words.w1 = (_SHIFTL((p0), 16, 16) | _SHIFTL((p1), 8, 8) | _SHIFTL((p2), 0, 8)); \ + }) + +#define gsImmp3(c, p0, p1, p2) \ + { _SHIFTL((c), 24, 8), (_SHIFTL((p0), 16, 16) | _SHIFTL((p1), 8, 8) | _SHIFTL((p2), 0, 8)) } + +#define gImmp21(pkt, c, p0, p1, dat) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | _SHIFTL((p1), 0, 8)); \ + _g->words.w1 = (uintptr_t)(dat); \ + }) + +#define gsImmp21(c, p0, p1, dat) \ + { _SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | _SHIFTL((p1), 0, 8), (uintptr_t)(dat) } + +#ifdef F3DEX_GBI_2 +#define gMoveWd(pkt, index, offset, data) gDma1p((pkt), G_MOVEWORD, data, offset, index) +#define gsMoveWd(index, offset, data) gsDma1p(G_MOVEWORD, data, offset, index) +#else /* F3DEX_GBI_2 */ +#define gMoveWd(pkt, index, offset, data) gImmp21((pkt), G_MOVEWORD, offset, index, data) +#define gsMoveWd(index, offset, data) gsImmp21(G_MOVEWORD, offset, index, data) +#endif /* F3DEX_GBI_2 */ + +/* Sprite immediate macros, there is also a sprite dma macro above */ + +#define gSPSprite2DScaleFlip(pkt, sx, sy, fx, fy) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_SPRITE2D_SCALEFLIP, 24, 8) | _SHIFTL((fx), 8, 8) | _SHIFTL((fy), 0, 8)); \ + _g->words.w1 = (_SHIFTL((sx), 16, 16) | _SHIFTL((sy), 0, 16)); \ + }) + +#define gsSPSprite2DScaleFlip(sx, sy, fx, fy) \ + { \ + (_SHIFTL(G_SPRITE2D_SCALEFLIP, 24, 8) | _SHIFTL((fx), 8, 8) | _SHIFTL((fy), 0, 8)), \ + (_SHIFTL((sx), 16, 16) | _SHIFTL((sy), 0, 16)) \ + } + +#define gSPSprite2DDraw(pkt, px, py) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_SPRITE2D_DRAW, 24, 8)); \ + _g->words.w1 = (_SHIFTL((px), 16, 16) | _SHIFTL((py), 0, 16)); \ + }) + +#define gsSPSprite2DDraw(px, py) \ + { (_SHIFTL(G_SPRITE2D_DRAW, 24, 8)), (_SHIFTL((px), 16, 16) | _SHIFTL((py), 0, 16)) } + +/* + * Note: the SP1Triangle() and line macros multiply the vertex indices + * by 10, this is an optimization for the microcode. + */ +#if (defined(F3DLP_GBI) || defined(F3DEX_GBI)) +#define __gsSP1Triangle_w1(v0, v1, v2) (_SHIFTL((v0)*2, 16, 8) | _SHIFTL((v1)*2, 8, 8) | _SHIFTL((v2)*2, 0, 8)) +#define __gsSP1Triangle_w1f(v0, v1, v2, flag) \ + (((flag) == 0) ? __gsSP1Triangle_w1(v0, v1, v2) \ + : ((flag) == 1) ? __gsSP1Triangle_w1(v1, v2, v0) \ + : __gsSP1Triangle_w1(v2, v0, v1)) +#define __gsSPLine3D_w1(v0, v1, wd) (_SHIFTL((v0)*2, 16, 8) | _SHIFT((v1)*2, 8, 8) | _SHIFT((wd), 0, 8)) +#define __gsSPLine3D_w1f(v0, v1, wd, flag) (((flag) == 0) ? __gsSPLine3D_w1(v0, v1, wd) : __gsSPLine3D_w1(v1, v0, wd)) +#define __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag) \ + (((flag) == 0) ? __gsSP1Triangle_w1(v0, v1, v2) \ + : ((flag) == 1) ? __gsSP1Triangle_w1(v1, v2, v3) \ + : ((flag) == 2) ? __gsSP1Triangle_w1(v2, v3, v0) \ + : __gsSP1Triangle_w1(v3, v0, v1)) +#define __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag) \ + (((flag) == 0) ? __gsSP1Triangle_w1(v0, v2, v3) \ + : ((flag) == 1) ? __gsSP1Triangle_w1(v1, v3, v0) \ + : ((flag) == 2) ? __gsSP1Triangle_w1(v2, v0, v1) \ + : __gsSP1Triangle_w1(v3, v1, v2)) +#else +#define __gsSP1Triangle_w1f(v0, v1, v2, flag) \ + (_SHIFTL((flag), 24, 8) | _SHIFTL((v0)*10, 16, 8) | _SHIFTL((v1)*10, 8, 8) | _SHIFTL((v2)*10, 0, 8)) +#define __gsSPLine3D_w1f(v0, v1, wd, flag) \ + (_SHIFTL((flag), 24, 8) | _SHIFTL((v0)*10, 16, 8) | _SHIFTL((v1)*10, 8, 8) | _SHIFTL((wd), 0, 8)) +#define __gsSP1Triangle_w1_wide(v0, v1, v2) (_SHIFTL((v0)*2, 16, 8) | _SHIFTL((v1)*2, 8, 8) | _SHIFTL((v2)*2, 0, 8)) +#define __gsSP1Triangle_w1f_wide(v0, v1, v2, flag) \ + (((flag) == 0) ? __gsSP1Triangle_w1_wide(v0, v1, v2) \ + : ((flag) == 1) ? __gsSP1Triangle_w1_wide(v1, v2, v0) \ + : __gsSP1Triangle_w1_wide(v2, v0, v1)) +#endif + +#ifdef F3DEX_GBI_2 +/*** + *** 1 Triangle + ***/ +#define gSP1Triangle(pkt, v0, v1, v2, flag) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_TRI1, 24, 8) | __gsSP1Triangle_w1f(v0, v1, v2, flag); \ + _g->words.w1 = 0; \ + }) +#define gsSP1Triangle(v0, v1, v2, flag) \ + { _SHIFTL(G_TRI1, 24, 8) | __gsSP1Triangle_w1f(v0, v1, v2, flag), 0 } + +/*** + *** Line + ***/ +#define gSPLine3D(pkt, v0, v1, flag) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_LINE3D, 24, 8) | __gsSPLine3D_w1f(v0, v1, 0, flag); \ + _g->words.w1 = 0; \ + }) +#define gsSPLine3D(v0, v1, flag) \ + { _SHIFTL(G_LINE3D, 24, 8) | __gsSPLine3D_w1f(v0, v1, 0, flag), 0 } + +/*** + *** LineW + ***/ +/* these macros are the same as SPLine3D, except they have an + * additional parameter for width. The width is added to the "minimum" + * thickness, which is 1.5 pixels. The units for width are in + * half-pixel units, so a width of 1 translates to (.5 + 1.5) or + * a 2.0 pixels wide line. + */ +#define gSPLineW3D(pkt, v0, v1, wd, flag) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_LINE3D, 24, 8) | __gsSPLine3D_w1f(v0, v1, wd, flag); \ + _g->words.w1 = 0; \ + }) +#define gsSPLineW3D(v0, v1, wd, flag) \ + { _SHIFTL(G_LINE3D, 24, 8) | __gsSPLine3D_w1f(v0, v1, wd, flag), 0 } + +/*** + *** 1 Quadrangle + ***/ +#define gSP1Quadrangle(pkt, v0, v1, v2, v3, flag) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_QUAD, 24, 8) | __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag)); \ + _g->words.w1 = __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag); \ + }) + +#define gsSP1Quadrangle(v0, v1, v2, v3, flag) \ + { \ + (_SHIFTL(G_QUAD, 24, 8) | __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag)), \ + __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag) \ + } +#else /* F3DEX_GBI_2 */ + +/*** + *** 1 Triangle + ***/ +#ifdef F3DEX_GBI +#define gSP1Triangle(pkt, v0, v1, v2, flag) \ + { \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_TRI1, 24, 8); \ + _g->words.w1 = __gsSP1Triangle_w1f(v0, v1, v2, flag); \ + } +#define gsSP1Triangle(v0, v1, v2, flag) \ + { _SHIFTL(G_TRI1, 24, 8), __gsSP1Triangle_w1f(v0, v1, v2, flag) } +#else +#define gSP1Triangle(pkt, v0, v1, v2, flag) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_TRI1_WIDE, 24, 8) | __gsSP1Triangle_w1f_wide(v0, v1, v2, flag); \ + _g->words.w1 = 0; \ + }) +#define gsSP1Triangle(v0, v1, v2, flag) \ + { _SHIFTL(G_TRI1_WIDE, 24, 8) | __gsSP1Triangle_w1f_wide(v0, v1, v2, flag), 0 } +#endif + +/*** + *** Line + ***/ +#define gSPLine3D(pkt, v0, v1, flag) \ + { \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_LINE3D, 24, 8); \ + _g->words.w1 = __gsSPLine3D_w1f(v0, v1, 0, flag); \ + } +#define gsSPLine3D(v0, v1, flag) \ + { _SHIFTL(G_LINE3D, 24, 8), __gsSPLine3D_w1f(v0, v1, 0, flag) } + +/*** + *** LineW + ***/ +/* these macros are the same as SPLine3D, except they have an + * additional parameter for width. The width is added to the "minimum" + * thickness, which is 1.5 pixels. The units for width are in + * half-pixel units, so a width of 1 translates to (.5 + 1.5) or + * a 2.0 pixels wide line. + */ +#define gSPLineW3D(pkt, v0, v1, wd, flag) \ + { \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_LINE3D, 24, 8); \ + _g->words.w1 = __gsSPLine3D_w1f(v0, v1, wd, flag); \ + } +#define gsSPLineW3D(v0, v1, wd, flag) \ + { _SHIFTL(G_LINE3D, 24, 8), __gsSPLine3D_w1f(v0, v1, wd, flag) } + +/*** + *** 1 Quadrangle + ***/ +#define gSP1Quadrangle(pkt, v0, v1, v2, v3, flag) \ + { \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_TRI2, 24, 8) | __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag)); \ + _g->words.w1 = __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag); \ + } + +#define gsSP1Quadrangle(v0, v1, v2, v3, flag) \ + { \ + (_SHIFTL(G_TRI2, 24, 8) | __gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag)), \ + __gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag) \ + } +#endif /* F3DEX_GBI_2 */ + +#if (defined(F3DLP_GBI) || defined(F3DEX_GBI)) +/*** + *** 2 Triangles + ***/ +#define gSP2Triangles(pkt, v00, v01, v02, flag0, v10, v11, v12, flag1) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_TRI2, 24, 8) | __gsSP1Triangle_w1f(v00, v01, v02, flag0)); \ + _g->words.w1 = __gsSP1Triangle_w1f(v10, v11, v12, flag1); \ + }) + +#define gsSP2Triangles(v00, v01, v02, flag0, v10, v11, v12, flag1) \ + { (_SHIFTL(G_TRI2, 24, 8) | __gsSP1Triangle_w1f(v00, v01, v02, flag0)), __gsSP1Triangle_w1f(v10, v11, v12, flag1) } + +#endif /* F3DEX_GBI/F3DLP_GBI */ + +#if (defined(F3DEX_GBI) || defined(F3DLP_GBI)) +#define gSPCullDisplayList(pkt, vstart, vend) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_CULLDL, 24, 8) | _SHIFTL((vstart)*2, 0, 16); \ + _g->words.w1 = _SHIFTL((vend)*2, 0, 16); \ + }) + +#define gsSPCullDisplayList(vstart, vend) \ + { _SHIFTL(G_CULLDL, 24, 8) | _SHIFTL((vstart)*2, 0, 16), _SHIFTL((vend)*2, 0, 16) } + +#else +#define gSPCullDisplayList(pkt, vstart, vend) \ + { \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_CULLDL, 24, 8) | ((0x0f & (vstart)) * 40); \ + _g->words.w1 = (unsigned int)((0x0f & ((vend) + 1)) * 40); \ + } + +#define gsSPCullDisplayList(vstart, vend) \ + { _SHIFTL(G_CULLDL, 24, 8) | ((0x0f & (vstart)) * 40), ((0x0f & ((vend) + 1)) * 40) } +#endif + +#define __gSPSegmentInterp(pkt, segment, base) gMoveWd(pkt, G_MW_SEGMENT_INTERP, segment, base) +#define __gSPSegment(pkt, segment, base) gMoveWd(pkt, G_MW_SEGMENT, (segment)*4, base) +#define gsSPSegment(segment, base) gsMoveWd(G_MW_SEGMENT, (segment)*4, base) + +/* + * Clipping Macros + */ +#define FR_NEG_FRUSTRATIO_1 0x00000001 +#define FR_POS_FRUSTRATIO_1 0x0000ffff +#define FR_NEG_FRUSTRATIO_2 0x00000002 +#define FR_POS_FRUSTRATIO_2 0x0000fffe +#define FR_NEG_FRUSTRATIO_3 0x00000003 +#define FR_POS_FRUSTRATIO_3 0x0000fffd +#define FR_NEG_FRUSTRATIO_4 0x00000004 +#define FR_POS_FRUSTRATIO_4 0x0000fffc +#define FR_NEG_FRUSTRATIO_5 0x00000005 +#define FR_POS_FRUSTRATIO_5 0x0000fffb +#define FR_NEG_FRUSTRATIO_6 0x00000006 +#define FR_POS_FRUSTRATIO_6 0x0000fffa +/* + * r should be one of: FRUSTRATIO_1, FRUSTRATIO_2, FRUSTRATIO_3, ... FRUSTRATIO_6 + */ +#define gSPClipRatio(pkt, r) \ + _DW({ \ + gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RNX, FR_NEG_##r); \ + gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RNY, FR_NEG_##r); \ + gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RPX, FR_POS_##r); \ + gMoveWd(pkt, G_MW_CLIP, G_MWO_CLIP_RPY, FR_POS_##r); \ + }) + +#define gsSPClipRatio(r) \ + gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RNX, FR_NEG_##r), gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RNY, FR_NEG_##r), \ + gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RPX, FR_POS_##r), gsMoveWd(G_MW_CLIP, G_MWO_CLIP_RPY, FR_POS_##r) + +/* + * Insert values into Matrix + * + * where = element of matrix (byte offset) + * num = new element (32 bit value replacing 2 int or 2 frac matrix + * componants + */ +#ifdef F3DEX_GBI_2 +#define gSPInsertMatrix(pkt, where, num) ERROR !!gSPInsertMatrix is no longer supported. +#define gsSPInsertMatrix(where, num) ERROR !!gsSPInsertMatrix is no longer supported. +#else +#define gSPInsertMatrix(pkt, where, num) gMoveWd(pkt, G_MW_MATRIX, where, num) +#define gsSPInsertMatrix(where, num) gsMoveWd(G_MW_MATRIX, where, num) +#endif + +/* + * Load new matrix directly + * + * mptr = pointer to matrix + */ +#ifdef F3DEX_GBI_2 +#define gSPForceMatrix(pkt, mptr) \ + _DW({ \ + gDma2p((pkt), G_MOVEMEM, (mptr), sizeof(Mtx), G_MV_MATRIX, 0); \ + gMoveWd((pkt), G_MW_FORCEMTX, 0, 0x00010000); \ + }) +#define gsSPForceMatrix(mptr) \ + gsDma2p(G_MOVEMEM, (mptr), sizeof(Mtx), G_MV_MATRIX, 0), gsMoveWd(G_MW_FORCEMTX, 0, 0x00010000) + +#else /* F3DEX_GBI_2 */ +#define gSPForceMatrix(pkt, mptr) \ + { \ + gDma1p(pkt, G_MOVEMEM, mptr, 16, G_MV_MATRIX_1); \ + gDma1p(pkt, G_MOVEMEM, (char*)(mptr) + 16, 16, G_MV_MATRIX_2); \ + gDma1p(pkt, G_MOVEMEM, (char*)(mptr) + 32, 16, G_MV_MATRIX_3); \ + gDma1p(pkt, G_MOVEMEM, (char*)(mptr) + 48, 16, G_MV_MATRIX_4); \ + } +#define gsSPForceMatrix(mptr) \ + gsDma1p(G_MOVEMEM, mptr, 16, G_MV_MATRIX_1), gsDma1p(G_MOVEMEM, (char*)(mptr) + 16, 16, G_MV_MATRIX_2), \ + gsDma1p(G_MOVEMEM, (char*)(mptr) + 32, 16, G_MV_MATRIX_3), \ + gsDma1p(G_MOVEMEM, (char*)(mptr) + 48, 16, G_MV_MATRIX_4) +#endif /* F3DEX_GBI_2 */ + +/* + * Insert values into Points + * + * point = point number 0-15 + * where = which element of point to modify (byte offset into point) + * num = new value (32 bit) + */ +#if (defined(F3DEX_GBI) || defined(F3DLP_GBI)) +#define gSPModifyVertex(pkt, vtx, where, val) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + _g->words.w0 = (_SHIFTL(G_MODIFYVTX, 24, 8) | _SHIFTL((where), 16, 8) | _SHIFTL((vtx)*2, 0, 16)); \ + _g->words.w1 = (unsigned int)(val); \ + }) +#define gsSPModifyVertex(vtx, where, val) \ + { _SHIFTL(G_MODIFYVTX, 24, 8) | _SHIFTL((where), 16, 8) | _SHIFTL((vtx)*2, 0, 16), (unsigned int)(val) } +#else +#define gSPModifyVertex(pkt, vtx, where, val) gMoveWd(pkt, G_MW_POINTS, (vtx)*40 + (where), val) +#define gsSPModifyVertex(vtx, where, val) gsMoveWd(G_MW_POINTS, (vtx)*40 + (where), val) +#endif + +#if (defined(F3DEX_GBI) || defined(F3DLP_GBI)) +/* + * gSPBranchLessZ Branch DL if (vtx.z) less than or equal (zval). + * + * dl = DL branch to + * vtx = Vertex + * zval = Screen depth + * near = Near plane + * far = Far plane + * flag = G_BZ_PERSP or G_BZ_ORTHO + */ + +#define G_BZ_PERSP 0 +#define G_BZ_ORTHO 1 + +#define G_DEPTOZSrg(zval, near, far, flag, zmin, zmax) \ + (((unsigned int)FTOFIX32(((flag) == G_BZ_PERSP \ + ? (1.0f - (float)(near) / (float)(zval)) / (1.0f - (float)(near) / (float)(far)) \ + : ((float)(zval) - (float)(near)) / ((float)(far) - (float)(near))))) * \ + (((int)((zmax) - (zmin))) & ~1) + \ + (int)FTOFIX32(zmin)) + +#define G_DEPTOZS(zval, near, far, flag) G_DEPTOZSrg(zval, near, far, flag, 0, G_MAXZ) + +#define gSPBranchLessZrg(pkt, dl, vtx, zval, near, far, flag, zmin, zmax) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + _g->words.w0 = _SHIFTL(G_RDPHALF_1, 24, 8); \ + _g->words.w1 = (uintptr_t)(dl); \ + _g = (Gfx*)(pkt); \ + _g->words.w0 = (_SHIFTL(G_BRANCH_Z, 24, 8) | _SHIFTL((vtx)*5, 12, 12) | _SHIFTL((vtx)*2, 0, 12)); \ + _g->words.w1 = G_DEPTOZSrg(zval, near, far, flag, zmin, zmax); \ + }) + +#define gsSPBranchLessZrg(dl, vtx, zval, near, far, flag, zmin, zmax) \ + { \ + _SHIFTL(G_RDPHALF_1, 24, 8), \ + (uintptr_t)(dl), \ + }, \ + { \ + _SHIFTL(G_BRANCH_Z, 24, 8) | _SHIFTL((vtx)*5, 12, 12) | _SHIFTL((vtx)*2, 0, 12), \ + G_DEPTOZSrg(zval, near, far, flag, zmin, zmax), \ + } + +#define gSPBranchLessZ(pkt, dl, vtx, zval, near, far, flag) \ + gSPBranchLessZrg(pkt, dl, vtx, zval, near, far, flag, 0, G_MAXZ) +#define gsSPBranchLessZ(dl, vtx, zval, near, far, flag) gsSPBranchLessZrg(dl, vtx, zval, near, far, flag, 0, G_MAXZ) + +/* + * gSPBranchLessZraw Branch DL if (vtx.z) less than or equal (raw zval). + * + * dl = DL branch to + * vtx = Vertex + * zval = Raw value of screen depth + */ +#define gSPBranchLessZraw(pkt, dl, vtx, zval) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + _g->words.w0 = _SHIFTL(G_RDPHALF_1, 24, 8); \ + _g->words.w1 = (uintptr_t)(dl); \ + _g = (Gfx*)(pkt); \ + _g->words.w0 = (_SHIFTL(G_BRANCH_Z, 24, 8) | _SHIFTL((vtx)*5, 12, 12) | _SHIFTL((vtx)*2, 0, 12)); \ + _g->words.w1 = (uintptr_t)(zval); \ + }) + +#define gsSPBranchLessZraw(dl, vtx, zval) \ + { \ + _SHIFTL(G_RDPHALF_1, 24, 8), \ + (uintptr_t)(dl), \ + }, \ + { \ + _SHIFTL(G_BRANCH_Z, 24, 8) | _SHIFTL((vtx)*5, 12, 12) | _SHIFTL((vtx)*2, 0, 12), (uintptr_t)(zval), \ + } + +/* + * gSPLoadUcode RSP loads specified ucode. + * + * uc_start = ucode text section start + * uc_dstart = ucode data section start + */ +#define gSPLoadUcodeEx(pkt, uc_start, uc_dstart, uc_dsize) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + _g->words.w0 = _SHIFTL(G_RDPHALF_1, 24, 8); \ + _g->words.w1 = (uintptr_t)(uc_dstart); \ + _g = (Gfx*)(pkt); \ + _g->words.w0 = (_SHIFTL(G_LOAD_UCODE, 24, 8) | _SHIFTL((int)(uc_dsize)-1, 0, 16)); \ + _g->words.w1 = (uintptr_t)(uc_start); \ + }) + +#define gsSPLoadUcodeEx(uc_start, uc_dstart, uc_dsize) \ + { \ + _SHIFTL(G_RDPHALF_1, 24, 8), \ + (uintptr_t)(uc_dstart), \ + }, \ + { \ + _SHIFTL(G_LOAD_UCODE, 24, 8) | _SHIFTL((int)(uc_dsize)-1, 0, 16), (uintptr_t)(uc_start), \ + } + +#define gSPLoadUcode(pkt, uc_index) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + _g->words.w0 = _SHIFTL(G_LOAD_UCODE, 24, 8) | _SHIFTL(uc_index, 0, 16); \ + }) + +#define gSPLoadUcodeL(pkt, uc_index) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + _g->words.w0 = _SHIFTL(G_LOAD_UCODE, 24, 8) | _SHIFTL(uc_index, 0, 16); \ + }) + +#endif + +#ifdef F3DEX_GBI_2 +/* + * gSPDma_io DMA to/from DMEM/IMEM for DEBUG. + */ +#define gSPDma_io(pkt, flag, dmem, dram, size) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + _g->words.w0 = _SHIFTL(G_DMA_IO, 24, 8) | _SHIFTL((flag), 23, 1) | _SHIFTL((dmem) / 8, 13, 10) | \ + _SHIFTL((size)-1, 0, 12); \ + _g->words.w1 = (uintptr_t)(dram); \ + }) + +#define gsSPDma_io(flag, dmem, dram, size) \ + { \ + _SHIFTL(G_DMA_IO, 24, 8) | _SHIFTL((flag), 23, 1) | _SHIFTL((dmem) / 8, 13, 10) | _SHIFTL((size)-1, 0, 12), \ + (uintptr_t)(dram) \ + } + +#define gSPDmaRead(pkt, dmem, dram, size) gSPDma_io((pkt), 0, (dmem), (dram), (size)) +#define gsSPDmaRead(dmem, dram, size) gsSPDma_io(0, (dmem), (dram), (size)) +#define gSPDmaWrite(pkt, dmem, dram, size) gSPDma_io((pkt), 1, (dmem), (dram), (size)) +#define gsSPDmaWrite(dmem, dram, size) gsSPDma_io(1, (dmem), (dram), (size)) +#endif + +/* + * Lighting Macros + */ +#ifdef F3DEX_GBI_2 +#define NUML(n) ((n)*24) +#else +#define NUML(n) (((n) + 1) * 32 + 0x80000000) +#endif +#define NUMLIGHTS_0 1 +#define NUMLIGHTS_1 1 +#define NUMLIGHTS_2 2 +#define NUMLIGHTS_3 3 +#define NUMLIGHTS_4 4 +#define NUMLIGHTS_5 5 +#define NUMLIGHTS_6 6 +#define NUMLIGHTS_7 7 +/* + * n should be one of: NUMLIGHTS_0, NUMLIGHTS_1, ..., NUMLIGHTS_7 + * NOTE: in addition to the number of directional lights specified, + * there is always 1 ambient light + */ +#define gSPNumLights(pkt, n) gMoveWd(pkt, G_MW_NUMLIGHT, G_MWO_NUMLIGHT, NUML(n)) +#define gsSPNumLights(n) gsMoveWd(G_MW_NUMLIGHT, G_MWO_NUMLIGHT, NUML(n)) + +#define LIGHT_1 1 +#define LIGHT_2 2 +#define LIGHT_3 3 +#define LIGHT_4 4 +#define LIGHT_5 5 +#define LIGHT_6 6 +#define LIGHT_7 7 +#define LIGHT_8 8 +/* + * l should point to a Light struct + * n should be one of: LIGHT_1, LIGHT_2, ..., LIGHT_8 + * NOTE: the highest numbered light is always the ambient light (eg if there are + * 3 directional lights defined: gsSPNumLights(NUMLIGHTS_3), then lights + * LIGHT_1 through LIGHT_3 will be the directional lights and light + * LIGHT_4 will be the ambient light. + */ +#ifdef F3DEX_GBI_2 +#define gSPLight(pkt, l, n) gDma2p((pkt), G_MOVEMEM, (l), sizeof(Light), G_MV_LIGHT, (n)*24 + 24) +#define gsSPLight(l, n) gsDma2p(G_MOVEMEM, (l), sizeof(Light), G_MV_LIGHT, (n)*24 + 24) +#else /* F3DEX_GBI_2 */ +#define gSPLight(pkt, l, n) gDma1p(pkt, G_MOVEMEM, l, sizeof(Light), ((n)-1) * 2 + G_MV_L0) +#define gsSPLight(l, n) gsDma1p(G_MOVEMEM, l, sizeof(Light), ((n)-1) * 2 + G_MV_L0) +#endif /* F3DEX_GBI_2 */ + +/* + * gSPLightColor changes color of light without recalculating light direction + * col is a 32 bit word with r,g,b,a (alpha is ignored) + * n should be one of LIGHT_1, LIGHT_2, ..., LIGHT_8 + */ +#define gSPLightColor(pkt, n, col) \ + _DW({ \ + gMoveWd(pkt, G_MW_LIGHTCOL, G_MWO_a##n, col); \ + gMoveWd(pkt, G_MW_LIGHTCOL, G_MWO_b##n, col); \ + }) +#define gsSPLightColor(n, col) gsMoveWd(G_MW_LIGHTCOL, G_MWO_a##n, col), gsMoveWd(G_MW_LIGHTCOL, G_MWO_b##n, col) + +/* These macros use a structure "name" which is init'd with the gdSPDefLights macros*/ + +#define gSPSetLights0(pkt, name) \ + _DW({ \ + gSPNumLights(pkt, NUMLIGHTS_0); \ + gSPLight(pkt, &name.l[0], 1); \ + gSPLight(pkt, &name.a, 2); \ + }) +#define gsSPSetLights0(name) gsSPNumLights(NUMLIGHTS_0), gsSPLight(&name.l[0], 1), gsSPLight(&name.a, 2) + +#define gSPSetLights1(pkt, name) \ + _DW({ \ + gSPNumLights(pkt, NUMLIGHTS_1); \ + gSPLight(pkt, &name.l[0], 1); \ + gSPLight(pkt, &name.a, 2); \ + }) +#define gsSPSetLights1(name) gsSPNumLights(NUMLIGHTS_1), gsSPLight(&name.l[0], 1), gsSPLight(&name.a, 2) + +#define gSPSetLights2(pkt, name) \ + _DW({ \ + gSPNumLights(pkt, NUMLIGHTS_2); \ + gSPLight(pkt, &name.l[0], 1); \ + gSPLight(pkt, &name.l[1], 2); \ + gSPLight(pkt, &name.a, 3); \ + }) +#define gsSPSetLights2(name) \ + gsSPNumLights(NUMLIGHTS_2), gsSPLight(&name.l[0], 1), gsSPLight(&name.l[1], 2), gsSPLight(&name.a, 3) + +#define gSPSetLights3(pkt, name) \ + _DW({ \ + gSPNumLights(pkt, NUMLIGHTS_3); \ + gSPLight(pkt, &name.l[0], 1); \ + gSPLight(pkt, &name.l[1], 2); \ + gSPLight(pkt, &name.l[2], 3); \ + gSPLight(pkt, &name.a, 4); \ + }) +#define gsSPSetLights3(name) \ + gsSPNumLights(NUMLIGHTS_3), gsSPLight(&name.l[0], 1), gsSPLight(&name.l[1], 2), gsSPLight(&name.l[2], 3), \ + gsSPLight(&name.a, 4) + +#define gSPSetLights4(pkt, name) \ + _DW({ \ + gSPNumLights(pkt, NUMLIGHTS_4); \ + gSPLight(pkt, &name.l[0], 1); \ + gSPLight(pkt, &name.l[1], 2); \ + gSPLight(pkt, &name.l[2], 3); \ + gSPLight(pkt, &name.l[3], 4); \ + gSPLight(pkt, &name.a, 5); \ + }) +#define gsSPSetLights4(name) \ + gsSPNumLights(NUMLIGHTS_4), gsSPLight(&name.l[0], 1), gsSPLight(&name.l[1], 2), gsSPLight(&name.l[2], 3), \ + gsSPLight(&name.l[3], 4), gsSPLight(&name.a, 5) + +#define gSPSetLights5(pkt, name) \ + _DW({ \ + gSPNumLights(pkt, NUMLIGHTS_5); \ + gSPLight(pkt, &name.l[0], 1); \ + gSPLight(pkt, &name.l[1], 2); \ + gSPLight(pkt, &name.l[2], 3); \ + gSPLight(pkt, &name.l[3], 4); \ + gSPLight(pkt, &name.l[4], 5); \ + gSPLight(pkt, &name.a, 6); \ + }) + +#define gsSPSetLights5(name) \ + gsSPNumLights(NUMLIGHTS_5), gsSPLight(&name.l[0], 1), gsSPLight(&name.l[1], 2), gsSPLight(&name.l[2], 3), \ + gsSPLight(&name.l[3], 4), gsSPLight(&name.l[4], 5), gsSPLight(&name.a, 6) + +#define gSPSetLights6(pkt, name) \ + _DW({ \ + gSPNumLights(pkt, NUMLIGHTS_6); \ + gSPLight(pkt, &name.l[0], 1); \ + gSPLight(pkt, &name.l[1], 2); \ + gSPLight(pkt, &name.l[2], 3); \ + gSPLight(pkt, &name.l[3], 4); \ + gSPLight(pkt, &name.l[4], 5); \ + gSPLight(pkt, &name.l[5], 6); \ + gSPLight(pkt, &name.a, 7); \ + }) + +#define gsSPSetLights6(name) \ + gsSPNumLights(NUMLIGHTS_6), gsSPLight(&name.l[0], 1), gsSPLight(&name.l[1], 2), gsSPLight(&name.l[2], 3), \ + gsSPLight(&name.l[3], 4), gsSPLight(&name.l[4], 5), gsSPLight(&name.l[5], 6), gsSPLight(&name.a, 7) + +#define gSPSetLights7(pkt, name) \ + _DW({ \ + gSPNumLights(pkt, NUMLIGHTS_7); \ + gSPLight(pkt, &name.l[0], 1); \ + gSPLight(pkt, &name.l[1], 2); \ + gSPLight(pkt, &name.l[2], 3); \ + gSPLight(pkt, &name.l[3], 4); \ + gSPLight(pkt, &name.l[4], 5); \ + gSPLight(pkt, &name.l[5], 6); \ + gSPLight(pkt, &name.l[6], 7); \ + gSPLight(pkt, &name.a, 8); \ + }) + +#define gsSPSetLights7(name) \ + gsSPNumLights(NUMLIGHTS_7), gsSPLight(&name.l[0], 1), gsSPLight(&name.l[1], 2), gsSPLight(&name.l[2], 3), \ + gsSPLight(&name.l[3], 4), gsSPLight(&name.l[4], 5), gsSPLight(&name.l[5], 6), gsSPLight(&name.l[6], 7), \ + gsSPLight(&name.a, 8) + +/* + * Reflection/Hiliting Macros + */ +#ifdef F3DEX_GBI_2 +#define gSPLookAtX(pkt, l) gDma2p((pkt), G_MOVEMEM, (l), sizeof(Light), G_MV_LIGHT, G_MVO_LOOKATX) +#define gsSPLookAtX(l) gsDma2p(G_MOVEMEM, (l), sizeof(Light), G_MV_LIGHT, G_MVO_LOOKATX) +#define gSPLookAtY(pkt, l) gDma2p((pkt), G_MOVEMEM, (l), sizeof(Light), G_MV_LIGHT, G_MVO_LOOKATY) +#define gsSPLookAtY(l) gsDma2p(G_MOVEMEM, (l), sizeof(Light), G_MV_LIGHT, G_MVO_LOOKATY) +#else /* F3DEX_GBI_2 */ +#define gSPLookAtX(pkt, l) gDma1p(pkt, G_MOVEMEM, l, sizeof(Light), G_MV_LOOKATX) +#define gsSPLookAtX(l) gsDma1p(G_MOVEMEM, l, sizeof(Light), G_MV_LOOKATX) +#define gSPLookAtY(pkt, l) gDma1p(pkt, G_MOVEMEM, l, sizeof(Light), G_MV_LOOKATY) +#define gsSPLookAtY(l) gsDma1p(G_MOVEMEM, l, sizeof(Light), G_MV_LOOKATY) +#endif /* F3DEX_GBI_2 */ + +#define gSPLookAt(pkt, la) \ + _DW({ \ + gSPLookAtX(pkt, la); \ + gSPLookAtY(pkt, (char*)(la) + 16); \ + }) +#define gsSPLookAt(la) gsSPLookAtX(la), gsSPLookAtY((char*)(la) + 16) + +#define gDPSetHilite1Tile(pkt, tile, hilite, width, height) \ + gDPSetTileSize(pkt, tile, (hilite)->h.x1 & 0xfff, (hilite)->h.y1 & 0xfff, \ + ((((width)-1) * 4) + (hilite)->h.x1) & 0xfff, ((((height)-1) * 4) + (hilite)->h.y1) & 0xfff) +#define gsDPSetHilite1Tile(tile, hilite, width, height) \ + gsDPSetTileSize(tile, (hilite)->h.x1 & 0xfff, (hilite)->h.y1 & 0xfff, \ + ((((width)-1) * 4) + (hilite)->h.x1) & 0xfff, ((((height)-1) * 4) + (hilite)->h.y1) & 0xfff) + +#define gDPSetHilite2Tile(pkt, tile, hilite, width, height) \ + gDPSetTileSize(pkt, tile, (hilite)->h.x2 & 0xfff, (hilite)->h.y2 & 0xfff, \ + ((((width)-1) * 4) + (hilite)->h.x2) & 0xfff, ((((height)-1) * 4) + (hilite)->h.y2) & 0xfff) +#define gsDPSetHilite2Tile(tile, hilite, width, height) \ + gsDPSetTileSize(tile, (hilite)->h.x2 & 0xfff, (hilite)->h.y2 & 0xfff, \ + ((((width)-1) * 4) + (hilite)->h.x2) & 0xfff, ((((height)-1) * 4) + (hilite)->h.y2) & 0xfff) + +/* + * FOG macros + * fm = z multiplier + * fo = z offset + * FOG FORMULA: alpha(fog) = (eyespace z) * fm + fo CLAMPED 0 to 255 + * note: (eyespace z) ranges -1 to 1 + * + * Alternate method of setting fog: + * min, max: range 0 to 1000: 0=nearplane, 1000=farplane + * min is where fog begins (usually less than max and often 0) + * max is where fog is thickest (usually 1000) + * + */ +#define gSPFogFactor(pkt, fm, fo) gMoveWd(pkt, G_MW_FOG, G_MWO_FOG, (_SHIFTL(fm, 16, 16) | _SHIFTL(fo, 0, 16))) + +#define gsSPFogFactor(fm, fo) gsMoveWd(G_MW_FOG, G_MWO_FOG, (_SHIFTL(fm, 16, 16) | _SHIFTL(fo, 0, 16))) + +#define gSPFogPosition(pkt, min, max) \ + gMoveWd(pkt, G_MW_FOG, G_MWO_FOG, \ + (_SHIFTL((128000 / ((max) - (min))), 16, 16) | _SHIFTL(((500 - (min)) * 256 / ((max) - (min))), 0, 16))) + +#define gsSPFogPosition(min, max) \ + gsMoveWd(G_MW_FOG, G_MWO_FOG, \ + (_SHIFTL((128000 / ((max) - (min))), 16, 16) | _SHIFTL(((500 - (min)) * 256 / ((max) - (min))), 0, 16))) + +#ifdef F3DEX_GBI_2 +/* + * Macros to turn texture on/off + */ +#define gSPTexture(pkt, s, t, level, tile, on) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_TEXTURE, 24, 8) | _SHIFTL(BOWTIE_VAL, 16, 8) | _SHIFTL((level), 11, 3) | \ + _SHIFTL((tile), 8, 3) | _SHIFTL((on), 1, 7)); \ + _g->words.w1 = (_SHIFTL((s), 16, 16) | _SHIFTL((t), 0, 16)); \ + }) +#define gsSPTexture(s, t, level, tile, on) \ + { \ + (_SHIFTL(G_TEXTURE, 24, 8) | _SHIFTL(BOWTIE_VAL, 16, 8) | _SHIFTL((level), 11, 3) | _SHIFTL((tile), 8, 3) | \ + _SHIFTL((on), 1, 7)), \ + (_SHIFTL((s), 16, 16) | _SHIFTL((t), 0, 16)) \ + } +/* + * Different version of SPTexture macro, has an additional parameter + * which is currently reserved in the microcode. + */ +#define gSPTextureL(pkt, s, t, level, xparam, tile, on) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_TEXTURE, 24, 8) | _SHIFTL((xparam), 16, 8) | _SHIFTL((level), 11, 3) | \ + _SHIFTL((tile), 8, 3) | _SHIFTL((on), 1, 7)); \ + _g->words.w1 = (_SHIFTL((s), 16, 16) | _SHIFTL((t), 0, 16)); \ + }) +#define gsSPTextureL(s, t, level, xparam, tile, on) \ + { \ + (_SHIFTL(G_TEXTURE, 24, 8) | _SHIFTL((xparam), 16, 8) | _SHIFTL((level), 11, 3) | _SHIFTL((tile), 8, 3) | \ + _SHIFTL((on), 1, 7)), \ + (_SHIFTL((s), 16, 16) | _SHIFTL((t), 0, 16)) \ + } +#else +/* + * Macros to turn texture on/off + */ +#define gSPTexture(pkt, s, t, level, tile, on) \ + { \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_TEXTURE, 24, 8) | _SHIFTL(BOWTIE_VAL, 16, 8) | _SHIFTL((level), 11, 3) | \ + _SHIFTL((tile), 8, 3) | _SHIFTL((on), 0, 8)); \ + _g->words.w1 = (_SHIFTL((s), 16, 16) | _SHIFTL((t), 0, 16)); \ + } +#define gsSPTexture(s, t, level, tile, on) \ + { \ + (_SHIFTL(G_TEXTURE, 24, 8) | _SHIFTL(BOWTIE_VAL, 16, 8) | _SHIFTL((level), 11, 3) | _SHIFTL((tile), 8, 3) | \ + _SHIFTL((on), 0, 8)), \ + (_SHIFTL((s), 16, 16) | _SHIFTL((t), 0, 16)) \ + } +/* + * Different version of SPTexture macro, has an additional parameter + * which is currently reserved in the microcode. + */ +#define gSPTextureL(pkt, s, t, level, xparam, tile, on) \ + { \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_TEXTURE, 24, 8) | _SHIFTL((xparam), 16, 8) | _SHIFTL((level), 11, 3) | \ + _SHIFTL((tile), 8, 3) | _SHIFTL((on), 0, 8)); \ + _g->words.w1 = (_SHIFTL((s), 16, 16) | _SHIFTL((t), 0, 16)); \ + } +#define gsSPTextureL(s, t, level, xparam, tile, on) \ + { \ + (_SHIFTL(G_TEXTURE, 24, 8) | _SHIFTL((xparam), 16, 8) | _SHIFTL((level), 11, 3) | _SHIFTL((tile), 8, 3) | \ + _SHIFTL((on), 0, 8)), \ + (_SHIFTL((s), 16, 16) | _SHIFTL((t), 0, 16)) \ + } +#endif + +#define gSPPerspNormalize(pkt, s) gMoveWd(pkt, G_MW_PERSPNORM, 0, (s)) +#define gsSPPerspNormalize(s) gsMoveWd(G_MW_PERSPNORM, 0, (s)) + +#ifdef F3DEX_GBI_2 +#define gSPPopMatrixN(pkt, n, num) gDma2p((pkt), G_POPMTX, (num)*64, 64, 2, 0) +#define gsSPPopMatrixN(n, num) gsDma2p(G_POPMTX, (num)*64, 64, 2, 0) +#define gSPPopMatrix(pkt, n) gSPPopMatrixN((pkt), (n), 1) +#define gsSPPopMatrix(n) gsSPPopMatrixN((n), 1) +#else /* F3DEX_GBI_2 */ +#define gSPPopMatrix(pkt, n) gImmp1(pkt, G_POPMTX, n) +#define gsSPPopMatrix(n) gsImmp1(G_POPMTX, n) +#endif /* F3DEX_GBI_2 */ + +#define gSPEndDisplayList(pkt) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_ENDDL, 24, 8); \ + _g->words.w1 = 0; \ + }) + +#define gsSPEndDisplayList() \ + { _SHIFTL(G_ENDDL, 24, 8), 0 } + +#define __gSPInvalidateTexCache(pkt, addr) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_INVALTEXCACHE, 24, 8); \ + _g->words.w1 = addr; \ + }) + +#define gsSPInvalidateTexCache() \ + { _SHIFTL(G_INVALTEXCACHE, 24, 8), 0 } + +#define gSPRegisterBlendedTex(pkt, timg, mask, replc) \ + { \ + Gfx *_g0 = (Gfx*)(pkt), *_g1 = (Gfx*)(pkt); \ + \ + _g0->words.w0 = _SHIFTL(G_REGBLENDEDTEX, 24, 8); \ + _g0->words.w1 = (uintptr_t)timg; \ + _g1->words.w0 = (uintptr_t)mask; \ + _g1->words.w1 = (uintptr_t)replc; \ + } + +#define gsSPSetFB(pkt, fb) \ + { \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_SETFB, 24, 8); \ + _g->words.w1 = fb; \ + } + +#define gsSPResetFB(pkt) \ + { \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_RESETFB, 24, 8); \ + _g->words.w1 = 0; \ + } + +// Copy a framebuffer's texture to another framebuffer's in the GPU +#define gDPCopyFB(pkt, dst, src, once, copiedPtr) \ + { \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_COPYFB, 24, 8) | _SHIFTL(dst, 11, 11) | _SHIFTL(src, 0, 11) | _SHIFTL(once, 22, 1); \ + _g->words.w1 = (uintptr_t)copiedPtr; \ + } + +// Read the framebuffer's texture to a cpu memory location as RGBA16 +#define gDPReadFB(pkt, src, rgba16buf, ulx, uly, width, height, bswap) \ + { \ + Gfx *_g0 = (Gfx*)(pkt), *_g1 = (Gfx*)(pkt); \ + \ + _g0->words.w0 = _SHIFTL(G_READFB, 24, 8) | _SHIFTL(bswap, 8, 1) | _SHIFTL(src, 0, 8); \ + _g0->words.w1 = (uintptr_t)rgba16buf; \ + _g1->words.w0 = _SHIFTL(uly, 16, 16) | _SHIFTL(ulx, 0, 16); \ + _g1->words.w1 = _SHIFTL(height, 16, 16) | _SHIFTL(width, 0, 16); \ + } + +#define gDPImageRectangle(pkt, x0, y0, s0, t0, x1, y1, s1, t1, tile, iw, ih) \ + { \ + Gfx *_g0 = (Gfx*)(pkt), *_g1 = (Gfx*)(pkt), *_g2 = (Gfx*)(pkt); \ + \ + _g0->words.w0 = _SHIFTL(G_IMAGERECT, 24, 8) | _SHIFTL((tile), 0, 3); \ + _g0->words.w1 = _SHIFTL((iw), 16, 16) | _SHIFTL((ih), 0, 16); \ + _g1->words.w0 = _SHIFTL((x0), 16, 16) | _SHIFTL((y0), 0, 16); \ + _g1->words.w1 = _SHIFTL((s0), 16, 16) | _SHIFTL((t0), 0, 16); \ + _g2->words.w0 = _SHIFTL((x1), 16, 16) | _SHIFTL((y1), 0, 16); \ + _g2->words.w1 = _SHIFTL((s1), 16, 16) | _SHIFTL((t1), 0, 16); \ + } + +#define gSPGrayscale(pkt, state) \ + { \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_SETGRAYSCALE, 24, 8); \ + _g->words.w1 = state; \ + } + +#define gsSPGrayscale(state) \ + { (_SHIFTL(G_SETGRAYSCALE, 24, 8)), (state) } + +#define gsSPPushShader(shader) \ + { (_SHIFTL(G_PUSH_SHADER, 24, 8)), (uintptr_t)(shader) }, { \ + 0, 0 \ + } + +#define gSPPushShader(pkt, shader) \ + { \ + Gfx* _g0 = (Gfx*)(pkt); \ + \ + _g0->words.w0 = _SHIFTL(G_PUSH_SHADER, 24, 8); \ + _g0->words.w1 = (uintptr_t)(shader); \ + } + +#define gsSPPopShader() \ + { (_SHIFTL(G_POP_SHADER, 24, 8)), 0 }, { \ + 0, 0 \ + } + +#define gSPPopShader(pkt) \ + { \ + Gfx* _g0 = (Gfx*)(pkt); \ + \ + _g0->words.w0 = _SHIFTL(G_POP_SHADER, 24, 8); \ + } + +#define gSPExtraGeometryMode(pkt, c, s) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_EXTRAGEOMETRYMODE, 24, 8) | _SHIFTL(~(u32)(c), 0, 24); \ + _g->words.w1 = (u32)(s); \ + }) + +#define gSPSetExtraGeometryMode(pkt, word) gSPExtraGeometryMode((pkt), 0, word) +#define gSPClearExtraGeometryMode(pkt, word) gSPExtraGeometryMode((pkt), word, 0) + +#ifdef F3DEX_GBI_2 +/* + * One gSPGeometryMode(pkt,c,s) GBI is equal to these two GBIs. + * + * gSPClearGeometryMode(pkt,c) + * gSPSetGeometryMode(pkt,s) + * + * gSPLoadGeometryMode(pkt, word) sets GeometryMode directly. + */ +#define gSPGeometryMode(pkt, c, s) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + _g->words.w0 = _SHIFTL(G_GEOMETRYMODE, 24, 8) | _SHIFTL(~(u32)(c), 0, 24); \ + _g->words.w1 = (u32)(s); \ + }) + +#define gsSPGeometryMode(c, s) \ + { (_SHIFTL(G_GEOMETRYMODE, 24, 8) | _SHIFTL(~(u32)(c), 0, 24)), (u32)(s) } +#define gSPSetGeometryMode(pkt, word) gSPGeometryMode((pkt), 0, (word)) +#define gsSPSetGeometryMode(word) gsSPGeometryMode(0, (word)) +#define gSPClearGeometryMode(pkt, word) gSPGeometryMode((pkt), (word), 0) +#define gsSPClearGeometryMode(word) gsSPGeometryMode((word), 0) +#define gSPLoadGeometryMode(pkt, word) gSPGeometryMode((pkt), -1, (word)) +#define gsSPLoadGeometryMode(word) gsSPGeometryMode(-1, (word)) + +#else /* F3DEX_GBI_2 */ +#define gSPSetGeometryMode(pkt, word) \ + { \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_SETGEOMETRYMODE, 24, 8); \ + _g->words.w1 = (unsigned int)(word); \ + } + +#define gsSPSetGeometryMode(word) \ + { _SHIFTL(G_SETGEOMETRYMODE, 24, 8), (unsigned int)(word) } + +#define gSPClearGeometryMode(pkt, word) \ + { \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_CLEARGEOMETRYMODE, 24, 8); \ + _g->words.w1 = (unsigned int)(word); \ + } + +#define gsSPClearGeometryMode(word) \ + { _SHIFTL(G_CLEARGEOMETRYMODE, 24, 8), (unsigned int)(word) } +#endif /* F3DEX_GBI_2 */ + +#ifdef F3DEX_GBI_2 +#define gSPSetOtherMode(pkt, cmd, sft, len, data) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + _g->words.w0 = (_SHIFTL(cmd, 24, 8) | _SHIFTL(32 - (sft) - (len), 8, 8) | _SHIFTL((len)-1, 0, 8)); \ + _g->words.w1 = (unsigned int)(data); \ + }) + +#define gsSPSetOtherMode(cmd, sft, len, data) \ + { _SHIFTL(cmd, 24, 8) | _SHIFTL(32 - (sft) - (len), 8, 8) | _SHIFTL((len)-1, 0, 8), (unsigned int)(data) } +#else +#define gSPSetOtherMode(pkt, cmd, sft, len, data) \ + { \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | _SHIFTL(len, 0, 8)); \ + _g->words.w1 = (unsigned int)(data); \ + } + +#define gsSPSetOtherMode(cmd, sft, len, data) \ + { _SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | _SHIFTL(len, 0, 8), (unsigned int)(data) } +#endif + +/* + * RDP setothermode register commands - register shadowed in RSP + */ +#define gDPPipelineMode(pkt, mode) gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_PIPELINE, 1, mode) +#define gsDPPipelineMode(mode) gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_PIPELINE, 1, mode) + +#define gDPSetCycleType(pkt, type) gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_CYCLETYPE, 2, type) +#define gsDPSetCycleType(type) gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_CYCLETYPE, 2, type) + +#define gDPSetTexturePersp(pkt, type) gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTPERSP, 1, type) +#define gsDPSetTexturePersp(type) gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTPERSP, 1, type) + +#define gDPSetTextureDetail(pkt, type) gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTDETAIL, 2, type) +#define gsDPSetTextureDetail(type) gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTDETAIL, 2, type) + +#define gDPSetTextureLOD(pkt, type) gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTLOD, 1, type) +#define gsDPSetTextureLOD(type) gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTLOD, 1, type) + +#define gDPSetTextureLUT(pkt, type) gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTLUT, 2, type) +#define gsDPSetTextureLUT(type) gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTLUT, 2, type) + +#define gDPSetTextureFilter(pkt, type) gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTFILT, 2, type) +#define gsDPSetTextureFilter(type) gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTFILT, 2, type) + +#define gDPSetTextureConvert(pkt, type) gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_TEXTCONV, 3, type) +#define gsDPSetTextureConvert(type) gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_TEXTCONV, 3, type) + +#define gDPSetCombineKey(pkt, type) gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_COMBKEY, 1, type) +#define gsDPSetCombineKey(type) gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_COMBKEY, 1, type) + +#ifndef _HW_VERSION_1 +#define gDPSetColorDither(pkt, mode) gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_RGBDITHER, 2, mode) +#define gsDPSetColorDither(mode) gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_RGBDITHER, 2, mode) +#else +#define gDPSetColorDither(pkt, mode) gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_COLORDITHER, 1, mode) +#define gsDPSetColorDither(mode) gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_COLORDITHER, 1, mode) +#endif + +#ifndef _HW_VERSION_1 +#define gDPSetAlphaDither(pkt, mode) gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_ALPHADITHER, 2, mode) +#define gsDPSetAlphaDither(mode) gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_ALPHADITHER, 2, mode) +#endif + +#define gDPSetDither(pkt, mode) gSPSetOtherMode(pkt, G_SETOTHERMODE_H, G_MDSFT_ALPHADITHER, 4, mode) + +/* 'blendmask' is not supported anymore. + * The bits are reserved for future use. + * Fri May 26 13:45:55 PDT 1995 + */ +#define gDPSetBlendMask(pkt, mask) gDPNoOp(pkt) +#define gsDPSetBlendMask(mask) gsDPNoOp() + +#define gDPSetAlphaCompare(pkt, type) gSPSetOtherMode(pkt, G_SETOTHERMODE_L, G_MDSFT_ALPHACOMPARE, 2, type) +#define gsDPSetAlphaCompare(type) gsSPSetOtherMode(G_SETOTHERMODE_L, G_MDSFT_ALPHACOMPARE, 2, type) + +#define gDPSetDepthSource(pkt, src) gSPSetOtherMode(pkt, G_SETOTHERMODE_L, G_MDSFT_ZSRCSEL, 1, src) +#define gsDPSetDepthSource(src) gsSPSetOtherMode(G_SETOTHERMODE_L, G_MDSFT_ZSRCSEL, 1, src) + +#define gDPSetRenderMode(pkt, c0, c1) gSPSetOtherMode(pkt, G_SETOTHERMODE_L, G_MDSFT_RENDERMODE, 29, (c0) | (c1)) +#define gsDPSetRenderMode(c0, c1) gsSPSetOtherMode(G_SETOTHERMODE_L, G_MDSFT_RENDERMODE, 29, (c0) | (c1)) + +#define gSetImage(pkt, cmd, fmt, siz, width, i) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) | _SHIFTL(siz, 19, 2) | _SHIFTL((width)-1, 0, 12); \ + _g->words.w1 = (uintptr_t)(i); \ + }) + +#define gsSetImage(cmd, fmt, siz, width, i) \ + { _SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) | _SHIFTL(siz, 19, 2) | _SHIFTL((width)-1, 0, 12), (uintptr_t)(i) } + +#define gDPSetColorImage(pkt, f, s, w, i) gSetImage(pkt, G_SETCIMG, f, s, w, i) +#define gsDPSetColorImage(f, s, w, i) gsSetImage(G_SETCIMG, f, s, w, i) + +/* use these for new code */ +#define gDPSetDepthImage(pkt, i) gSetImage(pkt, G_SETZIMG, 0, 0, 1, i) +#define gsDPSetDepthImage(i) gsSetImage(G_SETZIMG, 0, 0, 1, i) +/* kept for compatibility */ +#define gDPSetMaskImage(pkt, i) gDPSetDepthImage(pkt, i) +#define gsDPSetMaskImage(i) gsDPSetDepthImage(i) + +#define gDPSetTextureImage(pkt, f, s, w, i) gSetImage(pkt, G_SETTIMG, f, s, w, i) +#define gsDPSetTextureImage(f, s, w, i) gsSetImage(G_SETTIMG, f, s, w, i) +#define gDPSetTextureImageFB(pkt, f, s, w, i) gSetImage(pkt, G_SETTIMG_FB, f, s, w, i) + +/* + * RDP macros + */ + +#define gDPSetCombine(pkt, muxs0, muxs1) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24); \ + _g->words.w1 = (unsigned int)(muxs1); \ + }) + +#define gsDPSetCombine(muxs0, muxs1) \ + { _SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24), (unsigned int)(muxs1) } + +#define GCCc0w0(saRGB0, mRGB0, saA0, mA0) \ + (_SHIFTL((saRGB0), 20, 4) | _SHIFTL((mRGB0), 15, 5) | _SHIFTL((saA0), 12, 3) | _SHIFTL((mA0), 9, 3)) + +#define GCCc1w0(saRGB1, mRGB1) (_SHIFTL((saRGB1), 5, 4) | _SHIFTL((mRGB1), 0, 5)) + +#define GCCc0w1(sbRGB0, aRGB0, sbA0, aA0) \ + (_SHIFTL((sbRGB0), 28, 4) | _SHIFTL((aRGB0), 15, 3) | _SHIFTL((sbA0), 12, 3) | _SHIFTL((aA0), 9, 3)) + +#define GCCc1w1(sbRGB1, saA1, mA1, aRGB1, sbA1, aA1) \ + (_SHIFTL((sbRGB1), 24, 4) | _SHIFTL((saA1), 21, 3) | _SHIFTL((mA1), 18, 3) | _SHIFTL((aRGB1), 6, 3) | \ + _SHIFTL((sbA1), 3, 3) | _SHIFTL((aA1), 0, 3)) + +#define gDPSetCombineLERP(pkt, a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, a1, b1, c1, d1, Aa1, Ab1, Ac1, Ad1) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = \ + _SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(GCCc0w0(G_CCMUX_##a0, G_CCMUX_##c0, G_ACMUX_##Aa0, G_ACMUX_##Ac0) | \ + GCCc1w0(G_CCMUX_##a1, G_CCMUX_##c1), \ + 0, 24); \ + _g->words.w1 = (unsigned int)(GCCc0w1(G_CCMUX_##b0, G_CCMUX_##d0, G_ACMUX_##Ab0, G_ACMUX_##Ad0) | \ + GCCc1w1(G_CCMUX_##b1, G_ACMUX_##Aa1, G_ACMUX_##Ac1, G_CCMUX_##d1, G_ACMUX_##Ab1, \ + G_ACMUX_##Ad1)); \ + }) + +#define gsDPSetCombineLERP(a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, a1, b1, c1, d1, Aa1, Ab1, Ac1, Ad1) \ + { \ + _SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(GCCc0w0(G_CCMUX_##a0, G_CCMUX_##c0, G_ACMUX_##Aa0, G_ACMUX_##Ac0) | \ + GCCc1w0(G_CCMUX_##a1, G_CCMUX_##c1), \ + 0, 24), \ + (unsigned int)(GCCc0w1(G_CCMUX_##b0, G_CCMUX_##d0, G_ACMUX_##Ab0, G_ACMUX_##Ad0) | \ + GCCc1w1(G_CCMUX_##b1, G_ACMUX_##Aa1, G_ACMUX_##Ac1, G_CCMUX_##d1, G_ACMUX_##Ab1, \ + G_ACMUX_##Ad1)) \ + } + +#define gsDPSetCombineLERP_NoMacros(a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, a1, b1, c1, d1, Aa1, Ab1, Ac1, Ad1) \ + { \ + _SHIFTL(G_SETCOMBINE, 24, 8) | _SHIFTL(GCCc0w0(a0, c0, Aa0, Ac0) | GCCc1w0(a1, c1), 0, 24), \ + (unsigned int)(GCCc0w1(b0, d0, Ab0, Ad0) | GCCc1w1(b1, Aa1, Ac1, d1, Ab1, Ad1)) \ + } + +/* + * SetCombineMode macros are NOT redunant. It allow the C preprocessor + * to substitute single parameter which includes commas in the token and + * rescan for higher parameter count macro substitution. + * + * eg. gsDPSetCombineMode(G_CC_MODULATE, G_CC_MODULATE) turns into + * gsDPSetCombineLERP(TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0, + * TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0) + */ + +/* +#if _MSC_VER +#define gDPSetCombineMode(pkt, a, b) gDPNoParam(pkt, G_NOOP) +#else +#define gDPSetCombineMode(pkt, a, b) gDPSetCombineLERP(pkt, a, b) +//#define gDPSetCombineMode(pkt, a, b) gDPSetCombineLERP(pkt, ##a, b) +#endif +*/ + +#if defined(_MSC_VER) +#define CALL_2(A, B) A B +#define CALL_3(A, B, C) A B C + +#define gDPSetCombineMode(pkt, a, b) CALL_2(gDPSetCombineLERP, (pkt, a, b)) +#define gsDPSetCombineMode(a, b) CALL_2(gsDPSetCombineLERP, (a, b)) +#else +#define gDPSetCombineMode(pkt, a, b) gDPSetCombineLERP(pkt, a, b) +#define gsDPSetCombineMode(a, b) gsDPSetCombineLERP(a, b) +#endif + +#if defined(_MSC_VER) || defined(__GNUC__) +#define CALL_2(A, B) A B +#define CALL_3(A, B, C) A B C + +// #define gsDPSetCombineMode(a, b) CALL_2(gsDPSetCombineLERP, (a, b)) +// #define gsDPSetCombineMode(a, b) _SHIFTL(0, 24, 8), 0 +#else +#define gsDPSetCombineMode(a, b) gsDPSetCombineLERP(a, b) +#endif + +#define gDPSetColor(pkt, c, d) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(c, 24, 8); \ + _g->words.w1 = (unsigned int)(d); \ + }) + +#define gsDPSetColor(c, d) \ + { _SHIFTL(c, 24, 8), (unsigned int)(d) } + +#define DPRGBColor(pkt, cmd, r, g, b, a) \ + gDPSetColor(pkt, cmd, (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8))) +#define sDPRGBColor(cmd, r, g, b, a) \ + gsDPSetColor(cmd, (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8))) + +#define gDPSetGrayscaleColor(pkt, r, g, b, lerp) DPRGBColor(pkt, G_SETINTENSITY, r, g, b, lerp) +#define gsDPSetGrayscaleColor(r, g, b, a) sDPRGBColor(G_SETINTENSITY, r, g, b, a) +#define gDPSetEnvColor(pkt, r, g, b, a) DPRGBColor(pkt, G_SETENVCOLOR, r, g, b, a) +#define gsDPSetEnvColor(r, g, b, a) sDPRGBColor(G_SETENVCOLOR, r, g, b, a) +#define gDPSetBlendColor(pkt, r, g, b, a) DPRGBColor(pkt, G_SETBLENDCOLOR, r, g, b, a) +#define gsDPSetBlendColor(r, g, b, a) sDPRGBColor(G_SETBLENDCOLOR, r, g, b, a) +#define gDPSetFogColor(pkt, r, g, b, a) DPRGBColor(pkt, G_SETFOGCOLOR, r, g, b, a) +#define gsDPSetFogColor(r, g, b, a) sDPRGBColor(G_SETFOGCOLOR, r, g, b, a) +#define gDPSetFillColor(pkt, d) gDPSetColor(pkt, G_SETFILLCOLOR, (d)) +#define gsDPSetFillColor(d) gsDPSetColor(G_SETFILLCOLOR, (d)) +#define gDPSetPrimDepth(pkt, z, dz) gDPSetColor(pkt, G_SETPRIMDEPTH, _SHIFTL(z, 16, 16) | _SHIFTL(dz, 0, 16)) +#define gsDPSetPrimDepth(z, dz) gsDPSetColor(G_SETPRIMDEPTH, _SHIFTL(z, 16, 16) | _SHIFTL(dz, 0, 16)) + +#define gDPSetPrimColor(pkt, m, l, r, g, b, a) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_SETPRIMCOLOR, 24, 8) | _SHIFTL(m, 8, 8) | _SHIFTL(l, 0, 8)); \ + _g->words.w1 = (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8)); \ + }) + +#define gsDPSetPrimColor(m, l, r, g, b, a) \ + { \ + (_SHIFTL(G_SETPRIMCOLOR, 24, 8) | _SHIFTL(m, 8, 8) | _SHIFTL(l, 0, 8)), \ + (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8)) \ + } + +/* + * gDPSetOtherMode (This is for expert user.) + * + * This command makes all othermode parameters set. + * Do not use this command in the same DL with another g*SPSetOtherMode DLs. + * + * [Usage] + * gDPSetOtherMode(pkt, modeA, modeB) + * + * 'modeA' is described all parameters of GroupA GBI command. + * 'modeB' is also described all parameters of GroupB GBI command. + * + * GroupA: + * gDPPipelineMode, gDPSetCycleType, gSPSetTexturePersp, + * gDPSetTextureDetail, gDPSetTextureLOD, gDPSetTextureLUT, + * gDPSetTextureFilter, gDPSetTextureConvert, gDPSetCombineKey, + * gDPSetColorDither, gDPSetAlphaDither + * + * GroupB: + * gDPSetAlphaCompare, gDPSetDepthSource, gDPSetRenderMode + * + * Use 'OR' operation to get modeA and modeB. + * + * modeA = G_PM_* | G_CYC_* | G_TP_* | G_TD_* | G_TL_* | G_TT_* | G_TF_* + * G_TC_* | G_CK_* | G_CD_* | G_AD_*; + * + * modeB = G_AC_* | G_ZS_* | G_RM_* | G_RM_*2; + */ +#define gDPSetOtherMode(pkt, mode0, mode1) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_RDPSETOTHERMODE, 24, 8) | _SHIFTL(mode0, 0, 24); \ + _g->words.w1 = (unsigned int)(mode1); \ + }) + +#define gsDPSetOtherMode(mode0, mode1) \ + { _SHIFTL(G_RDPSETOTHERMODE, 24, 8) | _SHIFTL(mode0, 0, 24), (unsigned int)(mode1) } + +/* + * Texturing macros + */ + +/* These are also defined defined above for Sprite Microcode */ + +#define G_TX_LOADTILE 7 +#define G_TX_RENDERTILE 0 + +#define G_TX_NOMIRROR 0 +#define G_TX_WRAP 0 +#define G_TX_MIRROR 0x1 +#define G_TX_CLAMP 0x2 +#define G_TX_NOMASK 0 +#define G_TX_NOLOD 0 + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif +/* + * Dxt is the inverse of the number of 64-bit words in a line of + * the texture being loaded using the load_block command. If + * there are any 1's to the right of the 11th fractional bit, + * dxt should be rounded up. The following macros accomplish + * this. The 4b macros are a special case since 4-bit textures + * are loaded as 8-bit textures. Dxt is fixed point 1.11. RJM + */ +#define G_TX_DXT_FRAC 11 + +/* + * For RCP 2.0, the maximum number of texels that can be loaded + * using a load_block command is 2048. In order to load the total + * 4kB of Tmem, change the texel size when loading to be G_IM_SIZ_16b, + * then change the tile to the proper texel size after the load. + * The g*DPLoadTextureBlock macros already do this, so this change + * will be transparent if you use these macros. If you use + * the g*DPLoadBlock macros directly, you will need to handle this + * tile manipulation yourself. RJM. + */ + +#define G_TX_LDBLK_MAX_TXL 4095 + +#define TXL2WORDS(txls, b_txl) MAX(1, ((txls) * (b_txl) / 8)) +#define CALC_DXT(width, b_txl) (((1 << G_TX_DXT_FRAC) + TXL2WORDS(width, b_txl) - 1) / TXL2WORDS(width, b_txl)) + +#define TXL2WORDS_4b(txls) MAX(1, ((txls) / 16)) +#define CALC_DXT_4b(width) (((1 << G_TX_DXT_FRAC) + TXL2WORDS_4b(width) - 1) / TXL2WORDS_4b(width)) + +#define gDPLoadTileGeneric(pkt, c, tile, uls, ult, lrs, lrt) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(c, 24, 8) | _SHIFTL(uls, 12, 12) | _SHIFTL(ult, 0, 12); \ + _g->words.w1 = _SHIFTL(tile, 24, 3) | _SHIFTL(lrs, 12, 12) | _SHIFTL(lrt, 0, 12); \ + }) + +#define gsDPLoadTileGeneric(c, tile, uls, ult, lrs, lrt) \ + { \ + _SHIFTL(c, 24, 8) | _SHIFTL(uls, 12, 12) | _SHIFTL(ult, 0, 12), \ + _SHIFTL(tile, 24, 3) | _SHIFTL(lrs, 12, 12) | _SHIFTL(lrt, 0, 12) \ + } + +#define gDPSetInterpolation(pkt, index) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = G_SETTARGETINTERPINDEX << 24; \ + _g->words.w1 = index; \ + }) + +#define __gDPSetTileSizeInterp(pkt, t, uls, ult, lrs, lrt) \ + gDPLoadTileGeneric(pkt, G_SETTILESIZE_INTERP, t, uls, ult, lrs, lrt) + +/* + * Tile size interpolated at draw time between two endpoints using the + * interpreter's mInterpolationT (0 = previous game tick, 1 = current tick). + */ +#define __gDPSetTileSizeLerpCoord(g, w, coord) \ + _DW({ \ + float _f = (coord); \ + (g).words.w = *(uint32_t*)&_f; \ + }) + +#define __gDPSetTileSizeLerp(pkt, t, uls0, ult0, lrs0, lrt0, uls1, ult1, lrs1, lrt1) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g[0].words.w0 = _SHIFTL(G_SETTILESIZE_LERP, 24, 8); \ + _g[0].words.w1 = _SHIFTL(t, 24, 3); \ + __gDPSetTileSizeLerpCoord(_g[1], w0, uls0); \ + __gDPSetTileSizeLerpCoord(_g[1], w1, ult0); \ + __gDPSetTileSizeLerpCoord(_g[2], w0, lrs0); \ + __gDPSetTileSizeLerpCoord(_g[2], w1, lrt0); \ + __gDPSetTileSizeLerpCoord(_g[3], w0, uls1); \ + __gDPSetTileSizeLerpCoord(_g[3], w1, ult1); \ + __gDPSetTileSizeLerpCoord(_g[4], w0, lrs1); \ + __gDPSetTileSizeLerpCoord(_g[4], w1, lrt1); \ + }) +#define gDPSetTileSize(pkt, t, uls, ult, lrs, lrt) gDPLoadTileGeneric(pkt, G_SETTILESIZE, t, uls, ult, lrs, lrt) +#define gsDPSetTileSize(t, uls, ult, lrs, lrt) gsDPLoadTileGeneric(G_SETTILESIZE, t, uls, ult, lrs, lrt) +#define gDPLoadTile(pkt, t, uls, ult, lrs, lrt) gDPLoadTileGeneric(pkt, G_LOADTILE, t, uls, ult, lrs, lrt) +#define gsDPLoadTile(t, uls, ult, lrs, lrt) gsDPLoadTileGeneric(G_LOADTILE, t, uls, ult, lrs, lrt) + +#define gDPSetTile(pkt, fmt, siz, line, tmem, tile, palette, cmt, maskt, shiftt, cms, masks, shifts) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_SETTILE, 24, 8) | _SHIFTL(fmt, 21, 3) | _SHIFTL(siz, 19, 2) | _SHIFTL(line, 9, 9) | \ + _SHIFTL(tmem, 0, 9); \ + _g->words.w1 = _SHIFTL(tile, 24, 3) | _SHIFTL(palette, 20, 4) | _SHIFTL(cmt, 18, 2) | _SHIFTL(maskt, 14, 4) | \ + _SHIFTL(shiftt, 10, 4) | _SHIFTL(cms, 8, 2) | _SHIFTL(masks, 4, 4) | _SHIFTL(shifts, 0, 4); \ + }) + +#define gsDPSetTile(fmt, siz, line, tmem, tile, palette, cmt, maskt, shiftt, cms, masks, shifts) \ + { \ + (_SHIFTL(G_SETTILE, 24, 8) | _SHIFTL(fmt, 21, 3) | _SHIFTL(siz, 19, 2) | _SHIFTL(line, 9, 9) | \ + _SHIFTL(tmem, 0, 9)), \ + (_SHIFTL(tile, 24, 3) | _SHIFTL(palette, 20, 4) | _SHIFTL(cmt, 18, 2) | _SHIFTL(maskt, 14, 4) | \ + _SHIFTL(shiftt, 10, 4) | _SHIFTL(cms, 8, 2) | _SHIFTL(masks, 4, 4) | _SHIFTL(shifts, 0, 4)) \ + } + +/* + * For RCP 2.0, the maximum number of texels that can be loaded + * using a load_block command is 2048. In order to load the total + * 4kB of Tmem, change the texel size when loading to be G_IM_SIZ_16b, + * then change the tile to the proper texel size after the load. + * The g*DPLoadTextureBlock macros already do this, so this change + * will be transparent if you use these macros. If you use + * the g*DPLoadBlock macros directly, you will need to handle this + * tile manipulation yourself. RJM. + */ +#define gDPLoadBlock(pkt, tile, uls, ult, lrs, dxt) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_LOADBLOCK, 24, 8) | _SHIFTL(uls, 12, 12) | _SHIFTL(ult, 0, 12)); \ + _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL((MIN(lrs, G_TX_LDBLK_MAX_TXL)), 12, 12) | _SHIFTL(dxt, 0, 12)); \ + }) + +#define gsDPLoadBlock(tile, uls, ult, lrs, dxt) \ + { \ + (_SHIFTL(G_LOADBLOCK, 24, 8) | _SHIFTL(uls, 12, 12) | _SHIFTL(ult, 0, 12)), \ + (_SHIFTL(tile, 24, 3) | _SHIFTL((MIN(lrs, G_TX_LDBLK_MAX_TXL)), 12, 12) | _SHIFTL(dxt, 0, 12)) \ + } + +#define gDPLoadBlockWide(pkt, tile, uls, ult, lrs, dxt) \ + { \ + Gfx* _g0 = (Gfx*)(pkt); \ + Gfx* _g1 = (Gfx*)(pkt) + 1; \ + _g0->words.w0 = _SHIFTL(G_LOADBLOCK_WIDE, 24, 8) | _SHIFTL((tile), 0, 3); \ + _g0->words.w1 = (uint32_t)(lrs); \ + _g1->words.w0 = _SHIFTL((uls), 16, 16) | _SHIFTL((ult), 0, 16); \ + _g1->words.w1 = _SHIFTL((dxt), 0, 12); \ + } + +#define gsDPLoadBlockWide(tile, uls, ult, lrs, dxt) \ + { _SHIFTL(G_LOADBLOCK_WIDE, 24, 8) | _SHIFTL((tile), 0, 3), (uint32_t)(lrs) }, { \ + _SHIFTL((uls), 16, 16) | _SHIFTL((ult), 0, 16), _SHIFTL((dxt), 0, 12) \ + } + +#define gDPLoadTLUTCmd(pkt, tile, count) \ + _DW({ \ + Gfx* _g = (Gfx*)pkt; \ + \ + _g->words.w0 = _SHIFTL(G_LOADTLUT, 24, 8); \ + _g->words.w1 = _SHIFTL((tile), 24, 3) | _SHIFTL((count), 14, 10); \ + }) + +#define gsDPLoadTLUTCmd(tile, count) \ + { _SHIFTL(G_LOADTLUT, 24, 8), _SHIFTL((tile), 24, 3) | _SHIFTL((count), 14, 10) } + +#define gDPLoadTextureBlock(pkt, timg, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + _DW({ \ + gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \ + gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, (((width) * (height) + siz##_INCR) >> siz##_SHIFT) - 1, \ + CALC_DXT(width, siz##_BYTES)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, siz, (((width)*siz##_LINE_BYTES) + 7) >> 3, 0, G_TX_RENDERTILE, pal, cmt, maskt, shiftt, \ + cms, masks, shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC); \ + }) + +#define gDPLoadTextureBlockYuv(pkt, timg, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + _DW({ \ + gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \ + gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, (((width) * (height) + siz##_INCR) >> siz##_SHIFT) - 1, \ + CALC_DXT(width, siz##_BYTES)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, siz, (((width)*1) + 7) >> 3, 0, G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \ + shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC); \ + }) + +/* Load fix rww 27jun95 */ +/* The S at the end means odd lines are already word Swapped */ + +#define gDPLoadTextureBlockS(pkt, timg, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + _DW({ \ + gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \ + gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, (((width) * (height) + siz##_INCR) >> siz##_SHIFT) - 1, 0); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, siz, (((width)*siz##_LINE_BYTES) + 7) >> 3, 0, G_TX_RENDERTILE, pal, cmt, maskt, shiftt, \ + cms, masks, shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC); \ + }) + +/* + * Allow tmem address and render tile to be specified. + * The S at the end means odd lines are already word Swapped + */ +#define gDPLoadMultiBlockS(pkt, timg, tmem, rtile, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, \ + shiftt) \ + _DW({ \ + gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \ + gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, (((width) * (height) + siz##_INCR) >> siz##_SHIFT) - 1, 0); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, siz, (((width)*siz##_LINE_BYTES) + 7) >> 3, tmem, rtile, pal, cmt, maskt, shiftt, cms, \ + masks, shifts); \ + gDPSetTileSize(pkt, rtile, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, ((height)-1) << G_TEXTURE_IMAGE_FRAC); \ + }) + +#define gDPLoadTextureBlockYuvS(pkt, timg, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + _DW({ \ + gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \ + gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, (((width) * (height) + siz##_INCR) >> siz##_SHIFT) - 1, 0); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, siz, (((width)*1) + 7) >> 3, 0, G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, masks, \ + shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC); \ + }) + +/* + * allows tmem address to be specified + */ +#define _gDPLoadTextureBlock(pkt, timg, tmem, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + _DW({ \ + gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \ + gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, (((width) * (height) + siz##_INCR) >> siz##_SHIFT) - 1, \ + CALC_DXT(width, siz##_BYTES)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, siz, (((width)*siz##_LINE_BYTES) + 7) >> 3, tmem, G_TX_RENDERTILE, pal, cmt, maskt, \ + shiftt, cms, masks, shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC); \ + }) + +/* + * allows tmem address and render tile to be specified + */ +#define _gDPLoadTextureBlockTile(pkt, timg, tmem, rtile, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, \ + shiftt) \ + _DW({ \ + gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \ + gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, (((width) * (height) + siz##_INCR) >> siz##_SHIFT) - 1, \ + CALC_DXT(width, siz##_BYTES)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, siz, (((width)*siz##_LINE_BYTES) + 7) >> 3, tmem, rtile, pal, cmt, maskt, shiftt, cms, \ + masks, shifts); \ + gDPSetTileSize(pkt, rtile, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, ((height)-1) << G_TEXTURE_IMAGE_FRAC); \ + }) + +/* + * allows tmem address and render tile to be specified + */ +#define gDPLoadMultiBlock(pkt, timg, tmem, rtile, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, \ + shiftt) \ + _DW({ \ + gDPSetTextureImage(pkt, fmt, siz##_LOAD_BLOCK, 1, timg); \ + gDPSetTile(pkt, fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, (((width) * (height) + siz##_INCR) >> siz##_SHIFT) - 1, \ + CALC_DXT(width, siz##_BYTES)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, siz, (((width)*siz##_LINE_BYTES) + 7) >> 3, tmem, rtile, pal, cmt, maskt, shiftt, cms, \ + masks, shifts); \ + gDPSetTileSize(pkt, rtile, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, ((height)-1) << G_TEXTURE_IMAGE_FRAC); \ + }) + +#define gsDPLoadTextureBlock(timg, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \ + gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width) * (height) + siz##_INCR) >> siz##_SHIFT) - 1, \ + CALC_DXT(width, siz##_BYTES)), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, siz, ((((width)*siz##_LINE_BYTES) + 7) >> 3), 0, G_TX_RENDERTILE, pal, cmt, maskt, shiftt, \ + cms, masks, shifts), \ + gsDPSetTileSize(G_TX_RENDERTILE, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) + +/* Here is the static form of the pre-swapped texture block loading */ +/* See gDPLoadTextureBlockS() for reference. Basically, just don't + calculate DxT, use 0 */ + +#define gsDPLoadTextureBlockS(timg, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \ + gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width) * (height) + siz##_INCR) >> siz##_SHIFT) - 1, 0), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, siz, ((((width)*siz##_LINE_BYTES) + 7) >> 3), 0, G_TX_RENDERTILE, pal, cmt, maskt, shiftt, \ + cms, masks, shifts), \ + gsDPSetTileSize(G_TX_RENDERTILE, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) + +/* + * Allow tmem address to be specified + */ +#define _gsDPLoadTextureBlock(timg, tmem, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \ + gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width) * (height) + siz##_INCR) >> siz##_SHIFT) - 1, \ + CALC_DXT(width, siz##_BYTES)), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, siz, ((((width)*siz##_LINE_BYTES) + 7) >> 3), tmem, G_TX_RENDERTILE, pal, cmt, maskt, shiftt, \ + cms, masks, shifts), \ + gsDPSetTileSize(G_TX_RENDERTILE, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) + +/* + * Allow tmem address and render_tile to be specified + */ +#define _gsDPLoadTextureBlockTile(timg, tmem, rtile, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, \ + shiftt) \ + \ + gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \ + gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width) * (height) + siz##_INCR) >> siz##_SHIFT) - 1, \ + CALC_DXT(width, siz##_BYTES)), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, siz, ((((width)*siz##_LINE_BYTES) + 7) >> 3), tmem, rtile, pal, cmt, maskt, shiftt, cms, \ + masks, shifts), \ + gsDPSetTileSize(rtile, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, ((height)-1) << G_TEXTURE_IMAGE_FRAC) + +/* + * Allow tmem address and render_tile to be specified, useful when loading + * mutilple tiles at a time. + */ +#define gsDPLoadMultiBlock(timg, tmem, rtile, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \ + gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width) * (height) + siz##_INCR) >> siz##_SHIFT) - 1, \ + CALC_DXT(width, siz##_BYTES)), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, siz, ((((width)*siz##_LINE_BYTES) + 7) >> 3), tmem, rtile, pal, cmt, maskt, shiftt, cms, \ + masks, shifts), \ + gsDPSetTileSize(rtile, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, ((height)-1) << G_TEXTURE_IMAGE_FRAC) + +/* + * Allows tmem and render tile to be specified. Useful when loading + * several tiles at a time. + * + * Here is the static form of the pre-swapped texture block loading + * See gDPLoadTextureBlockS() for reference. Basically, just don't + * calculate DxT, use 0 + */ + +#define gsDPLoadMultiBlockS(timg, tmem, rtile, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, siz##_LOAD_BLOCK, 1, timg), \ + gsDPSetTile(fmt, siz##_LOAD_BLOCK, 0, tmem, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width) * (height) + siz##_INCR) >> siz##_SHIFT) - 1, 0), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, siz, ((((width)*siz##_LINE_BYTES) + 7) >> 3), tmem, rtile, pal, cmt, maskt, shiftt, cms, \ + masks, shifts), \ + gsDPSetTileSize(rtile, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, ((height)-1) << G_TEXTURE_IMAGE_FRAC) + +#define gDPLoadTextureBlock_4b(pkt, timg, fmt, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + _DW({ \ + gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, (((width) * (height) + 3) >> 2) - 1, CALC_DXT_4b(width)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width) >> 1) + 7) >> 3), 0, G_TX_RENDERTILE, pal, cmt, maskt, shiftt, \ + cms, masks, shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC); \ + }) + +/* Load fix rww 27jun95 */ +/* The S at the end means odd lines are already word Swapped */ + +#define gDPLoadTextureBlock_4bS(pkt, timg, fmt, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + _DW({ \ + gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, (((width) * (height) + 3) >> 2) - 1, 0); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width) >> 1) + 7) >> 3), 0, G_TX_RENDERTILE, pal, cmt, maskt, shiftt, \ + cms, masks, shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC); \ + }) + +/* + * 4-bit load block. Useful when loading multiple tiles + */ +#define gDPLoadMultiBlock_4b(pkt, timg, tmem, rtile, fmt, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + _DW({ \ + gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, (((width) * (height) + 3) >> 2) - 1, CALC_DXT_4b(width)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width) >> 1) + 7) >> 3), tmem, rtile, pal, cmt, maskt, shiftt, cms, \ + masks, shifts); \ + gDPSetTileSize(pkt, rtile, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, ((height)-1) << G_TEXTURE_IMAGE_FRAC); \ + }) + +/* + * 4-bit load block. Allows tmem and render tile to be specified. Useful when + * loading multiple tiles. The S means odd lines are already word swapped. + */ +#define gDPLoadMultiBlock_4bS(pkt, timg, tmem, rtile, fmt, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + _DW({ \ + gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, (((width) * (height) + 3) >> 2) - 1, 0); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width) >> 1) + 7) >> 3), tmem, rtile, pal, cmt, maskt, shiftt, cms, \ + masks, shifts); \ + gDPSetTileSize(pkt, rtile, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, ((height)-1) << G_TEXTURE_IMAGE_FRAC); \ + }) + +#define _gDPLoadTextureBlock_4b(pkt, timg, tmem, fmt, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + _DW({ \ + gDPSetTextureImage(pkt, fmt, G_IM_SIZ_16b, 1, timg); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadBlock(pkt, G_TX_LOADTILE, 0, 0, (((width) * (height) + 3) >> 2) - 1, CALC_DXT_4b(width)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_4b, ((((width) >> 1) + 7) >> 3), tmem, G_TX_RENDERTILE, pal, cmt, maskt, shiftt, \ + cms, masks, shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC); \ + }) + +#define gsDPLoadTextureBlock_4b(timg, fmt, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg), \ + gsDPSetTile(fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width) * (height) + 3) >> 2) - 1, CALC_DXT_4b(width)), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width) >> 1) + 7) >> 3), 0, G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, \ + masks, shifts), \ + gsDPSetTileSize(G_TX_RENDERTILE, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) + +#define gsDPLoadTextureBlock_4bS(timg, fmt, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg), \ + gsDPSetTile(fmt, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width) * (height) + 3) >> 2) - 1, 0), gsDPPipeSync(), \ + gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width) >> 1) + 7) >> 3), 0, G_TX_RENDERTILE, pal, cmt, maskt, shiftt, cms, \ + masks, shifts), \ + gsDPSetTileSize(G_TX_RENDERTILE, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) + +/* + * 4-bit load block. Allows tmem address and render tile to be specified. + * Useful when loading multiple tiles. + */ +#define gsDPLoadMultiBlock_4b(timg, tmem, rtile, fmt, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg), \ + gsDPSetTile(fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width) * (height) + 3) >> 2) - 1, CALC_DXT_4b(width)), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width) >> 1) + 7) >> 3), tmem, rtile, pal, cmt, maskt, shiftt, cms, masks, \ + shifts), \ + gsDPSetTileSize(rtile, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, ((height)-1) << G_TEXTURE_IMAGE_FRAC) + +/* + * 4-bit load block. Allows tmem address and render tile to be specified. + * Useful when loading multiple tiles. S means odd lines are already swapped. + */ +#define gsDPLoadMultiBlock_4bS(timg, tmem, rtile, fmt, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg), \ + gsDPSetTile(fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width) * (height) + 3) >> 2) - 1, 0), gsDPPipeSync(), \ + gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width) >> 1) + 7) >> 3), tmem, rtile, pal, cmt, maskt, shiftt, cms, masks, \ + shifts), \ + gsDPSetTileSize(rtile, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, ((height)-1) << G_TEXTURE_IMAGE_FRAC) + +/* + * Allows tmem address to be specified + */ +#define _gsDPLoadTextureBlock_4b(timg, tmem, fmt, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, G_IM_SIZ_16b, 1, timg), \ + gsDPSetTile(fmt, G_IM_SIZ_16b, 0, tmem, G_TX_LOADTILE, 0, cmt, maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), gsDPLoadBlock(G_TX_LOADTILE, 0, 0, (((width) * (height) + 3) >> 2) - 1, CALC_DXT_4b(width)), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, G_IM_SIZ_4b, ((((width) >> 1) + 7) >> 3), tmem, G_TX_RENDERTILE, pal, cmt, maskt, shiftt, \ + cms, masks, shifts), \ + gsDPSetTileSize(G_TX_RENDERTILE, 0, 0, ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ + ((height)-1) << G_TEXTURE_IMAGE_FRAC) + +#ifndef _HW_VERSION_1 + +#define gDPLoadTextureTile(pkt, timg, fmt, siz, width, height, uls, ult, lrs, lrt, pal, cms, cmt, masks, maskt, \ + shifts, shiftt) \ + _DW({ \ + gDPSetTextureImage(pkt, fmt, siz, width, timg); \ + gDPSetTile(pkt, fmt, siz, (((((lrs) - (uls) + 1) * siz##_TILE_BYTES) + 7) >> 3), 0, G_TX_LOADTILE, 0, cmt, \ + maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadTile(pkt, G_TX_LOADTILE, (uls) << G_TEXTURE_IMAGE_FRAC, (ult) << G_TEXTURE_IMAGE_FRAC, \ + (lrs) << G_TEXTURE_IMAGE_FRAC, (lrt) << G_TEXTURE_IMAGE_FRAC); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, siz, (((((lrs) - (uls) + 1) * siz##_LINE_BYTES) + 7) >> 3), 0, G_TX_RENDERTILE, pal, cmt, \ + maskt, shiftt, cms, masks, shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, (uls) << G_TEXTURE_IMAGE_FRAC, (ult) << G_TEXTURE_IMAGE_FRAC, \ + (lrs) << G_TEXTURE_IMAGE_FRAC, (lrt) << G_TEXTURE_IMAGE_FRAC); \ + }) + +#else /******** WORKAROUND hw 1 load tile bug ********/ + +#define gDPLoadTextureTile(pkt, timg, fmt, siz, width, height, uls, ult, lrs, lrt, pal, cms, cmt, masks, maskt, \ + shifts, shiftt) \ + \ + { \ + int _loadtile_i, _loadtile_nw; \ + Gfx* _loadtile_temp = pkt; \ + guDPLoadTextureTile(_loadtile_temp, timg, fmt, siz, width, height, uls, ult, lrs, lrt, pal, cms, cmt, masks, \ + maskt, shifts, shiftt); \ + _loadtile_nw = guGetDPLoadTextureTileSz(ult, lrt) - 1; \ + for (_loadtile_i = 0; _loadtile_i < _loadtile_nw; _loadtile_i++) \ + pkt; \ + } + +#endif /* HW_VERSION_1 */ + +/* + * Load texture tile. Allows tmem address and render tile to be specified. + * Useful for loading multiple tiles. + */ +#define gDPLoadMultiTile(pkt, timg, tmem, rtile, fmt, siz, width, height, uls, ult, lrs, lrt, pal, cms, cmt, masks, \ + maskt, shifts, shiftt) \ + _DW({ \ + gDPSetTextureImage(pkt, fmt, siz, width, timg); \ + gDPSetTile(pkt, fmt, siz, (((((lrs) - (uls) + 1) * siz##_TILE_BYTES) + 7) >> 3), tmem, G_TX_LOADTILE, 0, cmt, \ + maskt, shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadTile(pkt, G_TX_LOADTILE, (uls) << G_TEXTURE_IMAGE_FRAC, (ult) << G_TEXTURE_IMAGE_FRAC, \ + (lrs) << G_TEXTURE_IMAGE_FRAC, (lrt) << G_TEXTURE_IMAGE_FRAC); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, siz, (((((lrs) - (uls) + 1) * siz##_LINE_BYTES) + 7) >> 3), tmem, rtile, pal, cmt, maskt, \ + shiftt, cms, masks, shifts); \ + gDPSetTileSize(pkt, rtile, (uls) << G_TEXTURE_IMAGE_FRAC, (ult) << G_TEXTURE_IMAGE_FRAC, \ + (lrs) << G_TEXTURE_IMAGE_FRAC, (lrt) << G_TEXTURE_IMAGE_FRAC); \ + }) + +#define gsDPLoadTextureTile(timg, fmt, siz, width, height, uls, ult, lrs, lrt, pal, cms, cmt, masks, maskt, shifts, \ + shiftt) \ + \ + gsDPSetTextureImage(fmt, siz, width, timg), \ + gsDPSetTile(fmt, siz, (((((lrs) - (uls) + 1) * siz##_TILE_BYTES) + 7) >> 3), 0, G_TX_LOADTILE, 0, cmt, maskt, \ + shiftt, cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadTile(G_TX_LOADTILE, (uls) << G_TEXTURE_IMAGE_FRAC, (ult) << G_TEXTURE_IMAGE_FRAC, \ + (lrs) << G_TEXTURE_IMAGE_FRAC, (lrt) << G_TEXTURE_IMAGE_FRAC), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, siz, (((((lrs) - (uls) + 1) * siz##_LINE_BYTES) + 7) >> 3), 0, G_TX_RENDERTILE, pal, cmt, \ + maskt, shiftt, cms, masks, shifts), \ + gsDPSetTileSize(G_TX_RENDERTILE, (uls) << G_TEXTURE_IMAGE_FRAC, (ult) << G_TEXTURE_IMAGE_FRAC, \ + (lrs) << G_TEXTURE_IMAGE_FRAC, (lrt) << G_TEXTURE_IMAGE_FRAC) + +/* + * Load texture tile. Allows tmem address and render tile to be specified. + * Useful for loading multiple tiles. + */ +#define gsDPLoadMultiTile(timg, tmem, rtile, fmt, siz, width, height, uls, ult, lrs, lrt, pal, cms, cmt, masks, maskt, \ + shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, siz, width, timg), \ + gsDPSetTile(fmt, siz, (((((lrs) - (uls) + 1) * siz##_TILE_BYTES) + 7) >> 3), tmem, G_TX_LOADTILE, 0, cmt, \ + maskt, shiftt, cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadTile(G_TX_LOADTILE, (uls) << G_TEXTURE_IMAGE_FRAC, (ult) << G_TEXTURE_IMAGE_FRAC, \ + (lrs) << G_TEXTURE_IMAGE_FRAC, (lrt) << G_TEXTURE_IMAGE_FRAC), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, siz, (((((lrs) - (uls) + 1) * siz##_LINE_BYTES) + 7) >> 3), tmem, rtile, pal, cmt, maskt, \ + shiftt, cms, masks, shifts), \ + gsDPSetTileSize(rtile, (uls) << G_TEXTURE_IMAGE_FRAC, (ult) << G_TEXTURE_IMAGE_FRAC, \ + (lrs) << G_TEXTURE_IMAGE_FRAC, (lrt) << G_TEXTURE_IMAGE_FRAC) + +#define gDPLoadTextureTile_4b(pkt, timg, fmt, width, height, uls, ult, lrs, lrt, pal, cms, cmt, masks, maskt, shifts, \ + shiftt) \ + _DW({ \ + gDPSetTextureImage(pkt, fmt, G_IM_SIZ_8b, ((width) >> 1), timg); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_8b, (((((lrs) - (uls) + 1) >> 1) + 7) >> 3), 0, G_TX_LOADTILE, 0, cmt, maskt, \ + shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadTile(pkt, G_TX_LOADTILE, (uls) << (G_TEXTURE_IMAGE_FRAC - 1), (ult) << (G_TEXTURE_IMAGE_FRAC), \ + (lrs) << (G_TEXTURE_IMAGE_FRAC - 1), (lrt) << (G_TEXTURE_IMAGE_FRAC)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_4b, (((((lrs) - (uls) + 1) >> 1) + 7) >> 3), 0, G_TX_RENDERTILE, pal, cmt, \ + maskt, shiftt, cms, masks, shifts); \ + gDPSetTileSize(pkt, G_TX_RENDERTILE, (uls) << G_TEXTURE_IMAGE_FRAC, (ult) << G_TEXTURE_IMAGE_FRAC, \ + (lrs) << G_TEXTURE_IMAGE_FRAC, (lrt) << G_TEXTURE_IMAGE_FRAC); \ + }) + +/* + * Load texture tile. Allows tmem address and render tile to be specified. + * Useful for loading multiple tiles. + */ +#define gDPLoadMultiTile_4b(pkt, timg, tmem, rtile, fmt, width, height, uls, ult, lrs, lrt, pal, cms, cmt, masks, \ + maskt, shifts, shiftt) \ + _DW({ \ + gDPSetTextureImage(pkt, fmt, G_IM_SIZ_8b, ((width) >> 1), timg); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_8b, (((((lrs) - (uls) + 1) >> 1) + 7) >> 3), tmem, G_TX_LOADTILE, 0, cmt, maskt, \ + shiftt, cms, masks, shifts); \ + gDPLoadSync(pkt); \ + gDPLoadTile(pkt, G_TX_LOADTILE, (uls) << (G_TEXTURE_IMAGE_FRAC - 1), (ult) << (G_TEXTURE_IMAGE_FRAC), \ + (lrs) << (G_TEXTURE_IMAGE_FRAC - 1), (lrt) << (G_TEXTURE_IMAGE_FRAC)); \ + gDPPipeSync(pkt); \ + gDPSetTile(pkt, fmt, G_IM_SIZ_4b, (((((lrs) - (uls) + 1) >> 1) + 7) >> 3), tmem, rtile, pal, cmt, maskt, \ + shiftt, cms, masks, shifts); \ + gDPSetTileSize(pkt, rtile, (uls) << G_TEXTURE_IMAGE_FRAC, (ult) << G_TEXTURE_IMAGE_FRAC, \ + (lrs) << G_TEXTURE_IMAGE_FRAC, (lrt) << G_TEXTURE_IMAGE_FRAC); \ + }) + +#define gsDPLoadTextureTile_4b(timg, fmt, width, height, uls, ult, lrs, lrt, pal, cms, cmt, masks, maskt, shifts, \ + shiftt) \ + \ + gsDPSetTextureImage(fmt, G_IM_SIZ_8b, ((width) >> 1), timg), \ + gsDPSetTile(fmt, G_IM_SIZ_8b, (((((lrs) - (uls) + 1) >> 1) + 7) >> 3), 0, G_TX_LOADTILE, 0, cmt, maskt, \ + shiftt, cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadTile(G_TX_LOADTILE, (uls) << (G_TEXTURE_IMAGE_FRAC - 1), (ult) << (G_TEXTURE_IMAGE_FRAC), \ + (lrs) << (G_TEXTURE_IMAGE_FRAC - 1), (lrt) << (G_TEXTURE_IMAGE_FRAC)), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, G_IM_SIZ_4b, (((((lrs) - (uls) + 1) >> 1) + 7) >> 3), 0, G_TX_RENDERTILE, pal, cmt, maskt, \ + shiftt, cms, masks, shifts), \ + gsDPSetTileSize(G_TX_RENDERTILE, (uls) << G_TEXTURE_IMAGE_FRAC, (ult) << G_TEXTURE_IMAGE_FRAC, \ + (lrs) << G_TEXTURE_IMAGE_FRAC, (lrt) << G_TEXTURE_IMAGE_FRAC) + +/* + * Load texture tile. Allows tmem address and render tile to be specified. + * Useful for loading multiple tiles. + */ +#define gsDPLoadMultiTile_4b(timg, tmem, rtile, fmt, width, height, uls, ult, lrs, lrt, pal, cms, cmt, masks, maskt, \ + shifts, shiftt) \ + \ + gsDPSetTextureImage(fmt, G_IM_SIZ_8b, ((width) >> 1), timg), \ + gsDPSetTile(fmt, G_IM_SIZ_8b, (((((lrs) - (uls) + 1) >> 1) + 7) >> 3), tmem, G_TX_LOADTILE, 0, cmt, maskt, \ + shiftt, cms, masks, shifts), \ + gsDPLoadSync(), \ + gsDPLoadTile(G_TX_LOADTILE, (uls) << (G_TEXTURE_IMAGE_FRAC - 1), (ult) << (G_TEXTURE_IMAGE_FRAC), \ + (lrs) << (G_TEXTURE_IMAGE_FRAC - 1), (lrt) << (G_TEXTURE_IMAGE_FRAC)), \ + gsDPPipeSync(), \ + gsDPSetTile(fmt, G_IM_SIZ_4b, (((((lrs) - (uls) + 1) >> 1) + 7) >> 3), tmem, rtile, pal, cmt, maskt, shiftt, \ + cms, masks, shifts), \ + gsDPSetTileSize(rtile, (uls) << G_TEXTURE_IMAGE_FRAC, (ult) << G_TEXTURE_IMAGE_FRAC, \ + (lrs) << G_TEXTURE_IMAGE_FRAC, (lrt) << G_TEXTURE_IMAGE_FRAC) + +/* + * Load a 16-entry palette (for 4-bit CI textures) + * Assumes a 16 entry tlut is being loaded, palette # is 0-15 + */ +#ifndef _HW_VERSION_1 + +#define gDPLoadTLUT_pal16(pkt, pal, dram) \ + _DW({ \ + gDPSetTextureImage(pkt, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram); \ + gDPTileSync(pkt); \ + gDPSetTile(pkt, 0, 0, 0, (256 + (((pal)&0xf) * 16)), G_TX_LOADTILE, 0, 0, 0, 0, 0, 0, 0); \ + gDPLoadSync(pkt); \ + gDPLoadTLUTCmd(pkt, G_TX_LOADTILE, 15); \ + gDPPipeSync(pkt); \ + }) + +#else /* **** WORKAROUND hardware 1 load_tlut bug ****** */ + +#define gDPLoadTLUT_pal16(pkt, pal, dram) \ + \ + _gDPLoadTextureBlock(pkt, dram, (256 + (((pal)&0xf) * 16)), G_IM_FMT_RGBA, G_IM_SIZ_16b, 4 * 16, 1, pal, 0, 0, 0, \ + 0, 0, 0) + +#endif /* _HW_VERSION_1 */ + +/* + * Load a 16-entry palette (for 4-bit CI textures) + * Assumes a 16 entry tlut is being loaded, palette # is 0-15 + */ +#ifndef _HW_VERSION_1 + +#define gsDPLoadTLUT_pal16(pal, dram) \ + \ + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram), gsDPTileSync(), \ + gsDPSetTile(0, 0, 0, (256 + (((pal)&0xf) * 16)), G_TX_LOADTILE, 0, 0, 0, 0, 0, 0, 0), gsDPLoadSync(), \ + gsDPLoadTLUTCmd(G_TX_LOADTILE, 15), gsDPPipeSync() + +#else /* **** WORKAROUND hardware 1 load_tlut bug ****** */ + +#define gsDPLoadTLUT_pal16(pal, dram) \ + \ + _gsDPLoadTextureBlock(dram, (256 + (((pal)&0xf) * 16)), G_IM_FMT_RGBA, G_IM_SIZ_16b, 4 * 16, 1, pal, 0, 0, 0, 0, \ + 0, 0) + +#endif /* _HW_VERSION_1 */ + +/* + * Load a 256-entry palette (for 8-bit CI textures) + * Assumes a 256 entry tlut is being loaded, palette # is not used + */ +#ifndef _HW_VERSION_1 + +#define gDPLoadTLUT_pal256(pkt, dram) \ + _DW({ \ + gDPSetTextureImage(pkt, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram); \ + gDPTileSync(pkt); \ + gDPSetTile(pkt, 0, 0, 0, 256, G_TX_LOADTILE, 0, 0, 0, 0, 0, 0, 0); \ + gDPLoadSync(pkt); \ + gDPLoadTLUTCmd(pkt, G_TX_LOADTILE, 255); \ + gDPPipeSync(pkt); \ + }) + +#define gDPLoadTLUT_pal128(pkt, pal, dram) \ + _DW({ \ + gDPSetTextureImage(pkt, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram); \ + gDPTileSync(pkt); \ + gDPSetTile(pkt, 0, 0, 0, 256 + ((pal)&1) * 128, G_TX_LOADTILE, 0, 0, 0, 0, 0, 0, 0); \ + gDPLoadSync(pkt); \ + gDPLoadTLUTCmd(pkt, G_TX_LOADTILE, 127); \ + gDPPipeSync(pkt); \ + }) + +#else /* **** WORKAROUND hardware 1 load_tlut bug ****** */ + +#define gDPLoadTLUT_pal256(pkt, dram) \ + \ + _gDPLoadTextureBlock(pkt, dram, 256, G_IM_FMT_RGBA, G_IM_SIZ_16b, 4 * 256, 1, 0, 0, 0, 0, 0, 0, 0) + +#endif /* _HW_VERSION_1 */ + +#ifndef _HW_VERSION_1 + +#define gsDPLoadTLUT_pal256(dram) \ + \ + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram), gsDPTileSync(), \ + gsDPSetTile(0, 0, 0, 256, G_TX_LOADTILE, 0, 0, 0, 0, 0, 0, 0), gsDPLoadSync(), \ + gsDPLoadTLUTCmd(G_TX_LOADTILE, 255), gsDPPipeSync() + +#else /* **** WORKAROUND hardware 1 load_tlut bug ****** */ + +#define gsDPLoadTLUT_pal256(dram) \ + \ + _gsDPLoadTextureBlock(dram, 256, G_IM_FMT_RGBA, G_IM_SIZ_16b, 4 * 256, 1, 0, 0, 0, 0, 0, 0, 0) + +#endif /* _HW_VERSION_1 */ + +#ifndef _HW_VERSION_1 + +#define gDPLoadTLUT(pkt, count, tmemaddr, dram) \ + _DW({ \ + gDPSetTextureImage(pkt, G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram); \ + gDPTileSync(pkt); \ + gDPSetTile(pkt, 0, 0, 0, tmemaddr, G_TX_LOADTILE, 0, 0, 0, 0, 0, 0, 0); \ + gDPLoadSync(pkt); \ + gDPLoadTLUTCmd(pkt, G_TX_LOADTILE, ((count)-1)); \ + gDPPipeSync(pkt); \ + }) + +#else /* **** WORKAROUND hardware 1 load_tlut bug ****** */ + +#define gDPLoadTLUT(pkt, count, tmemaddr, dram) \ + \ + _gDPLoadTextureBlock(pkt, dram, tmemaddr, G_IM_FMT_RGBA, G_IM_SIZ_16b, 4, count, 0, 0, 0, 0, 0, 0, 0) + +#endif /* _HW_VERSION_1 */ + +#ifndef _HW_VERSION_1 + +#define gsDPLoadTLUT(count, tmemaddr, dram) \ + \ + gsDPSetTextureImage(G_IM_FMT_RGBA, G_IM_SIZ_16b, 1, dram), gsDPTileSync(), \ + gsDPSetTile(0, 0, 0, tmemaddr, G_TX_LOADTILE, 0, 0, 0, 0, 0, 0, 0), gsDPLoadSync(), \ + gsDPLoadTLUTCmd(G_TX_LOADTILE, ((count)-1)), gsDPPipeSync() + +#else /* **** WORKAROUND hardware 1 load_tlut bug ****** */ +#define gsDPLoadTLUT(count, tmemaddr, dram) \ + \ + _gsDPLoadTextureBlock(dram, tmemaddr, G_IM_FMT_RGBA, G_IM_SIZ_16b, 4, count, 0, 0, 0, 0, 0, 0, 0) + +#endif /* _HW_VERSION_1 */ + +#define gDPSetScissor(pkt, mode, ulx, uly, lrx, lry) \ + _DW({ \ + Gfx* _g = (Gfx*)pkt; \ + \ + _g->words.w0 = _SHIFTL(G_SETSCISSOR, 24, 8) | _SHIFTL((int)((float)(ulx)*4.0F), 12, 12) | \ + _SHIFTL((int)((float)(uly)*4.0F), 0, 12); \ + _g->words.w1 = _SHIFTL(mode, 24, 2) | _SHIFTL((int)((float)(lrx)*4.0F), 12, 12) | \ + _SHIFTL((int)((float)(lry)*4.0F), 0, 12); \ + }) + +#define gDPSetScissorFrac(pkt, mode, ulx, uly, lrx, lry) \ + _DW({ \ + Gfx* _g = (Gfx*)pkt; \ + \ + _g->words.w0 = _SHIFTL(G_SETSCISSOR, 24, 8) | _SHIFTL((int)((ulx)), 12, 12) | _SHIFTL((int)((uly)), 0, 12); \ + _g->words.w1 = _SHIFTL(mode, 24, 2) | _SHIFTL((int)((lrx)), 12, 12) | _SHIFTL((int)((lry)), 0, 12); \ + }) + +#define gsDPSetScissor(mode, ulx, uly, lrx, lry) \ + { \ + _SHIFTL(G_SETSCISSOR, 24, 8) | _SHIFTL((int)((float)(ulx)*4.0F), 12, 12) | \ + _SHIFTL((int)((float)(uly)*4.0F), 0, 12), \ + _SHIFTL(mode, 24, 2) | _SHIFTL((int)((float)(lrx)*4.0F), 12, 12) | \ + _SHIFTL((int)((float)(lry)*4.0F), 0, 12) \ + } + +#define gsDPSetScissorFrac(mode, ulx, uly, lrx, lry) \ + { \ + _SHIFTL(G_SETSCISSOR, 24, 8) | _SHIFTL((int)((ulx)), 12, 12) | _SHIFTL((int)((uly)), 0, 12), \ + _SHIFTL(mode, 24, 2) | _SHIFTL((int)(lrx), 12, 12) | _SHIFTL((int)(lry), 0, 12) \ + } + +#define gDPFillWideRectangle(pkt, ulx, uly, lrx, lry) \ + { \ + Gfx *_g0 = (Gfx*)(pkt), *_g1 = (Gfx*)(pkt); \ + _g0->words.w0 = _SHIFTL(G_FILLWIDERECT, 24, 8) | _SHIFTL((lrx), 2, 22); \ + _g0->words.w1 = _SHIFTL((lry), 2, 22); \ + _g1->words.w0 = _SHIFTL((ulx), 2, 22); \ + _g1->words.w1 = _SHIFTL((uly), 2, 22); \ + } + +/* Fraction never used in fill */ +#define gDPFillRectangle(pkt, ulx, uly, lrx, lry) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_FILLRECT, 24, 8) | _SHIFTL((lrx), 14, 10) | _SHIFTL((lry), 2, 10)); \ + _g->words.w1 = (_SHIFTL((ulx), 14, 10) | _SHIFTL((uly), 2, 10)); \ + }) + +#define gsDPFillRectangle(ulx, uly, lrx, lry) \ + { \ + (_SHIFTL(G_FILLRECT, 24, 8) | _SHIFTL((lrx), 14, 10) | _SHIFTL((lry), 2, 10)), \ + (_SHIFTL((ulx), 14, 10) | _SHIFTL((uly), 2, 10)) \ + } + +/* like gDPFillRectangle but accepts negative arguments */ +#define gDPScisFillRectangle(pkt, ulx, uly, lrx, lry) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_FILLRECT, 24, 8) | _SHIFTL(MAX((lrx), 0), 14, 10) | _SHIFTL(MAX((lry), 0), 2, 10)); \ + _g->words.w1 = (_SHIFTL(MAX((ulx), 0), 14, 10) | _SHIFTL(MAX((uly), 0), 2, 10)); \ + }) + +#define gDPSetConvert(pkt, k0, k1, k2, k3, k4, k5) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_SETCONVERT, 24, 8) | _SHIFTL(k0, 13, 9) | _SHIFTL(k1, 4, 9) | _SHIFTR(k2, 5, 4)); \ + _g->words.w1 = (_SHIFTL(k2, 27, 5) | _SHIFTL(k3, 18, 9) | _SHIFTL(k4, 9, 9) | _SHIFTL(k5, 0, 9)); \ + }) + +#define gsDPSetConvert(k0, k1, k2, k3, k4, k5) \ + { \ + (_SHIFTL(G_SETCONVERT, 24, 8) | _SHIFTL(k0, 13, 9) | _SHIFTL(k1, 4, 9) | _SHIFTL(k2, 5, 4)), \ + (_SHIFTL(k2, 27, 5) | _SHIFTL(k3, 18, 9) | _SHIFTL(k4, 9, 9) | _SHIFTL(k5, 0, 9)) \ + } + +#define gDPSetKeyR(pkt, cR, sR, wR) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(G_SETKEYR, 24, 8); \ + _g->words.w1 = (_SHIFTL(wR, 16, 12) | _SHIFTL(cR, 8, 8) | _SHIFTL(sR, 0, 8)); \ + }) + +#define gsDPSetKeyR(cR, sR, wR) \ + { _SHIFTL(G_SETKEYR, 24, 8), _SHIFTL(wR, 16, 12) | _SHIFTL(cR, 8, 8) | _SHIFTL(sR, 0, 8) } + +#define gDPSetKeyGB(pkt, cG, sG, wG, cB, sB, wB) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_SETKEYGB, 24, 8) | _SHIFTL(wG, 12, 12) | _SHIFTL(wB, 0, 12)); \ + _g->words.w1 = (_SHIFTL(cG, 24, 8) | _SHIFTL(sG, 16, 8) | _SHIFTL(cB, 8, 8) | _SHIFTL(sB, 0, 8)); \ + }) + +#define gsDPSetKeyGB(cG, sG, wG, cB, sB, wB) \ + { \ + (_SHIFTL(G_SETKEYGB, 24, 8) | _SHIFTL(wG, 12, 12) | _SHIFTL(wB, 0, 12)), \ + (_SHIFTL(cG, 24, 8) | _SHIFTL(sG, 16, 8) | _SHIFTL(cB, 8, 8) | _SHIFTL(sB, 0, 8)) \ + } + +#define gDPNoParam(pkt, cmd) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(cmd, 24, 8); \ + _g->words.w1 = 0; \ + }) + +#define gsDPNoParam(cmd) \ + { _SHIFTL(cmd, 24, 8), 0 } + +#define gDPParam(pkt, cmd, param) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = _SHIFTL(cmd, 24, 8); \ + _g->words.w1 = (param); \ + }) + +#define gsDPParam(cmd, param) \ + { _SHIFTL(cmd, 24, 8), (param) } + +/* Notice that textured rectangles are 128-bit commands, therefore + * gsDPTextureRectangle() should not be used in display lists + * under normal circumstances (use gsSPTextureRectangle()). + * That is also why there is no gDPTextureRectangle() macros. + */ +#define gsDPTextureRectangle(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \ + { \ + (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) | _SHIFTL(yh, 0, 12)), \ + (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)), \ + }, \ + { \ + _SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16), _SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16) \ + } + +#define gDPTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + if (pkt) \ + ; \ + _g->words.w0 = (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) | _SHIFTL(yh, 0, 12)); \ + _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)); \ + _g++; \ + _g->words.w0 = (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16)); \ + _g->words.w1 = (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)); \ + }) + +#define gsDPTextureRectangleFlip(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \ + { \ + (_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) | _SHIFTL(yh, 0, 12)), \ + (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)), \ + }, \ + { \ + _SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16), _SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16) \ + } + +#define gDPTextureRectangleFlip(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + if (pkt) \ + ; \ + _g->words.w0 = (_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) | _SHIFTL(yh, 0, 12)); \ + _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)); \ + _g++; \ + _g->words.w0 = (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16)); \ + _g->words.w1 = (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)); \ + }) + +#define gsSPTextureRectangle(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \ + (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) | _SHIFTL(yh, 0, 12)), \ + (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)), \ + gsImmp1(G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))), \ + gsImmp1(G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16))) + +#define gSPTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) | _SHIFTL(yh, 0, 12)); \ + _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)); \ + gImmp1(pkt, G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))); \ + gImmp1(pkt, G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16))); \ + }) + +#define gSPWideTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \ + { \ + Gfx *_g0 = (Gfx*)(pkt), *_g1 = (Gfx*)(pkt), *_g2 = (Gfx*)(pkt); \ + \ + _g0->words.w0 = _SHIFTL(G_TEXRECT_WIDE, 24, 8) | _SHIFTL((xh), 0, 24); \ + _g0->words.w1 = _SHIFTL((yh), 0, 24); \ + _g1->words.w0 = (_SHIFTL(tile, 24, 3) | _SHIFTL((xl), 0, 24)); \ + _g1->words.w1 = _SHIFTL((yl), 0, 24); \ + _g2->words.w0 = (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16)); \ + _g2->words.w1 = (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16)); \ + } + +#define gsSPWideTextureRectangle(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \ + { { \ + (_SHIFTL(G_TEXRECT_WIDE, 24, 8) | _SHIFTL((xh), 0, 24)), \ + _SHIFTL((yh), 0, 24), \ + } }, \ + { { \ + (_SHIFTL((tile), 24, 3) | _SHIFTL((xl), 0, 24)), \ + _SHIFTL((yl), 0, 24), \ + } }, \ + { \ + { _SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16), _SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16) } \ + } + +/* like gSPTextureRectangle but accepts negative position arguments */ +#define gSPScisTextureRectangle(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = \ + (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(MAX((s16)(xh), 0), 12, 12) | _SHIFTL(MAX((s16)(yh), 0), 0, 12)); \ + _g->words.w1 = \ + (_SHIFTL((tile), 24, 3) | _SHIFTL(MAX((s16)(xl), 0), 12, 12) | _SHIFTL(MAX((s16)(yl), 0), 0, 12)); \ + gImmp1(pkt, G_RDPHALF_1, \ + (_SHIFTL(((s) - (((s16)(xl) < 0) ? (((s16)(dsdx) < 0) ? (MAX((((s16)(xl) * (s16)(dsdx)) >> 7), 0)) \ + : (MIN((((s16)(xl) * (s16)(dsdx)) >> 7), 0))) \ + : 0)), \ + 16, 16) | \ + _SHIFTL(((t) - (((yl) < 0) ? (((s16)(dtdy) < 0) ? (MAX((((s16)(yl) * (s16)(dtdy)) >> 7), 0)) \ + : (MIN((((s16)(yl) * (s16)(dtdy)) >> 7), 0))) \ + : 0)), \ + 0, 16))); \ + gImmp1(pkt, G_RDPHALF_2, (_SHIFTL((dsdx), 16, 16) | _SHIFTL((dtdy), 0, 16))); \ + }) + +#define gsSPTextureRectangleFlip(xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \ + (_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) | _SHIFTL(yh, 0, 12)), \ + (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)), \ + gsImmp1(G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))), \ + gsImmp1(G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16))) + +#define gSPTextureRectangleFlip(pkt, xl, yl, xh, yh, tile, s, t, dsdx, dtdy) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + _g->words.w0 = (_SHIFTL(G_TEXRECTFLIP, 24, 8) | _SHIFTL(xh, 12, 12) | _SHIFTL(yh, 0, 12)); \ + _g->words.w1 = (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)); \ + gImmp1(pkt, G_RDPHALF_1, (_SHIFTL(s, 16, 16) | _SHIFTL(t, 0, 16))); \ + gImmp1(pkt, G_RDPHALF_2, (_SHIFTL(dsdx, 16, 16) | _SHIFTL(dtdy, 0, 16))); \ + }) + +#define gsDPWord(wordhi, wordlo) \ + gsImmp1(G_RDPHALF_1, (unsigned int)(wordhi)), gsImmp1(G_RDPHALF_2, (unsigned int)(wordlo)) + +#define gDPWord(pkt, wordhi, wordlo) \ + _DW({ \ + Gfx* _g = (Gfx*)(pkt); \ + \ + gImmp1(pkt, G_RDPHALF_1, (unsigned int)(wordhi)); \ + gImmp1(pkt, G_RDPHALF_2, (unsigned int)(wordlo)); \ + }) + +#define gDPFullSync(pkt) gDPNoParam(pkt, G_RDPFULLSYNC) +#define gsDPFullSync() gsDPNoParam(G_RDPFULLSYNC) +#define gDPTileSync(pkt) gDPNoParam(pkt, G_RDPTILESYNC) +#define gsDPTileSync() gsDPNoParam(G_RDPTILESYNC) +#define gDPPipeSync(pkt) gDPNoParam(pkt, G_RDPPIPESYNC) +#define gsDPPipeSync() gsDPNoParam(G_RDPPIPESYNC) +#define gDPLoadSync(pkt) gDPNoParam(pkt, G_RDPLOADSYNC) +#define gsDPLoadSync() gsDPNoParam(G_RDPLOADSYNC) +#define gDPNoOp(pkt) gDPNoParam(pkt, G_NOOP) +#define gsDPNoOp() gsDPNoParam(G_NOOP) +#define gDPNoOpTag(pkt, tag) gDPParam(pkt, G_NOOP, tag) +#define gsDPNoOpTag(tag) gsDPParam(G_NOOP, tag) + +#define gDPNoOpHere(pkt, file, line) gDma1p(pkt, G_NOOP, file, line, 1) +#define gDPNoOpString(pkt, data, n) gDma1p(pkt, G_NOOP, data, n, 2) +#define gDPNoOpWord(pkt, data, n) gDma1p(pkt, G_NOOP, data, n, 3) +#define gDPNoOpFloat(pkt, data, n) gDma1p(pkt, G_NOOP, data, n, 4) +#define gDPNoOpQuiet(pkt) gDma1p(pkt, G_NOOP, 0, 0, 5) +#define gDPNoOpVerbose(pkt, n) gDma1p(pkt, G_NOOP, 0, n, 5) +#define gDPNoOpCallBack(pkt, callback, arg) gDma1p(pkt, G_NOOP, callback, arg, 6) +#define gDPNoOpOpenDisp(pkt, file, line) gDma1p(pkt, G_NOOP, file, line, 7) +#define gDPNoOpCloseDisp(pkt, file, line) gDma1p(pkt, G_NOOP, file, line, 8) +#define gDPNoOpTag3(pkt, type, data, n) gDma1p(pkt, G_NOOP, data, n, type) + +#endif diff --git a/libultraship/include/libultraship/libultra/gs2dex.h b/libultraship/include/libultraship/libultra/gs2dex.h new file mode 100644 index 000000000..662d43ae9 --- /dev/null +++ b/libultraship/include/libultraship/libultra/gs2dex.h @@ -0,0 +1,384 @@ +#ifndef GS2DEX_H +#define GS2DEX_H + +#ifdef _LANGUAGE_C_PLUS_PLUS +extern "C" { +#endif + +/*===========================================================================* + * Macro + *===========================================================================*/ +#define GS_CALC_DXT(line) (((1 << G_TX_DXT_FRAC) - 1) / (line) + 1) +#define GS_PIX2TMEM(pix, siz) ((pix) >> (4 - (siz))) +#define GS_PIX2DXT(pix, siz) GS_CALC_DXT(GS_PIX2TMEM((pix), (siz))) + +/*===========================================================================* + * Data structures for S2DEX microcode + *===========================================================================*/ + +/*---------------------------------------------------------------------------* + * Background + *---------------------------------------------------------------------------*/ +#define G_BGLT_LOADBLOCK 0x0033 +#define G_BGLT_LOADTILE 0xfff4 + +#define G_BG_FLAG_FLIPS 0x01 +#define G_BG_FLAG_FLIPT 0x10 + +/* Non scalable background plane */ +typedef struct { + u16 imageX; /* x-coordinate of upper-left position of texture (u10.5) */ + u16 imageW; /* width of the texture (u10.2) */ + s16 frameX; /* upper-left position of transferred frame (s10.2) */ + u16 frameW; /* width of transferred frame (u10.2) */ + + u16 imageY; /* y-coordinate of upper-left position of texture (u10.5) */ + u16 imageH; /* height of the texture (u10.2) */ + s16 frameY; /* upper-left position of transferred frame (s10.2) */ + u16 frameH; /* height of transferred frame (u10.2) */ + + u64* imagePtr; /* texture source address on DRAM */ + u16 imageLoad; /* which to use, LoadBlock or LoadTile */ + u8 imageFmt; /* format of texel - G_IM_FMT_* */ + u8 imageSiz; /* size of texel - G_IM_SIZ_* */ + u16 imagePal; /* pallet number */ + u16 imageFlip; /* right & left image inversion (Inverted by G_BG_FLAG_FLIPS) */ + + /* The following is set in the initialization routine guS2DInitBg(). There is no need for the user to set it. */ + u16 tmemW; /* TMEM width and Word size of frame 1 line. + At LoadBlock, GS_PIX2TMEM(imageW/4,imageSiz) + At LoadTile GS_PIX2TMEM(frameW/4,imageSiz)+1 */ + u16 tmemH; /* height of TMEM loadable at a time (s13.2) 4 times value + When the normal texture, 512/tmemW*4 + When the CI texture, 256/tmemW*4 */ + u16 tmemLoadSH; /* SH value + At LoadBlock, tmemSize/2-1 + At LoadTile, tmemW*16-1 */ + u16 tmemLoadTH; /* TH value or Stride value + At LoadBlock, GS_CALC_DXT(tmemW) + At LoadTile, tmemH-1 */ + u16 tmemSizeW; /* skip value of imagePtr for image 1-line + At LoadBlock, tmemW*2 + At LoadTile, GS_PIX2TMEM(imageW/4,imageSiz)*2 */ + u16 tmemSize; /* skip value of imagePtr for 1-loading + = tmemSizeW*tmemH */ +} uObjBg_t; /* 40 bytes */ + +/* Scalable background plane */ +typedef struct { + u16 imageX; /* x-coordinate of upper-left position of texture (u10.5) */ + u16 imageW; /* width of texture (u10.2) */ + s16 frameX; /* upper-left position of transferred frame (s10.2) */ + u16 frameW; /* width of transferred frame (u10.2) */ + + u16 imageY; /* y-coordinate of upper-left position of texture (u10.5) */ + u16 imageH; /* height of texture (u10.2) */ + s16 frameY; /* upper-left position of transferred frame (s10.2) */ + u16 frameH; /* height of transferred frame (u10.2) */ + + u64* imagePtr; /* texture source address on DRAM */ + u16 imageLoad; /* Which to use, LoadBlock or LoadTile? */ + u8 imageFmt; /* format of texel - G_IM_FMT_* */ + u8 imageSiz; /* size of texel - G_IM_SIZ_* */ + u16 imagePal; /* pallet number */ + u16 imageFlip; /* right & left image inversion (Inverted by G_BG_FLAG_FLIPS) */ + + u16 scaleW; /* scale value of X-direction (u5.10) */ + u16 scaleH; /* scale value of Y-direction (u5.10) */ + s32 imageYorig; /* start point of drawing on image (s20.5) */ + + u8 padding[4]; + +} uObjScaleBg_t; /* 40 bytes */ + +typedef union { + uObjBg_t b; + uObjScaleBg_t s; + long long int force_structure_alignment; +} uObjBg; + +/*---------------------------------------------------------------------------* + * 2D Objects + *---------------------------------------------------------------------------*/ +#define G_OBJ_FLAG_FLIPS 1 << 0 /* inversion to S-direction */ +#define G_OBJ_FLAG_FLIPT 1 << 4 /* nversion to T-direction */ + +typedef struct { + s16 objX; /* s10.2 OBJ x-coordinate of upper-left end */ + u16 scaleW; /* u5.10 Scaling of u5.10 width direction */ + u16 imageW; /* u10.5 width of u10.5 texture (length of S-direction) */ + u16 paddingX; /* Unused - Always 0 */ + s16 objY; /* s10.2 OBJ y-coordinate of s10.2 OBJ upper-left end */ + u16 scaleH; /* u5.10 Scaling of u5.10 height direction */ + u16 imageH; /* u10.5 height of u10.5 texture (length of T-direction) */ + u16 paddingY; /* Unused - Always 0 */ + u16 imageStride; /* folding width of texel (In units of 64bit word) */ + u16 imageAdrs; /* texture header position in TMEM (In units of 64bit word) */ + u8 imageFmt; /* format of texel - G_IM_FMT_* */ + u8 imageSiz; /* size of texel - G_IM_SIZ_* */ + u8 imagePal; /* pallet number (0-7) */ + u8 imageFlags; /* The display flag - G_OBJ_FLAG_FLIP* */ +} uObjSprite_t; /* 24 bytes */ + +typedef union { + uObjSprite_t s; + long long int force_structure_alignment; +} uObjSprite; + +/*---------------------------------------------------------------------------* + * 2D Matrix + *---------------------------------------------------------------------------*/ +typedef struct { + s32 A, B, C, D; /* s15.16 */ + s16 X, Y; /* s10.2 */ + u16 BaseScaleX; /* u5.10 */ + u16 BaseScaleY; /* u5.10 */ +} uObjMtx_t; /* 24 bytes */ + +typedef union { + uObjMtx_t m; + long long int force_structure_alignment; +} uObjMtx; + +typedef struct { + s16 X, Y; /* s10.2 */ + u16 BaseScaleX; /* u5.10 */ + u16 BaseScaleY; /* u5.10 */ +} uObjSubMtx_t; /* 8 bytes */ + +typedef union { + uObjSubMtx_t m; + long long int force_structure_alignment; +} uObjSubMtx; + +/*---------------------------------------------------------------------------* + * Loading into TMEM + *---------------------------------------------------------------------------*/ +#define G_OBJLT_TXTRBLOCK 0x00001033 +#define G_OBJLT_TXTRTILE 0x00fc1034 +#define G_OBJLT_TLUT 0x00000030 + +#define GS_TB_TSIZE(pix, siz) (GS_PIX2TMEM((pix), (siz)) - 1) +#define GS_TB_TLINE(pix, siz) (GS_CALC_DXT(GS_PIX2TMEM((pix), (siz)))) + +typedef struct { + u32 type; /* G_OBJLT_TXTRBLOCK divided into types */ + u64* image; /* texture source address on DRAM */ + u16 tmem; /* loaded TMEM word address (8byteWORD) */ + u16 tsize; /* Texture size, Specified by macro GS_TB_TSIZE() */ + u16 tline; /* width of Texture 1-line, Specified by macro GS_TB_TLINE() */ + u16 sid; /* STATE ID Multipled by 4 (Either one of 0, 4, 8 and 12) */ + u32 flag; /* STATE flag */ + u32 mask; /* STATE mask */ +} uObjTxtrBlock_t; /* 24 bytes */ + +#define GS_TT_TWIDTH(pix, siz) ((GS_PIX2TMEM((pix), (siz)) << 2) - 1) +#define GS_TT_THEIGHT(pix, siz) (((pix) << 2) - 1) + +typedef struct { + u32 type; /* G_OBJLT_TXTRTILE divided into types */ + u64* image; /* texture source address on DRAM */ + u16 tmem; /* loaded TMEM word address (8byteWORD)*/ + u16 twidth; /* width of Texture (Specified by macro GS_TT_TWIDTH()) */ + u16 theight; /* height of Texture (Specified by macro GS_TT_THEIGHT()) */ + u16 sid; /* STATE ID Multipled by 4 (Either one of 0, 4, 8 and 12) */ + u32 flag; /* STATE flag */ + u32 mask; /* STATE mask */ +} uObjTxtrTile_t; /* 24 bytes */ + +#define GS_PAL_HEAD(head) ((head) + 256) +#define GS_PAL_NUM(num) ((num)-1) + +typedef struct { + u32 type; /* G_OBJLT_TLUT divided into types */ + u64* image; /* texture source address on DRAM */ + u16 phead; /* pallet number of load header (Between 256 and 511) */ + u16 pnum; /* loading pallet number -1 */ + u16 zero; /* Assign 0 all the time */ + u16 sid; /* STATE ID Multipled by 4 (Either one of 0, 4, 8 and 12)*/ + u32 flag; /* STATE flag */ + u32 mask; /* STATE mask */ +} uObjTxtrTLUT_t; /* 24 bytes */ + +typedef union { + uObjTxtrBlock_t block; + uObjTxtrTile_t tile; + uObjTxtrTLUT_t tlut; + long long int force_structure_alignment; +} uObjTxtr; + +/*---------------------------------------------------------------------------* + * Loading into TMEM & 2D Objects + *---------------------------------------------------------------------------*/ +typedef struct { + uObjTxtr txtr; + uObjSprite sprite; +} uObjTxSprite; /* 48 bytes */ + +/*===========================================================================* + * GBI Commands for S2DEX microcode + *===========================================================================*/ +/* GBI Header */ +#ifdef F3DEX_GBI_2 +#define G_OBJ_RECTANGLE_R 0xda +#define G_OBJ_MOVEMEM 0xdc +#define G_RDPHALF_0 0xe4 +#define G_OBJ_RECTANGLE 0x01 +#define G_OBJ_SPRITE 0x02 +#define G_SELECT_DL 0x04 +#define G_OBJ_LOADTXTR 0x05 +#define G_OBJ_LDTX_SPRITE 0x06 +#define G_OBJ_LDTX_RECT 0x07 +#define G_OBJ_LDTX_RECT_R 0x08 +#define G_BG_1CYC 0x09 +#define G_BG_COPY 0x0a +#define G_OBJ_RENDERMODE 0x0b +#else +#define G_BG_1CYC 0x01 +#define G_BG_COPY 0x02 +#define G_OBJ_RECTANGLE 0x03 +#define G_OBJ_SPRITE 0x04 +#define G_OBJ_MOVEMEM 0x05 +#define G_SELECT_DL 0xb0 +#define G_OBJ_RENDERMODE 0xb1 +#define G_OBJ_RECTANGLE_R 0xb2 +#define G_OBJ_LOADTXTR 0xc1 +#define G_OBJ_LDTX_SPRITE 0xc2 +#define G_OBJ_LDTX_RECT 0xc3 +#define G_OBJ_LDTX_RECT_R 0xc4 +#define G_RDPHALF_0 0xe4 +#endif + +/*---------------------------------------------------------------------------* + * Background wrapped screen + *---------------------------------------------------------------------------*/ +#define gSPBgRectangle(pkt, m, mptr) gDma0p((pkt), (m), (mptr), 0) +#define gsSPBgRectangle(m, mptr) gsDma0p((m), (mptr), 0) +#define gSPBgRectCopy(pkt, mptr) gSPBgRectangle((pkt), G_BG_COPY, (mptr)) +#define gsSPBgRectCopy(mptr) gsSPBgRectangle(G_BG_COPY, (mptr)) +#define gSPBgRect1Cyc(pkt, mptr) gSPBgRectangle((pkt), G_BG_1CYC, (mptr)) +#define gsSPBgRect1Cyc(mptr) gsSPBgRectangle(G_BG_1CYC, (mptr)) + +/*---------------------------------------------------------------------------* + * 2D Objects + *---------------------------------------------------------------------------*/ +#define gSPObjSprite(pkt, mptr) gDma0p((pkt), G_OBJ_SPRITE, (mptr), 0) +#define gsSPObjSprite(mptr) gsDma0p(G_OBJ_SPRITE, (mptr), 0) +#define gSPObjRectangle(pkt, mptr) gDma0p((pkt), G_OBJ_RECTANGLE, (mptr), 0) +#define gsSPObjRectangle(mptr) gsDma0p(G_OBJ_RECTANGLE, (mptr), 0) +#define gSPObjRectangleR(pkt, mptr) gDma0p((pkt), G_OBJ_RECTANGLE_R, (mptr), 0) +#define gsSPObjRectangleR(mptr) gsDma0p(G_OBJ_RECTANGLE_R, (mptr), 0) + +/*---------------------------------------------------------------------------* + * 2D Matrix + *---------------------------------------------------------------------------*/ +#define gSPObjMatrix(pkt, mptr) gDma1p((pkt), G_OBJ_MOVEMEM, (mptr), 0, 23) +#define gsSPObjMatrix(mptr) gsDma1p(G_OBJ_MOVEMEM, (mptr), 0, 23) +#define gSPObjSubMatrix(pkt, mptr) gDma1p((pkt), G_OBJ_MOVEMEM, (mptr), 2, 7) +#define gsSPObjSubMatrix(mptr) gsDma1p(G_OBJ_MOVEMEM, (mptr), 2, 7) + +/*---------------------------------------------------------------------------* + * Loading into TMEM + *---------------------------------------------------------------------------*/ +#define gSPObjLoadTxtr(pkt, tptr) gDma0p((pkt), G_OBJ_LOADTXTR, (tptr), 23) +#define gsSPObjLoadTxtr(tptr) gsDma0p(G_OBJ_LOADTXTR, (tptr), 23) +#define gSPObjLoadTxSprite(pkt, tptr) gDma0p((pkt), G_OBJ_LDTX_SPRITE, (tptr), 47) +#define gsSPObjLoadTxSprite(tptr) gsDma0p(G_OBJ_LDTX_SPRITE, (tptr), 47) +#define gSPObjLoadTxRect(pkt, tptr) gDma0p((pkt), G_OBJ_LDTX_RECT, (tptr), 47) +#define gsSPObjLoadTxRect(tptr) gsDma0p(G_OBJ_LDTX_RECT, (tptr), 47) +#define gSPObjLoadTxRectR(pkt, tptr) gDma0p((pkt), G_OBJ_LDTX_RECT_R, (tptr), 47) +#define gsSPObjLoadTxRectR(tptr) gsDma0p(G_OBJ_LDTX_RECT_R, (tptr), 47) + +/*---------------------------------------------------------------------------* + * Select Display List + *---------------------------------------------------------------------------*/ +#define gSPSelectDL(pkt, mptr, sid, flag, mask) \ + { \ + gDma1p((pkt), G_RDPHALF_0, (flag), (u32)(mptr)&0xffff, (sid)); \ + gDma1p((pkt), G_SELECT_DL, (mask), (u32)(mptr) >> 16, G_DL_PUSH); \ + } +#define gsSPSelectDL(mptr, sid, flag, mask) \ + { \ + gsDma1p(G_RDPHALF_0, (flag), (u32)(mptr)&0xffff, (sid)); \ + gsDma1p(G_SELECT_DL, (mask), (u32)(mptr) >> 16, G_DL_PUSH); \ + } +#define gSPSelectBranchDL(pkt, mptr, sid, flag, mask) \ + { \ + gDma1p((pkt), G_RDPHALF_0, (flag), (u32)(mptr)&0xffff, (sid)); \ + gDma1p((pkt), G_SELECT_DL, (mask), (u32)(mptr) >> 16, G_DL_NOPUSH); \ + } +#define gsSPSelectBranchDL(mptr, sid, flag, mask) \ + { \ + gsDma1p(G_RDPHALF_0, (flag), (u32)(mptr)&0xffff, (sid)); \ + gsDma1p(G_SELECT_DL, (mask), (u32)(mptr) >> 16, G_DL_NOPUSH); \ + } + +/*---------------------------------------------------------------------------* + * Set general status + *---------------------------------------------------------------------------*/ +#define G_MW_GENSTAT 0x08 /* Note that it is the same value of G_MW_FOG */ + +#define gSPSetStatus(pkt, sid, val) gMoveWd((pkt), G_MW_GENSTAT, (sid), (val)) +#define gsSPSetStatus(sid, val) gsMoveWd(G_MW_GENSTAT, (sid), (val)) + +/*---------------------------------------------------------------------------* + * Set Object Render Mode + *---------------------------------------------------------------------------*/ +#define G_OBJRM_NOTXCLAMP 0x01 +#define G_OBJRM_XLU 0x02 /* Ignored */ +#define G_OBJRM_ANTIALIAS 0x04 /* Ignored */ +#define G_OBJRM_BILERP 0x08 +#define G_OBJRM_SHRINKSIZE_1 0x10 +#define G_OBJRM_SHRINKSIZE_2 0x20 +#define G_OBJRM_WIDEN 0x40 + +#define gSPObjRenderMode(pkt, mode) gImmp1((pkt), G_OBJ_RENDERMODE, (mode)) +#define gsSPObjRenderMode(mode) gsImmp1(G_OBJ_RENDERMODE, (mode)) + +/*===========================================================================* + * Render Mode Macro + *===========================================================================*/ +#define RM_RA_SPRITE(clk) \ + AA_EN | CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ + GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + +#define G_RM_SPRITE G_RM_OPA_SURF +#define G_RM_SPRITE2 G_RM_OPA_SURF2 +#define G_RM_RA_SPRITE RM_RA_SPRITE(1) +#define G_RM_RA_SPRITE2 RM_RA_SPRITE(2) +#define G_RM_AA_SPRITE G_RM_AA_TEX_TERR +#define G_RM_AA_SPRITE2 G_RM_AA_TEX_TERR2 +#define G_RM_XLU_SPRITE G_RM_XLU_SURF +#define G_RM_XLU_SPRITE2 G_RM_XLU_SURF2 +#define G_RM_AA_XLU_SPRITE G_RM_AA_XLU_SURF +#define G_RM_AA_XLU_SPRITE2 G_RM_AA_XLU_SURF2 + +/*===========================================================================* + * External functions + *===========================================================================*/ +extern u64 gspS2DEX_fifoTextStart[], gspS2DEX_fifoTextEnd[]; +extern u64 gspS2DEX_fifoDataStart[], gspS2DEX_fifoDataEnd[]; +extern u64 gspS2DEX_fifo_dTextStart[], gspS2DEX_fifo_dTextEnd[]; +extern u64 gspS2DEX_fifo_dDataStart[], gspS2DEX_fifo_dDataEnd[]; +extern u64 gspS2DEX2_fifoTextStart[], gspS2DEX2_fifoTextEnd[]; +extern u64 gspS2DEX2_fifoDataStart[], gspS2DEX2_fifoDataEnd[]; +extern u64 gspS2DEX2_xbusTextStart[], gspS2DEX2_xbusTextEnd[]; +extern u64 gspS2DEX2_xbusDataStart[], gspS2DEX2_xbusDataEnd[]; +extern void guS2DInitBg(uObjBg*); + +#ifdef F3DEX_GBI_2 +#define guS2DEmuBgRect1Cyc guS2D2EmuBgRect1Cyc /*Wrapper*/ +#define guS2DEmuSetScissor guS2D2EmuSetScissor /*Wrapper*/ +extern void guS2D2EmuSetScissor(u32, u32, u32, u32, u8); +extern void guS2D2EmuBgRect1Cyc(Gfx**, uObjBg*); +#else +extern void guS2DEmuSetScissor(u32, u32, u32, u32, u8); +extern void guS2DEmuBgRect1Cyc(Gfx**, uObjBg*); +#endif + +#ifdef _LANGUAGE_C_PLUS_PLUS +} +#endif +#endif /* GS2DEX_H */ + +/*======== End of gs2dex.h ========*/ diff --git a/libultraship/include/libultraship/libultra/gu.h b/libultraship/include/libultraship/libultra/gu.h new file mode 100644 index 000000000..535140a92 --- /dev/null +++ b/libultraship/include/libultraship/libultra/gu.h @@ -0,0 +1,201 @@ +#pragma once + +#include "types.h" +#include "gbi.h" +#include "sptask.h" + +#define GU_PI 3.1415926 + +#define ROUND(x) (s32)(((x) >= 0.0) ? ((x) + 0.5) : ((x)-0.5)) + +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#define D_PI 3.14159265358979323846 +#define D_DTOR (3.14159265358979323846 / 180.0) + +#define FTOFIX32(x) (long)((x) * (float)0x00010000) +#define FIX32TOF(x) ((float)(x) * (1.0f / (float)0x00010000)) +#define FTOFRAC8(x) ((int)MIN(((x) * (128.0f)), 127.0f) & 0xff) + +#define FILTER_WRAP 0 +#define FILTER_CLAMP 1 + +#define RAND(x) (guRandom() % x) /* random number between 0 to x */ + +/* + * Data Structures + */ +typedef struct { + unsigned char* base; + int fmt, siz; + int xsize, ysize; + int lsize; + /* current tile info */ + int addr; + int w, h; + int s, t; +} Image; + +typedef struct { + float col[3]; + float pos[3]; + float a1, a2; /* actual color = col/(a1*dist + a2) */ +} PositionalLight; + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Function Prototypes + */ + +extern int guLoadTextureBlockMipMap(Gfx** glist, unsigned char* tbuf, Image* im, unsigned char startTile, + unsigned char pal, unsigned char cms, unsigned char cmt, unsigned char masks, + unsigned char maskt, unsigned char shifts, unsigned char shiftt, unsigned char cfs, + unsigned char cft); + +extern int guGetDPLoadTextureTileSz(int ult, int lrt); +extern void guDPLoadTextureTile(Gfx* glistp, void* timg, int texl_fmt, int texl_size, int img_width, int img_height, + int uls, int ult, int lrs, int lrt, int palette, int cms, int cmt, int masks, int maskt, + int shifts, int shiftt); + +/* + * matrix operations: + * + * The 'F' version is floating point, in case the application wants + * to do matrix manipulations and convert to fixed-point at the last + * minute. + */ +extern void guMtxIdent(Mtx* m); +extern void guMtxIdentF(float mf[4][4]); +extern void guOrtho(Mtx* m, float l, float r, float b, float t, float n, float f, float scale); +extern void guOrthoF(float mf[4][4], float l, float r, float b, float t, float n, float f, float scale); +extern void guFrustum(Mtx* m, float l, float r, float b, float t, float n, float f, float scale); +extern void guFrustumF(float mf[4][4], float l, float r, float b, float t, float n, float f, float scale); +extern void guPerspective(Mtx* m, u16* perspNorm, float fovy, float aspect, float near, float far, float scale); +extern void guPerspectiveF(float mf[4][4], u16* perspNorm, float fovy, float aspect, float near, float far, + float scale); +extern void guLookAt(Mtx* m, float xEye, float yEye, float zEye, float xAt, float yAt, float zAt, float xUp, float yUp, + float zUp); +extern void guLookAtF(float mf[4][4], float xEye, float yEye, float zEye, float xAt, float yAt, float zAt, float xUp, + float yUp, float zUp); +extern void guLookAtReflect(Mtx* m, LookAt* l, float xEye, float yEye, float zEye, float xAt, float yAt, float zAt, + float xUp, float yUp, float zUp); +extern void guLookAtReflectF(float mf[4][4], LookAt* l, float xEye, float yEye, float zEye, float xAt, float yAt, + float zAt, float xUp, float yUp, float zUp); +extern void guLookAtHilite(Mtx* m, LookAt* l, Hilite* h, float xEye, float yEye, float zEye, float xAt, float yAt, + float zAt, float xUp, float yUp, float zUp, float xl1, float yl1, float zl1, float xl2, + float yl2, float zl2, int twidth, int theight); +extern void guLookAtHiliteF(float mf[4][4], LookAt* l, Hilite* h, float xEye, float yEye, float zEye, float xAt, + float yAt, float zAt, float xUp, float yUp, float zUp, float xl1, float yl1, float zl1, + float xl2, float yl2, float zl2, int twidth, int theight); +extern void guLookAtStereo(Mtx* m, float xEye, float yEye, float zEye, float xAt, float yAt, float zAt, float xUp, + float yUp, float zUp, float eyedist); +extern void guLookAtStereoF(float mf[4][4], float xEye, float yEye, float zEye, float xAt, float yAt, float zAt, + float xUp, float yUp, float zUp, float eyedist); +extern void guRotate(Mtx* m, float a, float x, float y, float z); +extern void guRotateF(float mf[4][4], float a, float x, float y, float z); +extern void guRotateRPY(Mtx* m, float r, float p, float y); +extern void guRotateRPYF(float mf[4][4], float r, float p, float h); +extern void guAlign(Mtx* m, float a, float x, float y, float z); +extern void guAlignF(float mf[4][4], float a, float x, float y, float z); +extern void guScale(Mtx* m, float x, float y, float z); +extern void guScaleF(float mf[4][4], float x, float y, float z); +extern void guTranslate(Mtx* m, float x, float y, float z); +extern void guTranslateF(float mf[4][4], float x, float y, float z); +extern void guPosition(Mtx* m, float r, float p, float h, float s, float x, float y, float z); +extern void guPositionF(float mf[4][4], float r, float p, float h, float s, float x, float y, float z); +extern void guMtxF2L(float mf[4][4], Mtx* m); +extern void guMtxL2F(float mf[4][4], Mtx* m); +extern void guMtxCatF(float m[4][4], float n[4][4], float r[4][4]); +extern void guMtxCatL(Mtx* m, Mtx* n, Mtx* res); +extern void guMtxXFMF(float mf[4][4], float x, float y, float z, float* ox, float* oy, float* oz); +extern void guMtxXFML(Mtx* m, float x, float y, float z, float* ox, float* oy, float* oz); + +/* vector utility: */ +extern void guNormalize(float* x, float* y, float* z); + +/* light utilities: */ +void guPosLight(PositionalLight* pl, Light* l, float xOb, float yOb, float zOb); +void guPosLightHilite(PositionalLight* pl1, PositionalLight* pl2, Light* l1, Light* l2, LookAt* l, Hilite* h, + float xEye, float yEye, float zEye, float xOb, float yOb, float zOb, float xUp, float yUp, + float zUp, int twidth, int theight); +extern int guRandom(void); + +/* + * Math functions + */ +// extern float sinf(float angle); +// extern float cosf(float angle); +// extern signed short sins (unsigned short angle); +// extern signed short coss (unsigned short angle); +extern float guSqrtf(float value); + +/* + * Dump routines for low-level display lists + */ +/* flag values for guParseRdpDL() */ +#define GU_PARSERDP_VERBOSE 1 +#define GU_PARSERDP_PRAREA 2 +#define GU_PARSERDP_PRHISTO 4 +#define GU_PARSERDP_DUMPONLY 32 /* doesn't need to be same as */ + /* GU_PARSEGBI_DUMPOLNY, but this */ + /* allows app to use interchangeably */ + +extern void guParseRdpDL(u64* rdp_dl, u64 nbytes, u8 flags); +extern void guParseString(char* StringPointer, u64 nbytes); + +/* + * NO LONGER SUPPORTED, + * use guParseRdpDL with GU_PARSERDP_DUMPONLY flags + */ +/* extern void guDumpRawRdpDL(u64 *rdp_dl, u64 nbytes); */ + +/* flag values for guBlinkRdpDL() */ +#define GU_BLINKRDP_HILITE 1 +#define GU_BLINKRDP_EXTRACT 2 + +extern void guBlinkRdpDL(u64* rdp_dl_in, u64 nbytes_in, u64* rdp_dl_out, u64* nbytes_out, u32 x, u32 y, u32 radius, + u8 red, u8 green, u8 blue, u8 flags); + +/* flag values for guParseGbiDL() */ +#define GU_PARSEGBI_ROWMAJOR 1 +#define GU_PARSEGBI_NONEST 2 +#define GU_PARSEGBI_FLTMTX 4 +#define GU_PARSEGBI_SHOWDMA 8 +#define GU_PARSEGBI_ALLMTX 16 +#define GU_PARSEGBI_DUMPONLY 32 +/* +#define GU_PARSEGBI_HANGAFTER 64 +#define GU_PARSEGBI_NOTEXTURES 128 +*/ +extern void guParseGbiDL(u64* gbi_dl, u32 nbytes, u8 flags); +extern void guDumpGbiDL(OSTask* tp, u8 flags); + +#define GU_PARSE_GBI_TYPE 1 +#define GU_PARSE_RDP_TYPE 2 +#define GU_PARSE_READY 3 +#define GU_PARSE_MEM_BLOCK 4 +#define GU_PARSE_ABI_TYPE 5 +#define GU_PARSE_STRING_TYPE 6 + +typedef struct { + int dataSize; + int dlType; + int flags; + u32 paddr; +} guDLPrintCB; + +void guSprite2DInit(uSprite* SpritePointer, void* SourceImagePointer, void* TlutPointer, int Stride, int SubImageWidth, + int SubImageHeight, int SourceImageType, int SourceImageBitSize, int SourceImageOffsetS, + int SourceImageOffsetT); + +#ifdef __cplusplus +} +#endif diff --git a/libultraship/include/libultraship/libultra/internal.h b/libultraship/include/libultraship/libultra/internal.h new file mode 100644 index 000000000..1433033a8 --- /dev/null +++ b/libultraship/include/libultraship/libultra/internal.h @@ -0,0 +1,27 @@ +#pragma once + +#include "pi.h" + +typedef struct { + /* 0x00 */ u32 initialized; + /* 0x04 */ OSThread* mgrThread; + /* 0x08 */ OSMesgQueue* cmdQueue; + /* 0x0C */ OSMesgQueue* eventQueue; + /* 0x10 */ OSMesgQueue* accessQueue; + /* 0x14 */ s32 (*piDmaCallback)(s32, u32, void*, size_t); + /* 0x18 */ s32 (*epiDmaCallback)(OSPiHandle*, s32, u32, void*, size_t); +} OSMgrArgs; // size = 0x1C + +typedef struct { + /* 0x00 */ OSMesgQueue* queue; + /* 0x04 */ OSMesg msg; +} __OSEventState; // size = 0x08 + +#ifdef __cplusplus +extern "C" { +#endif +extern OSMgrArgs __osPiDevMgr; +extern __OSEventState __osEventStateTab[]; +#ifdef __cplusplus +} +#endif diff --git a/libultraship/include/libultraship/libultra/interrupt.h b/libultraship/include/libultraship/libultra/interrupt.h new file mode 100644 index 000000000..626ef4192 --- /dev/null +++ b/libultraship/include/libultraship/libultra/interrupt.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +typedef uint32_t OSIntMask; diff --git a/libultraship/include/libultraship/libultra/mbi.h b/libultraship/include/libultraship/libultra/mbi.h new file mode 100644 index 000000000..3019a6ce4 --- /dev/null +++ b/libultraship/include/libultraship/libultra/mbi.h @@ -0,0 +1,42 @@ +#ifndef ULTRA64_MBI_H +#define ULTRA64_MBI_H + +/* + * Header file for the Media Binary Interface + * + * NOTE: This file is included by the RSP microcode, so any C-specific + * constructs must be bracketed by #ifdef _LANGUAGE_C + * + */ + +/* + * the SHIFT macros are used to build display list commands, inserting + * bit-fields into a 32-bit word. They take a value, a shift amount, + * and a width. + * + * For the left shift, the lower bits of the value are masked, + * then shifted left. + * + * For the right shift, the value is shifted right, then the lower bits + * are masked. + * + * (NOTE: _SHIFTL(v, 0, 32) won't work, just use an assignment) + * + */ +#define _SHIFTL(v, s, w) ((u32)(((u32)(v) & ((0x01 << (w)) - 1)) << (s))) +#define _SHIFTR(v, s, w) ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1))) + +#define G_ON (1) +#define G_OFF (0) + +#include +#include "types.h" +#include "gbi.h" +#include "abi.h" + +#define NUM_SEGMENTS (16) +#define SEGMENT_OFFSET(a) ((u32)(a)&0x00FFFFFF) +#define SEGMENT_NUMBER(a) (((u32)(a) << 4) >> 28) +#define SEGMENT_ADDR(num, off) (((num) << 24) + (off)) + +#endif diff --git a/libultraship/include/libultraship/libultra/message.h b/libultraship/include/libultraship/libultra/message.h new file mode 100644 index 000000000..dca268f79 --- /dev/null +++ b/libultraship/include/libultraship/libultra/message.h @@ -0,0 +1,66 @@ +#ifndef ULTRA64_MESSAGE_H +#define ULTRA64_MESSAGE_H + +#include "thread.h" + +#define OS_MESG_NOBLOCK 0 +#define OS_MESG_BLOCK 1 + +typedef union { + u8 data8; + u16 data16; + u32 data32; + void* ptr; +} OSMesg; + +#define OS_MESG_8(x) ((OSMesg){ .data8 = (x) }) +#define OS_MESG_16(x) ((OSMesg){ .data16 = (x) }) +#define OS_MESG_32(x) ((OSMesg){ .data32 = (x) }) +#define OS_MESG_PTR(x) ((OSMesg){ .ptr = (x) }) + +#define osSendMesg8(queue, msg, flag) osSendMesg(queue, OS_MESG_8(msg), flag) +#define osSendMesg16(queue, msg, flag) osSendMesg(queue, OS_MESG_16(msg), flag) +#define osSendMesg32(queue, msg, flag) osSendMesg(queue, OS_MESG_32(msg), flag) +#define osSendMesgPtr(queue, msg, flag) osSendMesg(queue, OS_MESG_PTR(msg), flag) + +typedef u32 OSEvent; + +#define OS_NUM_EVENTS 15 + +#define OS_EVENT_SW1 0 /* CPU SW1 interrupt */ +#define OS_EVENT_SW2 1 /* CPU SW2 interrupt */ +#define OS_EVENT_CART 2 /* Cartridge interrupt: used by rmon */ +#define OS_EVENT_COUNTER 3 /* Counter int: used by VI/Timer Mgr */ +#define OS_EVENT_SP 4 /* SP task done interrupt */ +#define OS_EVENT_SI 5 /* SI (controller) interrupt */ +#define OS_EVENT_AI 6 /* AI interrupt */ +#define OS_EVENT_VI 7 /* VI interrupt: used by VI/Timer Mgr */ +#define OS_EVENT_PI 8 /* PI interrupt: used by PI Manager */ +#define OS_EVENT_DP 9 /* DP full sync interrupt */ +#define OS_EVENT_CPU_BREAK 10 /* CPU breakpoint: used by rmon */ +#define OS_EVENT_SP_BREAK 11 /* SP breakpoint: used by rmon */ +#define OS_EVENT_FAULT 12 /* CPU fault event: used by rmon */ +#define OS_EVENT_THREADSTATUS 13 /* CPU thread status: used by rmon */ +#define OS_EVENT_PRENMI 14 /* Pre NMI interrupt */ + +typedef struct OSMesgQueue { + /* 0x00 */ OSThread* mtqueue; + /* 0x04 */ OSThread* fullqueue; + /* 0x08 */ s32 validCount; + /* 0x0C */ s32 first; + /* 0x10 */ s32 msgCount; + /* 0x14 */ OSMesg* msg; +} OSMesgQueue; // size = 0x18 + +#ifdef __cplusplus +extern "C" { +#endif +void osCreateMesgQueue(OSMesgQueue* mq, OSMesg* msgBuf, int32_t count); +int32_t osSendMesg(OSMesgQueue* mq, OSMesg msg, int32_t flag); +int32_t osJamMesg(OSMesgQueue* mq, OSMesg msg, int32_t flag); +int32_t osRecvMesg(OSMesgQueue* mq, OSMesg* msg, int32_t flag); +void osSetEventMesg(OSEvent event, OSMesgQueue* mq, OSMesg msg); +#ifdef __cplusplus +} +#endif +#endif diff --git a/libultraship/include/libultraship/libultra/motor.h b/libultraship/include/libultraship/libultra/motor.h new file mode 100644 index 000000000..c6274fad9 --- /dev/null +++ b/libultraship/include/libultraship/libultra/motor.h @@ -0,0 +1,22 @@ +#ifndef ULTRA64_MOTOR_H +#define ULTRA64_MOTOR_H + +#include "pfs.h" + +#define MOTOR_START 1 +#define MOTOR_STOP 0 + +#define osMotorStart(x) __osMotorAccess((x), MOTOR_START) +#define osMotorStop(x) __osMotorAccess((x), MOTOR_STOP) + +#ifdef __cplusplus +extern "C" { +#endif + +s32 __osMotorAccess(OSPfs* pfs, u32 vibrate); +s32 osMotorInit(OSMesgQueue* ctrlrqueue, OSPfs* pfs, s32 channel); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/libultraship/include/libultraship/libultra/os.h b/libultraship/include/libultraship/libultra/os.h new file mode 100644 index 000000000..bd11553a4 --- /dev/null +++ b/libultraship/include/libultraship/libultra/os.h @@ -0,0 +1,152 @@ +#pragma once + +#ifndef OS_H +#define OS_H + +#include +#include "controller.h" +#include "message.h" +#include "time.h" +#include "pi.h" +#include "vi.h" + +#ifndef _HW_VERSION_1 +#define MAXCONTROLLERS 4 +#else +#define MAXCONTROLLERS 6 +#endif + +/* controller errors */ +#define CONT_NO_RESPONSE_ERROR 0x8 +#define CONT_OVERRUN_ERROR 0x4 +#define CONT_RANGE_ERROR -1 +#ifdef _HW_VERSION_1 +#define CONT_FRAME_ERROR 0x2 +#define CONT_COLLISION_ERROR 0x1 +#endif + +/* Controller type */ + +#define CONT_ABSOLUTE 0x0001 +#define CONT_RELATIVE 0x0002 +#define CONT_JOYPORT 0x0004 +#define CONT_EEPROM 0x8000 +#define CONT_EEP16K 0x4000 +#define CONT_TYPE_MASK 0x1F07 +#define CONT_TYPE_NORMAL 0x0005 +#define CONT_TYPE_MOUSE 0x0002 +#define CONT_TYPE_VOICE 0x0100 + +/* Controller status */ + +#define CONT_CARD_ON 0x01 +#define CONT_CARD_PULL 0x02 +#define CONT_ADDR_CRC_ER 0x04 +#define CONT_EEPROM_BUSY 0x80 + +/* Buttons */ + +#define CONT_A 0x8000 +#define CONT_B 0x4000 +#define CONT_G 0x2000 +#define CONT_START 0x1000 +#define CONT_UP 0x0800 +#define CONT_DOWN 0x0400 +#define CONT_LEFT 0x0200 +#define CONT_RIGHT 0x0100 +#define CONT_L 0x0020 +#define CONT_R 0x0010 +#define CONT_E 0x0008 +#define CONT_D 0x0004 +#define CONT_C 0x0002 +#define CONT_F 0x0001 + +/* Nintendo's official button names */ + +#define A_BUTTON CONT_A +#define B_BUTTON CONT_B +#define L_TRIG CONT_L +#define R_TRIG CONT_R +#define Z_TRIG CONT_G +#define START_BUTTON CONT_START +#define U_JPAD CONT_UP +#define L_JPAD CONT_LEFT +#define R_JPAD CONT_RIGHT +#define D_JPAD CONT_DOWN +#define U_CBUTTONS CONT_E +#define L_CBUTTONS CONT_C +#define R_CBUTTONS CONT_F +#define D_CBUTTONS CONT_D + +/* Controller error number */ + +#define CONT_ERR_NO_CONTROLLER PFS_ERR_NOPACK /* 1 */ +#define CONT_ERR_CONTRFAIL CONT_OVERRUN_ERROR /* 4 */ +#define CONT_ERR_INVALID PFS_ERR_INVALID /* 5 */ +#define CONT_ERR_DEVICE PFS_ERR_DEVICE /* 11 */ +#define CONT_ERR_NOT_READY 12 +#define CONT_ERR_VOICE_MEMORY 13 +#define CONT_ERR_VOICE_WORD 14 +#define CONT_ERR_VOICE_NO_RESPONSE 15 + +// EEPROM + +#define EEPROM_TYPE_4K 0x01 +#define EEPROM_TYPE_16K 0x02 + +#define EEPROM_MAXBLOCKS 64 +#define EEP16K_MAXBLOCKS 256 +#define EEPROM_BLOCK_SIZE 8 + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t osContInit(OSMesgQueue* mq, uint8_t* controllerBits, OSContStatus* status); +int32_t osContStartReadData(OSMesgQueue* mesg); +void osContGetReadData(OSContPad* pad); +uint8_t osContGetStatus(uint8_t controller); + +void osWritebackDCacheAll(); +void osInvalDCache(void* p, int32_t l); +void osInvalICache(void* p, int32_t x); +void osWritebackDCache(void* p, int32_t x); + +s32 osPiStartDma(OSIoMesg* mb, s32 priority, s32 direction, uintptr_t devAddr, void* vAddr, size_t nbytes, + OSMesgQueue* mq); +void osViSwapBuffer(void*); +void osViBlack(uint8_t active); +void osViFade(u8, u16); +void osViRepeatLine(u8); +void osViSetXScale(f32); +void osViSetYScale(f32); +void osViSetSpecialFeatures(u32); +void osViSetMode(OSViMode*); +void osViSetEvent(OSMesgQueue*, OSMesg, u32); +void osCreateViManager(OSPri); +void osCreatePiManager(OSPri pri, OSMesgQueue* cmdQ, OSMesg* cmdBuf, s32 cmdMsgCnt); + +void osSetTime(OSTime time); +uint64_t osGetTime(void); +uint32_t osGetCount(void); +s32 osEepromProbe(OSMesgQueue*); +s32 osEepromRead(OSMesgQueue*, u8, u8*); +s32 osEepromWrite(OSMesgQueue*, u8, u8*); +s32 osEepromLongRead(OSMesgQueue*, u8, u8*, int); +s32 osEepromLongWrite(OSMesgQueue*, u8, u8*, int); + +int osSetTimer(OSTimer* t, OSTime countdown, OSTime interval, OSMesgQueue* mq, OSMesg msg); + +s32 osAiSetFrequency(u32 freq); +OSPiHandle* osCartRomInit(void); +s32 osEPiStartDma(OSPiHandle* pihandle, OSIoMesg* mb, s32 direction); + +s32 osAiSetFrequency(u32); +s32 osAiSetNextBuffer(void*, size_t); +u32 osAiGetLength(void); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/libultraship/include/libultraship/libultra/pfs.h b/libultraship/include/libultraship/libultra/pfs.h new file mode 100644 index 000000000..faea235b5 --- /dev/null +++ b/libultraship/include/libultraship/libultra/pfs.h @@ -0,0 +1,134 @@ +#pragma once + +#include "message.h" + +/* File System size */ +#define OS_PFS_VERSION 0x0200 +#define OS_PFS_VERSION_HI (OS_PFS_VERSION >> 8) +#define OS_PFS_VERSION_LO (OS_PFS_VERSION & 255) + +#define PFS_INODE_SIZE_PER_PAGE 128 +#define PFS_FILE_NAME_LEN 16 +#define PFS_FILE_EXT_LEN 4 +#define BLOCKSIZE 32 +#define PFS_ONE_PAGE 8 +#define PFS_MAX_BANKS 62 + +/* File System flag */ + +#define PFS_READ 0 +#define PFS_WRITE 1 +#define PFS_CREATE 2 + +/* File System status */ +#define PFS_INITIALIZED 0x1 +#define PFS_CORRUPTED 0x2 +#define PFS_ID_BROKEN 0x4 +#define PFS_MOTOR_INITIALIZED 0x8 +#define PFS_GBPAK_INITIALIZED 0x10 + +/* Definition for page usage */ +#define PFS_EOF 1 +#define PFS_PAGE_NOT_EXIST 2 +#define PFS_PAGE_NOT_USED 3 + +/* File System error number */ + +#define PFS_ERR_NOPACK 1 /* no memory card is plugged or */ +#define PFS_ERR_NEW_PACK 2 /* ram pack has been changed to a different one */ +#define PFS_ERR_INCONSISTENT 3 /* need to run Pfschecker*/ +#define PFS_ERR_CONTRFAIL CONT_OVERRUN_ERROR +#define PFS_ERR_INVALID 5 /* invalid parameter or file not exist*/ +#define PFS_ERR_BAD_DATA 6 /* the data read from pack are bad*/ +#define PFS_DATA_FULL 7 /* no free pages on ram pack*/ +#define PFS_DIR_FULL 8 /* no free directories on ram pack*/ +#define PFS_ERR_EXIST 9 /* file exists*/ +#define PFS_ERR_ID_FATAL 10 /* dead ram pack */ +#define PFS_ERR_DEVICE 11 /* wrong device type*/ +#define PFS_ERR_NO_GBCART 12 /* no gb cartridge (64GB-PAK) */ +#define PFS_ERR_NEW_GBCART 13 /* gb cartridge may be changed */ + +/* Definition for bank */ +#define PFS_ID_BANK_256K 0 +#define PFS_ID_BANK_1M 4 +#define PFS_BANKS_256K 1 + +#define PFS_WRITTEN 2 +#define DEF_DIR_PAGES 2 + +#define PFS_ID_0AREA 1 +#define PFS_ID_1AREA 3 +#define PFS_ID_2AREA 4 +#define PFS_ID_3AREA 6 +#define PFS_LABEL_AREA 7 +#define PFS_ID_PAGE PFS_ONE_PAGE * 0 + +#define PFS_BANK_LAPPED_BY 8 /* => u8 */ +#define PFS_SECTOR_PER_BANK 32 +#define PFS_INODE_DIST_MAP (PFS_BANK_LAPPED_BY * PFS_SECTOR_PER_BANK) +#define PFS_SECTOR_SIZE (PFS_INODE_SIZE_PER_PAGE / PFS_SECTOR_PER_BANK) + +typedef struct { + /* 0x00 */ s32 status; + /* 0x04 */ OSMesgQueue* queue; + /* 0x08 */ s32 channel; + /* 0x0C */ u8 id[32]; + /* 0x2C */ u8 label[32]; + /* 0x4C */ s32 version; + /* 0x50 */ s32 dir_size; + /* 0x54 */ s32 inode_table; /* block location */ + /* 0x58 */ s32 minode_table; /* mirrioring inode_table */ + /* 0x5C */ s32 dir_table; /* block location */ + /* 0x60 */ s32 inodeStartPage; /* page # */ + /* 0x64 */ u8 banks; + /* 0x65 */ u8 activebank; +} OSPfs; // size = 0x68 + +typedef struct { + /* 0x00 */ u32 file_size; /* bytes */ + /* 0x04 */ u32 game_code; + /* 0x08 */ u16 company_code; + /* 0x0C */ char ext_name[4]; + /* 0x10 */ char game_name[16]; +} OSPfsState; // size = 0x20 + +typedef union { + struct { + /* 0x00 */ u8 bank; + /* 0x01 */ u8 page; + } inode_t; + /* 0x00 */ u16 ipage; +} __OSInodeUnit; // size = 0x02 + +typedef struct { + /* 0x00 */ __OSInodeUnit inodePage[128]; +} __OSInode; // size = 0x100 + +typedef struct { + /* 0x00 */ u32 game_code; + /* 0x04 */ u16 company_code; + /* 0x06 */ __OSInodeUnit start_page; + /* 0x08 */ u8 status; + /* 0x09 */ s8 reserved; + /* 0x0A */ u16 data_sum; + /* 0x0C */ u8 ext_name[PFS_FILE_EXT_LEN]; + /* 0x10 */ u8 game_name[PFS_FILE_NAME_LEN]; +} __OSDir; // size = 0x20 + +typedef struct { + /* 0x00 */ u32 repaired; + /* 0x04 */ u32 random; + /* 0x08 */ u64 serialMid; + /* 0x10 */ u64 serialLow; + /* 0x18 */ u16 deviceid; + /* 0x1A */ u8 banks; + /* 0x1B */ u8 version; + /* 0x1C */ u16 checksum; + /* 0x1E */ u16 invertedChecksum; +} __OSPackId; // size = 0x20 + +typedef struct { + /* 0x000 */ __OSInode inode; + /* 0x100 */ u8 bank; + /* 0x101 */ u8 map[PFS_INODE_DIST_MAP]; +} __OSInodeCache; // size = 0x202 diff --git a/libultraship/include/libultraship/libultra/pi.h b/libultraship/include/libultraship/libultra/pi.h new file mode 100644 index 000000000..1624900fe --- /dev/null +++ b/libultraship/include/libultraship/libultra/pi.h @@ -0,0 +1,79 @@ +#pragma once +#include "message.h" + +typedef struct { + /* 0x00 */ u32 errStatus; + /* 0x04 */ void* dramAddr; + /* 0x08 */ void* C2Addr; + /* 0x0C */ u32 sectorSize; + /* 0x10 */ u32 C1ErrNum; + /* 0x14 */ u32 C1ErrSector[4]; +} __OSBlockInfo; // size = 0x24 + +typedef struct { + /* 0x00 */ u32 cmdType; + /* 0x04 */ u16 transferMode; + /* 0x06 */ u16 blockNum; + /* 0x08 */ s32 sectorNum; + /* 0x0C */ u32 devAddr; + /* 0x10 */ u32 bmCtlShadow; + /* 0x14 */ u32 seqCtlShadow; + /* 0x18 */ __OSBlockInfo block[2]; +} __OSTranxInfo; // size = 0x60 + +typedef struct OSPiHandle { + /* 0x00 */ struct OSPiHandle* next; + /* 0x04 */ u8 type; + /* 0x05 */ u8 latency; + /* 0x06 */ u8 pageSize; + /* 0x07 */ u8 relDuration; + /* 0x08 */ u8 pulse; + /* 0x09 */ u8 domain; + /* 0x0C */ u32 baseAddress; + /* 0x10 */ u32 speed; + /* 0x14 */ __OSTranxInfo transferInfo; +} OSPiHandle; // size = 0x74 + +typedef struct { + /* 0x00 */ u8 type; + /* 0x04 */ u32 address; +} OSPiInfo; // size = 0x08 + +typedef struct { + /* 0x00 */ u16 type; + /* 0x02 */ u8 pri; + /* 0x03 */ u8 status; + /* 0x04 */ OSMesgQueue* retQueue; +} OSIoMesgHdr; // size = 0x08 + +typedef struct { + /* 0x00 */ OSIoMesgHdr hdr; + /* 0x08 */ void* dramAddr; + /* 0x0C */ u32 devAddr; + /* 0x10 */ size_t size; + /* 0x14 */ OSPiHandle* piHandle; +} OSIoMesg; // size = 0x18 + +#define OS_READ 0 // device -> RDRAM +#define OS_WRITE 1 // device <- RDRAM +#define OS_OTHERS 2 // for disk drive transfers + +#define PI_DOMAIN1 0 +#define PI_DOMAIN2 1 + +#define OS_MESG_TYPE_LOOPBACK 10 +#define OS_MESG_TYPE_DMAREAD 11 +#define OS_MESG_TYPE_DMAWRITE 12 +#define OS_MESG_TYPE_VRETRACE 13 +#define OS_MESG_TYPE_COUNTER 14 +#define OS_MESG_TYPE_EDMAREAD 15 +#define OS_MESG_TYPE_EDMAWRITE 16 + +#define OS_MESG_PRI_NORMAL 0 +#define OS_MESG_PRI_HIGH 1 + +#define DEVICE_TYPE_CART 0 /* ROM cartridge */ +#define DEVICE_TYPE_BULK 1 /* ROM bulk */ +#define DEVICE_TYPE_64DD 2 /* 64 Disk Drive */ +#define DEVICE_TYPE_SRAM 3 /* SRAM */ +#define DEVICE_TYPE_INIT 7 /* initial value */ diff --git a/libultraship/include/libultraship/libultra/printf.h b/libultraship/include/libultraship/libultra/printf.h new file mode 100644 index 000000000..f5ece686a --- /dev/null +++ b/libultraship/include/libultraship/libultra/printf.h @@ -0,0 +1,30 @@ +#pragma once + +#include "types.h" + +typedef struct { + /* 0x0 */ union { + /* 0x0 */ s64 ll; + /* 0x0 */ f64 ld; + } v; + /* 0x8 */ char* s; + /* 0xC */ s32 n0; + /* 0x10 */ s32 nz0; + /* 0x14 */ s32 n1; + /* 0x18 */ s32 nz1; + /* 0x1C */ s32 n2; + /* 0x20 */ s32 nz2; + /* 0x24 */ s32 prec; + /* 0x28 */ s32 width; + /* 0x2C */ u32 nchar; + /* 0x30 */ u32 flags; + /* 0x34 */ u8 qual; +} _Pft; // size = 0x38 + +typedef void* (*PrintCallback)(void*, const char*, u32); + +#define FLAGS_SPACE 1 +#define FLAGS_PLUS 2 +#define FLAGS_MINUS 4 +#define FLAGS_HASH 8 +#define FLAGS_ZERO 16 diff --git a/libultraship/include/libultraship/libultra/r4300.h b/libultraship/include/libultraship/libultra/r4300.h new file mode 100644 index 000000000..ac7d7c298 --- /dev/null +++ b/libultraship/include/libultraship/libultra/r4300.h @@ -0,0 +1,364 @@ +#pragma once + +#ifdef _LANGUAGE_C +#include "types.h" +#define U32(x) ((u32)x) +#define C_REG(x) (x) +#else +#define U32(x) (x) +#define C_REG(x) $x +#endif + +// Segment base addresses and sizes +#define KUBASE 0 +#define KUSIZE 0x80000000 +#define K0BASE 0x80000000 +#define K0SIZE 0x20000000 +#define K1BASE 0xA0000000 +#define K1SIZE 0x20000000 +#define K2BASE 0xC0000000 +#define K2SIZE 0x20000000 + +// Exception vectors +#define SIZE_EXCVEC 0x80 // Size of an exc. vec +#define UT_VEC K0BASE // utlbmiss vector +#define R_VEC (K1BASE + 0x1FC00000) // reset vector +#define XUT_VEC (K0BASE + 0x80) // extended address tlbmiss +#define ECC_VEC (K0BASE + 0x100) // Ecc exception vector +#define E_VEC (K0BASE + 0x180) // Gen. exception vector + +// Address conversion macros +#define K0_TO_K1(x) (U32(x) | 0xA0000000) // kseg0 to kseg1 +#define K1_TO_K0(x) (U32(x) & 0x9FFFFFFF) // kseg1 to kseg0 +#define K0_TO_PHYS(x) (U32(x) & 0x1FFFFFFF) // kseg0 to physical +#define K1_TO_PHYS(x) (U32(x) & 0x1FFFFFFF) // kseg1 to physical +#define KDM_TO_PHYS(x) (U32(x) & 0x1FFFFFFF) // direct mapped to physical +#define PHYS_TO_K0(x) (U32(x) | 0x80000000) // physical to kseg0 +#define PHYS_TO_K1(x) (U32(x) | 0xA0000000) // physical to kseg1 + +// Address predicates +#define IS_KSEG0(x) (U32(x) >= K0BASE && U32(x) < K1BASE) +#define IS_KSEG1(x) (U32(x) >= K1BASE && U32(x) < K2BASE) +#define IS_KSEGDM(x) (U32(x) >= K0BASE && U32(x) < K2BASE) +#define IS_KSEG2(x) (U32(x) >= K2BASE && U32(x) < KPTE_SHDUBASE) +#define IS_KPTESEG(x) (U32(x) >= KPTE_SHDUBASE) +#define IS_KUSEG(x) (U32(x) < K0BASE) + +// TLB size constants +#define NTLBENTRIES 31 /* entry 31 is reserved by rdb */ + +#define TLBHI_VPN2MASK 0xFFFFE000 +#define TLBHI_VPN2SHIFT 13 +#define TLBHI_PIDMASK 0xFF +#define TLBHI_PIDSHIFT 0 +#define TLBHI_NPID 255 // 255 to fit in 8 bits + +#define TLBLO_PFNMASK 0x3FFFFFC0 +#define TLBLO_PFNSHIFT 6 +#define TLBLO_CACHMASK 0x38 // cache coherency algorithm +#define TLBLO_CACHSHIFT 3 +#define TLBLO_UNCACHED 0x10 // not cached +#define TLBLO_NONCOHRNT 0x18 // Cacheable non-coherent +#define TLBLO_EXLWR 0x28 // Exclusive write +#define TLBLO_D 0x4 // writeable +#define TLBLO_V 0x2 // valid bit +#define TLBLO_G 0x1 // global access bit + +#define TLBINX_PROBE 0x80000000 +#define TLBINX_INXMASK 0x3F +#define TLBINX_INXSHIFT 0 + +#define TLBRAND_RANDMASK 0x3F +#define TLBRAND_RANDSHIFT 0 + +#define TLBWIRED_WIREDMASK 0x3F + +#define TLBCTXT_BASEMASK 0xFF800000 +#define TLBCTXT_BASESHIFT 23 +#define TLBCTXT_BASEBITS 9 + +#define TLBCTXT_VPNMASK 0x7FFFF0 +#define TLBCTXT_VPNSHIFT 4 + +#define TLBPGMASK_4K 0x0 +#define TLBPGMASK_16K 0x6000 +#define TLBPGMASK_64K 0x1E000 + +/* + * Status register + */ +#define SR_CUMASK 0xF0000000 // coproc usable bits + +#define SR_CU3 0x80000000 // Coprocessor 3 usable +#define SR_CU2 0x40000000 // Coprocessor 2 usable +#define SR_CU1 0x20000000 // Coprocessor 1 usable +#define SR_CU0 0x10000000 // Coprocessor 0 usable +#define SR_RP 0x08000000 // Reduced power (quarter speed) +#define SR_FR 0x04000000 // MIPS III FP register mode +#define SR_RE 0x02000000 // Reverse endian +#define SR_ITS 0x01000000 // Instruction trace support +#define SR_BEV 0x00400000 // Use boot exception vectors +#define SR_TS 0x00200000 // TLB shutdown +#define SR_SR 0x00100000 // Soft reset occured +#define SR_CH 0x00040000 // Cache hit for last 'cache' op +#define SR_CE 0x00020000 // Create ECC +#define SR_DE 0x00010000 // ECC of parity does not cause error + +// Interrupt enable bits +// (NOTE: bits set to 1 enable the corresponding level interrupt) +#define SR_IMASK 0x0000FF00 // Interrupt mask +#define SR_IMASK8 0x00000000 // mask level 8 +#define SR_IMASK7 0x00008000 // mask level 7 +#define SR_IMASK6 0x0000C000 // mask level 6 +#define SR_IMASK5 0x0000E000 // mask level 5 +#define SR_IMASK4 0x0000F000 // mask level 4 +#define SR_IMASK3 0x0000F800 // mask level 3 +#define SR_IMASK2 0x0000FC00 // mask level 2 +#define SR_IMASK1 0x0000FE00 // mask level 1 +#define SR_IMASK0 0x0000FF00 // mask level 0 + +#define SR_IBIT8 0x00008000 // bit level 8 +#define SR_IBIT7 0x00004000 // bit level 7 +#define SR_IBIT6 0x00002000 // bit level 6 +#define SR_IBIT5 0x00001000 // bit level 5 +#define SR_IBIT4 0x00000800 // bit level 4 +#define SR_IBIT3 0x00000400 // bit level 3 +#define SR_IBIT2 0x00000200 // bit level 2 +#define SR_IBIT1 0x00000100 // bit level 1 + +#define SR_IMASKSHIFT 8 + +#define SR_KX 0x00000080 // extended-addr TLB vec in kernel +#define SR_SX 0x00000040 // xtended-addr TLB vec supervisor +#define SR_UX 0x00000020 // xtended-addr TLB vec in user mode +#define SR_KSU_MASK 0x00000018 // mode mask +#define SR_KSU_USR 0x00000010 // user mode +#define SR_KSU_SUP 0x00000008 // supervisor mode +#define SR_KSU_KER 0x00000000 // kernel mode +#define SR_ERL 0x00000004 // Error level, 1=>cache error +#define SR_EXL 0x00000002 // Exception level, 1=>exception +#define SR_IE 0x00000001 // interrupt enable, 1=>enable + +// Cause Register +#define CAUSE_BD 0x80000000 // Branch delay slot +#define CAUSE_CEMASK 0x30000000 // coprocessor error +#define CAUSE_CESHIFT 28 + +// Interrupt pending bits +#define CAUSE_IP8 0x00008000 // External level 8 pending - COMPARE +#define CAUSE_IP7 0x00004000 // External level 7 pending - INT4 +#define CAUSE_IP6 0x00002000 // External level 6 pending - INT3 +#define CAUSE_IP5 0x00001000 // External level 5 pending - INT2 +#define CAUSE_IP4 0x00000800 // External level 4 pending - INT1 +#define CAUSE_IP3 0x00000400 // External level 3 pending - INT0 +#define CAUSE_SW2 0x00000200 // Software level 2 pending +#define CAUSE_SW1 0x00000100 // Software level 1 pending + +#define CAUSE_IPMASK 0x0000FF00 // Pending interrupt mask +#define CAUSE_IPSHIFT 8 + +#define CAUSE_EXCMASK 0x0000007C // Cause code bits +#define CAUSE_EXCSHIFT 2 + +// Cause register exception codes + +#define EXC_CODE(x) ((x) << 2) + +// Hardware exception codes +#define EXC_INT EXC_CODE(0) // interrupt +#define EXC_MOD EXC_CODE(1) // TLB mod +#define EXC_RMISS EXC_CODE(2) // Read TLB Miss +#define EXC_WMISS EXC_CODE(3) // Write TLB Miss +#define EXC_RADE EXC_CODE(4) // Read Address Error +#define EXC_WADE EXC_CODE(5) // Write Address Error +#define EXC_IBE EXC_CODE(6) // Instruction Bus Error +#define EXC_DBE EXC_CODE(7) // Data Bus Error +#define EXC_SYSCALL EXC_CODE(8) // SYSCALL +#define EXC_BREAK EXC_CODE(9) // BREAKpoint +#define EXC_II EXC_CODE(10) // Illegal Instruction +#define EXC_CPU EXC_CODE(11) // CoProcessor Unusable +#define EXC_OV EXC_CODE(12) // OVerflow +#define EXC_TRAP EXC_CODE(13) // Trap exception +#define EXC_VCEI EXC_CODE(14) // Virt. Coherency on Inst. fetch +#define EXC_FPE EXC_CODE(15) // Floating Point Exception +#define EXC_WATCH EXC_CODE(23) // Watchpoint reference +#define EXC_VCED EXC_CODE(31) // Virt. Coherency on data read + +// C0_PRID Defines +#define C0_IMPMASK 0xFF00 +#define C0_IMPSHIFT 8 +#define C0_REVMASK 0xFF +#define C0_MAJREVMASK 0xF0 +#define C0_MAJREVSHIFT 4 +#define C0_MINREVMASK 0xF + +// Coprocessor 0 operations +#define C0_READI 0x1 // read ITLB entry addressed by C0_INDEX +#define C0_WRITEI 0x2 // write ITLB entry addressed by C0_INDEX +#define C0_WRITER 0x6 // write ITLB entry addressed by C0_RAND +#define C0_PROBE 0x8 // probe for ITLB entry addressed by TLBHI +#define C0_RFE 0x10 // restore for exception + +// 'cache' instruction definitions + +// Target cache +#define CACH_PI 0x0 // specifies primary inst. cache +#define CACH_PD 0x1 // primary data cache +#define CACH_SI 0x2 // secondary instruction cache +#define CACH_SD 0x3 // secondary data cache + +// Cache operations +#define C_IINV 0x0 // index invalidate (inst, 2nd inst) +#define C_IWBINV 0x0 // index writeback inval (d, sd) +#define C_ILT 0x4 // index load tag (all) +#define C_IST 0x8 // index store tag (all) +#define C_CDX 0xC // create dirty exclusive (d, sd) +#define C_HINV 0x10 // hit invalidate (all) +#define C_HWBINV 0x14 // hit writeback inv. (d, sd) +#define C_FILL 0x14 // fill (i) +#define C_HWB 0x18 // hit writeback (i, d, sd) +#define C_HSV 0x1C // hit set virt. (si, sd) + +// Cache size definitions +#define ICACHE_SIZE 0x4000 // 16K +#define ICACHE_LINESIZE 32 // 8 words +#define ICACHE_LINEMASK (ICACHE_LINESIZE - 1) + +#define DCACHE_SIZE 0x2000 // 8K +#define DCACHE_LINESIZE 16 // 4 words +#define DCACHE_LINEMASK (DCACHE_LINESIZE - 1) + +// C0_CONFIG register definitions +#define CONFIG_CM 0x80000000 // 1 == Master-Checker enabled +#define CONFIG_EC 0x70000000 // System Clock ratio +#define CONFIG_EC_1_1 0x6 // System Clock ratio 1 :1 +#define CONFIG_EC_3_2 0x7 // System Clock ratio 1.5 :1 +#define CONFIG_EC_2_1 0x0 // System Clock ratio 2 :1 +#define CONFIG_EC_3_1 0x1 // System Clock ratio 3 :1 +#define CONFIG_EP 0x0F000000 // Transmit Data Pattern +#define CONFIG_SB 0x00C00000 // Secondary cache block size + +#define CONFIG_SS 0x00200000 // Split scache: 0 == I&D combined +#define CONFIG_SW 0x00100000 // scache port: 0==128, 1==64 +#define CONFIG_EW 0x000C0000 // System Port width: 0==64, 1==32 +#define CONFIG_SC 0x00020000 // 0 -> 2nd cache present +#define CONFIG_SM 0x00010000 // 0 -> Dirty Shared Coherency enable +#define CONFIG_BE 0x00008000 // Endian-ness: 1 --> BE +#define CONFIG_EM 0x00004000 // 1 -> ECC mode, 0 -> parity +#define CONFIG_EB 0x00002000 // Block order:1->sequent,0->subblock + +#define CONFIG_IC 0x00000E00 // Primary Icache size +#define CONFIG_DC 0x000001C0 // Primary Dcache size +#define CONFIG_IB 0x00000020 // Icache block size +#define CONFIG_DB 0x00000010 // Dcache block size +#define CONFIG_CU 0x00000008 // Update on Store-conditional +#define CONFIG_K0 0x00000007 // K0SEG Coherency algorithm + +#define CONFIG_UNCACHED 0x00000002 // K0 is uncached +#define CONFIG_NONCOHRNT 0x00000003 +#define CONFIG_COHRNT_EXLWR 0x00000005 +#define CONFIG_SB_SHFT 22 // shift SB to bit position 0 +#define CONFIG_IC_SHFT 9 // shift IC to bit position 0 +#define CONFIG_DC_SHFT 6 // shift DC to bit position 0 +#define CONFIG_BE_SHFT 15 // shift BE to bit position 0 + +// C0_TAGLO definitions for setting/getting cache states and physaddr bits +#define SADDRMASK 0xFFFFE000 // 31..13 -> scache paddr bits 35..17 +#define SVINDEXMASK 0x00000380 // 9..7: prim virt index bits 14..12 +#define SSTATEMASK 0x00001C00 // bits 12..10 hold scache line state +#define SINVALID 0x00000000 // invalid --> 000 == state 0 +#define SCLEANEXCL 0x00001000 // clean exclusive --> 100 == state 4 +#define SDIRTYEXCL 0x00001400 // dirty exclusive --> 101 == state 5 +#define SECC_MASK 0x0000007F // low 7 bits are ecc for the tag +#define SADDR_SHIFT 4 // shift STagLo (31..13) to 35..17 + +#define PADDRMASK 0xFFFFFF00 // PTagLo31..8->prim paddr bits35..12 +#define PADDR_SHIFT 4 // roll bits 35..12 down to 31..8 +#define PSTATEMASK 0x00C0 // bits 7..6 hold primary line state +#define PINVALID 0x0000 // invalid --> 000 == state 0 +#define PCLEANEXCL 0x0080 // clean exclusive --> 10 == state 2 +#define PDIRTYEXCL 0x00C0 // dirty exclusive --> 11 == state 3 +#define PPARITY_MASK 0x0001 // low bit is parity bit (even). + +// C0_CACHE_ERR definitions. +#define CACHERR_ER 0x80000000 // 0: inst ref, 1: data ref +#define CACHERR_EC 0x40000000 // 0: primary, 1: secondary +#define CACHERR_ED 0x20000000 // 1: data error +#define CACHERR_ET 0x10000000 // 1: tag error +#define CACHERR_ES 0x08000000 // 1: external ref, e.g. snoo +#define CACHERR_EE 0x04000000 // error on SysAD bus +#define CACHERR_EB 0x02000000 // complicated, see spec. +#define CACHERR_EI 0x01000000 // complicated, see spec. +#define CACHERR_SIDX_MASK 0x003FFFF8 // secondary cache index +#define CACHERR_PIDX_MASK 0x00000007 // primary cache index +#define CACHERR_PIDX_SHIFT 12 // bits 2..0 are paddr14..12 + +/* + * R4000 family supports hardware watchpoints: + * C0_WATCHLO: + * bits 31..3 are bits 31..3 of physaddr to watch + * bit 2: reserved; must be written as 0. + * bit 1: when set causes a watchpoint trap on load accesses to paddr. + * bit 0: when set traps on stores to paddr; + * C0_WATCHHI + * bits 31..4 are reserved and must be written as zeros. + * bits 3..0 are bits 35..32 of the physaddr to watch + */ +#define WATCHLO_WTRAP 0x00000001 +#define WATCHLO_RTRAP 0x00000002 +#define WATCHLO_ADDRMASK 0xFFFFFFF8 +#define WATCHLO_VALIDMASK 0xFFFFFFFB +#define WATCHHI_VALIDMASK 0x0000000F + +// Coprocessor 0 registers +#define C0_INX C_REG(0) +#define C0_RAND C_REG(1) +#define C0_ENTRYLO0 C_REG(2) +#define C0_ENTRYLO1 C_REG(3) +#define C0_CONTEXT C_REG(4) +#define C0_PAGEMASK C_REG(5) // page mask +#define C0_WIRED C_REG(6) // # wired entries in tlb +#define C0_BADVADDR C_REG(8) +#define C0_COUNT C_REG(9) // free-running counter +#define C0_ENTRYHI C_REG(10) +#define C0_COMPARE C_REG(11) // counter comparison reg. +#define C0_SR C_REG(12) +#define C0_CAUSE C_REG(13) +#define C0_EPC C_REG(14) +#define C0_PRID C_REG(15) // revision identifier +#define C0_CONFIG C_REG(16) // hardware configuration +#define C0_LLADDR C_REG(17) // load linked address +#define C0_WATCHLO C_REG(18) // watchpoint +#define C0_WATCHHI C_REG(19) // watchpoint +#define C0_ECC C_REG(26) // S-cache ECC and primary parity +#define C0_CACHE_ERR C_REG(27) // cache error status +#define C0_TAGLO C_REG(28) // cache operations +#define C0_TAGHI C_REG(29) // cache operations +#define C0_ERROR_EPC C_REG(30) // ECC error prg. counter + +// floating-point status register +#define C1_FPCSR C_REG(31) + +#define FPCSR_FS 0x01000000 // flush denorm to zero +#define FPCSR_C 0x00800000 // condition bit +#define FPCSR_CE 0x00020000 // cause: unimplemented operation +#define FPCSR_CV 0x00010000 // cause: invalid operation +#define FPCSR_CZ 0x00008000 // cause: division by zero +#define FPCSR_CO 0x00004000 // cause: overflow +#define FPCSR_CU 0x00002000 // cause: underflow +#define FPCSR_CI 0x00001000 // cause: inexact operation +#define FPCSR_EV 0x00000800 // enable: invalid operation +#define FPCSR_EZ 0x00000400 // enable: division by zero +#define FPCSR_EO 0x00000200 // enable: overflow +#define FPCSR_EU 0x00000100 // enable: underflow +#define FPCSR_EI 0x00000080 // enable: inexact operation +#define FPCSR_FV 0x00000040 // flag: invalid operation +#define FPCSR_FZ 0x00000020 // flag: division by zero +#define FPCSR_FO 0x00000010 // flag: overflow +#define FPCSR_FU 0x00000008 // flag: underflow +#define FPCSR_FI 0x00000004 // flag: inexact operation +#define FPCSR_RM_MASK 0x00000003 // rounding mode mask +#define FPCSR_RM_RN 0x00000000 // round to nearest +#define FPCSR_RM_RZ 0x00000001 // round to zero +#define FPCSR_RM_RP 0x00000002 // round to positive infinity +#define FPCSR_RM_RM 0x00000003 // round to negative infinity diff --git a/libultraship/include/libultraship/libultra/rcp.h b/libultraship/include/libultraship/libultra/rcp.h new file mode 100644 index 000000000..8f3ac31fd --- /dev/null +++ b/libultraship/include/libultraship/libultra/rcp.h @@ -0,0 +1,269 @@ +#pragma once + +/** + * PIF Physical memory map (total size = 2 KB) + * + * Size Description Mode + * 1FC007FF +-------+-----------------+-----+ + * | 64 B | JoyChannel RAM | R/W | + * 1FC007C0 +-------+-----------------+-----+ + * |1984 B | Boot ROM | * | * = Reserved + * 1FC00000 +-------+-----------------+-----+ + */ +#define PIF_ROM_START 0x1FC00000 +#define PIF_ROM_END 0x1FC007BF +#define PIF_RAM_START 0x1FC007C0 +#define PIF_RAM_END 0x1FC007FF + +/* + * Patterns to interpret VI_CONTROL_REG + */ +#define VI_CTRL_TYPE_16 0x00002 /* [1:0] pixel size: 16 bit */ +#define VI_CTRL_TYPE_32 0x00003 /* [1:0] pixel size: 32 bit */ +#define VI_CTRL_GAMMA_DITHER_ON 0x00004 /* 2: default = on */ +#define VI_CTRL_GAMMA_ON 0x00008 /* 3: default = on */ +#define VI_CTRL_DIVOT_ON 0x00010 /* 4: default = on */ +#define VI_CTRL_SERRATE_ON 0x00040 /* 6: on if interlaced */ +#define VI_CTRL_ANTIALIAS_MASK 0x00300 /* [9:8] anti-alias mode */ +#define VI_CTRL_ANTIALIAS_MODE_1 0x00100 /* Bit [9:8] anti-alias mode */ +#define VI_CTRL_ANTIALIAS_MODE_2 0x00200 /* Bit [9:8] anti-alias mode */ +#define VI_CTRL_ANTIALIAS_MODE_3 0x00300 /* Bit [9:8] anti-alias mode */ +#define VI_CTRL_PIXEL_ADV_MASK 0x01000 /* [15:12] pixel advance mode? */ +#define VI_CTRL_PIXEL_ADV_1 0x01000 /* Bit [15:12] pixel advance mode? */ +#define VI_CTRL_PIXEL_ADV_2 0x02000 /* Bit [15:12] pixel advance mode? */ +#define VI_CTRL_PIXEL_ADV_3 0x03000 /* Bit [15:12] pixel advance mode? */ +#define VI_CTRL_DITHER_FILTER_ON 0x10000 /* 16: dither-filter mode */ + +#define VI_NTSC_CLOCK 48681812 /* Hz = 48.681812 MHz */ +#define VI_PAL_CLOCK 49656530 /* Hz = 49.656530 MHz */ +#define VI_MPAL_CLOCK 48628316 /* Hz = 48.628316 MHz */ + +/** + * Audio Interface (AI) Registers + */ +#define AI_BASE_REG 0x04500000 + +/* AI DRAM address (W): [23:0] starting RDRAM address (8B-aligned) */ +#define AI_DRAM_ADDR_REG (AI_BASE_REG + 0x00) /* R0: DRAM address */ + +/* AI length (R/W): [14:0] transfer length (v1.0) - Bottom 3 bits are ignored */ +/* [17:0] transfer length (v2.0) - Bottom 3 bits are ignored */ +#define AI_LEN_REG (AI_BASE_REG + 0x04) /* R1: Length */ + +/* AI control (W): [0] DMA enable - if LSB == 1, DMA is enabled */ +#define AI_CONTROL_REG (AI_BASE_REG + 0x08) /* R2: DMA Control */ + +/* Value for control register */ +#define AI_CONTROL_DMA_ON 1 /* LSB = 1: DMA enable*/ +#define AI_CONTROL_DMA_OFF 0 /* LSB = 1: DMA enable*/ + +/* + * AI status (R): [31]/[0] ai_full (addr & len buffer full), [30] ai_busy + * Note that a 1->0 transition in ai_full will set interrupt + * (W): clear audio interrupt + */ +#define AI_STATUS_REG (AI_BASE_REG + 0x0C) /* R3: Status */ + +/* Value for status register */ +#define AI_STATUS_FIFO_FULL (1 << 31) +#define AI_STATUS_DMA_BUSY (1 << 30) + +/* + * AI DAC sample period register (W): [13:0] dac rate + * - vid_clock/(dperiod + 1) is the DAC sample rate + * - (dperiod + 1) >= 66 * (aclockhp + 1) must be true + */ +#define AI_DACRATE_REG (AI_BASE_REG + 0x10) /* R4: DAC rate 14-lsb*/ + +/* DAC rate = video clock / audio frequency + * - DAC rate >= (66 * Bit rate) must be true + */ +#define AI_MAX_DAC_RATE 16384 /* 14-bit+1 */ +#define AI_MIN_DAC_RATE 132 + +/* + * AI bit rate (W): [3:0] bit rate (abus clock half period register - aclockhp) + * - vid_clock/(2 * (aclockhp + 1)) is the DAC clock rate + * - The abus clock stops if aclockhp is zero + */ +#define AI_BITRATE_REG (AI_BASE_REG + 0x14) /* R5: Bit rate 4-lsb */ + +/* Bit rate <= (DAC rate / 66) */ +#define AI_MAX_BIT_RATE 16 /* 4-bit+1 */ +#define AI_MIN_BIT_RATE 2 + +#define CHNL_ERR_NORESP 0x80 /* Bit 7 (Rx): No response error */ +#define CHNL_ERR_OVERRUN 0x40 /* Bit 6 (Rx): Overrun error */ +#define CHNL_ERR_FRAME 0x80 /* Bit 7 (Tx): Frame error */ +#define CHNL_ERR_COLLISION 0x40 /* Bit 6 (Tx): Collision error */ + +#define CHNL_ERR_MASK 0xC0 /* Bit 6-7: channel errors */ + +#define DEVICE_TYPE_CART 0 /* ROM cartridge */ +#define DEVICE_TYPE_BULK 1 /* ROM bulk */ +#define DEVICE_TYPE_64DD 2 /* 64 Disk Drive */ +#define DEVICE_TYPE_SRAM 3 /* SRAM */ +#define DEVICE_TYPE_INIT 7 /* initial value */ + +/** + * Signal Processor (SP) Memory + */ +#define SP_DMEM_START 0x04000000 +#define SP_DMEM_END 0x04000FFF +#define SP_IMEM_START 0x04001000 +#define SP_IMEM_END 0x04001FFF + +#define SP_MEM_ADDR_REG 0x04040000 +#define SP_DRAM_ADDR_REG 0x04040004 +#define SP_RD_LEN_REG 0x04040008 +#define SP_WR_LEN_REG 0x0404000C +#define SP_STATUS_REG 0x04040010 +#define SP_DMA_FULL_REG 0x04040014 +#define SP_DMA_BUSY_REG 0x04040018 +#define SP_PC_REG 0x04080000 + +/** + * SP_STATUS_REG: write bits + */ +#define SP_CLR_HALT (1 << 0) +#define SP_SET_HALT (1 << 1) +#define SP_CLR_BROKE (1 << 2) +#define SP_CLR_INTR (1 << 3) +#define SP_SET_INTR (1 << 4) +#define SP_CLR_SSTEP (1 << 5) +#define SP_SET_SSTEP (1 << 6) +#define SP_CLR_INTR_BREAK (1 << 7) +#define SP_SET_INTR_BREAK (1 << 8) +#define SP_CLR_SIG0 (1 << 9) +#define SP_SET_SIG0 (1 << 10) +#define SP_CLR_SIG1 (1 << 11) +#define SP_SET_SIG1 (1 << 12) +#define SP_CLR_SIG2 (1 << 13) +#define SP_SET_SIG2 (1 << 14) +#define SP_CLR_SIG3 (1 << 15) +#define SP_SET_SIG3 (1 << 16) +#define SP_CLR_SIG4 (1 << 17) +#define SP_SET_SIG4 (1 << 18) +#define SP_CLR_SIG5 (1 << 19) +#define SP_SET_SIG5 (1 << 20) +#define SP_CLR_SIG6 (1 << 21) +#define SP_SET_SIG6 (1 << 22) +#define SP_CLR_SIG7 (1 << 23) +#define SP_SET_SIG7 (1 << 24) + +/* + * SP_STATUS_REG: read bits + */ +#define SP_STATUS_HALT (1 << 0) +#define SP_STATUS_BROKE (1 << 1) +#define SP_STATUS_DMA_BUSY (1 << 2) +#define SP_STATUS_DMA_FULL (1 << 3) +#define SP_STATUS_IO_FULL (1 << 4) +#define SP_STATUS_SSTEP (1 << 5) +#define SP_STATUS_INTR_BREAK (1 << 6) +#define SP_STATUS_SIG0 (1 << 7) +#define SP_STATUS_SIG1 (1 << 8) +#define SP_STATUS_SIG2 (1 << 9) +#define SP_STATUS_SIG3 (1 << 10) +#define SP_STATUS_SIG4 (1 << 11) +#define SP_STATUS_SIG5 (1 << 12) +#define SP_STATUS_SIG6 (1 << 13) +#define SP_STATUS_SIG7 (1 << 14) + +/** + * SP_STATUS_REG: use of SIG bits + */ +#define SP_CLR_YIELD SP_CLR_SIG0 +#define SP_SET_YIELD SP_SET_SIG0 +#define SP_STATUS_YIELD SP_STATUS_SIG0 +#define SP_CLR_YIELDED SP_CLR_SIG1 +#define SP_SET_YIELDED SP_SET_SIG1 +#define SP_STATUS_YIELDED SP_STATUS_SIG1 +#define SP_CLR_TASKDONE SP_CLR_SIG2 +#define SP_SET_TASKDONE SP_SET_SIG2 +#define SP_STATUS_TASKDONE SP_STATUS_SIG2 +#define SP_CLR_RSPSIGNAL SP_CLR_SIG3 +#define SP_SET_RSPSIGNAL SP_SET_SIG3 +#define SP_STATUS_RSPSIGNAL SP_STATUS_SIG3 +#define SP_CLR_CPUSIGNAL SP_CLR_SIG4 +#define SP_SET_CPUSIGNAL SP_SET_SIG4 +#define SP_STATUS_CPUSIGNAL SP_STATUS_SIG4 + +#define VI_STATUS_REG 0x04400000 +#define VI_CONTROL_REG 0x04400000 +#define VI_ORIGIN_REG 0x04400004 +#define VI_DRAM_ADDR_REG 0x04400004 +#define VI_WIDTH_REG 0x04400008 +#define VI_H_WIDTH_REG 0x04400008 +#define VI_INTR_REG 0x0440000C +#define VI_V_INTER_REG 0x0440000C +#define VI_CURRENT_REG 0x04400010 +#define VI_V_CURRENT_LINE_REG 0x04400010 +#define VI_BURST_REG 0x04400014 +#define VI_TIMING_REG 0x04400014 +#define VI_V_SYNC_REG 0x04400018 // VI vertical sync +#define VI_H_SYNC_REG 0x0440001C // VI horizontal sync +#define VI_LEAP_REG 0x04400020 // VI horizontal sync leap +#define VI_H_SYNC_LEAP_REG 0x04400020 +#define VI_H_START_REG 0x04400024 // VI horizontal video +#define VI_H_VIDEO_REG 0x04400024 +#define VI_V_START_REG 0x04400028 // VI vertical video +#define VI_V_VIDEO_REG 0x04400028 +#define VI_V_BURST_REG 0x0440002C // VI vertical burst +#define VI_X_SCALE_REG 0x04400030 // VI x-scale +#define VI_Y_SCALE_REG 0x04400034 // VI y-scale + +#define PI_DRAM_ADDR_REG 0x04600000 // PI DRAM address +#define PI_CART_ADDR_REG 0x04600004 // PI pbus (cartridge) address +#define PI_RD_LEN_REG 0x04600008 // PI read length +#define PI_WR_LEN_REG 0x0460000C // PI write length +#define PI_STATUS_REG 0x04600010 // PI status +#define PI_BSD_DOM1_LAT_REG 0x04600014 // PI dom1 latency +#define PI_DOMAIN1_REG 0x04600014 +#define PI_BSD_DOM1_PWD_REG 0x04600018 // PI dom1 pulse width +#define PI_BSD_DOM1_PGS_REG 0x0460001C // PI dom1 page size +#define PI_BSD_DOM1_RLS_REG 0x04600020 // PI dom1 release +#define PI_BSD_DOM2_LAT_REG 0x04600024 // PI dom2 latency +#define PI_DOMAIN2_REG 0x04600024 +#define PI_BSD_DOM2_PWD_REG 0x04600028 // PI dom2 pulse width +#define PI_BSD_DOM2_PGS_REG 0x0460002C // PI dom2 page size +#define PI_BSD_DOM2_RLS_REG 0x04600030 // PI dom2 release + +#define PI_STATUS_DMA_BUSY (1 << 0) +#define PI_STATUS_IO_BUSY (1 << 1) +#define PI_STATUS_ERROR (1 << 2) + +/* + * PI_STATUS_REG: write bits + */ +#define PI_STATUS_RESET (1 << 0) +#define PI_SET_RESET PI_STATUS_RESET + +#define PI_STATUS_CLR_INTR (1 << 1) +#define PI_CLR_INTR PI_STATUS_CLR_INTR + +#define PI_DMA_BUFFER_SIZE 128 + +#define PI_DOM1_ADDR1 0x06000000 /* to 0x07FFFFFF */ +#define PI_DOM1_ADDR2 0x10000000 /* to 0x1FBFFFFF */ +#define PI_DOM1_ADDR3 0x1FD00000 /* to 0x7FFFFFFF */ +#define PI_DOM2_ADDR1 0x05000000 /* to 0x05FFFFFF */ +#define PI_DOM2_ADDR2 0x08000000 /* to 0x0FFFFFFF */ + +/** + * Serial Interface (SI) Registers + */ +#define SI_BASE_REG 0x04800000 + +#define SI_DRAM_ADDR_REG (SI_BASE_REG + 0x00) +#define SI_PIF_ADDR_RD64B_REG (SI_BASE_REG + 0x04) +#define SI_PIF_ADDR_WR64B_REG (SI_BASE_REG + 0x10) +#define SI_STATUS_REG (SI_BASE_REG + 0x18) + +#define SI_STATUS_DMA_BUSY (1 << 0) +#define SI_STATUS_IO_READ_BUSY (1 << 1) +#define SI_STATUS_DMA_ERROR (1 << 3) +#define SI_STATUS_INTERRUPT (1 << 12) + +#define IO_READ(addr) (*(vu32*)PHYS_TO_K1(addr)) +#define IO_WRITE(addr, data) (*(vu32*)PHYS_TO_K1(addr) = (u32)(data)) diff --git a/libultraship/include/libultraship/libultra/rdp.h b/libultraship/include/libultraship/libultra/rdp.h new file mode 100644 index 000000000..6921ce581 --- /dev/null +++ b/libultraship/include/libultraship/libultra/rdp.h @@ -0,0 +1,48 @@ +#pragma once + +/* DP Command Registers */ + +#define DPC_REG_BASE 0xA4100000 + +#define DPC_START_REG (*(vu32*)(DPC_REG_BASE + 0x00)) +#define DPC_END_REG (*(vu32*)(DPC_REG_BASE + 0x04)) +#define DPC_CURRENT_REG (*(vu32*)(DPC_REG_BASE + 0x08)) +#define DPC_STATUS_REG (*(vu32*)(DPC_REG_BASE + 0x0C)) +#define DPC_CLOCK_REG (*(vu32*)(DPC_REG_BASE + 0x10)) +#define DPC_BUFBUSY_REG (*(vu32*)(DPC_REG_BASE + 0x14)) +#define DPC_PIPEBUSY_REG (*(vu32*)(DPC_REG_BASE + 0x18)) +#define DPC_TMEM_REG (*(vu32*)(DPC_REG_BASE + 0x1C)) + +/* DP Span Registers */ + +#define DPS_REG_BASE 0xA4200000 + +#define DPS_TBIST_REG (*(vu32*)(DPS_REG_BASE + 0x00)) +#define DPS_TEST_MODE_REG (*(vu32*)(DPS_REG_BASE + 0x04)) +#define DPS_BUFTEST_ADDR_REG (*(vu32*)(DPS_REG_BASE + 0x08)) +#define DPS_BUFTEST_DATA_REG (*(vu32*)(DPS_REG_BASE + 0x0C)) + +/* DP Status Read Flags */ +#define DPC_STATUS_XBUS_DMEM_DMA 0x001 +#define DPC_STATUS_FREEZE 0x002 +#define DPC_STATUS_FLUSH 0x004 +#define DPC_STATUS_START_GCLK 0x008 +#define DPC_STATUS_TMEM_BUSY 0x010 +#define DPC_STATUS_PIPE_BUSY 0x020 +#define DPC_STATUS_CMD_BUSY 0x040 +#define DPC_STATUS_CBUF_READY 0x080 +#define DPC_STATUS_DMA_BUSY 0x100 +#define DPC_STATUS_END_VALID 0x200 +#define DPC_STATUS_START_VALID 0x400 + +/* DP Status Write Flags */ +#define DPC_CLR_XBUS_DMEM_DMA 0x0001 +#define DPC_SET_XBUS_DMEM_DMA 0x0002 +#define DPC_CLR_FREEZE 0x0004 +#define DPC_SET_FREEZE 0x0008 +#define DPC_CLR_FLUSH 0x0010 +#define DPC_SET_FLUSH 0x0020 +#define DPC_CLR_TMEM_CTR 0x0040 +#define DPC_CLR_PIPE_CTR 0x0080 +#define DPC_CLR_CMD_CTR 0x0100 +#define DPC_CLR_CLOCK_CTR 0x0200 diff --git a/libultraship/include/libultraship/libultra/sptask.h b/libultraship/include/libultraship/libultra/sptask.h new file mode 100644 index 000000000..fa74dc921 --- /dev/null +++ b/libultraship/include/libultraship/libultra/sptask.h @@ -0,0 +1,65 @@ +#pragma once + +#include "types.h" + +/* Task Types */ +#define M_NULTASK 0 +#define M_GFXTASK 1 +#define M_AUDTASK 2 +#define M_VIDTASK 3 +#define M_NJPEGTASK 4 +#define M_HVQTASK 6 +#define M_HVQMTASK 7 + +/* Task Flags */ +#define M_TASK_FLAG0 1 +#define M_TASK_FLAG1 2 + +/* Task Flag Fields */ +#define OS_TASK_YIELDED 0x0001 +#define OS_TASK_DP_WAIT 0x0002 +#define OS_TASK_LOADABLE 0x0004 +#define OS_TASK_SP_ONLY 0x0008 +#define OS_TASK_USR0 0x0010 +#define OS_TASK_USR1 0x0020 +#define OS_TASK_USR2 0x0040 +#define OS_TASK_USR3 0x0080 + +#define OS_YIELD_DATA_SIZE 0xC00 + +typedef struct { + /* 0x00 */ u32 type; + /* 0x04 */ u32 flags; + + /* 0x08 */ u64* ucode_boot; + /* 0x0C */ u32 ucode_boot_size; + + /* 0x10 */ u64* ucode; + /* 0x14 */ u32 ucode_size; + + /* 0x18 */ u64* ucode_data; + /* 0x1C */ u32 ucode_data_size; + + /* 0x20 */ u64* dram_stack; + /* 0x24 */ u32 dram_stack_size; + + /* 0x28 */ u64* output_buff; + /* 0x2C */ u64* output_buff_size; + + /* 0x30 */ u64* data_ptr; + /* 0x34 */ u32 data_size; + + /* 0x38 */ u64* yield_data_ptr; + /* 0x3C */ u32 yield_data_size; +} OSTask_t; // size = 0x40 + +typedef union { + OSTask_t t; + long long int force_structure_alignment; +} OSTask; + +typedef u32 OSYieldResult; + +#define osSpTaskStart(p) \ + osSpTaskLoad(p); \ + osSpTaskStartGo(p); diff --git a/libultraship/include/libultraship/libultra/thread.h b/libultraship/include/libultraship/libultra/thread.h new file mode 100644 index 000000000..75ced5a75 --- /dev/null +++ b/libultraship/include/libultraship/libultra/thread.h @@ -0,0 +1,61 @@ +#pragma once + +#include "types.h" + +#define OS_PRIORITY_MAX 255 +#define OS_PRIORITY_VIMGR 254 +#define OS_PRIORITY_RMON 250 +#define OS_PRIORITY_RMONSPIN 200 +#define OS_PRIORITY_PIMGR 150 +#define OS_PRIORITY_SIMGR 140 +#define OS_PRIORITY_APPMAX 127 +#define OS_PRIORITY_IDLE 0 + +#define OS_STATE_STOPPED 1 +#define OS_STATE_RUNNABLE 2 +#define OS_STATE_RUNNING 4 +#define OS_STATE_WAITING 8 + +#define OS_FLAG_CPU_BREAK 1 +#define OS_FLAG_FAULT 2 + +typedef s32 OSPri; +typedef s32 OSId; + +typedef union { + struct { + /* 0x00 */ f32 f_odd; + /* 0x04 */ f32 f_even; + } f; +} __OSfp; // size = 0x08 + +typedef struct { + /* 0x000 */ u64 at, v0, v1, a0, a1, a2, a3; + /* 0x038 */ u64 t0, t1, t2, t3, t4, t5, t6, t7; + /* 0x078 */ u64 s0, s1, s2, s3, s4, s5, s6, s7; + /* 0x0B8 */ u64 t8, t9, gp, sp, s8, ra; + /* 0x0E8 */ u64 lo, hi; + /* 0x0F8 */ u32 sr, pc, cause, badvaddr, rcp; + /* 0x10C */ u32 fpcsr; + /* 0x110 */ __OSfp fp0, fp2, fp4, fp6, fp8, fp10, fp12, fp14; + /* 0x150 */ __OSfp fp16, fp18, fp20, fp22, fp24, fp26, fp28, fp30; +} __OSThreadContext; // size = 0x190 + +typedef struct { + /* 0x00 */ u32 flag; + /* 0x04 */ u32 count; + /* 0x08 */ u64 time; +} __OSThreadprofile; // size = 0x10 + +typedef struct OSThread { + /* 0x00 */ struct OSThread* next; + /* 0x04 */ OSPri priority; + /* 0x08 */ struct OSThread** queue; + /* 0x0C */ struct OSThread* tlnext; + /* 0x10 */ u16 state; + /* 0x12 */ u16 flags; + /* 0x14 */ OSId id; + /* 0x18 */ s32 fp; + /* 0x1C */ __OSThreadprofile* thprof; + /* 0x20 */ __OSThreadContext context; +} OSThread; // size = 0x1B0 diff --git a/libultraship/include/libultraship/libultra/time.h b/libultraship/include/libultraship/libultra/time.h new file mode 100644 index 000000000..6241eb05a --- /dev/null +++ b/libultraship/include/libultraship/libultra/time.h @@ -0,0 +1,14 @@ +#pragma once + +#include "message.h" + +typedef u64 OSTime; + +typedef struct OSTimer { + /* 0x00 */ struct OSTimer* next; + /* 0x04 */ struct OSTimer* prev; + /* 0x08 */ OSTime interval; + /* 0x10 */ OSTime value; + /* 0x18 */ OSMesgQueue* mq; + /* 0x1C */ OSMesg msg; +} OSTimer; // size = 0x20 diff --git a/libultraship/include/libultraship/libultra/types.h b/libultraship/include/libultraship/libultra/types.h new file mode 100644 index 000000000..3bdb4d31c --- /dev/null +++ b/libultraship/include/libultraship/libultra/types.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include +#include + +typedef signed char s8; +typedef unsigned char u8; +typedef signed short int s16; +typedef unsigned short int u16; +typedef signed int s32; +typedef unsigned int u32; +typedef signed long long int s64; +typedef unsigned long long int u64; + +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; +#if 0 + +typedef s32 ptrdiff_t; +typedef s32 intptr_t; +typedef u32 uintptr_t; +#endif diff --git a/libultraship/include/libultraship/libultra/vi.h b/libultraship/include/libultraship/libultra/vi.h new file mode 100644 index 000000000..1b50f3d92 --- /dev/null +++ b/libultraship/include/libultraship/libultra/vi.h @@ -0,0 +1,134 @@ +#pragma once + +#include "message.h" + +/* Special Features */ +#define OS_VI_GAMMA_ON 0x0001 +#define OS_VI_GAMMA_OFF 0x0002 +#define OS_VI_GAMMA_DITHER_ON 0x0004 +#define OS_VI_GAMMA_DITHER_OFF 0x0008 +#define OS_VI_DIVOT_ON 0x0010 +#define OS_VI_DIVOT_OFF 0x0020 +#define OS_VI_DITHER_FILTER_ON 0x0040 +#define OS_VI_DITHER_FILTER_OFF 0x0080 + +#define OS_VI_GAMMA 0x08 +#define OS_VI_GAMMA_DITHER 0x04 +#define OS_VI_DIVOT 0x10 +#define OS_VI_DITHER_FILTER 0x10000 +#define OS_VI_UNK1 0x1 +#define OS_VI_UNK2 0x2 +#define OS_VI_UNK40 0x40 +#define OS_VI_UNK100 0x100 +#define OS_VI_UNK200 0x200 +#define OS_VI_UNK1000 0x1000 +#define OS_VI_UNK2000 0x2000 + +typedef struct { + /* 0x00 */ u32 ctrl; + /* 0x04 */ u32 width; + /* 0x08 */ u32 burst; + /* 0x0C */ u32 vSync; + /* 0x10 */ u32 hSync; + /* 0x14 */ u32 leap; + /* 0x18 */ u32 hStart; + /* 0x1C */ u32 xScale; + /* 0x20 */ u32 vCurrent; +} OSViCommonRegs; // size = 0x20 + +typedef struct { + /* 0x00 */ u32 origin; + /* 0x04 */ u32 yScale; + /* 0x08 */ u32 vStart; + /* 0x0C */ u32 vBurst; + /* 0x10 */ u32 vIntr; +} OSViFieldRegs; // size = 0x14 + +typedef struct { + /* 0x00 */ u8 type; + /* 0x04 */ OSViCommonRegs comRegs; + /* 0x24 */ OSViFieldRegs fldRegs[2]; +} OSViMode; // size = 0x4C + +typedef struct { + /* 0x0 */ f32 factor; + /* 0x4 */ u16 offset; + /* 0x8 */ u32 scale; +} __OSViScale; // size = 0x0C + +typedef struct { + /* 0x00 */ u16 state; + /* 0x02 */ u16 retraceCount; + /* 0x04 */ void* buffer; + /* 0x08 */ OSViMode* modep; + /* 0x0C */ u32 features; + /* 0x10 */ OSMesgQueue* mq; + /* 0x14 */ OSMesg* msg; + /* 0x18 */ __OSViScale x; + /* 0x24 */ __OSViScale y; +} OSViContext; // size = 0x30 + +#define OS_VI_NTSC_LPN1 0 /* NTSC */ +#define OS_VI_NTSC_LPF1 1 +#define OS_VI_NTSC_LAN1 2 +#define OS_VI_NTSC_LAF1 3 +#define OS_VI_NTSC_LPN2 4 +#define OS_VI_NTSC_LPF2 5 +#define OS_VI_NTSC_LAN2 6 +#define OS_VI_NTSC_LAF2 7 +#define OS_VI_NTSC_HPN1 8 +#define OS_VI_NTSC_HPF1 9 +#define OS_VI_NTSC_HAN1 10 +#define OS_VI_NTSC_HAF1 11 +#define OS_VI_NTSC_HPN2 12 +#define OS_VI_NTSC_HPF2 13 + +#define OS_VI_PAL_LPN1 14 /* PAL */ +#define OS_VI_PAL_LPF1 15 +#define OS_VI_PAL_LAN1 16 +#define OS_VI_PAL_LAF1 17 +#define OS_VI_PAL_LPN2 18 +#define OS_VI_PAL_LPF2 19 +#define OS_VI_PAL_LAN2 20 +#define OS_VI_PAL_LAF2 21 +#define OS_VI_PAL_HPN1 22 +#define OS_VI_PAL_HPF1 23 +#define OS_VI_PAL_HAN1 24 +#define OS_VI_PAL_HAF1 25 +#define OS_VI_PAL_HPN2 26 +#define OS_VI_PAL_HPF2 27 + +#define OS_VI_MPAL_LPN1 28 /* MPAL - mainly Brazil */ +#define OS_VI_MPAL_LPF1 29 +#define OS_VI_MPAL_LAN1 30 +#define OS_VI_MPAL_LAF1 31 +#define OS_VI_MPAL_LPN2 32 +#define OS_VI_MPAL_LPF2 33 +#define OS_VI_MPAL_LAN2 34 +#define OS_VI_MPAL_LAF2 35 +#define OS_VI_MPAL_HPN1 36 +#define OS_VI_MPAL_HPF1 37 +#define OS_VI_MPAL_HAN1 38 +#define OS_VI_MPAL_HAF1 39 +#define OS_VI_MPAL_HPN2 40 +#define OS_VI_MPAL_HPF2 41 + +#define OS_VI_FPAL_LPN1 42 /* FPAL - Full screen PAL */ +#define OS_VI_FPAL_LPF1 43 +#define OS_VI_FPAL_LAN1 44 +#define OS_VI_FPAL_LAF1 45 +#define OS_VI_FPAL_LPN2 46 +#define OS_VI_FPAL_LPF2 47 +#define OS_VI_FPAL_LAN2 48 +#define OS_VI_FPAL_LAF2 49 +#define OS_VI_FPAL_HPN1 50 +#define OS_VI_FPAL_HPF1 51 +#define OS_VI_FPAL_HAN1 52 +#define OS_VI_FPAL_HAF1 53 +#define OS_VI_FPAL_HPN2 54 +#define OS_VI_FPAL_HPF2 55 + +#define OS_TV_PAL 0 +#define OS_TV_NTSC 1 +#define OS_TV_MPAL 2 +#define OS_VI_UNK28 28 diff --git a/libultraship/include/libultraship/libultraship.h b/libultraship/include/libultraship/libultraship.h new file mode 100644 index 000000000..e01d10e50 --- /dev/null +++ b/libultraship/include/libultraship/libultraship.h @@ -0,0 +1,10 @@ +#pragma once + +#include "libultra.h" +#include "bridge.h" +#include "color.h" +#include "luslog.h" + +#ifdef __cplusplus +#include "classes.h" +#endif diff --git a/libultraship/include/libultraship/log/luslog.h b/libultraship/include/libultraship/log/luslog.h new file mode 100644 index 000000000..d02134fc2 --- /dev/null +++ b/libultraship/include/libultraship/log/luslog.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include "ship/Api.h" + +// NOLINTBEGIN(readability-identifier-naming) + +/** + * @brief Writes a plain message to the Ship log at the given level. + * + * This is the low-level logging function. Prefer the LUSLOG_* convenience macros + * which automatically capture @c __FILE__ and @c __LINE__. + * + * @param file Source file name (typically @c __FILE__). + * @param line Source line number (typically @c __LINE__). + * @param logLevel Severity level (one of the LUSLOG_LEVEL_* constants). + * @param msg Null-terminated message string. + */ +API_EXPORT void luslog(const char* file, int32_t line, int32_t logLevel, const char* msg); + +/** + * @brief Formats and writes a message to the Ship log at the given level. + * + * Prefer the LUSLOG_* convenience macros which automatically capture @c __FILE__ + * and @c __LINE__. + * + * @param file Source file name (typically @c __FILE__). + * @param line Source line number (typically @c __LINE__). + * @param logLevel Severity level (one of the LUSLOG_LEVEL_* constants). + * @param fmt printf-style format string. + * @param ... Format arguments. + */ +API_EXPORT void lusprintf(const char* file, int32_t line, int32_t logLevel, const char* fmt, ...); + +// NOLINTEND(readability-identifier-naming) + +/** @brief Log level constant: emit all messages, including the most verbose trace output. */ +#define LUSLOG_LEVEL_TRACE 0 +/** @brief Log level constant: verbose debug output useful during development. */ +#define LUSLOG_LEVEL_DEBUG 1 +/** @brief Log level constant: informational messages about normal operation. */ +#define LUSLOG_LEVEL_INFO 2 +/** @brief Log level constant: warnings about unexpected but recoverable conditions. */ +#define LUSLOG_LEVEL_WARN 3 +/** @brief Log level constant: errors that indicate a failure in the current operation. */ +#define LUSLOG_LEVEL_ERROR 4 +/** @brief Log level constant: critical failures that may cause the application to terminate. */ +#define LUSLOG_LEVEL_CRITICAL 5 +/** @brief Log level constant: disable all logging output. */ +#define LUSLOG_LEVEL_OFF 6 + +/** @brief Writes a formatted log message at an explicit @p level. */ +#define LUSLOG(level, msg, ...) lusprintf(__FILE__, __LINE__, level, msg, ##__VA_ARGS__) +/** @brief Writes a formatted log message at TRACE level. */ +#define LUSLOG_TRACE(msg, ...) LUSLOG(LUSLOG_LEVEL_TRACE, msg, ##__VA_ARGS__) +/** @brief Writes a formatted log message at DEBUG level. */ +#define LUSLOG_DEBUG(msg, ...) LUSLOG(LUSLOG_LEVEL_DEBUG, msg, ##__VA_ARGS__) +/** @brief Writes a formatted log message at INFO level. */ +#define LUSLOG_INFO(msg, ...) LUSLOG(LUSLOG_LEVEL_INFO, msg, ##__VA_ARGS__) +/** @brief Writes a formatted log message at WARN level. */ +#define LUSLOG_WARN(msg, ...) LUSLOG(LUSLOG_LEVEL_WARN, msg, ##__VA_ARGS__) +/** @brief Writes a formatted log message at ERROR level. */ +#define LUSLOG_ERROR(msg, ...) LUSLOG(LUSLOG_LEVEL_ERROR, msg, ##__VA_ARGS__) +/** @brief Writes a formatted log message at CRITICAL level. */ +#define LUSLOG_CRITICAL(msg, ...) LUSLOG(LUSLOG_LEVEL_CRITICAL, msg, ##__VA_ARGS__) \ No newline at end of file diff --git a/libultraship/include/libultraship/luslog.h b/libultraship/include/libultraship/luslog.h new file mode 100644 index 000000000..d5a15ef5d --- /dev/null +++ b/libultraship/include/libultraship/luslog.h @@ -0,0 +1,3 @@ +#pragma once + +#include "log/luslog.h" diff --git a/libultraship/include/libultraship/window/gui/GfxDebuggerWindow.h b/libultraship/include/libultraship/window/gui/GfxDebuggerWindow.h new file mode 100644 index 000000000..ae79e95a6 --- /dev/null +++ b/libultraship/include/libultraship/window/gui/GfxDebuggerWindow.h @@ -0,0 +1,58 @@ +#pragma once + +#include "ship/window/gui/GuiWindow.h" +#include +#include + +namespace Fast { +union F3DGfx; +class Interpreter; +} // namespace Fast + +namespace LUS { + +/** + * @brief An ImGui window that visualises and inspects an N64 display list in real-time. + * + * GfxDebuggerWindow provides a tree-based disassembly view of the display list + * currently being executed by the Fast3D interpreter. When the user requests + * debugging (via the menu or GfxDebuggerRequestDebugging()), the window captures + * a single frame's display list and renders an expandable node tree where each + * node corresponds to one or more graphics microcode commands. + * + * The window is registered in the GUI as "Gfx Debugger" and is accessible via + * Gui::GetGuiWindow("Gfx Debugger"). + */ +class GfxDebuggerWindow : public Ship::GuiWindow { + public: + using GuiWindow::GuiWindow; + virtual ~GfxDebuggerWindow(); + + protected: + /** @brief Caches a weak reference to the Fast3D interpreter on first init. */ + void InitElement() override; + + /** @brief Polls the interpreter for a new display list when debugging is requested. */ + void UpdateElement() override; + + /** @brief Renders the disassembly tree for the captured display list. */ + void DrawElement() override; + + private: + /** + * @brief Recursively renders a single display-list command node. + * @param cmd Pointer to the F3DGfx command to display. + * @param gfxPath Full path from the root to @p cmd (for context/breadcrumbs). + * @param parentPosY Y position of the parent node (used for connector lines). + */ + void DrawDisasNode(const Fast::F3DGfx* cmd, std::vector& gfxPath, float parentPosY) const; + + /** @brief Renders the top-level disassembly tree for the last captured breakpoint. */ + void DrawDisas(); + + private: + std::vector mLastBreakPoint = {}; ///< Last captured display list command buffer. + std::weak_ptr mInterpreter; ///< Weak reference to the Fast3D interpreter. +}; + +} // namespace LUS diff --git a/libultraship/include/libultraship/window/gui/InputEditorWindow.h b/libultraship/include/libultraship/window/gui/InputEditorWindow.h new file mode 100644 index 000000000..9156fd0d0 --- /dev/null +++ b/libultraship/include/libultraship/window/gui/InputEditorWindow.h @@ -0,0 +1,253 @@ +#pragma once + +#include "stdint.h" +#include "ship/window/gui/GuiWindow.h" +#include +#include +#include +#include +#include +#include "ship/controller/controldevice/controller/Controller.h" + +namespace LUS { + +/** + * @brief An ImGui window for editing, binding, and testing controller mappings. + * + * InputEditorWindow provides a tab-based UI that allows the user to: + * - View and remap button bindings for each controller port. + * - View and remap analog stick axis bindings with sensitivity/dead-zone controls. + * - Test, enable, and configure rumble mappings. + * - Configure LED colour mappings. + * - View gyroscope input and assign a gyro mapping. + * + * The window is added to the GUI by Context::Init() and is accessible via + * Gui::GetGuiWindow("Input Editor"). + */ +class InputEditorWindow : public Ship::GuiWindow { + public: + using Ship::GuiWindow::GuiWindow; + + /** @brief Destroys the InputEditorWindow and releases any active rumble test state. */ + virtual ~InputEditorWindow(); + + /** + * @brief Renders a small coloured chip labelled with @p buttonName. + * + * Used to represent a single physical button within the editor layout. + * + * @param buttonName Human-readable button label. + * @param color Background colour of the chip. + */ + void DrawInputChip(const char* buttonName, ImVec4 color); + + /** + * @brief Renders a circular analog-stick preview widget. + * @param label Label displayed above the preview. + * @param stick Current stick position (X and Y in the range [-128, 127]). + * @param deadzone Deadzone radius drawn as an inner circle (0 = no deadzone ring). + * @param gyro If true, renders the preview in "gyro" style. + */ + void DrawAnalogPreview(const char* label, ImVec2 stick, float deadzone = 0, bool gyro = false); + + /** + * @brief Returns true while the rumble test is actively playing. + */ + bool TestingRumble(); + + protected: + /** @brief Registers button bitmasks and performs initial population of mapping tables. */ + void InitElement() override; + + /** @brief Renders the full port-tabbed input editor UI. */ + void DrawElement() override; + + /** @brief Refreshes cached mapping-ID tables and manages the rumble test timer. */ + void UpdateElement() override; + + private: + /** + * @brief Draws a single stick-direction mapping line (e.g. "Stick Up"). + * @param axisDirectionName Human-readable axis/direction label. + * @param port Controller port index. + * @param stick Stick index (0 = left, 1 = right). + * @param direction Cardinal direction of the axis. + * @param color Colour used for the input chip. + */ + void DrawStickDirectionLine(const char* axisDirectionName, uint8_t port, uint8_t stick, Ship::Direction direction, + ImVec4 color); + + /** + * @brief Draws a single button mapping line showing current bindings. + * @param buttonName Human-readable button label. + * @param port Controller port index. + * @param bitmask Button bitmask identifying the button. + * @param color Colour used for the input chip. + */ + void DrawButtonLine(const char* buttonName, uint8_t port, CONTROLLERBUTTONS_T bitmask, ImVec4 color); + + /** + * @brief Draws the edit/remove button for an existing button mapping. + * @param port Controller port index. + * @param bitmask Button bitmask identifying the button. + * @param id Mapping identifier string. + */ + void DrawButtonLineEditMappingButton(uint8_t port, CONTROLLERBUTTONS_T bitmask, std::string id); + + /** + * @brief Draws the "+" button that opens the mapping-add popup for a button. + * @param port Controller port index. + * @param bitmask Button bitmask identifying the button. + */ + void DrawButtonLineAddMappingButton(uint8_t port, CONTROLLERBUTTONS_T bitmask); + + /** + * @brief Draws the edit/remove button for an existing stick-direction mapping. + * @param port Controller port index. + * @param stick Stick index (0 = left, 1 = right). + * @param direction Cardinal direction of the axis. + * @param id Mapping identifier string. + */ + void DrawStickDirectionLineEditMappingButton(uint8_t port, uint8_t stick, Ship::Direction direction, + std::string id); + + /** + * @brief Draws the "+" button that opens the mapping-add popup for a stick direction. + * @param port Controller port index. + * @param stick Stick index (0 = left, 1 = right). + * @param direction Cardinal direction of the axis. + */ + void DrawStickDirectionLineAddMappingButton(uint8_t port, uint8_t stick, Ship::Direction direction); + + /** + * @brief Draws the complete analog-stick section (direction lines, preview, and sensitivity controls). + * @param port Controller port index. + * @param stick Stick index (0 = left, 1 = right). + * @param id ImGui identifier used to distinguish collapsing headers. + * @param color Colour used for input chips in this section. + */ + void DrawStickSection(uint8_t port, uint8_t stick, int32_t id, ImVec4 color); + + /** + * @brief Draws the rumble configuration section for a controller port. + * @param port Controller port index. + */ + void DrawRumbleSection(uint8_t port); + + /** + * @brief Draws a remove button for an existing rumble mapping. + * @param port Controller port index. + * @param id Mapping identifier string. + */ + void DrawRemoveRumbleMappingButton(uint8_t port, std::string id); + + /** + * @brief Draws the "+" button that opens the mapping-add popup for rumble. + * @param port Controller port index. + */ + void DrawAddRumbleMappingButton(uint8_t port); + + /** + * @brief Draws the LED colour configuration section for a controller port. + * @param port Controller port index. + */ + void DrawLEDSection(uint8_t port); + + /** + * @brief Draws a remove button for an existing LED mapping. + * @param port Controller port index. + * @param id Mapping identifier string. + */ + void DrawRemoveLEDMappingButton(uint8_t port, std::string id); + + /** + * @brief Draws the "+" button that opens the mapping-add popup for LED. + * @param port Controller port index. + */ + void DrawAddLEDMappingButton(uint8_t port); + + /** + * @brief Draws the gyroscope configuration section for a controller port. + * @param port Controller port index. + */ + void DrawGyroSection(uint8_t port); + + /** + * @brief Draws a remove button for an existing gyro mapping. + * @param port Controller port index. + * @param id Mapping identifier string. + */ + void DrawRemoveGyroMappingButton(uint8_t port, std::string id); + + /** + * @brief Draws the "+" button that opens the mapping-add popup for gyro. + * @param port Controller port index. + */ + void DrawAddGyroMappingButton(uint8_t port); + + int32_t mGameInputBlockTimer; + int32_t mMappingInputBlockTimer; + int32_t mRumbleTimer; + std::shared_ptr mRumbleMappingToTest; + + // mBitmaskToMappingIds[port][bitmask] = { id0, id1, ... } + std::unordered_map>> mBitmaskToMappingIds; + + // mStickDirectionToMappingIds[port][stick][direction] = { id0, id1, ... } + std::unordered_map>>> + mStickDirectionToMappingIds; + + /** + * @brief Rebuilds the cached bitmask-to-mapping-ID table for a port. + * @param port Controller port index. + */ + void UpdateBitmaskToMappingIds(uint8_t port); + + /** + * @brief Rebuilds the cached stick-direction-to-mapping-ID table for a port. + * @param port Controller port index. + */ + void UpdateStickDirectionToMappingIds(uint8_t port); + + /** + * @brief Resolves button colours based on the physical device type of a mapping. + * @param physicalDeviceType The device type to look up colours for. + * @param buttonColor Output normal-state colour. + * @param buttonHoveredColor Output hovered-state colour. + */ + void GetButtonColorsForPhysicalDeviceType(Ship::PhysicalDeviceType physicalDeviceType, ImVec4& buttonColor, + ImVec4& buttonHoveredColor); + + /** + * @brief Draws the full content of a single controller-port tab. + * @param portIndex Controller port index. + */ + void DrawPortTab(uint8_t portIndex); + + std::set mButtonsBitmasks; + std::set mDpadBitmasks; + bool mInputEditorPopupOpen; + + /** + * @brief Draws the "Set Defaults" button that restores default mappings for a port. + * @param portIndex Controller port index. + */ + void DrawSetDefaultsButton(uint8_t portIndex); + + /** + * @brief Draws the "Clear All" button that removes every mapping for a port. + * @param portIndex Controller port index. + */ + void DrawClearAllButton(uint8_t portIndex); + + /** + * @brief Draws per-device-type enable/disable toggles for a port. + * @param portIndex Controller port index. + */ + void DrawDeviceToggles(uint8_t portIndex); + + /** @brief Adjusts the position of the active mapping popup so it stays on-screen. */ + void OffsetMappingPopup(); +}; +} // namespace LUS diff --git a/libultraship/include/ship/Api.h b/libultraship/include/ship/Api.h new file mode 100644 index 000000000..ee779d7bf --- /dev/null +++ b/libultraship/include/ship/Api.h @@ -0,0 +1,38 @@ +/** + * @file Api.h + * @brief API export/import macros for cross-platform shared library symbol visibility. + * + * Provides the API_EXTERN and API_EXPORT macros used to mark functions and variables + * that need C linkage and/or DLL export/import attributes on Windows. + */ + +#pragma once + +/** + * @brief Applies C linkage when compiling as C++, or plain extern in C. + * + * Wraps symbols with `extern "C"` in C++ translation units so they are + * accessible from C code or from dynamic loaders that expect C-style names. + */ +#ifdef __cplusplus +#define API_EXTERN extern "C" +#else +#define API_EXTERN extern +#endif + +/** + * @brief Marks a symbol for export from (or import into) a shared library. + * + * On Windows, this resolves to `__declspec(dllexport)` when building the library + * and `__declspec(dllimport)` when consuming it (i.e. when __DLL__ is defined). + * On other platforms it is equivalent to API_EXTERN. + */ +#ifdef _WIN32 +#ifndef __DLL__ +#define API_EXPORT API_EXTERN __declspec(dllexport) +#else +#define API_EXPORT API_EXTERN __declspec(dllimport) +#endif +#else +#define API_EXPORT API_EXTERN +#endif \ No newline at end of file diff --git a/libultraship/include/ship/Context.h b/libultraship/include/ship/Context.h new file mode 100644 index 000000000..f47af27f2 --- /dev/null +++ b/libultraship/include/ship/Context.h @@ -0,0 +1,302 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include "ship/audio/Audio.h" + +namespace spdlog { +class logger; +} + +namespace Ship { + +class Console; +class ConsoleVariable; +class ControlDeck; +class CrashHandler; +class Window; +class Config; +class ResourceManager; +class FileDropMgr; +class EventSystem; +#ifdef ENABLE_SCRIPTING +class ScriptLoader; +class Keystore; +#endif + +/** + * @brief Central singleton context for the libultraship engine. + * + * Context owns and provides access to every major subsystem (resource management, + * window, audio, controller, logging, configuration, scripting, etc.). Exactly one + * Context should be alive at a time; use GetInstance() to retrieve it after creation. + * + * Typical usage: + * @code + * auto ctx = Ship::Context::CreateInstance("MyApp", "app", "config.json", archivePaths); + * // ... use ctx->GetResourceManager(), ctx->GetWindow(), etc. + * @endcode + * @note Pointers to @code Context@endcode should not be stored as members. You should always access + * @code Context@endcode via GetRawInstance + */ +class Context { + public: + /** + * @brief Returns the currently active global Context instance. + * @return Raw pointer to the Context. This should not be considered shared and should be considered invalid + * once the scope ends. + */ + static Context* GetRawInstance(); + static void DestroyInstance(); + /** + * @brief Creates, initializes, and stores the global Context instance. + * + * Convenience factory that calls CreateUninitializedInstance() followed by Init(). + * + * @param name Human-readable application name. + * @param shortName Short application identifier used for paths and config keys. + * @param configFilePath Path to the JSON configuration file. + * @param archivePaths List of archive file or directory paths to mount. + * @param validHashes Set of acceptable game-version hash values (empty = all allowed). + * @param reservedThreadCount Number of threads to keep free from the resource thread-pool. + * @param audioSettings Initial audio backend and channel configuration. + * @param window Optional pre-constructed Window to use; if nullptr a default is created. + * @param controlDeck Optional pre-constructed ControlDeck; if nullptr a default is created. + * @return Raw pointer to the fully initialized Context. + * @note The pointer returned by this function is only for convenience directly after creating an instance. + */ + static Context* CreateInstance(const std::string& name, const std::string& shortName, + const std::string& configFilePath, const std::vector& archivePaths = {}, + const std::unordered_set& validHashes = {}, + uint32_t reservedThreadCount = 1, AudioSettings audioSettings = {}, + std::shared_ptr window = nullptr, + std::shared_ptr controlDeck = nullptr); + + /** + * @brief Creates a Context that has not yet been initialized. + * + * Use this when you need finer control over initialization order; call Init() manually afterwards. + * + * @param name Human-readable application name. + * @param shortName Short application identifier. + * @param configFilePath Path to the JSON configuration file. + * @return Raw pointer to the uninitialized Context. + * @note The pointer returned by this function is only for convenience directly after creating an instance. + */ + static Context* CreateUninitializedInstance(const std::string& name, const std::string& shortName, + const std::string& configFilePath); + + /** + * @brief Returns the platform-specific application bundle directory (e.g. the .app bundle on macOS). + * @return Absolute path string, or an empty string on platforms without the concept of a bundle. + */ + static std::string GetAppBundlePath(); + + /** + * @brief Returns the platform-specific directory where the application stores its data. + * @param appName Override the application name used to build the path; defaults to the current app name. + * @return Absolute path string. + */ + static std::string GetAppDirectoryPath(const std::string& appName = ""); + + /** + * @brief Resolves a path relative to the application data directory. + * @param path Relative path to resolve. + * @param appName Override the application name used to build the base path. + * @return Absolute path string. + */ + static std::string GetPathRelativeToAppDirectory(const std::string& path, const std::string& appName = ""); + + /** + * @brief Resolves a path relative to the application bundle directory. + * @param path Relative path to resolve. + * @return Absolute path string. + */ + static std::string GetPathRelativeToAppBundle(const std::string& path); + + /** + * @brief Searches common application directories for a file and returns its absolute path. + * @param path Filename or relative path to locate. + * @param appName Override the application name used to search. + * @return Absolute path to the first match found, or an empty string if not found. + */ + static std::string LocateFileAcrossAppDirs(const std::string& path, const std::string& appName = ""); + + /** + * @brief Constructs a Context with the given identifiers but does not initialize subsystems. + * @param name Human-readable application name. + * @param shortName Short application identifier. + * @param configFilePath Path to the JSON configuration file. + */ + Context(std::string name, std::string shortName, std::string configFilePath); + ~Context(); + + /** + * @brief Initializes all subsystems in the correct order. + * + * Called automatically by CreateInstance(). When using CreateUninitializedInstance(), + * call this method manually after any custom pre-initialization setup. + * + * @param archivePaths List of archive paths to mount. + * @param validHashes Acceptable game-version hashes. + * @param reservedThreadCount Threads to reserve outside the resource pool. + * @param audioSettings Audio configuration. + * @param window Optional Window override. + * @param controlDeck Optional ControlDeck override. + * @return true on success, false if any subsystem failed to initialize. + */ + bool Init(const std::vector& archivePaths, const std::unordered_set& validHashes, + uint32_t reservedThreadCount, AudioSettings audioSettings, std::shared_ptr window = nullptr, + std::shared_ptr controlDeck = nullptr); + + /** @brief Returns the application-wide spdlog logger. */ + std::shared_ptr GetLogger() const; + /** @brief Returns the Config subsystem. */ + std::shared_ptr GetConfig() const; + /** @brief Returns the ConsoleVariable subsystem (CVars). */ + std::shared_ptr GetConsoleVariables() const; + /** @brief Returns the ResourceManager subsystem. */ + std::shared_ptr GetResourceManager() const; + /** @brief Returns the ControlDeck subsystem. */ + std::shared_ptr GetControlDeck() const; + /** @brief Returns the CrashHandler subsystem. */ + std::shared_ptr GetCrashHandler() const; + /** @brief Returns the Window subsystem. */ + std::shared_ptr GetWindow() const; + /** @brief Returns the developer Console subsystem. */ + std::shared_ptr GetConsole() const; + /** @brief Returns the Audio subsystem. */ + std::shared_ptr