From 8ef6e3a9dfa76654ebab3a8494aa6ab6ad0d3e36 Mon Sep 17 00:00:00 2001 From: Jaby Date: Wed, 8 Jan 2025 22:27:37 +0100 Subject: [PATCH] Fix inconsistent EOL --- .gitattributes | 3 +- .gitignore | 38 +- .../DebugColor/jabyengine_custom_config.hpp | 10 +- config/Readme.md | 94 +- config/dummy_default_config.hpp | 12 +- docs/Bugs/observed_bugs.md | 10 +- examples/PoolBox/Makefile | 102 +- examples/PoolBox/PoolBox.code-workspace | 184 +- examples/PoolBox/application/Makefile | 22 +- examples/PoolBox/application/Overlays.json | 42 +- .../PoolBox/application/include/asset_mgr.hpp | 80 +- .../PoolBox/application/include/shared.hpp | 18 +- .../application/src/Custom/custom_files.hpp | 24 +- .../application/src/Custom/file_parser.cpp | 50 +- .../src/Overlay/BIOSInfo/bios_info.cpp | 294 +- .../ControllerTest/controller_state.cpp | 218 +- .../ControllerTest/controller_test.cpp | 92 +- .../ControllerTest/controller_test_assets.cpp | 36 +- .../include/controller_state.hpp | 132 +- .../include/controller_test_assets.hpp | 14 +- .../src/Overlay/FontCycler/font_cycler.cpp | 154 +- .../src/Overlay/GPUTest/gpu_test.cpp | 348 +- .../src/Overlay/GPUTest/gpu_test_assets.cpp | 120 +- .../GPUTest/include/gpu_test_assets.hpp | 16 +- .../src/Overlay/GTETest/gte_test.cpp | 330 +- .../src/Overlay/GTETest/gte_test_assets.cpp | 28 +- .../Overlay/GTETest/include/GTE_Sprite.hpp | 92 +- .../GTETest/include/gte_test_assets.hpp | 24 +- .../application/src/Overlay/Overlays.hpp | 74 +- .../src/Overlay/ScreenCenter/frame.cpp | 8 +- .../Overlay/ScreenCenter/include/frame.hpp | 212 +- .../Overlay/ScreenCenter/screen_center.cpp | 416 +-- .../ScreenCenter/screen_center_assets.cpp | 32 +- .../PoolBox/application/src/application.cpp | 596 ++-- .../PoolBox/application/src/asset_mgr.cpp | 268 +- .../PoolBox/application/src/font_writer.cpp | 68 +- .../application/src/include/font_writer.hpp | 26 +- .../PoolBox/application/src/include/menu.hpp | 98 +- .../PoolBox/application/src/include/paco.hpp | 68 +- examples/PoolBox/application/src/menu.cpp | 160 +- examples/PoolBox/assets/Makefile | 130 +- examples/PoolBox/iso/Makefile | 2 +- include/PSX/Audio/CDDA.hpp | 44 +- include/PSX/Audio/CDXA.hpp | 26 +- include/PSX/Auxiliary/big_endian.hpp | 36 +- include/PSX/Auxiliary/circular_buffer.hpp | 120 +- include/PSX/Auxiliary/mem_dump.hpp | 28 +- include/PSX/Auxiliary/unaligned_read.hpp | 14 +- include/PSX/Auxiliary/word_helper.hpp | 30 +- include/PSX/File/Processor/file_processor.hpp | 144 +- include/PSX/File/file_processor_helper.hpp | 122 +- .../GPU/Primitives/primitive_gpu_commands.hpp | 102 +- include/PSX/GPU/gpu_auto_load_font.hpp | 68 +- include/PSX/GPU/make_gpu_primitives.hpp | 696 ++-- include/PSX/GTE/gte.hpp | 480 +-- include/PSX/GTE/gte_instruction.hpp | 272 +- include/PSX/GTE/gte_types.hpp | 274 +- include/PSX/Periphery/controller.hpp | 212 +- include/PSX/Periphery/periphery.hpp | 46 +- include/PSX/Periphery/raw_controller.hpp | 272 +- include/PSX/SPU/spu.hpp | 100 +- .../System/IOPorts/IOValues/cd_io_values.hpp | 210 +- .../System/IOPorts/IOValues/dma_io_values.hpp | 302 +- .../System/IOPorts/IOValues/gpu_io_values.hpp | 438 +-- .../IOPorts/IOValues/interrupt_io_values.hpp | 22 +- .../PSX/System/IOPorts/IOValues/ioport.hpp | 234 +- .../IOPorts/IOValues/memory_io_values.hpp | 34 +- .../IOPorts/IOValues/periphery_io_values.hpp | 102 +- .../System/IOPorts/IOValues/spu_io_values.hpp | 428 +-- .../IOPorts/IOValues/timer_io_values.hpp | 60 +- include/PSX/System/IOPorts/interrupt_io.hpp | 80 +- include/PSX/System/IOPorts/periphery_io.hpp | 56 +- include/PSX/System/IOPorts/timer_io.hpp | 176 +- include/PSX/System/callbacks.hpp | 38 +- include/PSX/System/syscalls.hpp | 584 ++-- include/PSX/Timer/frame_timer.hpp | 146 +- include/PSX/Timer/high_res_timer.hpp | 160 +- include/PSX/jabyengine_config.hpp | 72 +- include/PSX/jabyengine_defines.hpp | 30 +- include/math.hpp | 154 +- include/stdarg.hpp | 12 +- include/stdio.hpp | 6 +- include/string.hpp | 18 +- license | 40 +- mkfile/ISOMakefile.mk | 44 +- mkfile/Makefile | 194 +- mkfile/PSEXETarget.mk | 80 +- mkfile/common/CustomConfigHelper.mk | 6 +- mkfile/common/ExportPath.mk | 2 +- mkfile/common/RebuildTarget.mk | 4 +- mkfile/common/Wildcard.mk | 2 +- mkfile/psexe.ld | 522 +-- podman/Dockerfile | 36 +- readme.md | 180 +- src/Library/Library.code-workspace | 204 +- src/Library/MakeAll.mk | 50 +- src/Library/Makefile | 100 +- .../internal-include/SPU/spu_internal.hpp | 88 +- src/Library/internal-include/SPU/spu_mmu.hpp | 16 +- .../System/callbacks_internal.hpp | 102 +- .../internal-include/System/threads.hpp | 108 +- src/Library/internal-include/mipscalls.hpp | 74 +- .../internal-include/periphery_internal.hpp | 76 +- src/Library/reference/about_inline_n.md | 14 +- src/Library/reference/inline_n.h | 3034 ++++++++--------- src/Library/src/Audio/CDDA.cpp | 106 +- src/Library/src/Audio/CDXA.cpp | 134 +- .../BootLoader/BIOSFont/ascii_bios_font.hpp | 144 +- .../BootLoader/BIOSFont/bios_font_types.hpp | 194 +- src/Library/src/BootLoader/callbacks_boot.cxx | 48 +- src/Library/src/BootLoader/cd_boot.cpp | 82 +- src/Library/src/BootLoader/dma_boot.cpp | 48 +- src/Library/src/BootLoader/gpu_boot.cpp | 216 +- src/Library/src/BootLoader/gte_boot.cpp | 38 +- src/Library/src/BootLoader/periphery_boot.cpp | 32 +- src/Library/src/BootLoader/syscall_boot.cpp | 174 +- src/Library/src/BootLoader/timer_boot.cpp | 64 +- src/Library/src/CD/cd.cpp | 258 +- src/Library/src/CD/cd_interrupt_handler.cpp | 184 +- .../src/File/Processor/TIM/tim_helper.cpp | 132 +- .../src/File/Processor/TIM/tim_helper.hpp | 50 +- .../src/File/Processor/TIM/tim_processor.cpp | 120 +- .../src/File/Processor/cd_file_processor.cpp | 252 +- .../src/File/Processor/custom_processor.cpp | 18 +- .../src/File/Processor/vag_processor.cpp | 156 +- src/Library/src/GPU/gpu.cpp | 236 +- src/Library/src/GTE/gte.cpp | 256 +- src/Library/src/Periphery/periphery.cpp | 270 +- src/Library/src/SPU/spu.cpp | 60 +- src/Library/src/SPU/spu_mmu.cpp | 270 +- src/Library/src/System/callbacks.cxx | 86 +- src/Library/src/System/string.cpp | 124 +- src/Library/src/System/syscall.cpp | 14 +- src/Library/src/Timer/high_res_timer.cpp | 52 +- src/Library/src/syscall_printf.s | 22 +- src/Tools/Common.mk | 66 +- src/Tools/Makefile | 16 +- src/Tools/Tests/ISO_Planschbecken.xml | 38 +- src/Tools/Tools.code-workspace | 114 +- src/Tools/cdtypes/Makefile | 24 +- src/Tools/cpp_out/Makefile | 24 +- src/Tools/cpp_out/src/main.rs | 102 +- src/Tools/mkoverlay/Makefile | 24 +- src/Tools/mkoverlay/src/main.rs | 100 +- src/Tools/psxcdgen_ex/Makefile | 24 +- .../psxcdgen_ex/src/config_reader/mod.rs | 174 +- .../psxcdgen_ex/src/config_reader/xml.rs | 628 ++-- src/Tools/psxcdgen_ex/src/encoder/cd.rs | 1266 +++---- src/Tools/psxcdgen_ex/src/main.rs | 122 +- .../psxcdgen_ex/src/types/overlay/main.rs | 12 +- src/Tools/psxcdread/Makefile | 24 +- src/Tools/psxfileconv/Makefile | 24 +- src/Tools/psxfileconv/src/audio/mod.rs | 2 +- src/Tools/psxfileconv/src/audio/vag/mod.rs | 336 +- src/Tools/psxfileconv/src/audio/vag/types.rs | 450 +-- src/Tools/psxfileconv/src/audio/xa/mod.rs | 76 +- .../src/audio/xa/raw_audio/error.rs | 68 +- .../psxfileconv/src/audio/xa/raw_audio/mod.rs | 474 +-- .../psxfileconv/src/audio/xa/xa_audio/mod.rs | 38 +- .../src/audio/xa/xa_audio/xapcm.rs | 624 ++-- src/Tools/psxfileconv/src/images/args.rs | 136 +- src/Tools/psxfileconv/src/images/mod.rs | 298 +- .../psxfileconv/src/images/reduced_tim/mod.rs | 30 +- .../src/images/reduced_tim/types.rs | 124 +- src/Tools/psxfileconv/src/images/tim/mod.rs | 56 +- src/Tools/psxfileconv/src/images/tim/types.rs | 198 +- src/Tools/psxfileconv/src/lib.rs | 4 +- src/Tools/psxfileconv/src/nothing/mod.rs | 12 +- src/Tools/psxreadmap/Makefile | 24 +- src/Tools/psxreadmap/src/main.rs | 232 +- src/Tools/tool_helper/Makefile | 24 +- src/Tools/tool_helper/src/lib.rs | 532 +-- src/Tools/tool_helper/src/vec_helper.rs | 16 +- src/Tools/wslpath/Makefile | 24 +- support/include/FontWriter/Type/types.hpp | 118 +- support/include/FontWriter/font_writer.hpp | 122 +- support/include/FontWriter/fonts.hpp | 30 +- support/src/FontWriter/Makefile | 80 +- support/src/FontWriter/src/default_font.cpp | 46 +- support/src/FontWriter/src/font_writer.cpp | 308 +- .../src/global_primitive_buffer.cpp | 30 +- .../src/include/global_primitive_buffer.hpp | 56 +- support/src/Makefile | 10 +- template/JabyEngine-PSX_Game/iso/Makefile | 2 +- 184 files changed, 13686 insertions(+), 13685 deletions(-) diff --git a/.gitattributes b/.gitattributes index 47ba9f05..0788ae98 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,4 +2,5 @@ *.wav filter=lfs diff=lfs merge=lfs -text *.png filter=lfs diff=lfs merge=lfs -text *.mp3 filter=lfs diff=lfs merge=lfs -text -*.TMD filter=lfs diff=lfs merge=lfs -text \ No newline at end of file +*.TMD filter=lfs diff=lfs merge=lfs -text +* text=auto eol=lf \ No newline at end of file diff --git a/.gitignore b/.gitignore index e180f8b5..f20b5381 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,20 @@ -# For now we ignore what is in root -**/build -**/bin -**/gcm.cache -**/iso/Info -/iso - -# Custom configs should not be part of JabyEngine -**/config - -.lfsconfig - -*.d -*.a -*.o -*.ii -*.xa - -# TODO: Remove later +# For now we ignore what is in root +**/build +**/bin +**/gcm.cache +**/iso/Info +/iso + +# Custom configs should not be part of JabyEngine +**/config + +.lfsconfig + +*.d +*.a +*.o +*.ii +*.xa + +# TODO: Remove later examples/PoolBox/assets/tmp.VAG \ No newline at end of file diff --git a/config/DebugColor/jabyengine_custom_config.hpp b/config/DebugColor/jabyengine_custom_config.hpp index ab418d99..84c3167b 100644 --- a/config/DebugColor/jabyengine_custom_config.hpp +++ b/config/DebugColor/jabyengine_custom_config.hpp @@ -1,6 +1,6 @@ -#include "../dummy_default_config.hpp" - -struct CustomConfiguration : public DefaultConfiguration { -}; - +#include "../dummy_default_config.hpp" + +struct CustomConfiguration : public DefaultConfiguration { +}; + #define __USE_DEBUG_COLOR__ \ No newline at end of file diff --git a/config/Readme.md b/config/Readme.md index 1957ab90..0b85cea9 100644 --- a/config/Readme.md +++ b/config/Readme.md @@ -1,48 +1,48 @@ -# How to create custom configurations -1. Create folder with name of custom configuration -1. Add `jabyengine_custom_config.hpp` to folder - 1. Follow [guidelines](#jabyengine_custom_confighpp) -1. Build JabyEngine and select your configuration -1. Build your application and select your configuration - -## jabyengine_custom_config.hpp -### Default configuration file -```c++ -// Fix IntelliSense -#include "../dummy_default_config.hpp" - -// Overwrite various configurations -struct CustomConfiguration : public DefaultConfiguration { -}; - -// Define macros here -``` -### `CustomConfiguration` options -When overriding an option make sure to mark the function as `override` -```c++ -struct DefaultConfiguration { - struct BIOSFont { - // VRAM position and CLUT position to load the BIOS font too - static constexpr GPU::PositionU16 texture_load_pos(); - static constexpr GPU::PositionU16 CLUT_load_pos(); - }; - - // Offsets the default origin of the screen by the specified value - static constexpr auto DisplayDefaultOffset; - - struct Periphery { - // Turns on the second controller port and enables multi tap support - static constexpr bool include_portB(); - static constexpr bool use_multi_tap(); - }; -}; -``` -### `CustomConfiguration` macros -```c++ -// Turns on debug information of the SPU MMU (on by default [for now]) -#define __DEBUG_SPU_MMU__ -// Turns on colored rectangles during boot (off by default) -#define __USE_DEBUG_COLOR__ -// Turns on PS3 support (on by default) -#define __SUPPORT_PS3__ +# How to create custom configurations +1. Create folder with name of custom configuration +1. Add `jabyengine_custom_config.hpp` to folder + 1. Follow [guidelines](#jabyengine_custom_confighpp) +1. Build JabyEngine and select your configuration +1. Build your application and select your configuration + +## jabyengine_custom_config.hpp +### Default configuration file +```c++ +// Fix IntelliSense +#include "../dummy_default_config.hpp" + +// Overwrite various configurations +struct CustomConfiguration : public DefaultConfiguration { +}; + +// Define macros here +``` +### `CustomConfiguration` options +When overriding an option make sure to mark the function as `override` +```c++ +struct DefaultConfiguration { + struct BIOSFont { + // VRAM position and CLUT position to load the BIOS font too + static constexpr GPU::PositionU16 texture_load_pos(); + static constexpr GPU::PositionU16 CLUT_load_pos(); + }; + + // Offsets the default origin of the screen by the specified value + static constexpr auto DisplayDefaultOffset; + + struct Periphery { + // Turns on the second controller port and enables multi tap support + static constexpr bool include_portB(); + static constexpr bool use_multi_tap(); + }; +}; +``` +### `CustomConfiguration` macros +```c++ +// Turns on debug information of the SPU MMU (on by default [for now]) +#define __DEBUG_SPU_MMU__ +// Turns on colored rectangles during boot (off by default) +#define __USE_DEBUG_COLOR__ +// Turns on PS3 support (on by default) +#define __SUPPORT_PS3__ ``` \ No newline at end of file diff --git a/config/dummy_default_config.hpp b/config/dummy_default_config.hpp index 5f23015f..254fd132 100644 --- a/config/dummy_default_config.hpp +++ b/config/dummy_default_config.hpp @@ -1,7 +1,7 @@ -#pragma once -#ifdef __INTELLISENSE__ -// This provides a dummy struct so IntelliSense is happy - -struct DefaultConfiguration { -}; +#pragma once +#ifdef __INTELLISENSE__ +// This provides a dummy struct so IntelliSense is happy + +struct DefaultConfiguration { +}; #endif //! __INTELLISENSE__ \ No newline at end of file diff --git a/docs/Bugs/observed_bugs.md b/docs/Bugs/observed_bugs.md index 360f0e17..e35d3854 100644 --- a/docs/Bugs/observed_bugs.md +++ b/docs/Bugs/observed_bugs.md @@ -1,6 +1,6 @@ -# Observed bugs -- [Observed bugs](#observed-bugs) - - [Deadlock](#deadlock) - -## Deadlock +# Observed bugs +- [Observed bugs](#observed-bugs) + - [Deadlock](#deadlock) + +## Deadlock It was observed in `PoolBox` when loading the `FontCycler` overlay that a deadlock occurred. This error has not been observed since. The current theory is that accidentally an old save state in the emulator was loaded. \ No newline at end of file diff --git a/examples/PoolBox/Makefile b/examples/PoolBox/Makefile index a231ab4f..04237566 100644 --- a/examples/PoolBox/Makefile +++ b/examples/PoolBox/Makefile @@ -1,52 +1,52 @@ -ARTIFACT = PoolBox -make_assets = $(MAKE) $(1) ARTIFACT=$(ARTIFACT) -C assets -make_application = $(MAKE) $(1) ARTIFACT=$(ARTIFACT) -C application -make_cd = $(MAKE) $(1) ARTIFACT=$(ARTIFACT) -C iso - -ifndef REGION -$(error REGION has to be set!) -endif - -# Add regions on your own -# Extend them with what you need -ifeq ($(REGION),SCEE) - export PSX_TV_FORMAT=PAL - export PSX_LICENSE=LICENSEE - export PSX_BOOT_FILE=SLES_AAA.AA -endif -ifeq ($(REGION),SCEA) - export PSX_TV_FORMAT=NTSC - export PSX_LICENSE=LICENSEA - export PSX_BOOT_FILE=SLUS_AAA.AA -endif -ifeq ($(REGION),SCEI) - export PSX_TV_FORMAT=NTSC - export PSX_LICENSE=LICENSEJ - export PSX_BOOT_FILE=SLJS_AAA.AA -endif - -ifndef PSX_TV_FORMAT -$(error PSX_TV_FORMAT has not be set! REGION not specified?) -endif - -ifndef PSX_LICENSE -$(error PSX_LICENSE has not be set! REGION not specified?) -endif - -all clean rebuild: |assets_$(MAKECMDGOALS) application_$(MAKECMDGOALS) cd_$(MAKECMDGOALS) - -all_%: always - $(call make_assets,$*) - $(call make_application,$*) - $(call make_cd,$*) - -assets_%: always - $(call make_assets,$*) -application_%: always - $(call make_application,$*) -cd_%: always - $(call make_cd,$*) -pkg_%: always - $(call make_cd,pkg_$*) - +ARTIFACT = PoolBox +make_assets = $(MAKE) $(1) ARTIFACT=$(ARTIFACT) -C assets +make_application = $(MAKE) $(1) ARTIFACT=$(ARTIFACT) -C application +make_cd = $(MAKE) $(1) ARTIFACT=$(ARTIFACT) -C iso + +ifndef REGION +$(error REGION has to be set!) +endif + +# Add regions on your own +# Extend them with what you need +ifeq ($(REGION),SCEE) + export PSX_TV_FORMAT=PAL + export PSX_LICENSE=LICENSEE + export PSX_BOOT_FILE=SLES_AAA.AA +endif +ifeq ($(REGION),SCEA) + export PSX_TV_FORMAT=NTSC + export PSX_LICENSE=LICENSEA + export PSX_BOOT_FILE=SLUS_AAA.AA +endif +ifeq ($(REGION),SCEI) + export PSX_TV_FORMAT=NTSC + export PSX_LICENSE=LICENSEJ + export PSX_BOOT_FILE=SLJS_AAA.AA +endif + +ifndef PSX_TV_FORMAT +$(error PSX_TV_FORMAT has not be set! REGION not specified?) +endif + +ifndef PSX_LICENSE +$(error PSX_LICENSE has not be set! REGION not specified?) +endif + +all clean rebuild: |assets_$(MAKECMDGOALS) application_$(MAKECMDGOALS) cd_$(MAKECMDGOALS) + +all_%: always + $(call make_assets,$*) + $(call make_application,$*) + $(call make_cd,$*) + +assets_%: always + $(call make_assets,$*) +application_%: always + $(call make_application,$*) +cd_%: always + $(call make_cd,$*) +pkg_%: always + $(call make_cd,pkg_$*) + always: ; \ No newline at end of file diff --git a/examples/PoolBox/PoolBox.code-workspace b/examples/PoolBox/PoolBox.code-workspace index ddada09d..9fe05839 100644 --- a/examples/PoolBox/PoolBox.code-workspace +++ b/examples/PoolBox/PoolBox.code-workspace @@ -1,93 +1,93 @@ -{ - "folders": [ - { - "path": ".", - "name": "PoolBox" - } - ], - "tasks": { - "version": "2.0.0", - "tasks": [ - { - "label": "build", - "type": "shell", - "command": "${env:JABY_ENGINE_PATH}/scripts/podman_jaby_engine.sh ${workspaceFolder}:. make ${input:project}_${input:target} BUILD_PROFILE=${input:build profile} REGION=${input:region} CUSTOM_CONFIG=${input:custom config}", - "group": { - "kind": "build", - "isDefault": true - }, - }, - { - "label": "read memory map", - "type": "shell", - "command": "${env:JABY_ENGINE_PATH}/bin/psxreadmap ${input:output memory map} application/bin/${input:tv format}/PSX-${input:build profile}/PoolBox.elf", - "problemMatcher": [], - } - ], - "inputs": [ - { - "id": "build profile", - "type": "pickString", - "options": ["debug", "release"], - "default": "release", - "description": "The build profile for PoolBox" - }, - { - "id": "project", - "type": "pickString", - "options": ["all", "assets", "application", "cd", "pkg"], - "default": "all", - "description": "Project to build" - }, - { - "id": "target", - "type": "pickString", - "options": ["all", "clean", "rebuild"], - "default": "all", - "description": "the build target" - }, - { - "id": "region", - "type": "pickString", - "options": ["SCEE", "SCEA", "SCEI"], - "default": "SCEE", - "description": "Region profile to use" - }, - { - "id": "custom config", - "type": "command", - "command": "shellCommand.execute", - "args": { - "command": "echo \"|\" && ls -d */", - "cwd": "${env:JABY_ENGINE_PATH}/config", - "fieldSeparator": "|" - } - }, - { - "id": "output memory map", - "type": "pickString", - "options": ["", "-o application/bin/PoolBox.map"], - "default": "", - "description": "Output a memory map" - } - ] - }, - "extensions": { - "recommendations": ["augustocdias.tasks-shell-input"] - }, - "settings": { - "C_Cpp.default.includePath": [ - "${env:JABY_ENGINE_PATH}/include", - "${env:JABY_ENGINE_PATH}/support/include" - ], - "C_Cpp.default.compilerPath": "", - "C_Cpp.default.cStandard": "c17", - "C_Cpp.default.cppStandard": "c++20", - "C_Cpp.default.intelliSenseMode": "linux-gcc-x86", - "C_Cpp.default.compilerArgs": [ - ], - "C_Cpp.default.defines": [ - "JABYENGINE_PAL" - ], - } +{ + "folders": [ + { + "path": ".", + "name": "PoolBox" + } + ], + "tasks": { + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "shell", + "command": "${env:JABY_ENGINE_PATH}/scripts/podman_jaby_engine.sh ${workspaceFolder}:. make ${input:project}_${input:target} BUILD_PROFILE=${input:build profile} REGION=${input:region} CUSTOM_CONFIG=${input:custom config}", + "group": { + "kind": "build", + "isDefault": true + }, + }, + { + "label": "read memory map", + "type": "shell", + "command": "${env:JABY_ENGINE_PATH}/bin/psxreadmap ${input:output memory map} application/bin/${input:tv format}/PSX-${input:build profile}/PoolBox.elf", + "problemMatcher": [], + } + ], + "inputs": [ + { + "id": "build profile", + "type": "pickString", + "options": ["debug", "release"], + "default": "release", + "description": "The build profile for PoolBox" + }, + { + "id": "project", + "type": "pickString", + "options": ["all", "assets", "application", "cd", "pkg"], + "default": "all", + "description": "Project to build" + }, + { + "id": "target", + "type": "pickString", + "options": ["all", "clean", "rebuild"], + "default": "all", + "description": "the build target" + }, + { + "id": "region", + "type": "pickString", + "options": ["SCEE", "SCEA", "SCEI"], + "default": "SCEE", + "description": "Region profile to use" + }, + { + "id": "custom config", + "type": "command", + "command": "shellCommand.execute", + "args": { + "command": "echo \"|\" && ls -d */", + "cwd": "${env:JABY_ENGINE_PATH}/config", + "fieldSeparator": "|" + } + }, + { + "id": "output memory map", + "type": "pickString", + "options": ["", "-o application/bin/PoolBox.map"], + "default": "", + "description": "Output a memory map" + } + ] + }, + "extensions": { + "recommendations": ["augustocdias.tasks-shell-input"] + }, + "settings": { + "C_Cpp.default.includePath": [ + "${env:JABY_ENGINE_PATH}/include", + "${env:JABY_ENGINE_PATH}/support/include" + ], + "C_Cpp.default.compilerPath": "", + "C_Cpp.default.cStandard": "c17", + "C_Cpp.default.cppStandard": "c++20", + "C_Cpp.default.intelliSenseMode": "linux-gcc-x86", + "C_Cpp.default.compilerArgs": [ + ], + "C_Cpp.default.defines": [ + "JABYENGINE_PAL" + ], + } } \ No newline at end of file diff --git a/examples/PoolBox/application/Makefile b/examples/PoolBox/application/Makefile index cd3f4824..614a79ca 100644 --- a/examples/PoolBox/application/Makefile +++ b/examples/PoolBox/application/Makefile @@ -1,12 +1,12 @@ -OVERLAY_CONFIG = Overlays.json - -include $(JABY_ENGINE_DIR)/mkfile/common/Wildcard.mk -SRCS = $(call rwildcard, src, c cpp) - -INCLUDES += -I$(JABY_ENGINE_DIR)/support/include -I$(JABY_ENGINE_DIR)/include -CCFLAGS += -save-temps=obj - -SUPPORT_LIBS += FontWriter - -include $(JABY_ENGINE_DIR)/mkfile/Makefile +OVERLAY_CONFIG = Overlays.json + +include $(JABY_ENGINE_DIR)/mkfile/common/Wildcard.mk +SRCS = $(call rwildcard, src, c cpp) + +INCLUDES += -I$(JABY_ENGINE_DIR)/support/include -I$(JABY_ENGINE_DIR)/include +CCFLAGS += -save-temps=obj + +SUPPORT_LIBS += FontWriter + +include $(JABY_ENGINE_DIR)/mkfile/Makefile include $(JABY_ENGINE_DIR)/mkfile/PSEXETarget.mk \ No newline at end of file diff --git a/examples/PoolBox/application/Overlays.json b/examples/PoolBox/application/Overlays.json index ee993961..c67a037a 100644 --- a/examples/PoolBox/application/Overlays.json +++ b/examples/PoolBox/application/Overlays.json @@ -1,22 +1,22 @@ -{ - "slot_0": { - "bios_info": { - "pattern": "bin/*/src/Overlay/BIOSInfo/*.o" - }, - "controller_tests": { - "pattern": "bin/*/src/Overlay/ControllerTest/*.o" - }, - "gpu_tests": { - "pattern": "bin/*/src/Overlay/GPUTest/*.o" - }, - "gte_tests": { - "pattern": "bin/*/src/Overlay/GTETest/*.o" - }, - "font_cycler": { - "pattern": "bin/*/src/Overlay/FontCycler/*.o" - }, - "screen_center": { - "pattern": "bin/*/src/Overlay/ScreenCenter/*.o" - } - } +{ + "slot_0": { + "bios_info": { + "pattern": "bin/*/src/Overlay/BIOSInfo/*.o" + }, + "controller_tests": { + "pattern": "bin/*/src/Overlay/ControllerTest/*.o" + }, + "gpu_tests": { + "pattern": "bin/*/src/Overlay/GPUTest/*.o" + }, + "gte_tests": { + "pattern": "bin/*/src/Overlay/GTETest/*.o" + }, + "font_cycler": { + "pattern": "bin/*/src/Overlay/FontCycler/*.o" + }, + "screen_center": { + "pattern": "bin/*/src/Overlay/ScreenCenter/*.o" + } + } } \ No newline at end of file diff --git a/examples/PoolBox/application/include/asset_mgr.hpp b/examples/PoolBox/application/include/asset_mgr.hpp index 4dd3165d..5c50eb01 100644 --- a/examples/PoolBox/application/include/asset_mgr.hpp +++ b/examples/PoolBox/application/include/asset_mgr.hpp @@ -1,41 +1,41 @@ -#pragma once -#include - -namespace Assets { - using namespace JabyEngine; - - namespace Main { - struct ImageInfo { - SimpleTIM tim; - GPU::SizeI16 size; - }; - - static constexpr auto PacoTIM = SimpleTIM::create(896, 0, 960, 510); - static constexpr auto DoenerFishInfo = ImageInfo{ - .tim = SimpleTIM::create(896 + 30, 0, 960 + 16, 510), - .size = GPU::SizeI16::create(128, 64) - }; - - namespace JabyLoader { - static constexpr auto TIMLoaction = SimpleTIM::create(PacoTIM.get_texture_x(), PacoTIM.get_texture_y() + 128, 960 + 48, 510); - static constexpr auto JabyFrame = GPU::AreaI16::create(0, 0, 32, 44); - static constexpr auto FontFrame = GPU::AreaI16::create(0, 45, 186, 32); - }; - - void load(); - } - - namespace Overlay { - void load_bios_info(); - void load_controller_test(); - void load_gpu_test(); - void load_large_gpu_test(); - void load_gte_test(); - void load_font_cycler(); - void load_screen_center(); - } - - namespace XAAudio { - void play_mix(); - } +#pragma once +#include + +namespace Assets { + using namespace JabyEngine; + + namespace Main { + struct ImageInfo { + SimpleTIM tim; + GPU::SizeI16 size; + }; + + static constexpr auto PacoTIM = SimpleTIM::create(896, 0, 960, 510); + static constexpr auto DoenerFishInfo = ImageInfo{ + .tim = SimpleTIM::create(896 + 30, 0, 960 + 16, 510), + .size = GPU::SizeI16::create(128, 64) + }; + + namespace JabyLoader { + static constexpr auto TIMLoaction = SimpleTIM::create(PacoTIM.get_texture_x(), PacoTIM.get_texture_y() + 128, 960 + 48, 510); + static constexpr auto JabyFrame = GPU::AreaI16::create(0, 0, 32, 44); + static constexpr auto FontFrame = GPU::AreaI16::create(0, 45, 186, 32); + }; + + void load(); + } + + namespace Overlay { + void load_bios_info(); + void load_controller_test(); + void load_gpu_test(); + void load_large_gpu_test(); + void load_gte_test(); + void load_font_cycler(); + void load_screen_center(); + } + + namespace XAAudio { + void play_mix(); + } } \ No newline at end of file diff --git a/examples/PoolBox/application/include/shared.hpp b/examples/PoolBox/application/include/shared.hpp index f22ac265..99e14ec3 100644 --- a/examples/PoolBox/application/include/shared.hpp +++ b/examples/PoolBox/application/include/shared.hpp @@ -1,10 +1,10 @@ -#pragma once -#include "../src/include/menu.hpp" -#include "../src/include/font_writer.hpp" -#include - -namespace Shared { - extern Menu::BackMenu back_menu; - extern JabyEngine::GPU::POLY_G4 background; - extern bool load_test; +#pragma once +#include "../src/include/menu.hpp" +#include "../src/include/font_writer.hpp" +#include + +namespace Shared { + extern Menu::BackMenu back_menu; + extern JabyEngine::GPU::POLY_G4 background; + extern bool load_test; } \ No newline at end of file diff --git a/examples/PoolBox/application/src/Custom/custom_files.hpp b/examples/PoolBox/application/src/Custom/custom_files.hpp index 39e17ce4..96fc8733 100644 --- a/examples/PoolBox/application/src/Custom/custom_files.hpp +++ b/examples/PoolBox/application/src/Custom/custom_files.hpp @@ -1,13 +1,13 @@ -#pragma once -#include - -enum struct FileType : JabyEngine::CDFileType_t { - Jingle, -}; - -struct CustomCDFileBuilder { - static constexpr JabyEngine::CDFile jingle(uint32_t sfx_id) { - // v we reload Paco - return JabyEngine::CDFile::custom(0, FileType::Jingle, sfx_id); - } +#pragma once +#include + +enum struct FileType : JabyEngine::CDFileType_t { + Jingle, +}; + +struct CustomCDFileBuilder { + static constexpr JabyEngine::CDFile jingle(uint32_t sfx_id) { + // v we reload Paco + return JabyEngine::CDFile::custom(0, FileType::Jingle, sfx_id); + } }; \ No newline at end of file diff --git a/examples/PoolBox/application/src/Custom/file_parser.cpp b/examples/PoolBox/application/src/Custom/file_parser.cpp index ac63977b..725b55b0 100644 --- a/examples/PoolBox/application/src/Custom/file_parser.cpp +++ b/examples/PoolBox/application/src/Custom/file_parser.cpp @@ -1,26 +1,26 @@ -#include "custom_files.hpp" -#include -#include - -namespace JabyEngine { - namespace FileProcessor { - struct JingleState { - uint32_t sfx_id; - }; - - static Progress parse_jingle(State::CDDataProcessor& data_proc, JingleState& jingle) { - SPU::voice[jingle.sfx_id].play(); - return Progress::Done; - } - - State create_custom(const uint32_t* data_adr, const CDFileType_t& file_type, const CDFile::Payload& payload) { - switch(static_cast(file_type)) { - case FileType::Jingle: - return State::from(JingleState{.sfx_id = payload.raw}, data_adr, parse_jingle); - - default: - return FileProcessor::create(data_adr, Nothing()); - } - } - } +#include "custom_files.hpp" +#include +#include + +namespace JabyEngine { + namespace FileProcessor { + struct JingleState { + uint32_t sfx_id; + }; + + static Progress parse_jingle(State::CDDataProcessor& data_proc, JingleState& jingle) { + SPU::voice[jingle.sfx_id].play(); + return Progress::Done; + } + + State create_custom(const uint32_t* data_adr, const CDFileType_t& file_type, const CDFile::Payload& payload) { + switch(static_cast(file_type)) { + case FileType::Jingle: + return State::from(JingleState{.sfx_id = payload.raw}, data_adr, parse_jingle); + + default: + return FileProcessor::create(data_adr, Nothing()); + } + } + } } \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/BIOSInfo/bios_info.cpp b/examples/PoolBox/application/src/Overlay/BIOSInfo/bios_info.cpp index 55454f43..8bef9636 100644 --- a/examples/PoolBox/application/src/Overlay/BIOSInfo/bios_info.cpp +++ b/examples/PoolBox/application/src/Overlay/BIOSInfo/bios_info.cpp @@ -1,148 +1,148 @@ -#include "../../../include/asset_mgr.hpp" -#include "../../../include/shared.hpp" -#include -#include -#include -#include -#include -#include - -namespace BIOSInfo { - using namespace JabyEngine; - static constexpr auto TextOffset = Make::PositionI16(16, 16); - - using NameColorPair = pair; - - struct FontSlider { - static constexpr auto MoveTimeout = static_cast(300_ms); - static constexpr auto WaitTimeout = static_cast(1000_ms); - - int16_t count; - int16_t max; - int8_t delta; - IntervalTimer wait_timer; - - static FontSlider create_for(const FontWriter::FontInfo& font_info, const char* str) { - const auto max = static_cast((strlen(str)*font_info.get_kern_size().width) - GPU::Display::Width + (TextOffset.x << 1)); - return FontSlider{ - .count = 0, - .max = max, - .delta = static_cast(max < 0 ? 0 : font_info.get_kern_size().width/2), - .wait_timer = IntervalTimer::create(FontSlider::MoveTimeout) - }; - } - - void advance() { - if(this->wait_timer.is_expired()) { - this->wait_timer.reset(); - this->count += delta; - - if(this->count <= 0 || this->count >= this->max) { - this->delta *= -1; - this->wait_timer.set_interval(FontSlider::WaitTimeout); - } - - else { - this->wait_timer.set_interval(FontSlider::MoveTimeout); - } - } - } - }; - - static struct { - using BIOSStringOffset = const char*const (BIOS::Version::*); - - const BIOSStringOffset bios_str_offset; - const char*const display_str; - FontSlider font_slider; - } BIOSStringInfo[] = { - {.bios_str_offset = &BIOS::Version::kernel_maker, .display_str = "Kernel-Maker"}, - {.bios_str_offset = &BIOS::Version::version_str, .display_str = "Version"}, - {.bios_str_offset = &BIOS::Version::gui_version, .display_str = "GUI-Version"}, - {.bios_str_offset = &BIOS::Version::copyright, .display_str = "Copyright"}, - }; - - static GPU::TILE::Linked border_tiles[2] = { - Make::TILE(Make::AreaI16(0, 0, TextOffset.x, GPU::Display::Height - 32), GPU::Color24::Black()).linked(), - Make::TILE(Make::AreaI16(GPU::Display::Width - TextOffset.x, 0, TextOffset.x, GPU::Display::Height - 32), GPU::Color24::Black()).linked() - }; - - static NameColorPair bios_name; - static FontSlider bios_name_slider; - - static NameColorPair get_bios_name() { - switch(BIOS::version.type) { - case BIOS::Version::Devboard: - return {"DevBoard", GPU::Color24::Green()}; - case BIOS::Version::PS1: - return {"PS1", GPU::Color24::Red()}; - case BIOS::Version::PS2: - return {"PS2", GPU::Color24::Blue()}; - case BIOS::Version::PS3: - return {"PS3", GPU::Color24::Yellow()}; - case BIOS::Version::PSCompatible: - return {"Unkown PS compatible BIOS", GPU::Color24::Grey()}; - case BIOS::Version::No$psx: - return {"NO$PSX", GPU::Color24::Purple()}; - case BIOS::Version::XEBRA: - return {"XEBRA", GPU::Color24::Turquoise()}; - default: - return {"Unkown", GPU::Color24::White()}; - } - } - - static void setup() { - bios_name = get_bios_name(); - Shared::back_menu.reset(); - for(auto& bios_str_info : BIOSStringInfo) { - bios_str_info.font_slider = FontSlider::create_for(FontWriter::BIOSFont::Info, BIOS::version.*(bios_str_info.bios_str_offset)); - } - bios_name_slider = FontSlider::create_for(FontWriter::BIOSFont::Info, bios_name.first); - border_tiles[0].concat(border_tiles[1]); - } - - static bool update_or_exit() { - static const auto move_cursor = [](JabyEngine::Cursor& cursor, int16_t dx, int16_t old_x) -> JabyEngine::Cursor& { - cursor.pos.x = (old_x - dx); - return cursor; - }; - - Periphery::query_controller(); - if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) { - return true; - } - - auto cursor = FontWriter::update(TextOffset); - FontWriter::bios_font_writer.write(cursor, "BIOS INFORMATION\n----------------\nDate (day/month/year):\n%i/%i/%i\n", BIOS::version.date.day, BIOS::version.date.month, BIOS::version.date.year); - - const auto old_pos_x = cursor.pos.x; - for(auto& bios_str_info : BIOSStringInfo) { - bios_str_info.font_slider.advance(); - - FontWriter::bios_font_writer.write(move_cursor(cursor, 0, old_pos_x), "%s:\n", bios_str_info.display_str); - FontWriter::bios_font_writer.write(move_cursor(cursor, bios_str_info.font_slider.count, old_pos_x), "%s\n", BIOS::version.*(bios_str_info.bios_str_offset)); - } - FontWriter::bios_font_writer.write(move_cursor(cursor, 0, old_pos_x), "BIOS Type:\n"); - FontWriter::bios_font_writer.write(move_cursor(cursor, bios_name_slider.count, old_pos_x), "%s\n", bios_name.second, bios_name.first); - FontWriter::bios_font_writer.write(move_cursor(cursor, 0, old_pos_x), "----------------\n"); - - return false; - } - - static void render() { - Shared::back_menu.render(); - FontWriter::bios_font_writer.render(); - GPU::render(border_tiles[0]); - } - - void main() { - setup(); - while(true) { - if(update_or_exit()) { - break; - } - GPU::swap_buffers_vsync(1); - render(); - } - } +#include "../../../include/asset_mgr.hpp" +#include "../../../include/shared.hpp" +#include +#include +#include +#include +#include +#include + +namespace BIOSInfo { + using namespace JabyEngine; + static constexpr auto TextOffset = Make::PositionI16(16, 16); + + using NameColorPair = pair; + + struct FontSlider { + static constexpr auto MoveTimeout = static_cast(300_ms); + static constexpr auto WaitTimeout = static_cast(1000_ms); + + int16_t count; + int16_t max; + int8_t delta; + IntervalTimer wait_timer; + + static FontSlider create_for(const FontWriter::FontInfo& font_info, const char* str) { + const auto max = static_cast((strlen(str)*font_info.get_kern_size().width) - GPU::Display::Width + (TextOffset.x << 1)); + return FontSlider{ + .count = 0, + .max = max, + .delta = static_cast(max < 0 ? 0 : font_info.get_kern_size().width/2), + .wait_timer = IntervalTimer::create(FontSlider::MoveTimeout) + }; + } + + void advance() { + if(this->wait_timer.is_expired()) { + this->wait_timer.reset(); + this->count += delta; + + if(this->count <= 0 || this->count >= this->max) { + this->delta *= -1; + this->wait_timer.set_interval(FontSlider::WaitTimeout); + } + + else { + this->wait_timer.set_interval(FontSlider::MoveTimeout); + } + } + } + }; + + static struct { + using BIOSStringOffset = const char*const (BIOS::Version::*); + + const BIOSStringOffset bios_str_offset; + const char*const display_str; + FontSlider font_slider; + } BIOSStringInfo[] = { + {.bios_str_offset = &BIOS::Version::kernel_maker, .display_str = "Kernel-Maker"}, + {.bios_str_offset = &BIOS::Version::version_str, .display_str = "Version"}, + {.bios_str_offset = &BIOS::Version::gui_version, .display_str = "GUI-Version"}, + {.bios_str_offset = &BIOS::Version::copyright, .display_str = "Copyright"}, + }; + + static GPU::TILE::Linked border_tiles[2] = { + Make::TILE(Make::AreaI16(0, 0, TextOffset.x, GPU::Display::Height - 32), GPU::Color24::Black()).linked(), + Make::TILE(Make::AreaI16(GPU::Display::Width - TextOffset.x, 0, TextOffset.x, GPU::Display::Height - 32), GPU::Color24::Black()).linked() + }; + + static NameColorPair bios_name; + static FontSlider bios_name_slider; + + static NameColorPair get_bios_name() { + switch(BIOS::version.type) { + case BIOS::Version::Devboard: + return {"DevBoard", GPU::Color24::Green()}; + case BIOS::Version::PS1: + return {"PS1", GPU::Color24::Red()}; + case BIOS::Version::PS2: + return {"PS2", GPU::Color24::Blue()}; + case BIOS::Version::PS3: + return {"PS3", GPU::Color24::Yellow()}; + case BIOS::Version::PSCompatible: + return {"Unkown PS compatible BIOS", GPU::Color24::Grey()}; + case BIOS::Version::No$psx: + return {"NO$PSX", GPU::Color24::Purple()}; + case BIOS::Version::XEBRA: + return {"XEBRA", GPU::Color24::Turquoise()}; + default: + return {"Unkown", GPU::Color24::White()}; + } + } + + static void setup() { + bios_name = get_bios_name(); + Shared::back_menu.reset(); + for(auto& bios_str_info : BIOSStringInfo) { + bios_str_info.font_slider = FontSlider::create_for(FontWriter::BIOSFont::Info, BIOS::version.*(bios_str_info.bios_str_offset)); + } + bios_name_slider = FontSlider::create_for(FontWriter::BIOSFont::Info, bios_name.first); + border_tiles[0].concat(border_tiles[1]); + } + + static bool update_or_exit() { + static const auto move_cursor = [](JabyEngine::Cursor& cursor, int16_t dx, int16_t old_x) -> JabyEngine::Cursor& { + cursor.pos.x = (old_x - dx); + return cursor; + }; + + Periphery::query_controller(); + if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) { + return true; + } + + auto cursor = FontWriter::update(TextOffset); + FontWriter::bios_font_writer.write(cursor, "BIOS INFORMATION\n----------------\nDate (day/month/year):\n%i/%i/%i\n", BIOS::version.date.day, BIOS::version.date.month, BIOS::version.date.year); + + const auto old_pos_x = cursor.pos.x; + for(auto& bios_str_info : BIOSStringInfo) { + bios_str_info.font_slider.advance(); + + FontWriter::bios_font_writer.write(move_cursor(cursor, 0, old_pos_x), "%s:\n", bios_str_info.display_str); + FontWriter::bios_font_writer.write(move_cursor(cursor, bios_str_info.font_slider.count, old_pos_x), "%s\n", BIOS::version.*(bios_str_info.bios_str_offset)); + } + FontWriter::bios_font_writer.write(move_cursor(cursor, 0, old_pos_x), "BIOS Type:\n"); + FontWriter::bios_font_writer.write(move_cursor(cursor, bios_name_slider.count, old_pos_x), "%s\n", bios_name.second, bios_name.first); + FontWriter::bios_font_writer.write(move_cursor(cursor, 0, old_pos_x), "----------------\n"); + + return false; + } + + static void render() { + Shared::back_menu.render(); + FontWriter::bios_font_writer.render(); + GPU::render(border_tiles[0]); + } + + void main() { + setup(); + while(true) { + if(update_or_exit()) { + break; + } + GPU::swap_buffers_vsync(1); + render(); + } + } } \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/ControllerTest/controller_state.cpp b/examples/PoolBox/application/src/Overlay/ControllerTest/controller_state.cpp index 5d2919b8..ffa1cc26 100644 --- a/examples/PoolBox/application/src/Overlay/ControllerTest/controller_state.cpp +++ b/examples/PoolBox/application/src/Overlay/ControllerTest/controller_state.cpp @@ -1,110 +1,110 @@ -#include "include/controller_state.hpp" -#include -#include - -namespace ControllerTest { - using DigitalButton = Periphery::AnalogeController::Button; - using namespace JabyEngine; - - static void set_active(GPU::SPRT_16::Linked& sprt, bool is_active) { - sprt->tex_offset.y = is_active ? 16 : 0; - if(is_active) { - SPU::voice[1].play_if_end(); - } - } - - static void set_active(GPU::POLY_FT4::Linked& poly, bool is_active) { - poly->tex_offset0.y = is_active ? 16 : 0; - poly->tex_offset1.y = is_active ? 16 : 0; - poly->tex_offset2.y = is_active ? 32 : 16; - poly->tex_offset3.y = is_active ? 32 : 16; - - if(is_active) { - SPU::voice[1].play_if_end(); - } - } - - static const char* get_type_name(Periphery::ControllerType type) { - switch(type) { - case Periphery::ControllerType::Unkown: - return "Unkown"; - - case Periphery::ControllerType::Mouse: - return "Mouse"; - - case Periphery::ControllerType::NegCon: - return "NegCon"; - - case Periphery::ControllerType::HyperBlaster: - return "HyperBlaster"; - - case Periphery::ControllerType::Controller: - return "Digital Controller"; - - case Periphery::ControllerType::ArcadeFlightStick: - return "Flight Stick"; - - case Periphery::ControllerType::GCon: - return "GCon"; - - case Periphery::ControllerType::DualShock: - return "DualShock"; - - case Periphery::ControllerType::MultiTap: - return "MultiTap"; - - default: - return "???"; - } - } - - void ControllerState :: setup() { - for(size_t n = 0; n < 2; n++) { - GPU::LinkHelper::link_array(GPU::LinkHelper::link_array(&this->tex_page[n], this->buttons[n]), this->arrows[n]); - } - } - - void ControllerState :: update(const Periphery::AnalogeController* controller, JabyEngine::FontWriter& font_writer) { - static const DigitalButton ButtonSprtMap[] = { - DigitalButton::Triangle, DigitalButton::Circle, DigitalButton::Cross, DigitalButton::Square, - DigitalButton::ST, DigitalButton::SEL, DigitalButton::L1, DigitalButton::L2, DigitalButton::R1, DigitalButton::R2, - DigitalButton::L3, DigitalButton::R3 - }; - static const DigitalButton ArrowPolyMap[] = { - DigitalButton::Up, DigitalButton::Right, DigitalButton::Down, DigitalButton::Left - }; - - auto& cur_button_sprts = this->buttons[GPU::update_id()]; - auto& cur_arrow_poly = this->arrows[GPU::update_id()]; - - if(controller) { - for(size_t n = 0; n < sizeof(ButtonSprtMap)/sizeof(ButtonSprtMap[0]); n++) { - set_active(cur_button_sprts[n], controller->button.is_down(ButtonSprtMap[n])); - } - for(size_t n = 0; n < sizeof(ArrowPolyMap)/sizeof(ArrowPolyMap[0]); n++) { - set_active(cur_arrow_poly[n], controller->button.is_down(ArrowPolyMap[n])); - } - - set_active(cur_button_sprts[12], controller->header.state == Periphery::RawController::State::Disconnected); - - // Text stuff down here - const auto offset_point = cur_button_sprts[1]->position; - const auto left_stick = controller->get_left_stick_pos(); - const auto right_stick = controller->get_right_stick_pos(); - - auto cursor = Cursor::create(offset_point.move(16, 0), 0); - font_writer.write(cursor, "Right: %i, %i\nLeft : %i, %i\n", right_stick.x, right_stick.y, left_stick.x, left_stick.y); - font_writer.write(cursor, "[%s]", get_type_name(static_cast(controller->get_type()))); - } - - else { - auto cursor = Cursor::create(Make::PositionI16(cur_arrow_poly[3]->vertex0.x, cur_button_sprts[0]->position.y), 0); - font_writer.write(cursor, "!!This Port is not\nenabled in JabyEngine!!", GPU::Color24::Red()); - this->tex_page[GPU::update_id()].terminate(); - } - } - - void ControllerState :: render() { - GPU::render(this->tex_page[GPU::render_id()]); - } +#include "include/controller_state.hpp" +#include +#include + +namespace ControllerTest { + using DigitalButton = Periphery::AnalogeController::Button; + using namespace JabyEngine; + + static void set_active(GPU::SPRT_16::Linked& sprt, bool is_active) { + sprt->tex_offset.y = is_active ? 16 : 0; + if(is_active) { + SPU::voice[1].play_if_end(); + } + } + + static void set_active(GPU::POLY_FT4::Linked& poly, bool is_active) { + poly->tex_offset0.y = is_active ? 16 : 0; + poly->tex_offset1.y = is_active ? 16 : 0; + poly->tex_offset2.y = is_active ? 32 : 16; + poly->tex_offset3.y = is_active ? 32 : 16; + + if(is_active) { + SPU::voice[1].play_if_end(); + } + } + + static const char* get_type_name(Periphery::ControllerType type) { + switch(type) { + case Periphery::ControllerType::Unkown: + return "Unkown"; + + case Periphery::ControllerType::Mouse: + return "Mouse"; + + case Periphery::ControllerType::NegCon: + return "NegCon"; + + case Periphery::ControllerType::HyperBlaster: + return "HyperBlaster"; + + case Periphery::ControllerType::Controller: + return "Digital Controller"; + + case Periphery::ControllerType::ArcadeFlightStick: + return "Flight Stick"; + + case Periphery::ControllerType::GCon: + return "GCon"; + + case Periphery::ControllerType::DualShock: + return "DualShock"; + + case Periphery::ControllerType::MultiTap: + return "MultiTap"; + + default: + return "???"; + } + } + + void ControllerState :: setup() { + for(size_t n = 0; n < 2; n++) { + GPU::LinkHelper::link_array(GPU::LinkHelper::link_array(&this->tex_page[n], this->buttons[n]), this->arrows[n]); + } + } + + void ControllerState :: update(const Periphery::AnalogeController* controller, JabyEngine::FontWriter& font_writer) { + static const DigitalButton ButtonSprtMap[] = { + DigitalButton::Triangle, DigitalButton::Circle, DigitalButton::Cross, DigitalButton::Square, + DigitalButton::ST, DigitalButton::SEL, DigitalButton::L1, DigitalButton::L2, DigitalButton::R1, DigitalButton::R2, + DigitalButton::L3, DigitalButton::R3 + }; + static const DigitalButton ArrowPolyMap[] = { + DigitalButton::Up, DigitalButton::Right, DigitalButton::Down, DigitalButton::Left + }; + + auto& cur_button_sprts = this->buttons[GPU::update_id()]; + auto& cur_arrow_poly = this->arrows[GPU::update_id()]; + + if(controller) { + for(size_t n = 0; n < sizeof(ButtonSprtMap)/sizeof(ButtonSprtMap[0]); n++) { + set_active(cur_button_sprts[n], controller->button.is_down(ButtonSprtMap[n])); + } + for(size_t n = 0; n < sizeof(ArrowPolyMap)/sizeof(ArrowPolyMap[0]); n++) { + set_active(cur_arrow_poly[n], controller->button.is_down(ArrowPolyMap[n])); + } + + set_active(cur_button_sprts[12], controller->header.state == Periphery::RawController::State::Disconnected); + + // Text stuff down here + const auto offset_point = cur_button_sprts[1]->position; + const auto left_stick = controller->get_left_stick_pos(); + const auto right_stick = controller->get_right_stick_pos(); + + auto cursor = Cursor::create(offset_point.move(16, 0), 0); + font_writer.write(cursor, "Right: %i, %i\nLeft : %i, %i\n", right_stick.x, right_stick.y, left_stick.x, left_stick.y); + font_writer.write(cursor, "[%s]", get_type_name(static_cast(controller->get_type()))); + } + + else { + auto cursor = Cursor::create(Make::PositionI16(cur_arrow_poly[3]->vertex0.x, cur_button_sprts[0]->position.y), 0); + font_writer.write(cursor, "!!This Port is not\nenabled in JabyEngine!!", GPU::Color24::Red()); + this->tex_page[GPU::update_id()].terminate(); + } + } + + void ControllerState :: render() { + GPU::render(this->tex_page[GPU::render_id()]); + } } \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/ControllerTest/controller_test.cpp b/examples/PoolBox/application/src/Overlay/ControllerTest/controller_test.cpp index 2457c201..9ad8e71a 100644 --- a/examples/PoolBox/application/src/Overlay/ControllerTest/controller_test.cpp +++ b/examples/PoolBox/application/src/Overlay/ControllerTest/controller_test.cpp @@ -1,47 +1,47 @@ -#include "../../../include/shared.hpp" -#include "include/controller_state.hpp" -#include - -namespace ControllerTest { - using namespace JabyEngine; - - static auto controller_state0 = ControllerState::create(Make::PositionI16(0, 0)); - static auto controller_state1 = ControllerState::create(Make::PositionI16(0, 76)); - - static void setup() { - Shared::back_menu.reset(); - controller_state0.setup(); - controller_state1.setup(); - } - - static bool update_or_exit() { - Periphery::query_controller(); - if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) { - return true; - } - - controller_state0.update(&Periphery::get_primary_controller_as(), FontWriter::bios_font_writer); - controller_state1.update(Periphery::PortCount > 1 ? &Periphery::get_controller_as(1, 0) : nullptr, FontWriter::bios_font_writer); - return false; - } - - static void render() { - GPU::render(Shared::background); - controller_state0.render(); - controller_state1.render(); - FontWriter::bios_font_writer.render(); - Shared::back_menu.render(); - } - - void main() { - setup(); - - while(true) { - if(update_or_exit()) { - break; - } - GPU::swap_buffers_vsync(1); - render(); - } - } +#include "../../../include/shared.hpp" +#include "include/controller_state.hpp" +#include + +namespace ControllerTest { + using namespace JabyEngine; + + static auto controller_state0 = ControllerState::create(Make::PositionI16(0, 0)); + static auto controller_state1 = ControllerState::create(Make::PositionI16(0, 76)); + + static void setup() { + Shared::back_menu.reset(); + controller_state0.setup(); + controller_state1.setup(); + } + + static bool update_or_exit() { + Periphery::query_controller(); + if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) { + return true; + } + + controller_state0.update(&Periphery::get_primary_controller_as(), FontWriter::bios_font_writer); + controller_state1.update(Periphery::PortCount > 1 ? &Periphery::get_controller_as(1, 0) : nullptr, FontWriter::bios_font_writer); + return false; + } + + static void render() { + GPU::render(Shared::background); + controller_state0.render(); + controller_state1.render(); + FontWriter::bios_font_writer.render(); + Shared::back_menu.render(); + } + + void main() { + setup(); + + while(true) { + if(update_or_exit()) { + break; + } + GPU::swap_buffers_vsync(1); + render(); + } + } } \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/ControllerTest/controller_test_assets.cpp b/examples/PoolBox/application/src/Overlay/ControllerTest/controller_test_assets.cpp index fef8e5ee..4a001814 100644 --- a/examples/PoolBox/application/src/Overlay/ControllerTest/controller_test_assets.cpp +++ b/examples/PoolBox/application/src/Overlay/ControllerTest/controller_test_assets.cpp @@ -1,18 +1,18 @@ -#include "include/controller_test_assets.hpp" -#include -#include - -namespace ControllerTest { - using namespace JabyEngine; - - enum LBA { - __jabyengine_start_lba_request - __jabyengine_request_lba_for(CONT, "ASSETS/CONT/CONT.IMG"), - __jabyengine_end_lba_request - }; - __declare_lba_header(LBA); - - CDFile Assets[1] = { - CDFileBuilder::simple_tim(LBA::CONT, ControllerButtonTIM), - }; -} +#include "include/controller_test_assets.hpp" +#include +#include + +namespace ControllerTest { + using namespace JabyEngine; + + enum LBA { + __jabyengine_start_lba_request + __jabyengine_request_lba_for(CONT, "ASSETS/CONT/CONT.IMG"), + __jabyengine_end_lba_request + }; + __declare_lba_header(LBA); + + CDFile Assets[1] = { + CDFileBuilder::simple_tim(LBA::CONT, ControllerButtonTIM), + }; +} diff --git a/examples/PoolBox/application/src/Overlay/ControllerTest/include/controller_state.hpp b/examples/PoolBox/application/src/Overlay/ControllerTest/include/controller_state.hpp index 5378d575..f009be4c 100644 --- a/examples/PoolBox/application/src/Overlay/ControllerTest/include/controller_state.hpp +++ b/examples/PoolBox/application/src/Overlay/ControllerTest/include/controller_state.hpp @@ -1,67 +1,67 @@ -#pragma once -#include "controller_test_assets.hpp" -#include -#include -#include - -namespace ControllerTest { - using namespace JabyEngine; - - class ControllerState { - private: - GPU::TexPage::Linked tex_page[2]; - GPU::SPRT_16::Linked buttons[2][13]; - GPU::POLY_FT4::Linked arrows[2][4]; - - public: - static constexpr ControllerState create(GPU::PositionI16 offset = Make::PositionI16(0, 0)) { - ControllerState state; - - for(auto& tex_page : state.tex_page) { - tex_page = Make::TexPage(ControllerButtonTIM.get_texture_position(), GPU::TextureColorMode::clut4).linked(); - } - - for(auto& buttons : state.buttons) { - // Triangle - buttons[0] = Make::SPRT_16(Make::Vertex(71, 0).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(0, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); - // Circle - buttons[1] = Make::SPRT_16(Make::Vertex(82, 12).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(1, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); - // Cross - buttons[2] = Make::SPRT_16(Make::Vertex(71, 23).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(2, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); - // Square - buttons[3] = Make::SPRT_16(Make::Vertex(60, 11).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(3, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); - // Play - buttons[4] = Make::SPRT_16(Make::Vertex(51, 21).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(4, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); - // Block - buttons[5] = Make::SPRT_16(Make::Vertex(24, 21).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(5, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); - // L1 - buttons[6] = Make::SPRT_16(Make::Vertex(7, 39).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(7, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); - // L2 - buttons[7] = Make::SPRT_16(Make::Vertex(7, 49).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(8, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); - // R1 - buttons[8] = Make::SPRT_16(Make::Vertex(71, 39).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(7, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); - // R2 - buttons[9] = Make::SPRT_16(Make::Vertex(71, 49).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(8, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); - // L3 - buttons[10] = Make::SPRT_16(Make::Vertex(24, 34).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(9, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); - // R3 - buttons[11] = Make::SPRT_16(Make::Vertex(52, 34).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(9, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); - // Connection Symbol - buttons[12] = Make::SPRT_16(Make::Vertex(37, 9).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(10, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); - } - - for(auto& arrows : state.arrows) { - arrows[0] = Make::POLY_FT4(__jabyengine_polyFT4_vertex_rect( Make::AreaI16(Make::PositionI16( 7, 5).move(offset.x, offset.y), Make::SizeI16(16, 16)), Make::PositionI16(6*16, 0)), Make::TPage(ControllerButtonTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4), Make::PageClut(ControllerButtonTIM.get_clut_position())).linked(); - arrows[1] = Make::POLY_FT4(__jabyengine_polyFT4_vertex_rect270(Make::AreaI16(Make::PositionI16(14, 11).move(offset.x, offset.y), Make::SizeI16(16, 16)), Make::PositionI16(6*16, 0)), Make::TPage(ControllerButtonTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4), Make::PageClut(ControllerButtonTIM.get_clut_position())).linked(); - arrows[2] = Make::POLY_FT4(__jabyengine_polyFT4_vertex_rect180(Make::AreaI16(Make::PositionI16( 7, 17).move(offset.x, offset.y), Make::SizeI16(16, 16)), Make::PositionI16(6*16, 0)), Make::TPage(ControllerButtonTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4), Make::PageClut(ControllerButtonTIM.get_clut_position())).linked(); - arrows[3] = Make::POLY_FT4(__jabyengine_polyFT4_vertex_rect90( Make::AreaI16(Make::PositionI16( 0, 11).move(offset.x, offset.y), Make::SizeI16(16, 16)), Make::PositionI16(6*16, 0)), Make::TPage(ControllerButtonTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4), Make::PageClut(ControllerButtonTIM.get_clut_position())).linked(); - } - - return state; - } - - void setup(); - void update(const Periphery::AnalogeController* controller, JabyEngine::FontWriter& font_writer); - void render(); - }; +#pragma once +#include "controller_test_assets.hpp" +#include +#include +#include + +namespace ControllerTest { + using namespace JabyEngine; + + class ControllerState { + private: + GPU::TexPage::Linked tex_page[2]; + GPU::SPRT_16::Linked buttons[2][13]; + GPU::POLY_FT4::Linked arrows[2][4]; + + public: + static constexpr ControllerState create(GPU::PositionI16 offset = Make::PositionI16(0, 0)) { + ControllerState state; + + for(auto& tex_page : state.tex_page) { + tex_page = Make::TexPage(ControllerButtonTIM.get_texture_position(), GPU::TextureColorMode::clut4).linked(); + } + + for(auto& buttons : state.buttons) { + // Triangle + buttons[0] = Make::SPRT_16(Make::Vertex(71, 0).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(0, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // Circle + buttons[1] = Make::SPRT_16(Make::Vertex(82, 12).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(1, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // Cross + buttons[2] = Make::SPRT_16(Make::Vertex(71, 23).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(2, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // Square + buttons[3] = Make::SPRT_16(Make::Vertex(60, 11).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(3, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // Play + buttons[4] = Make::SPRT_16(Make::Vertex(51, 21).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(4, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // Block + buttons[5] = Make::SPRT_16(Make::Vertex(24, 21).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(5, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // L1 + buttons[6] = Make::SPRT_16(Make::Vertex(7, 39).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(7, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // L2 + buttons[7] = Make::SPRT_16(Make::Vertex(7, 49).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(8, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // R1 + buttons[8] = Make::SPRT_16(Make::Vertex(71, 39).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(7, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // R2 + buttons[9] = Make::SPRT_16(Make::Vertex(71, 49).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(8, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // L3 + buttons[10] = Make::SPRT_16(Make::Vertex(24, 34).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(9, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // R3 + buttons[11] = Make::SPRT_16(Make::Vertex(52, 34).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(9, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + // Connection Symbol + buttons[12] = Make::SPRT_16(Make::Vertex(37, 9).move(offset.x, offset.y), Make::OffsetPageWithClut(GPU::PageOffset::from_tile_id16(10, Make::SizeI16(16, 16)), Make::PageClut(ControllerButtonTIM.get_clut_position()))).linked(); + } + + for(auto& arrows : state.arrows) { + arrows[0] = Make::POLY_FT4(__jabyengine_polyFT4_vertex_rect( Make::AreaI16(Make::PositionI16( 7, 5).move(offset.x, offset.y), Make::SizeI16(16, 16)), Make::PositionI16(6*16, 0)), Make::TPage(ControllerButtonTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4), Make::PageClut(ControllerButtonTIM.get_clut_position())).linked(); + arrows[1] = Make::POLY_FT4(__jabyengine_polyFT4_vertex_rect270(Make::AreaI16(Make::PositionI16(14, 11).move(offset.x, offset.y), Make::SizeI16(16, 16)), Make::PositionI16(6*16, 0)), Make::TPage(ControllerButtonTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4), Make::PageClut(ControllerButtonTIM.get_clut_position())).linked(); + arrows[2] = Make::POLY_FT4(__jabyengine_polyFT4_vertex_rect180(Make::AreaI16(Make::PositionI16( 7, 17).move(offset.x, offset.y), Make::SizeI16(16, 16)), Make::PositionI16(6*16, 0)), Make::TPage(ControllerButtonTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4), Make::PageClut(ControllerButtonTIM.get_clut_position())).linked(); + arrows[3] = Make::POLY_FT4(__jabyengine_polyFT4_vertex_rect90( Make::AreaI16(Make::PositionI16( 0, 11).move(offset.x, offset.y), Make::SizeI16(16, 16)), Make::PositionI16(6*16, 0)), Make::TPage(ControllerButtonTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4), Make::PageClut(ControllerButtonTIM.get_clut_position())).linked(); + } + + return state; + } + + void setup(); + void update(const Periphery::AnalogeController* controller, JabyEngine::FontWriter& font_writer); + void render(); + }; } \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/ControllerTest/include/controller_test_assets.hpp b/examples/PoolBox/application/src/Overlay/ControllerTest/include/controller_test_assets.hpp index 55764ac1..f920a6c1 100644 --- a/examples/PoolBox/application/src/Overlay/ControllerTest/include/controller_test_assets.hpp +++ b/examples/PoolBox/application/src/Overlay/ControllerTest/include/controller_test_assets.hpp @@ -1,8 +1,8 @@ -#pragma once -#include - -namespace ControllerTest { - using namespace JabyEngine; - - static constexpr auto ControllerButtonTIM = SimpleTIM::create(384, 0, 384, 511); +#pragma once +#include + +namespace ControllerTest { + using namespace JabyEngine; + + static constexpr auto ControllerButtonTIM = SimpleTIM::create(384, 0, 384, 511); } \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/FontCycler/font_cycler.cpp b/examples/PoolBox/application/src/Overlay/FontCycler/font_cycler.cpp index c5cc71e1..a6e57a70 100644 --- a/examples/PoolBox/application/src/Overlay/FontCycler/font_cycler.cpp +++ b/examples/PoolBox/application/src/Overlay/FontCycler/font_cycler.cpp @@ -1,78 +1,78 @@ -#include "../../../include/shared.hpp" -#include -#include - -namespace FontCycler { - using namespace JabyEngine; - - static const char*const ASCII = "!\"#$%&'()*+,-./0\n123456789:;<=>?@\nABCDEFGHIJKLMNOP\nQRSTUVWXYZ[\\]^_`\nabcdefghijklmnop\nqrstuvwxyz{|}~\n"; - - static JabyEngine::FontWriter*const FontWriters[] = { - &FontWriter::bios_font_writer, - &FontWriter::new_font_writer, - }; - static constexpr auto MaxFontSelector = (sizeof(FontWriters)/sizeof(FontWriters[0])) - 1; - static uint8_t font_selector = 0; - - static void increment_font_selector() { - if(font_selector == MaxFontSelector) { - font_selector = 0; - } - - else { - font_selector++; - } - } - - static void decrement_font_selector() { - if(font_selector == 0) { - font_selector = MaxFontSelector; - } - - else { - font_selector--; - } - } - - static void setup() { - Shared::back_menu.reset(); - font_selector = 0; - } - - static bool update_or_exit() { - Periphery::query_controller(); - if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) { - return true; - } - - const auto& controller = Periphery::get_primary_controller_as(); - if(controller.button.went_up(Periphery::GenericController::Button::L1)) { - decrement_font_selector(); - } - if(controller.button.went_up(Periphery::GenericController::Button::R1)) { - increment_font_selector(); - } - - auto cursor = FontWriter::update(Make::PositionI16(8, 8)); - FontWriters[font_selector]->write(cursor, ASCII); - FontWriters[font_selector]->write(cursor, "\nPress L1 or R1 to cycle\nthrough fonts"); - return false; - } - - static void render() { - FontWriters[font_selector]->render(); - Shared::back_menu.render(); - } - - void main() { - setup(); - - while(true) { - if(update_or_exit()) { - break; - } - GPU::swap_buffers_vsync(1); - render(); - } - } +#include "../../../include/shared.hpp" +#include +#include + +namespace FontCycler { + using namespace JabyEngine; + + static const char*const ASCII = "!\"#$%&'()*+,-./0\n123456789:;<=>?@\nABCDEFGHIJKLMNOP\nQRSTUVWXYZ[\\]^_`\nabcdefghijklmnop\nqrstuvwxyz{|}~\n"; + + static JabyEngine::FontWriter*const FontWriters[] = { + &FontWriter::bios_font_writer, + &FontWriter::new_font_writer, + }; + static constexpr auto MaxFontSelector = (sizeof(FontWriters)/sizeof(FontWriters[0])) - 1; + static uint8_t font_selector = 0; + + static void increment_font_selector() { + if(font_selector == MaxFontSelector) { + font_selector = 0; + } + + else { + font_selector++; + } + } + + static void decrement_font_selector() { + if(font_selector == 0) { + font_selector = MaxFontSelector; + } + + else { + font_selector--; + } + } + + static void setup() { + Shared::back_menu.reset(); + font_selector = 0; + } + + static bool update_or_exit() { + Periphery::query_controller(); + if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) { + return true; + } + + const auto& controller = Periphery::get_primary_controller_as(); + if(controller.button.went_up(Periphery::GenericController::Button::L1)) { + decrement_font_selector(); + } + if(controller.button.went_up(Periphery::GenericController::Button::R1)) { + increment_font_selector(); + } + + auto cursor = FontWriter::update(Make::PositionI16(8, 8)); + FontWriters[font_selector]->write(cursor, ASCII); + FontWriters[font_selector]->write(cursor, "\nPress L1 or R1 to cycle\nthrough fonts"); + return false; + } + + static void render() { + FontWriters[font_selector]->render(); + Shared::back_menu.render(); + } + + void main() { + setup(); + + while(true) { + if(update_or_exit()) { + break; + } + GPU::swap_buffers_vsync(1); + render(); + } + } } \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/GPUTest/gpu_test.cpp b/examples/PoolBox/application/src/Overlay/GPUTest/gpu_test.cpp index e4c85c8e..356d630d 100644 --- a/examples/PoolBox/application/src/Overlay/GPUTest/gpu_test.cpp +++ b/examples/PoolBox/application/src/Overlay/GPUTest/gpu_test.cpp @@ -1,174 +1,174 @@ -#include "../../../include/shared.hpp" -#include "include/gpu_test_assets.hpp" -#include -#include -#include -#include - -namespace GPUTest { - using namespace JabyEngine; - - // Some default values for the objects - static constexpr auto TriangleColor = GPU::Color24::from_rgb(0x0, 0xFF, 0xFF); - static constexpr auto TriangleArea = Make::AreaI16(Make::PositionI16(0, 0), Make::SizeI16(64, 64)); - static constexpr auto TriangleTPage = Make::TPage(TexPageTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4); - static constexpr auto TriangleClut = Make::PageClut(TexPageTIM.get_clut_position()); - - static constexpr auto RectangleColor = GPU::Color24::from_rgb(0x80, 0x80, 0xFF); - static constexpr auto RectangleArea = Make::AreaI16(Make::PositionI16(0, TriangleArea.size.height), Make::SizeI16(80, 80)); - static constexpr auto RectangleTPage = Make::TPage(IconTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4); - static constexpr auto RectangleClut = Make::PageClut(IconTIM.get_clut_position()); - - static constexpr auto LineColor = GPU::Color24::from_rgb(0xFF, 0x0, 0x0); - - static constexpr const auto triangle1 = Make::POLY_F3({ - Make::Vertex(TriangleArea.position.x, TriangleArea.position.y), - Make::Vertex(TriangleArea.size.width, TriangleArea.size.height), - Make::Vertex(TriangleArea.position.x, TriangleArea.size.height) - }, TriangleColor - ); - static constexpr const auto triangle2 = Make::POLY_FT3({ - Make::Vertex(TriangleArea.position.x, TriangleArea.position.y), - Make::Vertex(TriangleArea.size.width, TriangleArea.position.y), - Make::Vertex(TriangleArea.size.width, TriangleArea.size.height) - },{ - // Texture - Make::PageOffset(TriangleArea.position.x, TriangleArea.position.y), - Make::PageOffset(TriangleArea.size.width, TriangleArea.position.y), - Make::PageOffset(TriangleArea.size.width, TriangleArea.size.height) - }, TriangleTPage, TriangleClut, GPU::Color24::Grey() - ); - static constexpr const auto triangle3 = Make::POLY_G3({ - {triangle1.vertex0.move(TriangleArea.size.width, 0), GPU::Color24::Red()}, - {triangle1.vertex1.move(TriangleArea.size.width, 0), GPU::Color24::Green()}, - {triangle1.vertex2.move(TriangleArea.size.width, 0), GPU::Color24::Blue()}} - ); - static constexpr const auto triangle4 = Make::POLY_GT3({ - {triangle2.vertex0.move(TriangleArea.size.width, 0), triangle2.tex_offset0, GPU::Color24::Red()}, - {triangle2.vertex1.move(TriangleArea.size.width, 0), triangle2.tex_offset1, GPU::Color24::Blue()}, - {triangle2.vertex2.move(TriangleArea.size.width, 0), triangle2.tex_offset2, GPU::Color24::Green()}}, - TriangleTPage, - TriangleClut - ); - - static constexpr const auto rectangle1 = Make::POLY_F4(RectangleArea, RectangleColor); - static constexpr const auto rectangle2 = Make::POLY_FT4(Make::AreaI16( - RectangleArea.position.move(RectangleArea.size.width, 0), RectangleArea.size), Make::PageOffset(0, 0), - RectangleTPage, - RectangleClut, - GPU::Color24::Grey() - ); - static constexpr const auto rectangle3 = Make::POLY_G4( - {RectangleArea.position.move(RectangleArea.size.width*2, 0), RectangleArea.size}, { - GPU::Color24::Red(), - GPU::Color24::Blue(), - GPU::Color24::Green(), - GPU::Color24::White()}); - static constexpr const auto rectangle4 = Make::POLY_GT4(Make::AreaI16( - RectangleArea.position.move(RectangleArea.size.width*3, 0), RectangleArea.size), Make::PageOffset(0, 0), - RectangleTPage, - RectangleClut, { - GPU::Color24::Red(), - GPU::Color24::Blue(), - GPU::Color24::Green(), - GPU::Color24::White()} - ); - static constexpr const auto rectangle5 = Make::POLY_GT4(Make::AreaI16( - RectangleArea.position.move(0, RectangleArea.size.height), RectangleArea.size), Make::PageOffset(0, 0), - RectangleTPage, - RectangleClut, { - GPU::Color24::Red(), - GPU::Color24::Blue(), - GPU::Color24::Green(), - GPU::Color24::White()} - ).set_semi_transparent(true); - - static constexpr const auto line1 = Make::LINE_F(LineColor, - Make::Vertex(0, 0), - Make::Vertex(GPU::Display::Width, GPU::Display::Height) - ); - static constexpr const auto line2 = Make::LINE_F(LineColor.invert(), - Make::Vertex(0, 0), - Make::Vertex(16, 0), - Make::Vertex(16, 16), - Make::Vertex(0, 0) - ); - static constexpr const auto line3 = Make::LINE_G( - GPU::ColorVertex{LineColor, Make::Vertex(GPU::Display::Width, 0)}, - GPU::ColorVertex{LineColor.invert(), Make::Vertex(0, GPU::Display::Height)} - ); - static constexpr const auto line4 = Make::LINE_G( - GPU::ColorVertex{GPU::Color24::Red(), Make::Vertex(0, 0)}, - GPU::ColorVertex{GPU::Color24::Green(), Make::Vertex(0, 16)}, - GPU::ColorVertex{GPU::Color24::Blue(), Make::Vertex(16, 16)}, - GPU::ColorVertex{GPU::Color24::White(), Make::Vertex(0, 0)} - ); - - static constexpr const auto rect1 = Make::TILE(Make::AreaI16(Make::PositionI16(GPU::Display::Width - 32, GPU::Display::Height - 32), Make::SizeI16(32, 32)), GPU::Color24::Green()); - static constexpr const auto rect2 = Make::TILE_16(Make::PositionI16(GPU::Display::Width - 16, GPU::Display::Height - 16), GPU::Color24::Blue()); - static constexpr const auto rect3 = Make::TILE_8(Make::PositionI16(GPU::Display::Width - 8, GPU::Display::Height - 8), GPU::Color24::Yellow()); - static constexpr const auto rect4 = Make::TILE_1(Make::PositionI16(GPU::Display::Width - 1, GPU::Display::Height - 1), GPU::Color24::Red()); - - static constexpr const auto texpage = Make::TexPage(TexPageTIM.get_texture_position(), GPU::TextureColorMode::clut4); - static constexpr const auto rect5 = Make::SPRT(Make::AreaI16(Make::PositionI16(0, GPU::Display::Height - 32), Make::SizeI16(32, 32)), {Make::PageOffset(0, 0), TriangleClut}, GPU::Color24::Green()); - static constexpr const auto rect6 = Make::SPRT_16(Make::Vertex(0, GPU::Display::Height - 16), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Blue()); - static constexpr const auto rect7 = Make::SPRT_8(Make::Vertex(0, GPU::Display::Height - 8), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Yellow()); - static constexpr const auto rect8 = Make::SPRT_1(Make::Vertex(0, GPU::Display::Height - 1), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Red()); - - static auto rect9 = Make::SPRT(Make::AreaI16(Make::PositionI16(GPU::Display::Width/2, GPU::Display::Height/2), Make::SizeI16(32, 32)).centered(), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Grey()).linked(); - static auto rect10 = Make::SPRT(Make::AreaI16(Make::PositionI16(GPU::Display::Width/2, GPU::Display::Height/2 - 32), Make::SizeI16(32, 32)).centered(), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Grey()).linked(); - - void main() { - rect9.concat(rect10); - Shared::back_menu.reset(); - HighResTime::enable(); - - auto start_time = HighResTime::get_time_stamp(); - auto time_passed = 0; - while(true) { - // Update Phase - Periphery::query_controller(); - if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) { - break; - } - - auto cursor = FontWriter::update(Make::PositionI16((GPU::Display::Width - 160)/2, GPU::Display::Height - 32)); - FontWriter::bios_font_writer.write(cursor, "Time: %ims", GPU::Color24::Blue(), time_passed); - - GPU::swap_buffers_vsync(1); - const auto end_time = HighResTime::get_time_stamp(); - time_passed = start_time.milliseconds_to(end_time); - start_time = end_time; - - GPU::render(triangle1); - GPU::render(triangle2); - GPU::render(triangle3); - GPU::render(triangle4); - - GPU::render(rectangle1); - GPU::render(rectangle2); - GPU::render(rectangle3); - GPU::render(rectangle4); - GPU::render(rectangle5); - - GPU::render(rect1); - GPU::render(rect2); - GPU::render(rect3); - GPU::render(rect4); - GPU::render(texpage); - GPU::render(rect5); - GPU::render(rect6); - GPU::render(rect7); - GPU::render(rect8); - - GPU::render(line1); - GPU::render(line2); - GPU::render(line3); - GPU::render(line4); - - GPU::render(rect9); - Shared::back_menu.render(); - } - HighResTime::disable(); - } -} +#include "../../../include/shared.hpp" +#include "include/gpu_test_assets.hpp" +#include +#include +#include +#include + +namespace GPUTest { + using namespace JabyEngine; + + // Some default values for the objects + static constexpr auto TriangleColor = GPU::Color24::from_rgb(0x0, 0xFF, 0xFF); + static constexpr auto TriangleArea = Make::AreaI16(Make::PositionI16(0, 0), Make::SizeI16(64, 64)); + static constexpr auto TriangleTPage = Make::TPage(TexPageTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4); + static constexpr auto TriangleClut = Make::PageClut(TexPageTIM.get_clut_position()); + + static constexpr auto RectangleColor = GPU::Color24::from_rgb(0x80, 0x80, 0xFF); + static constexpr auto RectangleArea = Make::AreaI16(Make::PositionI16(0, TriangleArea.size.height), Make::SizeI16(80, 80)); + static constexpr auto RectangleTPage = Make::TPage(IconTIM.get_texture_position(), GPU::SemiTransparency::B_Half_add_F_Half, GPU::TextureColorMode::clut4); + static constexpr auto RectangleClut = Make::PageClut(IconTIM.get_clut_position()); + + static constexpr auto LineColor = GPU::Color24::from_rgb(0xFF, 0x0, 0x0); + + static constexpr const auto triangle1 = Make::POLY_F3({ + Make::Vertex(TriangleArea.position.x, TriangleArea.position.y), + Make::Vertex(TriangleArea.size.width, TriangleArea.size.height), + Make::Vertex(TriangleArea.position.x, TriangleArea.size.height) + }, TriangleColor + ); + static constexpr const auto triangle2 = Make::POLY_FT3({ + Make::Vertex(TriangleArea.position.x, TriangleArea.position.y), + Make::Vertex(TriangleArea.size.width, TriangleArea.position.y), + Make::Vertex(TriangleArea.size.width, TriangleArea.size.height) + },{ + // Texture + Make::PageOffset(TriangleArea.position.x, TriangleArea.position.y), + Make::PageOffset(TriangleArea.size.width, TriangleArea.position.y), + Make::PageOffset(TriangleArea.size.width, TriangleArea.size.height) + }, TriangleTPage, TriangleClut, GPU::Color24::Grey() + ); + static constexpr const auto triangle3 = Make::POLY_G3({ + {triangle1.vertex0.move(TriangleArea.size.width, 0), GPU::Color24::Red()}, + {triangle1.vertex1.move(TriangleArea.size.width, 0), GPU::Color24::Green()}, + {triangle1.vertex2.move(TriangleArea.size.width, 0), GPU::Color24::Blue()}} + ); + static constexpr const auto triangle4 = Make::POLY_GT3({ + {triangle2.vertex0.move(TriangleArea.size.width, 0), triangle2.tex_offset0, GPU::Color24::Red()}, + {triangle2.vertex1.move(TriangleArea.size.width, 0), triangle2.tex_offset1, GPU::Color24::Blue()}, + {triangle2.vertex2.move(TriangleArea.size.width, 0), triangle2.tex_offset2, GPU::Color24::Green()}}, + TriangleTPage, + TriangleClut + ); + + static constexpr const auto rectangle1 = Make::POLY_F4(RectangleArea, RectangleColor); + static constexpr const auto rectangle2 = Make::POLY_FT4(Make::AreaI16( + RectangleArea.position.move(RectangleArea.size.width, 0), RectangleArea.size), Make::PageOffset(0, 0), + RectangleTPage, + RectangleClut, + GPU::Color24::Grey() + ); + static constexpr const auto rectangle3 = Make::POLY_G4( + {RectangleArea.position.move(RectangleArea.size.width*2, 0), RectangleArea.size}, { + GPU::Color24::Red(), + GPU::Color24::Blue(), + GPU::Color24::Green(), + GPU::Color24::White()}); + static constexpr const auto rectangle4 = Make::POLY_GT4(Make::AreaI16( + RectangleArea.position.move(RectangleArea.size.width*3, 0), RectangleArea.size), Make::PageOffset(0, 0), + RectangleTPage, + RectangleClut, { + GPU::Color24::Red(), + GPU::Color24::Blue(), + GPU::Color24::Green(), + GPU::Color24::White()} + ); + static constexpr const auto rectangle5 = Make::POLY_GT4(Make::AreaI16( + RectangleArea.position.move(0, RectangleArea.size.height), RectangleArea.size), Make::PageOffset(0, 0), + RectangleTPage, + RectangleClut, { + GPU::Color24::Red(), + GPU::Color24::Blue(), + GPU::Color24::Green(), + GPU::Color24::White()} + ).set_semi_transparent(true); + + static constexpr const auto line1 = Make::LINE_F(LineColor, + Make::Vertex(0, 0), + Make::Vertex(GPU::Display::Width, GPU::Display::Height) + ); + static constexpr const auto line2 = Make::LINE_F(LineColor.invert(), + Make::Vertex(0, 0), + Make::Vertex(16, 0), + Make::Vertex(16, 16), + Make::Vertex(0, 0) + ); + static constexpr const auto line3 = Make::LINE_G( + GPU::ColorVertex{LineColor, Make::Vertex(GPU::Display::Width, 0)}, + GPU::ColorVertex{LineColor.invert(), Make::Vertex(0, GPU::Display::Height)} + ); + static constexpr const auto line4 = Make::LINE_G( + GPU::ColorVertex{GPU::Color24::Red(), Make::Vertex(0, 0)}, + GPU::ColorVertex{GPU::Color24::Green(), Make::Vertex(0, 16)}, + GPU::ColorVertex{GPU::Color24::Blue(), Make::Vertex(16, 16)}, + GPU::ColorVertex{GPU::Color24::White(), Make::Vertex(0, 0)} + ); + + static constexpr const auto rect1 = Make::TILE(Make::AreaI16(Make::PositionI16(GPU::Display::Width - 32, GPU::Display::Height - 32), Make::SizeI16(32, 32)), GPU::Color24::Green()); + static constexpr const auto rect2 = Make::TILE_16(Make::PositionI16(GPU::Display::Width - 16, GPU::Display::Height - 16), GPU::Color24::Blue()); + static constexpr const auto rect3 = Make::TILE_8(Make::PositionI16(GPU::Display::Width - 8, GPU::Display::Height - 8), GPU::Color24::Yellow()); + static constexpr const auto rect4 = Make::TILE_1(Make::PositionI16(GPU::Display::Width - 1, GPU::Display::Height - 1), GPU::Color24::Red()); + + static constexpr const auto texpage = Make::TexPage(TexPageTIM.get_texture_position(), GPU::TextureColorMode::clut4); + static constexpr const auto rect5 = Make::SPRT(Make::AreaI16(Make::PositionI16(0, GPU::Display::Height - 32), Make::SizeI16(32, 32)), {Make::PageOffset(0, 0), TriangleClut}, GPU::Color24::Green()); + static constexpr const auto rect6 = Make::SPRT_16(Make::Vertex(0, GPU::Display::Height - 16), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Blue()); + static constexpr const auto rect7 = Make::SPRT_8(Make::Vertex(0, GPU::Display::Height - 8), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Yellow()); + static constexpr const auto rect8 = Make::SPRT_1(Make::Vertex(0, GPU::Display::Height - 1), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Red()); + + static auto rect9 = Make::SPRT(Make::AreaI16(Make::PositionI16(GPU::Display::Width/2, GPU::Display::Height/2), Make::SizeI16(32, 32)).centered(), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Grey()).linked(); + static auto rect10 = Make::SPRT(Make::AreaI16(Make::PositionI16(GPU::Display::Width/2, GPU::Display::Height/2 - 32), Make::SizeI16(32, 32)).centered(), Make::OffsetPageWithClut(Make::PageOffset(0, 0), TriangleClut), GPU::Color24::Grey()).linked(); + + void main() { + rect9.concat(rect10); + Shared::back_menu.reset(); + HighResTime::enable(); + + auto start_time = HighResTime::get_time_stamp(); + auto time_passed = 0; + while(true) { + // Update Phase + Periphery::query_controller(); + if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) { + break; + } + + auto cursor = FontWriter::update(Make::PositionI16((GPU::Display::Width - 160)/2, GPU::Display::Height - 32)); + FontWriter::bios_font_writer.write(cursor, "Time: %ims", GPU::Color24::Blue(), time_passed); + + GPU::swap_buffers_vsync(1); + const auto end_time = HighResTime::get_time_stamp(); + time_passed = start_time.milliseconds_to(end_time); + start_time = end_time; + + GPU::render(triangle1); + GPU::render(triangle2); + GPU::render(triangle3); + GPU::render(triangle4); + + GPU::render(rectangle1); + GPU::render(rectangle2); + GPU::render(rectangle3); + GPU::render(rectangle4); + GPU::render(rectangle5); + + GPU::render(rect1); + GPU::render(rect2); + GPU::render(rect3); + GPU::render(rect4); + GPU::render(texpage); + GPU::render(rect5); + GPU::render(rect6); + GPU::render(rect7); + GPU::render(rect8); + + GPU::render(line1); + GPU::render(line2); + GPU::render(line3); + GPU::render(line4); + + GPU::render(rect9); + Shared::back_menu.render(); + } + HighResTime::disable(); + } +} diff --git a/examples/PoolBox/application/src/Overlay/GPUTest/gpu_test_assets.cpp b/examples/PoolBox/application/src/Overlay/GPUTest/gpu_test_assets.cpp index 6e74d656..6d8826c8 100644 --- a/examples/PoolBox/application/src/Overlay/GPUTest/gpu_test_assets.cpp +++ b/examples/PoolBox/application/src/Overlay/GPUTest/gpu_test_assets.cpp @@ -1,60 +1,60 @@ -#include "include/gpu_test_assets.hpp" -#include -#include - -namespace GPUTest { - using namespace JabyEngine; - - enum LBA { - __jabyengine_start_lba_request - __jabyengine_request_lba_for(TEX, "ASSETS/TEX.IMG"), - __jabyengine_request_lba_for(ICON, "ASSETS/ICON.IMG"), - __jabyengine_request_lba_for(ALL_THE_JABY, "ASSETS/ATJ.TIM"), - __jabyengine_end_lba_request - }; - __declare_lba_header(LBA); - - CDFile Assets[2] = { - CDFileBuilder::simple_tim(LBA::TEX, TexPageTIM), - CDFileBuilder::simple_tim(LBA::ICON, IconTIM), - }; - - CDFile LargeAssets[36] = { - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), - }; -} +#include "include/gpu_test_assets.hpp" +#include +#include + +namespace GPUTest { + using namespace JabyEngine; + + enum LBA { + __jabyengine_start_lba_request + __jabyengine_request_lba_for(TEX, "ASSETS/TEX.IMG"), + __jabyengine_request_lba_for(ICON, "ASSETS/ICON.IMG"), + __jabyengine_request_lba_for(ALL_THE_JABY, "ASSETS/ATJ.TIM"), + __jabyengine_end_lba_request + }; + __declare_lba_header(LBA); + + CDFile Assets[2] = { + CDFileBuilder::simple_tim(LBA::TEX, TexPageTIM), + CDFileBuilder::simple_tim(LBA::ICON, IconTIM), + }; + + CDFile LargeAssets[36] = { + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + CDFileBuilder::sony_tim(LBA::ALL_THE_JABY, TIM::create()), + }; +} diff --git a/examples/PoolBox/application/src/Overlay/GPUTest/include/gpu_test_assets.hpp b/examples/PoolBox/application/src/Overlay/GPUTest/include/gpu_test_assets.hpp index aab812d4..738d0140 100644 --- a/examples/PoolBox/application/src/Overlay/GPUTest/include/gpu_test_assets.hpp +++ b/examples/PoolBox/application/src/Overlay/GPUTest/include/gpu_test_assets.hpp @@ -1,9 +1,9 @@ -#pragma once -#include - -namespace GPUTest { - using namespace JabyEngine; - - static constexpr auto TexPageTIM = SimpleTIM::create(384, 0, 384, 511); - static constexpr auto IconTIM = SimpleTIM::create(384, 256, 384, 510); +#pragma once +#include + +namespace GPUTest { + using namespace JabyEngine; + + static constexpr auto TexPageTIM = SimpleTIM::create(384, 0, 384, 511); + static constexpr auto IconTIM = SimpleTIM::create(384, 256, 384, 510); } \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/GTETest/gte_test.cpp b/examples/PoolBox/application/src/Overlay/GTETest/gte_test.cpp index 1c683d11..e96a5f8c 100644 --- a/examples/PoolBox/application/src/Overlay/GTETest/gte_test.cpp +++ b/examples/PoolBox/application/src/Overlay/GTETest/gte_test.cpp @@ -1,166 +1,166 @@ -#include "../../../include/asset_mgr.hpp" -#include "../../../include/shared.hpp" -#include "include/GTE_Sprite.hpp" -#include "include/gte_test_assets.hpp" -#include - -namespace GTETest { - using namespace JabyEngine; - using namespace GTETest; - - namespace Jaby { - static constexpr auto AnimationTime = 250_ms; - static const struct { - gte_float scale_left; - gte_float scale_right; - } animation[] = { - {.scale_left = 1.0_gf, .scale_right = 1.0_gf}, - {.scale_left = 1.0_gf, .scale_right = 1.0_gf}, - - {.scale_left = 1.2_gf, .scale_right = 1.5_gf}, - {.scale_left = 1.5_gf, .scale_right = 1.2_gf}, - {.scale_left = 1.2_gf, .scale_right = 1.5_gf}, - {.scale_left = 1.5_gf, .scale_right = 1.2_gf}, - - {.scale_left = 1.8_gf, .scale_right = 2.3_gf}, - {.scale_left = 2.3_gf, .scale_right = 1.8_gf}, - {.scale_left = 1.8_gf, .scale_right = 2.3_gf}, - {.scale_left = 2.3_gf, .scale_right = 1.8_gf}, - - {.scale_left = 3.2_gf, .scale_right = 4.5_gf}, - {.scale_left = 4.5_gf, .scale_right = 3.2_gf}, - {.scale_left = 3.2_gf, .scale_right = 4.5_gf}, - {.scale_left = 4.5_gf, .scale_right = 3.2_gf}, - - {.scale_left = 1.8_gf, .scale_right = 2.3_gf}, - {.scale_left = 2.3_gf, .scale_right = 1.8_gf}, - {.scale_left = 1.8_gf, .scale_right = 2.3_gf}, - {.scale_left = 2.3_gf, .scale_right = 1.8_gf}, - - {.scale_left = 1.2_gf, .scale_right = 1.5_gf}, - {.scale_left = 1.5_gf, .scale_right = 1.2_gf}, - {.scale_left = 1.2_gf, .scale_right = 1.5_gf}, - {.scale_left = 1.5_gf, .scale_right = 1.2_gf}, - }; - static IntervalTimer animation_timer; - static auto animation_id = 0; - static constexpr auto Position = Make::PositionI16(GPU::Display::Width - 64, GPU::Display::Height - 64); - - static constexpr GTE_Sprite make_star_eye(GPU::PositionI16 pos) { - return GTE_Sprite::create(Make::POLY_FT4( - Make::AreaI16(pos, GPU::SizeI16(8, 8)), - JabySTARTim.get_page_offset_clut4().add(0, 64), - Make::TPage(JabySTARTim.get_texture_position(), GPU::SemiTransparency::B_add_F, GPU::TextureColorMode::clut4), - Make::PageClut(JabySTARTim.get_clut_position()), - GPU::Color24::Grey() - ).linked()); - } - - static auto star_base = Make::SPRT( - Make::AreaI16(Position, Make::SizeI16(64, 64)), - Make::OffsetPageWithClut(JabySTARTim.get_page_offset_clut4(), Make::PageClut(JabySTARTim.get_clut_position())) - ).linked(); - - static GTE_Sprite star_eyes[2] = { - make_star_eye(Position.add(11, 30)), - make_star_eye(Position.add(33, 31)) - }; - } - - namespace Background { - static constexpr auto ColorBase = 0xC0; - - static constexpr GPU::AreaI16 Area[2] = { - Make::AreaI16(-30, -30, 350, 350), - Make::AreaI16(0, 0, GPU::Display::Width, GPU::Display::Width), - }; - static constexpr GPU::PositionI16 AreaPivot[2] = { - Make::PositionI16(Area[0].size.width/2, Area[0].size.height/2), - Make::PositionI16(Area[1].size.width/2, Area[1].size.height/2), - }; - - static GPU::POLY_G4 poly[2] = { - Make::POLY_G4(Area[0], {GPU::Color24::Blue(ColorBase), GPU::Color24::Red(ColorBase), GPU::Color24::Green(ColorBase), GPU::Color24::Purple(ColorBase)}), - Make::POLY_G4(Area[1], {GPU::Color24::Blue(ColorBase), GPU::Color24::Red(ColorBase), GPU::Color24::Green(ColorBase), GPU::Color24::Purple(ColorBase)}), - }; - } - - static auto doener_fish = GTE_Sprite::create(Make::POLY_FT4( - Make::AreaI16(Make::PositionI16(0, 0), Assets::Main::DoenerFishInfo.size), - Assets::Main::DoenerFishInfo.tim.get_page_offset_clut4(), - Make::TPage(Assets::Main::DoenerFishInfo.tim.get_texture_position(), GPU::SemiTransparency::B_add_F, GPU::TextureColorMode::clut4), - Make::PageClut(Assets::Main::DoenerFishInfo.tim.get_clut_position()), - GPU::Color24::Grey() - ).linked()); - - static auto gbl_rotation = 0.0_deg; - - static void setup() { - Jaby::star_base.concat(Jaby::star_eyes[0].display.concat(Jaby::star_eyes[1].display)); - Jaby::star_eyes[0].scale = Jaby::animation[0].scale_right; - Jaby::star_eyes[1].scale = Jaby::animation[0].scale_left; - Jaby::animation_id = 1; - Jaby::animation_timer = IntervalTimer::create(Jaby::AnimationTime); - - doener_fish.area.position = GPU::PositionI16::create(100, 100); - Shared::back_menu.reset(); - - GTE::set_geom_offset(0, 0); - GTE::set_geom_screen(256); - } - - static bool update_or_exit() { - Periphery::query_controller(); - if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) { - return true; - } - - if(Jaby::animation_timer.is_expired()) { - Jaby::star_eyes[0].scale = Jaby::animation[Jaby::animation_id].scale_right; - Jaby::star_eyes[1].scale = Jaby::animation[Jaby::animation_id].scale_left; - - Jaby::animation_id = (Jaby::animation_id + 1)%(sizeof(Jaby::animation)/sizeof(Jaby::animation[0])); - Jaby::animation_timer.reset(); - } - - for(size_t n = 0; n < sizeof(Background::poly)/sizeof(Background::poly[0]); n++) { - auto matrix = [](size_t n) -> GTE::MATRIX { - auto matrix = GTE::MATRIX::translated(-Background::AreaPivot[n].x, -Background::AreaPivot[n].y); - matrix.rotate(0.0_deg, 0.0_deg, (n == 0) ? gbl_rotation : -gbl_rotation); - return matrix.translate(Background::Area[n].position.x + Background::AreaPivot[n].x, Background::Area[n].position.y + Background::AreaPivot[n].y); - }(n); - matrix.apply_to_area(Background::poly[n], Make::AreaI16(Make::PositionI16(), Background::Area[n].size)); - } - - const auto matrix = GTE::MATRIX::rotated(-gbl_rotation, gbl_rotation, -gbl_rotation); - doener_fish.apply(matrix); - Jaby::star_eyes[0].apply(); - Jaby::star_eyes[1].apply(); - - doener_fish.angle += 25.0_deg; - gbl_rotation += 2.5_deg; - return false; - } - - static void render() { - for(const auto& poly : Background::poly) { - GPU::render(poly); - } - doener_fish.render(); - GPU::render(Jaby::star_base); - Shared::back_menu.render(); - GPU::wait_for_render(); //< Because we are single buffer - } - - void main() { - setup(); - - while(true) { - if(update_or_exit()) { - break; - } - GPU::swap_buffers_vsync(1, false); - render(); - } - } +#include "../../../include/asset_mgr.hpp" +#include "../../../include/shared.hpp" +#include "include/GTE_Sprite.hpp" +#include "include/gte_test_assets.hpp" +#include + +namespace GTETest { + using namespace JabyEngine; + using namespace GTETest; + + namespace Jaby { + static constexpr auto AnimationTime = 250_ms; + static const struct { + gte_float scale_left; + gte_float scale_right; + } animation[] = { + {.scale_left = 1.0_gf, .scale_right = 1.0_gf}, + {.scale_left = 1.0_gf, .scale_right = 1.0_gf}, + + {.scale_left = 1.2_gf, .scale_right = 1.5_gf}, + {.scale_left = 1.5_gf, .scale_right = 1.2_gf}, + {.scale_left = 1.2_gf, .scale_right = 1.5_gf}, + {.scale_left = 1.5_gf, .scale_right = 1.2_gf}, + + {.scale_left = 1.8_gf, .scale_right = 2.3_gf}, + {.scale_left = 2.3_gf, .scale_right = 1.8_gf}, + {.scale_left = 1.8_gf, .scale_right = 2.3_gf}, + {.scale_left = 2.3_gf, .scale_right = 1.8_gf}, + + {.scale_left = 3.2_gf, .scale_right = 4.5_gf}, + {.scale_left = 4.5_gf, .scale_right = 3.2_gf}, + {.scale_left = 3.2_gf, .scale_right = 4.5_gf}, + {.scale_left = 4.5_gf, .scale_right = 3.2_gf}, + + {.scale_left = 1.8_gf, .scale_right = 2.3_gf}, + {.scale_left = 2.3_gf, .scale_right = 1.8_gf}, + {.scale_left = 1.8_gf, .scale_right = 2.3_gf}, + {.scale_left = 2.3_gf, .scale_right = 1.8_gf}, + + {.scale_left = 1.2_gf, .scale_right = 1.5_gf}, + {.scale_left = 1.5_gf, .scale_right = 1.2_gf}, + {.scale_left = 1.2_gf, .scale_right = 1.5_gf}, + {.scale_left = 1.5_gf, .scale_right = 1.2_gf}, + }; + static IntervalTimer animation_timer; + static auto animation_id = 0; + static constexpr auto Position = Make::PositionI16(GPU::Display::Width - 64, GPU::Display::Height - 64); + + static constexpr GTE_Sprite make_star_eye(GPU::PositionI16 pos) { + return GTE_Sprite::create(Make::POLY_FT4( + Make::AreaI16(pos, GPU::SizeI16(8, 8)), + JabySTARTim.get_page_offset_clut4().add(0, 64), + Make::TPage(JabySTARTim.get_texture_position(), GPU::SemiTransparency::B_add_F, GPU::TextureColorMode::clut4), + Make::PageClut(JabySTARTim.get_clut_position()), + GPU::Color24::Grey() + ).linked()); + } + + static auto star_base = Make::SPRT( + Make::AreaI16(Position, Make::SizeI16(64, 64)), + Make::OffsetPageWithClut(JabySTARTim.get_page_offset_clut4(), Make::PageClut(JabySTARTim.get_clut_position())) + ).linked(); + + static GTE_Sprite star_eyes[2] = { + make_star_eye(Position.add(11, 30)), + make_star_eye(Position.add(33, 31)) + }; + } + + namespace Background { + static constexpr auto ColorBase = 0xC0; + + static constexpr GPU::AreaI16 Area[2] = { + Make::AreaI16(-30, -30, 350, 350), + Make::AreaI16(0, 0, GPU::Display::Width, GPU::Display::Width), + }; + static constexpr GPU::PositionI16 AreaPivot[2] = { + Make::PositionI16(Area[0].size.width/2, Area[0].size.height/2), + Make::PositionI16(Area[1].size.width/2, Area[1].size.height/2), + }; + + static GPU::POLY_G4 poly[2] = { + Make::POLY_G4(Area[0], {GPU::Color24::Blue(ColorBase), GPU::Color24::Red(ColorBase), GPU::Color24::Green(ColorBase), GPU::Color24::Purple(ColorBase)}), + Make::POLY_G4(Area[1], {GPU::Color24::Blue(ColorBase), GPU::Color24::Red(ColorBase), GPU::Color24::Green(ColorBase), GPU::Color24::Purple(ColorBase)}), + }; + } + + static auto doener_fish = GTE_Sprite::create(Make::POLY_FT4( + Make::AreaI16(Make::PositionI16(0, 0), Assets::Main::DoenerFishInfo.size), + Assets::Main::DoenerFishInfo.tim.get_page_offset_clut4(), + Make::TPage(Assets::Main::DoenerFishInfo.tim.get_texture_position(), GPU::SemiTransparency::B_add_F, GPU::TextureColorMode::clut4), + Make::PageClut(Assets::Main::DoenerFishInfo.tim.get_clut_position()), + GPU::Color24::Grey() + ).linked()); + + static auto gbl_rotation = 0.0_deg; + + static void setup() { + Jaby::star_base.concat(Jaby::star_eyes[0].display.concat(Jaby::star_eyes[1].display)); + Jaby::star_eyes[0].scale = Jaby::animation[0].scale_right; + Jaby::star_eyes[1].scale = Jaby::animation[0].scale_left; + Jaby::animation_id = 1; + Jaby::animation_timer = IntervalTimer::create(Jaby::AnimationTime); + + doener_fish.area.position = GPU::PositionI16::create(100, 100); + Shared::back_menu.reset(); + + GTE::set_geom_offset(0, 0); + GTE::set_geom_screen(256); + } + + static bool update_or_exit() { + Periphery::query_controller(); + if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) { + return true; + } + + if(Jaby::animation_timer.is_expired()) { + Jaby::star_eyes[0].scale = Jaby::animation[Jaby::animation_id].scale_right; + Jaby::star_eyes[1].scale = Jaby::animation[Jaby::animation_id].scale_left; + + Jaby::animation_id = (Jaby::animation_id + 1)%(sizeof(Jaby::animation)/sizeof(Jaby::animation[0])); + Jaby::animation_timer.reset(); + } + + for(size_t n = 0; n < sizeof(Background::poly)/sizeof(Background::poly[0]); n++) { + auto matrix = [](size_t n) -> GTE::MATRIX { + auto matrix = GTE::MATRIX::translated(-Background::AreaPivot[n].x, -Background::AreaPivot[n].y); + matrix.rotate(0.0_deg, 0.0_deg, (n == 0) ? gbl_rotation : -gbl_rotation); + return matrix.translate(Background::Area[n].position.x + Background::AreaPivot[n].x, Background::Area[n].position.y + Background::AreaPivot[n].y); + }(n); + matrix.apply_to_area(Background::poly[n], Make::AreaI16(Make::PositionI16(), Background::Area[n].size)); + } + + const auto matrix = GTE::MATRIX::rotated(-gbl_rotation, gbl_rotation, -gbl_rotation); + doener_fish.apply(matrix); + Jaby::star_eyes[0].apply(); + Jaby::star_eyes[1].apply(); + + doener_fish.angle += 25.0_deg; + gbl_rotation += 2.5_deg; + return false; + } + + static void render() { + for(const auto& poly : Background::poly) { + GPU::render(poly); + } + doener_fish.render(); + GPU::render(Jaby::star_base); + Shared::back_menu.render(); + GPU::wait_for_render(); //< Because we are single buffer + } + + void main() { + setup(); + + while(true) { + if(update_or_exit()) { + break; + } + GPU::swap_buffers_vsync(1, false); + render(); + } + } } \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/GTETest/gte_test_assets.cpp b/examples/PoolBox/application/src/Overlay/GTETest/gte_test_assets.cpp index 10f6cb96..c62af8e1 100644 --- a/examples/PoolBox/application/src/Overlay/GTETest/gte_test_assets.cpp +++ b/examples/PoolBox/application/src/Overlay/GTETest/gte_test_assets.cpp @@ -1,15 +1,15 @@ -#include "include/gte_test_assets.hpp" -#include - -namespace GTETest { - enum LBA { - __jabyengine_start_lba_request - __jabyengine_request_lba_for(JABY_STAR, "ASSETS/GTE/JABY.IMG"), - __jabyengine_end_lba_request - }; - __declare_lba_header(LBA); - - CDFile Assets[1] = { - CDFileBuilder::simple_tim(LBA::JABY_STAR, JabySTARTim), - }; +#include "include/gte_test_assets.hpp" +#include + +namespace GTETest { + enum LBA { + __jabyengine_start_lba_request + __jabyengine_request_lba_for(JABY_STAR, "ASSETS/GTE/JABY.IMG"), + __jabyengine_end_lba_request + }; + __declare_lba_header(LBA); + + CDFile Assets[1] = { + CDFileBuilder::simple_tim(LBA::JABY_STAR, JabySTARTim), + }; } \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/GTETest/include/GTE_Sprite.hpp b/examples/PoolBox/application/src/Overlay/GTETest/include/GTE_Sprite.hpp index e6bf841f..d781d054 100644 --- a/examples/PoolBox/application/src/Overlay/GTETest/include/GTE_Sprite.hpp +++ b/examples/PoolBox/application/src/Overlay/GTETest/include/GTE_Sprite.hpp @@ -1,47 +1,47 @@ -#pragma once -#include -#include -#include - -#include - -namespace GTETest { - using namespace JabyEngine; - - struct GTE_Sprite { - GPU::AreaI16 area; - GPU::PositionI16 pivot; - deg_t angle; - gte_float scale; - GPU::POLY_FT4::Linked display; - - static constexpr GTE_Sprite create(const GPU::POLY_FT4::Linked& base) { - const auto rect_size = base->get_rect_size(); - return GTE_Sprite{ - .area = GPU::AreaI16::create(base->get_rect_pos(), rect_size), - .pivot = GPU::PositionI16::create(rect_size.width/2, rect_size.height/2), - .angle = 0.0_deg, - .scale = 1.0_gf, - .display = base - }; - } - - void apply(const GTE::MATRIX& gbl_matrix = GTE::MATRIX::identity()) { - const auto matrix = - GTE::MATRIX::translated(-this->pivot.x, -this->pivot.y, 0) - .rotate(0.0_deg, 0.0_deg, this->angle) - .scale(this->scale, this->scale) - .translate(this->area.position.x + this->pivot.x, this->area.position.y + this->pivot.y, 0) - .comp(gbl_matrix); - - this->display->vertex0 = matrix.apply_to(GPU::Vertex::create(0, 0)); - this->display->vertex1 = matrix.apply_to(GPU::Vertex::create(this->area.size.width, 0)); - this->display->vertex2 = matrix.apply_to(GPU::Vertex::create(0, this->area.size.height)); - this->display->vertex3 = matrix.apply_to(GPU::Vertex::create(this->area.size.width, this->area.size.height)); - } - - void render() { - GPU::render(this->display); - } - }; +#pragma once +#include +#include +#include + +#include + +namespace GTETest { + using namespace JabyEngine; + + struct GTE_Sprite { + GPU::AreaI16 area; + GPU::PositionI16 pivot; + deg_t angle; + gte_float scale; + GPU::POLY_FT4::Linked display; + + static constexpr GTE_Sprite create(const GPU::POLY_FT4::Linked& base) { + const auto rect_size = base->get_rect_size(); + return GTE_Sprite{ + .area = GPU::AreaI16::create(base->get_rect_pos(), rect_size), + .pivot = GPU::PositionI16::create(rect_size.width/2, rect_size.height/2), + .angle = 0.0_deg, + .scale = 1.0_gf, + .display = base + }; + } + + void apply(const GTE::MATRIX& gbl_matrix = GTE::MATRIX::identity()) { + const auto matrix = + GTE::MATRIX::translated(-this->pivot.x, -this->pivot.y, 0) + .rotate(0.0_deg, 0.0_deg, this->angle) + .scale(this->scale, this->scale) + .translate(this->area.position.x + this->pivot.x, this->area.position.y + this->pivot.y, 0) + .comp(gbl_matrix); + + this->display->vertex0 = matrix.apply_to(GPU::Vertex::create(0, 0)); + this->display->vertex1 = matrix.apply_to(GPU::Vertex::create(this->area.size.width, 0)); + this->display->vertex2 = matrix.apply_to(GPU::Vertex::create(0, this->area.size.height)); + this->display->vertex3 = matrix.apply_to(GPU::Vertex::create(this->area.size.width, this->area.size.height)); + } + + void render() { + GPU::render(this->display); + } + }; } \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/GTETest/include/gte_test_assets.hpp b/examples/PoolBox/application/src/Overlay/GTETest/include/gte_test_assets.hpp index cf3ef791..656b676b 100644 --- a/examples/PoolBox/application/src/Overlay/GTETest/include/gte_test_assets.hpp +++ b/examples/PoolBox/application/src/Overlay/GTETest/include/gte_test_assets.hpp @@ -1,13 +1,13 @@ -#pragma once -#include "../../../../include/asset_mgr.hpp" -#include - -namespace GTETest { - using namespace JabyEngine; - - static constexpr auto JabySTARTim = SimpleTIM::create( - // v Doenerfisch rotates so we need some space - Assets::Main::DoenerFishInfo.tim.get_texture_x(), Assets::Main::DoenerFishInfo.tim.get_texture_y() + Assets::Main::DoenerFishInfo.size.height + 2, - Assets::Main::DoenerFishInfo.tim.get_clut_x() + 16, Assets::Main::DoenerFishInfo.tim.get_clut_y() - ); +#pragma once +#include "../../../../include/asset_mgr.hpp" +#include + +namespace GTETest { + using namespace JabyEngine; + + static constexpr auto JabySTARTim = SimpleTIM::create( + // v Doenerfisch rotates so we need some space + Assets::Main::DoenerFishInfo.tim.get_texture_x(), Assets::Main::DoenerFishInfo.tim.get_texture_y() + Assets::Main::DoenerFishInfo.size.height + 2, + Assets::Main::DoenerFishInfo.tim.get_clut_x() + 16, Assets::Main::DoenerFishInfo.tim.get_clut_y() + ); } \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/Overlays.hpp b/examples/PoolBox/application/src/Overlay/Overlays.hpp index 0a7f1641..f1f71125 100644 --- a/examples/PoolBox/application/src/Overlay/Overlays.hpp +++ b/examples/PoolBox/application/src/Overlay/Overlays.hpp @@ -1,38 +1,38 @@ -#pragma once -#include - -namespace BIOSInfo { - void main(); -} - -namespace ControllerTest { - extern const volatile JabyEngine::AutoLBAEntry lba[]; - extern JabyEngine::CDFile Assets[1]; - - void main(); -} - -namespace GPUTest { - extern const volatile JabyEngine::AutoLBAEntry lba[]; - extern JabyEngine::CDFile Assets[2]; - extern JabyEngine::CDFile LargeAssets[36]; - - void main(); -} - -namespace GTETest { - extern const volatile JabyEngine::AutoLBAEntry lba[]; - extern JabyEngine::CDFile Assets[1]; - - void main(); -} - -namespace FontCycler { - void main(); -} - -namespace ScreenCenter { - extern const volatile JabyEngine::AutoLBAEntry lba[]; - extern JabyEngine::CDFile Assets[1]; - void main(); +#pragma once +#include + +namespace BIOSInfo { + void main(); +} + +namespace ControllerTest { + extern const volatile JabyEngine::AutoLBAEntry lba[]; + extern JabyEngine::CDFile Assets[1]; + + void main(); +} + +namespace GPUTest { + extern const volatile JabyEngine::AutoLBAEntry lba[]; + extern JabyEngine::CDFile Assets[2]; + extern JabyEngine::CDFile LargeAssets[36]; + + void main(); +} + +namespace GTETest { + extern const volatile JabyEngine::AutoLBAEntry lba[]; + extern JabyEngine::CDFile Assets[1]; + + void main(); +} + +namespace FontCycler { + void main(); +} + +namespace ScreenCenter { + extern const volatile JabyEngine::AutoLBAEntry lba[]; + extern JabyEngine::CDFile Assets[1]; + void main(); } \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/ScreenCenter/frame.cpp b/examples/PoolBox/application/src/Overlay/ScreenCenter/frame.cpp index 22900b93..0cc4f478 100644 --- a/examples/PoolBox/application/src/Overlay/ScreenCenter/frame.cpp +++ b/examples/PoolBox/application/src/Overlay/ScreenCenter/frame.cpp @@ -1,5 +1,5 @@ -#include "include/frame.hpp" -#include - -namespace ScreenCenter { +#include "include/frame.hpp" +#include + +namespace ScreenCenter { } \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/ScreenCenter/include/frame.hpp b/examples/PoolBox/application/src/Overlay/ScreenCenter/include/frame.hpp index 5a319d6e..d0525e98 100644 --- a/examples/PoolBox/application/src/Overlay/ScreenCenter/include/frame.hpp +++ b/examples/PoolBox/application/src/Overlay/ScreenCenter/include/frame.hpp @@ -1,107 +1,107 @@ -#pragma once -#include -#include -#include - -namespace ScreenCenter { - using namespace JabyEngine; - - class Frame { - private: - struct TopBorder : public GPU::internal::LinkedElementCreator { - GPU::TILE top_left[2]; - GPU::TILE top_right[2]; - - static constexpr TopBorder::Linked create(GPU::Color24 BaseColor, GPU::SizeI16 Size) { - TopBorder frame; - - frame.top_left[0] = Make::TILE(Make::AreaI16(0, 0, Size.width, Size.height), BaseColor); - frame.top_left[1] = Make::TILE(Make::AreaI16(0, 0, Size.height, Size.width), BaseColor); - - frame.top_right[0] = Make::TILE(Make::AreaI16(GPU::Display::Width - Size.width, 0, Size.width, Size.height), BaseColor); - frame.top_right[1] = Make::TILE(Make::AreaI16(GPU::Display::Width - Size.height, 0, Size.height, Size.width), BaseColor); - return frame.linked(); - } - }; - - struct BottomBorder : GPU::internal::LinkedElementCreator { - GPU::TILE bottom_left[2]; - GPU::TILE bottom_right[2]; - - static constexpr BottomBorder::Linked create(GPU::Color24 BaseColor, GPU::SizeI16 Size) { - BottomBorder frame; - - frame.bottom_left[0] = Make::TILE(Make::AreaI16(0, GPU::Display::Height - Size.width, Size.height, Size.width), BaseColor); - frame.bottom_left[1] = Make::TILE(Make::AreaI16(0, GPU::Display::Height - Size.height, Size.width, Size.height), BaseColor); - - frame.bottom_right[0] = Make::TILE(Make::AreaI16(GPU::Display::Width - Size.height, GPU::Display::Height - Size.width, Size.height, Size.width), BaseColor); - frame.bottom_right[1] = Make::TILE(Make::AreaI16(GPU::Display::Width - Size.width, GPU::Display::Height - Size.height, Size.width, Size.height), BaseColor); - return frame.linked(); - } - }; - - struct LineBorder : GPU::internal::LinkedElementCreator { - GPU::LINE_G_MULTI<5> border; - - static constexpr LineBorder::Linked create(int16_t offset = 0) { - const auto get_color = [](size_t idx, int16_t offset) -> GPU::Color24 { - const GPU::Color24 Colors[4] = {GPU::Color24::Red(), GPU::Color24::Green(), GPU::Color24::Blue(), GPU::Color24::Yellow()}; - - return Colors[(idx + offset)%4]; - }; - const int16_t origin = 0 + offset; - const int16_t width = GPU::Display::Width - 1 - offset; - const int16_t height = GPU::Display::Height - 1 - offset; - LineBorder frame; - - frame.border = Make::LINE_G( - GPU::ColorVertex{get_color(0, offset), Make::Vertex(origin, origin)}, - GPU::ColorVertex{get_color(1, offset), Make::Vertex(origin, height)}, - GPU::ColorVertex{get_color(2, offset), Make::Vertex(width, height)}, - GPU::ColorVertex{get_color(3, offset), Make::Vertex(width, origin)}, - GPU::ColorVertex{get_color(4, offset), Make::Vertex(origin, origin)} - ); - return frame.linked(); - } - }; - - struct LineCross : GPU::internal::LinkedElementCreator { - GPU::LINE_G_SINGLE cross[2]; - - static constexpr LineCross::Linked create(const decltype(LineBorder::border)& border) { - LineCross frame; - - frame.cross[0] = Make::LINE_G(border[0], border[2]); - frame.cross[1] = Make::LINE_G(border[3], border[1]); - return frame.linked(); - } - }; - - TopBorder::Linked top_border; - BottomBorder::Linked bottom_border; - LineBorder::Linked line_border[2]; - LineCross::Linked line_cross; - public: - static constexpr Frame create() { - constexpr auto BaseColor = GPU::Color24::from_rgb(0x1D, 0xA0, 0xA3); - constexpr auto Size = Make::SizeI16(64, 16); - - Frame frame; - - frame.top_border = TopBorder::create(BaseColor, Size); - frame.bottom_border = BottomBorder::create(BaseColor, Size); - frame.line_border[0] = LineBorder::create(); - frame.line_border[1] = LineBorder::create(1); - frame.line_cross = LineCross::create(frame.line_border[0]->border); - return frame; - } - - void setup() { - this->top_border.concat(this->bottom_border.concat(this->line_border[0].concat(this->line_border[1].concat(this->line_cross)))); - } - - void render() const { - GPU::render(this->top_border); - } - }; +#pragma once +#include +#include +#include + +namespace ScreenCenter { + using namespace JabyEngine; + + class Frame { + private: + struct TopBorder : public GPU::internal::LinkedElementCreator { + GPU::TILE top_left[2]; + GPU::TILE top_right[2]; + + static constexpr TopBorder::Linked create(GPU::Color24 BaseColor, GPU::SizeI16 Size) { + TopBorder frame; + + frame.top_left[0] = Make::TILE(Make::AreaI16(0, 0, Size.width, Size.height), BaseColor); + frame.top_left[1] = Make::TILE(Make::AreaI16(0, 0, Size.height, Size.width), BaseColor); + + frame.top_right[0] = Make::TILE(Make::AreaI16(GPU::Display::Width - Size.width, 0, Size.width, Size.height), BaseColor); + frame.top_right[1] = Make::TILE(Make::AreaI16(GPU::Display::Width - Size.height, 0, Size.height, Size.width), BaseColor); + return frame.linked(); + } + }; + + struct BottomBorder : GPU::internal::LinkedElementCreator { + GPU::TILE bottom_left[2]; + GPU::TILE bottom_right[2]; + + static constexpr BottomBorder::Linked create(GPU::Color24 BaseColor, GPU::SizeI16 Size) { + BottomBorder frame; + + frame.bottom_left[0] = Make::TILE(Make::AreaI16(0, GPU::Display::Height - Size.width, Size.height, Size.width), BaseColor); + frame.bottom_left[1] = Make::TILE(Make::AreaI16(0, GPU::Display::Height - Size.height, Size.width, Size.height), BaseColor); + + frame.bottom_right[0] = Make::TILE(Make::AreaI16(GPU::Display::Width - Size.height, GPU::Display::Height - Size.width, Size.height, Size.width), BaseColor); + frame.bottom_right[1] = Make::TILE(Make::AreaI16(GPU::Display::Width - Size.width, GPU::Display::Height - Size.height, Size.width, Size.height), BaseColor); + return frame.linked(); + } + }; + + struct LineBorder : GPU::internal::LinkedElementCreator { + GPU::LINE_G_MULTI<5> border; + + static constexpr LineBorder::Linked create(int16_t offset = 0) { + const auto get_color = [](size_t idx, int16_t offset) -> GPU::Color24 { + const GPU::Color24 Colors[4] = {GPU::Color24::Red(), GPU::Color24::Green(), GPU::Color24::Blue(), GPU::Color24::Yellow()}; + + return Colors[(idx + offset)%4]; + }; + const int16_t origin = 0 + offset; + const int16_t width = GPU::Display::Width - 1 - offset; + const int16_t height = GPU::Display::Height - 1 - offset; + LineBorder frame; + + frame.border = Make::LINE_G( + GPU::ColorVertex{get_color(0, offset), Make::Vertex(origin, origin)}, + GPU::ColorVertex{get_color(1, offset), Make::Vertex(origin, height)}, + GPU::ColorVertex{get_color(2, offset), Make::Vertex(width, height)}, + GPU::ColorVertex{get_color(3, offset), Make::Vertex(width, origin)}, + GPU::ColorVertex{get_color(4, offset), Make::Vertex(origin, origin)} + ); + return frame.linked(); + } + }; + + struct LineCross : GPU::internal::LinkedElementCreator { + GPU::LINE_G_SINGLE cross[2]; + + static constexpr LineCross::Linked create(const decltype(LineBorder::border)& border) { + LineCross frame; + + frame.cross[0] = Make::LINE_G(border[0], border[2]); + frame.cross[1] = Make::LINE_G(border[3], border[1]); + return frame.linked(); + } + }; + + TopBorder::Linked top_border; + BottomBorder::Linked bottom_border; + LineBorder::Linked line_border[2]; + LineCross::Linked line_cross; + public: + static constexpr Frame create() { + constexpr auto BaseColor = GPU::Color24::from_rgb(0x1D, 0xA0, 0xA3); + constexpr auto Size = Make::SizeI16(64, 16); + + Frame frame; + + frame.top_border = TopBorder::create(BaseColor, Size); + frame.bottom_border = BottomBorder::create(BaseColor, Size); + frame.line_border[0] = LineBorder::create(); + frame.line_border[1] = LineBorder::create(1); + frame.line_cross = LineCross::create(frame.line_border[0]->border); + return frame; + } + + void setup() { + this->top_border.concat(this->bottom_border.concat(this->line_border[0].concat(this->line_border[1].concat(this->line_cross)))); + } + + void render() const { + GPU::render(this->top_border); + } + }; } \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/ScreenCenter/screen_center.cpp b/examples/PoolBox/application/src/Overlay/ScreenCenter/screen_center.cpp index 50aa18b4..89d91f14 100644 --- a/examples/PoolBox/application/src/Overlay/ScreenCenter/screen_center.cpp +++ b/examples/PoolBox/application/src/Overlay/ScreenCenter/screen_center.cpp @@ -1,209 +1,209 @@ -#include "../../../include/shared.hpp" -#include "include/frame.hpp" -#include -#include -#include -#include -#include - -namespace ScreenCenter { - using namespace JabyEngine; - using GenericButton = Periphery::GenericController::Button; - - struct ButtonPulser { - static constexpr auto StartTime = 2500_ms; - static constexpr auto PulseTime = 100_ms; - - enum struct State { - WentDown, - Pulse, - Unkown - }; - - SimpleTimer timer; - uint8_t pulse_time; - - void setup() { - this->timer.reset(); - this->pulse_time = StartTime; - } - - void reset() { - ButtonPulser::setup(); - } - - State check(GenericButton button) { - const auto controller = Periphery::get_primary_controller_as(); - - if(!controller.button.was_down(button)) { - ButtonPulser::reset(); - if(controller.button.went_down(button)) { - return State::WentDown; - } - } - - if(this->timer.is_expired_for(this->pulse_time)) { - this->pulse_time = PulseTime; - this->timer.reset(); - - return State::Pulse; - } - return State::Unkown; - } - }; - - #ifdef JABYENGINE_PAL - static const char TVModeStr[] = "PAL"; - static constexpr uint16_t ScanlinesV = 288; - #else - static const char TVModeStr[] = "NTSC"; - static constexpr uint16_t ScanlinesV = 240; - #endif //JABYENGINE_PAL - - namespace PSYQ { - static const char*const Name = "PSYQ"; - - static void set_offset(uint16_t x, uint16_t y) { - GPU::Display::set_offset(x, y); - } - } - - struct Formular { - const char* name; - void (*function)(uint16_t, uint16_t); - }; - - static const Formular ScreenFormulars[] = { - Formular{.name = PSYQ::Name, .function = PSYQ::set_offset} - }; - - static constexpr const GPU::VRAM2VRAM background_img[] = { - // current_id of 0 will be rendering on (0, 256) - GPU::VRAM2VRAM::create(Make::AreaU16(384, 240, 256, 240), Make::PositionU16(32, GPU::Display::Height)), - GPU::VRAM2VRAM::create(Make::AreaU16(384, 240, 256, 240), Make::PositionU16(32, 0)), - }; - - static auto frame = Frame::create(); - - static ButtonPulser button_pulse[4]; - static void (*update)() = nullptr; - static int16_t offset_x = 0; - static int16_t offset_y = 0; - static uint8_t formular_sel = 0; - - static void update_interactive(); - static void reset_screen(); - - static void update_enter_state() { - static const char IntroductionTest[] = "Press START to begin with\n"; - static constexpr auto IntroductionTestLength = BIOSFont::Info.estimate_str_render_length(IntroductionTest); - static constexpr auto CenterPoint = Make::PositionI16((GPU::Display::Width - IntroductionTestLength)/2, (GPU::Display::Height - (2*16))/2); - - const auto controller = Periphery::get_primary_controller_as(); - - if(controller.button.went_up(GenericButton::R1) || controller.button.went_up(GenericButton::L1)) { - // Only one mode supported - //formular_sel ^= 1; - } - - if(controller.button.went_down(GenericButton::ST)) { - update = update_interactive; - } - - auto cursor = FontWriter::update(CenterPoint); - FontWriter::bios_font_writer.write(cursor, IntroductionTest, GPU::Color24::White()); - FontWriter::bios_font_writer.write(cursor, ScreenFormulars[formular_sel].name, GPU::Color24::White()); - } - - static void update_interactive() { - static const auto handle_button = [](ButtonPulser& button_pulse, GenericButton button, int16_t &dst, const int16_t mlp) { - switch(button_pulse.check(button)) { - case ButtonPulser::State::WentDown: - dst += (1*mlp); - break; - - case ButtonPulser::State::Pulse: - dst += (2*mlp); - break; - } - }; - - static const char*const ModeStr = "TV-Mode: %s\n"; - static const char*const FormularStr = "<<%s>>\n"; - static const char OffsetStr[] = "Offset: %i, %i"; - - static constexpr auto CenterLength = FontWriter::BIOSFont::Info.estimate_str_render_length(OffsetStr); - static constexpr auto CenterPoint = Make::PositionI16((GPU::Display::Width - CenterLength)/2, (GPU::Display::Height - 3*16)/2); - - const auto& screen_formular = ScreenFormulars[formular_sel]; - const auto controller = Periphery::get_primary_controller_as(); - - handle_button(button_pulse[0], GenericButton::Left, offset_x, -1); - handle_button(button_pulse[1], GenericButton::Right, offset_x, 1); - handle_button(button_pulse[2], GenericButton::Up, offset_y, -1); - handle_button(button_pulse[3], GenericButton::Down, offset_y, 1); - - if(controller.button.is_down(GenericButton::R1) && controller.button.is_down(GenericButton::L1)) { - for(auto& pulse : button_pulse) { - pulse.setup(); - } - reset_screen(); - } - - auto cursor = FontWriter::update(CenterPoint.move(-offset_x, -offset_y)); - FontWriter::bios_font_writer.write(cursor, ModeStr, GPU::Color24::White(), TVModeStr); - FontWriter::bios_font_writer.write(cursor, FormularStr, GPU::Color24::White(), screen_formular.name); - FontWriter::bios_font_writer.write(cursor, OffsetStr, GPU::Color24::White(), offset_x, offset_y); - - screen_formular.function(offset_x, offset_y); - } - - static void reset_screen() { - PSYQ::set_offset(0, 0); - offset_x = 0; - offset_y = 0; - } - - static void setup() { - Shared::back_menu.reset(); - frame.setup(); - - for(auto& pulse : button_pulse) { - pulse.setup(); - } - - update = update_enter_state; - formular_sel = 0; - offset_x = 0; - offset_y = 0; - } - - static bool update_or_exit() { - Periphery::query_controller(); - if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) { - return true; - } - - update(); - return false; - } - - static void render() { - GPU::render(background_img[GPU::Display::current_id]); - frame.render(); - Shared::back_menu.render(); - } - - void main() { - setup(); - - while(true) { - if(update_or_exit()) { - reset_screen(); - break; - } - GPU::swap_buffers_vsync(1); - render(); - } - } +#include "../../../include/shared.hpp" +#include "include/frame.hpp" +#include +#include +#include +#include +#include + +namespace ScreenCenter { + using namespace JabyEngine; + using GenericButton = Periphery::GenericController::Button; + + struct ButtonPulser { + static constexpr auto StartTime = 2500_ms; + static constexpr auto PulseTime = 100_ms; + + enum struct State { + WentDown, + Pulse, + Unkown + }; + + SimpleTimer timer; + uint8_t pulse_time; + + void setup() { + this->timer.reset(); + this->pulse_time = StartTime; + } + + void reset() { + ButtonPulser::setup(); + } + + State check(GenericButton button) { + const auto controller = Periphery::get_primary_controller_as(); + + if(!controller.button.was_down(button)) { + ButtonPulser::reset(); + if(controller.button.went_down(button)) { + return State::WentDown; + } + } + + if(this->timer.is_expired_for(this->pulse_time)) { + this->pulse_time = PulseTime; + this->timer.reset(); + + return State::Pulse; + } + return State::Unkown; + } + }; + + #ifdef JABYENGINE_PAL + static const char TVModeStr[] = "PAL"; + static constexpr uint16_t ScanlinesV = 288; + #else + static const char TVModeStr[] = "NTSC"; + static constexpr uint16_t ScanlinesV = 240; + #endif //JABYENGINE_PAL + + namespace PSYQ { + static const char*const Name = "PSYQ"; + + static void set_offset(uint16_t x, uint16_t y) { + GPU::Display::set_offset(x, y); + } + } + + struct Formular { + const char* name; + void (*function)(uint16_t, uint16_t); + }; + + static const Formular ScreenFormulars[] = { + Formular{.name = PSYQ::Name, .function = PSYQ::set_offset} + }; + + static constexpr const GPU::VRAM2VRAM background_img[] = { + // current_id of 0 will be rendering on (0, 256) + GPU::VRAM2VRAM::create(Make::AreaU16(384, 240, 256, 240), Make::PositionU16(32, GPU::Display::Height)), + GPU::VRAM2VRAM::create(Make::AreaU16(384, 240, 256, 240), Make::PositionU16(32, 0)), + }; + + static auto frame = Frame::create(); + + static ButtonPulser button_pulse[4]; + static void (*update)() = nullptr; + static int16_t offset_x = 0; + static int16_t offset_y = 0; + static uint8_t formular_sel = 0; + + static void update_interactive(); + static void reset_screen(); + + static void update_enter_state() { + static const char IntroductionTest[] = "Press START to begin with\n"; + static constexpr auto IntroductionTestLength = BIOSFont::Info.estimate_str_render_length(IntroductionTest); + static constexpr auto CenterPoint = Make::PositionI16((GPU::Display::Width - IntroductionTestLength)/2, (GPU::Display::Height - (2*16))/2); + + const auto controller = Periphery::get_primary_controller_as(); + + if(controller.button.went_up(GenericButton::R1) || controller.button.went_up(GenericButton::L1)) { + // Only one mode supported + //formular_sel ^= 1; + } + + if(controller.button.went_down(GenericButton::ST)) { + update = update_interactive; + } + + auto cursor = FontWriter::update(CenterPoint); + FontWriter::bios_font_writer.write(cursor, IntroductionTest, GPU::Color24::White()); + FontWriter::bios_font_writer.write(cursor, ScreenFormulars[formular_sel].name, GPU::Color24::White()); + } + + static void update_interactive() { + static const auto handle_button = [](ButtonPulser& button_pulse, GenericButton button, int16_t &dst, const int16_t mlp) { + switch(button_pulse.check(button)) { + case ButtonPulser::State::WentDown: + dst += (1*mlp); + break; + + case ButtonPulser::State::Pulse: + dst += (2*mlp); + break; + } + }; + + static const char*const ModeStr = "TV-Mode: %s\n"; + static const char*const FormularStr = "<<%s>>\n"; + static const char OffsetStr[] = "Offset: %i, %i"; + + static constexpr auto CenterLength = FontWriter::BIOSFont::Info.estimate_str_render_length(OffsetStr); + static constexpr auto CenterPoint = Make::PositionI16((GPU::Display::Width - CenterLength)/2, (GPU::Display::Height - 3*16)/2); + + const auto& screen_formular = ScreenFormulars[formular_sel]; + const auto controller = Periphery::get_primary_controller_as(); + + handle_button(button_pulse[0], GenericButton::Left, offset_x, -1); + handle_button(button_pulse[1], GenericButton::Right, offset_x, 1); + handle_button(button_pulse[2], GenericButton::Up, offset_y, -1); + handle_button(button_pulse[3], GenericButton::Down, offset_y, 1); + + if(controller.button.is_down(GenericButton::R1) && controller.button.is_down(GenericButton::L1)) { + for(auto& pulse : button_pulse) { + pulse.setup(); + } + reset_screen(); + } + + auto cursor = FontWriter::update(CenterPoint.move(-offset_x, -offset_y)); + FontWriter::bios_font_writer.write(cursor, ModeStr, GPU::Color24::White(), TVModeStr); + FontWriter::bios_font_writer.write(cursor, FormularStr, GPU::Color24::White(), screen_formular.name); + FontWriter::bios_font_writer.write(cursor, OffsetStr, GPU::Color24::White(), offset_x, offset_y); + + screen_formular.function(offset_x, offset_y); + } + + static void reset_screen() { + PSYQ::set_offset(0, 0); + offset_x = 0; + offset_y = 0; + } + + static void setup() { + Shared::back_menu.reset(); + frame.setup(); + + for(auto& pulse : button_pulse) { + pulse.setup(); + } + + update = update_enter_state; + formular_sel = 0; + offset_x = 0; + offset_y = 0; + } + + static bool update_or_exit() { + Periphery::query_controller(); + if(Shared::back_menu.update(Make::PositionI16(0, GPU::Display::Height - 32))) { + return true; + } + + update(); + return false; + } + + static void render() { + GPU::render(background_img[GPU::Display::current_id]); + frame.render(); + Shared::back_menu.render(); + } + + void main() { + setup(); + + while(true) { + if(update_or_exit()) { + reset_screen(); + break; + } + GPU::swap_buffers_vsync(1); + render(); + } + } } \ No newline at end of file diff --git a/examples/PoolBox/application/src/Overlay/ScreenCenter/screen_center_assets.cpp b/examples/PoolBox/application/src/Overlay/ScreenCenter/screen_center_assets.cpp index 6d1670bb..ec989dc0 100644 --- a/examples/PoolBox/application/src/Overlay/ScreenCenter/screen_center_assets.cpp +++ b/examples/PoolBox/application/src/Overlay/ScreenCenter/screen_center_assets.cpp @@ -1,17 +1,17 @@ -#include -#include - -namespace ScreenCenter { - using namespace JabyEngine; - - enum LBA { - __jabyengine_start_lba_request - __jabyengine_request_lba_for(BG_IMAGE, "ASSETS/SAND.TIM"), - __jabyengine_end_lba_request - }; - __declare_lba_header(LBA); - - CDFile Assets[1] = { - CDFileBuilder::sony_tim(LBA::BG_IMAGE, TIM::create()) - }; +#include +#include + +namespace ScreenCenter { + using namespace JabyEngine; + + enum LBA { + __jabyengine_start_lba_request + __jabyengine_request_lba_for(BG_IMAGE, "ASSETS/SAND.TIM"), + __jabyengine_end_lba_request + }; + __declare_lba_header(LBA); + + CDFile Assets[1] = { + CDFileBuilder::sony_tim(LBA::BG_IMAGE, TIM::create()) + }; } \ No newline at end of file diff --git a/examples/PoolBox/application/src/application.cpp b/examples/PoolBox/application/src/application.cpp index 11b9c4b8..b2f3b03b 100644 --- a/examples/PoolBox/application/src/application.cpp +++ b/examples/PoolBox/application/src/application.cpp @@ -1,299 +1,299 @@ -#include "../include/asset_mgr.hpp" -#include "include/font_writer.hpp" -#include "include/menu.hpp" -#include "include/paco.hpp" -#include "Overlay/Overlays.hpp" -#include -#include -#include -#include -#include -#include - -using namespace JabyEngine; -using DigitalButton = Periphery::GenericController::Button; - -struct CDPlayer { - static constexpr auto MaxChannels = 2; - - uint8_t channel; - bool is_xa; - - static constexpr CDPlayer create() { - return CDPlayer{.channel = 0, .is_xa = true}; - } - - void play() { - if(this->is_xa) { - Assets::XAAudio::play_mix(); - } - - else { - const auto [first_track, last_track] = CDDA::get_tracks(); - CDDA::play(first_track); - } - } - - void stop() { - if(this->is_xa) { - CDXA::stop(); - } - - else { - CDDA::stop(); - } - } - - void change_channel(int8_t step) { - if(this->is_xa) { - this->channel = static_cast((this->channel + step))%MaxChannels; - CDXA::set_channel(this->channel); - } - } - - void change_audio() { - CDPlayer::stop(); - this->is_xa = !this->is_xa; - CDPlayer::play(); - } - - void push() { - if(this->is_xa) { - CDXA::push_play(); - } - - else { - CDDA::push_play(); - } - } - - void pop() { - if(this->is_xa) { - CDXA::pop_play(); - } - - else { - CDDA::pop_play(); - } - } -}; - -struct StateChange { - void (*asset_load)(); - void (*main)(); - - static constexpr StateChange empty() { - return StateChange{.asset_load = nullptr, .main = nullptr}; - } - - void clear() { - this->asset_load = nullptr; - this->main = nullptr; - } - - bool contains_state() const { - return this->main; - } - - auto operator<=>(const StateChange&) const = default; -}; - -static const Menu::SimpleMenu::Entry MenuEntries[] = { - {"Controller Test"}, - {"GPU Test"}, - {"GTE Test"}, - {"Font Cycler"}, - {"Screen Center"}, - {"BIOS Information"} -}; - -static const auto doener_fish = Make::SPRT( - Make::AreaI16(Make::PositionI16(8, GPU::Display::Height - Assets::Main::DoenerFishInfo.size.height), Assets::Main::DoenerFishInfo.size), // v this needs to be nicer! Has to be - Make::OffsetPageWithClut(Assets::Main::DoenerFishInfo.tim.get_page_offset_clut4(), Make::PageClut(Assets::Main::DoenerFishInfo.tim.get_clut_position())), - GPU::Color24::Grey() -); - -static CDPlayer cd_player = CDPlayer::create(); -static object::Paco paco; -static Menu::SimpleMenu menu; -static StateChange state_changer; -static StateChange old_state_changer; - -namespace Shared { - Menu::BackMenu back_menu; - JabyEngine::GPU::POLY_G4 background = Make::POLY_G4( - Make::AreaI16(0, 0, GPU::Display::Width, GPU::Display::Height), - {GPU::Color24::Red(0xA0), GPU::Color24::Green(0xA0), GPU::Color24::Blue(0xA0), GPU::Color24::Black()} - ); - bool load_test = false; -} - -static void setup() { - Assets::Main::load(); - FontWriter::setup(); - paco.setup(); - Shared::back_menu.setup(&FontWriter::bios_font_writer); - - menu.setup([](uint32_t selection) { - switch(selection) { - case 0: - state_changer.asset_load = Assets::Overlay::load_controller_test; - state_changer.main = ControllerTest::main; - break; - - case 1: - state_changer.asset_load = Assets::Overlay::load_gpu_test; - state_changer.main = GPUTest::main; - break; - - case 2: - state_changer.asset_load = Assets::Overlay::load_gte_test; - state_changer.main = GTETest::main; - break; - - case 3: - state_changer.asset_load = Assets::Overlay::load_font_cycler; - state_changer.main = FontCycler::main; - break; - - case 4: - state_changer.asset_load = Assets::Overlay::load_screen_center; - state_changer.main = ScreenCenter::main; - break; - - case 5: - state_changer.asset_load = Assets::Overlay::load_bios_info; - state_changer.main = BIOSInfo::main; - break; - } - },MenuEntries); - cd_player.play(); -} - -namespace NormalScene { - static void update() { - static const char Title[] = ">> Pool Box <<"; - static const char Version[] = "Ver. 0.9.0"; - static constexpr auto TitleLength = DefaultFont::Info.estimate_str_render_length(Title); - static constexpr auto VersionLength = DefaultFont::Info.estimate_str_render_length(Version); - - Periphery::query_controller(); - const auto& controller = Periphery::get_primary_controller_as(); - - if(controller.is_connected()) { - if(controller.button.went_down(DigitalButton::SEL)) { - cd_player.change_audio(); - } - - if(controller.button.went_down(DigitalButton::R1)) { - cd_player.change_channel(1); - } - - if(controller.button.went_down(DigitalButton::L1)) { - cd_player.change_channel(-1); - } - - // Trigger load test - if(controller.button.is_down(DigitalButton::R2) && controller.button.is_down(DigitalButton::L2) && controller.button.is_down(DigitalButton::ST)) { - Shared::load_test = true; - } - } - - auto cursor = FontWriter::update(Make::PositionI16((GPU::Display::Width-TitleLength)/2, 16)); - paco.update(); - - FontWriter::new_font_writer.write(cursor, Title, GPU::Color24::Yellow(0xD0), &FontWriter::wiggle); - FontWriter::new_font_writer.write(cursor.change_position(Make::PositionI16((GPU::Display::Width-VersionLength)/2, 16 + DefaultFont::Info.get_kern_size().height)), Version, GPU::Color24::Green(0xD0), &FontWriter::wiggle); - menu.update(FontWriter::bios_font_writer, cursor, Make::PositionI16(8, 64)); - - cursor.change_position(Make::PositionI16(doener_fish.position.x + doener_fish.size.width, GPU::Display::Height - 48)); - FontWriter::bios_font_writer.write(cursor, "Audio:\n%s\n(SEL/R1/R2)", cd_player.is_xa ? "CD-XA" : "CD-DA"); - - if(Shared::load_test) { - // Force state change if we are in the load_test state - state_changer.asset_load = Assets::Overlay::load_large_gpu_test; - state_changer.main = GPUTest::main; - } - } - - static void render() { - GPU::render(Shared::background); - FontWriter::new_font_writer.render(); - FontWriter::bios_font_writer.render(); - paco.render(); - GPU::render(doener_fish); - } - - static void run() { - update(); - GPU::swap_buffers_vsync(1); - render(); - } -} - -namespace LoadingScene { - static SimpleTimer jaby_timer; - static uint8_t jaby_frame_offset; - - static void update() { - jaby_timer.reset(); - jaby_frame_offset = 0; - } - - static void vsync_render() { - static constexpr auto StartPosition = Make::PositionI16(24, 64); - const auto load_font = Make::SPRT( - Make::AreaI16(StartPosition.move(Assets::Main::JabyLoader::JabyFrame.size.width + 8, 0), Assets::Main::JabyLoader::FontFrame.size), - Make::OffsetPageWithClut(Assets::Main::JabyLoader::TIMLoaction.get_page_offset_clut4().move(Assets::Main::JabyLoader::FontFrame.position.x, Assets::Main::JabyLoader::FontFrame.position.y), Make::PageClut(Assets::Main::JabyLoader::TIMLoaction.get_clut_position())), - GPU::Color24::Grey() - ); - auto jaby_sprt = Make::SPRT( - Make::AreaI16(StartPosition, Assets::Main::JabyLoader::JabyFrame.size), - Make::OffsetPageWithClut(Assets::Main::JabyLoader::TIMLoaction.get_page_offset_clut4(), Make::PageClut(Assets::Main::JabyLoader::TIMLoaction.get_clut_position())), - GPU::Color24::Grey() - ); - - if(jaby_timer.is_expired_for(500_ms)) { - jaby_frame_offset = jaby_frame_offset ? 0 : 32; - jaby_timer.reset(); - } - jaby_sprt.tex_offset.add(jaby_frame_offset, 0); - - GPU::swap_buffers(!Shared::load_test); - GPU::render(jaby_sprt); - GPU::render(load_font); - jaby_sprt.position.move(Assets::Main::JabyLoader::FontFrame.size.width + Assets::Main::JabyLoader::JabyFrame.size.width + 8, 0); - GPU::render(jaby_sprt); - } - - static void run() { - if(Shared::load_test || old_state_changer != state_changer) { - GPU::set_vsync_callback(vsync_render); - - cd_player.push(); - state_changer.asset_load(); - old_state_changer = state_changer; - cd_player.pop(); - - GPU::set_vsync_callback(nullptr); - } - - state_changer.main(); - state_changer.clear(); - } -} - -void main() { - const auto& controller = Periphery::get_primary_controller_as(); - - setup(); - while(true) { - if(state_changer.contains_state()) { - LoadingScene::run(); - } - - else { - NormalScene::run(); - } - } +#include "../include/asset_mgr.hpp" +#include "include/font_writer.hpp" +#include "include/menu.hpp" +#include "include/paco.hpp" +#include "Overlay/Overlays.hpp" +#include +#include +#include +#include +#include +#include + +using namespace JabyEngine; +using DigitalButton = Periphery::GenericController::Button; + +struct CDPlayer { + static constexpr auto MaxChannels = 2; + + uint8_t channel; + bool is_xa; + + static constexpr CDPlayer create() { + return CDPlayer{.channel = 0, .is_xa = true}; + } + + void play() { + if(this->is_xa) { + Assets::XAAudio::play_mix(); + } + + else { + const auto [first_track, last_track] = CDDA::get_tracks(); + CDDA::play(first_track); + } + } + + void stop() { + if(this->is_xa) { + CDXA::stop(); + } + + else { + CDDA::stop(); + } + } + + void change_channel(int8_t step) { + if(this->is_xa) { + this->channel = static_cast((this->channel + step))%MaxChannels; + CDXA::set_channel(this->channel); + } + } + + void change_audio() { + CDPlayer::stop(); + this->is_xa = !this->is_xa; + CDPlayer::play(); + } + + void push() { + if(this->is_xa) { + CDXA::push_play(); + } + + else { + CDDA::push_play(); + } + } + + void pop() { + if(this->is_xa) { + CDXA::pop_play(); + } + + else { + CDDA::pop_play(); + } + } +}; + +struct StateChange { + void (*asset_load)(); + void (*main)(); + + static constexpr StateChange empty() { + return StateChange{.asset_load = nullptr, .main = nullptr}; + } + + void clear() { + this->asset_load = nullptr; + this->main = nullptr; + } + + bool contains_state() const { + return this->main; + } + + auto operator<=>(const StateChange&) const = default; +}; + +static const Menu::SimpleMenu::Entry MenuEntries[] = { + {"Controller Test"}, + {"GPU Test"}, + {"GTE Test"}, + {"Font Cycler"}, + {"Screen Center"}, + {"BIOS Information"} +}; + +static const auto doener_fish = Make::SPRT( + Make::AreaI16(Make::PositionI16(8, GPU::Display::Height - Assets::Main::DoenerFishInfo.size.height), Assets::Main::DoenerFishInfo.size), // v this needs to be nicer! Has to be + Make::OffsetPageWithClut(Assets::Main::DoenerFishInfo.tim.get_page_offset_clut4(), Make::PageClut(Assets::Main::DoenerFishInfo.tim.get_clut_position())), + GPU::Color24::Grey() +); + +static CDPlayer cd_player = CDPlayer::create(); +static object::Paco paco; +static Menu::SimpleMenu menu; +static StateChange state_changer; +static StateChange old_state_changer; + +namespace Shared { + Menu::BackMenu back_menu; + JabyEngine::GPU::POLY_G4 background = Make::POLY_G4( + Make::AreaI16(0, 0, GPU::Display::Width, GPU::Display::Height), + {GPU::Color24::Red(0xA0), GPU::Color24::Green(0xA0), GPU::Color24::Blue(0xA0), GPU::Color24::Black()} + ); + bool load_test = false; +} + +static void setup() { + Assets::Main::load(); + FontWriter::setup(); + paco.setup(); + Shared::back_menu.setup(&FontWriter::bios_font_writer); + + menu.setup([](uint32_t selection) { + switch(selection) { + case 0: + state_changer.asset_load = Assets::Overlay::load_controller_test; + state_changer.main = ControllerTest::main; + break; + + case 1: + state_changer.asset_load = Assets::Overlay::load_gpu_test; + state_changer.main = GPUTest::main; + break; + + case 2: + state_changer.asset_load = Assets::Overlay::load_gte_test; + state_changer.main = GTETest::main; + break; + + case 3: + state_changer.asset_load = Assets::Overlay::load_font_cycler; + state_changer.main = FontCycler::main; + break; + + case 4: + state_changer.asset_load = Assets::Overlay::load_screen_center; + state_changer.main = ScreenCenter::main; + break; + + case 5: + state_changer.asset_load = Assets::Overlay::load_bios_info; + state_changer.main = BIOSInfo::main; + break; + } + },MenuEntries); + cd_player.play(); +} + +namespace NormalScene { + static void update() { + static const char Title[] = ">> Pool Box <<"; + static const char Version[] = "Ver. 0.9.0"; + static constexpr auto TitleLength = DefaultFont::Info.estimate_str_render_length(Title); + static constexpr auto VersionLength = DefaultFont::Info.estimate_str_render_length(Version); + + Periphery::query_controller(); + const auto& controller = Periphery::get_primary_controller_as(); + + if(controller.is_connected()) { + if(controller.button.went_down(DigitalButton::SEL)) { + cd_player.change_audio(); + } + + if(controller.button.went_down(DigitalButton::R1)) { + cd_player.change_channel(1); + } + + if(controller.button.went_down(DigitalButton::L1)) { + cd_player.change_channel(-1); + } + + // Trigger load test + if(controller.button.is_down(DigitalButton::R2) && controller.button.is_down(DigitalButton::L2) && controller.button.is_down(DigitalButton::ST)) { + Shared::load_test = true; + } + } + + auto cursor = FontWriter::update(Make::PositionI16((GPU::Display::Width-TitleLength)/2, 16)); + paco.update(); + + FontWriter::new_font_writer.write(cursor, Title, GPU::Color24::Yellow(0xD0), &FontWriter::wiggle); + FontWriter::new_font_writer.write(cursor.change_position(Make::PositionI16((GPU::Display::Width-VersionLength)/2, 16 + DefaultFont::Info.get_kern_size().height)), Version, GPU::Color24::Green(0xD0), &FontWriter::wiggle); + menu.update(FontWriter::bios_font_writer, cursor, Make::PositionI16(8, 64)); + + cursor.change_position(Make::PositionI16(doener_fish.position.x + doener_fish.size.width, GPU::Display::Height - 48)); + FontWriter::bios_font_writer.write(cursor, "Audio:\n%s\n(SEL/R1/R2)", cd_player.is_xa ? "CD-XA" : "CD-DA"); + + if(Shared::load_test) { + // Force state change if we are in the load_test state + state_changer.asset_load = Assets::Overlay::load_large_gpu_test; + state_changer.main = GPUTest::main; + } + } + + static void render() { + GPU::render(Shared::background); + FontWriter::new_font_writer.render(); + FontWriter::bios_font_writer.render(); + paco.render(); + GPU::render(doener_fish); + } + + static void run() { + update(); + GPU::swap_buffers_vsync(1); + render(); + } +} + +namespace LoadingScene { + static SimpleTimer jaby_timer; + static uint8_t jaby_frame_offset; + + static void update() { + jaby_timer.reset(); + jaby_frame_offset = 0; + } + + static void vsync_render() { + static constexpr auto StartPosition = Make::PositionI16(24, 64); + const auto load_font = Make::SPRT( + Make::AreaI16(StartPosition.move(Assets::Main::JabyLoader::JabyFrame.size.width + 8, 0), Assets::Main::JabyLoader::FontFrame.size), + Make::OffsetPageWithClut(Assets::Main::JabyLoader::TIMLoaction.get_page_offset_clut4().move(Assets::Main::JabyLoader::FontFrame.position.x, Assets::Main::JabyLoader::FontFrame.position.y), Make::PageClut(Assets::Main::JabyLoader::TIMLoaction.get_clut_position())), + GPU::Color24::Grey() + ); + auto jaby_sprt = Make::SPRT( + Make::AreaI16(StartPosition, Assets::Main::JabyLoader::JabyFrame.size), + Make::OffsetPageWithClut(Assets::Main::JabyLoader::TIMLoaction.get_page_offset_clut4(), Make::PageClut(Assets::Main::JabyLoader::TIMLoaction.get_clut_position())), + GPU::Color24::Grey() + ); + + if(jaby_timer.is_expired_for(500_ms)) { + jaby_frame_offset = jaby_frame_offset ? 0 : 32; + jaby_timer.reset(); + } + jaby_sprt.tex_offset.add(jaby_frame_offset, 0); + + GPU::swap_buffers(!Shared::load_test); + GPU::render(jaby_sprt); + GPU::render(load_font); + jaby_sprt.position.move(Assets::Main::JabyLoader::FontFrame.size.width + Assets::Main::JabyLoader::JabyFrame.size.width + 8, 0); + GPU::render(jaby_sprt); + } + + static void run() { + if(Shared::load_test || old_state_changer != state_changer) { + GPU::set_vsync_callback(vsync_render); + + cd_player.push(); + state_changer.asset_load(); + old_state_changer = state_changer; + cd_player.pop(); + + GPU::set_vsync_callback(nullptr); + } + + state_changer.main(); + state_changer.clear(); + } +} + +void main() { + const auto& controller = Periphery::get_primary_controller_as(); + + setup(); + while(true) { + if(state_changer.contains_state()) { + LoadingScene::run(); + } + + else { + NormalScene::run(); + } + } } \ No newline at end of file diff --git a/examples/PoolBox/application/src/asset_mgr.cpp b/examples/PoolBox/application/src/asset_mgr.cpp index 8f19c5bc..4c16542c 100644 --- a/examples/PoolBox/application/src/asset_mgr.cpp +++ b/examples/PoolBox/application/src/asset_mgr.cpp @@ -1,135 +1,135 @@ -#include "../include/asset_mgr.hpp" -#include "Custom/custom_files.hpp" -#include "Overlay/Overlays.hpp" -#include -#include -#include -#include -#include - -extern "C" uint32_t __bios_info_start; -extern "C" uint32_t __controller_tests_start; -extern "C" uint32_t __gpu_tests_start; -extern "C" uint32_t __gte_tests_start; -extern "C" uint32_t __font_cycler_start; -extern "C" uint32_t __screen_center_start; - -namespace Assets { - enum LBA { - __jabyengine_start_lba_request - __jabyengine_request_lba_for(PACO, "ASSETS/MAIN/PACO.IMG"), - __jabyengine_request_lba_for(DFISH, "ASSETS/MAIN/DFISH.IMG"), - __jabyengine_request_lba_for(JABY_LOAD, "ASSETS/MAIN/LOAD.IMG"), - __jabyengine_request_lba_for(APPLE_SFX, "SFX/APPLE.VAG"), - __jabyengine_request_lba_for(BLUBB_SFX, "SFX/BLUBB.VAG"), - __jabyengine_request_lba_for(FRIEND_SFX, "SFX/FRIEND.VAG"), - __jabyengine_request_lba_for(MIX_XA, "XAAUDIO/MIX.XA"), - __jabyengine_request_lba_for(BIOS_INFO_OVL, "BIO.BIN"), - __jabyengine_request_lba_for(GPU_TEST_OVL, "GTO.BIN"), - __jabyengine_request_lba_for(GTE_TEST_OVL, "GTE.BIN"), - __jabyengine_request_lba_for(CONT_TEST_OVL, "CTO.BIN"), - __jabyengine_request_lba_for(FONT_CYC_OVL, "FCO.BIN"), - __jabyengine_request_lba_for(SCREEN_CENT_OVL, "SCO.BIN"), - __jabyengine_end_lba_request - }; - __declare_lba_header(LBA); - - static void load(const volatile AutoLBAEntry* lba, const CDFile* assets, size_t size) { - const auto buffer_cfg = CDFileProcessor::BufferConfiguration::new_default(); - CDFileProcessor file_processor; - - file_processor.setup(lba, CDFileProcessor::JobArray{assets, size}, buffer_cfg); - while(true) { - switch(file_processor.process()) { - case Progress::InProgress: - break; - - case Progress::Done: - if(!file_processor.next(lba, buffer_cfg)) { - return; - } - break; - - case Progress::Error: - printf("Error detected! Aborting load\n"); - return; - } - } - file_processor.shutdown(); - } - - template - static void load(const volatile AutoLBAEntry* lba, const CDFile (&files)[N]) { - return load(lba, files, N); - } - - namespace Main { - using SPU::operator""_vol; - - static const CDFile Files[] = { - CDFileBuilder::simple_tim(LBA::PACO, PacoTIM), - CDFileBuilder::simple_tim(LBA::DFISH, DoenerFishInfo.tim), - CDFileBuilder::simple_tim(LBA::JABY_LOAD, JabyLoader::TIMLoaction), - CDFileBuilder::sony_vag(LBA::APPLE_SFX, VAG::create(0, 1.0_vol)), - CDFileBuilder::sony_vag(LBA::BLUBB_SFX, VAG::create(1, 1.0_vol)), - CDFileBuilder::sony_vag(LBA::FRIEND_SFX, VAG::create(2, 1.0_vol)), - CustomCDFileBuilder::jingle(2), - }; - - void load() { - ::Assets::load(lba, Files); - } - } - - namespace Overlay { - static void load(const CDFile& overlay_file, const volatile AutoLBAEntry* overlay_lba, const CDFile* overlay_assets, size_t size) { - ::Assets::load(lba, &overlay_file, 1); - if(overlay_lba) { - ::Assets::load(overlay_lba, overlay_assets, size); - } - } - - static void load(const CDFile& overlay_file) { - load(overlay_file, nullptr, nullptr, 0ull); - } - - template - static void load(const CDFile& overlay_file, const volatile AutoLBAEntry* overlay_lba, const CDFile (&overlay_assets)[N]) { - load(overlay_file, overlay_lba, overlay_assets, N); - } - - void load_bios_info() { - load(CDFileBuilder::overlay(LBA::BIOS_INFO_OVL, &__bios_info_start)); - } - - void load_controller_test() { - load(CDFileBuilder::overlay(LBA::CONT_TEST_OVL, &__controller_tests_start), ControllerTest::lba, ControllerTest::Assets); - } - - void load_gpu_test() { - load(CDFileBuilder::overlay(LBA::GPU_TEST_OVL, &__gpu_tests_start), GPUTest::lba, GPUTest::Assets); - } - - void load_large_gpu_test() { - load(CDFileBuilder::overlay(LBA::GPU_TEST_OVL, &__gpu_tests_start), GPUTest::lba, GPUTest::LargeAssets); - } - - void load_gte_test() { - load(CDFileBuilder::overlay(LBA::GTE_TEST_OVL, &__gte_tests_start), GTETest::lba, GTETest::Assets); - } - - void load_font_cycler() { - load(CDFileBuilder::overlay(LBA::FONT_CYC_OVL, &__font_cycler_start)); - } - - void load_screen_center() { - load(CDFileBuilder::overlay(LBA::SCREEN_CENT_OVL, &__screen_center_start), ScreenCenter::lba, ScreenCenter::Assets); - } - } - - namespace XAAudio { - void play_mix() { - CDXA::play(lba, MIX_XA, 0, false); - } - } +#include "../include/asset_mgr.hpp" +#include "Custom/custom_files.hpp" +#include "Overlay/Overlays.hpp" +#include +#include +#include +#include +#include + +extern "C" uint32_t __bios_info_start; +extern "C" uint32_t __controller_tests_start; +extern "C" uint32_t __gpu_tests_start; +extern "C" uint32_t __gte_tests_start; +extern "C" uint32_t __font_cycler_start; +extern "C" uint32_t __screen_center_start; + +namespace Assets { + enum LBA { + __jabyengine_start_lba_request + __jabyengine_request_lba_for(PACO, "ASSETS/MAIN/PACO.IMG"), + __jabyengine_request_lba_for(DFISH, "ASSETS/MAIN/DFISH.IMG"), + __jabyengine_request_lba_for(JABY_LOAD, "ASSETS/MAIN/LOAD.IMG"), + __jabyengine_request_lba_for(APPLE_SFX, "SFX/APPLE.VAG"), + __jabyengine_request_lba_for(BLUBB_SFX, "SFX/BLUBB.VAG"), + __jabyengine_request_lba_for(FRIEND_SFX, "SFX/FRIEND.VAG"), + __jabyengine_request_lba_for(MIX_XA, "XAAUDIO/MIX.XA"), + __jabyengine_request_lba_for(BIOS_INFO_OVL, "BIO.BIN"), + __jabyengine_request_lba_for(GPU_TEST_OVL, "GTO.BIN"), + __jabyengine_request_lba_for(GTE_TEST_OVL, "GTE.BIN"), + __jabyengine_request_lba_for(CONT_TEST_OVL, "CTO.BIN"), + __jabyengine_request_lba_for(FONT_CYC_OVL, "FCO.BIN"), + __jabyengine_request_lba_for(SCREEN_CENT_OVL, "SCO.BIN"), + __jabyengine_end_lba_request + }; + __declare_lba_header(LBA); + + static void load(const volatile AutoLBAEntry* lba, const CDFile* assets, size_t size) { + const auto buffer_cfg = CDFileProcessor::BufferConfiguration::new_default(); + CDFileProcessor file_processor; + + file_processor.setup(lba, CDFileProcessor::JobArray{assets, size}, buffer_cfg); + while(true) { + switch(file_processor.process()) { + case Progress::InProgress: + break; + + case Progress::Done: + if(!file_processor.next(lba, buffer_cfg)) { + return; + } + break; + + case Progress::Error: + printf("Error detected! Aborting load\n"); + return; + } + } + file_processor.shutdown(); + } + + template + static void load(const volatile AutoLBAEntry* lba, const CDFile (&files)[N]) { + return load(lba, files, N); + } + + namespace Main { + using SPU::operator""_vol; + + static const CDFile Files[] = { + CDFileBuilder::simple_tim(LBA::PACO, PacoTIM), + CDFileBuilder::simple_tim(LBA::DFISH, DoenerFishInfo.tim), + CDFileBuilder::simple_tim(LBA::JABY_LOAD, JabyLoader::TIMLoaction), + CDFileBuilder::sony_vag(LBA::APPLE_SFX, VAG::create(0, 1.0_vol)), + CDFileBuilder::sony_vag(LBA::BLUBB_SFX, VAG::create(1, 1.0_vol)), + CDFileBuilder::sony_vag(LBA::FRIEND_SFX, VAG::create(2, 1.0_vol)), + CustomCDFileBuilder::jingle(2), + }; + + void load() { + ::Assets::load(lba, Files); + } + } + + namespace Overlay { + static void load(const CDFile& overlay_file, const volatile AutoLBAEntry* overlay_lba, const CDFile* overlay_assets, size_t size) { + ::Assets::load(lba, &overlay_file, 1); + if(overlay_lba) { + ::Assets::load(overlay_lba, overlay_assets, size); + } + } + + static void load(const CDFile& overlay_file) { + load(overlay_file, nullptr, nullptr, 0ull); + } + + template + static void load(const CDFile& overlay_file, const volatile AutoLBAEntry* overlay_lba, const CDFile (&overlay_assets)[N]) { + load(overlay_file, overlay_lba, overlay_assets, N); + } + + void load_bios_info() { + load(CDFileBuilder::overlay(LBA::BIOS_INFO_OVL, &__bios_info_start)); + } + + void load_controller_test() { + load(CDFileBuilder::overlay(LBA::CONT_TEST_OVL, &__controller_tests_start), ControllerTest::lba, ControllerTest::Assets); + } + + void load_gpu_test() { + load(CDFileBuilder::overlay(LBA::GPU_TEST_OVL, &__gpu_tests_start), GPUTest::lba, GPUTest::Assets); + } + + void load_large_gpu_test() { + load(CDFileBuilder::overlay(LBA::GPU_TEST_OVL, &__gpu_tests_start), GPUTest::lba, GPUTest::LargeAssets); + } + + void load_gte_test() { + load(CDFileBuilder::overlay(LBA::GTE_TEST_OVL, &__gte_tests_start), GTETest::lba, GTETest::Assets); + } + + void load_font_cycler() { + load(CDFileBuilder::overlay(LBA::FONT_CYC_OVL, &__font_cycler_start)); + } + + void load_screen_center() { + load(CDFileBuilder::overlay(LBA::SCREEN_CENT_OVL, &__screen_center_start), ScreenCenter::lba, ScreenCenter::Assets); + } + } + + namespace XAAudio { + void play_mix() { + CDXA::play(lba, MIX_XA, 0, false); + } + } } \ No newline at end of file diff --git a/examples/PoolBox/application/src/font_writer.cpp b/examples/PoolBox/application/src/font_writer.cpp index 3ee50adc..f77c9f1d 100644 --- a/examples/PoolBox/application/src/font_writer.cpp +++ b/examples/PoolBox/application/src/font_writer.cpp @@ -1,35 +1,35 @@ -#include "include/font_writer.hpp" -#include -#include //< only for __heap_start D: -#include - -namespace FontWriter { - using namespace JabyEngine; - - static constexpr auto LibraryFontTIM = SimpleTIM::create(320, 0, 320, DefaultFont::Info.texture_size.height); - - static FontPrimitive font_buffer[2*256]; - Wiggle wiggle = {Make::PositionI8(0, 0), Make::PositionI8(1, -2), Make::PositionI8(0, -4), Make::PositionI8(-1, -2), Make::PositionI8(0, 0), Make::PositionI8(1, 2), Make::PositionI8(0, 4), Make::PositionI8(-1, 2)}; - JabyEngine::FontWriter new_font_writer = JabyEngine::FontWriter::empty(); - JabyEngine::FontWriter bios_font_writer = JabyEngine::FontWriter::empty(); - static SimpleTimer timer; - uint8_t wiggle_count = 0; - - void setup() { - JabyEngine::DefaultFont::load(&__heap_start, LibraryFontTIM); - JabyEngine::GlobalFontPrimitivePool::setup(font_buffer); - - new_font_writer.setup(LibraryFontTIM, JabyEngine::DefaultFont::Info); - bios_font_writer.setup(JabyEngine::BIOSFont::TIM, JabyEngine::BIOSFont::Info); - timer.reset(); - } - - Cursor update(const GPU::PositionI16& start) { - if(timer.is_expired_for(50_ms)) { - timer.reset(); - wiggle_count++; - } - - return Cursor::create(start, wiggle_count); - } +#include "include/font_writer.hpp" +#include +#include //< only for __heap_start D: +#include + +namespace FontWriter { + using namespace JabyEngine; + + static constexpr auto LibraryFontTIM = SimpleTIM::create(320, 0, 320, DefaultFont::Info.texture_size.height); + + static FontPrimitive font_buffer[2*256]; + Wiggle wiggle = {Make::PositionI8(0, 0), Make::PositionI8(1, -2), Make::PositionI8(0, -4), Make::PositionI8(-1, -2), Make::PositionI8(0, 0), Make::PositionI8(1, 2), Make::PositionI8(0, 4), Make::PositionI8(-1, 2)}; + JabyEngine::FontWriter new_font_writer = JabyEngine::FontWriter::empty(); + JabyEngine::FontWriter bios_font_writer = JabyEngine::FontWriter::empty(); + static SimpleTimer timer; + uint8_t wiggle_count = 0; + + void setup() { + JabyEngine::DefaultFont::load(&__heap_start, LibraryFontTIM); + JabyEngine::GlobalFontPrimitivePool::setup(font_buffer); + + new_font_writer.setup(LibraryFontTIM, JabyEngine::DefaultFont::Info); + bios_font_writer.setup(JabyEngine::BIOSFont::TIM, JabyEngine::BIOSFont::Info); + timer.reset(); + } + + Cursor update(const GPU::PositionI16& start) { + if(timer.is_expired_for(50_ms)) { + timer.reset(); + wiggle_count++; + } + + return Cursor::create(start, wiggle_count); + } } \ No newline at end of file diff --git a/examples/PoolBox/application/src/include/font_writer.hpp b/examples/PoolBox/application/src/include/font_writer.hpp index 8397a0ec..90ec013e 100644 --- a/examples/PoolBox/application/src/include/font_writer.hpp +++ b/examples/PoolBox/application/src/include/font_writer.hpp @@ -1,14 +1,14 @@ -#pragma once -#include -#include - -namespace FontWriter { - using namespace JabyEngine; - - extern Wiggle wiggle; - extern JabyEngine::FontWriter new_font_writer; - extern JabyEngine::FontWriter bios_font_writer; - - void setup(); - Cursor update(const GPU::PositionI16& start); +#pragma once +#include +#include + +namespace FontWriter { + using namespace JabyEngine; + + extern Wiggle wiggle; + extern JabyEngine::FontWriter new_font_writer; + extern JabyEngine::FontWriter bios_font_writer; + + void setup(); + Cursor update(const GPU::PositionI16& start); } \ No newline at end of file diff --git a/examples/PoolBox/application/src/include/menu.hpp b/examples/PoolBox/application/src/include/menu.hpp index 37c29760..1f88419c 100644 --- a/examples/PoolBox/application/src/include/menu.hpp +++ b/examples/PoolBox/application/src/include/menu.hpp @@ -1,50 +1,50 @@ -#pragma once -#include "font_writer.hpp" -#include -#include - -namespace Menu { - using namespace JabyEngine; - - class SimpleMenu { - public: - struct Entry { - const char* name; - }; - - typedef void (*Callback)(uint32_t selection); - - private: - Callback selection_callback; - const Entry* entries; - size_t size; - uint8_t cur_selection; - - public: - void setup(Callback callback, const Entry* entries, size_t size); - - template - void setup(Callback callback, const Entry (&entries)[N]) { - SimpleMenu::setup(callback, entries, N); - } - - void update(JabyEngine::FontWriter& font_writer, Cursor& cursor, const GPU::PositionI16& start); - }; - - class BackMenu { - private: - JabyEngine::FontWriter* font_writer; - SimpleTimer timeout; - bool waiting; - - public: - void setup(JabyEngine::FontWriter* font_writer); - void reset() { - this->timeout.reset(); - this->waiting = false; - } - - bool update(const GPU::PositionI16& position, bool auto_clear = true); - void render(); - }; +#pragma once +#include "font_writer.hpp" +#include +#include + +namespace Menu { + using namespace JabyEngine; + + class SimpleMenu { + public: + struct Entry { + const char* name; + }; + + typedef void (*Callback)(uint32_t selection); + + private: + Callback selection_callback; + const Entry* entries; + size_t size; + uint8_t cur_selection; + + public: + void setup(Callback callback, const Entry* entries, size_t size); + + template + void setup(Callback callback, const Entry (&entries)[N]) { + SimpleMenu::setup(callback, entries, N); + } + + void update(JabyEngine::FontWriter& font_writer, Cursor& cursor, const GPU::PositionI16& start); + }; + + class BackMenu { + private: + JabyEngine::FontWriter* font_writer; + SimpleTimer timeout; + bool waiting; + + public: + void setup(JabyEngine::FontWriter* font_writer); + void reset() { + this->timeout.reset(); + this->waiting = false; + } + + bool update(const GPU::PositionI16& position, bool auto_clear = true); + void render(); + }; } \ No newline at end of file diff --git a/examples/PoolBox/application/src/include/paco.hpp b/examples/PoolBox/application/src/include/paco.hpp index ab64ccc8..3e2cb339 100644 --- a/examples/PoolBox/application/src/include/paco.hpp +++ b/examples/PoolBox/application/src/include/paco.hpp @@ -1,35 +1,35 @@ -#pragma once -#include "../../include/asset_mgr.hpp" -#include -#include - -namespace object { - using namespace JabyEngine; - - class Paco { - private: - static constexpr auto Size = Make::SizeI16(120, 128); - static const GPU::Color24 Colors[]; - - GPU::TexPage::Linked tex_page; - GPU::SPRT::Linked sprite; - SimpleTimer timer; - uint8_t color_idx; - - public: - constexpr Paco() : - tex_page(Make::TexPage(Make::PositionU16( - Assets::Main::PacoTIM.get_texture_x(), Assets::Main::PacoTIM.get_texture_y()), - GPU::TextureColorMode::clut4).linked()), - sprite(Make::SPRT( - Make::AreaI16(Make::PositionI16(GPU::Display::Width - Size.width, GPU::Display::Height - Size.height), Size), - Make::OffsetPageWithClut(Make::PageOffset(0, 0), Make::PageClut(Assets::Main::PacoTIM.get_clut_x(), Assets::Main::PacoTIM.get_clut_y())), - GPU::Color24::Blue()).linked()), - timer(), - color_idx(0) {} - - void setup(); - void update(); - void render(); - }; +#pragma once +#include "../../include/asset_mgr.hpp" +#include +#include + +namespace object { + using namespace JabyEngine; + + class Paco { + private: + static constexpr auto Size = Make::SizeI16(120, 128); + static const GPU::Color24 Colors[]; + + GPU::TexPage::Linked tex_page; + GPU::SPRT::Linked sprite; + SimpleTimer timer; + uint8_t color_idx; + + public: + constexpr Paco() : + tex_page(Make::TexPage(Make::PositionU16( + Assets::Main::PacoTIM.get_texture_x(), Assets::Main::PacoTIM.get_texture_y()), + GPU::TextureColorMode::clut4).linked()), + sprite(Make::SPRT( + Make::AreaI16(Make::PositionI16(GPU::Display::Width - Size.width, GPU::Display::Height - Size.height), Size), + Make::OffsetPageWithClut(Make::PageOffset(0, 0), Make::PageClut(Assets::Main::PacoTIM.get_clut_x(), Assets::Main::PacoTIM.get_clut_y())), + GPU::Color24::Blue()).linked()), + timer(), + color_idx(0) {} + + void setup(); + void update(); + void render(); + }; } \ No newline at end of file diff --git a/examples/PoolBox/application/src/menu.cpp b/examples/PoolBox/application/src/menu.cpp index 1dcbfd09..91b34353 100644 --- a/examples/PoolBox/application/src/menu.cpp +++ b/examples/PoolBox/application/src/menu.cpp @@ -1,81 +1,81 @@ -#include "../include/shared.hpp" -#include "include/menu.hpp" -#include -#include - -namespace Menu { - using DigitalButton = Periphery::GenericController::Button; - - void SimpleMenu :: setup(Callback callback, const Entry* entries, size_t size) { - this->selection_callback = callback; - this->entries = entries; - this->size = size; - this->cur_selection = 0; - } - - void SimpleMenu :: update(JabyEngine::FontWriter& font_writer, Cursor& cursor, const GPU::PositionI16& start) { - const auto& controller = Periphery::get_primary_controller_as(); - - if(controller.button.went_down(DigitalButton::Up) && this->cur_selection > 0) { - this->cur_selection -= 1; - } - - if(controller.button.went_down(DigitalButton::Down) && this->cur_selection < (this->size - 1)) { - this->cur_selection += 1; - } - - if(controller.button.went_down(DigitalButton::Cross)) { - SPU::voice[0].play(); - this->selection_callback(this->cur_selection); - } - - cursor.pos = Make::PositionI16(8, 64); - for(size_t n = 0; n < this->size; n++) { - const auto& cur_entry = this->entries[n]; - - if(this->cur_selection == n) { - FontWriter::bios_font_writer.write(cursor, ">%s<\n", cur_entry.name); - } - - else { - FontWriter::bios_font_writer.write(cursor, "%s\n", cur_entry.name); - } - } - } - - void BackMenu :: setup(JabyEngine::FontWriter* font_writer) { - this->font_writer = font_writer; - this->timeout.reset(); - this->waiting = false; - } - - bool BackMenu :: update(const GPU::PositionI16& position, bool auto_clear) { - const auto& controller = Periphery::get_primary_controller_as(); - - if(Shared::load_test || controller.button.is_down(DigitalButton::Circle)) { - this->waiting = true; - if(this->timeout.is_expired_for(2500_ms)) { - return true; - } - } - - else { - this->waiting = false; - this->timeout.reset(); - } - - if(this->waiting) { - auto cursor = JabyEngine::Cursor::create(position); - this->font_writer->write(cursor, "Press and hold O\nto get back", GPU::Color24::Red(0xD0)); - } - - else if(auto_clear) { - this->font_writer->clear(); - } - return false; - } - - void BackMenu :: render() { - this->font_writer->render(); - } +#include "../include/shared.hpp" +#include "include/menu.hpp" +#include +#include + +namespace Menu { + using DigitalButton = Periphery::GenericController::Button; + + void SimpleMenu :: setup(Callback callback, const Entry* entries, size_t size) { + this->selection_callback = callback; + this->entries = entries; + this->size = size; + this->cur_selection = 0; + } + + void SimpleMenu :: update(JabyEngine::FontWriter& font_writer, Cursor& cursor, const GPU::PositionI16& start) { + const auto& controller = Periphery::get_primary_controller_as(); + + if(controller.button.went_down(DigitalButton::Up) && this->cur_selection > 0) { + this->cur_selection -= 1; + } + + if(controller.button.went_down(DigitalButton::Down) && this->cur_selection < (this->size - 1)) { + this->cur_selection += 1; + } + + if(controller.button.went_down(DigitalButton::Cross)) { + SPU::voice[0].play(); + this->selection_callback(this->cur_selection); + } + + cursor.pos = Make::PositionI16(8, 64); + for(size_t n = 0; n < this->size; n++) { + const auto& cur_entry = this->entries[n]; + + if(this->cur_selection == n) { + FontWriter::bios_font_writer.write(cursor, ">%s<\n", cur_entry.name); + } + + else { + FontWriter::bios_font_writer.write(cursor, "%s\n", cur_entry.name); + } + } + } + + void BackMenu :: setup(JabyEngine::FontWriter* font_writer) { + this->font_writer = font_writer; + this->timeout.reset(); + this->waiting = false; + } + + bool BackMenu :: update(const GPU::PositionI16& position, bool auto_clear) { + const auto& controller = Periphery::get_primary_controller_as(); + + if(Shared::load_test || controller.button.is_down(DigitalButton::Circle)) { + this->waiting = true; + if(this->timeout.is_expired_for(2500_ms)) { + return true; + } + } + + else { + this->waiting = false; + this->timeout.reset(); + } + + if(this->waiting) { + auto cursor = JabyEngine::Cursor::create(position); + this->font_writer->write(cursor, "Press and hold O\nto get back", GPU::Color24::Red(0xD0)); + } + + else if(auto_clear) { + this->font_writer->clear(); + } + return false; + } + + void BackMenu :: render() { + this->font_writer->render(); + } } \ No newline at end of file diff --git a/examples/PoolBox/assets/Makefile b/examples/PoolBox/assets/Makefile index dc7fc71f..df6be5d1 100644 --- a/examples/PoolBox/assets/Makefile +++ b/examples/PoolBox/assets/Makefile @@ -1,66 +1,66 @@ -include $(JABY_ENGINE_DIR)/mkfile/common/ExportPath.mk -include $(JABY_ENGINE_DIR)/mkfile/common/RebuildTarget.mk - -OUTPUT_DIR = bin -CLUT_4_COLOR_TRANS_FLAGS = simple-tim clut4 --color-trans - -# Ressources to convert -## Music tracks -INPUT += $(OUTPUT_DIR)/Evacuation_cdda.xa -INPUT += $(OUTPUT_DIR)/OnMyOwn_BailBonds.xa -INPUT += $(OUTPUT_DIR)/apple.vag -INPUT += $(OUTPUT_DIR)/blubb-mono.vag -INPUT += $(OUTPUT_DIR)/Friendship_samp.vag - -## Images -INPUT += $(OUTPUT_DIR)/TexturePage.img -TexturePage_FLAGS = simple-tim clut4 - -INPUT += $(OUTPUT_DIR)/IconTexture.img -IconTexture_FLAGS = simple-tim clut4 --semi-trans --color-trans - -INPUT += $(OUTPUT_DIR)/Paco.img -Paco_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS) - -INPUT += $(OUTPUT_DIR)/Controller.img -Controller_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS) - -INPUT += $(OUTPUT_DIR)/doener_fish.img -doener_fish_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS) - -INPUT += $(OUTPUT_DIR)/JabyStar.img -JabyStar_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS) - -INPUT += $(OUTPUT_DIR)/JabyTails.img -JabyTails_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS) - -INPUT += $(OUTPUT_DIR)/IMG_6921.tim -IMG_6921_TIM_FLAGS = tim full16 --clut-pos {384,255} --tex-pos {384,256} - -INPUT += $(OUTPUT_DIR)/AllTheJaby.tim -AllTheJaby_TIM_FLAGS = tim full16 --tex-pos {0,0} - -$(OUTPUT_DIR)/%.vag: audio/%.wav - @mkdir -p $(OUTPUT_DIR) - psxfileconv --lz4 $< -o $@ vag - -$(OUTPUT_DIR)/OnMyOwn_BailBonds.xa: audio/OnMyOwn_BailBonds.mp3 - @mkdir -p $(OUTPUT_DIR) - psxfileconv $< -o $@ xa - -$(OUTPUT_DIR)/%.xa: audio/%.wav - @mkdir -p $(OUTPUT_DIR) - psxfileconv $< -o $@ xa - -$(OUTPUT_DIR)/%.img: %.png - @mkdir -p $(OUTPUT_DIR) - psxfileconv --lz4 $< -o $@ $($*_FLAGS) - -$(OUTPUT_DIR)/%.tim: %.png - @mkdir -p $(OUTPUT_DIR) - psxfileconv --lz4 $< -o $@ $($*_TIM_FLAGS) - -all: $(INPUT) - -clean: +include $(JABY_ENGINE_DIR)/mkfile/common/ExportPath.mk +include $(JABY_ENGINE_DIR)/mkfile/common/RebuildTarget.mk + +OUTPUT_DIR = bin +CLUT_4_COLOR_TRANS_FLAGS = simple-tim clut4 --color-trans + +# Ressources to convert +## Music tracks +INPUT += $(OUTPUT_DIR)/Evacuation_cdda.xa +INPUT += $(OUTPUT_DIR)/OnMyOwn_BailBonds.xa +INPUT += $(OUTPUT_DIR)/apple.vag +INPUT += $(OUTPUT_DIR)/blubb-mono.vag +INPUT += $(OUTPUT_DIR)/Friendship_samp.vag + +## Images +INPUT += $(OUTPUT_DIR)/TexturePage.img +TexturePage_FLAGS = simple-tim clut4 + +INPUT += $(OUTPUT_DIR)/IconTexture.img +IconTexture_FLAGS = simple-tim clut4 --semi-trans --color-trans + +INPUT += $(OUTPUT_DIR)/Paco.img +Paco_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS) + +INPUT += $(OUTPUT_DIR)/Controller.img +Controller_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS) + +INPUT += $(OUTPUT_DIR)/doener_fish.img +doener_fish_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS) + +INPUT += $(OUTPUT_DIR)/JabyStar.img +JabyStar_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS) + +INPUT += $(OUTPUT_DIR)/JabyTails.img +JabyTails_FLAGS = $(CLUT_4_COLOR_TRANS_FLAGS) + +INPUT += $(OUTPUT_DIR)/IMG_6921.tim +IMG_6921_TIM_FLAGS = tim full16 --clut-pos {384,255} --tex-pos {384,256} + +INPUT += $(OUTPUT_DIR)/AllTheJaby.tim +AllTheJaby_TIM_FLAGS = tim full16 --tex-pos {0,0} + +$(OUTPUT_DIR)/%.vag: audio/%.wav + @mkdir -p $(OUTPUT_DIR) + psxfileconv --lz4 $< -o $@ vag + +$(OUTPUT_DIR)/OnMyOwn_BailBonds.xa: audio/OnMyOwn_BailBonds.mp3 + @mkdir -p $(OUTPUT_DIR) + psxfileconv $< -o $@ xa + +$(OUTPUT_DIR)/%.xa: audio/%.wav + @mkdir -p $(OUTPUT_DIR) + psxfileconv $< -o $@ xa + +$(OUTPUT_DIR)/%.img: %.png + @mkdir -p $(OUTPUT_DIR) + psxfileconv --lz4 $< -o $@ $($*_FLAGS) + +$(OUTPUT_DIR)/%.tim: %.png + @mkdir -p $(OUTPUT_DIR) + psxfileconv --lz4 $< -o $@ $($*_TIM_FLAGS) + +all: $(INPUT) + +clean: rm -fr $(OUTPUT_DIR) \ No newline at end of file diff --git a/examples/PoolBox/iso/Makefile b/examples/PoolBox/iso/Makefile index 925d0bd1..23283935 100644 --- a/examples/PoolBox/iso/Makefile +++ b/examples/PoolBox/iso/Makefile @@ -1,2 +1,2 @@ -include $(JABY_ENGINE_DIR)/mkfile/ISOMakefile.mk +include $(JABY_ENGINE_DIR)/mkfile/ISOMakefile.mk include $(JABY_ENGINE_DIR)/mkfile/common/RebuildTarget.mk \ No newline at end of file diff --git a/include/PSX/Audio/CDDA.hpp b/include/PSX/Audio/CDDA.hpp index acb6fc89..d3c24b13 100644 --- a/include/PSX/Audio/CDDA.hpp +++ b/include/PSX/Audio/CDDA.hpp @@ -1,23 +1,23 @@ -#pragma once -#include "../jabyengine_defines.hpp" - -namespace JabyEngine { - namespace CDDA { - struct TrackList { - uint8_t first_track; - uint8_t last_track; - - static constexpr TrackList empty() { - return TrackList{.first_track = 0, .last_track = 0}; - } - }; - - TrackList get_tracks(); - - void play(uint8_t track); - void stop(); - - void push_play(); - void pop_play(); - } +#pragma once +#include "../jabyengine_defines.hpp" + +namespace JabyEngine { + namespace CDDA { + struct TrackList { + uint8_t first_track; + uint8_t last_track; + + static constexpr TrackList empty() { + return TrackList{.first_track = 0, .last_track = 0}; + } + }; + + TrackList get_tracks(); + + void play(uint8_t track); + void stop(); + + void push_play(); + void pop_play(); + } } \ No newline at end of file diff --git a/include/PSX/Audio/CDXA.hpp b/include/PSX/Audio/CDXA.hpp index d4506b5d..31cbffde 100644 --- a/include/PSX/Audio/CDXA.hpp +++ b/include/PSX/Audio/CDXA.hpp @@ -1,14 +1,14 @@ -#pragma once -#include "../AutoLBA/auto_lba.hpp" - -namespace JabyEngine { - namespace CDXA { - void play(const volatile AutoLBAEntry* lba, uint8_t rel_lba_idx, uint8_t channel, bool double_speed); - void stop(); - - void set_channel(uint8_t channel); - - void push_play(); - void pop_play(); - } +#pragma once +#include "../AutoLBA/auto_lba.hpp" + +namespace JabyEngine { + namespace CDXA { + void play(const volatile AutoLBAEntry* lba, uint8_t rel_lba_idx, uint8_t channel, bool double_speed); + void stop(); + + void set_channel(uint8_t channel); + + void push_play(); + void pop_play(); + } } \ No newline at end of file diff --git a/include/PSX/Auxiliary/big_endian.hpp b/include/PSX/Auxiliary/big_endian.hpp index 4e24c32b..0be766e2 100644 --- a/include/PSX/Auxiliary/big_endian.hpp +++ b/include/PSX/Auxiliary/big_endian.hpp @@ -1,19 +1,19 @@ -#pragma once -#include "../jabyengine_defines.hpp" - -namespace JabyEngine { - // Taken from boost endian - - static constexpr uint8_t read_be(uint8_t x) { - return x; - } - - static constexpr uint16_t read_be(uint16_t x) { - return (x << 8) | (x >> 8); - } - - static constexpr uint32_t read_be(uint32_t x) { - const uint32_t step16 = x << 16 | x >> 16; - return ((step16 << 8) & 0xff00ff00) | ((step16 >> 8) & 0x00ff00ff); - } +#pragma once +#include "../jabyengine_defines.hpp" + +namespace JabyEngine { + // Taken from boost endian + + static constexpr uint8_t read_be(uint8_t x) { + return x; + } + + static constexpr uint16_t read_be(uint16_t x) { + return (x << 8) | (x >> 8); + } + + static constexpr uint32_t read_be(uint32_t x) { + const uint32_t step16 = x << 16 | x >> 16; + return ((step16 << 8) & 0xff00ff00) | ((step16 >> 8) & 0x00ff00ff); + } } \ No newline at end of file diff --git a/include/PSX/Auxiliary/circular_buffer.hpp b/include/PSX/Auxiliary/circular_buffer.hpp index 88ada439..1269a9a9 100644 --- a/include/PSX/Auxiliary/circular_buffer.hpp +++ b/include/PSX/Auxiliary/circular_buffer.hpp @@ -1,61 +1,61 @@ -#pragma once -#include "array_range.hpp" - -namespace JabyEngine { - template - class CircularBuffer { - private: - T* start_adr = nullptr; - T* end_adr = nullptr; - T* read_adr = nullptr; - T* write_adr = nullptr; - - T* increment(T* cur_element) const { - cur_element += 1; - if(cur_element == this->end_adr) { - return this->start_adr; - } - - return cur_element; - } - - public: - CircularBuffer() = default; - - T* setup(T* buffer_start_adr, size_t elements) { - this->start_adr = buffer_start_adr; - this->end_adr = &buffer_start_adr[elements]; - - this->read_adr = this->start_adr; - this->write_adr = this->start_adr; - return this->end_adr; - } - - T* allocate() { - T* cur_adr = this->write_adr; - T* next_adr = CircularBuffer::increment(cur_adr); - if(next_adr == this->read_adr) { - return nullptr; - } - - else { - this->write_adr = next_adr; - return cur_adr; - } - } - - T* get_next() const { - return this->read_adr; - } - - void pop() { - if(CircularBuffer::has_data()) { - this->read_adr = CircularBuffer::increment(this->read_adr); - } - } - - constexpr bool has_data() const { - return (this->read_adr != this->write_adr); - } - }; +#pragma once +#include "array_range.hpp" + +namespace JabyEngine { + template + class CircularBuffer { + private: + T* start_adr = nullptr; + T* end_adr = nullptr; + T* read_adr = nullptr; + T* write_adr = nullptr; + + T* increment(T* cur_element) const { + cur_element += 1; + if(cur_element == this->end_adr) { + return this->start_adr; + } + + return cur_element; + } + + public: + CircularBuffer() = default; + + T* setup(T* buffer_start_adr, size_t elements) { + this->start_adr = buffer_start_adr; + this->end_adr = &buffer_start_adr[elements]; + + this->read_adr = this->start_adr; + this->write_adr = this->start_adr; + return this->end_adr; + } + + T* allocate() { + T* cur_adr = this->write_adr; + T* next_adr = CircularBuffer::increment(cur_adr); + if(next_adr == this->read_adr) { + return nullptr; + } + + else { + this->write_adr = next_adr; + return cur_adr; + } + } + + T* get_next() const { + return this->read_adr; + } + + void pop() { + if(CircularBuffer::has_data()) { + this->read_adr = CircularBuffer::increment(this->read_adr); + } + } + + constexpr bool has_data() const { + return (this->read_adr != this->write_adr); + } + }; } \ No newline at end of file diff --git a/include/PSX/Auxiliary/mem_dump.hpp b/include/PSX/Auxiliary/mem_dump.hpp index 41839db5..207cc19b 100644 --- a/include/PSX/Auxiliary/mem_dump.hpp +++ b/include/PSX/Auxiliary/mem_dump.hpp @@ -1,14 +1,14 @@ -#pragma once -#include - -namespace JabyEngine { - template - static inline void dump_to_stdoutln(const T& object) { - const uint8_t* raw_ptr = reinterpret_cast(&object); - - for(size_t raw_pos = 0; raw_pos < sizeof(T); raw_pos++) { - printf("[%02X]", raw_ptr[raw_pos]); - } - printf("\n"); - } -} +#pragma once +#include + +namespace JabyEngine { + template + static inline void dump_to_stdoutln(const T& object) { + const uint8_t* raw_ptr = reinterpret_cast(&object); + + for(size_t raw_pos = 0; raw_pos < sizeof(T); raw_pos++) { + printf("[%02X]", raw_ptr[raw_pos]); + } + printf("\n"); + } +} diff --git a/include/PSX/Auxiliary/unaligned_read.hpp b/include/PSX/Auxiliary/unaligned_read.hpp index 4e40f354..31a234c2 100644 --- a/include/PSX/Auxiliary/unaligned_read.hpp +++ b/include/PSX/Auxiliary/unaligned_read.hpp @@ -1,8 +1,8 @@ -#pragma once -#include "../../stdint.hpp" - -namespace JabyEngine { - uint16_t unaligned_lhu(const uint8_t* adr) { - return (static_cast(adr[0]) | static_cast(adr[1]) << 8); - } +#pragma once +#include "../../stdint.hpp" + +namespace JabyEngine { + uint16_t unaligned_lhu(const uint8_t* adr) { + return (static_cast(adr[0]) | static_cast(adr[1]) << 8); + } } \ No newline at end of file diff --git a/include/PSX/Auxiliary/word_helper.hpp b/include/PSX/Auxiliary/word_helper.hpp index 6675c8af..f25b3c2a 100644 --- a/include/PSX/Auxiliary/word_helper.hpp +++ b/include/PSX/Auxiliary/word_helper.hpp @@ -1,15 +1,15 @@ -#pragma once -#include - -namespace JabyEngine { - using word_t = uint32_t; - - static constexpr size_t bytes_to_words(size_t bytes) { - return bytes/sizeof(word_t); - } - - static constexpr size_t words_to_bytes(size_t words) { - return words*sizeof(word_t); - } -} - +#pragma once +#include + +namespace JabyEngine { + using word_t = uint32_t; + + static constexpr size_t bytes_to_words(size_t bytes) { + return bytes/sizeof(word_t); + } + + static constexpr size_t words_to_bytes(size_t words) { + return words*sizeof(word_t); + } +} + diff --git a/include/PSX/File/Processor/file_processor.hpp b/include/PSX/File/Processor/file_processor.hpp index a31abdeb..74b804eb 100644 --- a/include/PSX/File/Processor/file_processor.hpp +++ b/include/PSX/File/Processor/file_processor.hpp @@ -1,73 +1,73 @@ -#pragma once -#include "../../Auxiliary/types.hpp" -#include "../cd_file_types.hpp" - -namespace JabyEngine { - namespace FileProcessor { - class State { - public: - struct Reserved { - uint32_t reserved[8]; - }; - - struct CDDataProcessor; - - template - using GenericProcessRoutine = Progress (*)(CDDataProcessor&, T&); - - typedef GenericProcessRoutine ProcessRoutine; - - struct CDDataProcessor { - ProcessRoutine process_routine = nullptr; - const uint8_t* data_adr = nullptr; - size_t data_bytes = 0ull; - - template - static __always_inline CDDataProcessor from(GenericProcessRoutine process_routine, const uint8_t* data_adr) { - return {reinterpret_cast(process_routine), data_adr}; - } - - template - T simple_read_r() { - static constexpr size_t T_SIZE = sizeof(T); - - T value = *reinterpret_cast(this->data_adr); - CDDataProcessor::processed(T_SIZE); - return value; - } - - constexpr void processed(size_t bytes) { - this->data_adr += bytes; - this->data_bytes -= bytes; - } - - constexpr void skip(size_t bytes) { - CDDataProcessor::processed(bytes); - } - }; - - CDDataProcessor data_proc; - Reserved reserved; - - template - static __always_inline State from(const T& state, const uint32_t* data_adr, GenericProcessRoutine process_routine) { - return {CDDataProcessor::from(process_routine, reinterpret_cast(data_adr)), *reinterpret_cast(&state)}; - static_assert(sizeof(T) <= sizeof(Reserved)); - } - - public: - Progress process(size_t bytes_ready) { - this->data_proc.data_bytes += bytes_ready; - return (*this->data_proc.process_routine)(this->data_proc, this->reserved); - } - }; - - // The nothing state - State create(const uint32_t* data_adr, const Nothing& nothing); - State create(const uint32_t* data_adr, const SimpleTIM& file); - State create(const uint32_t* data_adr, const TIM& file); - State create(const uint32_t* data_adr, const VAG& file); - - State create_custom(const uint32_t* data_adr, const CDFileType_t& file_type, const CDFile::Payload& payload); - } +#pragma once +#include "../../Auxiliary/types.hpp" +#include "../cd_file_types.hpp" + +namespace JabyEngine { + namespace FileProcessor { + class State { + public: + struct Reserved { + uint32_t reserved[8]; + }; + + struct CDDataProcessor; + + template + using GenericProcessRoutine = Progress (*)(CDDataProcessor&, T&); + + typedef GenericProcessRoutine ProcessRoutine; + + struct CDDataProcessor { + ProcessRoutine process_routine = nullptr; + const uint8_t* data_adr = nullptr; + size_t data_bytes = 0ull; + + template + static __always_inline CDDataProcessor from(GenericProcessRoutine process_routine, const uint8_t* data_adr) { + return {reinterpret_cast(process_routine), data_adr}; + } + + template + T simple_read_r() { + static constexpr size_t T_SIZE = sizeof(T); + + T value = *reinterpret_cast(this->data_adr); + CDDataProcessor::processed(T_SIZE); + return value; + } + + constexpr void processed(size_t bytes) { + this->data_adr += bytes; + this->data_bytes -= bytes; + } + + constexpr void skip(size_t bytes) { + CDDataProcessor::processed(bytes); + } + }; + + CDDataProcessor data_proc; + Reserved reserved; + + template + static __always_inline State from(const T& state, const uint32_t* data_adr, GenericProcessRoutine process_routine) { + return {CDDataProcessor::from(process_routine, reinterpret_cast(data_adr)), *reinterpret_cast(&state)}; + static_assert(sizeof(T) <= sizeof(Reserved)); + } + + public: + Progress process(size_t bytes_ready) { + this->data_proc.data_bytes += bytes_ready; + return (*this->data_proc.process_routine)(this->data_proc, this->reserved); + } + }; + + // The nothing state + State create(const uint32_t* data_adr, const Nothing& nothing); + State create(const uint32_t* data_adr, const SimpleTIM& file); + State create(const uint32_t* data_adr, const TIM& file); + State create(const uint32_t* data_adr, const VAG& file); + + State create_custom(const uint32_t* data_adr, const CDFileType_t& file_type, const CDFile::Payload& payload); + } } \ No newline at end of file diff --git a/include/PSX/File/file_processor_helper.hpp b/include/PSX/File/file_processor_helper.hpp index 04b1552a..6b8bfd42 100644 --- a/include/PSX/File/file_processor_helper.hpp +++ b/include/PSX/File/file_processor_helper.hpp @@ -1,62 +1,62 @@ -#pragma once -#include "Processor/file_processor.hpp" -#include "cd_file_types.hpp" -#include - -namespace JabyEngine { - namespace FileProcessor { - namespace Helper { - template - static Progress exchange_and_execute_process_function(State::GenericProcessRoutine process_routine, State::CDDataProcessor& data_proc, T& state) { - data_proc.process_routine = reinterpret_cast(process_routine); - return process_routine(data_proc, state); - } - - namespace DMA { - struct WordsReady { - uint32_t words_to_use; - bool is_last; - - static constexpr WordsReady calculate(const State::CDDataProcessor& data_proc, size_t words_left) { - const auto config_data_words = (data_proc.data_bytes/sizeof(uint32_t)); - const auto words_to_use = (config_data_words > words_left) ? words_left : config_data_words; - - return { - .words_to_use = words_to_use, - .is_last = words_to_use == words_left - }; - } - }; - - template - static size_t send_words(size_t words_to_send, bool send_all) { - auto blocks_to_send = words_to_send/16; - while(blocks_to_send > 0) { - const auto block_send = (blocks_to_send > UI16_MAX) ? UI16_MAX : blocks_to_send; - - // Send data! - T::wait(); - T::Receive::start(blocks_to_send); - blocks_to_send -= block_send; - } - - if(send_all) { - const auto last_words_to_send = (words_to_send & 0b1111); - if(last_words_to_send > 0) { - T::wait(); - T::Receive::start(1, last_words_to_send); - } - - T::wait(); - T::end(); - return words_to_send; - } - - else { - return (words_to_send & ~0b1111); - } - } - } - } - } +#pragma once +#include "Processor/file_processor.hpp" +#include "cd_file_types.hpp" +#include + +namespace JabyEngine { + namespace FileProcessor { + namespace Helper { + template + static Progress exchange_and_execute_process_function(State::GenericProcessRoutine process_routine, State::CDDataProcessor& data_proc, T& state) { + data_proc.process_routine = reinterpret_cast(process_routine); + return process_routine(data_proc, state); + } + + namespace DMA { + struct WordsReady { + uint32_t words_to_use; + bool is_last; + + static constexpr WordsReady calculate(const State::CDDataProcessor& data_proc, size_t words_left) { + const auto config_data_words = (data_proc.data_bytes/sizeof(uint32_t)); + const auto words_to_use = (config_data_words > words_left) ? words_left : config_data_words; + + return { + .words_to_use = words_to_use, + .is_last = words_to_use == words_left + }; + } + }; + + template + static size_t send_words(size_t words_to_send, bool send_all) { + auto blocks_to_send = words_to_send/16; + while(blocks_to_send > 0) { + const auto block_send = (blocks_to_send > UI16_MAX) ? UI16_MAX : blocks_to_send; + + // Send data! + T::wait(); + T::Receive::start(blocks_to_send); + blocks_to_send -= block_send; + } + + if(send_all) { + const auto last_words_to_send = (words_to_send & 0b1111); + if(last_words_to_send > 0) { + T::wait(); + T::Receive::start(1, last_words_to_send); + } + + T::wait(); + T::end(); + return words_to_send; + } + + else { + return (words_to_send & ~0b1111); + } + } + } + } + } } \ No newline at end of file diff --git a/include/PSX/GPU/Primitives/primitive_gpu_commands.hpp b/include/PSX/GPU/Primitives/primitive_gpu_commands.hpp index 80e385bd..7219f361 100644 --- a/include/PSX/GPU/Primitives/primitive_gpu_commands.hpp +++ b/include/PSX/GPU/Primitives/primitive_gpu_commands.hpp @@ -1,52 +1,52 @@ -#pragma once -#include "../../System/IOPorts/gpu_io.hpp" -#include "linked_elements.hpp" -#include "primitive_support_types.hpp" - -namespace JabyEngine { - namespace GPU { - struct TexPage : public internal::LinkedElementCreator { - static constexpr bool is_render_primitive = true; - - GPU_IO_Values::GP0 value; - - static constexpr TexPage create(const PositionU16& tex_pos, TextureColorMode tex_color, SemiTransparency transparency = SemiTransparency::B_Half_add_F_Half, bool dither = false) { - return TexPage{.value = GPU_IO_Values::GP0::TexPage(tex_pos, transparency, tex_color, dither, false)}; - } - }; - - struct CPU2VRAM { - static constexpr bool is_render_primitive = true; - - GPU_IO_Values::GP0 cmd; - GPU_IO_Values::GP0 pos; - GPU_IO_Values::GP0 size; - - static constexpr CPU2VRAM create(const AreaU16& dst) { - return CPU2VRAM{ - .cmd = GPU_IO_Values::GP0::CPU2VRAMBlitting(), - .pos = GPU_IO_Values::GP0::PostionTopLeft(dst.position), - .size = GPU_IO_Values::GP0::WidthHeight(dst.size) - }; - } - }; - - struct VRAM2VRAM { - static constexpr bool is_render_primitive = true; - - GPU_IO_Values::GP0 cmd; - GPU_IO_Values::GP0 src_pos; - GPU_IO_Values::GP0 dst_pos; - GPU_IO_Values::GP0 size; - - static constexpr VRAM2VRAM create(const AreaU16& src, const PositionU16& dst) { - return VRAM2VRAM{ - .cmd = GPU_IO_Values::GP0::VRAM2VRAMBlitting(), - .src_pos = GPU_IO_Values::GP0::PostionTopLeft(src.position), - .dst_pos = GPU_IO_Values::GP0::PostionTopLeft(dst), - .size = GPU_IO_Values::GP0::WidthHeight(src.size) - }; - } - }; - } +#pragma once +#include "../../System/IOPorts/gpu_io.hpp" +#include "linked_elements.hpp" +#include "primitive_support_types.hpp" + +namespace JabyEngine { + namespace GPU { + struct TexPage : public internal::LinkedElementCreator { + static constexpr bool is_render_primitive = true; + + GPU_IO_Values::GP0 value; + + static constexpr TexPage create(const PositionU16& tex_pos, TextureColorMode tex_color, SemiTransparency transparency = SemiTransparency::B_Half_add_F_Half, bool dither = false) { + return TexPage{.value = GPU_IO_Values::GP0::TexPage(tex_pos, transparency, tex_color, dither, false)}; + } + }; + + struct CPU2VRAM { + static constexpr bool is_render_primitive = true; + + GPU_IO_Values::GP0 cmd; + GPU_IO_Values::GP0 pos; + GPU_IO_Values::GP0 size; + + static constexpr CPU2VRAM create(const AreaU16& dst) { + return CPU2VRAM{ + .cmd = GPU_IO_Values::GP0::CPU2VRAMBlitting(), + .pos = GPU_IO_Values::GP0::PostionTopLeft(dst.position), + .size = GPU_IO_Values::GP0::WidthHeight(dst.size) + }; + } + }; + + struct VRAM2VRAM { + static constexpr bool is_render_primitive = true; + + GPU_IO_Values::GP0 cmd; + GPU_IO_Values::GP0 src_pos; + GPU_IO_Values::GP0 dst_pos; + GPU_IO_Values::GP0 size; + + static constexpr VRAM2VRAM create(const AreaU16& src, const PositionU16& dst) { + return VRAM2VRAM{ + .cmd = GPU_IO_Values::GP0::VRAM2VRAMBlitting(), + .src_pos = GPU_IO_Values::GP0::PostionTopLeft(src.position), + .dst_pos = GPU_IO_Values::GP0::PostionTopLeft(dst), + .size = GPU_IO_Values::GP0::WidthHeight(src.size) + }; + } + }; + } } \ No newline at end of file diff --git a/include/PSX/GPU/gpu_auto_load_font.hpp b/include/PSX/GPU/gpu_auto_load_font.hpp index ab979624..23a63dd0 100644 --- a/include/PSX/GPU/gpu_auto_load_font.hpp +++ b/include/PSX/GPU/gpu_auto_load_font.hpp @@ -1,35 +1,35 @@ -#pragma once -#include "../jabyengine_config.hpp" -#include "gpu_primitives.hpp" - -namespace JabyEngine { - namespace GPU { - struct BIOS_Font { - // This size is by Hardware limitation - static constexpr auto Size = SizeU16::create(16, 16); - - static constexpr auto TextureLoadPos = Configuration::BIOSFont::texture_load_pos(); - static constexpr auto CLUTLoadPos = Configuration::BIOSFont::CLUT_load_pos(); - - static constexpr TexPage get_tex_page() { - return TexPage::create(BIOS_Font::TextureLoadPos, GPU::TextureColorMode::clut4); - } - - static constexpr TPage get_tpage() { - return TPage::create(TextureLoadPos.x, TextureLoadPos.y, SemiTransparency::B_add_F, TextureColorMode::clut4); - } - - static constexpr PageOffset get_offset_page() { - return PageOffset::create(BIOS_Font::CLUTLoadPos.x & 0x3F, BIOS_Font::CLUTLoadPos.y & 0xFF); - } - - static constexpr PageClut get_page_clut() { - return PageClut::create(BIOS_Font::CLUTLoadPos); - } - - static constexpr OffsetPageWithClut get_offset_page_with_clut() { - return OffsetPageWithClut::create(BIOS_Font::get_offset_page(), BIOS_Font::get_page_clut()); - } - }; - } +#pragma once +#include "../jabyengine_config.hpp" +#include "gpu_primitives.hpp" + +namespace JabyEngine { + namespace GPU { + struct BIOS_Font { + // This size is by Hardware limitation + static constexpr auto Size = SizeU16::create(16, 16); + + static constexpr auto TextureLoadPos = Configuration::BIOSFont::texture_load_pos(); + static constexpr auto CLUTLoadPos = Configuration::BIOSFont::CLUT_load_pos(); + + static constexpr TexPage get_tex_page() { + return TexPage::create(BIOS_Font::TextureLoadPos, GPU::TextureColorMode::clut4); + } + + static constexpr TPage get_tpage() { + return TPage::create(TextureLoadPos.x, TextureLoadPos.y, SemiTransparency::B_add_F, TextureColorMode::clut4); + } + + static constexpr PageOffset get_offset_page() { + return PageOffset::create(BIOS_Font::CLUTLoadPos.x & 0x3F, BIOS_Font::CLUTLoadPos.y & 0xFF); + } + + static constexpr PageClut get_page_clut() { + return PageClut::create(BIOS_Font::CLUTLoadPos); + } + + static constexpr OffsetPageWithClut get_offset_page_with_clut() { + return OffsetPageWithClut::create(BIOS_Font::get_offset_page(), BIOS_Font::get_page_clut()); + } + }; + } } \ No newline at end of file diff --git a/include/PSX/GPU/make_gpu_primitives.hpp b/include/PSX/GPU/make_gpu_primitives.hpp index 146b8a28..c791a387 100644 --- a/include/PSX/GPU/make_gpu_primitives.hpp +++ b/include/PSX/GPU/make_gpu_primitives.hpp @@ -1,349 +1,349 @@ -#pragma once -#include "gpu_primitives.hpp" - -namespace JabyEngine { - namespace Make { - template - static constexpr T creator_template(const ARGS&...args) { - return T::create(args...); - } - - // ################################################################### - - static constexpr GPU::SizeI8 SizeI8() { - return creator_template(0_i8, 0_i8); - } - static constexpr GPU::SizeI8 SizeI8(int8_t x, int8_t y) { - return creator_template(x, y); - } - - // ################################################################### - - static constexpr GPU::SizeU8 SizeU8() { - return creator_template(0_u8, 0_u8); - } - static constexpr GPU::SizeU8 SizeU8(uint8_t x, uint8_t y) { - return creator_template(x, y); - } - - // ################################################################### - - static constexpr GPU::SizeI16 SizeI16() { - return creator_template(0_i16, 0_i16); - } - static constexpr GPU::SizeI16 SizeI16(int16_t x, int16_t y) { - return creator_template(x, y); - } - - // ################################################################### - - static constexpr GPU::SizeU16 SizeU16() { - return creator_template(0_u16, 0_u16); - } - static constexpr GPU::SizeU16 SizeU16(uint16_t x, uint16_t y) { - return creator_template(x, y); - } - - // ################################################################### - - static constexpr GPU::PositionI8 PositionI8() { - return creator_template(0_i8, 0_i8); - } - static constexpr GPU::PositionI8 PositionI8(int8_t x, int8_t y) { - return creator_template(x, y); - } - - // ################################################################### - - static constexpr GPU::PositionU8 PositionU8() { - return creator_template(0_u8, 0_u8); - } - static constexpr GPU::PositionU8 PositionU8(int8_t x, int8_t y) { - return creator_template(x, y); - } - - // ################################################################### - - static constexpr GPU::PositionI16 PositionI16() { - return creator_template(0_i16, 0_i16); - } - static constexpr GPU::PositionI16 PositionI16(int16_t x, int16_t y) { - return creator_template(x, y); - } - - // ################################################################### - - static constexpr GPU::PositionU16 PositionU16() { - return creator_template(0_u16, 0_u16); - } - static constexpr GPU::PositionU16 PositionU16(uint16_t x, uint16_t y) { - return creator_template(x, y); - } - - // ################################################################### - - static constexpr GPU::Vertex Vertex() { - return creator_template(0_i16, 0_i16); - } - static constexpr GPU::Vertex Vertex(int16_t x, int16_t y) { - return creator_template(x, y); - } - - // ################################################################### - - static constexpr GPU::AreaI16 AreaI16() { - return creator_template(0, 0, 0, 0); - } - static constexpr GPU::AreaI16 AreaI16(int16_t x, int16_t y, int16_t w, int16_t h) { - return creator_template(x, y, w, h); - } - static constexpr GPU::AreaI16 AreaI16(GPU::PositionI16 pos, GPU::SizeI16 size) { - return creator_template(pos, size); - } - - // ################################################################### - - static constexpr GPU::AreaU16 AreaU16() { - return creator_template(0, 0, 0, 0); - } - static constexpr GPU::AreaU16 AreaU16(uint16_t x, uint16_t y, uint16_t w, uint16_t h) { - return creator_template(x, y, w, h); - } - static constexpr GPU::AreaU16 AreaU16(GPU::PositionU16 pos, GPU::SizeU16 size) { - return creator_template(pos, size); - } - - // ################################################################### - - static constexpr GPU::PageOffset PageOffset() { - return creator_template(0_u8, 0_u8); - } - static constexpr GPU::PageOffset PageOffset(uint8_t u, uint8_t v) { - return creator_template(u, v); - } - - // ################################################################### - - static constexpr GPU::PageClut PageClut() { - return creator_template(0_u16, 0_u16); - } - static constexpr GPU::PageClut PageClut(uint16_t x, uint16_t y) { - return creator_template(x, y); - } - static constexpr GPU::PageClut PageClut(const GPU::PositionU16& clut_pos) { - return creator_template(clut_pos); - } - - // ################################################################### - - static constexpr GPU::TPage TPage() { - return creator_template(0_u16, 0_u16, GPU::SemiTransparency::B_add_F, GPU::TextureColorMode::clut4); - } - static constexpr GPU::TPage TPage(uint16_t x, uint16_t y, GPU::SemiTransparency transparency, GPU::TextureColorMode clut_color) { - return creator_template(x, y, transparency, clut_color); - } - static constexpr GPU::TPage TPage(const GPU::PositionU16& tex_pos, GPU::SemiTransparency transparency, GPU::TextureColorMode clut_color) { - return creator_template(tex_pos, transparency, clut_color); - } - - // ################################################################### - - static constexpr GPU::TexPage TexPage() { - return creator_template(PositionU16(), GPU::TextureColorMode::clut4, GPU::SemiTransparency::B_Half_add_F_Half, false); - } - static constexpr GPU::TexPage TexPage(const GPU::PositionU16& tex_pos, GPU::TextureColorMode tex_color, GPU::SemiTransparency transparency = GPU::SemiTransparency::B_Half_add_F_Half, bool dither = false) { - return creator_template(tex_pos, tex_color, transparency, dither); - } - - // ################################################################### - - static constexpr GPU::OffsetPageWithClut OffsetPageWithClut() { - return creator_template(PageOffset(), PageClut()); - } - static constexpr GPU::OffsetPageWithClut OffsetPageWithClut(GPU::PageOffset tex_offset, GPU::PageClut clut) { - return creator_template(tex_offset, clut); - } - - // ################################################################### - - static constexpr GPU::VertexColor VertexColor() { - return creator_template(Vertex(), GPU::Color24::Black()); - } - static constexpr GPU::VertexColor VertexColor(GPU::Vertex pos, GPU::Color24 color) { - return creator_template(pos, color); - } - - // ################################################################### - - static constexpr GPU::ColorVertex ColorVertex() { - return creator_template(GPU::Color24::Black(), Vertex()); - } - static constexpr GPU::ColorVertex ColorVertex(GPU::Color24 color, GPU::Vertex pos) { - return creator_template(color, pos); - } - - // ################################################################### - - static constexpr GPU::LINE_F_SINGLE LINE_F(const GPU::Color24& color, const GPU::Vertex& start_point, const GPU::Vertex& end_point) { - return GPU::LINE_F::create(color, start_point, end_point); - } - - template - static constexpr GPU::LINE_F_MULTI LINE_F(const GPU::Color24& color, const GPU::Vertex& start_point, const ARGS&...rest) { - return GPU::LINE_F::create(color, start_point, rest...); - } - - static constexpr GPU::LINE_G_SINGLE LINE_G(const GPU::ColorVertex& start_point, const GPU::ColorVertex& end_point) { - return GPU::LINE_G::create(start_point, end_point); - } - - template - static constexpr GPU::LINE_G_MULTI LINE_G(const GPU::ColorVertex& start_point, const ARGS&...rest) { - return GPU::LINE_G::create(start_point, rest...); - } - - // ################################################################### - // ################################################################### - // ################################################################### - - static constexpr GPU::POLY_F3 POLY_F3(const GPU::Vertex (&verticies)[3], GPU::Color24 color) { - return creator_template(verticies, color); - } - - static constexpr GPU::POLY_FT3 POLY_FT3(const GPU::Vertex (&verticies)[3], const GPU::PageOffset (&tex_offset)[3], GPU::TPage tpage, GPU::PageClut clut, GPU::Color24 color = GPU::Color24::Grey()) { - return creator_template(verticies, tex_offset, tpage, clut, color); - } - - static constexpr GPU::POLY_FT3 POLY_FT3(const GPU::POLY_FT3::VertexEx (&vertices_ex)[3], GPU::TPage tpage, GPU::PageClut clut, GPU::Color24 color) { - return creator_template(vertices_ex, tpage, clut, color); - } - - static constexpr GPU::POLY_G3 POLY_G3(const GPU::Vertex (&verticies)[3], const GPU::Color24 (&color)[3]) { - return creator_template(verticies, color); - } - - static constexpr GPU::POLY_G3 POLY_G3(const GPU::VertexColor (&verticies_ex)[3]) { - return creator_template(verticies_ex); - } - - static constexpr GPU::POLY_GT3 POLY_GT3(const GPU::Vertex (&verticies)[3], const GPU::PageOffset (&tex_offset)[3], const GPU::Color24 (&color)[3], GPU::TPage tpage, GPU::PageClut clut) { - return creator_template(verticies, tex_offset, color, tpage, clut); - } - - static constexpr GPU::POLY_GT3 POLY_GT3(const GPU::POLY_GT3::VertexEx (&verticies_ex)[3], GPU::TPage tpage, GPU::PageClut clut) { - return creator_template(verticies_ex, tpage, clut); - } - - static constexpr GPU::POLY_F4 POLY_F4(const GPU::Vertex (&verticies)[4], GPU::Color24 color) { - return creator_template(verticies, color); - } - - static constexpr GPU::POLY_F4 POLY_F4(const GPU::AreaI16& area, GPU::Color24 color) { - return creator_template(area, color); - } - - static constexpr GPU::POLY_FT4 POLY_FT4(const GPU::Vertex (&verticies)[4], const GPU::PageOffset (&tex_offset)[4], GPU::TPage tpage, GPU::PageClut clut, GPU::Color24 color) { - return creator_template(verticies, tex_offset, tpage, clut, color); - } - - static constexpr GPU::POLY_FT4 POLY_FT4(const GPU::POLY_FT4::VertexEx (&vertices_ex)[4], GPU::TPage tpage, GPU::PageClut clut, GPU::Color24 color = GPU::Color24::Grey()) { - return creator_template(vertices_ex, tpage, clut, color); - } - - static constexpr GPU::POLY_FT4 POLY_FT4(const GPU::AreaI16& area, const GPU::PageOffset& tex_offset, GPU::TPage tpage, GPU::PageClut clut, GPU::Color24 color = GPU::Color24::Grey()) { - return creator_template(area, tex_offset, tpage, clut, color); - } - - static constexpr GPU::POLY_G4 POLY_G4(const GPU::Vertex (&verticies)[4], const GPU::Color24 (&color)[4]) { - return creator_template(verticies, color); - } - - static constexpr GPU::POLY_G4 POLY_G4(const GPU::VertexColor (&verticies_ex)[4]) { - return creator_template(verticies_ex); - } - - static constexpr GPU::POLY_G4 POLY_G4(const GPU::AreaI16& area, const GPU::Color24 (&color)[4]) { - return creator_template(area, color); - } - - static constexpr GPU::POLY_GT4 POLY_GT4(const GPU::Vertex (&verticies)[4], const GPU::PageOffset (&tex_offset)[4], const GPU::Color24 (&color)[4], GPU::TPage tpage, GPU::PageClut clut) { - return creator_template(verticies, tex_offset, color, tpage, clut); - } - - static constexpr GPU::POLY_GT4 POLY_GT4(const GPU::POLY_GT4::VertexEx (&verticies_ex)[4], GPU::TPage tpage, GPU::PageClut clut) { - return creator_template(verticies_ex, tpage, clut); - } - - static constexpr GPU::POLY_GT4 POLY_GT4(const GPU::AreaI16& area, const GPU::PageOffset& tex_offset, GPU::TPage tpage, GPU::PageClut clut, const GPU::Color24 (&color)[4]) { - return creator_template(area, tex_offset, tpage, clut, color); - } - - // ################################################################### - - static constexpr GPU::TILE_1 TILE_1() { - return creator_template(Vertex(), GPU::Color24::Black()); - } - - static constexpr GPU::TILE_1 TILE_1(const GPU::Vertex& position, const GPU::Color24& color) { - return creator_template(position, color); - } - - static constexpr GPU::TILE_8 TILE_8() { - return creator_template(Vertex(), GPU::Color24::Black()); - } - - static constexpr GPU::TILE_8 TILE_8(const GPU::Vertex& position, const GPU::Color24& color) { - return creator_template(position, color); - } - - static constexpr GPU::TILE_16 TILE_16() { - return creator_template(Vertex(), GPU::Color24::Black()); - } - - static constexpr GPU::TILE_16 TILE_16(const GPU::Vertex& position, const GPU::Color24& color) { - return creator_template(position, color); - } - - static constexpr GPU::TILE TILE() { - return creator_template(AreaI16(), GPU::Color24::Black()); - } - - static constexpr GPU::TILE TILE(const GPU::AreaI16& area, const GPU::Color24& color) { - return creator_template(area, color); - } - - // ################################################################### - - static constexpr GPU::SPRT_1 SPRT_1() { - return creator_template(Vertex(), OffsetPageWithClut(), GPU::Color24::Black()); - } - - static constexpr GPU::SPRT_1 SPRT_1(const GPU::Vertex& position, const GPU::OffsetPageWithClut& tex_offset_w_clut, const GPU::Color24& color = GPU::Color24::Grey()) { - return creator_template(position, tex_offset_w_clut, color); - } - - static constexpr GPU::SPRT_8 SPRT_8() { - return creator_template(Vertex(), OffsetPageWithClut(), GPU::Color24::Black()); - } - - static constexpr GPU::SPRT_8 SPRT_8(const GPU::Vertex& position, const GPU::OffsetPageWithClut& tex_offset_w_clut, const GPU::Color24& color = GPU::Color24::Grey()) { - return creator_template(position, tex_offset_w_clut, color); - } - - static constexpr GPU::SPRT_16 SPRT_16() { - return creator_template(Vertex(), OffsetPageWithClut(), GPU::Color24::Black()); - } - - static constexpr GPU::SPRT_16 SPRT_16(const GPU::Vertex& position, const GPU::OffsetPageWithClut& tex_offset_w_clut, const GPU::Color24& color = GPU::Color24::Grey()) { - return creator_template(position, tex_offset_w_clut, color); - } - - static constexpr GPU::SPRT SPRT() { - return creator_template(AreaI16(), OffsetPageWithClut(), GPU::Color24::Black()); - } - - static constexpr GPU::SPRT SPRT(const GPU::AreaI16& area, const GPU::OffsetPageWithClut& tex_offset_w_clut, const GPU::Color24& color = GPU::Color24::Grey()) { - return creator_template(area, tex_offset_w_clut, color); - } - } +#pragma once +#include "gpu_primitives.hpp" + +namespace JabyEngine { + namespace Make { + template + static constexpr T creator_template(const ARGS&...args) { + return T::create(args...); + } + + // ################################################################### + + static constexpr GPU::SizeI8 SizeI8() { + return creator_template(0_i8, 0_i8); + } + static constexpr GPU::SizeI8 SizeI8(int8_t x, int8_t y) { + return creator_template(x, y); + } + + // ################################################################### + + static constexpr GPU::SizeU8 SizeU8() { + return creator_template(0_u8, 0_u8); + } + static constexpr GPU::SizeU8 SizeU8(uint8_t x, uint8_t y) { + return creator_template(x, y); + } + + // ################################################################### + + static constexpr GPU::SizeI16 SizeI16() { + return creator_template(0_i16, 0_i16); + } + static constexpr GPU::SizeI16 SizeI16(int16_t x, int16_t y) { + return creator_template(x, y); + } + + // ################################################################### + + static constexpr GPU::SizeU16 SizeU16() { + return creator_template(0_u16, 0_u16); + } + static constexpr GPU::SizeU16 SizeU16(uint16_t x, uint16_t y) { + return creator_template(x, y); + } + + // ################################################################### + + static constexpr GPU::PositionI8 PositionI8() { + return creator_template(0_i8, 0_i8); + } + static constexpr GPU::PositionI8 PositionI8(int8_t x, int8_t y) { + return creator_template(x, y); + } + + // ################################################################### + + static constexpr GPU::PositionU8 PositionU8() { + return creator_template(0_u8, 0_u8); + } + static constexpr GPU::PositionU8 PositionU8(int8_t x, int8_t y) { + return creator_template(x, y); + } + + // ################################################################### + + static constexpr GPU::PositionI16 PositionI16() { + return creator_template(0_i16, 0_i16); + } + static constexpr GPU::PositionI16 PositionI16(int16_t x, int16_t y) { + return creator_template(x, y); + } + + // ################################################################### + + static constexpr GPU::PositionU16 PositionU16() { + return creator_template(0_u16, 0_u16); + } + static constexpr GPU::PositionU16 PositionU16(uint16_t x, uint16_t y) { + return creator_template(x, y); + } + + // ################################################################### + + static constexpr GPU::Vertex Vertex() { + return creator_template(0_i16, 0_i16); + } + static constexpr GPU::Vertex Vertex(int16_t x, int16_t y) { + return creator_template(x, y); + } + + // ################################################################### + + static constexpr GPU::AreaI16 AreaI16() { + return creator_template(0, 0, 0, 0); + } + static constexpr GPU::AreaI16 AreaI16(int16_t x, int16_t y, int16_t w, int16_t h) { + return creator_template(x, y, w, h); + } + static constexpr GPU::AreaI16 AreaI16(GPU::PositionI16 pos, GPU::SizeI16 size) { + return creator_template(pos, size); + } + + // ################################################################### + + static constexpr GPU::AreaU16 AreaU16() { + return creator_template(0, 0, 0, 0); + } + static constexpr GPU::AreaU16 AreaU16(uint16_t x, uint16_t y, uint16_t w, uint16_t h) { + return creator_template(x, y, w, h); + } + static constexpr GPU::AreaU16 AreaU16(GPU::PositionU16 pos, GPU::SizeU16 size) { + return creator_template(pos, size); + } + + // ################################################################### + + static constexpr GPU::PageOffset PageOffset() { + return creator_template(0_u8, 0_u8); + } + static constexpr GPU::PageOffset PageOffset(uint8_t u, uint8_t v) { + return creator_template(u, v); + } + + // ################################################################### + + static constexpr GPU::PageClut PageClut() { + return creator_template(0_u16, 0_u16); + } + static constexpr GPU::PageClut PageClut(uint16_t x, uint16_t y) { + return creator_template(x, y); + } + static constexpr GPU::PageClut PageClut(const GPU::PositionU16& clut_pos) { + return creator_template(clut_pos); + } + + // ################################################################### + + static constexpr GPU::TPage TPage() { + return creator_template(0_u16, 0_u16, GPU::SemiTransparency::B_add_F, GPU::TextureColorMode::clut4); + } + static constexpr GPU::TPage TPage(uint16_t x, uint16_t y, GPU::SemiTransparency transparency, GPU::TextureColorMode clut_color) { + return creator_template(x, y, transparency, clut_color); + } + static constexpr GPU::TPage TPage(const GPU::PositionU16& tex_pos, GPU::SemiTransparency transparency, GPU::TextureColorMode clut_color) { + return creator_template(tex_pos, transparency, clut_color); + } + + // ################################################################### + + static constexpr GPU::TexPage TexPage() { + return creator_template(PositionU16(), GPU::TextureColorMode::clut4, GPU::SemiTransparency::B_Half_add_F_Half, false); + } + static constexpr GPU::TexPage TexPage(const GPU::PositionU16& tex_pos, GPU::TextureColorMode tex_color, GPU::SemiTransparency transparency = GPU::SemiTransparency::B_Half_add_F_Half, bool dither = false) { + return creator_template(tex_pos, tex_color, transparency, dither); + } + + // ################################################################### + + static constexpr GPU::OffsetPageWithClut OffsetPageWithClut() { + return creator_template(PageOffset(), PageClut()); + } + static constexpr GPU::OffsetPageWithClut OffsetPageWithClut(GPU::PageOffset tex_offset, GPU::PageClut clut) { + return creator_template(tex_offset, clut); + } + + // ################################################################### + + static constexpr GPU::VertexColor VertexColor() { + return creator_template(Vertex(), GPU::Color24::Black()); + } + static constexpr GPU::VertexColor VertexColor(GPU::Vertex pos, GPU::Color24 color) { + return creator_template(pos, color); + } + + // ################################################################### + + static constexpr GPU::ColorVertex ColorVertex() { + return creator_template(GPU::Color24::Black(), Vertex()); + } + static constexpr GPU::ColorVertex ColorVertex(GPU::Color24 color, GPU::Vertex pos) { + return creator_template(color, pos); + } + + // ################################################################### + + static constexpr GPU::LINE_F_SINGLE LINE_F(const GPU::Color24& color, const GPU::Vertex& start_point, const GPU::Vertex& end_point) { + return GPU::LINE_F::create(color, start_point, end_point); + } + + template + static constexpr GPU::LINE_F_MULTI LINE_F(const GPU::Color24& color, const GPU::Vertex& start_point, const ARGS&...rest) { + return GPU::LINE_F::create(color, start_point, rest...); + } + + static constexpr GPU::LINE_G_SINGLE LINE_G(const GPU::ColorVertex& start_point, const GPU::ColorVertex& end_point) { + return GPU::LINE_G::create(start_point, end_point); + } + + template + static constexpr GPU::LINE_G_MULTI LINE_G(const GPU::ColorVertex& start_point, const ARGS&...rest) { + return GPU::LINE_G::create(start_point, rest...); + } + + // ################################################################### + // ################################################################### + // ################################################################### + + static constexpr GPU::POLY_F3 POLY_F3(const GPU::Vertex (&verticies)[3], GPU::Color24 color) { + return creator_template(verticies, color); + } + + static constexpr GPU::POLY_FT3 POLY_FT3(const GPU::Vertex (&verticies)[3], const GPU::PageOffset (&tex_offset)[3], GPU::TPage tpage, GPU::PageClut clut, GPU::Color24 color = GPU::Color24::Grey()) { + return creator_template(verticies, tex_offset, tpage, clut, color); + } + + static constexpr GPU::POLY_FT3 POLY_FT3(const GPU::POLY_FT3::VertexEx (&vertices_ex)[3], GPU::TPage tpage, GPU::PageClut clut, GPU::Color24 color) { + return creator_template(vertices_ex, tpage, clut, color); + } + + static constexpr GPU::POLY_G3 POLY_G3(const GPU::Vertex (&verticies)[3], const GPU::Color24 (&color)[3]) { + return creator_template(verticies, color); + } + + static constexpr GPU::POLY_G3 POLY_G3(const GPU::VertexColor (&verticies_ex)[3]) { + return creator_template(verticies_ex); + } + + static constexpr GPU::POLY_GT3 POLY_GT3(const GPU::Vertex (&verticies)[3], const GPU::PageOffset (&tex_offset)[3], const GPU::Color24 (&color)[3], GPU::TPage tpage, GPU::PageClut clut) { + return creator_template(verticies, tex_offset, color, tpage, clut); + } + + static constexpr GPU::POLY_GT3 POLY_GT3(const GPU::POLY_GT3::VertexEx (&verticies_ex)[3], GPU::TPage tpage, GPU::PageClut clut) { + return creator_template(verticies_ex, tpage, clut); + } + + static constexpr GPU::POLY_F4 POLY_F4(const GPU::Vertex (&verticies)[4], GPU::Color24 color) { + return creator_template(verticies, color); + } + + static constexpr GPU::POLY_F4 POLY_F4(const GPU::AreaI16& area, GPU::Color24 color) { + return creator_template(area, color); + } + + static constexpr GPU::POLY_FT4 POLY_FT4(const GPU::Vertex (&verticies)[4], const GPU::PageOffset (&tex_offset)[4], GPU::TPage tpage, GPU::PageClut clut, GPU::Color24 color) { + return creator_template(verticies, tex_offset, tpage, clut, color); + } + + static constexpr GPU::POLY_FT4 POLY_FT4(const GPU::POLY_FT4::VertexEx (&vertices_ex)[4], GPU::TPage tpage, GPU::PageClut clut, GPU::Color24 color = GPU::Color24::Grey()) { + return creator_template(vertices_ex, tpage, clut, color); + } + + static constexpr GPU::POLY_FT4 POLY_FT4(const GPU::AreaI16& area, const GPU::PageOffset& tex_offset, GPU::TPage tpage, GPU::PageClut clut, GPU::Color24 color = GPU::Color24::Grey()) { + return creator_template(area, tex_offset, tpage, clut, color); + } + + static constexpr GPU::POLY_G4 POLY_G4(const GPU::Vertex (&verticies)[4], const GPU::Color24 (&color)[4]) { + return creator_template(verticies, color); + } + + static constexpr GPU::POLY_G4 POLY_G4(const GPU::VertexColor (&verticies_ex)[4]) { + return creator_template(verticies_ex); + } + + static constexpr GPU::POLY_G4 POLY_G4(const GPU::AreaI16& area, const GPU::Color24 (&color)[4]) { + return creator_template(area, color); + } + + static constexpr GPU::POLY_GT4 POLY_GT4(const GPU::Vertex (&verticies)[4], const GPU::PageOffset (&tex_offset)[4], const GPU::Color24 (&color)[4], GPU::TPage tpage, GPU::PageClut clut) { + return creator_template(verticies, tex_offset, color, tpage, clut); + } + + static constexpr GPU::POLY_GT4 POLY_GT4(const GPU::POLY_GT4::VertexEx (&verticies_ex)[4], GPU::TPage tpage, GPU::PageClut clut) { + return creator_template(verticies_ex, tpage, clut); + } + + static constexpr GPU::POLY_GT4 POLY_GT4(const GPU::AreaI16& area, const GPU::PageOffset& tex_offset, GPU::TPage tpage, GPU::PageClut clut, const GPU::Color24 (&color)[4]) { + return creator_template(area, tex_offset, tpage, clut, color); + } + + // ################################################################### + + static constexpr GPU::TILE_1 TILE_1() { + return creator_template(Vertex(), GPU::Color24::Black()); + } + + static constexpr GPU::TILE_1 TILE_1(const GPU::Vertex& position, const GPU::Color24& color) { + return creator_template(position, color); + } + + static constexpr GPU::TILE_8 TILE_8() { + return creator_template(Vertex(), GPU::Color24::Black()); + } + + static constexpr GPU::TILE_8 TILE_8(const GPU::Vertex& position, const GPU::Color24& color) { + return creator_template(position, color); + } + + static constexpr GPU::TILE_16 TILE_16() { + return creator_template(Vertex(), GPU::Color24::Black()); + } + + static constexpr GPU::TILE_16 TILE_16(const GPU::Vertex& position, const GPU::Color24& color) { + return creator_template(position, color); + } + + static constexpr GPU::TILE TILE() { + return creator_template(AreaI16(), GPU::Color24::Black()); + } + + static constexpr GPU::TILE TILE(const GPU::AreaI16& area, const GPU::Color24& color) { + return creator_template(area, color); + } + + // ################################################################### + + static constexpr GPU::SPRT_1 SPRT_1() { + return creator_template(Vertex(), OffsetPageWithClut(), GPU::Color24::Black()); + } + + static constexpr GPU::SPRT_1 SPRT_1(const GPU::Vertex& position, const GPU::OffsetPageWithClut& tex_offset_w_clut, const GPU::Color24& color = GPU::Color24::Grey()) { + return creator_template(position, tex_offset_w_clut, color); + } + + static constexpr GPU::SPRT_8 SPRT_8() { + return creator_template(Vertex(), OffsetPageWithClut(), GPU::Color24::Black()); + } + + static constexpr GPU::SPRT_8 SPRT_8(const GPU::Vertex& position, const GPU::OffsetPageWithClut& tex_offset_w_clut, const GPU::Color24& color = GPU::Color24::Grey()) { + return creator_template(position, tex_offset_w_clut, color); + } + + static constexpr GPU::SPRT_16 SPRT_16() { + return creator_template(Vertex(), OffsetPageWithClut(), GPU::Color24::Black()); + } + + static constexpr GPU::SPRT_16 SPRT_16(const GPU::Vertex& position, const GPU::OffsetPageWithClut& tex_offset_w_clut, const GPU::Color24& color = GPU::Color24::Grey()) { + return creator_template(position, tex_offset_w_clut, color); + } + + static constexpr GPU::SPRT SPRT() { + return creator_template(AreaI16(), OffsetPageWithClut(), GPU::Color24::Black()); + } + + static constexpr GPU::SPRT SPRT(const GPU::AreaI16& area, const GPU::OffsetPageWithClut& tex_offset_w_clut, const GPU::Color24& color = GPU::Color24::Grey()) { + return creator_template(area, tex_offset_w_clut, color); + } + } } \ No newline at end of file diff --git a/include/PSX/GTE/gte.hpp b/include/PSX/GTE/gte.hpp index f7124d01..043644a4 100644 --- a/include/PSX/GTE/gte.hpp +++ b/include/PSX/GTE/gte.hpp @@ -1,241 +1,241 @@ -#pragma once -#include "gte_instruction.hpp" - -namespace JabyEngine { - namespace GTE { - static constexpr auto StackSize = 16; - - /* - matrix: first input - - Sets the 3x3 constant rotation matrix and the parallel transfer vector from input - */ - void set_matrix(const MATRIX& matrix); - - /* - returns: current matrix - - Gets the current 3x3 constant rotation matrix and the parallel transfer vector - */ - MATRIX get_matrix(); - - /* - RotTrans - - Perform coordinate transformation using a rotation matrix - input: Input vector - output: Output vector - flag: flag output - */ - static void rot_trans(const SVECTOR& input, VECTOR& output, int32_t& flag) { - ldv0(input); - rt(); - stlvnl(output); - stflg(flag); - } - - /* - ScaleMatrix - - m: Pointer to matrix (input/output) - v: Pointer to scale vector (input) - - result: m - Scales m by v. The components of v are fixed point decimals in which 1.0 represents 4096 - */ - static ROTMATRIX& scale_matrix(ROTMATRIX& m, const VECTOR& v) { - static const auto multiply_matrix_row = [](int32_t value, ROTMATRIX& matrix, size_t row) { - ldir0(value); // lwc2 r8, v.x - ldclmv(matrix, row); // load matrix row to r9 - r11 (mtc2) - gpf12(); // gte_gpf12 - stclmv(matrix, row); // store matrix row - }; - - multiply_matrix_row(v.x, m, 0); - multiply_matrix_row(v.y, m, 1); - multiply_matrix_row(v.z, m, 2); - return m; - } - - /* - SetRotMatrix - - Sets a 3x3 matrix m as a constant rotation matrix. - matrix: The rotation matrix to set - */ - static void set_rot_matrix(const ROTMATRIX& matrix) { - __asm__ volatile("lw $12, 0(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); - __asm__ volatile("lw $13, 4(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); - __asm__ volatile("ctc2 $12, $0" :: "r"(&matrix) : "$12", "$13", "$14"); - __asm__ volatile("ctc2 $13, $1" :: "r"(&matrix) : "$12", "$13", "$14"); - __asm__ volatile("lw $12, 8(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); - __asm__ volatile("lw $13, 12(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); - __asm__ volatile("lw $14, 16(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); - __asm__ volatile("ctc2 $12, $2" :: "r"(&matrix) : "$12", "$13", "$14"); - __asm__ volatile("ctc2 $13, $3" :: "r"(&matrix) : "$12", "$13", "$14"); - __asm__ volatile("ctc2 $14, $4" :: "r"(&matrix) : "$12", "$13", "$14"); - } - - /* - GetRotMatrix - - Writes the current 3x3 constant rotation matrix to matrix - (This doesn't require us to use memory clobber) - */ - static void get_rot_matrix(ROTMATRIX &matrix) { - __asm__ volatile("cfc2 $12, $0" :: "r"(&matrix) : "$12", "$13", "$14"); - __asm__ volatile("cfc2 $13, $1" :: "r"(&matrix) : "$12", "$13", "$14"); - __asm__ volatile("sw $12, 0(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); - __asm__ volatile("sw $13, 4(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); - __asm__ volatile("cfc2 $12, $2" :: "r"(&matrix) : "$12", "$13", "$14"); - __asm__ volatile("cfc2 $13, $3" :: "r"(&matrix) : "$12", "$13", "$14"); - __asm__ volatile("cfc2 $14, $4" :: "r"(&matrix) : "$12", "$13", "$14"); - __asm__ volatile("sw $12, 8(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); - __asm__ volatile("sw $13, 12(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); - __asm__ volatile("sw $14, 16(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); - } - - /* - SetTransMatrix - - Sets a constant parallel transfer vector specified by m - */ - static void set_trans_vector(const TRANSFERVECTOR& vector) { - __asm__ volatile("lw $12, 0(%0)" :: "r"(&vector) : "$12", "$13", "$14"); - __asm__ volatile("lw $13, 4(%0)" :: "r"(&vector) : "$12", "$13", "$14"); - __asm__ volatile("ctc2 $12, $5" :: "r"(&vector) : "$12", "$13", "$14"); - __asm__ volatile("lw $14, 8(%0)" :: "r"(&vector) : "$12", "$13", "$14"); - __asm__ volatile("ctc2 $13, $6" :: "r"(&vector) : "$12", "$13", "$14"); - __asm__ volatile("ctc2 $14, $7" :: "r"(&vector) : "$12", "$13", "$14"); - } - - /* - GetTransMatrix - - Writes the current constant parallel transfer vector to matrix - (This doesn't require us to use memory clobber) - */ - static void get_trans_vector(TRANSFERVECTOR& vector) { - __asm__ volatile("cfc2 $14, $7" :: "r"(&vector) : "$12", "$13", "$14"); - __asm__ volatile("cfc2 $13, $6" :: "r"(&vector) : "$12", "$13", "$14"); - __asm__ volatile("sw $14, 8(%0)" :: "r"(&vector) : "$12", "$13", "$14"); - __asm__ volatile("cfc2 $12, $5" :: "r"(&vector) : "$12", "$13", "$14"); - __asm__ volatile("sw $13, 4(%0)" :: "r"(&vector) : "$12", "$13", "$14"); - __asm__ volatile("sw $12, 0(%0)" :: "r"(&vector) : "$12", "$13", "$14"); - } - - /* - ApplyMatrix - m0: Matrix to apply - v0: Vector to apply to - v1: Result - returns: result - - Applies the matrix to the vector - The function destroys the constant rotation matrix and transfer vector - */ - static SVECTOR& apply_matrix(const MATRIX& m0, const SVECTOR& v0, SVECTOR& v1) { - set_matrix(m0); - - JabyEngine::GTE::ldv0(v0); - JabyEngine::GTE::rt(); - JabyEngine::GTE::stsv(v1); - return v1; - } - - /* - Same as apply_matrix but works on Vertex - */ - static GPU::Vertex& apply_matrix(const MATRIX& m0, const GPU::Vertex& v0, GPU::Vertex& v1) { - set_matrix(m0); - - JabyEngine::GTE::ldgv0(v0); - JabyEngine::GTE::rt(); - JabyEngine::GTE::stgv(v1); - return v1; - } - - /* - MulMatrix0 - - m0: first input - m1: second input - result: result of multiplication - returns: result - - Multiplies two matrices m0 and m1. - The function destroys the constant rotation matrix - */ - ROTMATRIX& multiply_matrix(const ROTMATRIX& m0, const ROTMATRIX& m1, ROTMATRIX& result); - - /* - CompMatrix - - m0: first input - m1: second input - result: result of computing m0 and m1 - return: returns result - */ - static MATRIX& comp_matrix(const MATRIX& m0, const MATRIX& m1, MATRIX& result) { - multiply_matrix(m0.rotation, m1.rotation, result.rotation); - set_trans_vector(m0.transfer); - GTE::ldlv0(reinterpret_cast(m1.transfer)); - GTE::rt(); - GTE::stlvnl(reinterpret_cast(result.transfer)); - - return result; - } - - /* - matrix: optional input - - Pushes the current matrix (rotation and parallel) to an internal stack - Optional: replaces current matrix (rotation and parallel) with input - */ - void push_matrix(); - void push_matrix_and_set(const MATRIX& matrix); - - /* - Restores the previous stored matrix (rotation and parallel) - */ - MATRIX get_and_pop_matrix(); - void pop_matrix(); - - /* - SetGeomOffset(ofx,ofy) - - Load GTE-offset. - */ - static void set_geom_offset(int32_t off_x, int32_t off_y) { - __asm__ volatile("sll $12, %0, 16" :: "r"(off_x), "r"(off_y) : "$12", "$13"); - __asm__ volatile("sll $13, %1, 16" :: "r"(off_x), "r"(off_y) : "$12", "$13"); - __asm__ volatile("ctc2 $12, $24" :: "r"(off_x), "r"(off_y) : "$12", "$13"); - __asm__ volatile("ctc2 $13, $25" :: "r"(off_x), "r"(off_y) : "$12", "$13"); - } - - /* - SetGeomScreen(h) - - Load distance from viewpoint to screen. - */ - static void set_geom_screen(int32_t h) { - __asm__ volatile("ctc2 %0, $26" :: "r"(h)); - } - - // Implementations for the MATRIX struct - inline MATRIX& MATRIX :: comp(const MATRIX& matrix) { - return comp_matrix(matrix, *this, *this); - } - - inline GPU::Vertex& MATRIX :: apply_to(GPU::Vertex& vertex) const { - return apply_matrix(*this, vertex, vertex); - } - - inline GPU::Vertex MATRIX :: apply_to(const GPU::Vertex& vertex) const { - GPU::Vertex result; - - apply_matrix(*this, vertex, result); - return result; - } - } +#pragma once +#include "gte_instruction.hpp" + +namespace JabyEngine { + namespace GTE { + static constexpr auto StackSize = 16; + + /* + matrix: first input + + Sets the 3x3 constant rotation matrix and the parallel transfer vector from input + */ + void set_matrix(const MATRIX& matrix); + + /* + returns: current matrix + + Gets the current 3x3 constant rotation matrix and the parallel transfer vector + */ + MATRIX get_matrix(); + + /* + RotTrans + + Perform coordinate transformation using a rotation matrix + input: Input vector + output: Output vector + flag: flag output + */ + static void rot_trans(const SVECTOR& input, VECTOR& output, int32_t& flag) { + ldv0(input); + rt(); + stlvnl(output); + stflg(flag); + } + + /* + ScaleMatrix + + m: Pointer to matrix (input/output) + v: Pointer to scale vector (input) + + result: m + Scales m by v. The components of v are fixed point decimals in which 1.0 represents 4096 + */ + static ROTMATRIX& scale_matrix(ROTMATRIX& m, const VECTOR& v) { + static const auto multiply_matrix_row = [](int32_t value, ROTMATRIX& matrix, size_t row) { + ldir0(value); // lwc2 r8, v.x + ldclmv(matrix, row); // load matrix row to r9 - r11 (mtc2) + gpf12(); // gte_gpf12 + stclmv(matrix, row); // store matrix row + }; + + multiply_matrix_row(v.x, m, 0); + multiply_matrix_row(v.y, m, 1); + multiply_matrix_row(v.z, m, 2); + return m; + } + + /* + SetRotMatrix + + Sets a 3x3 matrix m as a constant rotation matrix. + matrix: The rotation matrix to set + */ + static void set_rot_matrix(const ROTMATRIX& matrix) { + __asm__ volatile("lw $12, 0(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("lw $13, 4(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("ctc2 $12, $0" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("ctc2 $13, $1" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("lw $12, 8(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("lw $13, 12(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("lw $14, 16(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("ctc2 $12, $2" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("ctc2 $13, $3" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("ctc2 $14, $4" :: "r"(&matrix) : "$12", "$13", "$14"); + } + + /* + GetRotMatrix + + Writes the current 3x3 constant rotation matrix to matrix + (This doesn't require us to use memory clobber) + */ + static void get_rot_matrix(ROTMATRIX &matrix) { + __asm__ volatile("cfc2 $12, $0" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("cfc2 $13, $1" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("sw $12, 0(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("sw $13, 4(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("cfc2 $12, $2" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("cfc2 $13, $3" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("cfc2 $14, $4" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("sw $12, 8(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("sw $13, 12(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + __asm__ volatile("sw $14, 16(%0)" :: "r"(&matrix) : "$12", "$13", "$14"); + } + + /* + SetTransMatrix + + Sets a constant parallel transfer vector specified by m + */ + static void set_trans_vector(const TRANSFERVECTOR& vector) { + __asm__ volatile("lw $12, 0(%0)" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("lw $13, 4(%0)" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("ctc2 $12, $5" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("lw $14, 8(%0)" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("ctc2 $13, $6" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("ctc2 $14, $7" :: "r"(&vector) : "$12", "$13", "$14"); + } + + /* + GetTransMatrix + + Writes the current constant parallel transfer vector to matrix + (This doesn't require us to use memory clobber) + */ + static void get_trans_vector(TRANSFERVECTOR& vector) { + __asm__ volatile("cfc2 $14, $7" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("cfc2 $13, $6" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("sw $14, 8(%0)" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("cfc2 $12, $5" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("sw $13, 4(%0)" :: "r"(&vector) : "$12", "$13", "$14"); + __asm__ volatile("sw $12, 0(%0)" :: "r"(&vector) : "$12", "$13", "$14"); + } + + /* + ApplyMatrix + m0: Matrix to apply + v0: Vector to apply to + v1: Result + returns: result + + Applies the matrix to the vector + The function destroys the constant rotation matrix and transfer vector + */ + static SVECTOR& apply_matrix(const MATRIX& m0, const SVECTOR& v0, SVECTOR& v1) { + set_matrix(m0); + + JabyEngine::GTE::ldv0(v0); + JabyEngine::GTE::rt(); + JabyEngine::GTE::stsv(v1); + return v1; + } + + /* + Same as apply_matrix but works on Vertex + */ + static GPU::Vertex& apply_matrix(const MATRIX& m0, const GPU::Vertex& v0, GPU::Vertex& v1) { + set_matrix(m0); + + JabyEngine::GTE::ldgv0(v0); + JabyEngine::GTE::rt(); + JabyEngine::GTE::stgv(v1); + return v1; + } + + /* + MulMatrix0 + + m0: first input + m1: second input + result: result of multiplication + returns: result + + Multiplies two matrices m0 and m1. + The function destroys the constant rotation matrix + */ + ROTMATRIX& multiply_matrix(const ROTMATRIX& m0, const ROTMATRIX& m1, ROTMATRIX& result); + + /* + CompMatrix + + m0: first input + m1: second input + result: result of computing m0 and m1 + return: returns result + */ + static MATRIX& comp_matrix(const MATRIX& m0, const MATRIX& m1, MATRIX& result) { + multiply_matrix(m0.rotation, m1.rotation, result.rotation); + set_trans_vector(m0.transfer); + GTE::ldlv0(reinterpret_cast(m1.transfer)); + GTE::rt(); + GTE::stlvnl(reinterpret_cast(result.transfer)); + + return result; + } + + /* + matrix: optional input + + Pushes the current matrix (rotation and parallel) to an internal stack + Optional: replaces current matrix (rotation and parallel) with input + */ + void push_matrix(); + void push_matrix_and_set(const MATRIX& matrix); + + /* + Restores the previous stored matrix (rotation and parallel) + */ + MATRIX get_and_pop_matrix(); + void pop_matrix(); + + /* + SetGeomOffset(ofx,ofy) + + Load GTE-offset. + */ + static void set_geom_offset(int32_t off_x, int32_t off_y) { + __asm__ volatile("sll $12, %0, 16" :: "r"(off_x), "r"(off_y) : "$12", "$13"); + __asm__ volatile("sll $13, %1, 16" :: "r"(off_x), "r"(off_y) : "$12", "$13"); + __asm__ volatile("ctc2 $12, $24" :: "r"(off_x), "r"(off_y) : "$12", "$13"); + __asm__ volatile("ctc2 $13, $25" :: "r"(off_x), "r"(off_y) : "$12", "$13"); + } + + /* + SetGeomScreen(h) + + Load distance from viewpoint to screen. + */ + static void set_geom_screen(int32_t h) { + __asm__ volatile("ctc2 %0, $26" :: "r"(h)); + } + + // Implementations for the MATRIX struct + inline MATRIX& MATRIX :: comp(const MATRIX& matrix) { + return comp_matrix(matrix, *this, *this); + } + + inline GPU::Vertex& MATRIX :: apply_to(GPU::Vertex& vertex) const { + return apply_matrix(*this, vertex, vertex); + } + + inline GPU::Vertex MATRIX :: apply_to(const GPU::Vertex& vertex) const { + GPU::Vertex result; + + apply_matrix(*this, vertex, result); + return result; + } + } } \ No newline at end of file diff --git a/include/PSX/GTE/gte_instruction.hpp b/include/PSX/GTE/gte_instruction.hpp index 9f5b9ca3..26d58ea8 100644 --- a/include/PSX/GTE/gte_instruction.hpp +++ b/include/PSX/GTE/gte_instruction.hpp @@ -1,137 +1,137 @@ -#pragma once -#include "gte_types.hpp" - -namespace JabyEngine { - namespace GTE { - // Load vertex or normal to vertex register 0 - static __always_inline void ldv0(const SVECTOR& vector) { - __asm__ volatile("lwc2 $0, 0(%0)" :: "r"(&vector)); - __asm__ volatile("lwc2 $1, 4(%0)" :: "r"(&vector)); - } - - // Load vertex or normal to vertex register 1 - static __always_inline void ldv1(const SVECTOR& vector) { - __asm__ volatile("lwc2 $2, 0(%0)" :: "r"(&vector)); - __asm__ volatile("lwc2 $3, 4(%0)" :: "r"(&vector)); - } - - // Load vertex or normal to vertex register 2 - static __always_inline void ldv2(const SVECTOR& vector) { - __asm__ volatile("lwc2 $4, 0(%0)" :: "r"(&vector)); - __asm__ volatile("lwc2 $5, 4(%0)" :: "r"(&vector)); - } - - // Load int32_t to ir0 register (for multiplying usually) - static __always_inline void ldir0(const int32_t& value) { - __asm__ volatile("lwc2 $8, 0(%0)" :: "r"(&value)); - } - - // Load LS 16 bits of VECTOR to 16 bit universal vector. - static __always_inline void ldlv0(const VECTOR& vector) { - __asm__ volatile("lhu $13, 4(%0)" :: "r"(&vector) : "$12", "$13"); - __asm__ volatile("lhu $12, 0(%0)" :: "r"(&vector) : "$12", "$13"); - __asm__ volatile("sll $13, $13, 16" :: "r"(&vector) : "$12", "$13"); - __asm__ volatile("or $12, $12, $13" :: "r"(&vector) : "$12", "$13"); - __asm__ volatile("mtc2 $12, $0" :: "r"(&vector) : "$12", "$13"); - __asm__ volatile("lwc2 $1, 8(%0)" :: "r"(&vector) : "$12", "$13"); - } - - // Loads a GPU VERTEX type - static __always_inline void ldgv0(const GPU::Vertex& vertex) { - __asm__ volatile("lwc2 $0, 0(%0)" :: "r"(&vertex)); - __asm__ volatile("lwc2 $1, 0" :: "r"(&vertex)); - } - - // Load column vector of MATRIX to universal register - static __always_inline void ldclmv(const ROTMATRIX& matrix, size_t col) { - __asm__ volatile("lhu $12, 0(%0)" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14"); - __asm__ volatile("lhu $13, 6(%0)" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14"); - __asm__ volatile("lhu $14, 12(%0)" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14"); - __asm__ volatile("mtc2 $12, $9" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14"); - __asm__ volatile("mtc2 $13, $10" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14"); - __asm__ volatile("mtc2 $14, $11" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14"); - } - - // Store flag - static __always_inline void stflg(int32_t& flag) { - __asm__ volatile("cfc2 $12, $31" :: "r"(&flag) : "$12", "memory"); - __asm__ volatile("nop" :: "r"(&flag) : "$12", "memory"); - __asm__ volatile("sw $12, 0(%0)" :: "r"(&flag) : "$12", "memory"); - } - - // Store MATRIX column from 16 bit universal register - static __always_inline void stclmv(ROTMATRIX& matrix, size_t col) { - __asm__ volatile("mfc2 $12, $9" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14", "memory"); - __asm__ volatile("mfc2 $13, $10" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14", "memory"); - __asm__ volatile("mfc2 $14, $11" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14", "memory"); - __asm__ volatile("sh $12, 0(%0)" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14", "memory"); - __asm__ volatile("sh $13, 6(%0)" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14", "memory"); - __asm__ volatile("sh $14, 12(%0)" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14", "memory"); - } - - // Store VECTOR from 32 bit universal register - static __always_inline void stlvnl(VECTOR& out_vector) { - __asm__ volatile("swc2 $25, 0(%0)" :: "r"(&out_vector) : "memory"); - __asm__ volatile("swc2 $26, 4(%0)" :: "r"(&out_vector) : "memory"); - __asm__ volatile("swc2 $27, 8(%0)" :: "r"(&out_vector) : "memory"); - } - - // Modify to store in VERTEX? - // Store SVECTOR from 16 bit universal register - static __always_inline void stsv(SVECTOR& out_vector) { - __asm__ volatile("mfc2 $12, $9" :: "r"(&out_vector) : "$12", "$13", "$14", "memory"); - __asm__ volatile("mfc2 $13, $10" :: "r"(&out_vector) : "$12", "$13", "$14", "memory"); - __asm__ volatile("mfc2 $14, $11" :: "r"(&out_vector) : "$12", "$13", "$14", "memory"); - __asm__ volatile("sh $12, 0(%0)" :: "r"(&out_vector) : "$12", "$13", "$14", "memory"); - __asm__ volatile("sh $13, 2(%0)" :: "r"(&out_vector) : "$12", "$13", "$14", "memory"); - __asm__ volatile("sh $14, 4(%0)" :: "r"(&out_vector) : "$12", "$13", "$14", "memory"); - } - - // Stores result into a GPU Vertex type - static __always_inline void stgv(GPU::Vertex& out_vertex) { - __asm__ volatile("mfc2 $12, $9" :: "r"(&out_vertex) : "$12", "$13", "$14", "memory"); - __asm__ volatile("mfc2 $13, $10" :: "r"(&out_vertex) : "$12", "$13", "$14", "memory"); - __asm__ volatile("sh $12, 0(%0)" :: "r"(&out_vertex) : "$12", "$13", "$14", "memory"); - __asm__ volatile("sh $13, 2(%0)" :: "r"(&out_vertex) : "$12", "$13", "$14", "memory"); - } - - /* - Kernel of RotTrans - (Transfer vector)+(Rotation Matrix)*(vertex register 0) - */ - static __always_inline void rt() { - __asm__ volatile("nop"); - __asm__ volatile("nop"); - __asm__ volatile("cop2 0x0480012"); - } - - /* - Variation of gte_rt - (Rotation Matrix)*(vertex register 0). - */ - static __always_inline void rtv0() { - __asm__ volatile("nop;"); - __asm__ volatile("nop;"); - __asm__ volatile("cop2 0x0486012;"); - } - - /* - Variation of gte_rt - (Rotation Matrix)*(16 bit universal vector) - */ - static __always_inline void rtir() { - __asm__ volatile("nop"); - __asm__ volatile("nop"); - __asm__ volatile("cop2 0x049E012"); - } - - /* - Last half of LoadAverage12. - */ - static __always_inline void gpf12(){ - __asm__ volatile("nop"); - __asm__ volatile("nop"); - __asm__ volatile("cop2 0x0198003D"); - } - } +#pragma once +#include "gte_types.hpp" + +namespace JabyEngine { + namespace GTE { + // Load vertex or normal to vertex register 0 + static __always_inline void ldv0(const SVECTOR& vector) { + __asm__ volatile("lwc2 $0, 0(%0)" :: "r"(&vector)); + __asm__ volatile("lwc2 $1, 4(%0)" :: "r"(&vector)); + } + + // Load vertex or normal to vertex register 1 + static __always_inline void ldv1(const SVECTOR& vector) { + __asm__ volatile("lwc2 $2, 0(%0)" :: "r"(&vector)); + __asm__ volatile("lwc2 $3, 4(%0)" :: "r"(&vector)); + } + + // Load vertex or normal to vertex register 2 + static __always_inline void ldv2(const SVECTOR& vector) { + __asm__ volatile("lwc2 $4, 0(%0)" :: "r"(&vector)); + __asm__ volatile("lwc2 $5, 4(%0)" :: "r"(&vector)); + } + + // Load int32_t to ir0 register (for multiplying usually) + static __always_inline void ldir0(const int32_t& value) { + __asm__ volatile("lwc2 $8, 0(%0)" :: "r"(&value)); + } + + // Load LS 16 bits of VECTOR to 16 bit universal vector. + static __always_inline void ldlv0(const VECTOR& vector) { + __asm__ volatile("lhu $13, 4(%0)" :: "r"(&vector) : "$12", "$13"); + __asm__ volatile("lhu $12, 0(%0)" :: "r"(&vector) : "$12", "$13"); + __asm__ volatile("sll $13, $13, 16" :: "r"(&vector) : "$12", "$13"); + __asm__ volatile("or $12, $12, $13" :: "r"(&vector) : "$12", "$13"); + __asm__ volatile("mtc2 $12, $0" :: "r"(&vector) : "$12", "$13"); + __asm__ volatile("lwc2 $1, 8(%0)" :: "r"(&vector) : "$12", "$13"); + } + + // Loads a GPU VERTEX type + static __always_inline void ldgv0(const GPU::Vertex& vertex) { + __asm__ volatile("lwc2 $0, 0(%0)" :: "r"(&vertex)); + __asm__ volatile("lwc2 $1, 0" :: "r"(&vertex)); + } + + // Load column vector of MATRIX to universal register + static __always_inline void ldclmv(const ROTMATRIX& matrix, size_t col) { + __asm__ volatile("lhu $12, 0(%0)" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14"); + __asm__ volatile("lhu $13, 6(%0)" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14"); + __asm__ volatile("lhu $14, 12(%0)" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14"); + __asm__ volatile("mtc2 $12, $9" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14"); + __asm__ volatile("mtc2 $13, $10" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14"); + __asm__ volatile("mtc2 $14, $11" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14"); + } + + // Store flag + static __always_inline void stflg(int32_t& flag) { + __asm__ volatile("cfc2 $12, $31" :: "r"(&flag) : "$12", "memory"); + __asm__ volatile("nop" :: "r"(&flag) : "$12", "memory"); + __asm__ volatile("sw $12, 0(%0)" :: "r"(&flag) : "$12", "memory"); + } + + // Store MATRIX column from 16 bit universal register + static __always_inline void stclmv(ROTMATRIX& matrix, size_t col) { + __asm__ volatile("mfc2 $12, $9" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14", "memory"); + __asm__ volatile("mfc2 $13, $10" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14", "memory"); + __asm__ volatile("mfc2 $14, $11" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14", "memory"); + __asm__ volatile("sh $12, 0(%0)" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14", "memory"); + __asm__ volatile("sh $13, 6(%0)" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14", "memory"); + __asm__ volatile("sh $14, 12(%0)" :: "r"(reinterpret_cast(&matrix) + (col << 1)) : "$12", "$13", "$14", "memory"); + } + + // Store VECTOR from 32 bit universal register + static __always_inline void stlvnl(VECTOR& out_vector) { + __asm__ volatile("swc2 $25, 0(%0)" :: "r"(&out_vector) : "memory"); + __asm__ volatile("swc2 $26, 4(%0)" :: "r"(&out_vector) : "memory"); + __asm__ volatile("swc2 $27, 8(%0)" :: "r"(&out_vector) : "memory"); + } + + // Modify to store in VERTEX? + // Store SVECTOR from 16 bit universal register + static __always_inline void stsv(SVECTOR& out_vector) { + __asm__ volatile("mfc2 $12, $9" :: "r"(&out_vector) : "$12", "$13", "$14", "memory"); + __asm__ volatile("mfc2 $13, $10" :: "r"(&out_vector) : "$12", "$13", "$14", "memory"); + __asm__ volatile("mfc2 $14, $11" :: "r"(&out_vector) : "$12", "$13", "$14", "memory"); + __asm__ volatile("sh $12, 0(%0)" :: "r"(&out_vector) : "$12", "$13", "$14", "memory"); + __asm__ volatile("sh $13, 2(%0)" :: "r"(&out_vector) : "$12", "$13", "$14", "memory"); + __asm__ volatile("sh $14, 4(%0)" :: "r"(&out_vector) : "$12", "$13", "$14", "memory"); + } + + // Stores result into a GPU Vertex type + static __always_inline void stgv(GPU::Vertex& out_vertex) { + __asm__ volatile("mfc2 $12, $9" :: "r"(&out_vertex) : "$12", "$13", "$14", "memory"); + __asm__ volatile("mfc2 $13, $10" :: "r"(&out_vertex) : "$12", "$13", "$14", "memory"); + __asm__ volatile("sh $12, 0(%0)" :: "r"(&out_vertex) : "$12", "$13", "$14", "memory"); + __asm__ volatile("sh $13, 2(%0)" :: "r"(&out_vertex) : "$12", "$13", "$14", "memory"); + } + + /* + Kernel of RotTrans + (Transfer vector)+(Rotation Matrix)*(vertex register 0) + */ + static __always_inline void rt() { + __asm__ volatile("nop"); + __asm__ volatile("nop"); + __asm__ volatile("cop2 0x0480012"); + } + + /* + Variation of gte_rt + (Rotation Matrix)*(vertex register 0). + */ + static __always_inline void rtv0() { + __asm__ volatile("nop;"); + __asm__ volatile("nop;"); + __asm__ volatile("cop2 0x0486012;"); + } + + /* + Variation of gte_rt + (Rotation Matrix)*(16 bit universal vector) + */ + static __always_inline void rtir() { + __asm__ volatile("nop"); + __asm__ volatile("nop"); + __asm__ volatile("cop2 0x049E012"); + } + + /* + Last half of LoadAverage12. + */ + static __always_inline void gpf12(){ + __asm__ volatile("nop"); + __asm__ volatile("nop"); + __asm__ volatile("cop2 0x0198003D"); + } + } } \ No newline at end of file diff --git a/include/PSX/GTE/gte_types.hpp b/include/PSX/GTE/gte_types.hpp index 300c6920..c5555eb2 100644 --- a/include/PSX/GTE/gte_types.hpp +++ b/include/PSX/GTE/gte_types.hpp @@ -1,138 +1,138 @@ -#pragma once -#include "../GPU/Primitives/primitive_poly_types.hpp" -#include "../GPU/gpu_types.hpp" -#include "../../math.hpp" -#include "../../stdio.hpp" - -namespace JabyEngine { - namespace GTE { - namespace internal { - template - struct VECTOR { - T x; - T y; - T z; - T pad; - - static constexpr VECTOR create() { - return VECTOR::create(0, 0, 0); - } - - static constexpr VECTOR create(T x, T y, T z) { - return VECTOR{.x = x, .y = y, .z = z, .pad = 0}; - } - - static constexpr VECTOR create(gte_float x, gte_float y, gte_float z) { - return VECTOR{.x = static_cast(x), .y = static_cast(y), .z = static_cast(z)}; - } - - template - static constexpr VECTOR from(const GPU::Position& pos) { - return VECTOR::create(static_cast(pos.x), static_cast(pos.y), 0); - } - - template - constexpr S to() const { - return S::create(static_cast(this->x), static_cast(this->y)); - } - }; - } - using VECTOR = internal::VECTOR; - using SVECTOR = internal::VECTOR; - - struct ROTMATRIX { - int16_t matrix[3][3]; - - static constexpr ROTMATRIX identity() { - return ROTMATRIX{.matrix = { - {static_cast(gte_float::one()), 0, 0}, - {0, static_cast(gte_float::one()), 0}, - {0, 0, static_cast(gte_float::one())} - } - }; - } - - static constexpr ROTMATRIX scaled(gte_float sx = 1.0_gf, gte_float sy = 1.0_gf, gte_float sz = 1.0_gf) { - return ROTMATRIX{.matrix = { - {static_cast(sx), 0, 0}, - {0, static_cast(sy), 0}, - {0, 0, static_cast(sz)} - } - }; - } - - static ROTMATRIX rotated(deg_t x = 0.0_deg, deg_t y = 0.0_deg, deg_t z = 0.0_deg); - }; - - struct TRANSFERVECTOR : public VECTOR { - static constexpr TRANSFERVECTOR identity() { - return TRANSFERVECTOR::translated(); - } - - static constexpr TRANSFERVECTOR translated(int32_t x = 0, int32_t y = 0, int32_t z = 0) { - return TRANSFERVECTOR{{.x = x, .y = y, .z = z}}; - } - }; - - struct MATRIX { - ROTMATRIX rotation; - TRANSFERVECTOR transfer; - - static constexpr MATRIX identity() { - return MATRIX{.rotation = ROTMATRIX::identity(), .transfer = TRANSFERVECTOR::identity()}; - } - - static constexpr MATRIX translated(int32_t x = 0, int32_t y = 0, int32_t z = 0) { - return MATRIX{.rotation = ROTMATRIX::identity(), .transfer = TRANSFERVECTOR::translated(x, y, z)}; - } - - static constexpr MATRIX scaled(gte_float sx = 1.0_gf, gte_float sy = 1.0_gf, gte_float sz = 1.0_gf) { - return MATRIX{.rotation = ROTMATRIX::scaled(sx, sy, sz), .transfer = TRANSFERVECTOR::identity()}; - } - - static MATRIX rotated(deg_t x = 0.0_deg, deg_t y = 0.0_deg, deg_t z = 0.0_deg) { - return MATRIX{.rotation = ROTMATRIX::rotated(x, y, z), .transfer = TRANSFERVECTOR::identity()}; - } - - static MATRIX comp(MATRIX new_matrix, const MATRIX& matrix) { - new_matrix.comp(matrix); - return new_matrix; - } - - void dump() const { - printf("---\n"); - printf("|%i|%i|%i|\n", this->rotation.matrix[0][0], this->rotation.matrix[0][1], this->rotation.matrix[0][2]); - printf("|%i|%i|%i|\n", this->rotation.matrix[1][0], this->rotation.matrix[1][1], this->rotation.matrix[1][2]); - printf("|%i|%i|%i|\n", this->rotation.matrix[2][0], this->rotation.matrix[2][1], this->rotation.matrix[2][2]); - printf("~~~\n"); - printf("|%i|%i|%i|\n", this->transfer.x, this->transfer.y, this->transfer.z); - printf("---\n"); - } - - MATRIX& comp(const MATRIX& matrix); - MATRIX& translate(int32_t x = 0, int32_t y = 0, int32_t z = 0) { - return MATRIX::comp(MATRIX::translated(x, y, z)); - } - - MATRIX& scale(gte_float sx = 1.0_gf, gte_float sy = 1.0_gf, gte_float sz = 1.0_gf) { - return MATRIX::comp(MATRIX::scaled(sx, sy, sz)); - } - - MATRIX& rotate(deg_t x = 0.0_deg, deg_t y = 0.0_deg, deg_t z = 0.0_deg) { - return MATRIX::comp(MATRIX::rotated(x, y, z)); - } - - GPU::Vertex& apply_to(GPU::Vertex& vertex) const; - GPU::Vertex apply_to(const GPU::Vertex& vertex) const; - - template - T& apply_to_area(T& poly, const GPU::AreaI16& area) const { - poly.vertex0 = MATRIX::apply_to(GPU::POLY_G4::vertex0_from(area)); - poly.vertex1 = MATRIX::apply_to(GPU::POLY_G4::vertex1_from(area)); - poly.vertex2 = MATRIX::apply_to(GPU::POLY_G4::vertex2_from(area)); - poly.vertex3 = MATRIX::apply_to(GPU::POLY_G4::vertex3_from(area)); - return poly; - } - }; - } +#pragma once +#include "../GPU/Primitives/primitive_poly_types.hpp" +#include "../GPU/gpu_types.hpp" +#include "../../math.hpp" +#include "../../stdio.hpp" + +namespace JabyEngine { + namespace GTE { + namespace internal { + template + struct VECTOR { + T x; + T y; + T z; + T pad; + + static constexpr VECTOR create() { + return VECTOR::create(0, 0, 0); + } + + static constexpr VECTOR create(T x, T y, T z) { + return VECTOR{.x = x, .y = y, .z = z, .pad = 0}; + } + + static constexpr VECTOR create(gte_float x, gte_float y, gte_float z) { + return VECTOR{.x = static_cast(x), .y = static_cast(y), .z = static_cast(z)}; + } + + template + static constexpr VECTOR from(const GPU::Position& pos) { + return VECTOR::create(static_cast(pos.x), static_cast(pos.y), 0); + } + + template + constexpr S to() const { + return S::create(static_cast(this->x), static_cast(this->y)); + } + }; + } + using VECTOR = internal::VECTOR; + using SVECTOR = internal::VECTOR; + + struct ROTMATRIX { + int16_t matrix[3][3]; + + static constexpr ROTMATRIX identity() { + return ROTMATRIX{.matrix = { + {static_cast(gte_float::one()), 0, 0}, + {0, static_cast(gte_float::one()), 0}, + {0, 0, static_cast(gte_float::one())} + } + }; + } + + static constexpr ROTMATRIX scaled(gte_float sx = 1.0_gf, gte_float sy = 1.0_gf, gte_float sz = 1.0_gf) { + return ROTMATRIX{.matrix = { + {static_cast(sx), 0, 0}, + {0, static_cast(sy), 0}, + {0, 0, static_cast(sz)} + } + }; + } + + static ROTMATRIX rotated(deg_t x = 0.0_deg, deg_t y = 0.0_deg, deg_t z = 0.0_deg); + }; + + struct TRANSFERVECTOR : public VECTOR { + static constexpr TRANSFERVECTOR identity() { + return TRANSFERVECTOR::translated(); + } + + static constexpr TRANSFERVECTOR translated(int32_t x = 0, int32_t y = 0, int32_t z = 0) { + return TRANSFERVECTOR{{.x = x, .y = y, .z = z}}; + } + }; + + struct MATRIX { + ROTMATRIX rotation; + TRANSFERVECTOR transfer; + + static constexpr MATRIX identity() { + return MATRIX{.rotation = ROTMATRIX::identity(), .transfer = TRANSFERVECTOR::identity()}; + } + + static constexpr MATRIX translated(int32_t x = 0, int32_t y = 0, int32_t z = 0) { + return MATRIX{.rotation = ROTMATRIX::identity(), .transfer = TRANSFERVECTOR::translated(x, y, z)}; + } + + static constexpr MATRIX scaled(gte_float sx = 1.0_gf, gte_float sy = 1.0_gf, gte_float sz = 1.0_gf) { + return MATRIX{.rotation = ROTMATRIX::scaled(sx, sy, sz), .transfer = TRANSFERVECTOR::identity()}; + } + + static MATRIX rotated(deg_t x = 0.0_deg, deg_t y = 0.0_deg, deg_t z = 0.0_deg) { + return MATRIX{.rotation = ROTMATRIX::rotated(x, y, z), .transfer = TRANSFERVECTOR::identity()}; + } + + static MATRIX comp(MATRIX new_matrix, const MATRIX& matrix) { + new_matrix.comp(matrix); + return new_matrix; + } + + void dump() const { + printf("---\n"); + printf("|%i|%i|%i|\n", this->rotation.matrix[0][0], this->rotation.matrix[0][1], this->rotation.matrix[0][2]); + printf("|%i|%i|%i|\n", this->rotation.matrix[1][0], this->rotation.matrix[1][1], this->rotation.matrix[1][2]); + printf("|%i|%i|%i|\n", this->rotation.matrix[2][0], this->rotation.matrix[2][1], this->rotation.matrix[2][2]); + printf("~~~\n"); + printf("|%i|%i|%i|\n", this->transfer.x, this->transfer.y, this->transfer.z); + printf("---\n"); + } + + MATRIX& comp(const MATRIX& matrix); + MATRIX& translate(int32_t x = 0, int32_t y = 0, int32_t z = 0) { + return MATRIX::comp(MATRIX::translated(x, y, z)); + } + + MATRIX& scale(gte_float sx = 1.0_gf, gte_float sy = 1.0_gf, gte_float sz = 1.0_gf) { + return MATRIX::comp(MATRIX::scaled(sx, sy, sz)); + } + + MATRIX& rotate(deg_t x = 0.0_deg, deg_t y = 0.0_deg, deg_t z = 0.0_deg) { + return MATRIX::comp(MATRIX::rotated(x, y, z)); + } + + GPU::Vertex& apply_to(GPU::Vertex& vertex) const; + GPU::Vertex apply_to(const GPU::Vertex& vertex) const; + + template + T& apply_to_area(T& poly, const GPU::AreaI16& area) const { + poly.vertex0 = MATRIX::apply_to(GPU::POLY_G4::vertex0_from(area)); + poly.vertex1 = MATRIX::apply_to(GPU::POLY_G4::vertex1_from(area)); + poly.vertex2 = MATRIX::apply_to(GPU::POLY_G4::vertex2_from(area)); + poly.vertex3 = MATRIX::apply_to(GPU::POLY_G4::vertex3_from(area)); + return poly; + } + }; + } } \ No newline at end of file diff --git a/include/PSX/Periphery/controller.hpp b/include/PSX/Periphery/controller.hpp index 80e25207..439e20a0 100644 --- a/include/PSX/Periphery/controller.hpp +++ b/include/PSX/Periphery/controller.hpp @@ -1,107 +1,107 @@ -#pragma once -#include "../GPU/gpu_types.hpp" -#include "raw_controller.hpp" - -namespace JabyEngine { - namespace Periphery { - class GenericController : public RawController { - public: - struct Rumble { - static constexpr uint8_t LargeMotorThreshold = 0x60; - }; - - enum struct Button : uint16_t { - L2 = static_cast(GenericButton::D0), - R2 = static_cast(GenericButton::D1), - L1 = static_cast(GenericButton::D2), - R1 = static_cast(GenericButton::D3), - Triangle = static_cast(GenericButton::D4), - Circle = static_cast(GenericButton::D5), - Cross = static_cast(GenericButton::D6), - Square = static_cast(GenericButton::D7), - SEL = static_cast(GenericButton::D8), - ST = static_cast(GenericButton::D11), - Up = static_cast(GenericButton::D12), - Right = static_cast(GenericButton::D13), - Down = static_cast(GenericButton::D14), - Left = static_cast(GenericButton::D15) - }; - - void set_digital_rumble() { - RawController::header.rumble0 = 0x1; - RawController::header.rumble1 = 0x7F; - } - - void set_analog_rumble(uint8_t largeMotor, bool smallMotor) { - RawController::header.rumble0 = smallMotor ? 0x1 : 0x0; - RawController::header.rumble1 = largeMotor; - } - - void stopRumble() { - RawController::header.rumble0 = 0x0; - RawController::header.rumble1 = 0x0; - } - - bool is_small_rumble() const { - return static_cast(RawController::header.rumble0); - } - - uint8_t get_large_rumble() const { - return RawController::header.rumble1; - } - - bool is_connected() const { - return RawController::header.state != RawController::State::Disconnected; - } - - bool is_useable() const { - const auto type = RawController::get_type(); - return ((RawController::header.state == RawController::State::Stable) && (type == ControllerType::Controller || type == ControllerType::DualShock)); - } - }; - - class AnalogeController : public GenericController { - public: - enum struct Button : uint16_t { - L2 = static_cast(GenericButton::D0), - R2 = static_cast(GenericButton::D1), - L1 = static_cast(GenericButton::D2), - R1 = static_cast(GenericButton::D3), - Triangle = static_cast(GenericButton::D4), - Circle = static_cast(GenericButton::D5), - Cross = static_cast(GenericButton::D6), - Square = static_cast(GenericButton::D7), - SEL = static_cast(GenericButton::D8), - L3 = static_cast(GenericButton::D9), - R3 = static_cast(GenericButton::D10), - ST = static_cast(GenericButton::D11), - Up = static_cast(GenericButton::D12), - Right = static_cast(GenericButton::D13), - Down = static_cast(GenericButton::D14), - Left = static_cast(GenericButton::D15) - }; - - private: - uint8_t read_special_byte(size_t idx) const { - return reinterpret_cast(this->special)[idx]; - } - - public: - GPU::PositionI16 get_right_stick_pos() const { - const uint8_t joy_x = AnalogeController::read_special_byte(0); - const uint8_t joy_y = AnalogeController::read_special_byte(1); - - return GPU::PositionI16::create(joy_x - 0x80, joy_y - 0x80); - } - - GPU::PositionI16 get_left_stick_pos() const { - const uint8_t joy_x = AnalogeController::read_special_byte(2); - const uint8_t joy_y = AnalogeController::read_special_byte(3); - - return GPU::PositionI16::create(joy_x - 0x80, joy_y - 0x80); - } - }; - - using GenericButtonState = GenericController::ButtonState; - } +#pragma once +#include "../GPU/gpu_types.hpp" +#include "raw_controller.hpp" + +namespace JabyEngine { + namespace Periphery { + class GenericController : public RawController { + public: + struct Rumble { + static constexpr uint8_t LargeMotorThreshold = 0x60; + }; + + enum struct Button : uint16_t { + L2 = static_cast(GenericButton::D0), + R2 = static_cast(GenericButton::D1), + L1 = static_cast(GenericButton::D2), + R1 = static_cast(GenericButton::D3), + Triangle = static_cast(GenericButton::D4), + Circle = static_cast(GenericButton::D5), + Cross = static_cast(GenericButton::D6), + Square = static_cast(GenericButton::D7), + SEL = static_cast(GenericButton::D8), + ST = static_cast(GenericButton::D11), + Up = static_cast(GenericButton::D12), + Right = static_cast(GenericButton::D13), + Down = static_cast(GenericButton::D14), + Left = static_cast(GenericButton::D15) + }; + + void set_digital_rumble() { + RawController::header.rumble0 = 0x1; + RawController::header.rumble1 = 0x7F; + } + + void set_analog_rumble(uint8_t largeMotor, bool smallMotor) { + RawController::header.rumble0 = smallMotor ? 0x1 : 0x0; + RawController::header.rumble1 = largeMotor; + } + + void stopRumble() { + RawController::header.rumble0 = 0x0; + RawController::header.rumble1 = 0x0; + } + + bool is_small_rumble() const { + return static_cast(RawController::header.rumble0); + } + + uint8_t get_large_rumble() const { + return RawController::header.rumble1; + } + + bool is_connected() const { + return RawController::header.state != RawController::State::Disconnected; + } + + bool is_useable() const { + const auto type = RawController::get_type(); + return ((RawController::header.state == RawController::State::Stable) && (type == ControllerType::Controller || type == ControllerType::DualShock)); + } + }; + + class AnalogeController : public GenericController { + public: + enum struct Button : uint16_t { + L2 = static_cast(GenericButton::D0), + R2 = static_cast(GenericButton::D1), + L1 = static_cast(GenericButton::D2), + R1 = static_cast(GenericButton::D3), + Triangle = static_cast(GenericButton::D4), + Circle = static_cast(GenericButton::D5), + Cross = static_cast(GenericButton::D6), + Square = static_cast(GenericButton::D7), + SEL = static_cast(GenericButton::D8), + L3 = static_cast(GenericButton::D9), + R3 = static_cast(GenericButton::D10), + ST = static_cast(GenericButton::D11), + Up = static_cast(GenericButton::D12), + Right = static_cast(GenericButton::D13), + Down = static_cast(GenericButton::D14), + Left = static_cast(GenericButton::D15) + }; + + private: + uint8_t read_special_byte(size_t idx) const { + return reinterpret_cast(this->special)[idx]; + } + + public: + GPU::PositionI16 get_right_stick_pos() const { + const uint8_t joy_x = AnalogeController::read_special_byte(0); + const uint8_t joy_y = AnalogeController::read_special_byte(1); + + return GPU::PositionI16::create(joy_x - 0x80, joy_y - 0x80); + } + + GPU::PositionI16 get_left_stick_pos() const { + const uint8_t joy_x = AnalogeController::read_special_byte(2); + const uint8_t joy_y = AnalogeController::read_special_byte(3); + + return GPU::PositionI16::create(joy_x - 0x80, joy_y - 0x80); + } + }; + + using GenericButtonState = GenericController::ButtonState; + } } \ No newline at end of file diff --git a/include/PSX/Periphery/periphery.hpp b/include/PSX/Periphery/periphery.hpp index 8cdc7a57..f4aa1bd7 100644 --- a/include/PSX/Periphery/periphery.hpp +++ b/include/PSX/Periphery/periphery.hpp @@ -1,24 +1,24 @@ -#pragma once -#include "../jabyengine_config.hpp" -#include "controller.hpp" - -namespace JabyEngine { - namespace Periphery { - static constexpr uint32_t PortCount = Configuration::Periphery::include_portB() ? 2 : 1; - static constexpr uint32_t DeviceCount = Configuration::Periphery::use_multi_tap() ? 4 : 1; - - extern RawController controller[PortCount][DeviceCount]; - - void query_controller(); - - template - inline T& get_controller_as(size_t port, size_t device) { - return *reinterpret_cast(&controller[port][device]); - } - - template - inline T& get_primary_controller_as() { - return get_controller_as(0, 0); - } - } +#pragma once +#include "../jabyengine_config.hpp" +#include "controller.hpp" + +namespace JabyEngine { + namespace Periphery { + static constexpr uint32_t PortCount = Configuration::Periphery::include_portB() ? 2 : 1; + static constexpr uint32_t DeviceCount = Configuration::Periphery::use_multi_tap() ? 4 : 1; + + extern RawController controller[PortCount][DeviceCount]; + + void query_controller(); + + template + inline T& get_controller_as(size_t port, size_t device) { + return *reinterpret_cast(&controller[port][device]); + } + + template + inline T& get_primary_controller_as() { + return get_controller_as(0, 0); + } + } } \ No newline at end of file diff --git a/include/PSX/Periphery/raw_controller.hpp b/include/PSX/Periphery/raw_controller.hpp index 3d675aee..ad39c41c 100644 --- a/include/PSX/Periphery/raw_controller.hpp +++ b/include/PSX/Periphery/raw_controller.hpp @@ -1,137 +1,137 @@ -#pragma once -#include "../jabyengine_defines.hpp" - -namespace JabyEngine { - namespace Periphery { - enum struct ControllerType : uint8_t { - Unkown = 0x0, - Mouse = 0x1, - NegCon = 0x2, - HyperBlaster = 0x3, // Konami Lightgun - Controller = 0x4, - ArcadeFlightStick = 0x5, - GCon = 0x6, - DualShock = 0x7, - MultiTap = 0x8 - }; - - enum struct GenericButton : uint16_t { - D8 = (1 << 0), - D9 = (1 << 1), - D10 = (1 << 2), - D11 = (1 << 3), - D12 = (1 << 4), - D13 = (1 << 5), - D14 = (1 << 6), - D15 = (1 << 7), - D0 = (1 << 8), - D1 = (1 << 9), - D2 = (1 << 10), - D3 = (1 << 11), - D4 = (1 << 12), - D5 = (1 << 13), - D6 = (1 << 14), - D7 = (1 << 15) - }; - - struct LED { - enum struct State : uint8_t { - Off = 0x0, - On = 0x1 - }; - - enum struct Lock { - Off = 0x2, - On = 0x3 - }; - }; - - class RawController { - public: - enum struct State : uint8_t - { - Disconnected = 0, - EnterConfigMode = (1 << 0), - LockAnalog = (1 << 1), - UnlockRumble = (1 << 2), - ExitConfigMode = (1 << 3), - Stable = (1 << 4) - }; - - protected: - struct Header { - uint8_t type; - State state; - uint8_t rumble0; - uint8_t rumble1; - - void clear() { - this->type = 0; - this->state = State::Disconnected; - } - }; - - public: - class ButtonState { - private: - uint16_t oldState; - uint16_t currentState; - - static bool is_down(uint16_t data, uint16_t button) { - return ((data & button) == 0); - } - - void exchange_state() { - this->oldState = this->currentState; - } - - public: - template - bool is_down(T button) const { - return ButtonState::is_down(this->currentState, static_cast(button)); - } - - template - bool was_down(T button) const { - return ButtonState::is_down(this->oldState, static_cast(button)); - } - - template - bool went_down(T button) const { - return (!ButtonState::was_down(button) && ButtonState::is_down(button)); - } - - template - bool went_up(T button) const { - return (ButtonState::was_down(button) && !ButtonState::is_down(button)); - } - - friend class RawController; - friend struct ControllerHelper; - friend void query_controller(); - }; - - Header header; - ButtonState button; - uint32_t special; - - public: - ControllerType get_type() const { - return static_cast((this->header.type >> 4)); - } - - ButtonState get_button_state() const { - return this->button; - } - - //For debugging only - uint8_t get_raw_type() const { - return this->header.type; - } - - uint16_t get_raw_button_state() const { - return this->button.currentState; - } - }; - } +#pragma once +#include "../jabyengine_defines.hpp" + +namespace JabyEngine { + namespace Periphery { + enum struct ControllerType : uint8_t { + Unkown = 0x0, + Mouse = 0x1, + NegCon = 0x2, + HyperBlaster = 0x3, // Konami Lightgun + Controller = 0x4, + ArcadeFlightStick = 0x5, + GCon = 0x6, + DualShock = 0x7, + MultiTap = 0x8 + }; + + enum struct GenericButton : uint16_t { + D8 = (1 << 0), + D9 = (1 << 1), + D10 = (1 << 2), + D11 = (1 << 3), + D12 = (1 << 4), + D13 = (1 << 5), + D14 = (1 << 6), + D15 = (1 << 7), + D0 = (1 << 8), + D1 = (1 << 9), + D2 = (1 << 10), + D3 = (1 << 11), + D4 = (1 << 12), + D5 = (1 << 13), + D6 = (1 << 14), + D7 = (1 << 15) + }; + + struct LED { + enum struct State : uint8_t { + Off = 0x0, + On = 0x1 + }; + + enum struct Lock { + Off = 0x2, + On = 0x3 + }; + }; + + class RawController { + public: + enum struct State : uint8_t + { + Disconnected = 0, + EnterConfigMode = (1 << 0), + LockAnalog = (1 << 1), + UnlockRumble = (1 << 2), + ExitConfigMode = (1 << 3), + Stable = (1 << 4) + }; + + protected: + struct Header { + uint8_t type; + State state; + uint8_t rumble0; + uint8_t rumble1; + + void clear() { + this->type = 0; + this->state = State::Disconnected; + } + }; + + public: + class ButtonState { + private: + uint16_t oldState; + uint16_t currentState; + + static bool is_down(uint16_t data, uint16_t button) { + return ((data & button) == 0); + } + + void exchange_state() { + this->oldState = this->currentState; + } + + public: + template + bool is_down(T button) const { + return ButtonState::is_down(this->currentState, static_cast(button)); + } + + template + bool was_down(T button) const { + return ButtonState::is_down(this->oldState, static_cast(button)); + } + + template + bool went_down(T button) const { + return (!ButtonState::was_down(button) && ButtonState::is_down(button)); + } + + template + bool went_up(T button) const { + return (ButtonState::was_down(button) && !ButtonState::is_down(button)); + } + + friend class RawController; + friend struct ControllerHelper; + friend void query_controller(); + }; + + Header header; + ButtonState button; + uint32_t special; + + public: + ControllerType get_type() const { + return static_cast((this->header.type >> 4)); + } + + ButtonState get_button_state() const { + return this->button; + } + + //For debugging only + uint8_t get_raw_type() const { + return this->header.type; + } + + uint16_t get_raw_button_state() const { + return this->button.currentState; + } + }; + } } \ No newline at end of file diff --git a/include/PSX/SPU/spu.hpp b/include/PSX/SPU/spu.hpp index 89329e00..d8366dfd 100644 --- a/include/PSX/SPU/spu.hpp +++ b/include/PSX/SPU/spu.hpp @@ -1,51 +1,51 @@ -#pragma once -#include "../System/IOPorts/spu_io.hpp" - -namespace JabyEngine { - namespace SPU { - using SPU_IO_Values::operator""_vol; - - using SRAMAdr = SPU_IO_Values::SRAMAdr; - using SimpleVolume = SPU_IO_Values::SimpleVolume; - using SweepVolume = SPU_IO_Values::SweepVolume; - - struct Voice { - size_t get_id() const { - return reinterpret_cast(this); - } - - SRAMAdr allocate(size_t size); - SRAMAdr allocate(SPU_IO_Values::SampleRate frequency, size_t size); - void deallocate(); - - void set_sample_rate(SPU_IO_Values::SampleRate frequency) { - SPU_IO::Voice[Voice::get_id()].sampleRate.write(frequency); - } - - void set_volume(SimpleVolume left, SimpleVolume right) { - SPU_IO::Voice[Voice::get_id()].volumeLeft.write(SweepVolume::create(left)); - SPU_IO::Voice[Voice::get_id()].volumeRight.write(SweepVolume::create(right)); - } - - void play() { - SPU_IO::Key::On.write(SPU_IO_Values::KeyOn::for_specific(Voice::get_id())); - } - - void play_if_end() { - if(Voice::is_end()) { - Voice::play(); - } - } - - void stop() { - SPU_IO::Key::Off.write(SPU_IO_Values::KeyOff::for_specific(Voice::get_id())); - } - - bool is_end() const { - return SPU_IO::Voice[Voice::get_id()].adsr_volume.read() == SimpleVolume::mute(); - } - }; - - static auto& voice = __declare_io_port_array(Voice, SPU_IO::VoiceCount, 0x0); - } +#pragma once +#include "../System/IOPorts/spu_io.hpp" + +namespace JabyEngine { + namespace SPU { + using SPU_IO_Values::operator""_vol; + + using SRAMAdr = SPU_IO_Values::SRAMAdr; + using SimpleVolume = SPU_IO_Values::SimpleVolume; + using SweepVolume = SPU_IO_Values::SweepVolume; + + struct Voice { + size_t get_id() const { + return reinterpret_cast(this); + } + + SRAMAdr allocate(size_t size); + SRAMAdr allocate(SPU_IO_Values::SampleRate frequency, size_t size); + void deallocate(); + + void set_sample_rate(SPU_IO_Values::SampleRate frequency) { + SPU_IO::Voice[Voice::get_id()].sampleRate.write(frequency); + } + + void set_volume(SimpleVolume left, SimpleVolume right) { + SPU_IO::Voice[Voice::get_id()].volumeLeft.write(SweepVolume::create(left)); + SPU_IO::Voice[Voice::get_id()].volumeRight.write(SweepVolume::create(right)); + } + + void play() { + SPU_IO::Key::On.write(SPU_IO_Values::KeyOn::for_specific(Voice::get_id())); + } + + void play_if_end() { + if(Voice::is_end()) { + Voice::play(); + } + } + + void stop() { + SPU_IO::Key::Off.write(SPU_IO_Values::KeyOff::for_specific(Voice::get_id())); + } + + bool is_end() const { + return SPU_IO::Voice[Voice::get_id()].adsr_volume.read() == SimpleVolume::mute(); + } + }; + + static auto& voice = __declare_io_port_array(Voice, SPU_IO::VoiceCount, 0x0); + } } \ No newline at end of file diff --git a/include/PSX/System/IOPorts/IOValues/cd_io_values.hpp b/include/PSX/System/IOPorts/IOValues/cd_io_values.hpp index f99c160c..d8055667 100644 --- a/include/PSX/System/IOPorts/IOValues/cd_io_values.hpp +++ b/include/PSX/System/IOPorts/IOValues/cd_io_values.hpp @@ -1,106 +1,106 @@ -#pragma once -#include "ioport.hpp" - -namespace JabyEngine { - namespace CD_IO_Values { - __declare_io_struct(AudioVolumeApply, uint8_t) { - static constexpr auto Mute = Bit(0); - static constexpr auto ApplyChanges = Bit(5); - }; - - struct CDDAVolume { - using Type = uint8_t; - - static constexpr uint8_t Off = 0x0; - static constexpr uint8_t Default = 0x80; - static constexpr uint8_t Max = 0xFF; - }; - - __declare_io_struct(CommandFifo, uint8_t) { - }; - - __declare_io_struct(DataFifo, uint8_t) { - }; - - __declare_io_struct(DataFifo16, uint16_t) { - }; - - __declare_io_struct(InterruptEnable, uint8_t) { - static constexpr auto InterruptTypValue = BitRange::from_to(0, 2); - static constexpr auto InterruptExtended = BitRange::from_to(0, 4); - static constexpr auto UnknownIRQ = Bit(3); - static constexpr auto CommandStartIRQ = Bit(4); - }; - using InterruptFlag = InterruptEnable; - - __declare_io_struct(IndexStatus, uint8_t) { - static constexpr auto PortIndex = BitRange::from_to(0, 1); - static constexpr auto HasXAFifoData = Bit(2); - static constexpr auto IsParameterFifoEmpty = Bit(3); - static constexpr auto HasParameterFifoSpace = Bit(4); - static constexpr auto HasResponseFifoData = Bit(5); - static constexpr auto HasDataFifoData = Bit(6); - static constexpr auto IsTransmissionBusy = Bit(7); - }; - - __declare_io_struct(LeftCD2LeftSPU, CDDAVolume::Type) { - }; - - __declare_io_struct(LeftCD2RightSPU, CDDAVolume::Type) { - }; - - __declare_io_struct(Mode, uint8_t) { - static constexpr auto DoubleSpeed = Bit(7); - static constexpr auto SingleSpeed = !DoubleSpeed; - static constexpr auto XADPCM = Bit(6); - static constexpr auto WholeSector = Bit(5); - static constexpr auto DataSector = !WholeSector; - static constexpr auto UseXAFilter = Bit(3); - static constexpr auto AudioPlayIRQ = Bit(2); - static constexpr auto AutoPauseTrack = Bit(1); - static constexpr auto CDDA = Bit(0); - - operator uint8_t() const { - return this->raw; - } - }; - - __declare_io_struct(ParameterFifo, uint8_t) { - }; - - __declare_io_struct(Request, uint8_t) { - static constexpr auto WantCommandStartIRQ = Bit(5); - static constexpr auto WantData = Bit(7); - - static Request want_data() { - return Request{static_cast(Request::WantData)}; - } - - static Request reset() { - return Request{0}; - } - }; - - __declare_io_struct(ResponseFifo, uint8_t) { - }; - - __declare_io_struct(RightCD2LeftSPU, CDDAVolume::Type) { - }; - - __declare_io_struct(RightCD2RightSPU, CDDAVolume::Type) { - }; - - __declare_io_struct(SoundMapCoding, uint8_t) { - static constexpr auto Stereo = Bit(0); - static constexpr auto Mono = !Stereo; - static constexpr auto SampleRate_18900hz = Bit(2); - static constexpr auto SampleRate_37800hz = !SampleRate_18900hz; - static constexpr auto BitsPerSample8 = Bit(4); - static constexpr auto BitsPerSample4 = !BitsPerSample8; - static constexpr auto Emphasis = Bit(6); - }; - - __declare_io_struct(SoundMapDataOut, uint8_t) { - }; - } +#pragma once +#include "ioport.hpp" + +namespace JabyEngine { + namespace CD_IO_Values { + __declare_io_struct(AudioVolumeApply, uint8_t) { + static constexpr auto Mute = Bit(0); + static constexpr auto ApplyChanges = Bit(5); + }; + + struct CDDAVolume { + using Type = uint8_t; + + static constexpr uint8_t Off = 0x0; + static constexpr uint8_t Default = 0x80; + static constexpr uint8_t Max = 0xFF; + }; + + __declare_io_struct(CommandFifo, uint8_t) { + }; + + __declare_io_struct(DataFifo, uint8_t) { + }; + + __declare_io_struct(DataFifo16, uint16_t) { + }; + + __declare_io_struct(InterruptEnable, uint8_t) { + static constexpr auto InterruptTypValue = BitRange::from_to(0, 2); + static constexpr auto InterruptExtended = BitRange::from_to(0, 4); + static constexpr auto UnknownIRQ = Bit(3); + static constexpr auto CommandStartIRQ = Bit(4); + }; + using InterruptFlag = InterruptEnable; + + __declare_io_struct(IndexStatus, uint8_t) { + static constexpr auto PortIndex = BitRange::from_to(0, 1); + static constexpr auto HasXAFifoData = Bit(2); + static constexpr auto IsParameterFifoEmpty = Bit(3); + static constexpr auto HasParameterFifoSpace = Bit(4); + static constexpr auto HasResponseFifoData = Bit(5); + static constexpr auto HasDataFifoData = Bit(6); + static constexpr auto IsTransmissionBusy = Bit(7); + }; + + __declare_io_struct(LeftCD2LeftSPU, CDDAVolume::Type) { + }; + + __declare_io_struct(LeftCD2RightSPU, CDDAVolume::Type) { + }; + + __declare_io_struct(Mode, uint8_t) { + static constexpr auto DoubleSpeed = Bit(7); + static constexpr auto SingleSpeed = !DoubleSpeed; + static constexpr auto XADPCM = Bit(6); + static constexpr auto WholeSector = Bit(5); + static constexpr auto DataSector = !WholeSector; + static constexpr auto UseXAFilter = Bit(3); + static constexpr auto AudioPlayIRQ = Bit(2); + static constexpr auto AutoPauseTrack = Bit(1); + static constexpr auto CDDA = Bit(0); + + operator uint8_t() const { + return this->raw; + } + }; + + __declare_io_struct(ParameterFifo, uint8_t) { + }; + + __declare_io_struct(Request, uint8_t) { + static constexpr auto WantCommandStartIRQ = Bit(5); + static constexpr auto WantData = Bit(7); + + static Request want_data() { + return Request{static_cast(Request::WantData)}; + } + + static Request reset() { + return Request{0}; + } + }; + + __declare_io_struct(ResponseFifo, uint8_t) { + }; + + __declare_io_struct(RightCD2LeftSPU, CDDAVolume::Type) { + }; + + __declare_io_struct(RightCD2RightSPU, CDDAVolume::Type) { + }; + + __declare_io_struct(SoundMapCoding, uint8_t) { + static constexpr auto Stereo = Bit(0); + static constexpr auto Mono = !Stereo; + static constexpr auto SampleRate_18900hz = Bit(2); + static constexpr auto SampleRate_37800hz = !SampleRate_18900hz; + static constexpr auto BitsPerSample8 = Bit(4); + static constexpr auto BitsPerSample4 = !BitsPerSample8; + static constexpr auto Emphasis = Bit(6); + }; + + __declare_io_struct(SoundMapDataOut, uint8_t) { + }; + } } \ No newline at end of file diff --git a/include/PSX/System/IOPorts/IOValues/dma_io_values.hpp b/include/PSX/System/IOPorts/IOValues/dma_io_values.hpp index 78b5cfb5..d9726f8f 100644 --- a/include/PSX/System/IOPorts/IOValues/dma_io_values.hpp +++ b/include/PSX/System/IOPorts/IOValues/dma_io_values.hpp @@ -1,152 +1,152 @@ -#pragma once -#include "ioport.hpp" - -namespace JabyEngine { - namespace DMA_IO_Values { - using Priority = uint32_t; - static constexpr Priority HighestPriority = 0; - static constexpr Priority LowestPriority = 7; - - __declare_io_struct(BCR, uint32_t) { - struct SyncMode0 { - static constexpr auto NumberOfWords = BitRange::from_to(0, 15); - static constexpr auto CD_OneBlock = Bit(16); - - static constexpr BCR for_cd(size_t words) { - return BCR::from(SyncMode0::CD_OneBlock, SyncMode0::NumberOfWords.with(words)); - } - }; - - struct SyncMode1 { - static constexpr auto BlockSize = BitRange::from_to(0, 15); - static constexpr auto BlockAmount = BitRange::from_to(16, 31); - }; - - struct SyncMode2 { - static constexpr BCR for_gpu_cmd() { - return {0}; - } - }; - }; - - __declare_io_struct(CHCHR, uint32_t) { - enum SyncMode_t { - Sync0 = 0, //Start immediately, - Sync1 = 1, //Sync blocks to DMA requests - Sync2 = 2, //Linked List - }; - - static constexpr auto ManualStart = Bit(28); - - static constexpr auto Start = Bit(24); - static constexpr auto Busy = Start; - - static constexpr auto ChoppingCPUWindowSize = BitRange::from_to(20, 22); - static constexpr auto ChoppingDMAWindowSize = BitRange::from_to(16, 18); - - static constexpr auto SyncMode = BitRange::from_to(9, 10); - static constexpr auto UseSyncMode0 = SyncMode.with(Sync0); - static constexpr auto UseSyncMode1 = SyncMode.with(Sync1); - static constexpr auto UseSyncMode2 = SyncMode.with(Sync2); - - static constexpr auto UseChopping = Bit(8); - - static constexpr auto MemoryAdrDecreaseBy4 = Bit(1); - static constexpr auto MemoryAdrIncreaseBy4 = !MemoryAdrDecreaseBy4; - - static constexpr auto FromMainRAM = Bit(0); - static constexpr auto ToMainRAM = !FromMainRAM; - - static constexpr CHCHR StartMDECin() { - return CHCHR{0x01000201}; - } - - static constexpr CHCHR StartMDECout() { - return CHCHR{0x01000200}; - } - - static constexpr CHCHR StartGPUReceive() { - return CHCHR{0x01000201}; - } - - static constexpr CHCHR StartGPULinked() { - return CHCHR{0x01000401}; - } - - static constexpr CHCHR StartCDROM() { - return CHCHR{0x11000000}; - } - - static constexpr CHCHR StartSPUReceive() { - return CHCHR{0x01000201}; - } - - static constexpr CHCHR StartOTC() { - return CHCHR{0x11000002}; - } - }; - - __declare_io_struct(DICR, uint32_t) { - static constexpr auto MasterEnable = Bit(31); - static constexpr auto Flags = BitRange::from_to(24, 30); - static constexpr auto MasterEnableDPCR = Bit(23); - static constexpr auto EnableDPCR = BitRange::from_to(16, 22); - static constexpr auto ForceIRQ = Bit(15); - - static constexpr DICR empty() { - return DICR{0}; - } - }; - - __declare_io_struct(DPCR, uint32_t) { - struct DMASetting { - uint16_t master_bit; - - static constexpr DMASetting create(uint16_t master_bit) { - return DMASetting{master_bit}; - } - - constexpr BitRange::RangeValuePair turn_on(uint8_t priority) const { - return BitRange::from_to(this->master_bit - 3, this->master_bit).with(static_cast(0b1000 + (priority & 0b111))); - } - - constexpr ClearBit turn_off() const { - return ClearBit(this->master_bit); - } - }; - - static constexpr const auto OTC = DMASetting(27); - static constexpr const auto PIO = DMASetting(23); - static constexpr const auto SPU = DMASetting(19); - static constexpr const auto CDROM = DMASetting(15); - static constexpr const auto GPU = DMASetting(11); - static constexpr const auto MDEC_Out = DMASetting(7); - static constexpr const auto MDEC_In = DMASetting(3); - - static constexpr auto OTCEnabled = Bit(27); - static constexpr auto OTCPriority = BitRange::from_to(24, 26); - - static constexpr auto PIOEnabled = Bit(23); - static constexpr auto PIOPriority = BitRange::from_to(20, 22); - - static constexpr auto SPUEnabled = Bit(19); - static constexpr auto SPUPriority = BitRange::from_to(16, 18); - - static constexpr auto CDROMEnabled = Bit(15); - static constexpr auto CDROMPriority = BitRange::from_to(12, 14); - - static constexpr auto GPUEnabled = Bit(11); - static constexpr auto GPUPriority = BitRange::from_to(8, 10); - - static constexpr auto MDECoutEnabled = Bit(7); - static constexpr auto MDECoutPriority = BitRange::from_to(4, 6); - - static constexpr auto MDECinEnabled = Bit(3); - static constexpr auto MDECinPriority = BitRange::from_to(0, 2); - }; - - __declare_io_struct(MADR, uint32_t) { - static constexpr auto MemoryAdr = BitRange::from_to(0, 23); - }; - } +#pragma once +#include "ioport.hpp" + +namespace JabyEngine { + namespace DMA_IO_Values { + using Priority = uint32_t; + static constexpr Priority HighestPriority = 0; + static constexpr Priority LowestPriority = 7; + + __declare_io_struct(BCR, uint32_t) { + struct SyncMode0 { + static constexpr auto NumberOfWords = BitRange::from_to(0, 15); + static constexpr auto CD_OneBlock = Bit(16); + + static constexpr BCR for_cd(size_t words) { + return BCR::from(SyncMode0::CD_OneBlock, SyncMode0::NumberOfWords.with(words)); + } + }; + + struct SyncMode1 { + static constexpr auto BlockSize = BitRange::from_to(0, 15); + static constexpr auto BlockAmount = BitRange::from_to(16, 31); + }; + + struct SyncMode2 { + static constexpr BCR for_gpu_cmd() { + return {0}; + } + }; + }; + + __declare_io_struct(CHCHR, uint32_t) { + enum SyncMode_t { + Sync0 = 0, //Start immediately, + Sync1 = 1, //Sync blocks to DMA requests + Sync2 = 2, //Linked List + }; + + static constexpr auto ManualStart = Bit(28); + + static constexpr auto Start = Bit(24); + static constexpr auto Busy = Start; + + static constexpr auto ChoppingCPUWindowSize = BitRange::from_to(20, 22); + static constexpr auto ChoppingDMAWindowSize = BitRange::from_to(16, 18); + + static constexpr auto SyncMode = BitRange::from_to(9, 10); + static constexpr auto UseSyncMode0 = SyncMode.with(Sync0); + static constexpr auto UseSyncMode1 = SyncMode.with(Sync1); + static constexpr auto UseSyncMode2 = SyncMode.with(Sync2); + + static constexpr auto UseChopping = Bit(8); + + static constexpr auto MemoryAdrDecreaseBy4 = Bit(1); + static constexpr auto MemoryAdrIncreaseBy4 = !MemoryAdrDecreaseBy4; + + static constexpr auto FromMainRAM = Bit(0); + static constexpr auto ToMainRAM = !FromMainRAM; + + static constexpr CHCHR StartMDECin() { + return CHCHR{0x01000201}; + } + + static constexpr CHCHR StartMDECout() { + return CHCHR{0x01000200}; + } + + static constexpr CHCHR StartGPUReceive() { + return CHCHR{0x01000201}; + } + + static constexpr CHCHR StartGPULinked() { + return CHCHR{0x01000401}; + } + + static constexpr CHCHR StartCDROM() { + return CHCHR{0x11000000}; + } + + static constexpr CHCHR StartSPUReceive() { + return CHCHR{0x01000201}; + } + + static constexpr CHCHR StartOTC() { + return CHCHR{0x11000002}; + } + }; + + __declare_io_struct(DICR, uint32_t) { + static constexpr auto MasterEnable = Bit(31); + static constexpr auto Flags = BitRange::from_to(24, 30); + static constexpr auto MasterEnableDPCR = Bit(23); + static constexpr auto EnableDPCR = BitRange::from_to(16, 22); + static constexpr auto ForceIRQ = Bit(15); + + static constexpr DICR empty() { + return DICR{0}; + } + }; + + __declare_io_struct(DPCR, uint32_t) { + struct DMASetting { + uint16_t master_bit; + + static constexpr DMASetting create(uint16_t master_bit) { + return DMASetting{master_bit}; + } + + constexpr BitRange::RangeValuePair turn_on(uint8_t priority) const { + return BitRange::from_to(this->master_bit - 3, this->master_bit).with(static_cast(0b1000 + (priority & 0b111))); + } + + constexpr ClearBit turn_off() const { + return ClearBit(this->master_bit); + } + }; + + static constexpr const auto OTC = DMASetting(27); + static constexpr const auto PIO = DMASetting(23); + static constexpr const auto SPU = DMASetting(19); + static constexpr const auto CDROM = DMASetting(15); + static constexpr const auto GPU = DMASetting(11); + static constexpr const auto MDEC_Out = DMASetting(7); + static constexpr const auto MDEC_In = DMASetting(3); + + static constexpr auto OTCEnabled = Bit(27); + static constexpr auto OTCPriority = BitRange::from_to(24, 26); + + static constexpr auto PIOEnabled = Bit(23); + static constexpr auto PIOPriority = BitRange::from_to(20, 22); + + static constexpr auto SPUEnabled = Bit(19); + static constexpr auto SPUPriority = BitRange::from_to(16, 18); + + static constexpr auto CDROMEnabled = Bit(15); + static constexpr auto CDROMPriority = BitRange::from_to(12, 14); + + static constexpr auto GPUEnabled = Bit(11); + static constexpr auto GPUPriority = BitRange::from_to(8, 10); + + static constexpr auto MDECoutEnabled = Bit(7); + static constexpr auto MDECoutPriority = BitRange::from_to(4, 6); + + static constexpr auto MDECinEnabled = Bit(3); + static constexpr auto MDECinPriority = BitRange::from_to(0, 2); + }; + + __declare_io_struct(MADR, uint32_t) { + static constexpr auto MemoryAdr = BitRange::from_to(0, 23); + }; + } } \ No newline at end of file diff --git a/include/PSX/System/IOPorts/IOValues/gpu_io_values.hpp b/include/PSX/System/IOPorts/IOValues/gpu_io_values.hpp index c015b2b5..41894655 100644 --- a/include/PSX/System/IOPorts/IOValues/gpu_io_values.hpp +++ b/include/PSX/System/IOPorts/IOValues/gpu_io_values.hpp @@ -1,220 +1,220 @@ -#pragma once -#include "../../../GPU/gpu_types.hpp" -#include "ioport.hpp" - -namespace JabyEngine { - namespace GPU_IO_Values { - namespace internal { - template - static constexpr T construct_cmd(uint32_t cmd, uint32_t value) { - return T::from(T::ID.with(cmd), T::Value.with(value)); - } - } - - __declare_io_struct(DisplayMode, uint32_t) { - enum AreaColorDepth { - $15bit = 0, - $24bit = 1, - }; - - enum State { - On = 0, - Off = 1 - }; - - enum HorizontalResolution { - $256 = 0, - $320 = 1, - $512 = 2, - $640 = 3, - }; - - enum struct TVEncoding { - NTSC = 0, - PAL = 1, - }; - - enum VerticalResolution { - $240 = 0, - $480 = 1 - }; - - static constexpr auto HorizontalResolution368 = Bit(6); - static constexpr auto VerticalInterlace = Bit(5); - static constexpr auto DisplayAreaColorDepth = BitRange::from_to(4, 4); - static constexpr auto VideoMode = BitRange::from_to(3, 3); - static constexpr auto VerticalResolution = BitRange::from_to(2, 2); - static constexpr auto HorizontalResolution = BitRange::from_to(0, 1); - - static constexpr DisplayMode PAL() { - return DisplayMode::from( - HorizontalResolution.with(HorizontalResolution::$320), - VerticalResolution.with(VerticalResolution::$240), - VideoMode.with(TVEncoding::PAL), - DisplayAreaColorDepth.with(AreaColorDepth::$15bit) - ); - } - - static constexpr DisplayMode NTSC() { - return DisplayMode::from( - HorizontalResolution.with(HorizontalResolution::$320), - VerticalResolution.with(VerticalResolution::$240), - VideoMode.with(TVEncoding::NTSC), - DisplayAreaColorDepth.with(AreaColorDepth::$15bit) - ); - } - }; - - __declare_io_struct(GPUREAD, uint32_t) { - }; - - __declare_io_struct(GPUSTAT, uint32_t) { - enum DMADirection { - Off = 0, - Fifo = 1, - CPU2GPU = 2, - GPU2CPU = 3, - }; - - static constexpr auto DrawingOddLinesInterlaced = Bit(31); - static constexpr auto DMADirectionValue = BitRange::from_to(29, 30); - static constexpr auto DMAReady = Bit(28); - static constexpr auto VRAMtoCPUtransferReay = Bit(27); - static constexpr auto GP0ReadyForCMD = Bit(26); - static constexpr auto FifoNotFull = Bit(25); // Only for Fifo - static constexpr auto InterruptRequest = Bit(24); - static constexpr auto DisplayDisabled = Bit(23); - static constexpr auto VerticalInterlaceOn = Bit(22); - static constexpr auto DisplayAreaColorDepth = BitRange::from_to(21, 21); - static constexpr auto VideoModePal = Bit(20); - static constexpr auto VerticalResolutionValue = BitRange::from_to(19, 19); - static constexpr auto HorizontalResolutionValue = BitRange::from_to(17, 18); - static constexpr auto HorizontalResolution368 = Bit(16); - static constexpr auto TexturesDisabled = Bit(15); - static constexpr auto NotDrawingMaskedPixels = Bit(12); - static constexpr auto MaskBitSetDuringDrawEnabled = Bit(11); - static constexpr auto DrawingToDisplayAreadAllowed = Bit(10); - static constexpr auto DitherEnabled = Bit(9); - static constexpr auto TexturePageColorValue = BitRange::from_to(7, 8); - static constexpr auto SemiTransparencyValue = BitRange::from_to(5, 6); - static constexpr auto TexturePageY = BitRange::from_to(4, 4); // N*256 - static constexpr auto TexturePageX = BitRange::from_to(0, 3); // N*64 - - static constexpr auto VerticalResolution480 = Bit(19); - static constexpr auto TexturePageY256 = Bit(4); - }; - - __declare_io_struct(GP0, uint32_t) { - static constexpr auto ID = BitRange::from_to(24, 31); - static constexpr auto Value = BitRange::from_to(0, 23); - - static constexpr GP0 DrawAreaTemplate(uint8_t code, uint16_t x, uint16_t y) { - constexpr auto Command = BitRange::from_to(24, 31); - constexpr auto Y = BitRange::from_to(10, 18); - constexpr auto X = BitRange::from_to(0, 9); - - return internal::construct_cmd(code, Y.as_value(static_cast(y)) | X.as_value(static_cast(x))); - } - - static constexpr GP0 ClearCache() { - return internal::construct_cmd(0x01, 0x0); - } - - static constexpr GP0 QuickFill(GPU::Color24 color) { - return internal::construct_cmd(0x02, color.raw()); - } - - static constexpr GP0 VRAM2VRAMBlitting() { - return internal::construct_cmd(0x80, 0); - } - - static constexpr GP0 CPU2VRAMBlitting() { - return internal::construct_cmd(0xA0, 0); - } - - static constexpr GP0 TexPage(const GPU::PositionU16& page_pos, GPU::SemiTransparency transparency, GPU::TextureColorMode tex_color, bool dither, bool draw_on_display_area) { - constexpr auto TexXRange = BitRange::from_to(0, 3); - constexpr auto TexYRange = BitRange::from_to(4, 4); - constexpr auto TransparencyRange = BitRange::from_to(5, 6); - constexpr auto TextureColorRange = BitRange::from_to(7, 8); - constexpr auto DitherBit = BitRange::from_to(9, 9); - constexpr auto DrawOnDisplayAreaBit = BitRange::from_to(10, 10); - - return internal::construct_cmd(0xE1, - TexXRange.as_value(page_pos.x >> 6) | TexYRange.as_value(page_pos.y >> 8) | - TransparencyRange.as_value(static_cast(transparency)) | TextureColorRange.as_value(static_cast(tex_color)) | - DitherBit.as_value(static_cast(dither)) | DrawOnDisplayAreaBit.as_value(static_cast(draw_on_display_area)) - ); - } - - static constexpr GP0 DrawAreaTopLeft(const GPU::PositionU16& position) { - return GP0::DrawAreaTemplate(0xE3, position.x, position.y); - } - - static constexpr GP0 DrawAreaBottomRight(const GPU::PositionU16& position) { - return GP0::DrawAreaTemplate(0xE4, position.x, position.y); - } - - static constexpr GP0 DrawOffset(const GPU::PositionI16& offset) { - constexpr auto X = BitRange::from_to(0, 10); - constexpr auto Y = BitRange::from_to(11, 21); - - return internal::construct_cmd(0xE5, X.as_value(static_cast(offset.x)) | Y.as_value(static_cast(offset.y))); - } - - static constexpr GP0 PostionTopLeft(const GPU::PositionU16& position) { - return GP0{(static_cast(position.y) << 16u) | position.x}; - } - - static constexpr GP0 WidthHeight(const GPU::SizeU16& size) { - return GP0{(static_cast(size.height) << 16u) | size.width}; - } - }; - - __declare_io_struct(GP1, uint32_t) { - static constexpr auto ID = BitRange::from_to(24, 31); - static constexpr auto Value = BitRange::from_to(0, 23); - - static constexpr GP1 Reset() { - return GP1{0}; - } - - static constexpr GP1 ResetCMDBuffer() { - return internal::construct_cmd(0x01, 0); - } - - static constexpr GP1 DisplayState(DisplayMode::State state) { - return internal::construct_cmd(0x03, static_cast(state)); - } - - static constexpr GP1 DMADirection(GPUSTAT::DMADirection dir) { - return internal::construct_cmd(0x04, dir); - } - - static constexpr GP1 DisplayArea(const GPU::PositionU16& position) { - constexpr auto X = BitRange::from_to(0, 9); - constexpr auto Y = BitRange::from_to(10, 18); - - return internal::construct_cmd(0x05, X.as_value(static_cast(position.x)) | Y.as_value(static_cast(position.y))); - } - - static constexpr GP1 HorizontalDisplayRange(uint16_t x1, uint16_t x2) { - constexpr auto X1 = BitRange::from_to(0, 11); - constexpr auto X2 = BitRange::from_to(12, 23); - - return internal::construct_cmd(0x06, X1.as_value(static_cast(x1)) | X2.as_value(static_cast(x2))); - } - - static constexpr GP1 VerticalDisplayRange(uint16_t y1, uint16_t y2) { - constexpr auto Y1 = BitRange::from_to(0, 9); - constexpr auto Y2 = BitRange::from_to(10, 19); - - return internal::construct_cmd(0x07, Y1.as_value(static_cast(y1)) | Y2.as_value(static_cast(y2))); - } - - static constexpr GP1 DisplayMode(GPU_IO_Values::DisplayMode mode) { - return internal::construct_cmd(0x08, mode.raw); - } - }; - } +#pragma once +#include "../../../GPU/gpu_types.hpp" +#include "ioport.hpp" + +namespace JabyEngine { + namespace GPU_IO_Values { + namespace internal { + template + static constexpr T construct_cmd(uint32_t cmd, uint32_t value) { + return T::from(T::ID.with(cmd), T::Value.with(value)); + } + } + + __declare_io_struct(DisplayMode, uint32_t) { + enum AreaColorDepth { + $15bit = 0, + $24bit = 1, + }; + + enum State { + On = 0, + Off = 1 + }; + + enum HorizontalResolution { + $256 = 0, + $320 = 1, + $512 = 2, + $640 = 3, + }; + + enum struct TVEncoding { + NTSC = 0, + PAL = 1, + }; + + enum VerticalResolution { + $240 = 0, + $480 = 1 + }; + + static constexpr auto HorizontalResolution368 = Bit(6); + static constexpr auto VerticalInterlace = Bit(5); + static constexpr auto DisplayAreaColorDepth = BitRange::from_to(4, 4); + static constexpr auto VideoMode = BitRange::from_to(3, 3); + static constexpr auto VerticalResolution = BitRange::from_to(2, 2); + static constexpr auto HorizontalResolution = BitRange::from_to(0, 1); + + static constexpr DisplayMode PAL() { + return DisplayMode::from( + HorizontalResolution.with(HorizontalResolution::$320), + VerticalResolution.with(VerticalResolution::$240), + VideoMode.with(TVEncoding::PAL), + DisplayAreaColorDepth.with(AreaColorDepth::$15bit) + ); + } + + static constexpr DisplayMode NTSC() { + return DisplayMode::from( + HorizontalResolution.with(HorizontalResolution::$320), + VerticalResolution.with(VerticalResolution::$240), + VideoMode.with(TVEncoding::NTSC), + DisplayAreaColorDepth.with(AreaColorDepth::$15bit) + ); + } + }; + + __declare_io_struct(GPUREAD, uint32_t) { + }; + + __declare_io_struct(GPUSTAT, uint32_t) { + enum DMADirection { + Off = 0, + Fifo = 1, + CPU2GPU = 2, + GPU2CPU = 3, + }; + + static constexpr auto DrawingOddLinesInterlaced = Bit(31); + static constexpr auto DMADirectionValue = BitRange::from_to(29, 30); + static constexpr auto DMAReady = Bit(28); + static constexpr auto VRAMtoCPUtransferReay = Bit(27); + static constexpr auto GP0ReadyForCMD = Bit(26); + static constexpr auto FifoNotFull = Bit(25); // Only for Fifo + static constexpr auto InterruptRequest = Bit(24); + static constexpr auto DisplayDisabled = Bit(23); + static constexpr auto VerticalInterlaceOn = Bit(22); + static constexpr auto DisplayAreaColorDepth = BitRange::from_to(21, 21); + static constexpr auto VideoModePal = Bit(20); + static constexpr auto VerticalResolutionValue = BitRange::from_to(19, 19); + static constexpr auto HorizontalResolutionValue = BitRange::from_to(17, 18); + static constexpr auto HorizontalResolution368 = Bit(16); + static constexpr auto TexturesDisabled = Bit(15); + static constexpr auto NotDrawingMaskedPixels = Bit(12); + static constexpr auto MaskBitSetDuringDrawEnabled = Bit(11); + static constexpr auto DrawingToDisplayAreadAllowed = Bit(10); + static constexpr auto DitherEnabled = Bit(9); + static constexpr auto TexturePageColorValue = BitRange::from_to(7, 8); + static constexpr auto SemiTransparencyValue = BitRange::from_to(5, 6); + static constexpr auto TexturePageY = BitRange::from_to(4, 4); // N*256 + static constexpr auto TexturePageX = BitRange::from_to(0, 3); // N*64 + + static constexpr auto VerticalResolution480 = Bit(19); + static constexpr auto TexturePageY256 = Bit(4); + }; + + __declare_io_struct(GP0, uint32_t) { + static constexpr auto ID = BitRange::from_to(24, 31); + static constexpr auto Value = BitRange::from_to(0, 23); + + static constexpr GP0 DrawAreaTemplate(uint8_t code, uint16_t x, uint16_t y) { + constexpr auto Command = BitRange::from_to(24, 31); + constexpr auto Y = BitRange::from_to(10, 18); + constexpr auto X = BitRange::from_to(0, 9); + + return internal::construct_cmd(code, Y.as_value(static_cast(y)) | X.as_value(static_cast(x))); + } + + static constexpr GP0 ClearCache() { + return internal::construct_cmd(0x01, 0x0); + } + + static constexpr GP0 QuickFill(GPU::Color24 color) { + return internal::construct_cmd(0x02, color.raw()); + } + + static constexpr GP0 VRAM2VRAMBlitting() { + return internal::construct_cmd(0x80, 0); + } + + static constexpr GP0 CPU2VRAMBlitting() { + return internal::construct_cmd(0xA0, 0); + } + + static constexpr GP0 TexPage(const GPU::PositionU16& page_pos, GPU::SemiTransparency transparency, GPU::TextureColorMode tex_color, bool dither, bool draw_on_display_area) { + constexpr auto TexXRange = BitRange::from_to(0, 3); + constexpr auto TexYRange = BitRange::from_to(4, 4); + constexpr auto TransparencyRange = BitRange::from_to(5, 6); + constexpr auto TextureColorRange = BitRange::from_to(7, 8); + constexpr auto DitherBit = BitRange::from_to(9, 9); + constexpr auto DrawOnDisplayAreaBit = BitRange::from_to(10, 10); + + return internal::construct_cmd(0xE1, + TexXRange.as_value(page_pos.x >> 6) | TexYRange.as_value(page_pos.y >> 8) | + TransparencyRange.as_value(static_cast(transparency)) | TextureColorRange.as_value(static_cast(tex_color)) | + DitherBit.as_value(static_cast(dither)) | DrawOnDisplayAreaBit.as_value(static_cast(draw_on_display_area)) + ); + } + + static constexpr GP0 DrawAreaTopLeft(const GPU::PositionU16& position) { + return GP0::DrawAreaTemplate(0xE3, position.x, position.y); + } + + static constexpr GP0 DrawAreaBottomRight(const GPU::PositionU16& position) { + return GP0::DrawAreaTemplate(0xE4, position.x, position.y); + } + + static constexpr GP0 DrawOffset(const GPU::PositionI16& offset) { + constexpr auto X = BitRange::from_to(0, 10); + constexpr auto Y = BitRange::from_to(11, 21); + + return internal::construct_cmd(0xE5, X.as_value(static_cast(offset.x)) | Y.as_value(static_cast(offset.y))); + } + + static constexpr GP0 PostionTopLeft(const GPU::PositionU16& position) { + return GP0{(static_cast(position.y) << 16u) | position.x}; + } + + static constexpr GP0 WidthHeight(const GPU::SizeU16& size) { + return GP0{(static_cast(size.height) << 16u) | size.width}; + } + }; + + __declare_io_struct(GP1, uint32_t) { + static constexpr auto ID = BitRange::from_to(24, 31); + static constexpr auto Value = BitRange::from_to(0, 23); + + static constexpr GP1 Reset() { + return GP1{0}; + } + + static constexpr GP1 ResetCMDBuffer() { + return internal::construct_cmd(0x01, 0); + } + + static constexpr GP1 DisplayState(DisplayMode::State state) { + return internal::construct_cmd(0x03, static_cast(state)); + } + + static constexpr GP1 DMADirection(GPUSTAT::DMADirection dir) { + return internal::construct_cmd(0x04, dir); + } + + static constexpr GP1 DisplayArea(const GPU::PositionU16& position) { + constexpr auto X = BitRange::from_to(0, 9); + constexpr auto Y = BitRange::from_to(10, 18); + + return internal::construct_cmd(0x05, X.as_value(static_cast(position.x)) | Y.as_value(static_cast(position.y))); + } + + static constexpr GP1 HorizontalDisplayRange(uint16_t x1, uint16_t x2) { + constexpr auto X1 = BitRange::from_to(0, 11); + constexpr auto X2 = BitRange::from_to(12, 23); + + return internal::construct_cmd(0x06, X1.as_value(static_cast(x1)) | X2.as_value(static_cast(x2))); + } + + static constexpr GP1 VerticalDisplayRange(uint16_t y1, uint16_t y2) { + constexpr auto Y1 = BitRange::from_to(0, 9); + constexpr auto Y2 = BitRange::from_to(10, 19); + + return internal::construct_cmd(0x07, Y1.as_value(static_cast(y1)) | Y2.as_value(static_cast(y2))); + } + + static constexpr GP1 DisplayMode(GPU_IO_Values::DisplayMode mode) { + return internal::construct_cmd(0x08, mode.raw); + } + }; + } } \ No newline at end of file diff --git a/include/PSX/System/IOPorts/IOValues/interrupt_io_values.hpp b/include/PSX/System/IOPorts/IOValues/interrupt_io_values.hpp index 549d1b9d..11db75e3 100644 --- a/include/PSX/System/IOPorts/IOValues/interrupt_io_values.hpp +++ b/include/PSX/System/IOPorts/IOValues/interrupt_io_values.hpp @@ -1,12 +1,12 @@ -#pragma once -#include "ioport.hpp" - -namespace JabyEngine { - namespace Interrupt_IO_Values { - __declare_io_struct(Mask, uint32_t) { - }; - - __declare_io_struct(Status, uint32_t) { - }; - } +#pragma once +#include "ioport.hpp" + +namespace JabyEngine { + namespace Interrupt_IO_Values { + __declare_io_struct(Mask, uint32_t) { + }; + + __declare_io_struct(Status, uint32_t) { + }; + } } \ No newline at end of file diff --git a/include/PSX/System/IOPorts/IOValues/ioport.hpp b/include/PSX/System/IOPorts/IOValues/ioport.hpp index aa72cc49..55bca5b8 100644 --- a/include/PSX/System/IOPorts/IOValues/ioport.hpp +++ b/include/PSX/System/IOPorts/IOValues/ioport.hpp @@ -1,118 +1,118 @@ -#pragma once -#include "../../../Auxiliary/types.hpp" -#include "../../../Auxiliary/bits.hpp" - -namespace JabyEngine { - namespace IOAdress { - constexpr uintptr_t patch_adr(uintptr_t adr) { - constexpr uintptr_t Mask = 0xF0000000; - constexpr uintptr_t Base = 0x10000000; // We might want to change this later to 0xB0000000 for caching and stuff (More research needed) - - return (Base + (adr & ~Mask)); - } - } - - namespace internal { - template - struct IOValue { - typedef S UnderlyingType; - - UnderlyingType raw; - - template - static constexpr T from(const ARGS&...args) { - return T{0}.set(args...); - } - - constexpr T& set(Bit bit) { - this->raw = bit::set(this->raw, bit); - return static_cast(*this); - } - - constexpr T& set(ClearBit bit) { - this->raw = bit::set(this->raw, bit); - return static_cast(*this); - } - - constexpr T& set_range(const BitRange& bits, UnderlyingType value) { - this->raw = bit::value::set_normalized(this->raw, bits, value); - return static_cast(*this); - } - - template - constexpr T& set(const BitRange::RangeValuePair& value) { - this->raw = bit::value::set_normalized(this->raw, value); - return static_cast(*this); - } - - template - constexpr T& set(const U& head, const ARGS&...tail) { - return this->set(head).set(tail...); - } - - constexpr IOValue::UnderlyingType get(BitRange bits) const { - return bit::value::get_normalized(this->raw, bits.pos, bits.length); - } - - constexpr T& clear(Bit bit) { - this->raw = bit::clear(this->raw, bit); - return static_cast(*this); - } - - constexpr bool is_set(Bit bit) const { - return bit::is_set(this->raw, bit); - } - }; - } - - template - struct IOPort { - using Value = T; - T value; - - T read() const { - return {const_cast*>(this)->value.raw}; - } - - void write(T value) { - const_cast*>(this)->value.raw = value.raw; - } - }; - - template<> - struct IOPort; - - template - struct IOPort32 { - union ValueHelper { - struct { - uint16_t low; - uint16_t high; - }; - T value; - }; - using Value = T; - T value; - - T read() const { - const auto* cast_this = reinterpret_cast*>(this); - const volatile auto* cv_this = const_cast(cast_this); - - return ValueHelper{.low = cv_this->value.low, .high = cv_this->value.high}.value; - } - - void write(T value) { - const auto new_value = ValueHelper{.value = value}; - auto* cast_this = reinterpret_cast*>(this); - volatile auto* v_this = const_cast(cast_this); - - v_this->value.low = new_value.low; - v_this->value.high = new_value.high; - } - }; - - #define __declare_io_struct(name, type) struct name : public ::JabyEngine::internal::IOValue - #define __declare_io_port(type, adr) *reinterpret_cast(adr) - #define __declare_io_value(type, adr) __declare_io_port(type, adr) - #define __declare_io_port_array(type, size, adr) reinterpret_cast(*reinterpret_cast(adr)) +#pragma once +#include "../../../Auxiliary/types.hpp" +#include "../../../Auxiliary/bits.hpp" + +namespace JabyEngine { + namespace IOAdress { + constexpr uintptr_t patch_adr(uintptr_t adr) { + constexpr uintptr_t Mask = 0xF0000000; + constexpr uintptr_t Base = 0x10000000; // We might want to change this later to 0xB0000000 for caching and stuff (More research needed) + + return (Base + (adr & ~Mask)); + } + } + + namespace internal { + template + struct IOValue { + typedef S UnderlyingType; + + UnderlyingType raw; + + template + static constexpr T from(const ARGS&...args) { + return T{0}.set(args...); + } + + constexpr T& set(Bit bit) { + this->raw = bit::set(this->raw, bit); + return static_cast(*this); + } + + constexpr T& set(ClearBit bit) { + this->raw = bit::set(this->raw, bit); + return static_cast(*this); + } + + constexpr T& set_range(const BitRange& bits, UnderlyingType value) { + this->raw = bit::value::set_normalized(this->raw, bits, value); + return static_cast(*this); + } + + template + constexpr T& set(const BitRange::RangeValuePair& value) { + this->raw = bit::value::set_normalized(this->raw, value); + return static_cast(*this); + } + + template + constexpr T& set(const U& head, const ARGS&...tail) { + return this->set(head).set(tail...); + } + + constexpr IOValue::UnderlyingType get(BitRange bits) const { + return bit::value::get_normalized(this->raw, bits.pos, bits.length); + } + + constexpr T& clear(Bit bit) { + this->raw = bit::clear(this->raw, bit); + return static_cast(*this); + } + + constexpr bool is_set(Bit bit) const { + return bit::is_set(this->raw, bit); + } + }; + } + + template + struct IOPort { + using Value = T; + T value; + + T read() const { + return {const_cast*>(this)->value.raw}; + } + + void write(T value) { + const_cast*>(this)->value.raw = value.raw; + } + }; + + template<> + struct IOPort; + + template + struct IOPort32 { + union ValueHelper { + struct { + uint16_t low; + uint16_t high; + }; + T value; + }; + using Value = T; + T value; + + T read() const { + const auto* cast_this = reinterpret_cast*>(this); + const volatile auto* cv_this = const_cast(cast_this); + + return ValueHelper{.low = cv_this->value.low, .high = cv_this->value.high}.value; + } + + void write(T value) { + const auto new_value = ValueHelper{.value = value}; + auto* cast_this = reinterpret_cast*>(this); + volatile auto* v_this = const_cast(cast_this); + + v_this->value.low = new_value.low; + v_this->value.high = new_value.high; + } + }; + + #define __declare_io_struct(name, type) struct name : public ::JabyEngine::internal::IOValue + #define __declare_io_port(type, adr) *reinterpret_cast(adr) + #define __declare_io_value(type, adr) __declare_io_port(type, adr) + #define __declare_io_port_array(type, size, adr) reinterpret_cast(*reinterpret_cast(adr)) } \ No newline at end of file diff --git a/include/PSX/System/IOPorts/IOValues/memory_io_values.hpp b/include/PSX/System/IOPorts/IOValues/memory_io_values.hpp index 70050b3b..8514b456 100644 --- a/include/PSX/System/IOPorts/IOValues/memory_io_values.hpp +++ b/include/PSX/System/IOPorts/IOValues/memory_io_values.hpp @@ -1,18 +1,18 @@ -#pragma once -#include "ioport.hpp" - -namespace JabyEngine { - namespace Memory_IO_Values { - __declare_io_struct(CD_DELAY, uint32_t) { - static constexpr CD_DELAY create() { - return CD_DELAY{0x20943}; - } - }; - - __declare_io_struct(COM_DELAY, uint32_t) { - static constexpr COM_DELAY create() { - return COM_DELAY{0x1325}; - } - }; - } +#pragma once +#include "ioport.hpp" + +namespace JabyEngine { + namespace Memory_IO_Values { + __declare_io_struct(CD_DELAY, uint32_t) { + static constexpr CD_DELAY create() { + return CD_DELAY{0x20943}; + } + }; + + __declare_io_struct(COM_DELAY, uint32_t) { + static constexpr COM_DELAY create() { + return COM_DELAY{0x1325}; + } + }; + } } \ No newline at end of file diff --git a/include/PSX/System/IOPorts/IOValues/periphery_io_values.hpp b/include/PSX/System/IOPorts/IOValues/periphery_io_values.hpp index dc49c7ca..34dc6c1b 100644 --- a/include/PSX/System/IOPorts/IOValues/periphery_io_values.hpp +++ b/include/PSX/System/IOPorts/IOValues/periphery_io_values.hpp @@ -1,52 +1,52 @@ -#pragma once -#include "ioport.hpp" - -namespace JabyEngine { - namespace Periphery_IO_Values { - __declare_io_struct(JOY_BAUD, uint16_t) { - static constexpr JOY_BAUD create() { - return JOY_BAUD{0x0088}; - } - }; - - __declare_io_struct(JOY_CTRL, uint16_t) { - static constexpr auto TXEnable = Bit(0); - static constexpr auto SelectJoy = Bit(1); - static constexpr auto ACK = Bit(4); - static constexpr auto ACKIrqEnable = Bit(12); - static constexpr auto PortBSelected = Bit(13); - static constexpr auto PortASelected = !PortBSelected; - - static constexpr JOY_CTRL create_for(uint16_t port) { - return JOY_CTRL{static_cast(port << PortBSelected)}.set(TXEnable, SelectJoy, ACKIrqEnable); - } - - static constexpr JOY_CTRL close() { - return JOY_CTRL{0}; - } - }; - - __declare_io_struct(JOY_MODE, uint16_t) { - static constexpr JOY_MODE create() { - return JOY_MODE{0x000D}; - } - }; - - __declare_io_struct(JOY_RX_DATA, uint8_t) { - }; - - __declare_io_struct(JOY_STAT, uint32_t) { - static constexpr auto TXReadyStart = Bit(0); - static constexpr auto RXFifoNonEmpty = Bit(1); - static constexpr auto TXReadyFinished = Bit(2); - static constexpr auto RXParityError = Bit(3); - static constexpr auto ACKIrqLow = Bit(7); - }; - - __declare_io_struct(JOY_TX_DATA, uint32_t) { - static constexpr JOY_TX_DATA create(uint8_t byte) { - return JOY_TX_DATA{byte}; - } - }; - } +#pragma once +#include "ioport.hpp" + +namespace JabyEngine { + namespace Periphery_IO_Values { + __declare_io_struct(JOY_BAUD, uint16_t) { + static constexpr JOY_BAUD create() { + return JOY_BAUD{0x0088}; + } + }; + + __declare_io_struct(JOY_CTRL, uint16_t) { + static constexpr auto TXEnable = Bit(0); + static constexpr auto SelectJoy = Bit(1); + static constexpr auto ACK = Bit(4); + static constexpr auto ACKIrqEnable = Bit(12); + static constexpr auto PortBSelected = Bit(13); + static constexpr auto PortASelected = !PortBSelected; + + static constexpr JOY_CTRL create_for(uint16_t port) { + return JOY_CTRL{static_cast(port << PortBSelected)}.set(TXEnable, SelectJoy, ACKIrqEnable); + } + + static constexpr JOY_CTRL close() { + return JOY_CTRL{0}; + } + }; + + __declare_io_struct(JOY_MODE, uint16_t) { + static constexpr JOY_MODE create() { + return JOY_MODE{0x000D}; + } + }; + + __declare_io_struct(JOY_RX_DATA, uint8_t) { + }; + + __declare_io_struct(JOY_STAT, uint32_t) { + static constexpr auto TXReadyStart = Bit(0); + static constexpr auto RXFifoNonEmpty = Bit(1); + static constexpr auto TXReadyFinished = Bit(2); + static constexpr auto RXParityError = Bit(3); + static constexpr auto ACKIrqLow = Bit(7); + }; + + __declare_io_struct(JOY_TX_DATA, uint32_t) { + static constexpr JOY_TX_DATA create(uint8_t byte) { + return JOY_TX_DATA{byte}; + } + }; + } } \ No newline at end of file diff --git a/include/PSX/System/IOPorts/IOValues/spu_io_values.hpp b/include/PSX/System/IOPorts/IOValues/spu_io_values.hpp index 220a66fc..d17e2a5d 100644 --- a/include/PSX/System/IOPorts/IOValues/spu_io_values.hpp +++ b/include/PSX/System/IOPorts/IOValues/spu_io_values.hpp @@ -1,215 +1,215 @@ -#pragma once -#include "ioport.hpp" -#include - -namespace JabyEngine { - namespace SPU_IO_Values { - namespace MemoryMap { - static constexpr uintptr_t ADPCM = 0x01000; - static constexpr uintptr_t End = 0x7FFFF; - } - - __declare_io_struct(AD, uint16_t) { - static constexpr auto AttackMode = Bit(15); - static constexpr auto AttackShift = BitRange::from_to(10, 14); - static constexpr auto AttackStep = BitRange::from_to(8, 9); - static constexpr auto DecayShift = BitRange::from_to(4, 7); - static constexpr auto SustainLevel = BitRange::from_to(0, 3); - - static constexpr AD none() { - return AD{0}; - } - }; - - __declare_io_struct(ControlRegister, uint16_t) { - enum RAMTransferMode { - Stop = 0, - ManualWrite = 1, - DMAWrite = 2, - DMARead = 3 - }; - - static constexpr auto Enable = Bit(15); - static constexpr auto Unmute = Bit(14); - static constexpr auto NoiseFrequcenyShift = BitRange::from_to(10, 13); - static constexpr auto NoiseFrequcenyStep = BitRange::from_to(8, 9); - static constexpr auto ReverbMasterEnable = Bit(7); - static constexpr auto IRQ9Enable = Bit(6); - static constexpr auto TransferMode = BitRange::from_to(4, 5); - static constexpr auto ExternalAudioReverb = Bit(3); - static constexpr auto CDAudioReverb = Bit(2); - static constexpr auto ExternalAudioEnable = Bit(1); - static constexpr auto CDAudioEnable = Bit(0); - }; - - __declare_io_struct(DataTransferControl, uint16_t) { - static constexpr DataTransferControl NormalTransferMode() { - return DataTransferControl{0x0004}; - } - }; - - __declare_io_struct(Echo, uint32_t) { - static constexpr auto EchoBits = BitRange::from_to(0, 23); - - static constexpr Echo AllOff() { - return Echo{0}; - } - }; - - __declare_io_struct(KeyOff, uint32_t) { - static constexpr KeyOff for_specific(uint32_t id) { - return KeyOff{1u << id}; - } - - static constexpr KeyOff all() { - return KeyOff{UI32_MAX}; - } - }; - - __declare_io_struct(KeyOn, uint32_t) { - static constexpr KeyOn for_specific(uint32_t id) { - return KeyOn{1u << id}; - } - - static constexpr KeyOn all() { - return KeyOn{UI32_MAX}; - } - }; - - __declare_io_struct(KeyStatus, uint32_t) { - }; - - __declare_io_struct(Noise, uint16_t) { - static constexpr auto NoiseBits = BitRange::from_to(0, 23); - - static constexpr Noise AllOff() { - return Noise{0}; - } - }; - - __declare_io_struct(PitchModulation, uint32_t) { - static constexpr auto EnableBits = BitRange::from_to(1, 23); - - static constexpr PitchModulation AllOff() { - return PitchModulation{0}; - } - }; - - __declare_io_struct(SampleRate, uint16_t) { - static constexpr SampleRate stop() { - return SampleRate{0}; - } - - static constexpr SampleRate from_HZ(uint32_t freq) { - constexpr uint32_t Base1024Hz = static_cast((4096.0/44100.0)*1024.0); - return SampleRate{static_cast((freq >> 10)*Base1024Hz)}; - } - - static constexpr SampleRate from_HZ(double freq) { - //4096 == 44100Hz - constexpr double Base = (4096.0 / 44100.0); - return SampleRate{static_cast((freq*Base))}; - } - }; - - __declare_io_struct(SimpleVolume, int16_t) { - static constexpr auto MaxVolume = I16_MAX; - - static constexpr SimpleVolume mute() { - return SimpleVolume{0}; - } - - constexpr operator int16_t() const { - return this->raw; - } - }; - - static constexpr SimpleVolume operator""_vol(long double fraction) { - return {static_cast(static_cast(SimpleVolume::MaxVolume)*fraction)}; - } - - __declare_io_struct(SR, uint16_t) { - static constexpr auto SustainMode = Bit(31 - 16); - static constexpr auto SustainDirection = Bit(30 - 16); - static constexpr auto SustainShift = BitRange::from_to((24 - 16), (28 - 16)); - static constexpr auto SustainStep = BitRange::from_to((22 - 16), (23 - 16)); - static constexpr auto ReleaseMode = Bit(21 - 16); - static constexpr auto ReleaseShift = BitRange::from_to((16 - 16), (20 - 16)); - - static constexpr SR none() { - return SR{0}; - } - }; - - __declare_io_struct(SRAMAdr, uint16_t) { - static constexpr SRAMAdr null() { - return SRAMAdr{0x0}; - } - - static constexpr SRAMAdr adpcm_start() { - return SRAMAdr{MemoryMap::ADPCM}; - } - }; - - __declare_io_struct(StatusRegister, uint16_t) { - enum CapureBufferHalf { - First = 0, - Second = 1 - }; - - static constexpr auto Unused = BitRange::from_to(12, 15); - static constexpr auto CaputreBufferHalf = Bit(11); - static constexpr auto TransferBusy = Bit(10); - static constexpr auto IsDMARead = Bit(9); - static constexpr auto isDMAWrite = Bit(8); - static constexpr auto isDMA = Bit(7); - static constexpr auto isIRQ = Bit(6); - // Copies of ControlRegister - static constexpr auto TransferMode = BitRange::from_to(4, 5); - static constexpr auto ExternalAudioReverb = Bit(3); - static constexpr auto CDAudioReverb = Bit(2); - static constexpr auto ExternalAudioEnable = Bit(1); - static constexpr auto CDAudioEnable = Bit(0); - }; - - __declare_io_struct(SweepVolume, int16_t) { - struct VolumeMode { - static constexpr auto MaxVolume = (I16_MAX >> 1); - static constexpr auto EnableSweep = Bit(15); - static constexpr auto Enable = !EnableSweep; - static constexpr auto Volume = BitRange::from_to(0, 14); - }; - - struct SweepMode { - enum Mode { - Linear = 0, - Exponential = 1, - }; - - enum Direction { - Increase = 0, - Decrease = 1, - }; - - enum Phase { - Posititve = 0, - Negative = 1, - }; - - static constexpr auto Mode = Bit(14); - static constexpr auto Direction = Bit(13); - static constexpr auto Phase = Bit(12); - static constexpr auto Shift = BitRange::from_to(2, 6); - static constexpr auto Step = BitRange::from_to(0, 1); - }; - - static constexpr SweepVolume create(SimpleVolume volume) { - return from(VolumeMode::Enable, VolumeMode::Volume.with(volume.raw >> 1)); - } - - static constexpr SweepVolume mute() { - return SweepVolume{0}; - } - }; - } +#pragma once +#include "ioport.hpp" +#include + +namespace JabyEngine { + namespace SPU_IO_Values { + namespace MemoryMap { + static constexpr uintptr_t ADPCM = 0x01000; + static constexpr uintptr_t End = 0x7FFFF; + } + + __declare_io_struct(AD, uint16_t) { + static constexpr auto AttackMode = Bit(15); + static constexpr auto AttackShift = BitRange::from_to(10, 14); + static constexpr auto AttackStep = BitRange::from_to(8, 9); + static constexpr auto DecayShift = BitRange::from_to(4, 7); + static constexpr auto SustainLevel = BitRange::from_to(0, 3); + + static constexpr AD none() { + return AD{0}; + } + }; + + __declare_io_struct(ControlRegister, uint16_t) { + enum RAMTransferMode { + Stop = 0, + ManualWrite = 1, + DMAWrite = 2, + DMARead = 3 + }; + + static constexpr auto Enable = Bit(15); + static constexpr auto Unmute = Bit(14); + static constexpr auto NoiseFrequcenyShift = BitRange::from_to(10, 13); + static constexpr auto NoiseFrequcenyStep = BitRange::from_to(8, 9); + static constexpr auto ReverbMasterEnable = Bit(7); + static constexpr auto IRQ9Enable = Bit(6); + static constexpr auto TransferMode = BitRange::from_to(4, 5); + static constexpr auto ExternalAudioReverb = Bit(3); + static constexpr auto CDAudioReverb = Bit(2); + static constexpr auto ExternalAudioEnable = Bit(1); + static constexpr auto CDAudioEnable = Bit(0); + }; + + __declare_io_struct(DataTransferControl, uint16_t) { + static constexpr DataTransferControl NormalTransferMode() { + return DataTransferControl{0x0004}; + } + }; + + __declare_io_struct(Echo, uint32_t) { + static constexpr auto EchoBits = BitRange::from_to(0, 23); + + static constexpr Echo AllOff() { + return Echo{0}; + } + }; + + __declare_io_struct(KeyOff, uint32_t) { + static constexpr KeyOff for_specific(uint32_t id) { + return KeyOff{1u << id}; + } + + static constexpr KeyOff all() { + return KeyOff{UI32_MAX}; + } + }; + + __declare_io_struct(KeyOn, uint32_t) { + static constexpr KeyOn for_specific(uint32_t id) { + return KeyOn{1u << id}; + } + + static constexpr KeyOn all() { + return KeyOn{UI32_MAX}; + } + }; + + __declare_io_struct(KeyStatus, uint32_t) { + }; + + __declare_io_struct(Noise, uint16_t) { + static constexpr auto NoiseBits = BitRange::from_to(0, 23); + + static constexpr Noise AllOff() { + return Noise{0}; + } + }; + + __declare_io_struct(PitchModulation, uint32_t) { + static constexpr auto EnableBits = BitRange::from_to(1, 23); + + static constexpr PitchModulation AllOff() { + return PitchModulation{0}; + } + }; + + __declare_io_struct(SampleRate, uint16_t) { + static constexpr SampleRate stop() { + return SampleRate{0}; + } + + static constexpr SampleRate from_HZ(uint32_t freq) { + constexpr uint32_t Base1024Hz = static_cast((4096.0/44100.0)*1024.0); + return SampleRate{static_cast((freq >> 10)*Base1024Hz)}; + } + + static constexpr SampleRate from_HZ(double freq) { + //4096 == 44100Hz + constexpr double Base = (4096.0 / 44100.0); + return SampleRate{static_cast((freq*Base))}; + } + }; + + __declare_io_struct(SimpleVolume, int16_t) { + static constexpr auto MaxVolume = I16_MAX; + + static constexpr SimpleVolume mute() { + return SimpleVolume{0}; + } + + constexpr operator int16_t() const { + return this->raw; + } + }; + + static constexpr SimpleVolume operator""_vol(long double fraction) { + return {static_cast(static_cast(SimpleVolume::MaxVolume)*fraction)}; + } + + __declare_io_struct(SR, uint16_t) { + static constexpr auto SustainMode = Bit(31 - 16); + static constexpr auto SustainDirection = Bit(30 - 16); + static constexpr auto SustainShift = BitRange::from_to((24 - 16), (28 - 16)); + static constexpr auto SustainStep = BitRange::from_to((22 - 16), (23 - 16)); + static constexpr auto ReleaseMode = Bit(21 - 16); + static constexpr auto ReleaseShift = BitRange::from_to((16 - 16), (20 - 16)); + + static constexpr SR none() { + return SR{0}; + } + }; + + __declare_io_struct(SRAMAdr, uint16_t) { + static constexpr SRAMAdr null() { + return SRAMAdr{0x0}; + } + + static constexpr SRAMAdr adpcm_start() { + return SRAMAdr{MemoryMap::ADPCM}; + } + }; + + __declare_io_struct(StatusRegister, uint16_t) { + enum CapureBufferHalf { + First = 0, + Second = 1 + }; + + static constexpr auto Unused = BitRange::from_to(12, 15); + static constexpr auto CaputreBufferHalf = Bit(11); + static constexpr auto TransferBusy = Bit(10); + static constexpr auto IsDMARead = Bit(9); + static constexpr auto isDMAWrite = Bit(8); + static constexpr auto isDMA = Bit(7); + static constexpr auto isIRQ = Bit(6); + // Copies of ControlRegister + static constexpr auto TransferMode = BitRange::from_to(4, 5); + static constexpr auto ExternalAudioReverb = Bit(3); + static constexpr auto CDAudioReverb = Bit(2); + static constexpr auto ExternalAudioEnable = Bit(1); + static constexpr auto CDAudioEnable = Bit(0); + }; + + __declare_io_struct(SweepVolume, int16_t) { + struct VolumeMode { + static constexpr auto MaxVolume = (I16_MAX >> 1); + static constexpr auto EnableSweep = Bit(15); + static constexpr auto Enable = !EnableSweep; + static constexpr auto Volume = BitRange::from_to(0, 14); + }; + + struct SweepMode { + enum Mode { + Linear = 0, + Exponential = 1, + }; + + enum Direction { + Increase = 0, + Decrease = 1, + }; + + enum Phase { + Posititve = 0, + Negative = 1, + }; + + static constexpr auto Mode = Bit(14); + static constexpr auto Direction = Bit(13); + static constexpr auto Phase = Bit(12); + static constexpr auto Shift = BitRange::from_to(2, 6); + static constexpr auto Step = BitRange::from_to(0, 1); + }; + + static constexpr SweepVolume create(SimpleVolume volume) { + return from(VolumeMode::Enable, VolumeMode::Volume.with(volume.raw >> 1)); + } + + static constexpr SweepVolume mute() { + return SweepVolume{0}; + } + }; + } } \ No newline at end of file diff --git a/include/PSX/System/IOPorts/IOValues/timer_io_values.hpp b/include/PSX/System/IOPorts/IOValues/timer_io_values.hpp index 66945fbc..3a05cc69 100644 --- a/include/PSX/System/IOPorts/IOValues/timer_io_values.hpp +++ b/include/PSX/System/IOPorts/IOValues/timer_io_values.hpp @@ -1,31 +1,31 @@ -#pragma once -#include "ioport.hpp" - -namespace JabyEngine { - namespace Timer_IO_Values { - __declare_io_struct(CounterMode, uint32_t) { - static constexpr auto SyncEnable = Bit(0); - static constexpr auto FreeRun = !SyncEnable; - static constexpr auto SyncMode = BitRange::from_to(1, 2); - static constexpr auto ResetAfterTarget = Bit(3); - static constexpr auto IRQAtTarget = Bit(4); - static constexpr auto IRQAtMax = Bit(5); - static constexpr auto IRQEveryTime = Bit(6); - static constexpr auto IRQOneShot = !IRQEveryTime; - static constexpr auto IRQToggle = Bit(7); - static constexpr auto IRQPulse = !IRQToggle; - static constexpr auto ClockSource = BitRange::from_to(8, 9); - static constexpr auto HasIRQRequest = Bit(10); - static constexpr auto IsTargetReached = Bit(11); - static constexpr auto IsMaxReached = Bit(12); - }; - - __declare_io_struct(CounterTarget, uint32_t) { - static constexpr auto CounterTargetValue = BitRange::from_to(0, 15); - }; - - __declare_io_struct(CounterValue, uint32_t) { - static constexpr auto Value = BitRange::from_to(0, 15); - }; - } +#pragma once +#include "ioport.hpp" + +namespace JabyEngine { + namespace Timer_IO_Values { + __declare_io_struct(CounterMode, uint32_t) { + static constexpr auto SyncEnable = Bit(0); + static constexpr auto FreeRun = !SyncEnable; + static constexpr auto SyncMode = BitRange::from_to(1, 2); + static constexpr auto ResetAfterTarget = Bit(3); + static constexpr auto IRQAtTarget = Bit(4); + static constexpr auto IRQAtMax = Bit(5); + static constexpr auto IRQEveryTime = Bit(6); + static constexpr auto IRQOneShot = !IRQEveryTime; + static constexpr auto IRQToggle = Bit(7); + static constexpr auto IRQPulse = !IRQToggle; + static constexpr auto ClockSource = BitRange::from_to(8, 9); + static constexpr auto HasIRQRequest = Bit(10); + static constexpr auto IsTargetReached = Bit(11); + static constexpr auto IsMaxReached = Bit(12); + }; + + __declare_io_struct(CounterTarget, uint32_t) { + static constexpr auto CounterTargetValue = BitRange::from_to(0, 15); + }; + + __declare_io_struct(CounterValue, uint32_t) { + static constexpr auto Value = BitRange::from_to(0, 15); + }; + } } \ No newline at end of file diff --git a/include/PSX/System/IOPorts/interrupt_io.hpp b/include/PSX/System/IOPorts/interrupt_io.hpp index 00687402..e5ba57ce 100644 --- a/include/PSX/System/IOPorts/interrupt_io.hpp +++ b/include/PSX/System/IOPorts/interrupt_io.hpp @@ -1,41 +1,41 @@ -#pragma once -#include "IOValues/interrupt_io_values.hpp" - -namespace JabyEngine { - using Status_IO = IOPort; - using Mask_IO = IOPort; - - struct Interrupt { - static constexpr auto VBlank = Bit(0); - static constexpr auto GPU = Bit(1); - static constexpr auto CDROM = Bit(2); - static constexpr auto DMA = Bit(3); - static constexpr auto Timer0 = Bit(4); - static constexpr auto Timer1 = Bit(5); - static constexpr auto Timer2 = Bit(6); - static constexpr auto Periphery = Bit(7); - static constexpr auto SIO = Bit(8); - static constexpr auto SPU = Bit(9); - static constexpr auto Controller = Bit(10); - static constexpr auto LightPen = Controller; - - static inline auto& Status = __declare_io_port(Status_IO, 0x1F801070); - static inline auto& Mask = __declare_io_port(Mask_IO, 0x1F801074); - - static bool is_irq(Bit irq) { - return Status.read().is_set(irq); - } - - static void ack_irq(Bit irq) { - Status.write({bit::clear(0b11111111111, irq)}); - } - - static void disable_irq(Bit irq) { - Mask.write(Mask.read().clear(irq)); - } - - static void enable_irq(Bit irq) { - Mask.write(Mask.read().set(irq)); - } - }; +#pragma once +#include "IOValues/interrupt_io_values.hpp" + +namespace JabyEngine { + using Status_IO = IOPort; + using Mask_IO = IOPort; + + struct Interrupt { + static constexpr auto VBlank = Bit(0); + static constexpr auto GPU = Bit(1); + static constexpr auto CDROM = Bit(2); + static constexpr auto DMA = Bit(3); + static constexpr auto Timer0 = Bit(4); + static constexpr auto Timer1 = Bit(5); + static constexpr auto Timer2 = Bit(6); + static constexpr auto Periphery = Bit(7); + static constexpr auto SIO = Bit(8); + static constexpr auto SPU = Bit(9); + static constexpr auto Controller = Bit(10); + static constexpr auto LightPen = Controller; + + static inline auto& Status = __declare_io_port(Status_IO, 0x1F801070); + static inline auto& Mask = __declare_io_port(Mask_IO, 0x1F801074); + + static bool is_irq(Bit irq) { + return Status.read().is_set(irq); + } + + static void ack_irq(Bit irq) { + Status.write({bit::clear(0b11111111111, irq)}); + } + + static void disable_irq(Bit irq) { + Mask.write(Mask.read().clear(irq)); + } + + static void enable_irq(Bit irq) { + Mask.write(Mask.read().set(irq)); + } + }; } \ No newline at end of file diff --git a/include/PSX/System/IOPorts/periphery_io.hpp b/include/PSX/System/IOPorts/periphery_io.hpp index c986c578..f691d162 100644 --- a/include/PSX/System/IOPorts/periphery_io.hpp +++ b/include/PSX/System/IOPorts/periphery_io.hpp @@ -1,29 +1,29 @@ -#pragma once -#include "IOValues/periphery_io_values.hpp" - -namespace JabyEngine { - namespace Periphery_IO { - struct JOY_STAT_IO : public IOPort { - inline bool has_response() const { - return this->read().is_set(Periphery_IO_Values::JOY_STAT::RXFifoNonEmpty); - } - - inline bool is_ready_transfer() const { - return this->read().is_set(Periphery_IO_Values::JOY_STAT::TXReadyFinished); - } - }; - - using JOY_BAUD_IO = IOPort; - using JOY_CTRL_IO = IOPort; - using JOY_MODE_IO = IOPort; - using JOY_RX_DATA_IO = IOPort; - using JOY_TX_DATA_IO = IOPort; - - static auto& JOY_TX_DATA = __declare_io_port(JOY_TX_DATA_IO, 0x1F801040); - static const auto& JOY_RX_DATA = __declare_io_port(JOY_RX_DATA_IO, 0x1F801040); - static const auto& JOY_STAT = __declare_io_port(JOY_STAT_IO, 0x1F801044); - static auto& JOY_MODE = __declare_io_port(JOY_MODE_IO, 0x1F801048); - static auto& JOY_CTRL = __declare_io_port(JOY_CTRL_IO, 0x1F80104A); - static auto& JOY_BAUD = __declare_io_port(JOY_BAUD_IO, 0x1F80104E); - } +#pragma once +#include "IOValues/periphery_io_values.hpp" + +namespace JabyEngine { + namespace Periphery_IO { + struct JOY_STAT_IO : public IOPort { + inline bool has_response() const { + return this->read().is_set(Periphery_IO_Values::JOY_STAT::RXFifoNonEmpty); + } + + inline bool is_ready_transfer() const { + return this->read().is_set(Periphery_IO_Values::JOY_STAT::TXReadyFinished); + } + }; + + using JOY_BAUD_IO = IOPort; + using JOY_CTRL_IO = IOPort; + using JOY_MODE_IO = IOPort; + using JOY_RX_DATA_IO = IOPort; + using JOY_TX_DATA_IO = IOPort; + + static auto& JOY_TX_DATA = __declare_io_port(JOY_TX_DATA_IO, 0x1F801040); + static const auto& JOY_RX_DATA = __declare_io_port(JOY_RX_DATA_IO, 0x1F801040); + static const auto& JOY_STAT = __declare_io_port(JOY_STAT_IO, 0x1F801044); + static auto& JOY_MODE = __declare_io_port(JOY_MODE_IO, 0x1F801048); + static auto& JOY_CTRL = __declare_io_port(JOY_CTRL_IO, 0x1F80104A); + static auto& JOY_BAUD = __declare_io_port(JOY_BAUD_IO, 0x1F80104E); + } } \ No newline at end of file diff --git a/include/PSX/System/IOPorts/timer_io.hpp b/include/PSX/System/IOPorts/timer_io.hpp index 5cda8a83..0c261e65 100644 --- a/include/PSX/System/IOPorts/timer_io.hpp +++ b/include/PSX/System/IOPorts/timer_io.hpp @@ -1,89 +1,89 @@ -#pragma once -#include "IOValues/timer_io_values.hpp" - -namespace JabyEngine { - namespace Timer_IO { - using CounterMode_IO = IOPort; - using CounterTarget_IO = IOPort; - using CounterValue_IO = IOPort; - - #pragma pack(push, 1) - struct Counter { - CounterValue_IO value; - CounterMode_IO mode; - CounterTarget_IO target; - uint32_t unused; - - inline uint16_t get_current_value() const { - return this->value.read().get(Timer_IO_Values::CounterValue::Value); - } - - inline void set_target_value(uint16_t value) { - this->target.write(Timer_IO_Values::CounterTarget{0}.set_range(Timer_IO_Values::CounterTarget::CounterTargetValue, value)); - } - - inline void set_mode(Timer_IO_Values::CounterMode mode) { - this->mode.write(mode); - } - }; - #pragma pack(pop) - - #pragma pack(push, 1) - struct Counter0 : public Counter { - struct SyncMode { - static constexpr auto Zero_At_Hblank = Timer_IO_Values::CounterMode::SyncMode.with(1u); - static constexpr auto Pause_During_Hblank = Timer_IO_Values::CounterMode::SyncMode.with(0u); - static constexpr auto Zero_At_Hblank_Pause_Outside_Hblank = Timer_IO_Values::CounterMode::SyncMode.with(2u); - static constexpr auto Pause_Until_Hblank_Then_Freerun = Timer_IO_Values::CounterMode::SyncMode.with(3u); - }; - - struct Source { - static constexpr auto System_Clock = Timer_IO_Values::CounterMode::ClockSource.with(0u); - static constexpr auto Dot_Clock = Timer_IO_Values::CounterMode::ClockSource.with(1u); - static constexpr auto System_Clock_Too = Timer_IO_Values::CounterMode::ClockSource.with(2u); - static constexpr auto Dot_Clock_Too = Timer_IO_Values::CounterMode::ClockSource.with(3u); - }; - }; - - struct Counter1 : public Counter { - struct SyncMode { - static constexpr auto Pause_During_Vblank = Timer_IO_Values::CounterMode::SyncMode.with(0u); - static constexpr auto Zero_At_Vblank = Timer_IO_Values::CounterMode::SyncMode.with(1u); - static constexpr auto Zero_At_Vblank_Pause_Outside_Vblank = Timer_IO_Values::CounterMode::SyncMode.with(2u); - static constexpr auto Pause_Until_Vblank_Then_FreeRun = Timer_IO_Values::CounterMode::SyncMode.with(3u); - }; - - struct Source { - static constexpr auto System_Clock = Timer_IO_Values::CounterMode::ClockSource.with(0u); - static constexpr auto Hblank = Timer_IO_Values::CounterMode::ClockSource.with(1u); - static constexpr auto System_Clock_Too = Timer_IO_Values::CounterMode::ClockSource.with(2u); - static constexpr auto Hblank_Too = Timer_IO_Values::CounterMode::ClockSource.with(3u); - }; - }; - - struct Counter2 : public Counter { - struct SyncMode { - static constexpr auto Stop_Counter = Timer_IO_Values::CounterMode::SyncMode.with(0u); - static constexpr auto FreeRun = Timer_IO_Values::CounterMode::SyncMode.with(1u); - static constexpr auto FreeRun_Too = Timer_IO_Values::CounterMode::SyncMode.with(2u); - static constexpr auto Stop_Counter_Too = Timer_IO_Values::CounterMode::SyncMode.with(3u); - }; - - struct Source { - static constexpr auto System_Clock = Timer_IO_Values::CounterMode::ClockSource.with(0u); - static constexpr auto System_Clock_Too = Timer_IO_Values::CounterMode::ClockSource.with(1u); - static constexpr auto System_Clock_Div_8 = Timer_IO_Values::CounterMode::ClockSource.with(2u); - static constexpr auto System_Clock_Div_8_Too = Timer_IO_Values::CounterMode::ClockSource.with(3u); - }; - }; - #pragma pack(pop) - - static constexpr uintptr_t counter_base_adr(size_t ID) { - return (0x1F801100 + (ID*0x10)); - } - - static auto& Counter0 = __declare_io_value(struct Counter0, counter_base_adr(0)); - static auto& Counter1 = __declare_io_value(struct Counter1, counter_base_adr(1)); - static auto& Counter2 = __declare_io_value(struct Counter2, counter_base_adr(2)); - } +#pragma once +#include "IOValues/timer_io_values.hpp" + +namespace JabyEngine { + namespace Timer_IO { + using CounterMode_IO = IOPort; + using CounterTarget_IO = IOPort; + using CounterValue_IO = IOPort; + + #pragma pack(push, 1) + struct Counter { + CounterValue_IO value; + CounterMode_IO mode; + CounterTarget_IO target; + uint32_t unused; + + inline uint16_t get_current_value() const { + return this->value.read().get(Timer_IO_Values::CounterValue::Value); + } + + inline void set_target_value(uint16_t value) { + this->target.write(Timer_IO_Values::CounterTarget{0}.set_range(Timer_IO_Values::CounterTarget::CounterTargetValue, value)); + } + + inline void set_mode(Timer_IO_Values::CounterMode mode) { + this->mode.write(mode); + } + }; + #pragma pack(pop) + + #pragma pack(push, 1) + struct Counter0 : public Counter { + struct SyncMode { + static constexpr auto Zero_At_Hblank = Timer_IO_Values::CounterMode::SyncMode.with(1u); + static constexpr auto Pause_During_Hblank = Timer_IO_Values::CounterMode::SyncMode.with(0u); + static constexpr auto Zero_At_Hblank_Pause_Outside_Hblank = Timer_IO_Values::CounterMode::SyncMode.with(2u); + static constexpr auto Pause_Until_Hblank_Then_Freerun = Timer_IO_Values::CounterMode::SyncMode.with(3u); + }; + + struct Source { + static constexpr auto System_Clock = Timer_IO_Values::CounterMode::ClockSource.with(0u); + static constexpr auto Dot_Clock = Timer_IO_Values::CounterMode::ClockSource.with(1u); + static constexpr auto System_Clock_Too = Timer_IO_Values::CounterMode::ClockSource.with(2u); + static constexpr auto Dot_Clock_Too = Timer_IO_Values::CounterMode::ClockSource.with(3u); + }; + }; + + struct Counter1 : public Counter { + struct SyncMode { + static constexpr auto Pause_During_Vblank = Timer_IO_Values::CounterMode::SyncMode.with(0u); + static constexpr auto Zero_At_Vblank = Timer_IO_Values::CounterMode::SyncMode.with(1u); + static constexpr auto Zero_At_Vblank_Pause_Outside_Vblank = Timer_IO_Values::CounterMode::SyncMode.with(2u); + static constexpr auto Pause_Until_Vblank_Then_FreeRun = Timer_IO_Values::CounterMode::SyncMode.with(3u); + }; + + struct Source { + static constexpr auto System_Clock = Timer_IO_Values::CounterMode::ClockSource.with(0u); + static constexpr auto Hblank = Timer_IO_Values::CounterMode::ClockSource.with(1u); + static constexpr auto System_Clock_Too = Timer_IO_Values::CounterMode::ClockSource.with(2u); + static constexpr auto Hblank_Too = Timer_IO_Values::CounterMode::ClockSource.with(3u); + }; + }; + + struct Counter2 : public Counter { + struct SyncMode { + static constexpr auto Stop_Counter = Timer_IO_Values::CounterMode::SyncMode.with(0u); + static constexpr auto FreeRun = Timer_IO_Values::CounterMode::SyncMode.with(1u); + static constexpr auto FreeRun_Too = Timer_IO_Values::CounterMode::SyncMode.with(2u); + static constexpr auto Stop_Counter_Too = Timer_IO_Values::CounterMode::SyncMode.with(3u); + }; + + struct Source { + static constexpr auto System_Clock = Timer_IO_Values::CounterMode::ClockSource.with(0u); + static constexpr auto System_Clock_Too = Timer_IO_Values::CounterMode::ClockSource.with(1u); + static constexpr auto System_Clock_Div_8 = Timer_IO_Values::CounterMode::ClockSource.with(2u); + static constexpr auto System_Clock_Div_8_Too = Timer_IO_Values::CounterMode::ClockSource.with(3u); + }; + }; + #pragma pack(pop) + + static constexpr uintptr_t counter_base_adr(size_t ID) { + return (0x1F801100 + (ID*0x10)); + } + + static auto& Counter0 = __declare_io_value(struct Counter0, counter_base_adr(0)); + static auto& Counter1 = __declare_io_value(struct Counter1, counter_base_adr(1)); + static auto& Counter2 = __declare_io_value(struct Counter2, counter_base_adr(2)); + } } \ No newline at end of file diff --git a/include/PSX/System/callbacks.hpp b/include/PSX/System/callbacks.hpp index efbd9f46..eb4a21cf 100644 --- a/include/PSX/System/callbacks.hpp +++ b/include/PSX/System/callbacks.hpp @@ -1,20 +1,20 @@ -#pragma once -#include "syscalls.hpp" - -namespace JabyEngine { - namespace Callback { - struct [[deprecated("Currently not supported")]] VSyncCallback { - using Function = void (*)(); - - static Function callback; - - static void install(Function function) { - VSyncCallback::callback = function; - } - - static void uninstall() { - VSyncCallback::install(nullptr); - } - }; - } +#pragma once +#include "syscalls.hpp" + +namespace JabyEngine { + namespace Callback { + struct [[deprecated("Currently not supported")]] VSyncCallback { + using Function = void (*)(); + + static Function callback; + + static void install(Function function) { + VSyncCallback::callback = function; + } + + static void uninstall() { + VSyncCallback::install(nullptr); + } + }; + } } \ No newline at end of file diff --git a/include/PSX/System/syscalls.hpp b/include/PSX/System/syscalls.hpp index 08a699f5..15f7b40b 100644 --- a/include/PSX/System/syscalls.hpp +++ b/include/PSX/System/syscalls.hpp @@ -1,293 +1,293 @@ -#pragma once -#include "../jabyengine_defines.hpp" - -/* -R0 zr Constant Zero -R1 at Reserved for the assembler -R2-R3 v0-v1 Values for results and expression evaluation -R4-R7 a0-a3 Arguments -R8-R15 t0-t7 Temporaries (not preserved across call) -R16-R23 s0-s7 Saved (preserved across call) -R24-R25 t8-t9 More temporaries (not preserved across call) -R26-R27 k0-k1 Reserved for OS Kernel -R28 gp Global Pointer -R29 sp Stack Pointer -R30 fp Frame Pointer -R31 ra Return address (set by function call) -*/ - -namespace JabyEngine { - namespace BIOS { - struct Version { - enum Type { - Unkown, - Devboard, - PS1, - PS2, - PS3, - PSCompatible, // internal usage only - No$psx, - XEBRA - }; - - struct { - uint8_t day; - uint8_t month; - uint16_t year; - } date; - Type type; - const char* kernel_maker; - const char* version_str; - const char* gui_version; - const char* copyright; - }; - - extern const Version version; - } - - struct TCB { - uint32_t status; - uint32_t unused; - uint32_t reg[32]; - uint32_t epc; - uint32_t hi; - uint32_t lo; - uint32_t sr; - uint32_t cause; - uint32_t unused2[9]; - }; - - struct PCB { - TCB* current_tcb; - }; - - struct ToT { - using ExCB = void; - using EvCB = void; - using FCB = void; - - ExCB* exception_chain; - uint32_t exception_chain_size; - PCB* processes; - uint32_t processes_size; - TCB* threads; - uint32_t threads_size; - uint32_t reserved_0; - uint32_t reserved_1; - EvCB* events; - uint32_t events_size; - uint32_t reserved_2; - uint32_t reserved_3; - uint32_t reserved_4; - uint32_t reserved_5; - uint32_t reserved_6; - uint32_t reserved_7; - FCB* files; - uint32_t files_size; - uint32_t reserved_8; - uint32_t reserved_9; - }; - - extern ToT table_of_tables; - - namespace SysCall { - static constexpr const uint32_t Table_A = 0xA0; - static constexpr const uint32_t Table_B = 0xB0; - static constexpr const uint32_t Table_C = 0xC0; - - enum struct Priority { - CdromDmaIrq = 0, - CdromIoIrq = 0, - SyscallException = 0, - - CardSpecificIrq = 1, - VblankIrq = 1, - Timer2Irq = 1, - Timer1Irq = 1, - Timer0Irq = 1, - - PadCardIrq = 2, - - DefInt = 3 - }; - - enum InterruptVerifierResult { - SkipHandler = 0, - ExecuteHandler = 1 - }; - - typedef InterruptVerifierResult (*InterruptVerifier)(); - typedef void (*InterruptHandler)(uint32_t); - using ThreadHandle = uint32_t; - - #pragma pack(push, 1) - struct InterruptCallback { - struct InterruptCallback* next; - InterruptHandler handler_function; - InterruptVerifier verifier_function; - uint32_t notUsed; - - static constexpr InterruptCallback from(InterruptVerifier verifier, InterruptHandler handler) { - return InterruptCallback{nullptr, handler, verifier, 0}; - } - }; - #pragma pack(pop) - - #define __syscall_function_cast(table, ...) reinterpret_cast<__VA_ARGS__>(table) - - static __always_inline uint32_t* get_gp() { - uint32_t* gp; - __asm__("sw $gp, %0" : "=m"(gp)); - return gp; - } - - static __always_inline void DequeueCdIntr() { - register uint32_t FuncID asm("t1") = 0xa3; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - __syscall_function_cast(Table_A, void(*)())(); - } - - static __always_inline void FlushCache() { - register uint32_t FuncID asm("t1") = 0x44; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - __syscall_function_cast(Table_A, void(*)())(); - } - - static __always_inline void* memcpy(void *dst, const void *src, size_t len) { - register uint32_t FuncID asm("t1") = 0x2A; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - return __syscall_function_cast(Table_A, void*(*)(void*, const void*, size_t))(dst, src, len); - } - - static __always_inline ThreadHandle OpenThread(void (*thread_func)(), uint32_t* stack_ptr, uint32_t* gp) { - register uint32_t FuncID asm("t1") = 0x0E; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - return __syscall_function_cast(Table_B, ThreadHandle(*)(void(*)(), uint32_t*, uint32_t*))(thread_func, stack_ptr, gp); - } - - static __always_inline void [[noreturn]] ChangeThread(ThreadHandle handle) { - register uint32_t FuncID asm("t1") = 0x10; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - __syscall_function_cast(Table_B, void(*)(ThreadHandle))(handle); - } - - static __always_inline void InitPad(uint8_t *portA, uint32_t portASize, uint8_t *portB, uint32_t portBSize) { - register uint32_t FuncID asm("t1") = 0x12; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - __syscall_function_cast(Table_B, void(*)(uint8_t*, uint32_t, uint8_t*, uint32_t))(portA, portASize, portB, portBSize); - } - - static __always_inline void StartPad() { - register uint32_t FuncID asm("t1") = 0x13; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - __syscall_function_cast(Table_B, void(*)())(); - } - - static __always_inline void StopPad() { - register uint32_t FuncID asm("t1") = 0x14; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - __syscall_function_cast(Table_B, void(*)())(); - } - - static __always_inline void ChangeClearPad(int32_t _reserved) { - register uint32_t FuncID asm("t1") = 0x5B; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - __syscall_function_cast(Table_B, void(*)(int32_t))(_reserved); - } - - static __always_inline void [[noreturn]] ReturnFromException() { - register uint32_t FuncID asm("t1") = 0x17; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - __syscall_function_cast(Table_B, void(*)())(); - } - - static __always_inline void SetDefaultExitFromException() { - register uint32_t FuncID asm("t1") = 0x18; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - __syscall_function_cast(Table_B, void(*)())(); - } - - static __always_inline int SysEnqIntRP(Priority prio, InterruptCallback* interElm) { - register uint32_t FuncID asm("t1") = 0x02; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - return __syscall_function_cast(Table_C, int(*)(Priority prio, InterruptCallback *interElm))(prio, interElm); - } - - static __always_inline int SysDeqIntRP(Priority prio, InterruptCallback *interElm) { - register uint32_t FuncID asm("t1") = 0x03; - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - - return __syscall_function_cast(Table_C, int(*)(Priority prio, InterruptCallback *interElm))(prio, interElm); - } - - static __always_inline uint32_t EnterCriticalSection() { - register uint32_t FuncID asm("a0") = 0x01; - register uint32_t returnValue asm("v0"); - - __asm__ volatile("syscall" : "=r"(returnValue) : "r"(FuncID) : "memory"); - return returnValue; - } - - static __always_inline void ExitCriticalSection() { - register uint32_t FuncID asm("a0") = 0x02; - - __asm__ volatile("syscall" :: "r"(FuncID) : "memory"); - } - - static __always_inline void DeliverEvent(uint32_t classId, uint32_t spec) { - register uint32_t FuncID asm("t1") = 0x07; - - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - __syscall_function_cast(Table_B, void (*)(uint32_t, uint32_t))(classId, spec); - } - - static __always_inline uint32_t OpenEvent(uint32_t classId, uint32_t spec, uint32_t mode, void (*handler)()) { - register uint32_t FuncID asm("t1") = 0x08; - - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - return __syscall_function_cast(Table_B, uint32_t(*)(uint32_t, uint32_t, uint32_t, void(*)()))(classId, spec, mode, handler); - } - - static __always_inline int CloseEvent(uint32_t event) { - register uint32_t FuncID asm("t1") = 0x09; - - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - return __syscall_function_cast(Table_B, uint32_t(*)(uint32_t))(event); - } - - static __always_inline int32_t TestEvent(uint32_t event) { - register uint32_t FuncID asm("t1") = 0x0B; - - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - return __syscall_function_cast(Table_B, int32_t (*)(uint32_t))(event); - } - - static __always_inline int32_t EnableEvent(uint32_t event) { - register uint32_t FuncID asm("t1") = 0x0C; - - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - return __syscall_function_cast(Table_B, int32_t (*)(uint32_t))(event); - } - - static __always_inline const uint16_t* Krom2RawAdd(uint16_t sjis_code) { - register uint32_t FuncID asm("t1") = 0x51; - - __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); - return __syscall_function_cast(Table_B, const uint16_t* (*)(uint16_t))(sjis_code); - } - - void printf(const char* txt, ...); - } +#pragma once +#include "../jabyengine_defines.hpp" + +/* +R0 zr Constant Zero +R1 at Reserved for the assembler +R2-R3 v0-v1 Values for results and expression evaluation +R4-R7 a0-a3 Arguments +R8-R15 t0-t7 Temporaries (not preserved across call) +R16-R23 s0-s7 Saved (preserved across call) +R24-R25 t8-t9 More temporaries (not preserved across call) +R26-R27 k0-k1 Reserved for OS Kernel +R28 gp Global Pointer +R29 sp Stack Pointer +R30 fp Frame Pointer +R31 ra Return address (set by function call) +*/ + +namespace JabyEngine { + namespace BIOS { + struct Version { + enum Type { + Unkown, + Devboard, + PS1, + PS2, + PS3, + PSCompatible, // internal usage only + No$psx, + XEBRA + }; + + struct { + uint8_t day; + uint8_t month; + uint16_t year; + } date; + Type type; + const char* kernel_maker; + const char* version_str; + const char* gui_version; + const char* copyright; + }; + + extern const Version version; + } + + struct TCB { + uint32_t status; + uint32_t unused; + uint32_t reg[32]; + uint32_t epc; + uint32_t hi; + uint32_t lo; + uint32_t sr; + uint32_t cause; + uint32_t unused2[9]; + }; + + struct PCB { + TCB* current_tcb; + }; + + struct ToT { + using ExCB = void; + using EvCB = void; + using FCB = void; + + ExCB* exception_chain; + uint32_t exception_chain_size; + PCB* processes; + uint32_t processes_size; + TCB* threads; + uint32_t threads_size; + uint32_t reserved_0; + uint32_t reserved_1; + EvCB* events; + uint32_t events_size; + uint32_t reserved_2; + uint32_t reserved_3; + uint32_t reserved_4; + uint32_t reserved_5; + uint32_t reserved_6; + uint32_t reserved_7; + FCB* files; + uint32_t files_size; + uint32_t reserved_8; + uint32_t reserved_9; + }; + + extern ToT table_of_tables; + + namespace SysCall { + static constexpr const uint32_t Table_A = 0xA0; + static constexpr const uint32_t Table_B = 0xB0; + static constexpr const uint32_t Table_C = 0xC0; + + enum struct Priority { + CdromDmaIrq = 0, + CdromIoIrq = 0, + SyscallException = 0, + + CardSpecificIrq = 1, + VblankIrq = 1, + Timer2Irq = 1, + Timer1Irq = 1, + Timer0Irq = 1, + + PadCardIrq = 2, + + DefInt = 3 + }; + + enum InterruptVerifierResult { + SkipHandler = 0, + ExecuteHandler = 1 + }; + + typedef InterruptVerifierResult (*InterruptVerifier)(); + typedef void (*InterruptHandler)(uint32_t); + using ThreadHandle = uint32_t; + + #pragma pack(push, 1) + struct InterruptCallback { + struct InterruptCallback* next; + InterruptHandler handler_function; + InterruptVerifier verifier_function; + uint32_t notUsed; + + static constexpr InterruptCallback from(InterruptVerifier verifier, InterruptHandler handler) { + return InterruptCallback{nullptr, handler, verifier, 0}; + } + }; + #pragma pack(pop) + + #define __syscall_function_cast(table, ...) reinterpret_cast<__VA_ARGS__>(table) + + static __always_inline uint32_t* get_gp() { + uint32_t* gp; + __asm__("sw $gp, %0" : "=m"(gp)); + return gp; + } + + static __always_inline void DequeueCdIntr() { + register uint32_t FuncID asm("t1") = 0xa3; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + __syscall_function_cast(Table_A, void(*)())(); + } + + static __always_inline void FlushCache() { + register uint32_t FuncID asm("t1") = 0x44; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + __syscall_function_cast(Table_A, void(*)())(); + } + + static __always_inline void* memcpy(void *dst, const void *src, size_t len) { + register uint32_t FuncID asm("t1") = 0x2A; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + return __syscall_function_cast(Table_A, void*(*)(void*, const void*, size_t))(dst, src, len); + } + + static __always_inline ThreadHandle OpenThread(void (*thread_func)(), uint32_t* stack_ptr, uint32_t* gp) { + register uint32_t FuncID asm("t1") = 0x0E; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + return __syscall_function_cast(Table_B, ThreadHandle(*)(void(*)(), uint32_t*, uint32_t*))(thread_func, stack_ptr, gp); + } + + static __always_inline void [[noreturn]] ChangeThread(ThreadHandle handle) { + register uint32_t FuncID asm("t1") = 0x10; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + __syscall_function_cast(Table_B, void(*)(ThreadHandle))(handle); + } + + static __always_inline void InitPad(uint8_t *portA, uint32_t portASize, uint8_t *portB, uint32_t portBSize) { + register uint32_t FuncID asm("t1") = 0x12; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + __syscall_function_cast(Table_B, void(*)(uint8_t*, uint32_t, uint8_t*, uint32_t))(portA, portASize, portB, portBSize); + } + + static __always_inline void StartPad() { + register uint32_t FuncID asm("t1") = 0x13; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + __syscall_function_cast(Table_B, void(*)())(); + } + + static __always_inline void StopPad() { + register uint32_t FuncID asm("t1") = 0x14; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + __syscall_function_cast(Table_B, void(*)())(); + } + + static __always_inline void ChangeClearPad(int32_t _reserved) { + register uint32_t FuncID asm("t1") = 0x5B; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + __syscall_function_cast(Table_B, void(*)(int32_t))(_reserved); + } + + static __always_inline void [[noreturn]] ReturnFromException() { + register uint32_t FuncID asm("t1") = 0x17; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + __syscall_function_cast(Table_B, void(*)())(); + } + + static __always_inline void SetDefaultExitFromException() { + register uint32_t FuncID asm("t1") = 0x18; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + __syscall_function_cast(Table_B, void(*)())(); + } + + static __always_inline int SysEnqIntRP(Priority prio, InterruptCallback* interElm) { + register uint32_t FuncID asm("t1") = 0x02; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + return __syscall_function_cast(Table_C, int(*)(Priority prio, InterruptCallback *interElm))(prio, interElm); + } + + static __always_inline int SysDeqIntRP(Priority prio, InterruptCallback *interElm) { + register uint32_t FuncID asm("t1") = 0x03; + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + + return __syscall_function_cast(Table_C, int(*)(Priority prio, InterruptCallback *interElm))(prio, interElm); + } + + static __always_inline uint32_t EnterCriticalSection() { + register uint32_t FuncID asm("a0") = 0x01; + register uint32_t returnValue asm("v0"); + + __asm__ volatile("syscall" : "=r"(returnValue) : "r"(FuncID) : "memory"); + return returnValue; + } + + static __always_inline void ExitCriticalSection() { + register uint32_t FuncID asm("a0") = 0x02; + + __asm__ volatile("syscall" :: "r"(FuncID) : "memory"); + } + + static __always_inline void DeliverEvent(uint32_t classId, uint32_t spec) { + register uint32_t FuncID asm("t1") = 0x07; + + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + __syscall_function_cast(Table_B, void (*)(uint32_t, uint32_t))(classId, spec); + } + + static __always_inline uint32_t OpenEvent(uint32_t classId, uint32_t spec, uint32_t mode, void (*handler)()) { + register uint32_t FuncID asm("t1") = 0x08; + + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + return __syscall_function_cast(Table_B, uint32_t(*)(uint32_t, uint32_t, uint32_t, void(*)()))(classId, spec, mode, handler); + } + + static __always_inline int CloseEvent(uint32_t event) { + register uint32_t FuncID asm("t1") = 0x09; + + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + return __syscall_function_cast(Table_B, uint32_t(*)(uint32_t))(event); + } + + static __always_inline int32_t TestEvent(uint32_t event) { + register uint32_t FuncID asm("t1") = 0x0B; + + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + return __syscall_function_cast(Table_B, int32_t (*)(uint32_t))(event); + } + + static __always_inline int32_t EnableEvent(uint32_t event) { + register uint32_t FuncID asm("t1") = 0x0C; + + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + return __syscall_function_cast(Table_B, int32_t (*)(uint32_t))(event); + } + + static __always_inline const uint16_t* Krom2RawAdd(uint16_t sjis_code) { + register uint32_t FuncID asm("t1") = 0x51; + + __asm__ volatile("" : "=r"(FuncID) : "r"(FuncID)); + return __syscall_function_cast(Table_B, const uint16_t* (*)(uint16_t))(sjis_code); + } + + void printf(const char* txt, ...); + } } \ No newline at end of file diff --git a/include/PSX/Timer/frame_timer.hpp b/include/PSX/Timer/frame_timer.hpp index 47888d9a..26bd6af2 100644 --- a/include/PSX/Timer/frame_timer.hpp +++ b/include/PSX/Timer/frame_timer.hpp @@ -1,74 +1,74 @@ -#ifndef __JABYENGINE_FRAME_TIMER_HPP__ -#define __JABYENGINE_FRAME_TIMER_HPP__ -#include "frame_time_helper.hpp" -#include - -namespace JabyEngine { - class MasterTime { - __friends: - static uint32_t value; - - public: - static uint32_t read() { - return reinterpret_cast(MasterTime::value); - } - - template - static T read_as() { - return static_cast(MasterTime::read()); - } - }; - - template - class SimpleTimer { - protected: - T value = 0; - - public: - constexpr SimpleTimer() = default; - - static SimpleTimer create() { - SimpleTimer timer; - - timer.reset(); - return timer; - } - - bool is_expired_for(T time) const { - return static_cast((MasterTime::read_as() - this->value)) >= time; - } - - void reset() { - this->value = MasterTime::read_as(); - } - }; - - template - class IntervalTimer : public SimpleTimer { - private: - T interval = 0; - - public: - constexpr IntervalTimer() = default; - constexpr IntervalTimer(T interval) : SimpleTimer(), interval(interval) { - } - - static constexpr IntervalTimer create(T interval) { - IntervalTimer timer; - - static_cast&>(timer) = SimpleTimer::create(); - timer.interval = interval; - return timer; - } - - void set_interval(T interval) { - this->interval = interval; - } - - bool is_expired() const { - return SimpleTimer::is_expired_for(this->interval); - } - }; -} - +#ifndef __JABYENGINE_FRAME_TIMER_HPP__ +#define __JABYENGINE_FRAME_TIMER_HPP__ +#include "frame_time_helper.hpp" +#include + +namespace JabyEngine { + class MasterTime { + __friends: + static uint32_t value; + + public: + static uint32_t read() { + return reinterpret_cast(MasterTime::value); + } + + template + static T read_as() { + return static_cast(MasterTime::read()); + } + }; + + template + class SimpleTimer { + protected: + T value = 0; + + public: + constexpr SimpleTimer() = default; + + static SimpleTimer create() { + SimpleTimer timer; + + timer.reset(); + return timer; + } + + bool is_expired_for(T time) const { + return static_cast((MasterTime::read_as() - this->value)) >= time; + } + + void reset() { + this->value = MasterTime::read_as(); + } + }; + + template + class IntervalTimer : public SimpleTimer { + private: + T interval = 0; + + public: + constexpr IntervalTimer() = default; + constexpr IntervalTimer(T interval) : SimpleTimer(), interval(interval) { + } + + static constexpr IntervalTimer create(T interval) { + IntervalTimer timer; + + static_cast&>(timer) = SimpleTimer::create(); + timer.interval = interval; + return timer; + } + + void set_interval(T interval) { + this->interval = interval; + } + + bool is_expired() const { + return SimpleTimer::is_expired_for(this->interval); + } + }; +} + #endif //!__JABYENGINE_FRAME_TIMER_HPP__ \ No newline at end of file diff --git a/include/PSX/Timer/high_res_timer.hpp b/include/PSX/Timer/high_res_timer.hpp index c3e1626e..e8a1be29 100644 --- a/include/PSX/Timer/high_res_timer.hpp +++ b/include/PSX/Timer/high_res_timer.hpp @@ -1,81 +1,81 @@ -#ifndef __JABYENGINE_HIGH_RES_TIMER_HPP__ -#define __JABYENGINE_HIGH_RES_TIMER_HPP__ -#include "../jabyengine_defines.hpp" -#include -#include - -namespace JabyEngine { - struct CPUTicks { - static constexpr double Frequency_Hz = 33868800.0; - static constexpr double Frequency_Hz_Div8 = (Frequency_Hz/8.0); - - template - static constexpr T ticks_per_ns(double CPU_Frequency_Hz, double time = 1.0) { - return static_cast((time/CPU_Frequency_Hz)*1000.0*1000.0*1000.0); - } - - template - static constexpr T ticks_per_us(double CPU_Frequency_Hz, double time = 1.0) { - return static_cast(((time*1000.0)/ticks_per_ns(CPU_Frequency_Hz))); - } - - template - static constexpr T ticks_per_ms(double CPU_Frequency_Hz, double time = 1.0) { - return static_cast(((time*1000.0*1000.0)/ticks_per_ns(CPU_Frequency_Hz))); - } - }; - - class HighResTime { - public: - class TimeStamp { - private: - uint16_t counter_10ms_value; - uint16_t fraction; - - constexpr TimeStamp(uint16_t counter_10ms_value, uint16_t fraction) : counter_10ms_value(counter_10ms_value), fraction(fraction) { - } - - constexpr static size_t to_us(uint16_t counter_10ms_value, uint16_t fraction) { - return counter_10ms_value*(10*1000) + ((fraction/HighResTime::TicksFor100us)*100); - } - - constexpr static size_t to_ms(uint16_t counter_10ms_value, uint16_t fraction) { - return counter_10ms_value*10 + (fraction/HighResTime::TicksFor1ms); - } - - public: - constexpr size_t microseconds_to(const TimeStamp& end) const { - return TimeStamp::to_us((end.counter_10ms_value - this->counter_10ms_value), (end.fraction - this->fraction)); - } - - constexpr size_t milliseconds_to(const TimeStamp& end) const { - return TimeStamp::to_ms((end.counter_10ms_value - this->counter_10ms_value), (end.fraction - this->fraction)); - } - friend class HighResTime; - }; - - __friends: - static constexpr uint16_t TicksFor100us = CPUTicks::ticks_per_us(CPUTicks::Frequency_Hz_Div8, 100.0); - static constexpr uint16_t TicksFor1ms = CPUTicks::ticks_per_ms(CPUTicks::Frequency_Hz_Div8, 1.0); - static constexpr uint16_t TicksFor10ms = CPUTicks::ticks_per_ms(CPUTicks::Frequency_Hz_Div8, 10.0); - - static volatile uint16_t global_counter_10ms; - - public: - HighResTime() = delete; - ~HighResTime() = delete; - - static void enable() { - Interrupt::enable_irq(Interrupt::Timer2); - } - - static void disable() { - Interrupt::disable_irq(Interrupt::Timer2); - } - - static TimeStamp get_time_stamp() { - return TimeStamp(HighResTime::global_counter_10ms, Timer_IO::Counter2.get_current_value()); - } - }; -} +#ifndef __JABYENGINE_HIGH_RES_TIMER_HPP__ +#define __JABYENGINE_HIGH_RES_TIMER_HPP__ +#include "../jabyengine_defines.hpp" +#include +#include + +namespace JabyEngine { + struct CPUTicks { + static constexpr double Frequency_Hz = 33868800.0; + static constexpr double Frequency_Hz_Div8 = (Frequency_Hz/8.0); + + template + static constexpr T ticks_per_ns(double CPU_Frequency_Hz, double time = 1.0) { + return static_cast((time/CPU_Frequency_Hz)*1000.0*1000.0*1000.0); + } + + template + static constexpr T ticks_per_us(double CPU_Frequency_Hz, double time = 1.0) { + return static_cast(((time*1000.0)/ticks_per_ns(CPU_Frequency_Hz))); + } + + template + static constexpr T ticks_per_ms(double CPU_Frequency_Hz, double time = 1.0) { + return static_cast(((time*1000.0*1000.0)/ticks_per_ns(CPU_Frequency_Hz))); + } + }; + + class HighResTime { + public: + class TimeStamp { + private: + uint16_t counter_10ms_value; + uint16_t fraction; + + constexpr TimeStamp(uint16_t counter_10ms_value, uint16_t fraction) : counter_10ms_value(counter_10ms_value), fraction(fraction) { + } + + constexpr static size_t to_us(uint16_t counter_10ms_value, uint16_t fraction) { + return counter_10ms_value*(10*1000) + ((fraction/HighResTime::TicksFor100us)*100); + } + + constexpr static size_t to_ms(uint16_t counter_10ms_value, uint16_t fraction) { + return counter_10ms_value*10 + (fraction/HighResTime::TicksFor1ms); + } + + public: + constexpr size_t microseconds_to(const TimeStamp& end) const { + return TimeStamp::to_us((end.counter_10ms_value - this->counter_10ms_value), (end.fraction - this->fraction)); + } + + constexpr size_t milliseconds_to(const TimeStamp& end) const { + return TimeStamp::to_ms((end.counter_10ms_value - this->counter_10ms_value), (end.fraction - this->fraction)); + } + friend class HighResTime; + }; + + __friends: + static constexpr uint16_t TicksFor100us = CPUTicks::ticks_per_us(CPUTicks::Frequency_Hz_Div8, 100.0); + static constexpr uint16_t TicksFor1ms = CPUTicks::ticks_per_ms(CPUTicks::Frequency_Hz_Div8, 1.0); + static constexpr uint16_t TicksFor10ms = CPUTicks::ticks_per_ms(CPUTicks::Frequency_Hz_Div8, 10.0); + + static volatile uint16_t global_counter_10ms; + + public: + HighResTime() = delete; + ~HighResTime() = delete; + + static void enable() { + Interrupt::enable_irq(Interrupt::Timer2); + } + + static void disable() { + Interrupt::disable_irq(Interrupt::Timer2); + } + + static TimeStamp get_time_stamp() { + return TimeStamp(HighResTime::global_counter_10ms, Timer_IO::Counter2.get_current_value()); + } + }; +} #endif //!__JABYENGINE_HIGH_RES_TIMER_HPP__ \ No newline at end of file diff --git a/include/PSX/jabyengine_config.hpp b/include/PSX/jabyengine_config.hpp index 64b5cd2a..bf4e473c 100644 --- a/include/PSX/jabyengine_config.hpp +++ b/include/PSX/jabyengine_config.hpp @@ -1,37 +1,37 @@ -#pragma once -#include - -namespace JabyEngine { - struct DefaultConfiguration { - struct BIOSFont { - static constexpr GPU::PositionU16 texture_load_pos() { - return GPU::PositionU16::create(320, 256); - } - - static constexpr GPU::PositionU16 CLUT_load_pos() { - return GPU::PositionU16::create(320, 511); - } - }; - - static constexpr auto DisplayDefaultOffset = GPU::PositionI16::create(0, 0); - - struct Periphery { - static constexpr bool include_portB() { - return false; - } - - static constexpr bool use_multi_tap(){ - return false; - } - }; - }; - - #if __has_include() - #include - using Configuration = CustomConfiguration; - #else - using Configuration = DefaultConfiguration; - #define __SUPPORT_PS3__ - #define __DEBUG_SPU_MMU__ - #endif // has jabyengine_custom_config +#pragma once +#include + +namespace JabyEngine { + struct DefaultConfiguration { + struct BIOSFont { + static constexpr GPU::PositionU16 texture_load_pos() { + return GPU::PositionU16::create(320, 256); + } + + static constexpr GPU::PositionU16 CLUT_load_pos() { + return GPU::PositionU16::create(320, 511); + } + }; + + static constexpr auto DisplayDefaultOffset = GPU::PositionI16::create(0, 0); + + struct Periphery { + static constexpr bool include_portB() { + return false; + } + + static constexpr bool use_multi_tap(){ + return false; + } + }; + }; + + #if __has_include() + #include + using Configuration = CustomConfiguration; + #else + using Configuration = DefaultConfiguration; + #define __SUPPORT_PS3__ + #define __DEBUG_SPU_MMU__ + #endif // has jabyengine_custom_config } \ No newline at end of file diff --git a/include/PSX/jabyengine_defines.hpp b/include/PSX/jabyengine_defines.hpp index b9b19fb9..3a7929f5 100644 --- a/include/PSX/jabyengine_defines.hpp +++ b/include/PSX/jabyengine_defines.hpp @@ -1,16 +1,16 @@ -#pragma once -#include "Auxiliary/literals.hpp" -#include - -#define __used __attribute__((used)) -#define __no_align __attribute__((packed)) -#define __no_inline __attribute__((noinline)) -#define __no_return __attribute__((noreturn)) -#define __always_inline __attribute__((always_inline)) -#define __weak __attribute__((weak)) -#define __section(name) __attribute__((section(name))) -#define __collect(...) __VA_ARGS__ - -#ifndef __friends - #define __friends private +#pragma once +#include "Auxiliary/literals.hpp" +#include + +#define __used __attribute__((used)) +#define __no_align __attribute__((packed)) +#define __no_inline __attribute__((noinline)) +#define __no_return __attribute__((noreturn)) +#define __always_inline __attribute__((always_inline)) +#define __weak __attribute__((weak)) +#define __section(name) __attribute__((section(name))) +#define __collect(...) __VA_ARGS__ + +#ifndef __friends + #define __friends private #endif //!__friends \ No newline at end of file diff --git a/include/math.hpp b/include/math.hpp index a48aa03e..1b0e645c 100644 --- a/include/math.hpp +++ b/include/math.hpp @@ -1,78 +1,78 @@ -#pragma once -#include "stdint.hpp" - -namespace math { - template - struct raw_math { - constexpr T operator-() const { - return T{.raw = static_cast(-(static_cast(*this).raw))}; - } - - constexpr T operator+(const T& obj) const { - return T{.raw = static_cast(*this).raw + obj.raw}; - } - - constexpr T operator-(const T& b) const {} - - constexpr T& operator+=(const T& obj) { - static_cast(*this).raw += obj.raw; - return static_cast(*this); - } - - constexpr T& operator-=(const T& obj) { - static_cast(*this).raw -= obj.raw; - return static_cast(*this); - } - }; -} - -struct deg_t : public math::raw_math { - static constexpr auto full_circle = 32768; - static constexpr auto one_degree = full_circle/360; - static constexpr auto one_tenth_degree = full_circle/3600; - - int16_t raw; - - static constexpr deg_t zero() { - return deg_t{.raw = 0}; - } - - static constexpr deg_t from_degree(int32_t deg) { - return deg_t{.raw = static_cast(deg*one_degree)}; - } - - static constexpr deg_t from_tenth_degree(int32_t deg10) { - return deg_t{.raw = static_cast(deg10*one_tenth_degree)}; - } -}; - -static constexpr deg_t operator""_deg(long double degree) { - return deg_t::from_tenth_degree((degree*10.0)); -} - -struct gte_float : public math::raw_math { - int32_t raw; - - static constexpr gte_float from_double(double value) { - return gte_float{.raw = static_cast(4096.0*value)}; - } - - static constexpr gte_float one() { - return gte_float::from_double(1.0); - } - - constexpr explicit operator int32_t() const { - return this->raw; - } - - constexpr explicit operator int16_t() const { - return static_cast(this->raw); - } -}; - -static constexpr gte_float operator""_gf(long double value) { - return gte_float::from_double(value); -} - -gte_float sin(deg_t value); +#pragma once +#include "stdint.hpp" + +namespace math { + template + struct raw_math { + constexpr T operator-() const { + return T{.raw = static_cast(-(static_cast(*this).raw))}; + } + + constexpr T operator+(const T& obj) const { + return T{.raw = static_cast(*this).raw + obj.raw}; + } + + constexpr T operator-(const T& b) const {} + + constexpr T& operator+=(const T& obj) { + static_cast(*this).raw += obj.raw; + return static_cast(*this); + } + + constexpr T& operator-=(const T& obj) { + static_cast(*this).raw -= obj.raw; + return static_cast(*this); + } + }; +} + +struct deg_t : public math::raw_math { + static constexpr auto full_circle = 32768; + static constexpr auto one_degree = full_circle/360; + static constexpr auto one_tenth_degree = full_circle/3600; + + int16_t raw; + + static constexpr deg_t zero() { + return deg_t{.raw = 0}; + } + + static constexpr deg_t from_degree(int32_t deg) { + return deg_t{.raw = static_cast(deg*one_degree)}; + } + + static constexpr deg_t from_tenth_degree(int32_t deg10) { + return deg_t{.raw = static_cast(deg10*one_tenth_degree)}; + } +}; + +static constexpr deg_t operator""_deg(long double degree) { + return deg_t::from_tenth_degree((degree*10.0)); +} + +struct gte_float : public math::raw_math { + int32_t raw; + + static constexpr gte_float from_double(double value) { + return gte_float{.raw = static_cast(4096.0*value)}; + } + + static constexpr gte_float one() { + return gte_float::from_double(1.0); + } + + constexpr explicit operator int32_t() const { + return this->raw; + } + + constexpr explicit operator int16_t() const { + return static_cast(this->raw); + } +}; + +static constexpr gte_float operator""_gf(long double value) { + return gte_float::from_double(value); +} + +gte_float sin(deg_t value); gte_float cos(deg_t value); \ No newline at end of file diff --git a/include/stdarg.hpp b/include/stdarg.hpp index d4c85692..440c2d5e 100644 --- a/include/stdarg.hpp +++ b/include/stdarg.hpp @@ -1,7 +1,7 @@ -#pragma once - -using va_list = __builtin_va_list; -#define va_start __builtin_va_start -#define va_end __builtin_va_end -#define next_arg __builtin_next_arg +#pragma once + +using va_list = __builtin_va_list; +#define va_start __builtin_va_start +#define va_end __builtin_va_end +#define next_arg __builtin_next_arg #define va_arg __builtin_va_arg \ No newline at end of file diff --git a/include/stdio.hpp b/include/stdio.hpp index 79fcaf81..99d3d1ca 100644 --- a/include/stdio.hpp +++ b/include/stdio.hpp @@ -1,4 +1,4 @@ -#pragma once -#include "PSX/jabyengine_defines.hpp" - +#pragma once +#include "PSX/jabyengine_defines.hpp" + int printf(const char* txt, ...) asm("_ZN10JabyEngine7SysCall6printfEPKcz"); \ No newline at end of file diff --git a/include/string.hpp b/include/string.hpp index 072c20b8..7d4a3647 100644 --- a/include/string.hpp +++ b/include/string.hpp @@ -1,10 +1,10 @@ -#pragma once -#include "PSX/jabyengine_defines.hpp" - -int strncmp(const char* s1, const char* s2, size_t n); -size_t strlen(const char* str); - -extern "C" { - // Needs to be provided for GCC optimizations - void* memset(void* dest, int val, size_t len); +#pragma once +#include "PSX/jabyengine_defines.hpp" + +int strncmp(const char* s1, const char* s2, size_t n); +size_t strlen(const char* str); + +extern "C" { + // Needs to be provided for GCC optimizations + void* memset(void* dest, int val, size_t len); } \ No newline at end of file diff --git a/license b/license index 94a198ab..257f5d23 100644 --- a/license +++ b/license @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2025 Jaby - -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 +MIT License + +Copyright (c) 2025 Jaby + +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. \ No newline at end of file diff --git a/mkfile/ISOMakefile.mk b/mkfile/ISOMakefile.mk index 4799aa2b..81971b0a 100644 --- a/mkfile/ISOMakefile.mk +++ b/mkfile/ISOMakefile.mk @@ -1,23 +1,23 @@ -CD_OUTPUT ?= $(REGION)/$(ARTIFACT).bin -PKG_OUTPUT ?= $(REGION)/$(ARTIFACT).pkg - -$(CD_OUTPUT): always - @mkdir -p $(REGION) - psxcdgen_ex --list $(REGION)/$(ARTIFACT).lba -o $(REGION)/$(ARTIFACT) bin-cue Config.xml - -$(PKG_OUTPUT): always - @mkdir -p $(REGION) - @echo "!!PKG generation is experimentel!!" - run_pop_fe.sh $(ARTIFACT) $(shell pwd)/../assets/pkg $(shell pwd)/$(REGION)/$(ARTIFACT).cue - -all: $(CD_OUTPUT) -clean: pkg_clean - rm -fr $(REGION)/*.bin - rm -fr $(REGION)/*.cue - rm -fr $(REGION)/*.lba - -pkg_all: $(PKG_OUTPUT) -pkg_clean: - rm -fr $(REGION)/*.pkg - +CD_OUTPUT ?= $(REGION)/$(ARTIFACT).bin +PKG_OUTPUT ?= $(REGION)/$(ARTIFACT).pkg + +$(CD_OUTPUT): always + @mkdir -p $(REGION) + psxcdgen_ex --list $(REGION)/$(ARTIFACT).lba -o $(REGION)/$(ARTIFACT) bin-cue Config.xml + +$(PKG_OUTPUT): always + @mkdir -p $(REGION) + @echo "!!PKG generation is experimentel!!" + run_pop_fe.sh $(ARTIFACT) $(shell pwd)/../assets/pkg $(shell pwd)/$(REGION)/$(ARTIFACT).cue + +all: $(CD_OUTPUT) +clean: pkg_clean + rm -fr $(REGION)/*.bin + rm -fr $(REGION)/*.cue + rm -fr $(REGION)/*.lba + +pkg_all: $(PKG_OUTPUT) +pkg_clean: + rm -fr $(REGION)/*.pkg + always: ; \ No newline at end of file diff --git a/mkfile/Makefile b/mkfile/Makefile index 4aa1e396..da1535e2 100644 --- a/mkfile/Makefile +++ b/mkfile/Makefile @@ -1,98 +1,98 @@ -SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST))) -include $(SELF_DIR)common/ExportPath.mk - -substitute = $(subst $(JABY_ENGINE_DIR)/include/modules,!JABYENGINEMODULES,$(subst ..,!super,$1)) -desubstitute = $(subst !JABYENGINEMODULES,$(JABY_ENGINE_DIR)/include/modules,$(subst !super,..,$1)) - -#Build architecture/variant string, possible values: x86, armv7le, etc... -PLATFORM ?= PSX - -#Build profile, possible values: release, debug, profile, coverage -BUILD_DIR ?= bin/$(PSX_TV_FORMAT) -BUILD_PROFILE ?= debug -PSX_TV_FORMAT ?= PAL - -CONFIG_NAME ?= $(PLATFORM)-$(BUILD_PROFILE) -OUTPUT_DIR = $(BUILD_DIR)/$(CONFIG_NAME) -TARGET = $(OUTPUT_DIR)/$(ARTIFACT) - -#Compiler definitions -HAS_LINUX_MIPS_GCC = $(shell which mipsel-linux-gnu-gcc > /dev/null 2> /dev/null && echo true || echo false) -ifeq ($(HAS_LINUX_MIPS_GCC),true) -PREFIX ?= mipsel-linux-gnu -FORMAT ?= elf32-tradlittlemips -else -PREFIX ?= mipsel-none-elf -FORMAT ?= elf32-littlemips -endif - -#Take this to PSEXETarget.mk?? -#LDSCRIPT ?= $(PSCX_REDUX_DIR)/ps-exe.ld -#ifneq ($(strip $(OVERLAYSCRIPT)),) -#LDSCRIPT := $(addprefix $(OVERLAYSCRIPT) , -T$(LDSCRIPT)) -#else -#LDSCRIPT := $(addprefix $(PSCX_REDUX_DIR)/default.ld , -T$(LDSCRIPT)) -#endif - -CC = $(PREFIX)-gcc -CXX = $(PREFIX)-g++ -LD = $(CXX) -AR = ar - -#architecture flags -ARCHFLAGS = -march=r2000 -mtune=r2000 -mabi=32 -EL -fno-pic -mno-shared -nostdinc -nostdinc++ -mno-abicalls -mfp32 -mno-llsc -ARCHFLAGS += -fno-stack-protector -nostdlib -ffreestanding - -#Compiler flags for build profiles -CCFLAGS_release += -O3 -CCFLAGS_debug += -O0 - -CXXFLAGS += -fno-exceptions -fno-rtti -fno-threadsafe-statics - -CCFLAGS += -mno-gpopt -fomit-frame-pointer -ffunction-sections -fdata-sections -CCFLAGS += -fno-builtin -fno-strict-aliasing -Wno-attributes -CCFLAGS += -std=c++20 -fmodules-ts -CCFLAGS += $(CCFLAGS_$(BUILD_PROFILE)) -CCFLAGS += $(ARCHFLAGS) -CCFLAGS += $(INCLUDES) -CCFLAGS += -DJABYENGINE_$(PSX_TV_FORMAT) - -#Linker flags -LDFLAGS_release += -Os - -LDFLAGS_all += -Wl,-Map=$(TARGET).map -nostdlib -T$(JABY_ENGINE_DIR)/mkfile/psexe.ld -static -Wl,--gc-sections -Wl,--build-id=none -Wl,--no-check-sections -LDFLAGS_all += $(ARCHFLAGS) -Wl,--oformat=$(FORMAT) -LDFLAGS_all += $(LDFLAGS_$(BUILD_PROFILE)) - -LIBS_all += $(LIBS_$(BUILD_PROFILE)) - -DEPS = -Wp,-MMD,$(@:%.o=%.d),-MT,$@ - -#Object files list -MODS += $(call rwildcard,$(JABY_ENGINE_DIR)/include/modules, cxx) -SRCS := $(MODS) $(SRCS) -OBJS = $(addprefix $(OUTPUT_DIR)/,$(addsuffix .o, $(call substitute,$(basename $(SRCS))))) - -#Compiling rule -.SECONDEXPANSION: -$(OUTPUT_DIR)/%.o: $$(call desubstitute,%.s) - @mkdir -p $(dir $@) - $(CC) -c $(DEPS) -o $@ $(CCFLAGS) $< - -.SECONDEXPANSION: -$(OUTPUT_DIR)/%.o: $$(call desubstitute,%.c) - @mkdir -p $(dir $@) - $(CC) -c $(DEPS) -o $@ $(CCFLAGS) $< - -.SECONDEXPANSION: -$(OUTPUT_DIR)/%.o: $$(call desubstitute,%.cpp) - @mkdir -p $(dir $@) - $(CXX) -c $(DEPS) -o $@ $(CCFLAGS) $(CXXFLAGS) $< - -.SECONDEXPANSION: -$(OUTPUT_DIR)/%.o: $$(call desubstitute,%.cxx) - @mkdir -p $(dir $@) - $(CXX) -c $(DEPS) -o $@ $(CCFLAGS) $(CXXFLAGS) $< - -#Inclusion of dependencies (object files to source and includes) +SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST))) +include $(SELF_DIR)common/ExportPath.mk + +substitute = $(subst $(JABY_ENGINE_DIR)/include/modules,!JABYENGINEMODULES,$(subst ..,!super,$1)) +desubstitute = $(subst !JABYENGINEMODULES,$(JABY_ENGINE_DIR)/include/modules,$(subst !super,..,$1)) + +#Build architecture/variant string, possible values: x86, armv7le, etc... +PLATFORM ?= PSX + +#Build profile, possible values: release, debug, profile, coverage +BUILD_DIR ?= bin/$(PSX_TV_FORMAT) +BUILD_PROFILE ?= debug +PSX_TV_FORMAT ?= PAL + +CONFIG_NAME ?= $(PLATFORM)-$(BUILD_PROFILE) +OUTPUT_DIR = $(BUILD_DIR)/$(CONFIG_NAME) +TARGET = $(OUTPUT_DIR)/$(ARTIFACT) + +#Compiler definitions +HAS_LINUX_MIPS_GCC = $(shell which mipsel-linux-gnu-gcc > /dev/null 2> /dev/null && echo true || echo false) +ifeq ($(HAS_LINUX_MIPS_GCC),true) +PREFIX ?= mipsel-linux-gnu +FORMAT ?= elf32-tradlittlemips +else +PREFIX ?= mipsel-none-elf +FORMAT ?= elf32-littlemips +endif + +#Take this to PSEXETarget.mk?? +#LDSCRIPT ?= $(PSCX_REDUX_DIR)/ps-exe.ld +#ifneq ($(strip $(OVERLAYSCRIPT)),) +#LDSCRIPT := $(addprefix $(OVERLAYSCRIPT) , -T$(LDSCRIPT)) +#else +#LDSCRIPT := $(addprefix $(PSCX_REDUX_DIR)/default.ld , -T$(LDSCRIPT)) +#endif + +CC = $(PREFIX)-gcc +CXX = $(PREFIX)-g++ +LD = $(CXX) +AR = ar + +#architecture flags +ARCHFLAGS = -march=r2000 -mtune=r2000 -mabi=32 -EL -fno-pic -mno-shared -nostdinc -nostdinc++ -mno-abicalls -mfp32 -mno-llsc +ARCHFLAGS += -fno-stack-protector -nostdlib -ffreestanding + +#Compiler flags for build profiles +CCFLAGS_release += -O3 +CCFLAGS_debug += -O0 + +CXXFLAGS += -fno-exceptions -fno-rtti -fno-threadsafe-statics + +CCFLAGS += -mno-gpopt -fomit-frame-pointer -ffunction-sections -fdata-sections +CCFLAGS += -fno-builtin -fno-strict-aliasing -Wno-attributes +CCFLAGS += -std=c++20 -fmodules-ts +CCFLAGS += $(CCFLAGS_$(BUILD_PROFILE)) +CCFLAGS += $(ARCHFLAGS) +CCFLAGS += $(INCLUDES) +CCFLAGS += -DJABYENGINE_$(PSX_TV_FORMAT) + +#Linker flags +LDFLAGS_release += -Os + +LDFLAGS_all += -Wl,-Map=$(TARGET).map -nostdlib -T$(JABY_ENGINE_DIR)/mkfile/psexe.ld -static -Wl,--gc-sections -Wl,--build-id=none -Wl,--no-check-sections +LDFLAGS_all += $(ARCHFLAGS) -Wl,--oformat=$(FORMAT) +LDFLAGS_all += $(LDFLAGS_$(BUILD_PROFILE)) + +LIBS_all += $(LIBS_$(BUILD_PROFILE)) + +DEPS = -Wp,-MMD,$(@:%.o=%.d),-MT,$@ + +#Object files list +MODS += $(call rwildcard,$(JABY_ENGINE_DIR)/include/modules, cxx) +SRCS := $(MODS) $(SRCS) +OBJS = $(addprefix $(OUTPUT_DIR)/,$(addsuffix .o, $(call substitute,$(basename $(SRCS))))) + +#Compiling rule +.SECONDEXPANSION: +$(OUTPUT_DIR)/%.o: $$(call desubstitute,%.s) + @mkdir -p $(dir $@) + $(CC) -c $(DEPS) -o $@ $(CCFLAGS) $< + +.SECONDEXPANSION: +$(OUTPUT_DIR)/%.o: $$(call desubstitute,%.c) + @mkdir -p $(dir $@) + $(CC) -c $(DEPS) -o $@ $(CCFLAGS) $< + +.SECONDEXPANSION: +$(OUTPUT_DIR)/%.o: $$(call desubstitute,%.cpp) + @mkdir -p $(dir $@) + $(CXX) -c $(DEPS) -o $@ $(CCFLAGS) $(CXXFLAGS) $< + +.SECONDEXPANSION: +$(OUTPUT_DIR)/%.o: $$(call desubstitute,%.cxx) + @mkdir -p $(dir $@) + $(CXX) -c $(DEPS) -o $@ $(CCFLAGS) $(CXXFLAGS) $< + +#Inclusion of dependencies (object files to source and includes) -include $(OBJS:%.o=%.d) \ No newline at end of file diff --git a/mkfile/PSEXETarget.mk b/mkfile/PSEXETarget.mk index ac315988..d3a6f427 100644 --- a/mkfile/PSEXETarget.mk +++ b/mkfile/PSEXETarget.mk @@ -1,40 +1,40 @@ -#Not intended to be overriden -AUTO_OVERLAY_DIR = $(OUTPUT_DIR)/auto_overlay - -include $(AUTO_OVERLAY_DIR)/Overlays.mk -include $(JABY_ENGINE_DIR)/mkfile/common/CustomConfigHelper.mk - -JABY_ENGINE_LIB_DIR = $(JABY_ENGINE_DIR)/lib/PSX-$(BUILD_PROFILE)/$(CUSTOM_CONFIG) -JABY_ENGINE_SUPPORT_LIB_DIR = $(JABY_ENGINE_DIR)/support/lib/PSX-$(BUILD_PROFILE) -JABY_ENGINE_SUPPORT_LIBS = $(addprefix -l,$(SUPPORT_LIBS)) -JABY_ENGINE_SUPPORT_DEPS = $(addsuffix .a,$(addprefix $(JABY_ENGINE_SUPPORT_LIB_DIR)/lib,$(SUPPORT_LIBS))) -JABY_ENGINE_LIB_NAME = JabyEngine_$(PSX_TV_FORMAT) - -OVERLAY_TARGET = $(foreach ovl, $(OVERLAYSECTION), $(OUTPUT_DIR)/Overlay$(ovl)) - -#Linking rule -$(TARGET).elf: $(OBJS) $(JABY_ENGINE_LIB_DIR)/lib$(JABY_ENGINE_LIB_NAME).a $(JABY_ENGINE_SUPPORT_DEPS) $(AUTO_OVERLAY_DIR)/Overlays.ld - $(LD) -o $(TARGET).elf $(LDFLAGS_all) $(LDFLAGS) $(OBJS) -L$(JABY_ENGINE_LIB_DIR) -L$(JABY_ENGINE_SUPPORT_LIB_DIR) -L$(AUTO_OVERLAY_DIR) -l$(JABY_ENGINE_LIB_NAME) $(LIBS) $(JABY_ENGINE_SUPPORT_LIBS) - -#Strips the psexe -$(TARGET).psexe: $(TARGET).elf - $(PREFIX)-objcopy $(addprefix -R , $(OVERLAYSECTION)) -O binary $< $@ - -#Create overlays -$(OVERLAY_TARGET): $(TARGET).elf - $(PREFIX)-objcopy -j $(suffix $@) -O binary $< $@ - -#Create overlay makefile -$(AUTO_OVERLAY_DIR)/Overlays.mk: $(OVERLAY_CONFIG) - @mkdir -p $(AUTO_OVERLAY_DIR) - mkoverlay --mk-file $(AUTO_OVERLAY_DIR)/Overlays.mk --ld-script $(AUTO_OVERLAY_DIR)/Overlays.ld $< - -#Rules section for default compilation and linking -all: $(TARGET).psexe $(OVERLAY_TARGET) - -clean: - rm -fr $(OUTPUT_DIR) - -# For mkoverlay to function correctly this is required (otherwise Overlays.mk is not re-generated) -rebuild: clean - $(MAKE) all +#Not intended to be overriden +AUTO_OVERLAY_DIR = $(OUTPUT_DIR)/auto_overlay + +include $(AUTO_OVERLAY_DIR)/Overlays.mk +include $(JABY_ENGINE_DIR)/mkfile/common/CustomConfigHelper.mk + +JABY_ENGINE_LIB_DIR = $(JABY_ENGINE_DIR)/lib/PSX-$(BUILD_PROFILE)/$(CUSTOM_CONFIG) +JABY_ENGINE_SUPPORT_LIB_DIR = $(JABY_ENGINE_DIR)/support/lib/PSX-$(BUILD_PROFILE) +JABY_ENGINE_SUPPORT_LIBS = $(addprefix -l,$(SUPPORT_LIBS)) +JABY_ENGINE_SUPPORT_DEPS = $(addsuffix .a,$(addprefix $(JABY_ENGINE_SUPPORT_LIB_DIR)/lib,$(SUPPORT_LIBS))) +JABY_ENGINE_LIB_NAME = JabyEngine_$(PSX_TV_FORMAT) + +OVERLAY_TARGET = $(foreach ovl, $(OVERLAYSECTION), $(OUTPUT_DIR)/Overlay$(ovl)) + +#Linking rule +$(TARGET).elf: $(OBJS) $(JABY_ENGINE_LIB_DIR)/lib$(JABY_ENGINE_LIB_NAME).a $(JABY_ENGINE_SUPPORT_DEPS) $(AUTO_OVERLAY_DIR)/Overlays.ld + $(LD) -o $(TARGET).elf $(LDFLAGS_all) $(LDFLAGS) $(OBJS) -L$(JABY_ENGINE_LIB_DIR) -L$(JABY_ENGINE_SUPPORT_LIB_DIR) -L$(AUTO_OVERLAY_DIR) -l$(JABY_ENGINE_LIB_NAME) $(LIBS) $(JABY_ENGINE_SUPPORT_LIBS) + +#Strips the psexe +$(TARGET).psexe: $(TARGET).elf + $(PREFIX)-objcopy $(addprefix -R , $(OVERLAYSECTION)) -O binary $< $@ + +#Create overlays +$(OVERLAY_TARGET): $(TARGET).elf + $(PREFIX)-objcopy -j $(suffix $@) -O binary $< $@ + +#Create overlay makefile +$(AUTO_OVERLAY_DIR)/Overlays.mk: $(OVERLAY_CONFIG) + @mkdir -p $(AUTO_OVERLAY_DIR) + mkoverlay --mk-file $(AUTO_OVERLAY_DIR)/Overlays.mk --ld-script $(AUTO_OVERLAY_DIR)/Overlays.ld $< + +#Rules section for default compilation and linking +all: $(TARGET).psexe $(OVERLAY_TARGET) + +clean: + rm -fr $(OUTPUT_DIR) + +# For mkoverlay to function correctly this is required (otherwise Overlays.mk is not re-generated) +rebuild: clean + $(MAKE) all diff --git a/mkfile/common/CustomConfigHelper.mk b/mkfile/common/CustomConfigHelper.mk index 35bdb867..a8d7c36b 100644 --- a/mkfile/common/CustomConfigHelper.mk +++ b/mkfile/common/CustomConfigHelper.mk @@ -1,4 +1,4 @@ -JABY_ENGINE_CONFIG_DIR = $(JABY_ENGINE_DIR)config -ifdef CUSTOM_CONFIG - CCFLAGS += -I$(JABY_ENGINE_CONFIG_DIR)/$(CUSTOM_CONFIG) -imacros $(JABY_ENGINE_CONFIG_DIR)/$(CUSTOM_CONFIG)/jabyengine_custom_config.hpp +JABY_ENGINE_CONFIG_DIR = $(JABY_ENGINE_DIR)config +ifdef CUSTOM_CONFIG + CCFLAGS += -I$(JABY_ENGINE_CONFIG_DIR)/$(CUSTOM_CONFIG) -imacros $(JABY_ENGINE_CONFIG_DIR)/$(CUSTOM_CONFIG)/jabyengine_custom_config.hpp endif \ No newline at end of file diff --git a/mkfile/common/ExportPath.mk b/mkfile/common/ExportPath.mk index 2cbdb7a7..fcc3b8d3 100644 --- a/mkfile/common/ExportPath.mk +++ b/mkfile/common/ExportPath.mk @@ -1,2 +1,2 @@ -#Add the JabyEngine tools to path +#Add the JabyEngine tools to path export PATH := $(JABY_ENGINE_DIR)/bin/:$(PATH) \ No newline at end of file diff --git a/mkfile/common/RebuildTarget.mk b/mkfile/common/RebuildTarget.mk index c26595ee..635f19ac 100644 --- a/mkfile/common/RebuildTarget.mk +++ b/mkfile/common/RebuildTarget.mk @@ -1,3 +1,3 @@ -rebuild: - $(MAKE) clean +rebuild: + $(MAKE) clean $(MAKE) all \ No newline at end of file diff --git a/mkfile/common/Wildcard.mk b/mkfile/common/Wildcard.mk index b16caa2e..d86f7509 100644 --- a/mkfile/common/Wildcard.mk +++ b/mkfile/common/Wildcard.mk @@ -1,2 +1,2 @@ -#Macro to expand files recursively: parameters $1 - directory, $2 - extension, i.e. cpp +#Macro to expand files recursively: parameters $1 - directory, $2 - extension, i.e. cpp rwildcard = $(wildcard $(addprefix $1/*.,$2)) $(foreach d,$(wildcard $1/*),$(call rwildcard,$d,$2)) \ No newline at end of file diff --git a/mkfile/psexe.ld b/mkfile/psexe.ld index 8b672b79..993250a4 100644 --- a/mkfile/psexe.ld +++ b/mkfile/psexe.ld @@ -1,262 +1,262 @@ -/* - -MIT License - -Copyright (c) 2019 PCSX-Redux authors - -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. - -*/ - -OUTPUT_FORMAT("binary") -EXTERN(_ZN10JabyEngine5startEv) -ENTRY(_ZN10JabyEngine5startEv) - -TLOAD_ADDR = DEFINED(TLOAD_ADDR) ? TLOAD_ADDR : 0x80010000; - -MEMORY { - zero : ORIGIN = 0x0 LENGTH = 0x100 - bios : ORIGIN = 0x100, LENGTH = 0x500 - loader : ORIGIN = (TLOAD_ADDR - 0x800), LENGTH = 2048 - ram(rwx) : ORIGIN = 0x80010000, LENGTH = 2M - 0x10000 - ram_alt(rwx) : ORIGIN = 0x80010000, LENGTH = 2M - 0x10000 - dcache : ORIGIN = 0x1f800000, LENGTH = 0x400 -} - -__ram_top = ORIGIN(ram) + LENGTH(ram); -__sp = __ram_top - 0x100; - -__dcache = ORIGIN(dcache); -__dcache_top = ORIGIN(dcache) + LENGTH(dcache); - -__bss_len = (__bss_end - __bss_start); -__ftext_len = (__ftext_end - __ftext_start); -__fdata_len = (__planschi_end - __fdata_start); -__persistent_lbas_len = (__persistent_lbas_end - __persistent_lbas_start); - -__stack_start = ORIGIN(ram) + LENGTH(ram); - - -SECTIONS { - .zero (NOLOAD) : { - _ZN10JabyEngine3SPU5voiceE = .; - } > zero - - .bios (NOLOAD) : { - _ZN10JabyEngine15table_of_tablesE = .; - } > bios - - /DISCARD/ : { *(.MIPS.abiflags) } - - /* Everything is statically linked, so discard PLTs. */ - /DISCARD/ : { *(.rel.iplt) *(.rela.iplt) *(.rel.plt) *(.rela.plt) *(.plt) *(.iplt) } - - /* Discard things that the standard link script drops, too. */ - /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) *(.gnu.*) *(.comment) } -} - -/*Overlay sections created by mkoverlay*/ -INCLUDE Overlays.ld -SECTIONS { - .planschi __engine_bss_end : SUBALIGN(4) - { - __planschi_start = .; - __boot_loader_start = .; - - *libJabyEngine_*.a:*_boot.o(.text.startup._GLOBAL__*) - *_boot.o(.text.startup._GLOBAL__*) - *libJabyEngine_*.a:*_boot.o(.ctors) - *_boot.o(.ctors) - - *libJabyEngine_*.a:*_boot.o(.text.*) - *_boot.o(.text.*) - *libJabyEngine_*.a:*_boot.o(.rodata*) - *_boot.o(.rodata*) - *libJabyEngine_*.a:*_boot.o(.sdata*) - *_boot.o(.sdata*) - *libJabyEngine_*.a:*_boot.o(.data*) - *_boot.o(.data*) - *libJabyEngine_*.a:*_boot.o(.sbss*) - *_boot.o(.sbss*) - *libJabyEngine_*.a:*_boot.o(.bss*) - *_boot.o(.bss*) - *libJabyEngine_*.a:*_boot.o(*) - *_boot.o(*) - - . = ALIGN(4); - __boot_loader_end = .; - /*Only needed for the PSX BIOS to load the entire game*/ - . = ALIGN(2048); - __planschi_end = .; - } > ram -} - -SECTIONS { - .PSX_EXE_Header : { - /* - 0x0000 - 0x0007 : "PS-X EXE" - */ - BYTE(80); BYTE(83); BYTE(45); BYTE(88); BYTE(32); BYTE(69); BYTE(88); BYTE(69); - - /* 0x0008 - 0x000F : skip text_off and data_off since they're not supported by the PS1 BIOS */ - LONG(0); LONG(0); - - /* 0x0010 - 0x0013 : entry point */ - LONG(ABSOLUTE(_ZN10JabyEngine5startEv)); - - /* 0x0014 - 0x0017 : initial value of $gp */ - LONG(0); - - /* 0x0018 - 0x001B : Memory address to load "text" section to. */ - /* - NOTE: The "text" section is actually all of the "load" - sections of the file including .text, .rodata, .data. - etc. - */ - LONG(TLOAD_ADDR); - - /* 0x001C - 0x001F : size, in bytes, of the "text" section. */ - LONG(__persistent_lbas_len + __ftext_len + __fdata_len); - - /* 0x0020 - 0x002F : - Skip "data_addr", "data_size", "bss_addr" and "bss_size". - None of these are supported by retail PS1 BIOS. - */ - LONG(0); LONG(0); - LONG(0); LONG(0); - - /* 0x0030 - 0x0033 : Initial stack address. */ - LONG(DEFINED(_sp) ? ABSOLUTE(_sp) : 0x801FFF00); - - /* 0x0034 - 0x0037 : Initial stack size, set it to 0. */ - LONG(0); - - /* Skip the remaining fields as they're not supported by the BIOS */ - /* e.g. 2048 header bytes minus whatever we've actually used */ - . = . + 1992; - } > loader - - .persistent_lbas TLOAD_ADDR : { - __persistent_lbas_start = .; - __persistent_lbas = .; - KEEP(*(.header.lbas)) - . = ALIGN(4); - __persistent_lbas_end = .; - } > ram - - __ftext_start = ABSOLUTE(.); - .text : { - __text_start = .; - *(.start) - *(.init) - KEEP (*(SORT_NONE(.fini))) - *(.text.unlikely .text.*_unlikely .text.unlikely.*) - *(.text.exit .text.exit.*) - *(.text.startup .text.startup.*) - *(.text.hot .text.hot.*) - *(.text .stub .text.* .gnu.linkonce.t.*) - - . = ALIGN(16); - KEEP(*(.init)) - . = ALIGN(16); - KEEP(*(.fini)) - . = ALIGN(16); - __text_end = .; - } > ram - __ftext_end = ABSOLUTE(.); - - __fdata_start = ABSOLUTE(.); - .rodata : { - *(.rodata .rodata.* .rdata .rdata.* .gnu.linkonce.r.*) - . = ALIGN(16); - __preinit_array_start = .; - KEEP (*(.preinit_array)) - __preinit_array_end = .; - - . = ALIGN(16); - __init_array_start = .; - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - - . = ALIGN(16); - KEEP (*crtbegin.o(.ctors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*crtend.o(.ctors)) - __init_array_end = .; - - . = ALIGN(16); - __fini_array_start = .; - KEEP (*(.fini_array)) - KEEP (*(SORT(.fini_array.*))) - - KEEP (*crtbegin.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*crtend.o(.dtors)) - __fini_array_end = .; - __build_id = .; - *(.note.gnu.build-id) - __build_id_end = .; - } > ram - - .rodata1 : { - *(.rodata1) - } > ram - - .data : { - __data_start = .; - *(.a0table) - *(.data .data.* .gnu.linkonce.d.*) - *(.data1) - *(.sdata .sdata.* .gnu.linkonce.s.*) - *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) - *(.got.plt) - *(.got) - __data_end = .; - } > ram - - .engine_bss : { - __engine_bss_start = .; - *libJabyEngine_*.a:*(.dynsbss) - *libJabyEngine_*.a:*(.sbss .sbss.* .gnu.linkonce.sb.*) - *libJabyEngine_*.a:*(.scommon) - *libJabyEngine_*.a:*(.dynbss) - *libJabyEngine_*.a:*(.bss .bss.* .gnu.linkonce.b.*) - *libJabyEngine_*.a:*(COMMON) - . = ALIGN(4); - __engine_bss_end = .; - } > ram - __fdata_end = .; - - .bss __persistent_overlay_end (NOLOAD) : { - __bss_start = .; - *(.dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - . = ALIGN(4); - __bss_end = .; - } > ram - - __heap_start = __bss_end; - __end = .; +/* + +MIT License + +Copyright (c) 2019 PCSX-Redux authors + +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. + +*/ + +OUTPUT_FORMAT("binary") +EXTERN(_ZN10JabyEngine5startEv) +ENTRY(_ZN10JabyEngine5startEv) + +TLOAD_ADDR = DEFINED(TLOAD_ADDR) ? TLOAD_ADDR : 0x80010000; + +MEMORY { + zero : ORIGIN = 0x0 LENGTH = 0x100 + bios : ORIGIN = 0x100, LENGTH = 0x500 + loader : ORIGIN = (TLOAD_ADDR - 0x800), LENGTH = 2048 + ram(rwx) : ORIGIN = 0x80010000, LENGTH = 2M - 0x10000 + ram_alt(rwx) : ORIGIN = 0x80010000, LENGTH = 2M - 0x10000 + dcache : ORIGIN = 0x1f800000, LENGTH = 0x400 +} + +__ram_top = ORIGIN(ram) + LENGTH(ram); +__sp = __ram_top - 0x100; + +__dcache = ORIGIN(dcache); +__dcache_top = ORIGIN(dcache) + LENGTH(dcache); + +__bss_len = (__bss_end - __bss_start); +__ftext_len = (__ftext_end - __ftext_start); +__fdata_len = (__planschi_end - __fdata_start); +__persistent_lbas_len = (__persistent_lbas_end - __persistent_lbas_start); + +__stack_start = ORIGIN(ram) + LENGTH(ram); + + +SECTIONS { + .zero (NOLOAD) : { + _ZN10JabyEngine3SPU5voiceE = .; + } > zero + + .bios (NOLOAD) : { + _ZN10JabyEngine15table_of_tablesE = .; + } > bios + + /DISCARD/ : { *(.MIPS.abiflags) } + + /* Everything is statically linked, so discard PLTs. */ + /DISCARD/ : { *(.rel.iplt) *(.rela.iplt) *(.rel.plt) *(.rela.plt) *(.plt) *(.iplt) } + + /* Discard things that the standard link script drops, too. */ + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) *(.gnu.*) *(.comment) } +} + +/*Overlay sections created by mkoverlay*/ +INCLUDE Overlays.ld +SECTIONS { + .planschi __engine_bss_end : SUBALIGN(4) + { + __planschi_start = .; + __boot_loader_start = .; + + *libJabyEngine_*.a:*_boot.o(.text.startup._GLOBAL__*) + *_boot.o(.text.startup._GLOBAL__*) + *libJabyEngine_*.a:*_boot.o(.ctors) + *_boot.o(.ctors) + + *libJabyEngine_*.a:*_boot.o(.text.*) + *_boot.o(.text.*) + *libJabyEngine_*.a:*_boot.o(.rodata*) + *_boot.o(.rodata*) + *libJabyEngine_*.a:*_boot.o(.sdata*) + *_boot.o(.sdata*) + *libJabyEngine_*.a:*_boot.o(.data*) + *_boot.o(.data*) + *libJabyEngine_*.a:*_boot.o(.sbss*) + *_boot.o(.sbss*) + *libJabyEngine_*.a:*_boot.o(.bss*) + *_boot.o(.bss*) + *libJabyEngine_*.a:*_boot.o(*) + *_boot.o(*) + + . = ALIGN(4); + __boot_loader_end = .; + /*Only needed for the PSX BIOS to load the entire game*/ + . = ALIGN(2048); + __planschi_end = .; + } > ram +} + +SECTIONS { + .PSX_EXE_Header : { + /* + 0x0000 - 0x0007 : "PS-X EXE" + */ + BYTE(80); BYTE(83); BYTE(45); BYTE(88); BYTE(32); BYTE(69); BYTE(88); BYTE(69); + + /* 0x0008 - 0x000F : skip text_off and data_off since they're not supported by the PS1 BIOS */ + LONG(0); LONG(0); + + /* 0x0010 - 0x0013 : entry point */ + LONG(ABSOLUTE(_ZN10JabyEngine5startEv)); + + /* 0x0014 - 0x0017 : initial value of $gp */ + LONG(0); + + /* 0x0018 - 0x001B : Memory address to load "text" section to. */ + /* + NOTE: The "text" section is actually all of the "load" + sections of the file including .text, .rodata, .data. + etc. + */ + LONG(TLOAD_ADDR); + + /* 0x001C - 0x001F : size, in bytes, of the "text" section. */ + LONG(__persistent_lbas_len + __ftext_len + __fdata_len); + + /* 0x0020 - 0x002F : + Skip "data_addr", "data_size", "bss_addr" and "bss_size". + None of these are supported by retail PS1 BIOS. + */ + LONG(0); LONG(0); + LONG(0); LONG(0); + + /* 0x0030 - 0x0033 : Initial stack address. */ + LONG(DEFINED(_sp) ? ABSOLUTE(_sp) : 0x801FFF00); + + /* 0x0034 - 0x0037 : Initial stack size, set it to 0. */ + LONG(0); + + /* Skip the remaining fields as they're not supported by the BIOS */ + /* e.g. 2048 header bytes minus whatever we've actually used */ + . = . + 1992; + } > loader + + .persistent_lbas TLOAD_ADDR : { + __persistent_lbas_start = .; + __persistent_lbas = .; + KEEP(*(.header.lbas)) + . = ALIGN(4); + __persistent_lbas_end = .; + } > ram + + __ftext_start = ABSOLUTE(.); + .text : { + __text_start = .; + *(.start) + *(.init) + KEEP (*(SORT_NONE(.fini))) + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(.text .stub .text.* .gnu.linkonce.t.*) + + . = ALIGN(16); + KEEP(*(.init)) + . = ALIGN(16); + KEEP(*(.fini)) + . = ALIGN(16); + __text_end = .; + } > ram + __ftext_end = ABSOLUTE(.); + + __fdata_start = ABSOLUTE(.); + .rodata : { + *(.rodata .rodata.* .rdata .rdata.* .gnu.linkonce.r.*) + . = ALIGN(16); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + + . = ALIGN(16); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + + . = ALIGN(16); + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + __init_array_end = .; + + . = ALIGN(16); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + __fini_array_end = .; + __build_id = .; + *(.note.gnu.build-id) + __build_id_end = .; + } > ram + + .rodata1 : { + *(.rodata1) + } > ram + + .data : { + __data_start = .; + *(.a0table) + *(.data .data.* .gnu.linkonce.d.*) + *(.data1) + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + *(.got.plt) + *(.got) + __data_end = .; + } > ram + + .engine_bss : { + __engine_bss_start = .; + *libJabyEngine_*.a:*(.dynsbss) + *libJabyEngine_*.a:*(.sbss .sbss.* .gnu.linkonce.sb.*) + *libJabyEngine_*.a:*(.scommon) + *libJabyEngine_*.a:*(.dynbss) + *libJabyEngine_*.a:*(.bss .bss.* .gnu.linkonce.b.*) + *libJabyEngine_*.a:*(COMMON) + . = ALIGN(4); + __engine_bss_end = .; + } > ram + __fdata_end = .; + + .bss __persistent_overlay_end (NOLOAD) : { + __bss_start = .; + *(.dynsbss) + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + . = ALIGN(4); + __bss_end = .; + } > ram + + __heap_start = __bss_end; + __end = .; } \ No newline at end of file diff --git a/podman/Dockerfile b/podman/Dockerfile index c278cf2d..6b2e84cb 100644 --- a/podman/Dockerfile +++ b/podman/Dockerfile @@ -1,19 +1,19 @@ -FROM "ubuntu:22.04" -WORKDIR /usr/scripts -ADD ["scripts/make_gcc.sh", "/usr/scripts"] -WORKDIR /tmp -RUN apt update && /usr/scripts/make_gcc.sh - -WORKDIR /usr/scripts -ADD ["scripts/install_rust.sh", "/usr/scripts"] -RUN apt update && ./install_rust.sh - -ADD ["scripts/install_pop-fe.sh", "scripts/run_pop_fe.sh", "/usr/scripts"] -WORKDIR /usr/jaby_engine/bin/extern -RUN apt update && /usr/scripts/install_pop-fe.sh - -WORKDIR /project -ENV PATH="/jaby_engine/bin:/root/.cargo/bin:${PATH}" -ENV JABY_ENGINE_PATH=/jaby_engine -ENV JABY_ENGINE_DIR=/jaby_engine +FROM "ubuntu:22.04" +WORKDIR /usr/scripts +ADD ["scripts/make_gcc.sh", "/usr/scripts"] +WORKDIR /tmp +RUN apt update && /usr/scripts/make_gcc.sh + +WORKDIR /usr/scripts +ADD ["scripts/install_rust.sh", "/usr/scripts"] +RUN apt update && ./install_rust.sh + +ADD ["scripts/install_pop-fe.sh", "scripts/run_pop_fe.sh", "/usr/scripts"] +WORKDIR /usr/jaby_engine/bin/extern +RUN apt update && /usr/scripts/install_pop-fe.sh + +WORKDIR /project +ENV PATH="/jaby_engine/bin:/root/.cargo/bin:${PATH}" +ENV JABY_ENGINE_PATH=/jaby_engine +ENV JABY_ENGINE_DIR=/jaby_engine ENV PSX_LICENSE_PATH=/psx_license \ No newline at end of file diff --git a/readme.md b/readme.md index f6610118..4c393549 100644 --- a/readme.md +++ b/readme.md @@ -1,90 +1,90 @@ -- [JabyEngine](#jabyengine) - - [About](#about) - - [How to build](#how-to-build) - - [Building `Tools` (without VS Code)](#building-tools-without-vs-code) - - [Building `JabyEngine` (without VS Code)](#building-jabyengine-without-vs-code) - - [Building support library (without VS Code)](#building-support-library-without-vs-code) - - [`FontWriter` (without VSCode)](#fontwriter-without-vscode) - - [Building `PoolBox` (without VSCode)](#building-poolbox-without-vscode) -- [Media creators](#media-creators) - - [JabyEngine](#jabyengine-1) - - [PoolBox](#poolbox) -- [Special thanks](#special-thanks) - -# JabyEngine -## About -JabyEngine is my personal attempt to eventually make my own PS1 game from "ground up". Originally I didn't indented to release this code publicly but recently I decided to give it a try. If you read this, thank you! - -## How to build -JabyEngine can be build with a docker image using `podman`. Simply run the `install.sh` script from the `podman` folder and you should be good to go. - -`podman_jaby_engine.sh` allows you to easily run the docker image for builds: -`podman_jaby_engine.sh : <...>` - -The following environment variables should be set: -* `JABY_ENGINE_PATH`: The path to the root folder of this repo. If you used the `install.sh` script and the environment variable was not set, the script will have set it to the folder. Restarting the shell or VS Code might be required. -* `PSX_LICENSE_PATH`: The path to a folder containing the PS1 licenses for generating a CD. - -Additionally you can also specify the following optional environment variables: -* `JABY_ENGINE_NO_DOCKER`: Turns off the usage of `podman` for builds. This is only recommended for specific development. - -VS Code has build targets set for all the projects which should be build in this order: -* `src/Tools/Tools.code-workspace`: Build all tools -* `src/Library/Library.code-workspace`: Build JabyEngine for the configurations you need -* `support/src/SupportLibrary.code-workspace` (optional): Build for using support code -* `examples/PoolBox/PoolBox.code-workspace`(optional): Build for an example "game" - -### Building `Tools` (without VS Code) -`make` requires the following values to be passed: -* `CARGO_CMD`: `build` -* `BUILD_PROFILE`: `debug`/`release` - -### Building `JabyEngine` (without VS Code) -`make` requires the following values to be passed: -* `BUILD_PROFILE`: `debug`/`release` -* `PSX_TV_FORMAT`: `PAL`/`NTSC` -* `CUSTOM_CONFIG`: Empty or folder name under `./config` - -### Building support library (without VS Code) -These projects shall eventually turn into useful extensions for the engine. So far they are more tests then proper code. However `PoolBox` is depended on `FontWriter`. - -#### `FontWriter` (without VSCode) -`make` requires the following values to be passed: -* `BUILD_PROFILE`: `debug`/`release` - -### Building `PoolBox` (without VSCode) -`PoolBox` is the one and only example project so far. -`make` requires the following values to be passed: -* `BUILD_PROFILE`: `debug`/`release` -* `REGION`: `SCEE`/`SCEA`/`SCEI` -* `CUSTOM_CONFIG`: Empty or folder name under `$(JABY_ENGINE_PATH)/config` - - -# Media creators -## JabyEngine -| Art | Author | -|-----------------------------------------------------------------|------------------------------------------------------------| -| `ressources\Splash_ntsc.png`
`ressources\Splash_ntsc.png` | Niuka | -| `bin/extern/32BIT.TMD` | http://psx.arthus.net/homebrew/assets/boot_logos/32BIT.TMD | - -## PoolBox -| Art | Author | -|-----------------------------------------------------------------|-------------| -| `examples\PoolBox\assets\AllTheJaby.png` | Niuka | -| `examples\PoolBox\assets\IconTexture.png` | Charlie Nax | -| `examples\PoolBox\assets\Paco.png` | Paco | - -| Music | Author | -|---------------------------------------------------------------------------|---------------------------------------| -| `examples\PoolBox\assets\audio\apple.wav` | ??? | -| `examples\PoolBox\assets\audio\blubb-mono.wav` | ??? | -| `examples\PoolBox\assets\audio\Evacuation_cdda.wav` | Cody the white tiger | -| `examples\PoolBox\assets\audio\Friendship_samp.wav` | From Dragon Quest VII | -| `examples\PoolBox\assets\audio\jlbrock44_Three_Kings_Funk_cdda_ready.wav` | `Three Kings Funk` by spinningmerkaba | -| `examples\PoolBox\assets\audio\OnMyOwn_BailBonds.mp3` | `On My Own` by Bail Bonds | - -# Special thanks -* Cody the white tiger -* Nicolas Noble -* Pyravia -* Sickle +- [JabyEngine](#jabyengine) + - [About](#about) + - [How to build](#how-to-build) + - [Building `Tools` (without VS Code)](#building-tools-without-vs-code) + - [Building `JabyEngine` (without VS Code)](#building-jabyengine-without-vs-code) + - [Building support library (without VS Code)](#building-support-library-without-vs-code) + - [`FontWriter` (without VSCode)](#fontwriter-without-vscode) + - [Building `PoolBox` (without VSCode)](#building-poolbox-without-vscode) +- [Media creators](#media-creators) + - [JabyEngine](#jabyengine-1) + - [PoolBox](#poolbox) +- [Special thanks](#special-thanks) + +# JabyEngine +## About +JabyEngine is my personal attempt to eventually make my own PS1 game from "ground up". Originally I didn't indented to release this code publicly but recently I decided to give it a try. If you read this, thank you! + +## How to build +JabyEngine can be build with a docker image using `podman`. Simply run the `install.sh` script from the `podman` folder and you should be good to go. + +`podman_jaby_engine.sh` allows you to easily run the docker image for builds: +`podman_jaby_engine.sh : <...>` + +The following environment variables should be set: +* `JABY_ENGINE_PATH`: The path to the root folder of this repo. If you used the `install.sh` script and the environment variable was not set, the script will have set it to the folder. Restarting the shell or VS Code might be required. +* `PSX_LICENSE_PATH`: The path to a folder containing the PS1 licenses for generating a CD. + +Additionally you can also specify the following optional environment variables: +* `JABY_ENGINE_NO_DOCKER`: Turns off the usage of `podman` for builds. This is only recommended for specific development. + +VS Code has build targets set for all the projects which should be build in this order: +* `src/Tools/Tools.code-workspace`: Build all tools +* `src/Library/Library.code-workspace`: Build JabyEngine for the configurations you need +* `support/src/SupportLibrary.code-workspace` (optional): Build for using support code +* `examples/PoolBox/PoolBox.code-workspace`(optional): Build for an example "game" + +### Building `Tools` (without VS Code) +`make` requires the following values to be passed: +* `CARGO_CMD`: `build` +* `BUILD_PROFILE`: `debug`/`release` + +### Building `JabyEngine` (without VS Code) +`make` requires the following values to be passed: +* `BUILD_PROFILE`: `debug`/`release` +* `PSX_TV_FORMAT`: `PAL`/`NTSC` +* `CUSTOM_CONFIG`: Empty or folder name under `./config` + +### Building support library (without VS Code) +These projects shall eventually turn into useful extensions for the engine. So far they are more tests then proper code. However `PoolBox` is depended on `FontWriter`. + +#### `FontWriter` (without VSCode) +`make` requires the following values to be passed: +* `BUILD_PROFILE`: `debug`/`release` + +### Building `PoolBox` (without VSCode) +`PoolBox` is the one and only example project so far. +`make` requires the following values to be passed: +* `BUILD_PROFILE`: `debug`/`release` +* `REGION`: `SCEE`/`SCEA`/`SCEI` +* `CUSTOM_CONFIG`: Empty or folder name under `$(JABY_ENGINE_PATH)/config` + + +# Media creators +## JabyEngine +| Art | Author | +|-----------------------------------------------------------------|------------------------------------------------------------| +| `ressources\Splash_ntsc.png`
`ressources\Splash_ntsc.png` | Niuka | +| `bin/extern/32BIT.TMD` | http://psx.arthus.net/homebrew/assets/boot_logos/32BIT.TMD | + +## PoolBox +| Art | Author | +|-----------------------------------------------------------------|-------------| +| `examples\PoolBox\assets\AllTheJaby.png` | Niuka | +| `examples\PoolBox\assets\IconTexture.png` | Charlie Nax | +| `examples\PoolBox\assets\Paco.png` | Paco | + +| Music | Author | +|---------------------------------------------------------------------------|---------------------------------------| +| `examples\PoolBox\assets\audio\apple.wav` | ??? | +| `examples\PoolBox\assets\audio\blubb-mono.wav` | ??? | +| `examples\PoolBox\assets\audio\Evacuation_cdda.wav` | Cody the white tiger | +| `examples\PoolBox\assets\audio\Friendship_samp.wav` | From Dragon Quest VII | +| `examples\PoolBox\assets\audio\jlbrock44_Three_Kings_Funk_cdda_ready.wav` | `Three Kings Funk` by spinningmerkaba | +| `examples\PoolBox\assets\audio\OnMyOwn_BailBonds.mp3` | `On My Own` by Bail Bonds | + +# Special thanks +* Cody the white tiger +* Nicolas Noble +* Pyravia +* Sickle diff --git a/src/Library/Library.code-workspace b/src/Library/Library.code-workspace index d63328b3..3331dc0b 100644 --- a/src/Library/Library.code-workspace +++ b/src/Library/Library.code-workspace @@ -1,103 +1,103 @@ -{ - "folders": [ - { - "name": "JabyEngine", - "path": ".", - }, - { - "name": "Include", - "path": "..\\..\\include" - }, - { - "name": "Root", - "path": "..\\.." - } - ], - "tasks": { - "version": "2.0.0", - "tasks": [ - { - "label": "make", - "type": "shell", - "command": "../../scripts/podman_jaby_engine.sh ../../:src/Library make ${input:target} BUILD_PROFILE=${input:build cfg} PSX_TV_FORMAT=${input:tv format} CUSTOM_CONFIG=${input:config options}", - "group": "build" - }, - { - "label": "make_all", - "type": "shell", - "command": "../../scripts/podman_jaby_engine.sh ../../:src/Library make -f MakeAll.mk ${input:target prefix}_${input:target} BUILD_PROFILE=${input:build cfg} CUSTOM_CONFIG=${input:config options}", - "group": "build" - } - ], - "inputs": [ - { - "id": "build cfg", - "type": "pickString", - "options": ["debug", "release"], - "default": "release", - "description": "build configuration" - }, - { - "id": "tv format", - "type": "pickString", - "options": ["PAL", "NTSC"], - "default": "PAL", - "description": "TV format to use" - }, - { - "id": "config options", - "type": "command", - "command": "shellCommand.execute", - "args": { - "command": "echo \"|\" && ls -d */", - "cwd": "${workspaceFolder}/../../config", - "fieldSeparator": "|" - } - }, - { - "id": "target prefix", - "type": "pickString", - "options": ["jabyengine", "all_jabyengine"], - "default": "jabyengine", - "description": "To build JabyEngine or JabyEngine with all configs" - }, - { - "id": "target", - "type": "pickString", - "options": ["all", "clean", "rebuild"], - "default": "all", - "description": "build target", - } - ] - }, - "extensions": { - "recommendations": ["augustocdias.tasks-shell-input", "cantonios.project-templates"] - }, - "settings": { - "cmake.configureOnOpen": false, - "C_Cpp.default.includePath": [ - "include", - "../../include" - ], - "C_Cpp.default.compilerPath": "", - "C_Cpp.default.cStandard": "c17", - "C_Cpp.default.cppStandard": "c++20", - "C_Cpp.default.intelliSenseMode": "linux-gcc-x86", - "C_Cpp.default.compilerArgs": [ - ], - "C_Cpp.default.defines": [ - "JABYENGINE_PAL", - "__DEBUG_SPU_MMU__", - "__friends=public" - ], - "files.exclude": { - "**/*.o": true, - "**/*.dep": true - }, - "files.associations": { - "stdio.h": "c", - "TUTO0.C": "cpp", - "MAIN.C": "cpp" - } - } +{ + "folders": [ + { + "name": "JabyEngine", + "path": ".", + }, + { + "name": "Include", + "path": "..\\..\\include" + }, + { + "name": "Root", + "path": "..\\.." + } + ], + "tasks": { + "version": "2.0.0", + "tasks": [ + { + "label": "make", + "type": "shell", + "command": "../../scripts/podman_jaby_engine.sh ../../:src/Library make ${input:target} BUILD_PROFILE=${input:build cfg} PSX_TV_FORMAT=${input:tv format} CUSTOM_CONFIG=${input:config options}", + "group": "build" + }, + { + "label": "make_all", + "type": "shell", + "command": "../../scripts/podman_jaby_engine.sh ../../:src/Library make -f MakeAll.mk ${input:target prefix}_${input:target} BUILD_PROFILE=${input:build cfg} CUSTOM_CONFIG=${input:config options}", + "group": "build" + } + ], + "inputs": [ + { + "id": "build cfg", + "type": "pickString", + "options": ["debug", "release"], + "default": "release", + "description": "build configuration" + }, + { + "id": "tv format", + "type": "pickString", + "options": ["PAL", "NTSC"], + "default": "PAL", + "description": "TV format to use" + }, + { + "id": "config options", + "type": "command", + "command": "shellCommand.execute", + "args": { + "command": "echo \"|\" && ls -d */", + "cwd": "${workspaceFolder}/../../config", + "fieldSeparator": "|" + } + }, + { + "id": "target prefix", + "type": "pickString", + "options": ["jabyengine", "all_jabyengine"], + "default": "jabyengine", + "description": "To build JabyEngine or JabyEngine with all configs" + }, + { + "id": "target", + "type": "pickString", + "options": ["all", "clean", "rebuild"], + "default": "all", + "description": "build target", + } + ] + }, + "extensions": { + "recommendations": ["augustocdias.tasks-shell-input", "cantonios.project-templates"] + }, + "settings": { + "cmake.configureOnOpen": false, + "C_Cpp.default.includePath": [ + "include", + "../../include" + ], + "C_Cpp.default.compilerPath": "", + "C_Cpp.default.cStandard": "c17", + "C_Cpp.default.cppStandard": "c++20", + "C_Cpp.default.intelliSenseMode": "linux-gcc-x86", + "C_Cpp.default.compilerArgs": [ + ], + "C_Cpp.default.defines": [ + "JABYENGINE_PAL", + "__DEBUG_SPU_MMU__", + "__friends=public" + ], + "files.exclude": { + "**/*.o": true, + "**/*.dep": true + }, + "files.associations": { + "stdio.h": "c", + "TUTO0.C": "cpp", + "MAIN.C": "cpp" + } + } } \ No newline at end of file diff --git a/src/Library/MakeAll.mk b/src/Library/MakeAll.mk index 962c404e..9525ed22 100644 --- a/src/Library/MakeAll.mk +++ b/src/Library/MakeAll.mk @@ -1,26 +1,26 @@ -define make_one -$(MAKE) $1 PSX_TV_FORMAT=PAL CUSTOM_CONFIG=$2 -$(MAKE) $1 PSX_TV_FORMAT=NTSC CUSTOM_CONFIG=$2 -endef - -define make_all -$(call make_one,$1,) -$(foreach config,$2,$(call make_one,$1,$(config))) -endef - -config_files = $(shell cd ../../config && ls -d */) - -jabyengine_%: - $(call make_one,$*,$(CUSTOM_CONFIG)) - -all_jabyengine_%: - $(call make_all,$*,$(config_files)) - -all: - $(call make_all,all,$(config_files)) - -clean: - $(call make_all,clean,$(config_files)) - -rebuild: +define make_one +$(MAKE) $1 PSX_TV_FORMAT=PAL CUSTOM_CONFIG=$2 +$(MAKE) $1 PSX_TV_FORMAT=NTSC CUSTOM_CONFIG=$2 +endef + +define make_all +$(call make_one,$1,) +$(foreach config,$2,$(call make_one,$1,$(config))) +endef + +config_files = $(shell cd ../../config && ls -d */) + +jabyengine_%: + $(call make_one,$*,$(CUSTOM_CONFIG)) + +all_jabyengine_%: + $(call make_all,$*,$(config_files)) + +all: + $(call make_all,all,$(config_files)) + +clean: + $(call make_all,clean,$(config_files)) + +rebuild: $(call make_all,rebuild,$(config_files)) \ No newline at end of file diff --git a/src/Library/Makefile b/src/Library/Makefile index 1f9114db..0bf02ad2 100644 --- a/src/Library/Makefile +++ b/src/Library/Makefile @@ -1,51 +1,51 @@ -include ../../mkfile/common/RebuildTarget.mk -JABY_ENGINE_DIR = ../../ - -ARTIFACT = libJabyEngine_$(PSX_TV_FORMAT) - -SPLASH_IMAGE = src/BootLoader/splash_image_pal_boot.hpp -SPLASH_IMAGE_NTSC = src/BootLoader/splash_image_ntsc_boot.hpp - -CCFLAGS += -I../../include -D__friends=public -CCFLAGS += -save-temps=obj - -include ../../mkfile/common/CustomConfigHelper.mk -CONFIG_NAME = $(PLATFORM)-$(BUILD_PROFILE)/$(CUSTOM_CONFIG) - -include ../../mkfile/common/Wildcard.mk -SRCS = $(call rwildcard, src, c cpp s) - -include ../../mkfile/Makefile -LIB_DIR = ../../lib/$(CONFIG_NAME) - -MAIN_LIB_OBJS = $(filter-out $(MAIN_BOOT_OBJ) $(OVERLAY_BOOT_OBJ),$(OBJS)) - -#$(info $$var is [${MAIN_BOOT_OBJ}]) -#$(info $$var2 is [${MAIN_LIB_OBJS}]) - -#Linking rule -$(TARGET).a: $(MAIN_LIB_OBJS) $(SPLASH_IMAGE) - @mkdir -p $(dir $@) - $(AR) rcs $(TARGET).a $(MAIN_LIB_OBJS) - -#Copy rules -$(LIB_DIR)/$(ARTIFACT).a: $(TARGET).a - @mkdir -p $(LIB_DIR) - cp $(TARGET).a $(LIB_DIR)/$(ARTIFACT).a - -# rule to make the boot image -$(SPLASH_IMAGE): ressources/Splash.png - psxfileconv --lz4 $< simple-tim full16 | cpp_out --name SplashScreen -o $@ - -$(SPLASH_IMAGE_NTSC): ressources/Splash_ntsc.png - psxfileconv --lz4 $< simple-tim full16 | cpp_out --name SplashScreen -o $@ - -#Rules section for default compilation and linking -all: $(SPLASH_IMAGE) $(SPLASH_IMAGE_NTSC) $(LIB_DIR)/$(ARTIFACT).a - -clean: - rm -fr $(SPLASH_IMAGE) - rm -fr $(SPLASH_IMAGE_NTSC) - rm -fr $(OUTPUT_DIR) - rm -fr gcm.cache +include ../../mkfile/common/RebuildTarget.mk +JABY_ENGINE_DIR = ../../ + +ARTIFACT = libJabyEngine_$(PSX_TV_FORMAT) + +SPLASH_IMAGE = src/BootLoader/splash_image_pal_boot.hpp +SPLASH_IMAGE_NTSC = src/BootLoader/splash_image_ntsc_boot.hpp + +CCFLAGS += -I../../include -D__friends=public +CCFLAGS += -save-temps=obj + +include ../../mkfile/common/CustomConfigHelper.mk +CONFIG_NAME = $(PLATFORM)-$(BUILD_PROFILE)/$(CUSTOM_CONFIG) + +include ../../mkfile/common/Wildcard.mk +SRCS = $(call rwildcard, src, c cpp s) + +include ../../mkfile/Makefile +LIB_DIR = ../../lib/$(CONFIG_NAME) + +MAIN_LIB_OBJS = $(filter-out $(MAIN_BOOT_OBJ) $(OVERLAY_BOOT_OBJ),$(OBJS)) + +#$(info $$var is [${MAIN_BOOT_OBJ}]) +#$(info $$var2 is [${MAIN_LIB_OBJS}]) + +#Linking rule +$(TARGET).a: $(MAIN_LIB_OBJS) $(SPLASH_IMAGE) + @mkdir -p $(dir $@) + $(AR) rcs $(TARGET).a $(MAIN_LIB_OBJS) + +#Copy rules +$(LIB_DIR)/$(ARTIFACT).a: $(TARGET).a + @mkdir -p $(LIB_DIR) + cp $(TARGET).a $(LIB_DIR)/$(ARTIFACT).a + +# rule to make the boot image +$(SPLASH_IMAGE): ressources/Splash.png + psxfileconv --lz4 $< simple-tim full16 | cpp_out --name SplashScreen -o $@ + +$(SPLASH_IMAGE_NTSC): ressources/Splash_ntsc.png + psxfileconv --lz4 $< simple-tim full16 | cpp_out --name SplashScreen -o $@ + +#Rules section for default compilation and linking +all: $(SPLASH_IMAGE) $(SPLASH_IMAGE_NTSC) $(LIB_DIR)/$(ARTIFACT).a + +clean: + rm -fr $(SPLASH_IMAGE) + rm -fr $(SPLASH_IMAGE_NTSC) + rm -fr $(OUTPUT_DIR) + rm -fr gcm.cache rm -fr $(LIB_DIR)/$(ARTIFACT).a \ No newline at end of file diff --git a/src/Library/internal-include/SPU/spu_internal.hpp b/src/Library/internal-include/SPU/spu_internal.hpp index dc2c7120..c5a78077 100644 --- a/src/Library/internal-include/SPU/spu_internal.hpp +++ b/src/Library/internal-include/SPU/spu_internal.hpp @@ -1,44 +1,44 @@ -#pragma once -#include -#include - -namespace JabyEngine { - namespace SPU { - namespace internal { - struct DMA { - static void wait() { - DMA_IO::SPU.wait(); - while(SPU_IO::StatusRegister.read().is_set(SPU_IO_Values::StatusRegister::TransferBusy)); - } - - static void end() { - SPU_IO::ControlRegister.set_transfer_mode(SPU_IO_Values::ControlRegister::Stop); - } - - struct Receive { - static void prepare() { - end(); - SPU_IO::DataTransferControl.write(SPU_IO_Values::DataTransferControl::NormalTransferMode()); - SPU_IO::ControlRegister.set_transfer_mode(SPU_IO_Values::ControlRegister::Stop); - } - - static void set_src(uintptr_t adr) { - DMA_IO::SPU.set_adr(adr); - } - - static void set_dst(SPU::SRAMAdr adr) { - SPU_IO::SRAMTransferAdr.write(adr); - SPU_IO::ControlRegister.set_transfer_mode(SPU_IO_Values::ControlRegister::DMAWrite); - } - - static void start(uint16_t blockCount, uint16_t wordsPerBlock = 0x10) { - using SyncMode1 = DMA_IO_Values::BCR::SyncMode1; - - DMA_IO::SPU.block_ctrl.write(DMA_IO_Values::BCR::from(SyncMode1::BlockSize.with(wordsPerBlock), SyncMode1::BlockAmount.with(blockCount))); - DMA_IO::SPU.channel_ctrl.write(DMA_IO_Values::CHCHR::StartSPUReceive()); - } - }; - }; - } - } -} +#pragma once +#include +#include + +namespace JabyEngine { + namespace SPU { + namespace internal { + struct DMA { + static void wait() { + DMA_IO::SPU.wait(); + while(SPU_IO::StatusRegister.read().is_set(SPU_IO_Values::StatusRegister::TransferBusy)); + } + + static void end() { + SPU_IO::ControlRegister.set_transfer_mode(SPU_IO_Values::ControlRegister::Stop); + } + + struct Receive { + static void prepare() { + end(); + SPU_IO::DataTransferControl.write(SPU_IO_Values::DataTransferControl::NormalTransferMode()); + SPU_IO::ControlRegister.set_transfer_mode(SPU_IO_Values::ControlRegister::Stop); + } + + static void set_src(uintptr_t adr) { + DMA_IO::SPU.set_adr(adr); + } + + static void set_dst(SPU::SRAMAdr adr) { + SPU_IO::SRAMTransferAdr.write(adr); + SPU_IO::ControlRegister.set_transfer_mode(SPU_IO_Values::ControlRegister::DMAWrite); + } + + static void start(uint16_t blockCount, uint16_t wordsPerBlock = 0x10) { + using SyncMode1 = DMA_IO_Values::BCR::SyncMode1; + + DMA_IO::SPU.block_ctrl.write(DMA_IO_Values::BCR::from(SyncMode1::BlockSize.with(wordsPerBlock), SyncMode1::BlockAmount.with(blockCount))); + DMA_IO::SPU.channel_ctrl.write(DMA_IO_Values::CHCHR::StartSPUReceive()); + } + }; + }; + } + } +} diff --git a/src/Library/internal-include/SPU/spu_mmu.hpp b/src/Library/internal-include/SPU/spu_mmu.hpp index 58103f4e..e2e14217 100644 --- a/src/Library/internal-include/SPU/spu_mmu.hpp +++ b/src/Library/internal-include/SPU/spu_mmu.hpp @@ -1,9 +1,9 @@ -#pragma once -#include - -namespace JabyEngine { - namespace SPU_MMU { - const uint8_t* allocate(uint8_t voice, size_t size); - void deallocate(uint8_t voice); - } +#pragma once +#include + +namespace JabyEngine { + namespace SPU_MMU { + const uint8_t* allocate(uint8_t voice, size_t size); + void deallocate(uint8_t voice); + } } \ No newline at end of file diff --git a/src/Library/internal-include/System/callbacks_internal.hpp b/src/Library/internal-include/System/callbacks_internal.hpp index 590fe80e..e31a53c5 100644 --- a/src/Library/internal-include/System/callbacks_internal.hpp +++ b/src/Library/internal-include/System/callbacks_internal.hpp @@ -1,51 +1,51 @@ -#pragma once -#include "threads.hpp" -#include - -namespace JabyEngine { - namespace Callback { - namespace internal { - static void execute_callback(Thread::Handle thread_handle, uint32_t parm) { - if(CurrentThread::is_me(MainThread::Handle)) { - CurrentThread::replace_with(thread_handle); - CurrentThread::force_a0(parm); - } - SysCall::ReturnFromException(); - } - - static uint32_t resume_callback(Thread::Handle handle) { - SysCall::ChangeThread(handle); - asm("sw $a0, %0" : "=m"(handle)); - return handle; - } - - namespace VSync { - static constexpr size_t StackSize = 64; - - extern SysCall::ThreadHandle thread_handle; - extern uint32_t stack[StackSize]; - void routine(); - - static void [[deprecated("Currently not in use")]] execute() { - execute_callback(VSync::thread_handle, 0); - } - } - - namespace CD { - static constexpr size_t StackSize = 256; - - extern Thread::Handle thread_handle; - extern uint32_t stack[StackSize]; - void routine(uint32_t irq); - - static void execute(uint32_t irq) { - execute_callback(CD::thread_handle, irq); - } - - static uint32_t resume() { - return resume_callback(MainThread::Handle); - } - } - } - } -} +#pragma once +#include "threads.hpp" +#include + +namespace JabyEngine { + namespace Callback { + namespace internal { + static void execute_callback(Thread::Handle thread_handle, uint32_t parm) { + if(CurrentThread::is_me(MainThread::Handle)) { + CurrentThread::replace_with(thread_handle); + CurrentThread::force_a0(parm); + } + SysCall::ReturnFromException(); + } + + static uint32_t resume_callback(Thread::Handle handle) { + SysCall::ChangeThread(handle); + asm("sw $a0, %0" : "=m"(handle)); + return handle; + } + + namespace VSync { + static constexpr size_t StackSize = 64; + + extern SysCall::ThreadHandle thread_handle; + extern uint32_t stack[StackSize]; + void routine(); + + static void [[deprecated("Currently not in use")]] execute() { + execute_callback(VSync::thread_handle, 0); + } + } + + namespace CD { + static constexpr size_t StackSize = 256; + + extern Thread::Handle thread_handle; + extern uint32_t stack[StackSize]; + void routine(uint32_t irq); + + static void execute(uint32_t irq) { + execute_callback(CD::thread_handle, irq); + } + + static uint32_t resume() { + return resume_callback(MainThread::Handle); + } + } + } + } +} diff --git a/src/Library/internal-include/System/threads.hpp b/src/Library/internal-include/System/threads.hpp index 22f7450b..0bf7dd7a 100644 --- a/src/Library/internal-include/System/threads.hpp +++ b/src/Library/internal-include/System/threads.hpp @@ -1,55 +1,55 @@ -#pragma once -#include - -namespace JabyEngine { - struct Thread { - using Handle = SysCall::ThreadHandle; - - static constexpr uint32_t idx_from_handle(SysCall::ThreadHandle thread) { - return thread & 0xFFFF; - } - - static uintptr_t get_pic_of(Handle handle) { - return table_of_tables.threads[idx_from_handle(handle)].epc; - } - - template - static Handle create(void(*function)(uint32_t), uint32_t(&stack)[N]) { - return SysCall::OpenThread(reinterpret_cast(function), &stack[N - 1], SysCall::get_gp()); - } - - static void set_kernel_mode_for(SysCall::ThreadHandle handle) { - table_of_tables.threads[idx_from_handle(handle)].sr = 0x0; - } - - static void set_user_mode_for(SysCall::ThreadHandle handle) { - table_of_tables.threads[idx_from_handle(handle)].sr = 0x40000404; - } - }; - - struct CurrentThread { - static uintptr_t get_pic() { - return table_of_tables.processes->current_tcb->epc; - } - - static void force_a0(uint32_t a0) { - table_of_tables.processes->current_tcb->reg[4] = a0; - } - - static bool is_me(Thread::Handle handle) { - return table_of_tables.processes->current_tcb == &table_of_tables.threads[Thread::idx_from_handle(handle)]; - } - - static void replace_with(Thread::Handle handle) { - table_of_tables.processes->current_tcb = &table_of_tables.threads[Thread::idx_from_handle(handle)]; - } - }; - - struct MainThread { - static constexpr const Thread::Handle Handle = 0xFF000000; - - static uintptr_t get_pic() { - return table_of_tables.threads[0].epc; - } - }; +#pragma once +#include + +namespace JabyEngine { + struct Thread { + using Handle = SysCall::ThreadHandle; + + static constexpr uint32_t idx_from_handle(SysCall::ThreadHandle thread) { + return thread & 0xFFFF; + } + + static uintptr_t get_pic_of(Handle handle) { + return table_of_tables.threads[idx_from_handle(handle)].epc; + } + + template + static Handle create(void(*function)(uint32_t), uint32_t(&stack)[N]) { + return SysCall::OpenThread(reinterpret_cast(function), &stack[N - 1], SysCall::get_gp()); + } + + static void set_kernel_mode_for(SysCall::ThreadHandle handle) { + table_of_tables.threads[idx_from_handle(handle)].sr = 0x0; + } + + static void set_user_mode_for(SysCall::ThreadHandle handle) { + table_of_tables.threads[idx_from_handle(handle)].sr = 0x40000404; + } + }; + + struct CurrentThread { + static uintptr_t get_pic() { + return table_of_tables.processes->current_tcb->epc; + } + + static void force_a0(uint32_t a0) { + table_of_tables.processes->current_tcb->reg[4] = a0; + } + + static bool is_me(Thread::Handle handle) { + return table_of_tables.processes->current_tcb == &table_of_tables.threads[Thread::idx_from_handle(handle)]; + } + + static void replace_with(Thread::Handle handle) { + table_of_tables.processes->current_tcb = &table_of_tables.threads[Thread::idx_from_handle(handle)]; + } + }; + + struct MainThread { + static constexpr const Thread::Handle Handle = 0xFF000000; + + static uintptr_t get_pic() { + return table_of_tables.threads[0].epc; + } + }; } \ No newline at end of file diff --git a/src/Library/internal-include/mipscalls.hpp b/src/Library/internal-include/mipscalls.hpp index 2a74af18..9ce4d793 100644 --- a/src/Library/internal-include/mipscalls.hpp +++ b/src/Library/internal-include/mipscalls.hpp @@ -1,38 +1,38 @@ -#pragma once -#include - -namespace JabyEngine { - namespace MIPS { - struct SR { - static constexpr auto IEc = Bit(0); // Current Interrupt Enable (0=Disable, 1=Enable) - static constexpr auto KUc = Bit(1); // Current Kernel/User Mode (0=Kernel, 1=User) - static constexpr auto IEp = Bit(2); // Previous Interrupt Disable - static constexpr auto KUp = Bit(3); // Previous Kernal/User Mode - static constexpr auto IEo = Bit(4); // Old Interrupt Disable - static constexpr auto KUo = Bit(5); // Old Kernal/User Mode - static constexpr auto Im = BitRange::from_to(8, 15); // 8 bit interrupt mask fields. When set the corresponding interrupts are allowed to cause an exception. - static constexpr auto Isc = Bit(16); // Isolate Cache (0=No, 1=Isolate) When isolated, all load and store operations are targetted to the Data cache, and never the main memory. (Used by PSX Kernel, in combination with Port FFFE0130h) - static constexpr auto Swc = Bit(17); // Swc Swapped cache mode (0=Normal, 1=Swapped) Instruction cache will act as Data cache and vice versa. Use only with Isc to access & invalidate Instr. cache entries. (Not used by PSX Kernel) - static constexpr auto PZ = Bit(18); // PZ When set cache parity bits are written as 0. - static constexpr auto CM = Bit(19); // CM Shows the result of the last load operation with the D-cache isolated. It gets set if the cache really contained data for the addressed memory location. - static constexpr auto PE = Bit(20); // Cache parity error (Does not cause exception) - static constexpr auto TS = Bit(21); // TLB shutdown. Gets set if a programm address simultaneously matches 2 TLB entries. (initial value on reset allows to detect extended CPU version?) - static constexpr auto BEV = Bit(22); // Boot exception vectors in RAM/ROM (0=RAM/KSEG0, 1=ROM/KSEG1) - static constexpr auto RE = Bit(25); // Reverse endianness (0=Normal endianness, 1=Reverse endianness) Reverses the byte order in which data is stored in memory. (lo-hi -> hi-lo) (Has affect only to User mode, not to Kernal mode) (?) (The bit doesn't exist in PSX ?) - static constexpr auto CU0 = Bit(28); // COP0 Enable (0=Enable only in Kernal Mode, 1=Kernal and User Mode) - static constexpr auto CU1 = Bit(29); // COP1 Enable (0=Disable, 1=Enable) (none such in PSX) - static constexpr auto CU2 = Bit(30); // COP2 Enable (0=Disable, 1=Enable) (GTE in PSX) - static constexpr auto CU3 = Bit(31); // COP3 Enable (0=Disable, 1=Enable) (none such in PSX) - - static uint32_t read() { - uint32_t sr; - __asm__("mfc0 %0, $12" : "=rm"(sr)); - return sr; - } - - static void write(uint32_t sr) { - __asm__("mtc0 %0, $12" :: "rm"(sr)); - } - }; - } +#pragma once +#include + +namespace JabyEngine { + namespace MIPS { + struct SR { + static constexpr auto IEc = Bit(0); // Current Interrupt Enable (0=Disable, 1=Enable) + static constexpr auto KUc = Bit(1); // Current Kernel/User Mode (0=Kernel, 1=User) + static constexpr auto IEp = Bit(2); // Previous Interrupt Disable + static constexpr auto KUp = Bit(3); // Previous Kernal/User Mode + static constexpr auto IEo = Bit(4); // Old Interrupt Disable + static constexpr auto KUo = Bit(5); // Old Kernal/User Mode + static constexpr auto Im = BitRange::from_to(8, 15); // 8 bit interrupt mask fields. When set the corresponding interrupts are allowed to cause an exception. + static constexpr auto Isc = Bit(16); // Isolate Cache (0=No, 1=Isolate) When isolated, all load and store operations are targetted to the Data cache, and never the main memory. (Used by PSX Kernel, in combination with Port FFFE0130h) + static constexpr auto Swc = Bit(17); // Swc Swapped cache mode (0=Normal, 1=Swapped) Instruction cache will act as Data cache and vice versa. Use only with Isc to access & invalidate Instr. cache entries. (Not used by PSX Kernel) + static constexpr auto PZ = Bit(18); // PZ When set cache parity bits are written as 0. + static constexpr auto CM = Bit(19); // CM Shows the result of the last load operation with the D-cache isolated. It gets set if the cache really contained data for the addressed memory location. + static constexpr auto PE = Bit(20); // Cache parity error (Does not cause exception) + static constexpr auto TS = Bit(21); // TLB shutdown. Gets set if a programm address simultaneously matches 2 TLB entries. (initial value on reset allows to detect extended CPU version?) + static constexpr auto BEV = Bit(22); // Boot exception vectors in RAM/ROM (0=RAM/KSEG0, 1=ROM/KSEG1) + static constexpr auto RE = Bit(25); // Reverse endianness (0=Normal endianness, 1=Reverse endianness) Reverses the byte order in which data is stored in memory. (lo-hi -> hi-lo) (Has affect only to User mode, not to Kernal mode) (?) (The bit doesn't exist in PSX ?) + static constexpr auto CU0 = Bit(28); // COP0 Enable (0=Enable only in Kernal Mode, 1=Kernal and User Mode) + static constexpr auto CU1 = Bit(29); // COP1 Enable (0=Disable, 1=Enable) (none such in PSX) + static constexpr auto CU2 = Bit(30); // COP2 Enable (0=Disable, 1=Enable) (GTE in PSX) + static constexpr auto CU3 = Bit(31); // COP3 Enable (0=Disable, 1=Enable) (none such in PSX) + + static uint32_t read() { + uint32_t sr; + __asm__("mfc0 %0, $12" : "=rm"(sr)); + return sr; + } + + static void write(uint32_t sr) { + __asm__("mtc0 %0, $12" :: "rm"(sr)); + } + }; + } } \ No newline at end of file diff --git a/src/Library/internal-include/periphery_internal.hpp b/src/Library/internal-include/periphery_internal.hpp index e2bfa408..6d746019 100644 --- a/src/Library/internal-include/periphery_internal.hpp +++ b/src/Library/internal-include/periphery_internal.hpp @@ -1,39 +1,39 @@ -#pragma once -#include -#include -#include -#include - -extern "C" void busy_loop(int count); - -namespace JabyEngine { - namespace Periphery { - using namespace Periphery_IO; - - static void connect_to(uint16_t port) { - JOY_CTRL.write(Periphery_IO_Values::JOY_CTRL::create_for(port)); - busy_loop(500); - } - - static void close_connection() { - JOY_CTRL.write(Periphery_IO_Values::JOY_CTRL::close()); - } - - static void send_byte(uint8_t byte) { - while(!JOY_STAT.is_ready_transfer()); - JOY_TX_DATA.write(Periphery_IO_Values::JOY_TX_DATA::create(byte)); - } - - static uint8_t read_byte() { - while(!JOY_STAT.has_response()); - return JOY_RX_DATA.read().raw; - } - - static void acknowledge() { - while(JOY_STAT.read().is_set(Periphery_IO_Values::JOY_STAT::ACKIrqLow)); - JOY_CTRL.write(JOY_CTRL.read().set(Periphery_IO_Values::JOY_CTRL::ACK)); - - Interrupt::ack_irq(Interrupt::Periphery); - } - } +#pragma once +#include +#include +#include +#include + +extern "C" void busy_loop(int count); + +namespace JabyEngine { + namespace Periphery { + using namespace Periphery_IO; + + static void connect_to(uint16_t port) { + JOY_CTRL.write(Periphery_IO_Values::JOY_CTRL::create_for(port)); + busy_loop(500); + } + + static void close_connection() { + JOY_CTRL.write(Periphery_IO_Values::JOY_CTRL::close()); + } + + static void send_byte(uint8_t byte) { + while(!JOY_STAT.is_ready_transfer()); + JOY_TX_DATA.write(Periphery_IO_Values::JOY_TX_DATA::create(byte)); + } + + static uint8_t read_byte() { + while(!JOY_STAT.has_response()); + return JOY_RX_DATA.read().raw; + } + + static void acknowledge() { + while(JOY_STAT.read().is_set(Periphery_IO_Values::JOY_STAT::ACKIrqLow)); + JOY_CTRL.write(JOY_CTRL.read().set(Periphery_IO_Values::JOY_CTRL::ACK)); + + Interrupt::ack_irq(Interrupt::Periphery); + } + } } \ No newline at end of file diff --git a/src/Library/reference/about_inline_n.md b/src/Library/reference/about_inline_n.md index 0b858063..a9e9d12c 100644 --- a/src/Library/reference/about_inline_n.md +++ b/src/Library/reference/about_inline_n.md @@ -1,8 +1,8 @@ -# inline_n.h -This header is directly lifted from psx-redux and not my creation. I will try to give it my personal touch but the original implementation will be always from [pcsx-redux](https://github.com/grumpycoders/pcsx-redux) and the **grumpycoders**. - -# GTEMAC.H -Great for reference! It is under `psyq\include\GTEMAC.H` - -# LIBGTE.H +# inline_n.h +This header is directly lifted from psx-redux and not my creation. I will try to give it my personal touch but the original implementation will be always from [pcsx-redux](https://github.com/grumpycoders/pcsx-redux) and the **grumpycoders**. + +# GTEMAC.H +Great for reference! It is under `psyq\include\GTEMAC.H` + +# LIBGTE.H Not so helpful but can be found under `psyq\include\LIBGTE.H` \ No newline at end of file diff --git a/src/Library/reference/inline_n.h b/src/Library/reference/inline_n.h index ba40b2e5..7ceed246 100644 --- a/src/Library/reference/inline_n.h +++ b/src/Library/reference/inline_n.h @@ -1,1517 +1,1517 @@ -/* - * GTE Macro definitions - special version for Nugget (NO DMPSX) - */ - -/* - * Type 1 functions - */ - -#define gte_ldv0(r0) \ - __asm__ volatile( \ - "lwc2 $0, 0( %0 );" \ - "lwc2 $1, 4( %0 )" \ - : \ - : "r"(r0)) - -#define gte_ldv1(r0) \ - __asm__ volatile( \ - "lwc2 $2, 0( %0 );" \ - "lwc2 $3, 4( %0 )" \ - : \ - : "r"(r0)) - -#define gte_ldv2(r0) \ - __asm__ volatile( \ - "lwc2 $4, 0( %0 );" \ - "lwc2 $5, 4( %0 )" \ - : \ - : "r"(r0)) - -#define gte_ldv3(r0, r1, r2) \ - __asm__ volatile( \ - "lwc2 $0, 0( %0 );" \ - "lwc2 $1, 4( %0 );" \ - "lwc2 $2, 0( %1 );" \ - "lwc2 $3, 4( %1 );" \ - "lwc2 $4, 0( %2 );" \ - "lwc2 $5, 4( %2 )" \ - : \ - : "r"(r0), "r"(r1), "r"(r2)) - -#define gte_ldv3c(r0) \ - __asm__ volatile( \ - "lwc2 $0, 0( %0 );" \ - "lwc2 $1, 4( %0 );" \ - "lwc2 $2, 8( %0 );" \ - "lwc2 $3, 12( %0 );" \ - "lwc2 $4, 16( %0 );" \ - "lwc2 $5, 20( %0 )" \ - : \ - : "r"(r0)) - -#define gte_ldv3c_vertc(r0) \ - __asm__ volatile( \ - "lwc2 $0, 0( %0 );" \ - "lwc2 $1, 4( %0 );" \ - "lwc2 $2, 12( %0 );" \ - "lwc2 $3, 16( %0 );" \ - "lwc2 $4, 24( %0 );" \ - "lwc2 $5, 28( %0 )" \ - : \ - : "r"(r0)) - -#define gte_ldv01(r0, r1) \ - __asm__ volatile( \ - "lwc2 $0, 0( %0 );" \ - "lwc2 $1, 4( %0 );" \ - "lwc2 $2, 0( %1 );" \ - "lwc2 $3, 4( %1 )" \ - : \ - : "r"(r0), "r"(r1)) - -#define gte_ldv01c(r0) \ - __asm__ volatile( \ - "lwc2 $0, 0( %0 );" \ - "lwc2 $1, 4( %0 );" \ - "lwc2 $2, 8( %0 );" \ - "lwc2 $3, 12( %0 )" \ - : \ - : "r"(r0)) - -#define gte_ldrgb(r0) __asm__ volatile("lwc2 $6, 0( %0 )" : : "r"(r0)) - -#define gte_ldrgb3(r0, r1, r2) \ - __asm__ volatile( \ - "lwc2 $20, 0( %0 );" \ - "lwc2 $21, 0( %1 );" \ - "lwc2 $22, 0( %2 );" \ - "lwc2 $6, 0( %2 )" \ - : \ - : "r"(r0), "r"(r1), "r"(r2)) - -#define gte_ldrgb3c(r0) \ - __asm__ volatile( \ - "lwc2 $20, 0( %0 );" \ - "lwc2 $21, 4( %0 );" \ - "lwc2 $22, 8( %0 );" \ - "lwc2 $6, 8( %0 )" \ - : \ - : "r"(r0)) - -#define gte_ldlv0(r0) \ - __asm__ volatile( \ - "lhu $13, 4( %0 );" \ - "lhu $12, 0( %0 );" \ - "sll $13, $13, 16;" \ - "or $12, $12, $13;" \ - "mtc2 $12, $0;" \ - "lwc2 $1, 8( %0 )" \ - : \ - : "r"(r0) \ - : "$12", "$13") - -#define gte_ldlvl(r0) \ - __asm__ volatile( \ - "lwc2 $9, 0( %0 );" \ - "lwc2 $10, 4( %0 );" \ - "lwc2 $11, 8( %0 )" \ - : \ - : "r"(r0)) - -#define gte_ldsv(r0) \ - __asm__ volatile( \ - "lhu $12, 0( %0 );" \ - "lhu $13, 2( %0 );" \ - "lhu $14, 4( %0 );" \ - "mtc2 $12, $9;" \ - "mtc2 $13, $10;" \ - "mtc2 $14, $11" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14") - -#define gte_ldbv(r0) \ - __asm__ volatile( \ - "lbu $12, 0( %0 );" \ - "lbu $13, 1( %0 );" \ - "mtc2 $12, $9;" \ - "mtc2 $13, $10" \ - : \ - : "r"(r0) \ - : "$12", "$13") - -#define gte_ldcv(r0) \ - __asm__ volatile( \ - "lbu $12, 0( %0 );" \ - "lbu $13, 1( %0 );" \ - "lbu $14, 2( %0 );" \ - "mtc2 $12, $9;" \ - "mtc2 $13, $10;" \ - "mtc2 $14, $11" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14") - -#define gte_ldclmv(r0) \ - __asm__ volatile( \ - "lhu $12, 0( %0 );" \ - "lhu $13, 6( %0 );" \ - "lhu $14, 12( %0 );" \ - "mtc2 $12, $9;" \ - "mtc2 $13, $10;" \ - "mtc2 $14, $11" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14") - -#define gte_lddp(r0) __asm__ volatile("mtc2 %0, $8" : : "r"(r0)) - -#define gte_ldsxy0(r0) __asm__ volatile("mtc2 %0, $12" : : "r"(r0)) - -#define gte_ldsxy1(r0) __asm__ volatile("mtc2 %0, $13" : : "r"(r0)) - -#define gte_ldsxy2(r0) __asm__ volatile("mtc2 %0, $14" : : "r"(r0)) - -#define gte_ldsxy3(r0, r1, r2) \ - __asm__ volatile( \ - "mtc2 %0, $12;" \ - "mtc2 %2, $14;" \ - "mtc2 %1, $13" \ - : \ - : "r"(r0), "r"(r1), "r"(r2)) - -#define gte_ldsxy3c(r0) \ - __asm__ volatile( \ - "lwc2 $12, 0( %0 );" \ - "lwc2 $13, 4( %0 );" \ - "lwc2 $14, 8( %0 )" \ - : \ - : "r"(r0)) - -#define gte_ldsz3(r0, r1, r2) \ - __asm__ volatile( \ - "mtc2 %0, $17;" \ - "mtc2 %1, $18;" \ - "mtc2 %2, $19" \ - : \ - : "r"(r0), "r"(r1), "r"(r2)) - -#define gte_ldsz4(r0, r1, r2, r3) \ - __asm__ volatile( \ - "mtc2 %0, $16;" \ - "mtc2 %1, $17;" \ - "mtc2 %2, $18;" \ - "mtc2 %3, $19" \ - : \ - : "r"(r0), "r"(r1), "r"(r2), "r"(r3)) - -#define gte_ldopv1(r0) \ - __asm__ volatile( \ - "lw $12, 0( %0 );" \ - "lw $13, 4( %0 );" \ - "ctc2 $12, $0;" \ - "lw $14, 8( %0 );" \ - "ctc2 $13, $2;" \ - "ctc2 $14, $4" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14") - -#define gte_ldopv2(r0) \ - __asm__ volatile( \ - "lwc2 $11, 8( %0 );" \ - "lwc2 $9, 0( %0 );" \ - "lwc2 $10, 4( %0 )" \ - : \ - : "r"(r0)) - -#define gte_ldlzc(r0) __asm__ volatile("mtc2 %0, $30" : : "r"(r0)) - -#define gte_SetRGBcd(r0) __asm__ volatile("lwc2 $6, 0( %0 )" : : "r"(r0)) - -#define gte_ldbkdir(r0, r1, r2) \ - __asm__ volatile( \ - "ctc2 %0, $13;" \ - "ctc2 %1, $14;" \ - "ctc2 %2, $15" \ - : \ - : "r"(r0), "r"(r1), "r"(r2)) - -#define gte_SetBackColor(r0, r1, r2) \ - __asm__ volatile( \ - "sll $12, %0, 4;" \ - "sll $13, %1, 4;" \ - "sll $14, %2, 4;" \ - "ctc2 $12, $13;" \ - "ctc2 $13, $14;" \ - "ctc2 $14, $15" \ - : \ - : "r"(r0), "r"(r1), "r"(r2) \ - : "$12", "$13", "$14") - -#define gte_ldfcdir(r0, r1, r2) \ - __asm__ volatile( \ - "ctc2 %0, $21;" \ - "ctc2 %1, $22;" \ - "ctc2 %2, $23" \ - : \ - : "r"(r0), "r"(r1), "r"(r2)) - -#define gte_SetFarColor(r0, r1, r2) \ - __asm__ volatile( \ - "sll $12, %0, 4;" \ - "sll $13, %1, 4;" \ - "sll $14, %2, 4;" \ - "ctc2 $12, $21;" \ - "ctc2 $13, $22;" \ - "ctc2 $14, $23" \ - : \ - : "r"(r0), "r"(r1), "r"(r2) \ - : "$12", "$13", "$14") - -#define gte_SetGeomOffset(r0, r1) \ - __asm__ volatile( \ - "sll $12, %0, 16;" \ - "sll $13, %1, 16;" \ - "ctc2 $12, $24;" \ - "ctc2 $13, $25" \ - : \ - : "r"(r0), "r"(r1) \ - : "$12", "$13") - -#define gte_SetGeomScreen(r0) __asm__ volatile("ctc2 %0, $26" : : "r"(r0)) - -#define gte_ldsvrtrow0(r0) \ - __asm__ volatile( \ - "lw $12, 0( %0 );" \ - "lw $13, 4( %0 );" \ - "ctc2 $12, $0;" \ - "ctc2 $13, $1" \ - : \ - : "r"(r0) \ - : "$12", "$13") - -#define gte_SetRotMatrix(r0) \ - __asm__ volatile( \ - "lw $12, 0( %0 );" \ - "lw $13, 4( %0 );" \ - "ctc2 $12, $0;" \ - "ctc2 $13, $1;" \ - "lw $12, 8( %0 );" \ - "lw $13, 12( %0 );" \ - "lw $14, 16( %0 );" \ - "ctc2 $12, $2;" \ - "ctc2 $13, $3;" \ - "ctc2 $14, $4" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14") - -#define gte_ldsvllrow0(r0) \ - __asm__ volatile( \ - "lw $12, 0( %0 );" \ - "lw $13, 4( %0 );" \ - "ctc2 $12, $8;" \ - "ctc2 $13, $9" \ - : \ - : "r"(r0) \ - : "$12", "$13") - -#define gte_SetLightMatrix(r0) \ - __asm__ volatile( \ - "lw $12, 0( %0 );" \ - "lw $13, 4( %0 );" \ - "ctc2 $12, $8;" \ - "ctc2 $13, $9;" \ - "lw $12, 8( %0 );" \ - "lw $13, 12( %0 );" \ - "lw $14, 16( %0 );" \ - "ctc2 $12, $10;" \ - "ctc2 $13, $11;" \ - "ctc2 $14, $12" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14") - -#define gte_ldsvlcrow0(r0) \ - __asm__ volatile( \ - "lw $12, 0( %0 );" \ - "lw $13, 4( %0 );" \ - "ctc2 $12, $16;" \ - "ctc2 $13, $17" \ - : \ - : "r"(r0) \ - : "$12", "$13") - -#define gte_SetColorMatrix(r0) \ - __asm__ volatile( \ - "lw $12, 0( %0 );" \ - "lw $13, 4( %0 );" \ - "ctc2 $12, $16;" \ - "ctc2 $13, $17;" \ - "lw $12, 8( %0 );" \ - "lw $13, 12( %0 );" \ - "lw $14, 16( %0 );" \ - "ctc2 $12, $18;" \ - "ctc2 $13, $19;" \ - "ctc2 $14, $20" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14") - -#define gte_SetTransMatrix(r0) \ - __asm__ volatile( \ - "lw $12, 20( %0 );" \ - "lw $13, 24( %0 );" \ - "ctc2 $12, $5;" \ - "lw $14, 28( %0 );" \ - "ctc2 $13, $6;" \ - "ctc2 $14, $7" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14") - -#define gte_ldtr(r0, r1, r2) \ - __asm__ volatile( \ - "ctc2 %0, $5;" \ - "ctc2 %1, $6;" \ - "ctc2 %2, $7" \ - : \ - : "r"(r0), "r"(r1), "r"(r2)) - -#define gte_SetTransVector(r0) \ - __asm__ volatile( \ - "lw $12, 0( %0 );" \ - "lw $13, 4( %0 );" \ - "lw $14, 8( %0 );" \ - "ctc2 $12, $5;" \ - "ctc2 $13, $6;" \ - "ctc2 $14, $7" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14") - -#define gte_ld_intpol_uv0(r0) \ - __asm__ volatile( \ - "lbu $12, 0( %0 );" \ - "lbu $13, 1( %0 );" \ - "ctc2 $12, $21;" \ - "ctc2 $13, $22" \ - : \ - : "r"(r0) \ - : "$12", "$13") - -#define gte_ld_intpol_uv1(r0) \ - __asm__ volatile( \ - "lbu $12, 0( %0 );" \ - "lbu $13, 1( %0 );" \ - "mtc2 $12, $9;" \ - "mtc2 $13, $10" \ - : \ - : "r"(r0) \ - : "$12", "$13") - -#define gte_ld_intpol_bv0(r0) \ - __asm__ volatile( \ - "lbu $12, 0( %0 );" \ - "lbu $13, 1( %0 );" \ - "ctc2 $12, $21;" \ - "ctc2 $13, $22" \ - : \ - : "r"(r0) \ - : "$12", "$13") - -#define gte_ld_intpol_bv1(r0) \ - __asm__ volatile( \ - "lbu $12, 0( %0 );" \ - "lbu $13, 1( %0 );" \ - "mtc2 $12, $9;" \ - "mtc2 $13, $10" \ - : \ - : "r"(r0) \ - : "$12", "$13") - -#define gte_ld_intpol_sv0(r0) \ - __asm__ volatile( \ - "lh $12, 0( %0 );" \ - "lh $13, 2( %0 );" \ - "lh $14, 4( %0 );" \ - "ctc2 $12, $21;" \ - "ctc2 $13, $22;" \ - "ctc2 $14, $23" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14") - -#define gte_ld_intpol_sv1(r0) \ - __asm__ volatile( \ - "lh $12, 0( %0 );" \ - "lh $13, 2( %0 );" \ - "lh $14, 4( %0 );" \ - "mtc2 $12, $9;" \ - "mtc2 $13, $10;" \ - "mtc2 $14, $11" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14") - -#define gte_ldfc(r0) \ - __asm__ volatile( \ - "lw $12, 0( %0 );" \ - "lw $13, 4( %0 );" \ - "lw $14, 8( %0 );" \ - "ctc2 $12, $21;" \ - "ctc2 $13, $22;" \ - "ctc2 $14, $23" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14") - -#define gte_ldopv2SV(r0) \ - __asm__ volatile( \ - "lh $12, 0( %0 );" \ - "lh $13, 2( %0 );" \ - "lh $14, 4( %0 );" \ - "mtc2 $12, $9;" \ - "mtc2 $13, $10;" \ - "mtc2 $14, $11" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14") - -#define gte_ldopv1SV(r0) \ - __asm__ volatile( \ - "lh $12, 0( %0 );" \ - "lh $13, 2( %0 );" \ - "ctc2 $12, $0;" \ - "lh $14, 4( %0 );" \ - "ctc2 $13, $2;" \ - "ctc2 $14, $4" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14") - -/* - * Type 2 functions - */ - -#define gte_rtps() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0180001;") - -#define gte_rtpt() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0280030;") - -#define gte_rt() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0480012;") - -#define gte_rtv0() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0486012;") - -#define gte_rtv1() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x048E012;") - -#define gte_rtv2() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0496012;") - -#define gte_rtir() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x049E012;") - -#define gte_rtir_sf0() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x041E012;") - -#define gte_rtv0tr() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0480012;") - -#define gte_rtv1tr() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0488012;") - -#define gte_rtv2tr() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0490012;") - -#define gte_rtirtr() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0498012;") - -#define gte_rtv0bk() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0482012;") - -#define gte_rtv1bk() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x048A012;") - -#define gte_rtv2bk() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0492012;") - -#define gte_rtirbk() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x049A012;") - -#define gte_ll() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04A6412;") - -#define gte_llv0() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04A6012;") - -#define gte_llv1() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04AE012;") - -#define gte_llv2() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04B6012;") - -#define gte_llir() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04BE012;") - -#define gte_llv0tr() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04A0012;") - -#define gte_llv1tr() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04A8012;") - -#define gte_llv2tr() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04B0012;") - -#define gte_llirtr() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04B8012;") - -#define gte_llv0bk() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04A2012;") - -#define gte_llv1bk() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04AA012;") - -#define gte_llv2bk() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04B2012;") - -#define gte_llirbk() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04BA012;") - -#define gte_lc() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04DA412;") - -#define gte_lcv0() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04C6012;") - -#define gte_lcv1() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04CE012;") - -#define gte_lcv2() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04D6012;") - -#define gte_lcir() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04DE012;") - -#define gte_lcv0tr() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04C0012;") - -#define gte_lcv1tr() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04C8012;") - -#define gte_lcv2tr() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04D0012;") - -#define gte_lcirtr() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04D8012;") - -#define gte_lcv0bk() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04C2012;") - -#define gte_lcv1bk() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04CA012;") - -#define gte_lcv2bk() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04D2012;") - -#define gte_lcirbk() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x04DA012;") - -#define gte_dpcl() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0680029;") - -#define gte_dpcs() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0780010;") - -#define gte_dpct() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0F8002A;") - -#define gte_intpl() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0980011;") - -#define gte_sqr12() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0A80428;") - -#define gte_sqr0() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0A00428;") - -#define gte_ncs() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0C8041E;") - -#define gte_nct() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0D80420;") - -#define gte_ncds() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0E80413;") - -#define gte_ncdt() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0F80416;") - -#define gte_nccs() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0108041B;") - -#define gte_ncct() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0118043F;") - -#define gte_cdp() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x01280414;") - -#define gte_cc() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0138041C;") - -#define gte_nclip() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x01400006;") - -#define gte_avsz3() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0158002D;") - -#define gte_avsz4() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0168002E;") - -#define gte_op12() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0178000C;") - -#define gte_op0() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0170000C;") - -#define gte_gpf12() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0198003D;") - -#define gte_gpf0() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x0190003D;") - -#define gte_gpl12() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x01A8003E;") - -#define gte_gpl0() \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 0x01A0003E0") - -#define gte_mvmva_core(r0) \ - __asm__ volatile( \ - "nop;" \ - "nop;" \ - "cop2 %0" \ - : \ - : "g"(r0)) - -#define gte_mvmva(sf, mx, v, cv, lm) \ - gte_mvmva_core(0x0400012 | ((sf) << 19) | ((mx) << 17) | ((v) << 15) | ((cv) << 13) | ((lm) << 10)) - -/* - * Type 2 functions without nop - */ - -#define gte_rtps_b() __asm__ volatile("cop2 0x0180001;") -#define gte_rtpt_b() __asm__ volatile("cop2 0x0280030;") -#define gte_rt_b() __asm__ volatile("cop2 0x0480012;") -#define gte_rtv0_b() __asm__ volatile("cop2 0x0486012;") -#define gte_rtv1_b() __asm__ volatile("cop2 0x048E012;") -#define gte_rtv2_b() __asm__ volatile("cop2 0x0496012;") -#define gte_rtir_b() __asm__ volatile("cop2 0x049E012;") -#define gte_rtir_sf0_b() __asm__ volatile("cop2 0x041E012;") -#define gte_rtv0tr_b() __asm__ volatile("cop2 0x0480012;") -#define gte_rtv1tr_b() __asm__ volatile("cop2 0x0488012;") -#define gte_rtv2tr_b() __asm__ volatile("cop2 0x0490012;") -#define gte_rtirtr_b() __asm__ volatile("cop2 0x0498012;") -#define gte_rtv0bk_b() __asm__ volatile("cop2 0x0482012;") -#define gte_rtv1bk_b() __asm__ volatile("cop2 0x048A012;") -#define gte_rtv2bk_b() __asm__ volatile("cop2 0x0492012;") -#define gte_rtirbk_b() __asm__ volatile("cop2 0x049A012;") -#define gte_ll_b() __asm__ volatile("cop2 0x04A6412;") -#define gte_llv0_b() __asm__ volatile("cop2 0x04A6012;") -#define gte_llv1_b() __asm__ volatile("cop2 0x04AE012;") -#define gte_llv2_b() __asm__ volatile("cop2 0x04B6012;") -#define gte_llir_b() __asm__ volatile("cop2 0x04BE012;") -#define gte_llv0tr_b() __asm__ volatile("cop2 0x04A0012;") -#define gte_llv1tr_b() __asm__ volatile("cop2 0x04A8012;") -#define gte_llv2tr_b() __asm__ volatile("cop2 0x04B0012;") -#define gte_llirtr_b() __asm__ volatile("cop2 0x04B8012;") -#define gte_llv0bk_b() __asm__ volatile("cop2 0x04A2012;") -#define gte_llv1bk_b() __asm__ volatile("cop2 0x04AA012;") -#define gte_llv2bk_b() __asm__ volatile("cop2 0x04B2012;") -#define gte_llirbk_b() __asm__ volatile("cop2 0x04BA012;") -#define gte_lc_b() __asm__ volatile("cop2 0x04DA412;") -#define gte_lcv0_b() __asm__ volatile("cop2 0x04C6012;") -#define gte_lcv1_b() __asm__ volatile("cop2 0x04CE012;") -#define gte_lcv2_b() __asm__ volatile("cop2 0x04D6012;") -#define gte_lcir_b() __asm__ volatile("cop2 0x04DE012;") -#define gte_lcv0tr_b() __asm__ volatile("cop2 0x04C0012;") -#define gte_lcv1tr_b() __asm__ volatile("cop2 0x04C8012;") -#define gte_lcv2tr_b() __asm__ volatile("cop2 0x04D0012;") -#define gte_lcirtr_b() __asm__ volatile("cop2 0x04D8012;") -#define gte_lcv0bk_b() __asm__ volatile("cop2 0x04C2012;") -#define gte_lcv1bk_b() __asm__ volatile("cop2 0x04CA012;") -#define gte_lcv2bk_b() __asm__ volatile("cop2 0x04D2012;") -#define gte_lcirbk_b() __asm__ volatile("cop2 0x04DA012;") -#define gte_dpcl_b() __asm__ volatile("cop2 0x0680029;") -#define gte_dpcs_b() __asm__ volatile("cop2 0x0780010;") -#define gte_dpct_b() __asm__ volatile("cop2 0x0F8002A;") -#define gte_intpl_b() __asm__ volatile("cop2 0x0980011;") -#define gte_sqr12_b() __asm__ volatile("cop2 0x0A80428;") -#define gte_sqr0_b() __asm__ volatile("cop2 0x0A00428;") -#define gte_ncs_b() __asm__ volatile("cop2 0x0C8041E;") -#define gte_nct_b() __asm__ volatile("cop2 0x0D80420;") -#define gte_ncds_b() __asm__ volatile("cop2 0x0E80413;") -#define gte_ncdt_b() __asm__ volatile("cop2 0x0F80416;") -#define gte_nccs_b() __asm__ volatile("cop2 0x0108041B;") -#define gte_ncct_b() __asm__ volatile("cop2 0x0118043F;") -#define gte_cdp_b() __asm__ volatile("cop2 0x01280414;") -#define gte_cc_b() __asm__ volatile("cop2 0x0138041C;") -#define gte_nclip_b() __asm__ volatile("cop2 0x01400006;") -#define gte_avsz3_b() __asm__ volatile("cop2 0x0158002D;") -#define gte_avsz4_b() __asm__ volatile("cop2 0x0168002E;") -#define gte_op12_b() __asm__ volatile("cop2 0x0178000C;") -#define gte_op0_b() __asm__ volatile("cop2 0x0170000C;") -#define gte_gpf12_b() __asm__ volatile("cop2 0x0198003D;") -#define gte_gpf0_b() __asm__ volatile("cop2 0x0190003D;") -#define gte_gpl12_b() __asm__ volatile("cop2 0x01A8003E;") -#define gte_gpl0_b() __asm__ volatile("cop2 0x01A0003E0;") -#define gte_mvmva_core_b(r0) __asm__ volatile("cop2 %0" : : "g"(r0)) -#define gte_mvmva_b(sf, mx, v, cv, lm) \ - gte_mvmva_core_b(0x0400012 | ((sf) << 19) | ((mx) << 17) | ((v) << 15) | ((cv) << 13) | ((lm) << 10)) - -/* - * Type 3 functions - */ - -#define gte_stsxy(r0) __asm__ volatile("swc2 $14, 0( %0 )" : : "r"(r0) : "memory") - -#define gte_stsxy3(r0, r1, r2) \ - __asm__ volatile( \ - "swc2 $12, 0( %0 );" \ - "swc2 $13, 0( %1 );" \ - "swc2 $14, 0( %2 )" \ - : \ - : "r"(r0), "r"(r1), "r"(r2) \ - : "memory") - -#define gte_stsxy3c(r0) \ - __asm__ volatile( \ - "swc2 $12, 0( %0 );" \ - "swc2 $13, 4( %0 );" \ - "swc2 $14, 8( %0 )" \ - : \ - : "r"(r0) \ - : "memory") - -#define gte_stsxy2(r0) __asm__ volatile("swc2 $14, 0( %0 )" : : "r"(r0) : "memory") - -#define gte_stsxy1(r0) __asm__ volatile("swc2 $13, 0( %0 )" : : "r"(r0) : "memory") - -#define gte_stsxy0(r0) __asm__ volatile("swc2 $12, 0( %0 )" : : "r"(r0) : "memory") - -#define gte_stsxy01(r0, r1) \ - __asm__ volatile( \ - "swc2 $12, 0( %0 );" \ - "swc2 $13, 0( %1 )" \ - : \ - : "r"(r0), "r"(r1) \ - : "memory") - -#define gte_stsxy01c(r0) \ - __asm__ volatile( \ - "swc2 $12, 0( %0 );" \ - "swc2 $13, 4( %0 )" \ - : \ - : "r"(r0) \ - : "memory") - -#define gte_stsxy3_f3(r0) \ - __asm__ volatile( \ - "swc2 $12, 8( %0 );" \ - "swc2 $13, 12( %0 );" \ - "swc2 $14, 16( %0 )" \ - : \ - : "r"(r0) \ - : "memory") - -#define gte_stsxy3_g3(r0) \ - __asm__ volatile( \ - "swc2 $12, 8( %0 );" \ - "swc2 $13, 16( %0 );" \ - "swc2 $14, 24( %0 )" \ - : \ - : "r"(r0) \ - : "memory") - -#define gte_stsxy3_ft3(r0) \ - __asm__ volatile( \ - "swc2 $12, 8( %0 );" \ - "swc2 $13, 16( %0 );" \ - "swc2 $14, 24( %0 )" \ - : \ - : "r"(r0) \ - : "memory") - -#define gte_stsxy3_gt3(r0) \ - __asm__ volatile( \ - "swc2 $12, 8( %0 );" \ - "swc2 $13, 20( %0 );" \ - "swc2 $14, 32( %0 )" \ - : \ - : "r"(r0) \ - : "memory") - -#define gte_stsxy3_f4(r0) \ - __asm__ volatile( \ - "swc2 $12, 8( %0 );" \ - "swc2 $13, 12( %0 );" \ - "swc2 $14, 16( %0 )" \ - : \ - : "r"(r0) \ - : "memory") - -#define gte_stsxy3_g4(r0) \ - __asm__ volatile( \ - "swc2 $12, 8( %0 );" \ - "swc2 $13, 16( %0 );" \ - "swc2 $14, 24( %0 )" \ - : \ - : "r"(r0) \ - : "memory") - -#define gte_stsxy3_ft4(r0) \ - __asm__ volatile( \ - "swc2 $12, 8( %0 );" \ - "swc2 $13, 16( %0 );" \ - "swc2 $14, 24( %0 )" \ - : \ - : "r"(r0) \ - : "memory") - -#define gte_stsxy3_gt4(r0) \ - __asm__ volatile( \ - "swc2 $12, 8( %0 );" \ - "swc2 $13, 20( %0 );" \ - "swc2 $14, 32( %0 )" \ - : \ - : "r"(r0) \ - : "memory") - -#define gte_stdp(r0) __asm__ volatile("swc2 $8, 0( %0 )" : : "r"(r0) : "memory") - -#define gte_stflg(r0) \ - __asm__ volatile( \ - "cfc2 $12, $31;" \ - "nop;" \ - "sw $12, 0( %0 )" \ - : \ - : "r"(r0) \ - : "$12", "memory") - -#define gte_stflg_4(r0) \ - __asm__ volatile( \ - "cfc2 $12, $31;" \ - "addi $13, $0, 4;" \ - "sll $13, $13, 16;" \ - "and $12, $12, $13;" \ - "sw $12, 0( %0 )" \ - : \ - : "r"(r0) \ - : "$12", "$13", "memory") - -#define gte_stsz(r0) __asm__ volatile("swc2 $19, 0( %0 )" : : "r"(r0) : "memory") - -#define gte_stsz3(r0, r1, r2) \ - __asm__ volatile( \ - "swc2 $17, 0( %0 );" \ - "swc2 $18, 0( %1 );" \ - "swc2 $19, 0( %2 )" \ - : \ - : "r"(r0), "r"(r1), "r"(r2) \ - : "memory") - -#define gte_stsz4(r0, r1, r2, r3) \ - __asm__ volatile( \ - "swc2 $16, 0( %0 );" \ - "swc2 $17, 0( %1 );" \ - "swc2 $18, 0( %2 );" \ - "swc2 $19, 0( %3 )" \ - : \ - : "r"(r0), "r"(r1), "r"(r2), "r"(r3) \ - : "memory") - -#define gte_stsz3c(r0) \ - __asm__ volatile( \ - "swc2 $17, 0( %0 );" \ - "swc2 $18, 4( %0 );" \ - "swc2 $19, 8( %0 )" \ - : \ - : "r"(r0) \ - : "memory") - -#define gte_stsz4c(r0) \ - __asm__ volatile( \ - "swc2 $16, 0( %0 );" \ - "swc2 $17, 4( %0 );" \ - "swc2 $18, 8( %0 );" \ - "swc2 $19, 12( %0 )" \ - : \ - : "r"(r0) \ - : "memory") - -#define gte_stszotz(r0) \ - __asm__ volatile( \ - "mfc2 $12, $19;" \ - "nop;" \ - "sra $12, $12, 2;" \ - "sw $12, 0( %0 )" \ - : \ - : "r"(r0) \ - : "$12", "memory") - -#define gte_stotz(r0) __asm__ volatile("swc2 $7, 0( %0 )" : : "r"(r0) : "memory") - -#define gte_stopz(r0) __asm__ volatile("swc2 $24, 0( %0 )" : : "r"(r0) : "memory") - -#define gte_stlvl(r0) \ - __asm__ volatile( \ - "swc2 $9, 0( %0 );" \ - "swc2 $10, 4( %0 );" \ - "swc2 $11, 8( %0 )" \ - : \ - : "r"(r0) \ - : "memory") - -#define gte_stlvnl(r0) \ - __asm__ volatile( \ - "swc2 $25, 0( %0 );" \ - "swc2 $26, 4( %0 );" \ - "swc2 $27, 8( %0 )" \ - : \ - : "r"(r0) \ - : "memory") - -#define gte_stlvnl0(r0) __asm__ volatile("swc2 $25, 0( %0 )" : : "r"(r0) : "memory") - -#define gte_stlvnl1(r0) __asm__ volatile("swc2 $26, 0( %0 )" : : "r"(r0) : "memory") - -#define gte_stlvnl2(r0) __asm__ volatile("swc2 $27, 0( %0 )" : : "r"(r0) : "memory") - -#define gte_stsv(r0) \ - __asm__ volatile( \ - "mfc2 $12, $9;" \ - "mfc2 $13, $10;" \ - "mfc2 $14, $11;" \ - "sh $12, 0( %0 );" \ - "sh $13, 2( %0 );" \ - "sh $14, 4( %0 )" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14", "memory") - -#define gte_stclmv(r0) \ - __asm__ volatile( \ - "mfc2 $12, $9;" \ - "mfc2 $13, $10;" \ - "mfc2 $14, $11;" \ - "sh $12, 0( %0 );" \ - "sh $13, 6( %0 );" \ - "sh $14, 12( %0 )" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14", "memory") - -#define gte_stbv(r0) \ - __asm__ volatile( \ - "mfc2 $12, $9;" \ - "mfc2 $13, $10;" \ - "sb $12, 0( %0 );" \ - "sb $13, 1( %0 )" \ - : \ - : "r"(r0) \ - : "$12", "$13", "memory") - -#define gte_stcv(r0) \ - __asm__ volatile( \ - "mfc2 $12, $9;" \ - "mfc2 $13, $10;" \ - "mfc2 $14, $11;" \ - "sb $12, 0( %0 );" \ - "sb $13, 1( %0 );" \ - "sb $14, 2( %0 )" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14", "memory") - -#define gte_strgb(r0) __asm__ volatile("swc2 $22, 0( %0 )" : : "r"(r0) : "memory") - -#define gte_strgb3(r0, r1, r2) \ - __asm__ volatile( \ - "swc2 $20, 0( %0 );" \ - "swc2 $21, 0( %1 );" \ - "swc2 $22, 0( %2 )" \ - : \ - : "r"(r0), "r"(r1), "r"(r2) \ - : "memory") - -#define gte_strgb3_g3(r0) \ - __asm__ volatile( \ - "swc2 $20, 4( %0 );" \ - "swc2 $21, 12( %0 );" \ - "swc2 $22, 20( %0 )" \ - : \ - : "r"(r0) \ - : "memory") - -#define gte_strgb3_gt3(r0) \ - __asm__ volatile( \ - "swc2 $20, 4( %0 );" \ - "swc2 $21, 16( %0 );" \ - "swc2 $22, 28( %0 )" \ - : \ - : "r"(r0) \ - : "memory") - -#define gte_strgb3_g4(r0) \ - __asm__ volatile( \ - "swc2 $20, 4( %0 );" \ - "swc2 $21, 12( %0 );" \ - "swc2 $22, 20( %0 )" \ - : \ - : "r"(r0) \ - : "memory") - -#define gte_strgb3_gt4(r0) \ - __asm__ volatile( \ - "swc2 $20, 4( %0 );" \ - "swc2 $21, 16( %0 );" \ - "swc2 $22, 28( %0 )" \ - : \ - : "r"(r0) \ - : "memory") - -#define gte_ReadGeomOffset(r0, r1) \ - __asm__ volatile( \ - "cfc2 $12, $24;" \ - "cfc2 $13, $25;" \ - "sra $12, $12, 16;" \ - "sra $13, $13, 16;" \ - "sw $12, 0( %0 );" \ - "sw $13, 0( %1 )" \ - : \ - : "r"(r0), "r"(r1) \ - : "$12", "$13", "memory") - -#define gte_ReadGeomScreen(r0) \ - __asm__ volatile( \ - "cfc2 $12, $26;" \ - "nop;" \ - "sw $12, 0( %0 )" \ - : \ - : "r"(r0) \ - : "$12", "memory") - -#define gte_ReadRotMatrix(r0) \ - __asm__ volatile( \ - "cfc2 $12, $0;" \ - "cfc2 $13, $1;" \ - "sw $12, 0( %0 );" \ - "sw $13, 4( %0 );" \ - "cfc2 $12, $2;" \ - "cfc2 $13, $3;" \ - "cfc2 $14, $4;" \ - "sw $12, 8( %0 );" \ - "sw $13, 12( %0 );" \ - "sw $14, 16( %0 );" \ - "cfc2 $12, $5;" \ - "cfc2 $13, $6;" \ - "cfc2 $14, $7;" \ - "sw $12, 20( %0 );" \ - "sw $13, 24( %0 );" \ - "sw $14, 28( %0 )" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14", "memory") - -#define gte_sttr(r0) \ - __asm__ volatile( \ - "cfc2 $12, $5;" \ - "cfc2 $13, $6;" \ - "cfc2 $14, $7;" \ - "sw $12, 0( %0 );" \ - "sw $13, 4( %0 );" \ - "sw $14, 8( %0 )" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14", "memory") - -#define gte_ReadLightMatrix(r0) \ - __asm__ volatile( \ - "cfc2 $12, $8;" \ - "cfc2 $13, $9;" \ - "sw $12, 0( %0 );" \ - "sw $13, 4( %0 );" \ - "cfc2 $12, $10;" \ - "cfc2 $13, $11;" \ - "cfc2 $14, $12;" \ - "sw $12, 8( %0 );" \ - "sw $13, 12( %0 );" \ - "sw $14, 16( %0 );" \ - "cfc2 $12, $13;" \ - "cfc2 $13, $14;" \ - "cfc2 $14, $15;" \ - "sw $12, 20( %0 );" \ - "sw $13, 24( %0 );" \ - "sw $14, 28( %0 )" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14", "memory") - -#define gte_ReadColorMatrix(r0) \ - __asm__ volatile( \ - "cfc2 $12, $16;" \ - "cfc2 $13, $17;" \ - "sw $12, 0( %0 );" \ - "sw $13, 4( %0 );" \ - "cfc2 $12, $18;" \ - "cfc2 $13, $19;" \ - "cfc2 $14, $20;" \ - "sw $12, 8( %0 );" \ - "sw $13, 12( %0 );" \ - "sw $14, 16( %0 );" \ - "cfc2 $12, $21;" \ - "cfc2 $13, $22;" \ - "cfc2 $14, $23;" \ - "sw $12, 20( %0 );" \ - "sw $13, 24( %0 );" \ - "sw $14, 28( %0 )" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14", "memory") - -#define gte_stlzc(r0) __asm__ volatile("swc2 $31, 0( %0 )" : : "r"(r0) : "memory") - -#define gte_stfc(r0) \ - __asm__ volatile( \ - "cfc2 $12, $21;" \ - "cfc2 $13, $22;" \ - "cfc2 $14, $23;" \ - "sw $12, 0( %0 );" \ - "sw $13, 4( %0 );" \ - "sw $14, 8( %0 )" \ - : \ - : "r"(r0) \ - : "$12", "$13", "$14", "memory") - -#define gte_mvlvtr() \ - __asm__ volatile( \ - "mfc2 $12, $25;" \ - "mfc2 $13, $26;" \ - "mfc2 $14, $27;" \ - "ctc2 $12, $5;" \ - "ctc2 $13, $6;" \ - "ctc2 $14, $7" \ - : \ - : \ - : "$12", "$13", "$14") - -#define gte_nop() __asm__ volatile("nop") - -#define gte_subdvl(r0, r1, r2) \ - __asm__ volatile( \ - "lw $12, 0( %0 );" \ - "lw $13, 0( %1 );" \ - "mtc2 $12, $9;" \ - "mtc2 $13, $10;" \ - "sra $12, $12, 16;" \ - "sra $13, $13, 16;" \ - "subu $15, $12, $13;" \ - "mfc2 $12, $9;" \ - "mfc2 $13, $10;" \ - "sw $15, 4( %2 );" \ - "subu $12, $12, $13;" \ - "sw $12, 0( %2 )" \ - : \ - : "r"(r0), "r"(r1), "r"(r2) \ - : "$12", "$13", "$14", "$15", "memory") - -#define gte_subdvd(r0, r1, r2) \ - __asm__ volatile( \ - "lw $12, 0( %0 );" \ - "lw $13, 0( %1 );" \ - "mtc2 $12, $9;" \ - "mtc2 $13, $10;" \ - "sra $12, $12, 16;" \ - "sra $13, $13, 16;" \ - "subu $15, $12, $13;" \ - "mfc2 $12, $9;" \ - "mfc2 $13, $10;" \ - "sh $15, 2( %2 );" \ - "subu $12, $12, $13;" \ - "sh $12, 0( %2 )" \ - : \ - : "r"(r0), "r"(r1), "r"(r2) \ - : "$12", "$13", "$14", "$15", "memory") - -#define gte_adddvl(r0, r1, r2) \ - __asm__ volatile( \ - "lw $12, 0( %0 );" \ - "lw $13, 0( %1 );" \ - "mtc2 $12, $9;" \ - "mtc2 $13, $10;" \ - "sra $12, $12, 16;" \ - "sra $13, $13, 16;" \ - "addu $15, $12, $13;" \ - "mfc2 $12, $9;" \ - "mfc2 $13, $10;" \ - "sw $15, 4( %2 );" \ - "addu $12, $12, $13;" \ - "sw $12, 0( %2 )" \ - : \ - : "r"(r0), "r"(r1), "r"(r2) \ - : "$12", "$13", "$14", "$15", "memory") - -#define gte_adddvd(r0, r1, r2) \ - __asm__ volatile( \ - "lw $12, 0( %0 );" \ - "lw $13, 0( %1 );" \ - "mtc2 $12, $9;" \ - "mtc2 $13, $10;" \ - "sra $12, $12, 16;" \ - "sra $13, $13, 16;" \ - "addu $15, $12, $13;" \ - "mfc2 $12, $9;" \ - "mfc2 $13, $10;" \ - "sh $15, 2( %2 );" \ - "addu $12, $12, $13;" \ - "sh $12, 0( %2 )" \ - : \ - : "r"(r0), "r"(r1), "r"(r2) \ - : "$12", "$13", "$14", "$15", "memory") - -#define gte_FlipRotMatrixX() \ - __asm__ volatile( \ - "cfc2 $12, $0;" \ - "cfc2 $13, $1;" \ - "sll $14, $12, 16;" \ - "sra $14, $14, 16;" \ - "subu $14, $0, $14;" \ - "sra $15, $12, 16;" \ - "subu $15, $0, $15;" \ - "sll $15, $15, 16;" \ - "sll $14, $14, 16;" \ - "srl $14, $14, 16;" \ - "or $14, $14, $15;" \ - "ctc2 $14, $0;" \ - "sll $14, $13, 16;" \ - "sra $14, $14, 16;" \ - "subu $14, $0, $14;" \ - "sra $15, $13, 16;" \ - "sll $15, $15, 16;" \ - "sll $14, $14, 16;" \ - "srl $14, $14, 16;" \ - "or $14, $14, $15;" \ - "ctc2 $14, $1" \ - : \ - : \ - : "$12", "$13", "$14", "$15") - -#define gte_FlipTRX() \ - __asm__ volatile( \ - "cfc2 $12, $5;" \ - "nop;" \ - "subu $12, $0, $12;" \ - "ctc2 $12, $5" \ - : \ - : \ - : "$12") +/* + * GTE Macro definitions - special version for Nugget (NO DMPSX) + */ + +/* + * Type 1 functions + */ + +#define gte_ldv0(r0) \ + __asm__ volatile( \ + "lwc2 $0, 0( %0 );" \ + "lwc2 $1, 4( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldv1(r0) \ + __asm__ volatile( \ + "lwc2 $2, 0( %0 );" \ + "lwc2 $3, 4( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldv2(r0) \ + __asm__ volatile( \ + "lwc2 $4, 0( %0 );" \ + "lwc2 $5, 4( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldv3(r0, r1, r2) \ + __asm__ volatile( \ + "lwc2 $0, 0( %0 );" \ + "lwc2 $1, 4( %0 );" \ + "lwc2 $2, 0( %1 );" \ + "lwc2 $3, 4( %1 );" \ + "lwc2 $4, 0( %2 );" \ + "lwc2 $5, 4( %2 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2)) + +#define gte_ldv3c(r0) \ + __asm__ volatile( \ + "lwc2 $0, 0( %0 );" \ + "lwc2 $1, 4( %0 );" \ + "lwc2 $2, 8( %0 );" \ + "lwc2 $3, 12( %0 );" \ + "lwc2 $4, 16( %0 );" \ + "lwc2 $5, 20( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldv3c_vertc(r0) \ + __asm__ volatile( \ + "lwc2 $0, 0( %0 );" \ + "lwc2 $1, 4( %0 );" \ + "lwc2 $2, 12( %0 );" \ + "lwc2 $3, 16( %0 );" \ + "lwc2 $4, 24( %0 );" \ + "lwc2 $5, 28( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldv01(r0, r1) \ + __asm__ volatile( \ + "lwc2 $0, 0( %0 );" \ + "lwc2 $1, 4( %0 );" \ + "lwc2 $2, 0( %1 );" \ + "lwc2 $3, 4( %1 )" \ + : \ + : "r"(r0), "r"(r1)) + +#define gte_ldv01c(r0) \ + __asm__ volatile( \ + "lwc2 $0, 0( %0 );" \ + "lwc2 $1, 4( %0 );" \ + "lwc2 $2, 8( %0 );" \ + "lwc2 $3, 12( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldrgb(r0) __asm__ volatile("lwc2 $6, 0( %0 )" : : "r"(r0)) + +#define gte_ldrgb3(r0, r1, r2) \ + __asm__ volatile( \ + "lwc2 $20, 0( %0 );" \ + "lwc2 $21, 0( %1 );" \ + "lwc2 $22, 0( %2 );" \ + "lwc2 $6, 0( %2 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2)) + +#define gte_ldrgb3c(r0) \ + __asm__ volatile( \ + "lwc2 $20, 0( %0 );" \ + "lwc2 $21, 4( %0 );" \ + "lwc2 $22, 8( %0 );" \ + "lwc2 $6, 8( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldlv0(r0) \ + __asm__ volatile( \ + "lhu $13, 4( %0 );" \ + "lhu $12, 0( %0 );" \ + "sll $13, $13, 16;" \ + "or $12, $12, $13;" \ + "mtc2 $12, $0;" \ + "lwc2 $1, 8( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13") + +#define gte_ldlvl(r0) \ + __asm__ volatile( \ + "lwc2 $9, 0( %0 );" \ + "lwc2 $10, 4( %0 );" \ + "lwc2 $11, 8( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldsv(r0) \ + __asm__ volatile( \ + "lhu $12, 0( %0 );" \ + "lhu $13, 2( %0 );" \ + "lhu $14, 4( %0 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10;" \ + "mtc2 $14, $11" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ldbv(r0) \ + __asm__ volatile( \ + "lbu $12, 0( %0 );" \ + "lbu $13, 1( %0 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10" \ + : \ + : "r"(r0) \ + : "$12", "$13") + +#define gte_ldcv(r0) \ + __asm__ volatile( \ + "lbu $12, 0( %0 );" \ + "lbu $13, 1( %0 );" \ + "lbu $14, 2( %0 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10;" \ + "mtc2 $14, $11" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ldclmv(r0) \ + __asm__ volatile( \ + "lhu $12, 0( %0 );" \ + "lhu $13, 6( %0 );" \ + "lhu $14, 12( %0 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10;" \ + "mtc2 $14, $11" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_lddp(r0) __asm__ volatile("mtc2 %0, $8" : : "r"(r0)) + +#define gte_ldsxy0(r0) __asm__ volatile("mtc2 %0, $12" : : "r"(r0)) + +#define gte_ldsxy1(r0) __asm__ volatile("mtc2 %0, $13" : : "r"(r0)) + +#define gte_ldsxy2(r0) __asm__ volatile("mtc2 %0, $14" : : "r"(r0)) + +#define gte_ldsxy3(r0, r1, r2) \ + __asm__ volatile( \ + "mtc2 %0, $12;" \ + "mtc2 %2, $14;" \ + "mtc2 %1, $13" \ + : \ + : "r"(r0), "r"(r1), "r"(r2)) + +#define gte_ldsxy3c(r0) \ + __asm__ volatile( \ + "lwc2 $12, 0( %0 );" \ + "lwc2 $13, 4( %0 );" \ + "lwc2 $14, 8( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldsz3(r0, r1, r2) \ + __asm__ volatile( \ + "mtc2 %0, $17;" \ + "mtc2 %1, $18;" \ + "mtc2 %2, $19" \ + : \ + : "r"(r0), "r"(r1), "r"(r2)) + +#define gte_ldsz4(r0, r1, r2, r3) \ + __asm__ volatile( \ + "mtc2 %0, $16;" \ + "mtc2 %1, $17;" \ + "mtc2 %2, $18;" \ + "mtc2 %3, $19" \ + : \ + : "r"(r0), "r"(r1), "r"(r2), "r"(r3)) + +#define gte_ldopv1(r0) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 4( %0 );" \ + "ctc2 $12, $0;" \ + "lw $14, 8( %0 );" \ + "ctc2 $13, $2;" \ + "ctc2 $14, $4" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ldopv2(r0) \ + __asm__ volatile( \ + "lwc2 $11, 8( %0 );" \ + "lwc2 $9, 0( %0 );" \ + "lwc2 $10, 4( %0 )" \ + : \ + : "r"(r0)) + +#define gte_ldlzc(r0) __asm__ volatile("mtc2 %0, $30" : : "r"(r0)) + +#define gte_SetRGBcd(r0) __asm__ volatile("lwc2 $6, 0( %0 )" : : "r"(r0)) + +#define gte_ldbkdir(r0, r1, r2) \ + __asm__ volatile( \ + "ctc2 %0, $13;" \ + "ctc2 %1, $14;" \ + "ctc2 %2, $15" \ + : \ + : "r"(r0), "r"(r1), "r"(r2)) + +#define gte_SetBackColor(r0, r1, r2) \ + __asm__ volatile( \ + "sll $12, %0, 4;" \ + "sll $13, %1, 4;" \ + "sll $14, %2, 4;" \ + "ctc2 $12, $13;" \ + "ctc2 $13, $14;" \ + "ctc2 $14, $15" \ + : \ + : "r"(r0), "r"(r1), "r"(r2) \ + : "$12", "$13", "$14") + +#define gte_ldfcdir(r0, r1, r2) \ + __asm__ volatile( \ + "ctc2 %0, $21;" \ + "ctc2 %1, $22;" \ + "ctc2 %2, $23" \ + : \ + : "r"(r0), "r"(r1), "r"(r2)) + +#define gte_SetFarColor(r0, r1, r2) \ + __asm__ volatile( \ + "sll $12, %0, 4;" \ + "sll $13, %1, 4;" \ + "sll $14, %2, 4;" \ + "ctc2 $12, $21;" \ + "ctc2 $13, $22;" \ + "ctc2 $14, $23" \ + : \ + : "r"(r0), "r"(r1), "r"(r2) \ + : "$12", "$13", "$14") + +#define gte_SetGeomOffset(r0, r1) \ + __asm__ volatile( \ + "sll $12, %0, 16;" \ + "sll $13, %1, 16;" \ + "ctc2 $12, $24;" \ + "ctc2 $13, $25" \ + : \ + : "r"(r0), "r"(r1) \ + : "$12", "$13") + +#define gte_SetGeomScreen(r0) __asm__ volatile("ctc2 %0, $26" : : "r"(r0)) + +#define gte_ldsvrtrow0(r0) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 4( %0 );" \ + "ctc2 $12, $0;" \ + "ctc2 $13, $1" \ + : \ + : "r"(r0) \ + : "$12", "$13") + +#define gte_SetRotMatrix(r0) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 4( %0 );" \ + "ctc2 $12, $0;" \ + "ctc2 $13, $1;" \ + "lw $12, 8( %0 );" \ + "lw $13, 12( %0 );" \ + "lw $14, 16( %0 );" \ + "ctc2 $12, $2;" \ + "ctc2 $13, $3;" \ + "ctc2 $14, $4" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ldsvllrow0(r0) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 4( %0 );" \ + "ctc2 $12, $8;" \ + "ctc2 $13, $9" \ + : \ + : "r"(r0) \ + : "$12", "$13") + +#define gte_SetLightMatrix(r0) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 4( %0 );" \ + "ctc2 $12, $8;" \ + "ctc2 $13, $9;" \ + "lw $12, 8( %0 );" \ + "lw $13, 12( %0 );" \ + "lw $14, 16( %0 );" \ + "ctc2 $12, $10;" \ + "ctc2 $13, $11;" \ + "ctc2 $14, $12" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ldsvlcrow0(r0) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 4( %0 );" \ + "ctc2 $12, $16;" \ + "ctc2 $13, $17" \ + : \ + : "r"(r0) \ + : "$12", "$13") + +#define gte_SetColorMatrix(r0) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 4( %0 );" \ + "ctc2 $12, $16;" \ + "ctc2 $13, $17;" \ + "lw $12, 8( %0 );" \ + "lw $13, 12( %0 );" \ + "lw $14, 16( %0 );" \ + "ctc2 $12, $18;" \ + "ctc2 $13, $19;" \ + "ctc2 $14, $20" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_SetTransMatrix(r0) \ + __asm__ volatile( \ + "lw $12, 20( %0 );" \ + "lw $13, 24( %0 );" \ + "ctc2 $12, $5;" \ + "lw $14, 28( %0 );" \ + "ctc2 $13, $6;" \ + "ctc2 $14, $7" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ldtr(r0, r1, r2) \ + __asm__ volatile( \ + "ctc2 %0, $5;" \ + "ctc2 %1, $6;" \ + "ctc2 %2, $7" \ + : \ + : "r"(r0), "r"(r1), "r"(r2)) + +#define gte_SetTransVector(r0) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 4( %0 );" \ + "lw $14, 8( %0 );" \ + "ctc2 $12, $5;" \ + "ctc2 $13, $6;" \ + "ctc2 $14, $7" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ld_intpol_uv0(r0) \ + __asm__ volatile( \ + "lbu $12, 0( %0 );" \ + "lbu $13, 1( %0 );" \ + "ctc2 $12, $21;" \ + "ctc2 $13, $22" \ + : \ + : "r"(r0) \ + : "$12", "$13") + +#define gte_ld_intpol_uv1(r0) \ + __asm__ volatile( \ + "lbu $12, 0( %0 );" \ + "lbu $13, 1( %0 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10" \ + : \ + : "r"(r0) \ + : "$12", "$13") + +#define gte_ld_intpol_bv0(r0) \ + __asm__ volatile( \ + "lbu $12, 0( %0 );" \ + "lbu $13, 1( %0 );" \ + "ctc2 $12, $21;" \ + "ctc2 $13, $22" \ + : \ + : "r"(r0) \ + : "$12", "$13") + +#define gte_ld_intpol_bv1(r0) \ + __asm__ volatile( \ + "lbu $12, 0( %0 );" \ + "lbu $13, 1( %0 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10" \ + : \ + : "r"(r0) \ + : "$12", "$13") + +#define gte_ld_intpol_sv0(r0) \ + __asm__ volatile( \ + "lh $12, 0( %0 );" \ + "lh $13, 2( %0 );" \ + "lh $14, 4( %0 );" \ + "ctc2 $12, $21;" \ + "ctc2 $13, $22;" \ + "ctc2 $14, $23" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ld_intpol_sv1(r0) \ + __asm__ volatile( \ + "lh $12, 0( %0 );" \ + "lh $13, 2( %0 );" \ + "lh $14, 4( %0 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10;" \ + "mtc2 $14, $11" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ldfc(r0) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 4( %0 );" \ + "lw $14, 8( %0 );" \ + "ctc2 $12, $21;" \ + "ctc2 $13, $22;" \ + "ctc2 $14, $23" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ldopv2SV(r0) \ + __asm__ volatile( \ + "lh $12, 0( %0 );" \ + "lh $13, 2( %0 );" \ + "lh $14, 4( %0 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10;" \ + "mtc2 $14, $11" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +#define gte_ldopv1SV(r0) \ + __asm__ volatile( \ + "lh $12, 0( %0 );" \ + "lh $13, 2( %0 );" \ + "ctc2 $12, $0;" \ + "lh $14, 4( %0 );" \ + "ctc2 $13, $2;" \ + "ctc2 $14, $4" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14") + +/* + * Type 2 functions + */ + +#define gte_rtps() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0180001;") + +#define gte_rtpt() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0280030;") + +#define gte_rt() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0480012;") + +#define gte_rtv0() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0486012;") + +#define gte_rtv1() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x048E012;") + +#define gte_rtv2() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0496012;") + +#define gte_rtir() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x049E012;") + +#define gte_rtir_sf0() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x041E012;") + +#define gte_rtv0tr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0480012;") + +#define gte_rtv1tr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0488012;") + +#define gte_rtv2tr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0490012;") + +#define gte_rtirtr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0498012;") + +#define gte_rtv0bk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0482012;") + +#define gte_rtv1bk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x048A012;") + +#define gte_rtv2bk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0492012;") + +#define gte_rtirbk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x049A012;") + +#define gte_ll() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04A6412;") + +#define gte_llv0() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04A6012;") + +#define gte_llv1() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04AE012;") + +#define gte_llv2() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04B6012;") + +#define gte_llir() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04BE012;") + +#define gte_llv0tr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04A0012;") + +#define gte_llv1tr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04A8012;") + +#define gte_llv2tr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04B0012;") + +#define gte_llirtr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04B8012;") + +#define gte_llv0bk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04A2012;") + +#define gte_llv1bk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04AA012;") + +#define gte_llv2bk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04B2012;") + +#define gte_llirbk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04BA012;") + +#define gte_lc() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04DA412;") + +#define gte_lcv0() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04C6012;") + +#define gte_lcv1() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04CE012;") + +#define gte_lcv2() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04D6012;") + +#define gte_lcir() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04DE012;") + +#define gte_lcv0tr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04C0012;") + +#define gte_lcv1tr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04C8012;") + +#define gte_lcv2tr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04D0012;") + +#define gte_lcirtr() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04D8012;") + +#define gte_lcv0bk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04C2012;") + +#define gte_lcv1bk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04CA012;") + +#define gte_lcv2bk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04D2012;") + +#define gte_lcirbk() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x04DA012;") + +#define gte_dpcl() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0680029;") + +#define gte_dpcs() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0780010;") + +#define gte_dpct() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0F8002A;") + +#define gte_intpl() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0980011;") + +#define gte_sqr12() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0A80428;") + +#define gte_sqr0() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0A00428;") + +#define gte_ncs() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0C8041E;") + +#define gte_nct() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0D80420;") + +#define gte_ncds() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0E80413;") + +#define gte_ncdt() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0F80416;") + +#define gte_nccs() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0108041B;") + +#define gte_ncct() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0118043F;") + +#define gte_cdp() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x01280414;") + +#define gte_cc() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0138041C;") + +#define gte_nclip() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x01400006;") + +#define gte_avsz3() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0158002D;") + +#define gte_avsz4() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0168002E;") + +#define gte_op12() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0178000C;") + +#define gte_op0() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0170000C;") + +#define gte_gpf12() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0198003D;") + +#define gte_gpf0() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x0190003D;") + +#define gte_gpl12() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x01A8003E;") + +#define gte_gpl0() \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 0x01A0003E0") + +#define gte_mvmva_core(r0) \ + __asm__ volatile( \ + "nop;" \ + "nop;" \ + "cop2 %0" \ + : \ + : "g"(r0)) + +#define gte_mvmva(sf, mx, v, cv, lm) \ + gte_mvmva_core(0x0400012 | ((sf) << 19) | ((mx) << 17) | ((v) << 15) | ((cv) << 13) | ((lm) << 10)) + +/* + * Type 2 functions without nop + */ + +#define gte_rtps_b() __asm__ volatile("cop2 0x0180001;") +#define gte_rtpt_b() __asm__ volatile("cop2 0x0280030;") +#define gte_rt_b() __asm__ volatile("cop2 0x0480012;") +#define gte_rtv0_b() __asm__ volatile("cop2 0x0486012;") +#define gte_rtv1_b() __asm__ volatile("cop2 0x048E012;") +#define gte_rtv2_b() __asm__ volatile("cop2 0x0496012;") +#define gte_rtir_b() __asm__ volatile("cop2 0x049E012;") +#define gte_rtir_sf0_b() __asm__ volatile("cop2 0x041E012;") +#define gte_rtv0tr_b() __asm__ volatile("cop2 0x0480012;") +#define gte_rtv1tr_b() __asm__ volatile("cop2 0x0488012;") +#define gte_rtv2tr_b() __asm__ volatile("cop2 0x0490012;") +#define gte_rtirtr_b() __asm__ volatile("cop2 0x0498012;") +#define gte_rtv0bk_b() __asm__ volatile("cop2 0x0482012;") +#define gte_rtv1bk_b() __asm__ volatile("cop2 0x048A012;") +#define gte_rtv2bk_b() __asm__ volatile("cop2 0x0492012;") +#define gte_rtirbk_b() __asm__ volatile("cop2 0x049A012;") +#define gte_ll_b() __asm__ volatile("cop2 0x04A6412;") +#define gte_llv0_b() __asm__ volatile("cop2 0x04A6012;") +#define gte_llv1_b() __asm__ volatile("cop2 0x04AE012;") +#define gte_llv2_b() __asm__ volatile("cop2 0x04B6012;") +#define gte_llir_b() __asm__ volatile("cop2 0x04BE012;") +#define gte_llv0tr_b() __asm__ volatile("cop2 0x04A0012;") +#define gte_llv1tr_b() __asm__ volatile("cop2 0x04A8012;") +#define gte_llv2tr_b() __asm__ volatile("cop2 0x04B0012;") +#define gte_llirtr_b() __asm__ volatile("cop2 0x04B8012;") +#define gte_llv0bk_b() __asm__ volatile("cop2 0x04A2012;") +#define gte_llv1bk_b() __asm__ volatile("cop2 0x04AA012;") +#define gte_llv2bk_b() __asm__ volatile("cop2 0x04B2012;") +#define gte_llirbk_b() __asm__ volatile("cop2 0x04BA012;") +#define gte_lc_b() __asm__ volatile("cop2 0x04DA412;") +#define gte_lcv0_b() __asm__ volatile("cop2 0x04C6012;") +#define gte_lcv1_b() __asm__ volatile("cop2 0x04CE012;") +#define gte_lcv2_b() __asm__ volatile("cop2 0x04D6012;") +#define gte_lcir_b() __asm__ volatile("cop2 0x04DE012;") +#define gte_lcv0tr_b() __asm__ volatile("cop2 0x04C0012;") +#define gte_lcv1tr_b() __asm__ volatile("cop2 0x04C8012;") +#define gte_lcv2tr_b() __asm__ volatile("cop2 0x04D0012;") +#define gte_lcirtr_b() __asm__ volatile("cop2 0x04D8012;") +#define gte_lcv0bk_b() __asm__ volatile("cop2 0x04C2012;") +#define gte_lcv1bk_b() __asm__ volatile("cop2 0x04CA012;") +#define gte_lcv2bk_b() __asm__ volatile("cop2 0x04D2012;") +#define gte_lcirbk_b() __asm__ volatile("cop2 0x04DA012;") +#define gte_dpcl_b() __asm__ volatile("cop2 0x0680029;") +#define gte_dpcs_b() __asm__ volatile("cop2 0x0780010;") +#define gte_dpct_b() __asm__ volatile("cop2 0x0F8002A;") +#define gte_intpl_b() __asm__ volatile("cop2 0x0980011;") +#define gte_sqr12_b() __asm__ volatile("cop2 0x0A80428;") +#define gte_sqr0_b() __asm__ volatile("cop2 0x0A00428;") +#define gte_ncs_b() __asm__ volatile("cop2 0x0C8041E;") +#define gte_nct_b() __asm__ volatile("cop2 0x0D80420;") +#define gte_ncds_b() __asm__ volatile("cop2 0x0E80413;") +#define gte_ncdt_b() __asm__ volatile("cop2 0x0F80416;") +#define gte_nccs_b() __asm__ volatile("cop2 0x0108041B;") +#define gte_ncct_b() __asm__ volatile("cop2 0x0118043F;") +#define gte_cdp_b() __asm__ volatile("cop2 0x01280414;") +#define gte_cc_b() __asm__ volatile("cop2 0x0138041C;") +#define gte_nclip_b() __asm__ volatile("cop2 0x01400006;") +#define gte_avsz3_b() __asm__ volatile("cop2 0x0158002D;") +#define gte_avsz4_b() __asm__ volatile("cop2 0x0168002E;") +#define gte_op12_b() __asm__ volatile("cop2 0x0178000C;") +#define gte_op0_b() __asm__ volatile("cop2 0x0170000C;") +#define gte_gpf12_b() __asm__ volatile("cop2 0x0198003D;") +#define gte_gpf0_b() __asm__ volatile("cop2 0x0190003D;") +#define gte_gpl12_b() __asm__ volatile("cop2 0x01A8003E;") +#define gte_gpl0_b() __asm__ volatile("cop2 0x01A0003E0;") +#define gte_mvmva_core_b(r0) __asm__ volatile("cop2 %0" : : "g"(r0)) +#define gte_mvmva_b(sf, mx, v, cv, lm) \ + gte_mvmva_core_b(0x0400012 | ((sf) << 19) | ((mx) << 17) | ((v) << 15) | ((cv) << 13) | ((lm) << 10)) + +/* + * Type 3 functions + */ + +#define gte_stsxy(r0) __asm__ volatile("swc2 $14, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stsxy3(r0, r1, r2) \ + __asm__ volatile( \ + "swc2 $12, 0( %0 );" \ + "swc2 $13, 0( %1 );" \ + "swc2 $14, 0( %2 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2) \ + : "memory") + +#define gte_stsxy3c(r0) \ + __asm__ volatile( \ + "swc2 $12, 0( %0 );" \ + "swc2 $13, 4( %0 );" \ + "swc2 $14, 8( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsxy2(r0) __asm__ volatile("swc2 $14, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stsxy1(r0) __asm__ volatile("swc2 $13, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stsxy0(r0) __asm__ volatile("swc2 $12, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stsxy01(r0, r1) \ + __asm__ volatile( \ + "swc2 $12, 0( %0 );" \ + "swc2 $13, 0( %1 )" \ + : \ + : "r"(r0), "r"(r1) \ + : "memory") + +#define gte_stsxy01c(r0) \ + __asm__ volatile( \ + "swc2 $12, 0( %0 );" \ + "swc2 $13, 4( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsxy3_f3(r0) \ + __asm__ volatile( \ + "swc2 $12, 8( %0 );" \ + "swc2 $13, 12( %0 );" \ + "swc2 $14, 16( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsxy3_g3(r0) \ + __asm__ volatile( \ + "swc2 $12, 8( %0 );" \ + "swc2 $13, 16( %0 );" \ + "swc2 $14, 24( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsxy3_ft3(r0) \ + __asm__ volatile( \ + "swc2 $12, 8( %0 );" \ + "swc2 $13, 16( %0 );" \ + "swc2 $14, 24( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsxy3_gt3(r0) \ + __asm__ volatile( \ + "swc2 $12, 8( %0 );" \ + "swc2 $13, 20( %0 );" \ + "swc2 $14, 32( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsxy3_f4(r0) \ + __asm__ volatile( \ + "swc2 $12, 8( %0 );" \ + "swc2 $13, 12( %0 );" \ + "swc2 $14, 16( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsxy3_g4(r0) \ + __asm__ volatile( \ + "swc2 $12, 8( %0 );" \ + "swc2 $13, 16( %0 );" \ + "swc2 $14, 24( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsxy3_ft4(r0) \ + __asm__ volatile( \ + "swc2 $12, 8( %0 );" \ + "swc2 $13, 16( %0 );" \ + "swc2 $14, 24( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsxy3_gt4(r0) \ + __asm__ volatile( \ + "swc2 $12, 8( %0 );" \ + "swc2 $13, 20( %0 );" \ + "swc2 $14, 32( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stdp(r0) __asm__ volatile("swc2 $8, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stflg(r0) \ + __asm__ volatile( \ + "cfc2 $12, $31;" \ + "nop;" \ + "sw $12, 0( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "memory") + +#define gte_stflg_4(r0) \ + __asm__ volatile( \ + "cfc2 $12, $31;" \ + "addi $13, $0, 4;" \ + "sll $13, $13, 16;" \ + "and $12, $12, $13;" \ + "sw $12, 0( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "memory") + +#define gte_stsz(r0) __asm__ volatile("swc2 $19, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stsz3(r0, r1, r2) \ + __asm__ volatile( \ + "swc2 $17, 0( %0 );" \ + "swc2 $18, 0( %1 );" \ + "swc2 $19, 0( %2 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2) \ + : "memory") + +#define gte_stsz4(r0, r1, r2, r3) \ + __asm__ volatile( \ + "swc2 $16, 0( %0 );" \ + "swc2 $17, 0( %1 );" \ + "swc2 $18, 0( %2 );" \ + "swc2 $19, 0( %3 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2), "r"(r3) \ + : "memory") + +#define gte_stsz3c(r0) \ + __asm__ volatile( \ + "swc2 $17, 0( %0 );" \ + "swc2 $18, 4( %0 );" \ + "swc2 $19, 8( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stsz4c(r0) \ + __asm__ volatile( \ + "swc2 $16, 0( %0 );" \ + "swc2 $17, 4( %0 );" \ + "swc2 $18, 8( %0 );" \ + "swc2 $19, 12( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stszotz(r0) \ + __asm__ volatile( \ + "mfc2 $12, $19;" \ + "nop;" \ + "sra $12, $12, 2;" \ + "sw $12, 0( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "memory") + +#define gte_stotz(r0) __asm__ volatile("swc2 $7, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stopz(r0) __asm__ volatile("swc2 $24, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stlvl(r0) \ + __asm__ volatile( \ + "swc2 $9, 0( %0 );" \ + "swc2 $10, 4( %0 );" \ + "swc2 $11, 8( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stlvnl(r0) \ + __asm__ volatile( \ + "swc2 $25, 0( %0 );" \ + "swc2 $26, 4( %0 );" \ + "swc2 $27, 8( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_stlvnl0(r0) __asm__ volatile("swc2 $25, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stlvnl1(r0) __asm__ volatile("swc2 $26, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stlvnl2(r0) __asm__ volatile("swc2 $27, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stsv(r0) \ + __asm__ volatile( \ + "mfc2 $12, $9;" \ + "mfc2 $13, $10;" \ + "mfc2 $14, $11;" \ + "sh $12, 0( %0 );" \ + "sh $13, 2( %0 );" \ + "sh $14, 4( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14", "memory") + +#define gte_stclmv(r0) \ + __asm__ volatile( \ + "mfc2 $12, $9;" \ + "mfc2 $13, $10;" \ + "mfc2 $14, $11;" \ + "sh $12, 0( %0 );" \ + "sh $13, 6( %0 );" \ + "sh $14, 12( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14", "memory") + +#define gte_stbv(r0) \ + __asm__ volatile( \ + "mfc2 $12, $9;" \ + "mfc2 $13, $10;" \ + "sb $12, 0( %0 );" \ + "sb $13, 1( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "memory") + +#define gte_stcv(r0) \ + __asm__ volatile( \ + "mfc2 $12, $9;" \ + "mfc2 $13, $10;" \ + "mfc2 $14, $11;" \ + "sb $12, 0( %0 );" \ + "sb $13, 1( %0 );" \ + "sb $14, 2( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14", "memory") + +#define gte_strgb(r0) __asm__ volatile("swc2 $22, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_strgb3(r0, r1, r2) \ + __asm__ volatile( \ + "swc2 $20, 0( %0 );" \ + "swc2 $21, 0( %1 );" \ + "swc2 $22, 0( %2 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2) \ + : "memory") + +#define gte_strgb3_g3(r0) \ + __asm__ volatile( \ + "swc2 $20, 4( %0 );" \ + "swc2 $21, 12( %0 );" \ + "swc2 $22, 20( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_strgb3_gt3(r0) \ + __asm__ volatile( \ + "swc2 $20, 4( %0 );" \ + "swc2 $21, 16( %0 );" \ + "swc2 $22, 28( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_strgb3_g4(r0) \ + __asm__ volatile( \ + "swc2 $20, 4( %0 );" \ + "swc2 $21, 12( %0 );" \ + "swc2 $22, 20( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_strgb3_gt4(r0) \ + __asm__ volatile( \ + "swc2 $20, 4( %0 );" \ + "swc2 $21, 16( %0 );" \ + "swc2 $22, 28( %0 )" \ + : \ + : "r"(r0) \ + : "memory") + +#define gte_ReadGeomOffset(r0, r1) \ + __asm__ volatile( \ + "cfc2 $12, $24;" \ + "cfc2 $13, $25;" \ + "sra $12, $12, 16;" \ + "sra $13, $13, 16;" \ + "sw $12, 0( %0 );" \ + "sw $13, 0( %1 )" \ + : \ + : "r"(r0), "r"(r1) \ + : "$12", "$13", "memory") + +#define gte_ReadGeomScreen(r0) \ + __asm__ volatile( \ + "cfc2 $12, $26;" \ + "nop;" \ + "sw $12, 0( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "memory") + +#define gte_ReadRotMatrix(r0) \ + __asm__ volatile( \ + "cfc2 $12, $0;" \ + "cfc2 $13, $1;" \ + "sw $12, 0( %0 );" \ + "sw $13, 4( %0 );" \ + "cfc2 $12, $2;" \ + "cfc2 $13, $3;" \ + "cfc2 $14, $4;" \ + "sw $12, 8( %0 );" \ + "sw $13, 12( %0 );" \ + "sw $14, 16( %0 );" \ + "cfc2 $12, $5;" \ + "cfc2 $13, $6;" \ + "cfc2 $14, $7;" \ + "sw $12, 20( %0 );" \ + "sw $13, 24( %0 );" \ + "sw $14, 28( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14", "memory") + +#define gte_sttr(r0) \ + __asm__ volatile( \ + "cfc2 $12, $5;" \ + "cfc2 $13, $6;" \ + "cfc2 $14, $7;" \ + "sw $12, 0( %0 );" \ + "sw $13, 4( %0 );" \ + "sw $14, 8( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14", "memory") + +#define gte_ReadLightMatrix(r0) \ + __asm__ volatile( \ + "cfc2 $12, $8;" \ + "cfc2 $13, $9;" \ + "sw $12, 0( %0 );" \ + "sw $13, 4( %0 );" \ + "cfc2 $12, $10;" \ + "cfc2 $13, $11;" \ + "cfc2 $14, $12;" \ + "sw $12, 8( %0 );" \ + "sw $13, 12( %0 );" \ + "sw $14, 16( %0 );" \ + "cfc2 $12, $13;" \ + "cfc2 $13, $14;" \ + "cfc2 $14, $15;" \ + "sw $12, 20( %0 );" \ + "sw $13, 24( %0 );" \ + "sw $14, 28( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14", "memory") + +#define gte_ReadColorMatrix(r0) \ + __asm__ volatile( \ + "cfc2 $12, $16;" \ + "cfc2 $13, $17;" \ + "sw $12, 0( %0 );" \ + "sw $13, 4( %0 );" \ + "cfc2 $12, $18;" \ + "cfc2 $13, $19;" \ + "cfc2 $14, $20;" \ + "sw $12, 8( %0 );" \ + "sw $13, 12( %0 );" \ + "sw $14, 16( %0 );" \ + "cfc2 $12, $21;" \ + "cfc2 $13, $22;" \ + "cfc2 $14, $23;" \ + "sw $12, 20( %0 );" \ + "sw $13, 24( %0 );" \ + "sw $14, 28( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14", "memory") + +#define gte_stlzc(r0) __asm__ volatile("swc2 $31, 0( %0 )" : : "r"(r0) : "memory") + +#define gte_stfc(r0) \ + __asm__ volatile( \ + "cfc2 $12, $21;" \ + "cfc2 $13, $22;" \ + "cfc2 $14, $23;" \ + "sw $12, 0( %0 );" \ + "sw $13, 4( %0 );" \ + "sw $14, 8( %0 )" \ + : \ + : "r"(r0) \ + : "$12", "$13", "$14", "memory") + +#define gte_mvlvtr() \ + __asm__ volatile( \ + "mfc2 $12, $25;" \ + "mfc2 $13, $26;" \ + "mfc2 $14, $27;" \ + "ctc2 $12, $5;" \ + "ctc2 $13, $6;" \ + "ctc2 $14, $7" \ + : \ + : \ + : "$12", "$13", "$14") + +#define gte_nop() __asm__ volatile("nop") + +#define gte_subdvl(r0, r1, r2) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 0( %1 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10;" \ + "sra $12, $12, 16;" \ + "sra $13, $13, 16;" \ + "subu $15, $12, $13;" \ + "mfc2 $12, $9;" \ + "mfc2 $13, $10;" \ + "sw $15, 4( %2 );" \ + "subu $12, $12, $13;" \ + "sw $12, 0( %2 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2) \ + : "$12", "$13", "$14", "$15", "memory") + +#define gte_subdvd(r0, r1, r2) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 0( %1 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10;" \ + "sra $12, $12, 16;" \ + "sra $13, $13, 16;" \ + "subu $15, $12, $13;" \ + "mfc2 $12, $9;" \ + "mfc2 $13, $10;" \ + "sh $15, 2( %2 );" \ + "subu $12, $12, $13;" \ + "sh $12, 0( %2 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2) \ + : "$12", "$13", "$14", "$15", "memory") + +#define gte_adddvl(r0, r1, r2) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 0( %1 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10;" \ + "sra $12, $12, 16;" \ + "sra $13, $13, 16;" \ + "addu $15, $12, $13;" \ + "mfc2 $12, $9;" \ + "mfc2 $13, $10;" \ + "sw $15, 4( %2 );" \ + "addu $12, $12, $13;" \ + "sw $12, 0( %2 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2) \ + : "$12", "$13", "$14", "$15", "memory") + +#define gte_adddvd(r0, r1, r2) \ + __asm__ volatile( \ + "lw $12, 0( %0 );" \ + "lw $13, 0( %1 );" \ + "mtc2 $12, $9;" \ + "mtc2 $13, $10;" \ + "sra $12, $12, 16;" \ + "sra $13, $13, 16;" \ + "addu $15, $12, $13;" \ + "mfc2 $12, $9;" \ + "mfc2 $13, $10;" \ + "sh $15, 2( %2 );" \ + "addu $12, $12, $13;" \ + "sh $12, 0( %2 )" \ + : \ + : "r"(r0), "r"(r1), "r"(r2) \ + : "$12", "$13", "$14", "$15", "memory") + +#define gte_FlipRotMatrixX() \ + __asm__ volatile( \ + "cfc2 $12, $0;" \ + "cfc2 $13, $1;" \ + "sll $14, $12, 16;" \ + "sra $14, $14, 16;" \ + "subu $14, $0, $14;" \ + "sra $15, $12, 16;" \ + "subu $15, $0, $15;" \ + "sll $15, $15, 16;" \ + "sll $14, $14, 16;" \ + "srl $14, $14, 16;" \ + "or $14, $14, $15;" \ + "ctc2 $14, $0;" \ + "sll $14, $13, 16;" \ + "sra $14, $14, 16;" \ + "subu $14, $0, $14;" \ + "sra $15, $13, 16;" \ + "sll $15, $15, 16;" \ + "sll $14, $14, 16;" \ + "srl $14, $14, 16;" \ + "or $14, $14, $15;" \ + "ctc2 $14, $1" \ + : \ + : \ + : "$12", "$13", "$14", "$15") + +#define gte_FlipTRX() \ + __asm__ volatile( \ + "cfc2 $12, $5;" \ + "nop;" \ + "subu $12, $0, $12;" \ + "ctc2 $12, $5" \ + : \ + : \ + : "$12") diff --git a/src/Library/src/Audio/CDDA.cpp b/src/Library/src/Audio/CDDA.cpp index a40f4788..42e8ffee 100644 --- a/src/Library/src/Audio/CDDA.cpp +++ b/src/Library/src/Audio/CDDA.cpp @@ -1,54 +1,54 @@ -#include "../../internal-include/CD/cd_internal.hpp" -#include - -namespace JabyEngine { - namespace CDDA { - namespace CD = JabyEngine::CD::internal; - - static CD::BCDTimeStamp last_track; - CD::BCDTimeStamp playing_track; - - TrackList get_tracks() { - CD::Command::send_wait_response(CD_IO::Command::GetTN); - - const auto stat = CD_IO::PortIndex0::ResponseFifo.read(); - const auto first = CD_IO::PortIndex0::ResponseFifo.read().raw; - const auto end = CD_IO::PortIndex0::ResponseFifo.read().raw; - const auto last_track = (end - first) + 1; - - if(last_track == 1) { - return TrackList::empty(); - } - - return TrackList{.first_track = 2, .last_track = static_cast(last_track)}; - } - - void play(uint8_t track) { - CD::enable_CDDA(); - CD::Command::send_wait_response(CD_IO::Command::GetTD, track); - const auto stats = CD_IO::PortIndex0::ResponseFifo.read().raw; - playing_track.min = CD_IO::PortIndex0::ResponseFifo.read().raw; - playing_track.sec = CD_IO::PortIndex0::ResponseFifo.read().raw; - - CD::Command::send(CD_IO::Command::SetLoc, playing_track.min, playing_track.sec, 0x0_u8); - CD::Command::send(CD_IO::Command::Play); - // The PS3 does not support playing a track by track id - //CD::Command::send(CD_IO::Command::Play, track); - } - - void stop() { - CD::pause(); - } - - void push_play() { - stop(); - last_track = CD::get_loc(); - } - - void pop_play() { - CD::enable_CDDA(); - CD::Command::send(CD_IO::Command::SetLoc, last_track.min, last_track.sec, last_track.sector); - CD::Command::send(CD_IO::Command::Play); - } - } +#include "../../internal-include/CD/cd_internal.hpp" +#include + +namespace JabyEngine { + namespace CDDA { + namespace CD = JabyEngine::CD::internal; + + static CD::BCDTimeStamp last_track; + CD::BCDTimeStamp playing_track; + + TrackList get_tracks() { + CD::Command::send_wait_response(CD_IO::Command::GetTN); + + const auto stat = CD_IO::PortIndex0::ResponseFifo.read(); + const auto first = CD_IO::PortIndex0::ResponseFifo.read().raw; + const auto end = CD_IO::PortIndex0::ResponseFifo.read().raw; + const auto last_track = (end - first) + 1; + + if(last_track == 1) { + return TrackList::empty(); + } + + return TrackList{.first_track = 2, .last_track = static_cast(last_track)}; + } + + void play(uint8_t track) { + CD::enable_CDDA(); + CD::Command::send_wait_response(CD_IO::Command::GetTD, track); + const auto stats = CD_IO::PortIndex0::ResponseFifo.read().raw; + playing_track.min = CD_IO::PortIndex0::ResponseFifo.read().raw; + playing_track.sec = CD_IO::PortIndex0::ResponseFifo.read().raw; + + CD::Command::send(CD_IO::Command::SetLoc, playing_track.min, playing_track.sec, 0x0_u8); + CD::Command::send(CD_IO::Command::Play); + // The PS3 does not support playing a track by track id + //CD::Command::send(CD_IO::Command::Play, track); + } + + void stop() { + CD::pause(); + } + + void push_play() { + stop(); + last_track = CD::get_loc(); + } + + void pop_play() { + CD::enable_CDDA(); + CD::Command::send(CD_IO::Command::SetLoc, last_track.min, last_track.sec, last_track.sector); + CD::Command::send(CD_IO::Command::Play); + } + } } \ No newline at end of file diff --git a/src/Library/src/Audio/CDXA.cpp b/src/Library/src/Audio/CDXA.cpp index 5d81818b..c780b5ce 100644 --- a/src/Library/src/Audio/CDXA.cpp +++ b/src/Library/src/Audio/CDXA.cpp @@ -1,68 +1,68 @@ -#include "../../internal-include/CD/cd_internal.hpp" -#include "../../internal-include/CD/cd_types.hpp" -#include - -namespace JabyEngine { - namespace CDXA { - namespace CD = JabyEngine::CD::internal; - - static struct { - CD::BCDTimeStamp start_loc; - CD::BCDTimeStamp last_loc; - bool double_speed; - uint8_t channel; - } setting; - - CD::State interrupt_handler(uint8_t irq) { - switch(irq) { - case CD_IO::Interrupt::DataReady: { - // The IRQ stack is 0x1000 bytes large so this should fit - const auto xa_file = CD::copy_from_sector(); - if(setting.channel == xa_file.sub_header.channel_number) { - CD::set_loc(setting.start_loc); - CD::Command::send_no_wait(CD_IO::Command::ReadS); - } - } break; - - case CD_IO::Interrupt::DiskError: - return CD::State::Error; - }; - return CD::State::XAMode; - } - - void play(const volatile AutoLBAEntry* lba, uint8_t rel_lba_idx, uint8_t channel, bool double_speed) { - setting.start_loc = CD::BCDTimeStamp::from(lba[rel_lba_idx].get_lba()); - setting.double_speed = double_speed; - - CD::enable_CDXA(double_speed); //< Activates PortIndex0 - set_channel(channel); - CD::Command::send(CD_IO::Command::SetLoc, setting.start_loc.min, setting.start_loc.sec, setting.start_loc.sector); - CD::Command::send(CD_IO::Command::ReadS); - } - - void stop() { - CD::pause(); - } - - void set_channel(uint8_t channel) { - static constexpr uint8_t File = 1; - - CD::Command::send(CD_IO::Command::Filter, File, channel); - setting.channel = channel; - } - - void push_play() { - stop(); - setting.last_loc = CD::get_loc(); - CD::current_state = CD::State::Ready; - } - - void pop_play() { - CD::enable_CDXA(setting.double_speed); //< Activates PortIndex0 - - set_channel(setting.channel); - CD::Command::send(CD_IO::Command::SetLoc, setting.last_loc.min, setting.last_loc.sec, setting.last_loc.sector); - CD::Command::send(CD_IO::Command::ReadS); - } - } +#include "../../internal-include/CD/cd_internal.hpp" +#include "../../internal-include/CD/cd_types.hpp" +#include + +namespace JabyEngine { + namespace CDXA { + namespace CD = JabyEngine::CD::internal; + + static struct { + CD::BCDTimeStamp start_loc; + CD::BCDTimeStamp last_loc; + bool double_speed; + uint8_t channel; + } setting; + + CD::State interrupt_handler(uint8_t irq) { + switch(irq) { + case CD_IO::Interrupt::DataReady: { + // The IRQ stack is 0x1000 bytes large so this should fit + const auto xa_file = CD::copy_from_sector(); + if(setting.channel == xa_file.sub_header.channel_number) { + CD::set_loc(setting.start_loc); + CD::Command::send_no_wait(CD_IO::Command::ReadS); + } + } break; + + case CD_IO::Interrupt::DiskError: + return CD::State::Error; + }; + return CD::State::XAMode; + } + + void play(const volatile AutoLBAEntry* lba, uint8_t rel_lba_idx, uint8_t channel, bool double_speed) { + setting.start_loc = CD::BCDTimeStamp::from(lba[rel_lba_idx].get_lba()); + setting.double_speed = double_speed; + + CD::enable_CDXA(double_speed); //< Activates PortIndex0 + set_channel(channel); + CD::Command::send(CD_IO::Command::SetLoc, setting.start_loc.min, setting.start_loc.sec, setting.start_loc.sector); + CD::Command::send(CD_IO::Command::ReadS); + } + + void stop() { + CD::pause(); + } + + void set_channel(uint8_t channel) { + static constexpr uint8_t File = 1; + + CD::Command::send(CD_IO::Command::Filter, File, channel); + setting.channel = channel; + } + + void push_play() { + stop(); + setting.last_loc = CD::get_loc(); + CD::current_state = CD::State::Ready; + } + + void pop_play() { + CD::enable_CDXA(setting.double_speed); //< Activates PortIndex0 + + set_channel(setting.channel); + CD::Command::send(CD_IO::Command::SetLoc, setting.last_loc.min, setting.last_loc.sec, setting.last_loc.sector); + CD::Command::send(CD_IO::Command::ReadS); + } + } } \ No newline at end of file diff --git a/src/Library/src/BootLoader/BIOSFont/ascii_bios_font.hpp b/src/Library/src/BootLoader/BIOSFont/ascii_bios_font.hpp index 977797b9..848bed64 100644 --- a/src/Library/src/BootLoader/BIOSFont/ascii_bios_font.hpp +++ b/src/Library/src/BootLoader/BIOSFont/ascii_bios_font.hpp @@ -1,73 +1,73 @@ -#pragma once -#include "../../../internal-include/GPU/gpu_internal.hpp" -#include "bios_font_types.hpp" -#include - -// | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | 0 | -// | 8149 | 8168 | 8194 | 8190 | 8193 | 8195 | 8166 | 8169 | 816A | 8196 | 817B | 8143 | 817C | 8144 | 815E | 8240 | -// | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? | @ | -// | 8251 | 8252 | 8253 | 8254 | 8255 | 8256 | 8257 | 8258 | 8259 | 8146 | 8147 | 8183 | 8181 | 8184 | 8148 | 8197 | -// | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | -// | 8260 | 8261 | 8262 | 8263 | 8264 | 8265 | 8266 | 8267 | 8268 | 8269 | 826A | 826B | 826C | 826D | 826E | 826F | -// | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ | ` | -// | 8270 | 8271 | 8272 | 8273 | 8274 | 8275 | 8276 | 8277 | 8278 | 8279 | 816D | 815F | 816E | 814F | 8151 | 814D | -// | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | -// | 8281 | 8282 | 8283 | 8284 | 8285 | 8286 | 8287 | 8288 | 8289 | 828A | 828B | 828C | 828D | 828E | 828F | 8290 | -// | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | | | -// | 8291 | 8292 | 8293 | 8294 | 8295 | 8296 | 8297 | 8298 | 8299 | 829A | 816F | 8162 | 8170 | 8160 | | | - -namespace JabyEngine { - namespace GPU { - namespace SJIS { - // base: 0x8100 - static const SpecialChar Specials[] = { // ToDo: Can we split this into 4 arrays? Would that help somehow? - // { ! } { " } { # } { $ } { % } { & } { ' } { ( } { ) } { * } { + } { , } { - } { . } { / } - {0x49, 0}, {0x68, 1}, {0x94, 2}, {0x90, 3}, {0x93, 4}, {0x95, 5}, {0x66, 6}, {0x69, 7}, {0x6A, 8}, {0x96, 9}, {0x7B, 10}, {0x43, 11}, {0x7C, 12}, {0x44, 13}, {0x5E, 14}, - // { : } { ; } { < } { = } { > } { ? } { @ } - {0x46, 25}, {0x47, 26}, {0x83, 27}, {0x81, 28}, {0x84, 29}, {0x48, 30}, {0x97, 31}, - // { [ } { \ } { ] } { ^ } { _ } { ` } - {0x6D, 58}, {0x5F, 59}, {0x6E, 60}, {0x4F, 61}, {0x51, 62}, {0x4D, 63}, - // { { } { | } { } } { ~ } - {0x6F, 90}, {0x62, 91}, {0x70, 92}, {0x60, 93} - }; - - // base: 0x8200 - static const RangeChar AlphaNumeric[] = { - // { 0 } - {{0x4F, 15}, 1}, - // { 1 - 9 } - {{0x50, 16}, 9}, - // { A - Z } - {{0x60, 32}, 26}, - // { a - z } - {{0x81, 64}, 26} - }; - - static void load(const PositionU16& start_pos) { - FontBuffer font_buffer; - const auto load_special_chars = [&font_buffer](const PositionU16& pos, const SpecialChar(&special_chars)[Size]) { - for(const auto& special_char : special_chars) { - font_buffer.load_to(pos.add(FontBuffer::vram_offset(special_char.tile_id)), SysCall::Krom2RawAdd(0x8100 | special_char.base_offset)); - } - }; - const auto load_alpha_num = [&font_buffer](const PositionU16& pos, const RangeChar(&range_char)[Size]) { - for(const auto& range : range_char) { - const auto end_tile = range.start_char.tile_id + range.length; - auto sjis_code = 0x8200 | range.start_char.base_offset; - - for(uint16_t tile_id = range.start_char.tile_id; tile_id < end_tile; tile_id++,sjis_code++) { - font_buffer.load_to(pos.add(FontBuffer::vram_offset(tile_id)), SysCall::Krom2RawAdd(sjis_code)); - } - } - }; - - font_buffer.setup(); - - GPU::internal::DMA::Receive::prepare(); - load_special_chars(start_pos, Specials); - load_alpha_num(start_pos, AlphaNumeric); - font_buffer.shutdown(); - } - } - } +#pragma once +#include "../../../internal-include/GPU/gpu_internal.hpp" +#include "bios_font_types.hpp" +#include + +// | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | 0 | +// | 8149 | 8168 | 8194 | 8190 | 8193 | 8195 | 8166 | 8169 | 816A | 8196 | 817B | 8143 | 817C | 8144 | 815E | 8240 | +// | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? | @ | +// | 8251 | 8252 | 8253 | 8254 | 8255 | 8256 | 8257 | 8258 | 8259 | 8146 | 8147 | 8183 | 8181 | 8184 | 8148 | 8197 | +// | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | +// | 8260 | 8261 | 8262 | 8263 | 8264 | 8265 | 8266 | 8267 | 8268 | 8269 | 826A | 826B | 826C | 826D | 826E | 826F | +// | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ | ` | +// | 8270 | 8271 | 8272 | 8273 | 8274 | 8275 | 8276 | 8277 | 8278 | 8279 | 816D | 815F | 816E | 814F | 8151 | 814D | +// | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | +// | 8281 | 8282 | 8283 | 8284 | 8285 | 8286 | 8287 | 8288 | 8289 | 828A | 828B | 828C | 828D | 828E | 828F | 8290 | +// | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | | | +// | 8291 | 8292 | 8293 | 8294 | 8295 | 8296 | 8297 | 8298 | 8299 | 829A | 816F | 8162 | 8170 | 8160 | | | + +namespace JabyEngine { + namespace GPU { + namespace SJIS { + // base: 0x8100 + static const SpecialChar Specials[] = { // ToDo: Can we split this into 4 arrays? Would that help somehow? + // { ! } { " } { # } { $ } { % } { & } { ' } { ( } { ) } { * } { + } { , } { - } { . } { / } + {0x49, 0}, {0x68, 1}, {0x94, 2}, {0x90, 3}, {0x93, 4}, {0x95, 5}, {0x66, 6}, {0x69, 7}, {0x6A, 8}, {0x96, 9}, {0x7B, 10}, {0x43, 11}, {0x7C, 12}, {0x44, 13}, {0x5E, 14}, + // { : } { ; } { < } { = } { > } { ? } { @ } + {0x46, 25}, {0x47, 26}, {0x83, 27}, {0x81, 28}, {0x84, 29}, {0x48, 30}, {0x97, 31}, + // { [ } { \ } { ] } { ^ } { _ } { ` } + {0x6D, 58}, {0x5F, 59}, {0x6E, 60}, {0x4F, 61}, {0x51, 62}, {0x4D, 63}, + // { { } { | } { } } { ~ } + {0x6F, 90}, {0x62, 91}, {0x70, 92}, {0x60, 93} + }; + + // base: 0x8200 + static const RangeChar AlphaNumeric[] = { + // { 0 } + {{0x4F, 15}, 1}, + // { 1 - 9 } + {{0x50, 16}, 9}, + // { A - Z } + {{0x60, 32}, 26}, + // { a - z } + {{0x81, 64}, 26} + }; + + static void load(const PositionU16& start_pos) { + FontBuffer font_buffer; + const auto load_special_chars = [&font_buffer](const PositionU16& pos, const SpecialChar(&special_chars)[Size]) { + for(const auto& special_char : special_chars) { + font_buffer.load_to(pos.add(FontBuffer::vram_offset(special_char.tile_id)), SysCall::Krom2RawAdd(0x8100 | special_char.base_offset)); + } + }; + const auto load_alpha_num = [&font_buffer](const PositionU16& pos, const RangeChar(&range_char)[Size]) { + for(const auto& range : range_char) { + const auto end_tile = range.start_char.tile_id + range.length; + auto sjis_code = 0x8200 | range.start_char.base_offset; + + for(uint16_t tile_id = range.start_char.tile_id; tile_id < end_tile; tile_id++,sjis_code++) { + font_buffer.load_to(pos.add(FontBuffer::vram_offset(tile_id)), SysCall::Krom2RawAdd(sjis_code)); + } + } + }; + + font_buffer.setup(); + + GPU::internal::DMA::Receive::prepare(); + load_special_chars(start_pos, Specials); + load_alpha_num(start_pos, AlphaNumeric); + font_buffer.shutdown(); + } + } + } } \ No newline at end of file diff --git a/src/Library/src/BootLoader/BIOSFont/bios_font_types.hpp b/src/Library/src/BootLoader/BIOSFont/bios_font_types.hpp index dc88aeee..3fb5e59f 100644 --- a/src/Library/src/BootLoader/BIOSFont/bios_font_types.hpp +++ b/src/Library/src/BootLoader/BIOSFont/bios_font_types.hpp @@ -1,98 +1,98 @@ -#pragma once -#include "../../../internal-include/GPU/gpu_internal.hpp" -#include - -namespace JabyEngine { - namespace GPU { - namespace SJIS { - struct FontBuffer { - // A line of 16 Pixel - struct Line { - LookUpColor4 pixel[BIOS_Font::Size.width/4]; - - void load(uint16_t bit_pattern) { - static constexpr auto BitsPerRound = 4; - - size_t px_idx = 0; - for(uint16_t shift = 1 << 15; shift; shift = shift >> BitsPerRound) { - uint8_t lu_ids[BitsPerRound]; - - for(size_t n = 0; n < BitsPerRound; n++) { - lu_ids[n] = (bit_pattern & (shift >> n)) ? 1 : 0; - } - - this->pixel[px_idx++] = LookUpColor4::create(lu_ids); - } - } - - static PositionU16 vram_offset(uint16_t tile_id) { - return tile_id_for16(tile_id, SizeU16::create(4, 16)); - } - }; - - // Letters are actually only 16x15 but should be treated 16x16 - struct Letter { - PositionU16 position; - Line lines[BIOS_Font::Size.height - 1]; - Line empty_line; - - void setup() { - this->empty_line.load(0); - } - - void load_to(const PositionU16& pos, const uint16_t* bit_map) { - this->position = pos; - for(auto& cur_line : this->lines) { - cur_line.load(__builtin_bswap16(*bit_map++)); - } - } - }; - - // v double buffer do not change size without adjusting - Letter letter_buffer[2]; - uint8_t free_idx; - - void setup() { - for(auto& letter : this->letter_buffer) { - letter.setup(); - } - this->free_idx = 0; - GPU::internal::DMA::Receive::prepare(); - } - - void shutdown() { - GPU::internal::DMA::wait(); - GPU::internal::DMA::end(); - } - - void load_to(const PositionU16& pos, const uint16_t* bit_map) { - auto& cur_letter = this->letter_buffer[this->free_idx]; - this->free_idx ^= 1; - - cur_letter.load_to(pos, bit_map); - GPU::internal::DMA::wait(); - GPU::internal::DMA::Receive::set_src(reinterpret_cast(cur_letter.lines)); - // v 4 Pixel per byte - GPU::internal::DMA::Receive::set_dst(cur_letter.position, SizeU16::create(16/4, 16)); - GPU::internal::DMA::Receive::start(sizeof(Line) >> 2); - } - - static PositionU16 vram_offset(uint16_t tile_id) { - return Line::vram_offset(tile_id); - } - }; - - struct SpecialChar { - uint8_t base_offset; - uint8_t tile_id; - }; - - struct RangeChar { - SpecialChar start_char; - uint8_t length; - }; - - static_assert(BIOS_Font::Size == SizeU16::create(16, 16)); - } - } +#pragma once +#include "../../../internal-include/GPU/gpu_internal.hpp" +#include + +namespace JabyEngine { + namespace GPU { + namespace SJIS { + struct FontBuffer { + // A line of 16 Pixel + struct Line { + LookUpColor4 pixel[BIOS_Font::Size.width/4]; + + void load(uint16_t bit_pattern) { + static constexpr auto BitsPerRound = 4; + + size_t px_idx = 0; + for(uint16_t shift = 1 << 15; shift; shift = shift >> BitsPerRound) { + uint8_t lu_ids[BitsPerRound]; + + for(size_t n = 0; n < BitsPerRound; n++) { + lu_ids[n] = (bit_pattern & (shift >> n)) ? 1 : 0; + } + + this->pixel[px_idx++] = LookUpColor4::create(lu_ids); + } + } + + static PositionU16 vram_offset(uint16_t tile_id) { + return tile_id_for16(tile_id, SizeU16::create(4, 16)); + } + }; + + // Letters are actually only 16x15 but should be treated 16x16 + struct Letter { + PositionU16 position; + Line lines[BIOS_Font::Size.height - 1]; + Line empty_line; + + void setup() { + this->empty_line.load(0); + } + + void load_to(const PositionU16& pos, const uint16_t* bit_map) { + this->position = pos; + for(auto& cur_line : this->lines) { + cur_line.load(__builtin_bswap16(*bit_map++)); + } + } + }; + + // v double buffer do not change size without adjusting + Letter letter_buffer[2]; + uint8_t free_idx; + + void setup() { + for(auto& letter : this->letter_buffer) { + letter.setup(); + } + this->free_idx = 0; + GPU::internal::DMA::Receive::prepare(); + } + + void shutdown() { + GPU::internal::DMA::wait(); + GPU::internal::DMA::end(); + } + + void load_to(const PositionU16& pos, const uint16_t* bit_map) { + auto& cur_letter = this->letter_buffer[this->free_idx]; + this->free_idx ^= 1; + + cur_letter.load_to(pos, bit_map); + GPU::internal::DMA::wait(); + GPU::internal::DMA::Receive::set_src(reinterpret_cast(cur_letter.lines)); + // v 4 Pixel per byte + GPU::internal::DMA::Receive::set_dst(cur_letter.position, SizeU16::create(16/4, 16)); + GPU::internal::DMA::Receive::start(sizeof(Line) >> 2); + } + + static PositionU16 vram_offset(uint16_t tile_id) { + return Line::vram_offset(tile_id); + } + }; + + struct SpecialChar { + uint8_t base_offset; + uint8_t tile_id; + }; + + struct RangeChar { + SpecialChar start_char; + uint8_t length; + }; + + static_assert(BIOS_Font::Size == SizeU16::create(16, 16)); + } + } } \ No newline at end of file diff --git a/src/Library/src/BootLoader/callbacks_boot.cxx b/src/Library/src/BootLoader/callbacks_boot.cxx index 90fa716c..9b517698 100644 --- a/src/Library/src/BootLoader/callbacks_boot.cxx +++ b/src/Library/src/BootLoader/callbacks_boot.cxx @@ -1,25 +1,25 @@ -#include "../../internal-include/BootLoader/boot_loader.hpp" -#include "../../internal-include/System/callbacks_internal.hpp" - -namespace JabyEngine { - namespace boot { - namespace Callbacks { - namespace InternalCallback = JabyEngine::Callback::internal; - - void setup() { - // We do not use threads anymore but keep the code for it - /*SysCall::EnterCriticalSection(); - /*InternalCallback::VSync::thread_handle = SysCall::OpenThread( - InternalCallback::VSync::routine, - &InternalCallback::VSync::stack[InternalCallback::VSync::StackSize - 1], - SysCall::get_gp() - ); - Thread::set_user_mode_for(InternalCallback::VSync::thread_handle); - - InternalCallback::CD::thread_handle = Thread::create(InternalCallback::CD::routine, InternalCallback::CD::stack); - Thread::set_user_mode_for(InternalCallback::CD::thread_handle); - SysCall::ExitCriticalSection();*/ - } - } - } +#include "../../internal-include/BootLoader/boot_loader.hpp" +#include "../../internal-include/System/callbacks_internal.hpp" + +namespace JabyEngine { + namespace boot { + namespace Callbacks { + namespace InternalCallback = JabyEngine::Callback::internal; + + void setup() { + // We do not use threads anymore but keep the code for it + /*SysCall::EnterCriticalSection(); + /*InternalCallback::VSync::thread_handle = SysCall::OpenThread( + InternalCallback::VSync::routine, + &InternalCallback::VSync::stack[InternalCallback::VSync::StackSize - 1], + SysCall::get_gp() + ); + Thread::set_user_mode_for(InternalCallback::VSync::thread_handle); + + InternalCallback::CD::thread_handle = Thread::create(InternalCallback::CD::routine, InternalCallback::CD::stack); + Thread::set_user_mode_for(InternalCallback::CD::thread_handle); + SysCall::ExitCriticalSection();*/ + } + } + } } \ No newline at end of file diff --git a/src/Library/src/BootLoader/cd_boot.cpp b/src/Library/src/BootLoader/cd_boot.cpp index 2d91da03..3dc143b8 100644 --- a/src/Library/src/BootLoader/cd_boot.cpp +++ b/src/Library/src/BootLoader/cd_boot.cpp @@ -1,42 +1,42 @@ -#include "../../internal-include/BootLoader/boot_loader.hpp" -#include "../../internal-include/CD/cd_internal.hpp" -#include -#include -#include - -namespace JabyEngine { - namespace CD { - namespace internal { - extern SysCall::InterruptCallback irq_callback; - } - } - - namespace boot { - namespace CD { - using JabyEngine::CD::internal::Command; - - void setup() { - static constexpr auto DebugX = 1; - static constexpr auto DebugY = 1; - static constexpr auto DebugScale = 1.0; - - __debug_boot_color_at(::JabyEngine::GPU::Color24::White(), DebugX, DebugY, DebugScale); - SysCall::EnterCriticalSection(); - Memory_IO::COM_DELAY.write(Memory_IO_Values::COM_DELAY::create()); - Memory_IO::CD_DELAY.write(Memory_IO_Values::CD_DELAY::create()); - - SysCall::SysEnqIntRP(SysCall::Priority::CdromIoIrq, &::JabyEngine::CD::internal::irq_callback); - - CD_IO::PortIndex1::change_to(); - CD_IO::Interrupt::ack_extended(CD_IO::PortIndex1::InterruptFlag); - - // TODO: Verify this on real HW - CD_IO::Interrupt::enable_extended(CD_IO::PortIndex1::InterruptEnable); - - Interrupt::enable_irq(Interrupt::CDROM); - Interrupt::ack_irq(Interrupt::CDROM); - SysCall::ExitCriticalSection(); - } - } - } +#include "../../internal-include/BootLoader/boot_loader.hpp" +#include "../../internal-include/CD/cd_internal.hpp" +#include +#include +#include + +namespace JabyEngine { + namespace CD { + namespace internal { + extern SysCall::InterruptCallback irq_callback; + } + } + + namespace boot { + namespace CD { + using JabyEngine::CD::internal::Command; + + void setup() { + static constexpr auto DebugX = 1; + static constexpr auto DebugY = 1; + static constexpr auto DebugScale = 1.0; + + __debug_boot_color_at(::JabyEngine::GPU::Color24::White(), DebugX, DebugY, DebugScale); + SysCall::EnterCriticalSection(); + Memory_IO::COM_DELAY.write(Memory_IO_Values::COM_DELAY::create()); + Memory_IO::CD_DELAY.write(Memory_IO_Values::CD_DELAY::create()); + + SysCall::SysEnqIntRP(SysCall::Priority::CdromIoIrq, &::JabyEngine::CD::internal::irq_callback); + + CD_IO::PortIndex1::change_to(); + CD_IO::Interrupt::ack_extended(CD_IO::PortIndex1::InterruptFlag); + + // TODO: Verify this on real HW + CD_IO::Interrupt::enable_extended(CD_IO::PortIndex1::InterruptEnable); + + Interrupt::enable_irq(Interrupt::CDROM); + Interrupt::ack_irq(Interrupt::CDROM); + SysCall::ExitCriticalSection(); + } + } + } } \ No newline at end of file diff --git a/src/Library/src/BootLoader/dma_boot.cpp b/src/Library/src/BootLoader/dma_boot.cpp index b844393a..6388e475 100644 --- a/src/Library/src/BootLoader/dma_boot.cpp +++ b/src/Library/src/BootLoader/dma_boot.cpp @@ -1,25 +1,25 @@ -#include -#include -#include - -namespace JabyEngine { - namespace boot { - namespace DMA { - void setup() { - static constexpr auto EnableDMA = DMA_IO_Values::DPCR::from( - DMA_IO_Values::DPCR::SPU.turn_on(3), DMA_IO_Values::DPCR::GPU.turn_on(3), DMA_IO_Values::DPCR::CDROM.turn_on(3) - ); - - DMA_IO::DPCR.write(EnableDMA); - DMA_IO::DICR.write(DMA_IO_Values::DICR::empty()); - // ACK IRQ - DMA_IO::DICR.write(DMA_IO::DICR.read()); - - SysCall::EnterCriticalSection(); - Interrupt::disable_irq(Interrupt::DMA); - Interrupt::ack_irq(Interrupt::DMA); - SysCall::ExitCriticalSection(); - } - } - } +#include +#include +#include + +namespace JabyEngine { + namespace boot { + namespace DMA { + void setup() { + static constexpr auto EnableDMA = DMA_IO_Values::DPCR::from( + DMA_IO_Values::DPCR::SPU.turn_on(3), DMA_IO_Values::DPCR::GPU.turn_on(3), DMA_IO_Values::DPCR::CDROM.turn_on(3) + ); + + DMA_IO::DPCR.write(EnableDMA); + DMA_IO::DICR.write(DMA_IO_Values::DICR::empty()); + // ACK IRQ + DMA_IO::DICR.write(DMA_IO::DICR.read()); + + SysCall::EnterCriticalSection(); + Interrupt::disable_irq(Interrupt::DMA); + Interrupt::ack_irq(Interrupt::DMA); + SysCall::ExitCriticalSection(); + } + } + } } \ No newline at end of file diff --git a/src/Library/src/BootLoader/gpu_boot.cpp b/src/Library/src/BootLoader/gpu_boot.cpp index e5a43f2c..08dfb60b 100644 --- a/src/Library/src/BootLoader/gpu_boot.cpp +++ b/src/Library/src/BootLoader/gpu_boot.cpp @@ -1,109 +1,109 @@ -#include "../../internal-include/GPU/gpu_internal.hpp" -#include -#include -#include -#include -#include -#include - -#ifdef JABYENGINE_PAL - #include "splash_image_pal_boot.hpp" -#else - #include "splash_image_ntsc_boot.hpp" -#endif //JABYENGINE_PAL - -// Concept for switchting BIOS Fonts...? -#include "BIOSFont/ascii_bios_font.hpp" - -extern "C" uint32_t __boot_loader_end; - -namespace JabyEngine { - namespace GPU { - namespace internal { - extern SysCall::InterruptCallback irq_callback; - } - - namespace SJIS { - void load_clut(const PositionU16& dst_cord) { - struct CLUT { - CPU2VRAM cmd; - Color data[16]; - }; - const CLUT clut { - .cmd = CPU2VRAM::create(AreaU16::create(dst_cord, GPU::SizeU16::create(16, 1))), - .data = { - Color::Black(), Color::Grey(), - Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), - Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), - } - }; - - GPU::internal::render(reinterpret_cast(&clut), sizeof(CLUT)/sizeof(uint32_t)); - } - } - } - - namespace boot { - namespace GPU { - using namespace JabyEngine::GPU; - - static void configure_display() { - GPU_IO::GP1.set_display_mode(::JabyEngine::GPU::internal::Display::DisplayMode); - GPU::Display::set_offset(0, 0); - } - - static size_t decompress_logo() { - LZ4Decompressor lz4_decomp(reinterpret_cast(&__boot_loader_end)); - - const auto [progress, bytes_ready] = lz4_decomp.process(ArrayRange(SplashScreen, sizeof(SplashScreen)), true); - switch(progress) { - case Progress::InProgress: - printf("Decompressing still in progress... %llu\n", bytes_ready); - break; - - case Progress::Error: - printf("Error decompressing!!!\n"); - break; - - case Progress::Done: - printf("Done decompressing: %llu Bytes ready\n", bytes_ready); - break; - } - - return bytes_ready; - } - - void display_logo() { - static constexpr uint16_t TexturePageHeight = 256; - const auto bytes_ready = decompress_logo(); - - // Upload SplashScreen picture - auto state = FileProcessor::create(&__boot_loader_end, SimpleTIM::create(32, 0, 0, 0)); - state.process(bytes_ready); - - // Now load the BIOS font to the specified location - SJIS::load(BIOS_Font::TextureLoadPos); - SJIS::load_clut(BIOS_Font::CLUTLoadPos); - - // Duplicate DisplayBuffer content - ::JabyEngine::GPU::internal::copy_vram_to_vram({PositionU16::create(0, TexturePageHeight), SizeU16::create(Display::Width, TexturePageHeight)}, PositionU16::create(0, 0)); - - Display::enable(); - } - - void setup() { - GPU_IO::GP1.reset(); - configure_display(); - ::JabyEngine::GPU::internal::Display::exchange_buffer_and_display(); - - GPU::internal::wait_ready_for_CMD(); - GPU::internal::quick_fill_fast(Color24::Black(), {PositionU16::create(0, 0), SizeU16::create(Display::Width, Display::Height)}); - - SysCall::EnterCriticalSection(); - SysCall::SysEnqIntRP(SysCall::Priority::VblankIrq, &::JabyEngine::GPU::internal::irq_callback); - Interrupt::enable_irq(Interrupt::VBlank); - SysCall::ExitCriticalSection(); - } - } - } +#include "../../internal-include/GPU/gpu_internal.hpp" +#include +#include +#include +#include +#include +#include + +#ifdef JABYENGINE_PAL + #include "splash_image_pal_boot.hpp" +#else + #include "splash_image_ntsc_boot.hpp" +#endif //JABYENGINE_PAL + +// Concept for switchting BIOS Fonts...? +#include "BIOSFont/ascii_bios_font.hpp" + +extern "C" uint32_t __boot_loader_end; + +namespace JabyEngine { + namespace GPU { + namespace internal { + extern SysCall::InterruptCallback irq_callback; + } + + namespace SJIS { + void load_clut(const PositionU16& dst_cord) { + struct CLUT { + CPU2VRAM cmd; + Color data[16]; + }; + const CLUT clut { + .cmd = CPU2VRAM::create(AreaU16::create(dst_cord, GPU::SizeU16::create(16, 1))), + .data = { + Color::Black(), Color::Grey(), + Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), + Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), Color::Black(), + } + }; + + GPU::internal::render(reinterpret_cast(&clut), sizeof(CLUT)/sizeof(uint32_t)); + } + } + } + + namespace boot { + namespace GPU { + using namespace JabyEngine::GPU; + + static void configure_display() { + GPU_IO::GP1.set_display_mode(::JabyEngine::GPU::internal::Display::DisplayMode); + GPU::Display::set_offset(0, 0); + } + + static size_t decompress_logo() { + LZ4Decompressor lz4_decomp(reinterpret_cast(&__boot_loader_end)); + + const auto [progress, bytes_ready] = lz4_decomp.process(ArrayRange(SplashScreen, sizeof(SplashScreen)), true); + switch(progress) { + case Progress::InProgress: + printf("Decompressing still in progress... %llu\n", bytes_ready); + break; + + case Progress::Error: + printf("Error decompressing!!!\n"); + break; + + case Progress::Done: + printf("Done decompressing: %llu Bytes ready\n", bytes_ready); + break; + } + + return bytes_ready; + } + + void display_logo() { + static constexpr uint16_t TexturePageHeight = 256; + const auto bytes_ready = decompress_logo(); + + // Upload SplashScreen picture + auto state = FileProcessor::create(&__boot_loader_end, SimpleTIM::create(32, 0, 0, 0)); + state.process(bytes_ready); + + // Now load the BIOS font to the specified location + SJIS::load(BIOS_Font::TextureLoadPos); + SJIS::load_clut(BIOS_Font::CLUTLoadPos); + + // Duplicate DisplayBuffer content + ::JabyEngine::GPU::internal::copy_vram_to_vram({PositionU16::create(0, TexturePageHeight), SizeU16::create(Display::Width, TexturePageHeight)}, PositionU16::create(0, 0)); + + Display::enable(); + } + + void setup() { + GPU_IO::GP1.reset(); + configure_display(); + ::JabyEngine::GPU::internal::Display::exchange_buffer_and_display(); + + GPU::internal::wait_ready_for_CMD(); + GPU::internal::quick_fill_fast(Color24::Black(), {PositionU16::create(0, 0), SizeU16::create(Display::Width, Display::Height)}); + + SysCall::EnterCriticalSection(); + SysCall::SysEnqIntRP(SysCall::Priority::VblankIrq, &::JabyEngine::GPU::internal::irq_callback); + Interrupt::enable_irq(Interrupt::VBlank); + SysCall::ExitCriticalSection(); + } + } + } } \ No newline at end of file diff --git a/src/Library/src/BootLoader/gte_boot.cpp b/src/Library/src/BootLoader/gte_boot.cpp index caa93717..de95b3f1 100644 --- a/src/Library/src/BootLoader/gte_boot.cpp +++ b/src/Library/src/BootLoader/gte_boot.cpp @@ -1,20 +1,20 @@ -#include "../../internal-include/mipscalls.hpp" -#include -#include - - -namespace JabyEngine { - namespace boot { - namespace GTE { - void setup() { - SysCall::EnterCriticalSection(); - const auto sr = bit::set(MIPS::SR::read(), MIPS::SR::CU2); - MIPS::SR::write(sr); - SysCall::ExitCriticalSection(); - - JabyEngine::GTE::set_geom_offset(0, 0); - JabyEngine::GTE::set_geom_screen(512); - } - } - } +#include "../../internal-include/mipscalls.hpp" +#include +#include + + +namespace JabyEngine { + namespace boot { + namespace GTE { + void setup() { + SysCall::EnterCriticalSection(); + const auto sr = bit::set(MIPS::SR::read(), MIPS::SR::CU2); + MIPS::SR::write(sr); + SysCall::ExitCriticalSection(); + + JabyEngine::GTE::set_geom_offset(0, 0); + JabyEngine::GTE::set_geom_screen(512); + } + } + } } \ No newline at end of file diff --git a/src/Library/src/BootLoader/periphery_boot.cpp b/src/Library/src/BootLoader/periphery_boot.cpp index 02379fcc..bc99c54e 100644 --- a/src/Library/src/BootLoader/periphery_boot.cpp +++ b/src/Library/src/BootLoader/periphery_boot.cpp @@ -1,17 +1,17 @@ -#include "../../internal-include/periphery_internal.hpp" -#include - -namespace JabyEngine { - namespace boot { - namespace Periphery { - void setup() { - Periphery_IO::JOY_MODE.write(Periphery_IO_Values::JOY_MODE::create()); - Periphery_IO::JOY_BAUD.write(Periphery_IO_Values::JOY_BAUD::create()); - - SysCall::EnterCriticalSection(); - Interrupt::disable_irq(Interrupt::Periphery); - SysCall::ExitCriticalSection(); - } - } - } +#include "../../internal-include/periphery_internal.hpp" +#include + +namespace JabyEngine { + namespace boot { + namespace Periphery { + void setup() { + Periphery_IO::JOY_MODE.write(Periphery_IO_Values::JOY_MODE::create()); + Periphery_IO::JOY_BAUD.write(Periphery_IO_Values::JOY_BAUD::create()); + + SysCall::EnterCriticalSection(); + Interrupt::disable_irq(Interrupt::Periphery); + SysCall::ExitCriticalSection(); + } + } + } } \ No newline at end of file diff --git a/src/Library/src/BootLoader/syscall_boot.cpp b/src/Library/src/BootLoader/syscall_boot.cpp index 009a2f3c..b0da91de 100644 --- a/src/Library/src/BootLoader/syscall_boot.cpp +++ b/src/Library/src/BootLoader/syscall_boot.cpp @@ -1,88 +1,88 @@ -#include -#include -#include - -namespace JabyEngine { - namespace boot { - namespace BIOS { - using Version = JabyEngine::BIOS::Version; - - static uint32_t get_bcd_version() { - return *reinterpret_cast(0xBFC00100); - } - - static const char* get_kernel_maker_str() { - return reinterpret_cast(0xBFC00108); - } - - static const char* get_version_str() { - const char* kernel_maker = get_kernel_maker_str(); - const char* ver_start = kernel_maker + (strlen(kernel_maker) + 1); - - while(*ver_start == 0) { - ver_start++; - } - return ver_start; - } - - static Version::Type get_raw_bios_type(const char* version_str) { - static const auto str_length = [](const char (&name)[N]) -> size_t { - return N - 1; - }; - const char dev_str[] = "DTL-"; - const char ps1_str[] = "CEX-"; - const char ps_compatible_str[] = "PS compatible mode"; - const char no$psx_str[] = "no$psx"; - const char xebra_str[] = "XEBRA"; - - const struct { - const char* name; - size_t name_length; - Version::Type type; - } bioses[] = { - // Sorted by likeliness - {.name = ps1_str, .name_length = str_length(ps1_str), .type = Version::Type::PS1}, - {.name = ps_compatible_str, .name_length = str_length(ps_compatible_str), .type = Version::Type::PSCompatible}, - {.name = no$psx_str, .name_length = str_length(no$psx_str), .type = Version::Type::No$psx}, - {.name = xebra_str, .name_length = str_length(xebra_str), .type = Version::Type::XEBRA}, - {.name = dev_str, .name_length = str_length(dev_str), .type = Version::Type::Devboard} - }; - - for(const auto& bios : bioses) { - if(strncmp(version_str, bios.name, bios.name_length) == 0) { - return bios.type; - } - } - return Version::Type::Unkown; - } - - static Version::Type refine_bios_type(Version::Type type) { - if(type == Version::Type::PSCompatible) { - const auto bios_year_bcd = get_bcd_version() >> 16; - return bios_year_bcd == 0x2011 ? Version::Type::PS3 : Version::Type::PS2; - } - return type; - } - - static Version get_bios_version() { - Version version; - const auto date_bcd = get_bcd_version(); - const char*const version_str = get_version_str(); - - version.date.day = from_bcd(static_cast(date_bcd & 0xFF)); - version.date.month = from_bcd(static_cast((date_bcd >> 8) & 0xFF)); - version.date.year = from_bcd(static_cast(date_bcd >> 16)); - version.type = refine_bios_type(get_raw_bios_type(version_str)); - version.kernel_maker = get_kernel_maker_str(); - version.version_str = version_str; - version.gui_version = reinterpret_cast(0xBFC7FF32); - version.copyright = version.gui_version + (strlen(version.gui_version) + 1); - return version; - } - - void identify() { - const_cast(JabyEngine::BIOS::version) = get_bios_version(); - } - } - } +#include +#include +#include + +namespace JabyEngine { + namespace boot { + namespace BIOS { + using Version = JabyEngine::BIOS::Version; + + static uint32_t get_bcd_version() { + return *reinterpret_cast(0xBFC00100); + } + + static const char* get_kernel_maker_str() { + return reinterpret_cast(0xBFC00108); + } + + static const char* get_version_str() { + const char* kernel_maker = get_kernel_maker_str(); + const char* ver_start = kernel_maker + (strlen(kernel_maker) + 1); + + while(*ver_start == 0) { + ver_start++; + } + return ver_start; + } + + static Version::Type get_raw_bios_type(const char* version_str) { + static const auto str_length = [](const char (&name)[N]) -> size_t { + return N - 1; + }; + const char dev_str[] = "DTL-"; + const char ps1_str[] = "CEX-"; + const char ps_compatible_str[] = "PS compatible mode"; + const char no$psx_str[] = "no$psx"; + const char xebra_str[] = "XEBRA"; + + const struct { + const char* name; + size_t name_length; + Version::Type type; + } bioses[] = { + // Sorted by likeliness + {.name = ps1_str, .name_length = str_length(ps1_str), .type = Version::Type::PS1}, + {.name = ps_compatible_str, .name_length = str_length(ps_compatible_str), .type = Version::Type::PSCompatible}, + {.name = no$psx_str, .name_length = str_length(no$psx_str), .type = Version::Type::No$psx}, + {.name = xebra_str, .name_length = str_length(xebra_str), .type = Version::Type::XEBRA}, + {.name = dev_str, .name_length = str_length(dev_str), .type = Version::Type::Devboard} + }; + + for(const auto& bios : bioses) { + if(strncmp(version_str, bios.name, bios.name_length) == 0) { + return bios.type; + } + } + return Version::Type::Unkown; + } + + static Version::Type refine_bios_type(Version::Type type) { + if(type == Version::Type::PSCompatible) { + const auto bios_year_bcd = get_bcd_version() >> 16; + return bios_year_bcd == 0x2011 ? Version::Type::PS3 : Version::Type::PS2; + } + return type; + } + + static Version get_bios_version() { + Version version; + const auto date_bcd = get_bcd_version(); + const char*const version_str = get_version_str(); + + version.date.day = from_bcd(static_cast(date_bcd & 0xFF)); + version.date.month = from_bcd(static_cast((date_bcd >> 8) & 0xFF)); + version.date.year = from_bcd(static_cast(date_bcd >> 16)); + version.type = refine_bios_type(get_raw_bios_type(version_str)); + version.kernel_maker = get_kernel_maker_str(); + version.version_str = version_str; + version.gui_version = reinterpret_cast(0xBFC7FF32); + version.copyright = version.gui_version + (strlen(version.gui_version) + 1); + return version; + } + + void identify() { + const_cast(JabyEngine::BIOS::version) = get_bios_version(); + } + } + } } \ No newline at end of file diff --git a/src/Library/src/BootLoader/timer_boot.cpp b/src/Library/src/BootLoader/timer_boot.cpp index 76c75e15..d2b5c74e 100644 --- a/src/Library/src/BootLoader/timer_boot.cpp +++ b/src/Library/src/BootLoader/timer_boot.cpp @@ -1,33 +1,33 @@ -#include -#include -#include - -namespace JabyEngine { - namespace Timer { - extern SysCall::InterruptCallback irq_callback; - } - - namespace boot { - namespace Timer { - using namespace JabyEngine::Timer; - - void setup() { - using namespace Timer_IO; - using namespace Timer_IO_Values; - - static constexpr auto Mode = CounterMode::from(CounterMode::FreeRun, Counter2::SyncMode::FreeRun, CounterMode::ResetAfterTarget, CounterMode::IRQAtTarget, CounterMode::IRQEveryTime, CounterMode::IRQPulse, Counter2::Source::System_Clock_Div_8); - - // We disable the IRQ here so it can be enabled by user demand later - // Having the interrupt fire every 10ms will slow us down slightly so we only do it on demand - Interrupt::disable_irq(Interrupt::Timer2); - - SysCall::EnterCriticalSection(); - SysCall::SysEnqIntRP(SysCall::Priority::Timer2Irq, &irq_callback); - SysCall::ExitCriticalSection(); - - Counter2.set_target_value(HighResTime::TicksFor10ms); - Counter2.set_mode(Mode); - } - } - } +#include +#include +#include + +namespace JabyEngine { + namespace Timer { + extern SysCall::InterruptCallback irq_callback; + } + + namespace boot { + namespace Timer { + using namespace JabyEngine::Timer; + + void setup() { + using namespace Timer_IO; + using namespace Timer_IO_Values; + + static constexpr auto Mode = CounterMode::from(CounterMode::FreeRun, Counter2::SyncMode::FreeRun, CounterMode::ResetAfterTarget, CounterMode::IRQAtTarget, CounterMode::IRQEveryTime, CounterMode::IRQPulse, Counter2::Source::System_Clock_Div_8); + + // We disable the IRQ here so it can be enabled by user demand later + // Having the interrupt fire every 10ms will slow us down slightly so we only do it on demand + Interrupt::disable_irq(Interrupt::Timer2); + + SysCall::EnterCriticalSection(); + SysCall::SysEnqIntRP(SysCall::Priority::Timer2Irq, &irq_callback); + SysCall::ExitCriticalSection(); + + Counter2.set_target_value(HighResTime::TicksFor10ms); + Counter2.set_mode(Mode); + } + } + } } \ No newline at end of file diff --git a/src/Library/src/CD/cd.cpp b/src/Library/src/CD/cd.cpp index 250ba58d..2a0501c8 100644 --- a/src/Library/src/CD/cd.cpp +++ b/src/Library/src/CD/cd.cpp @@ -1,130 +1,130 @@ -#include "../../internal-include/CD/cd_internal.hpp" -#include "../../internal-include/System/callbacks_internal.hpp" -#include -#include -#include -#include - -namespace JabyEngine { - namespace CD { - namespace internal { - extern SectorBufferAllocator sector_allocator; - extern File cur_file; - - static constexpr auto AudioSectorMode = CD_IO_Values::Mode::from(CD_IO_Values::Mode::SingleSpeed, CD_IO_Values::Mode::AutoPauseTrack, CD_IO_Values::Mode::CDDA); - static constexpr auto DataSectorMode = CD_IO_Values::Mode::from(CD_IO_Values::Mode::DoubleSpeed, CD_IO_Values::Mode::DataSector); - static constexpr auto XAAudioSectorMode = CD_IO_Values::Mode::from(CD_IO_Values::Mode::SingleSpeed, CD_IO_Values::Mode::XADPCM, CD_IO_Values::Mode::WholeSector, CD_IO_Values::Mode::UseXAFilter); - - namespace IRQ { - SysCall::InterruptVerifierResult verifier(); - void handler(uint32_t); - } - - auto irq_callback = SysCall::InterruptCallback::from(IRQ::verifier, IRQ::handler); - State current_state = State::Ready; - uint8_t irq_bit_pending = CD_IO::Interrupt::None; - - static void read_sector_dma(uint32_t* dst, size_t bytes) { - static const auto WaitSectorReady = []() { - while(!CD_IO::IndexStatus.read().is_set(CD_IO_Values::IndexStatus::HasDataFifoData)); - }; - - static const auto ReadSector = [](uint32_t* dst, size_t bytes) { - DMA_IO::CDROM.set_adr(reinterpret_cast(dst)); - DMA_IO::CDROM.block_ctrl.write(DMA_IO_Values::BCR::SyncMode0::for_cd(bytes >> 2)); - DMA_IO::CDROM.channel_ctrl.write(DMA_IO_Values::CHCHR::StartCDROM()); - - DMA_IO::CDROM.wait(); - CD_IO::PortIndex0::change_to(); - - CD_IO::PortIndex0::Request.write(CD_IO_Values::Request::reset()); - }; - - WaitSectorReady(); - ReadSector(dst, bytes); - } - - static BCDTimeStamp send_read_cmd(uint32_t lba, CD_IO::Command::Desc cmd) { - const auto loc = BCDTimeStamp::from(lba); - - Command::send(CD_IO::Command::SetLoc, loc.min, loc.sec, loc.sector); - Command::send(cmd); - return loc; - } - - static void send_read_n(uint32_t lba) { - send_read_cmd(lba, CD_IO::Command::ReadN); - current_state = State::Reading; - } - - void read_file(AutoLBAEntry file_info, const SectorBufferAllocator& buffer_allocator) { - cur_file.set_from(file_info); - sector_allocator = buffer_allocator; - - enable_CD(); - send_read_n(cur_file.cur_lba); - } - - void end_read_file() { - sector_allocator = SectorBufferAllocator::invalid(); - } - - void continue_reading() { - if(current_state == State::BufferFull) { - CD_IO::PortIndex0::change_to(); - send_read_n(cur_file.cur_lba); - } - } - - void copy_from_sector(uint32_t* dst, size_t bytes) { - read_sector_dma(dst, bytes); - } - - BCDTimeStamp get_loc() { - Command::send_wait_response(CD_IO::Command::GetLocP); - - // XEBRA does not support the mirror register so we go for the original... - CD_IO::PortIndex1::change_to(); - const auto track = CD_IO::PortIndex1::ResponseFifo.read().raw; // track number (AAh=Lead-out area) (FFh=unknown, toc, none?) - const auto index = CD_IO::PortIndex1::ResponseFifo.read().raw; // index number (Usually 01h) - const auto mm = CD_IO::PortIndex1::ResponseFifo.read().raw; // minute number within track (00h and up) - const auto ss = CD_IO::PortIndex1::ResponseFifo.read().raw; // second number within track (00h to 59h) - const auto sect = CD_IO::PortIndex1::ResponseFifo.read().raw; // sector number within track (00h to 74h) - - const auto min = CD_IO::PortIndex1::ResponseFifo.read().raw; // minute number on entire disk (00h and up) - const auto sec = CD_IO::PortIndex1::ResponseFifo.read().raw; // second number on entire disk (00h to 59h) - const auto sectors = CD_IO::PortIndex1::ResponseFifo.read().raw; // sector number on entire disk (00h to 74h) - - return BCDTimeStamp{min, sec, sectors}; - } - - BCDTimeStamp get_locL() { - Command::send_wait_response(CD_IO::Command::GetLocL); - - const auto min = CD_IO::PortIndex0::ResponseFifo.read().raw; - const auto sec = CD_IO::PortIndex0::ResponseFifo.read().raw; - const auto sector = CD_IO::PortIndex0::ResponseFifo.read().raw; - - return BCDTimeStamp{min, sec, sector}; - } - - void enable_CD() { - Command::send(CD_IO::Command::SetMode, DataSectorMode); - } - - void enable_CDDA() { - Command::send(CD_IO::Command::SetMode, AudioSectorMode); - } - - void enable_CDXA(bool double_speed) { - static constexpr uint8_t SingleSpeedBit = 0x0; - static constexpr uint8_t DoubleSpeedBit = static_cast(CD_IO_Values::Mode::DoubleSpeed); - - const uint8_t mode = XAAudioSectorMode.raw | (double_speed ? DoubleSpeedBit : SingleSpeedBit); - - Command::send(CD_IO::Command::SetMode, mode); - current_state = State::XAMode; - } - } - } +#include "../../internal-include/CD/cd_internal.hpp" +#include "../../internal-include/System/callbacks_internal.hpp" +#include +#include +#include +#include + +namespace JabyEngine { + namespace CD { + namespace internal { + extern SectorBufferAllocator sector_allocator; + extern File cur_file; + + static constexpr auto AudioSectorMode = CD_IO_Values::Mode::from(CD_IO_Values::Mode::SingleSpeed, CD_IO_Values::Mode::AutoPauseTrack, CD_IO_Values::Mode::CDDA); + static constexpr auto DataSectorMode = CD_IO_Values::Mode::from(CD_IO_Values::Mode::DoubleSpeed, CD_IO_Values::Mode::DataSector); + static constexpr auto XAAudioSectorMode = CD_IO_Values::Mode::from(CD_IO_Values::Mode::SingleSpeed, CD_IO_Values::Mode::XADPCM, CD_IO_Values::Mode::WholeSector, CD_IO_Values::Mode::UseXAFilter); + + namespace IRQ { + SysCall::InterruptVerifierResult verifier(); + void handler(uint32_t); + } + + auto irq_callback = SysCall::InterruptCallback::from(IRQ::verifier, IRQ::handler); + State current_state = State::Ready; + uint8_t irq_bit_pending = CD_IO::Interrupt::None; + + static void read_sector_dma(uint32_t* dst, size_t bytes) { + static const auto WaitSectorReady = []() { + while(!CD_IO::IndexStatus.read().is_set(CD_IO_Values::IndexStatus::HasDataFifoData)); + }; + + static const auto ReadSector = [](uint32_t* dst, size_t bytes) { + DMA_IO::CDROM.set_adr(reinterpret_cast(dst)); + DMA_IO::CDROM.block_ctrl.write(DMA_IO_Values::BCR::SyncMode0::for_cd(bytes >> 2)); + DMA_IO::CDROM.channel_ctrl.write(DMA_IO_Values::CHCHR::StartCDROM()); + + DMA_IO::CDROM.wait(); + CD_IO::PortIndex0::change_to(); + + CD_IO::PortIndex0::Request.write(CD_IO_Values::Request::reset()); + }; + + WaitSectorReady(); + ReadSector(dst, bytes); + } + + static BCDTimeStamp send_read_cmd(uint32_t lba, CD_IO::Command::Desc cmd) { + const auto loc = BCDTimeStamp::from(lba); + + Command::send(CD_IO::Command::SetLoc, loc.min, loc.sec, loc.sector); + Command::send(cmd); + return loc; + } + + static void send_read_n(uint32_t lba) { + send_read_cmd(lba, CD_IO::Command::ReadN); + current_state = State::Reading; + } + + void read_file(AutoLBAEntry file_info, const SectorBufferAllocator& buffer_allocator) { + cur_file.set_from(file_info); + sector_allocator = buffer_allocator; + + enable_CD(); + send_read_n(cur_file.cur_lba); + } + + void end_read_file() { + sector_allocator = SectorBufferAllocator::invalid(); + } + + void continue_reading() { + if(current_state == State::BufferFull) { + CD_IO::PortIndex0::change_to(); + send_read_n(cur_file.cur_lba); + } + } + + void copy_from_sector(uint32_t* dst, size_t bytes) { + read_sector_dma(dst, bytes); + } + + BCDTimeStamp get_loc() { + Command::send_wait_response(CD_IO::Command::GetLocP); + + // XEBRA does not support the mirror register so we go for the original... + CD_IO::PortIndex1::change_to(); + const auto track = CD_IO::PortIndex1::ResponseFifo.read().raw; // track number (AAh=Lead-out area) (FFh=unknown, toc, none?) + const auto index = CD_IO::PortIndex1::ResponseFifo.read().raw; // index number (Usually 01h) + const auto mm = CD_IO::PortIndex1::ResponseFifo.read().raw; // minute number within track (00h and up) + const auto ss = CD_IO::PortIndex1::ResponseFifo.read().raw; // second number within track (00h to 59h) + const auto sect = CD_IO::PortIndex1::ResponseFifo.read().raw; // sector number within track (00h to 74h) + + const auto min = CD_IO::PortIndex1::ResponseFifo.read().raw; // minute number on entire disk (00h and up) + const auto sec = CD_IO::PortIndex1::ResponseFifo.read().raw; // second number on entire disk (00h to 59h) + const auto sectors = CD_IO::PortIndex1::ResponseFifo.read().raw; // sector number on entire disk (00h to 74h) + + return BCDTimeStamp{min, sec, sectors}; + } + + BCDTimeStamp get_locL() { + Command::send_wait_response(CD_IO::Command::GetLocL); + + const auto min = CD_IO::PortIndex0::ResponseFifo.read().raw; + const auto sec = CD_IO::PortIndex0::ResponseFifo.read().raw; + const auto sector = CD_IO::PortIndex0::ResponseFifo.read().raw; + + return BCDTimeStamp{min, sec, sector}; + } + + void enable_CD() { + Command::send(CD_IO::Command::SetMode, DataSectorMode); + } + + void enable_CDDA() { + Command::send(CD_IO::Command::SetMode, AudioSectorMode); + } + + void enable_CDXA(bool double_speed) { + static constexpr uint8_t SingleSpeedBit = 0x0; + static constexpr uint8_t DoubleSpeedBit = static_cast(CD_IO_Values::Mode::DoubleSpeed); + + const uint8_t mode = XAAudioSectorMode.raw | (double_speed ? DoubleSpeedBit : SingleSpeedBit); + + Command::send(CD_IO::Command::SetMode, mode); + current_state = State::XAMode; + } + } + } } \ No newline at end of file diff --git a/src/Library/src/CD/cd_interrupt_handler.cpp b/src/Library/src/CD/cd_interrupt_handler.cpp index 1aa6b607..85958418 100644 --- a/src/Library/src/CD/cd_interrupt_handler.cpp +++ b/src/Library/src/CD/cd_interrupt_handler.cpp @@ -1,93 +1,93 @@ -#include "../../internal-include/CD/cd_internal.hpp" -#include - -namespace JabyEngine { - namespace CDDA { - extern CD::internal::BCDTimeStamp playing_track; - } - - namespace CDXA { - CD::internal::State interrupt_handler(uint8_t irq); - } - - namespace CD { - namespace internal { - SectorBufferAllocator sector_allocator; - File cur_file; - - namespace IRQ { - static void process(uint32_t irq) { - if(current_state != State::XAMode) { - switch(irq) { - case CD_IO::Interrupt::DataReady: { - // Obtain sector content here - auto* sector = sector_allocator.allocate_sector(); - if(sector) { - //Now obtain sector - copy_from_sector(sector->data, CD_IO::DataSector::SizeBytes); - - if(cur_file.done_processing()) { - current_state = State::Done; - Command::send_no_wait(CD_IO::Command::Pause); - } - } - - else { - current_state = State::BufferFull; - Command::send_no_wait(CD_IO::Command::Pause); - } - } break; - - case CD_IO::Interrupt::DataEnd: { - set_loc(CDDA::playing_track); - Command::send_no_wait(CD_IO::Command::Play); - } break; - - case CD_IO::Interrupt::DiskError: { - current_state = State::Error; - } break; - } - } - - else { - current_state = CDXA::interrupt_handler(irq); - } - } - - //###################################################################################################################### - - SysCall::InterruptVerifierResult verifier() { - if(Interrupt::is_irq(Interrupt::CDROM)) { - Interrupt::ack_irq(Interrupt::CDROM); - return SysCall::InterruptVerifierResult::ExecuteHandler; - } - - else { - return SysCall::InterruptVerifierResult::SkipHandler; - } - } - - void handler(uint32_t x) { - const auto old_status = CD_IO::IndexStatus.read(); - - CD_IO::PortIndex1::change_to(); - const auto cur_irq = CD_IO::Interrupt::get_type(CD_IO::PortIndex1::InterruptFlag); - CD_IO::PortIndex1::change_to(); - CD_IO::Interrupt::ack_extended(CD_IO::PortIndex1::InterruptFlag); - - irq_bit_pending = bit::clear(irq_bit_pending, cur_irq); - - CD_IO::PortIndex0::change_to(); - if(cur_irq == CD_IO::Interrupt::DataReady) { - CD_IO::PortIndex0::Request.write(CD_IO_Values::Request::want_data()); - } - - process(cur_irq); - // No masking required because we can only write bit 0 - 2 - CD_IO::IndexStatus.write(old_status); - return SysCall::ReturnFromException(); - } - } - } - } +#include "../../internal-include/CD/cd_internal.hpp" +#include + +namespace JabyEngine { + namespace CDDA { + extern CD::internal::BCDTimeStamp playing_track; + } + + namespace CDXA { + CD::internal::State interrupt_handler(uint8_t irq); + } + + namespace CD { + namespace internal { + SectorBufferAllocator sector_allocator; + File cur_file; + + namespace IRQ { + static void process(uint32_t irq) { + if(current_state != State::XAMode) { + switch(irq) { + case CD_IO::Interrupt::DataReady: { + // Obtain sector content here + auto* sector = sector_allocator.allocate_sector(); + if(sector) { + //Now obtain sector + copy_from_sector(sector->data, CD_IO::DataSector::SizeBytes); + + if(cur_file.done_processing()) { + current_state = State::Done; + Command::send_no_wait(CD_IO::Command::Pause); + } + } + + else { + current_state = State::BufferFull; + Command::send_no_wait(CD_IO::Command::Pause); + } + } break; + + case CD_IO::Interrupt::DataEnd: { + set_loc(CDDA::playing_track); + Command::send_no_wait(CD_IO::Command::Play); + } break; + + case CD_IO::Interrupt::DiskError: { + current_state = State::Error; + } break; + } + } + + else { + current_state = CDXA::interrupt_handler(irq); + } + } + + //###################################################################################################################### + + SysCall::InterruptVerifierResult verifier() { + if(Interrupt::is_irq(Interrupt::CDROM)) { + Interrupt::ack_irq(Interrupt::CDROM); + return SysCall::InterruptVerifierResult::ExecuteHandler; + } + + else { + return SysCall::InterruptVerifierResult::SkipHandler; + } + } + + void handler(uint32_t x) { + const auto old_status = CD_IO::IndexStatus.read(); + + CD_IO::PortIndex1::change_to(); + const auto cur_irq = CD_IO::Interrupt::get_type(CD_IO::PortIndex1::InterruptFlag); + CD_IO::PortIndex1::change_to(); + CD_IO::Interrupt::ack_extended(CD_IO::PortIndex1::InterruptFlag); + + irq_bit_pending = bit::clear(irq_bit_pending, cur_irq); + + CD_IO::PortIndex0::change_to(); + if(cur_irq == CD_IO::Interrupt::DataReady) { + CD_IO::PortIndex0::Request.write(CD_IO_Values::Request::want_data()); + } + + process(cur_irq); + // No masking required because we can only write bit 0 - 2 + CD_IO::IndexStatus.write(old_status); + return SysCall::ReturnFromException(); + } + } + } + } } \ No newline at end of file diff --git a/src/Library/src/File/Processor/TIM/tim_helper.cpp b/src/Library/src/File/Processor/TIM/tim_helper.cpp index 6a86ed29..1b3e05f6 100644 --- a/src/Library/src/File/Processor/TIM/tim_helper.cpp +++ b/src/Library/src/File/Processor/TIM/tim_helper.cpp @@ -1,67 +1,67 @@ -#include "tim_helper.hpp" - -namespace JabyEngine { - namespace TIMFileProcessor { - namespace { - void set_gpu_receive(const uint32_t* src, uint16_t x, uint16_t y, uint16_t w, uint16_t h) { - GPU::internal::DMA::Receive::prepare(); - GPU::internal::DMA::Receive::set_dst(PositionU16::create(x, y), SizeU16::create(w, h)); - GPU::internal::DMA::Receive::set_src(reinterpret_cast(src)); - } - - size_t set_gpu_receive_data(const uint32_t* src, const AreaU16& dst) { - const auto width = dst.size.width; - const auto height = dst.size.height; - - set_gpu_receive(src, dst.position.x, dst.position.y, width, height); - return (width*height)/2; - } - - Progress parse_data(State::CDDataProcessor& data_proc, GenericTIM& generic_tim) { - const auto [words_to_use, is_last] = Helper::DMA::WordsReady::calculate(data_proc, generic_tim.words_left); - const auto words_used = Helper::DMA::send_words(words_to_use, is_last); - - generic_tim.words_left -= words_used; - data_proc.processed(words_used*sizeof(uint32_t)); - return is_last ? Progress::Done : Progress::InProgress; - } - - Progress switch_state_parse_data(State::CDDataProcessor& data_proc, GenericTIM& generic_tim) { - const auto result = generic_tim.pre_data_parsing(data_proc); - if(result == Progress::Done) { - generic_tim.words_left = TIMFileProcessor::set_gpu_receive_data(reinterpret_cast(data_proc.data_adr), generic_tim.tex_area); - return Helper::exchange_and_execute_process_function(TIMFileProcessor::parse_data, data_proc, generic_tim); - } - - return result; - } - - Progress parse_clut(State::CDDataProcessor& data_proc, GenericTIM& generic_tim) { - if(const auto result = TIMFileProcessor::parse_data(data_proc, generic_tim); result != Progress::Done) { - return result; - } - - else { - return switch_state_parse_data(data_proc, generic_tim); - } - } - } - - Progress parse_header(State::CDDataProcessor& data_proc, GenericTIM& generic_tim) { - const auto result = generic_tim.parse_header(data_proc); - if(result == Progress::Done) { - //Check if we have a clut to care about - if(generic_tim.has_clut()) { - //CLUTs are 16bit full color anyway - generic_tim.words_left = TIMFileProcessor::set_gpu_receive_data(reinterpret_cast(data_proc.data_adr), generic_tim.clut_area); - return Helper::exchange_and_execute_process_function(parse_clut, data_proc, generic_tim); - } - - else { - return switch_state_parse_data(data_proc, generic_tim); - } - } - return result; - } - } +#include "tim_helper.hpp" + +namespace JabyEngine { + namespace TIMFileProcessor { + namespace { + void set_gpu_receive(const uint32_t* src, uint16_t x, uint16_t y, uint16_t w, uint16_t h) { + GPU::internal::DMA::Receive::prepare(); + GPU::internal::DMA::Receive::set_dst(PositionU16::create(x, y), SizeU16::create(w, h)); + GPU::internal::DMA::Receive::set_src(reinterpret_cast(src)); + } + + size_t set_gpu_receive_data(const uint32_t* src, const AreaU16& dst) { + const auto width = dst.size.width; + const auto height = dst.size.height; + + set_gpu_receive(src, dst.position.x, dst.position.y, width, height); + return (width*height)/2; + } + + Progress parse_data(State::CDDataProcessor& data_proc, GenericTIM& generic_tim) { + const auto [words_to_use, is_last] = Helper::DMA::WordsReady::calculate(data_proc, generic_tim.words_left); + const auto words_used = Helper::DMA::send_words(words_to_use, is_last); + + generic_tim.words_left -= words_used; + data_proc.processed(words_used*sizeof(uint32_t)); + return is_last ? Progress::Done : Progress::InProgress; + } + + Progress switch_state_parse_data(State::CDDataProcessor& data_proc, GenericTIM& generic_tim) { + const auto result = generic_tim.pre_data_parsing(data_proc); + if(result == Progress::Done) { + generic_tim.words_left = TIMFileProcessor::set_gpu_receive_data(reinterpret_cast(data_proc.data_adr), generic_tim.tex_area); + return Helper::exchange_and_execute_process_function(TIMFileProcessor::parse_data, data_proc, generic_tim); + } + + return result; + } + + Progress parse_clut(State::CDDataProcessor& data_proc, GenericTIM& generic_tim) { + if(const auto result = TIMFileProcessor::parse_data(data_proc, generic_tim); result != Progress::Done) { + return result; + } + + else { + return switch_state_parse_data(data_proc, generic_tim); + } + } + } + + Progress parse_header(State::CDDataProcessor& data_proc, GenericTIM& generic_tim) { + const auto result = generic_tim.parse_header(data_proc); + if(result == Progress::Done) { + //Check if we have a clut to care about + if(generic_tim.has_clut()) { + //CLUTs are 16bit full color anyway + generic_tim.words_left = TIMFileProcessor::set_gpu_receive_data(reinterpret_cast(data_proc.data_adr), generic_tim.clut_area); + return Helper::exchange_and_execute_process_function(parse_clut, data_proc, generic_tim); + } + + else { + return switch_state_parse_data(data_proc, generic_tim); + } + } + return result; + } + } } \ No newline at end of file diff --git a/src/Library/src/File/Processor/TIM/tim_helper.hpp b/src/Library/src/File/Processor/TIM/tim_helper.hpp index dc012e92..eae0bf75 100644 --- a/src/Library/src/File/Processor/TIM/tim_helper.hpp +++ b/src/Library/src/File/Processor/TIM/tim_helper.hpp @@ -1,26 +1,26 @@ -#pragma once -#include "../../../../internal-include/GPU/gpu_internal.hpp" -#include -#include - -namespace JabyEngine { - namespace TIMFileProcessor { - using namespace FileProcessor; - using namespace GPU; - - struct GenericTIM { - AreaU16 clut_area; - AreaU16 tex_area; - size_t words_left; //32bit values - - bool has_clut() const { - return this->clut_area.size.width > 0; - } - - virtual Progress parse_header(State::CDDataProcessor& data_proc) = 0; - virtual Progress pre_data_parsing(State::CDDataProcessor& data_proc) = 0; - }; - - Progress parse_header(State::CDDataProcessor& data_proc, GenericTIM& generic_tim); - } +#pragma once +#include "../../../../internal-include/GPU/gpu_internal.hpp" +#include +#include + +namespace JabyEngine { + namespace TIMFileProcessor { + using namespace FileProcessor; + using namespace GPU; + + struct GenericTIM { + AreaU16 clut_area; + AreaU16 tex_area; + size_t words_left; //32bit values + + bool has_clut() const { + return this->clut_area.size.width > 0; + } + + virtual Progress parse_header(State::CDDataProcessor& data_proc) = 0; + virtual Progress pre_data_parsing(State::CDDataProcessor& data_proc) = 0; + }; + + Progress parse_header(State::CDDataProcessor& data_proc, GenericTIM& generic_tim); + } } \ No newline at end of file diff --git a/src/Library/src/File/Processor/TIM/tim_processor.cpp b/src/Library/src/File/Processor/TIM/tim_processor.cpp index 57d11ca8..3a4eb5db 100644 --- a/src/Library/src/File/Processor/TIM/tim_processor.cpp +++ b/src/Library/src/File/Processor/TIM/tim_processor.cpp @@ -1,61 +1,61 @@ -#include "tim_helper.hpp" -#include - -namespace JabyEngine { - namespace FileProcessor { - namespace { - using GPU::AreaU16; - - struct BlockInfo { - uint32_t size; - uint16_t x; - uint16_t y; - uint16_t w; - uint16_t h; - }; - - struct TIMState : public TIMFileProcessor::GenericTIM { - static TIMState create() { - TIMState state; - return state; - } - - virtual Progress parse_header(State::CDDataProcessor& data_proc) override { - static constexpr auto HEADER_SIZE = 2*sizeof(uint32_t); - - if(data_proc.data_bytes >= (HEADER_SIZE + sizeof(BlockInfo))) { - static constexpr auto HAS_CLUT_BIT = (0x1 << 3); - - data_proc.processed(sizeof(uint32_t)); - const auto flag = data_proc.simple_read_r(); - - if(flag & HAS_CLUT_BIT) { - const auto block_info = data_proc.simple_read_r(); - this->clut_area = AreaU16::create(block_info.x, block_info.y, block_info.w, block_info.h); - } - - else { - this->clut_area = AreaU16::create(0, 0, 0, 0); - } - return Progress::Done; - } - return Progress::Error; - } - - virtual Progress pre_data_parsing(State::CDDataProcessor& data_proc) { - if(data_proc.data_bytes >= sizeof(BlockInfo)) { - const auto block_info = data_proc.simple_read_r(); - this->tex_area = AreaU16::create(block_info.x, block_info.y, block_info.w, block_info.h); - return Progress::Done; - } - return Progress::InProgress; - } - }; - } - - State create(const uint32_t* data_adr, const TIM& file) { - using Callback = Progress(*)(State::CDDataProcessor& data_proc, TIMState& simple_tim); - return State::from(TIMState::create(), data_adr, reinterpret_cast(TIMFileProcessor::parse_header)); - } - } +#include "tim_helper.hpp" +#include + +namespace JabyEngine { + namespace FileProcessor { + namespace { + using GPU::AreaU16; + + struct BlockInfo { + uint32_t size; + uint16_t x; + uint16_t y; + uint16_t w; + uint16_t h; + }; + + struct TIMState : public TIMFileProcessor::GenericTIM { + static TIMState create() { + TIMState state; + return state; + } + + virtual Progress parse_header(State::CDDataProcessor& data_proc) override { + static constexpr auto HEADER_SIZE = 2*sizeof(uint32_t); + + if(data_proc.data_bytes >= (HEADER_SIZE + sizeof(BlockInfo))) { + static constexpr auto HAS_CLUT_BIT = (0x1 << 3); + + data_proc.processed(sizeof(uint32_t)); + const auto flag = data_proc.simple_read_r(); + + if(flag & HAS_CLUT_BIT) { + const auto block_info = data_proc.simple_read_r(); + this->clut_area = AreaU16::create(block_info.x, block_info.y, block_info.w, block_info.h); + } + + else { + this->clut_area = AreaU16::create(0, 0, 0, 0); + } + return Progress::Done; + } + return Progress::Error; + } + + virtual Progress pre_data_parsing(State::CDDataProcessor& data_proc) { + if(data_proc.data_bytes >= sizeof(BlockInfo)) { + const auto block_info = data_proc.simple_read_r(); + this->tex_area = AreaU16::create(block_info.x, block_info.y, block_info.w, block_info.h); + return Progress::Done; + } + return Progress::InProgress; + } + }; + } + + State create(const uint32_t* data_adr, const TIM& file) { + using Callback = Progress(*)(State::CDDataProcessor& data_proc, TIMState& simple_tim); + return State::from(TIMState::create(), data_adr, reinterpret_cast(TIMFileProcessor::parse_header)); + } + } } \ No newline at end of file diff --git a/src/Library/src/File/Processor/cd_file_processor.cpp b/src/Library/src/File/Processor/cd_file_processor.cpp index aaaccedf..5fed924f 100644 --- a/src/Library/src/File/Processor/cd_file_processor.cpp +++ b/src/Library/src/File/Processor/cd_file_processor.cpp @@ -1,127 +1,127 @@ -#include "../../../internal-include/CD/cd_internal.hpp" -#include -#include - -namespace JabyEngine { - static constexpr auto DisabledCircularBufferSize = 512; - - void CDFileProcessor :: start_cur_job(const AutoLBAEntry* lba, const BufferConfiguration& buf_cfg) { - using CD::internal::SectorBufferAllocator; - const auto configurate_for = [this](const CDFile& file, const BufferConfiguration& buf_cfg, bool is_lz4) -> FileProcessor::State { - const uint32_t* data_adr = [this](const CDFile& file, const BufferConfiguration& buf_cfg, bool is_lz4) -> const uint32_t* { - const auto disable_lz4 = [this](uint32_t* work_area, size_t size, uint32_t* overwrite_dst = nullptr) -> uint32_t* { - reinterpret_cast(this->circular_buffer.setup(reinterpret_cast(work_area), size)); - - this->lz4_decomp.disable(); - return overwrite_dst ? overwrite_dst : reinterpret_cast(work_area); - }; - - const auto enable_lz4 = [this](uint32_t* work_area, size_t size, uint32_t* override_dst = nullptr) -> uint32_t* { - uint8_t* dst_adr = reinterpret_cast(this->circular_buffer.setup(reinterpret_cast(work_area), size)); - - if(override_dst) { - dst_adr = reinterpret_cast(override_dst); - } - - this->lz4_decomp.setup(dst_adr); - return reinterpret_cast(dst_adr); - }; - - if(file.type == CDFileType::CopyTo) { - return is_lz4 ? enable_lz4(buf_cfg.adr, buf_cfg.sector_count, file.payload.overlay.dst) : disable_lz4(file.payload.copy_to.dst, DisabledCircularBufferSize); - } - - else { - return is_lz4 ? enable_lz4(buf_cfg.adr, buf_cfg.sector_count) : disable_lz4(buf_cfg.adr, DisabledCircularBufferSize); - } - }(file, buf_cfg, is_lz4); - - switch(file.type) { - case CDFileType::CopyTo: - return FileProcessor::create(data_adr, Nothing()); - - case CDFileType::SimpleTIM: - return FileProcessor::create(data_adr, file.payload.simple_tim); - - case CDFileType::SonyTIM: - return FileProcessor::create(data_adr, file.payload.tim); - - case CDFileType::SonyVAG: - return FileProcessor::create(data_adr, file.payload.vag); - - default: - return FileProcessor::create_custom(data_adr, static_cast(file.type) - static_cast(CDFileType::Custom), file.payload); - } - }; - - const auto& cur_job = *this->jobs.files; - const auto& cur_lba = lba[cur_job.rel_lba_idx]; - - this->file_state = configurate_for(cur_job, buf_cfg, cur_lba.is_lz4()); - CD::internal::read_file(cur_lba, SectorBufferAllocator::create(this, - [](void* ctx) -> CD_IO::DataSector* { - CDFileProcessor &self = *reinterpret_cast(ctx); - return self.circular_buffer.allocate(); - })); - - //printf(">>> %i.) CD needs to load LBA: %i -> %i (is LZ4: [%s])\n", cur_job.rel_lba_idx, cur_lba.get_lba(), cur_lba.get_size_in_sectors(), cur_lba.is_lz4() ? "Yes" : "No"); - } - - bool CDFileProcessor :: process_data() { - while(this->circular_buffer.has_data()) { - ArrayRange cur_sector(reinterpret_cast(this->circular_buffer.get_next()->data), CD_IO::DataSector::SizeBytes); - - // v We can not know if there will be more data or not - but it also doesn't matter much for us - const auto result = this->lz4_decomp.process(cur_sector, false); - this->circular_buffer.pop(); - - if(result) { - // Process the data in the tmp_area - if(this->file_state.process(result.bytes_ready) == Progress::Error) { - return false; - } - } - - else { - return false; - } - } - return true; - } - - void CDFileProcessor :: setup(const volatile AutoLBAEntry* lba, JobArray jobs, const BufferConfiguration& buf_cfg) { - this->jobs = jobs; - CDFileProcessor::start_cur_job(const_cast(lba), buf_cfg); - } - - void CDFileProcessor :: shutdown() { - CD::internal::end_read_file(); - } - - Progress CDFileProcessor :: process() { - const auto cur_state = CD::internal::read_current_state(); - CDFileProcessor::process_data(); - switch(cur_state) { - case CD::internal::State::Done: - /* - We are done now! - The user decides if he wants the next value - */ - //while(this->file_state.process(0) != Progress::Done); - return Progress::Done; - - case CD::internal::State::BufferFull: - /* We processed data and unpause the CD drive */ - CD::internal::continue_reading(); - return Progress::InProgress; - - case CD::internal::State::Reading: - return Progress::InProgress; - - case CD::internal::State::Error: - default: - /* Error for real */ - return Progress::Error; - } - } +#include "../../../internal-include/CD/cd_internal.hpp" +#include +#include + +namespace JabyEngine { + static constexpr auto DisabledCircularBufferSize = 512; + + void CDFileProcessor :: start_cur_job(const AutoLBAEntry* lba, const BufferConfiguration& buf_cfg) { + using CD::internal::SectorBufferAllocator; + const auto configurate_for = [this](const CDFile& file, const BufferConfiguration& buf_cfg, bool is_lz4) -> FileProcessor::State { + const uint32_t* data_adr = [this](const CDFile& file, const BufferConfiguration& buf_cfg, bool is_lz4) -> const uint32_t* { + const auto disable_lz4 = [this](uint32_t* work_area, size_t size, uint32_t* overwrite_dst = nullptr) -> uint32_t* { + reinterpret_cast(this->circular_buffer.setup(reinterpret_cast(work_area), size)); + + this->lz4_decomp.disable(); + return overwrite_dst ? overwrite_dst : reinterpret_cast(work_area); + }; + + const auto enable_lz4 = [this](uint32_t* work_area, size_t size, uint32_t* override_dst = nullptr) -> uint32_t* { + uint8_t* dst_adr = reinterpret_cast(this->circular_buffer.setup(reinterpret_cast(work_area), size)); + + if(override_dst) { + dst_adr = reinterpret_cast(override_dst); + } + + this->lz4_decomp.setup(dst_adr); + return reinterpret_cast(dst_adr); + }; + + if(file.type == CDFileType::CopyTo) { + return is_lz4 ? enable_lz4(buf_cfg.adr, buf_cfg.sector_count, file.payload.overlay.dst) : disable_lz4(file.payload.copy_to.dst, DisabledCircularBufferSize); + } + + else { + return is_lz4 ? enable_lz4(buf_cfg.adr, buf_cfg.sector_count) : disable_lz4(buf_cfg.adr, DisabledCircularBufferSize); + } + }(file, buf_cfg, is_lz4); + + switch(file.type) { + case CDFileType::CopyTo: + return FileProcessor::create(data_adr, Nothing()); + + case CDFileType::SimpleTIM: + return FileProcessor::create(data_adr, file.payload.simple_tim); + + case CDFileType::SonyTIM: + return FileProcessor::create(data_adr, file.payload.tim); + + case CDFileType::SonyVAG: + return FileProcessor::create(data_adr, file.payload.vag); + + default: + return FileProcessor::create_custom(data_adr, static_cast(file.type) - static_cast(CDFileType::Custom), file.payload); + } + }; + + const auto& cur_job = *this->jobs.files; + const auto& cur_lba = lba[cur_job.rel_lba_idx]; + + this->file_state = configurate_for(cur_job, buf_cfg, cur_lba.is_lz4()); + CD::internal::read_file(cur_lba, SectorBufferAllocator::create(this, + [](void* ctx) -> CD_IO::DataSector* { + CDFileProcessor &self = *reinterpret_cast(ctx); + return self.circular_buffer.allocate(); + })); + + //printf(">>> %i.) CD needs to load LBA: %i -> %i (is LZ4: [%s])\n", cur_job.rel_lba_idx, cur_lba.get_lba(), cur_lba.get_size_in_sectors(), cur_lba.is_lz4() ? "Yes" : "No"); + } + + bool CDFileProcessor :: process_data() { + while(this->circular_buffer.has_data()) { + ArrayRange cur_sector(reinterpret_cast(this->circular_buffer.get_next()->data), CD_IO::DataSector::SizeBytes); + + // v We can not know if there will be more data or not - but it also doesn't matter much for us + const auto result = this->lz4_decomp.process(cur_sector, false); + this->circular_buffer.pop(); + + if(result) { + // Process the data in the tmp_area + if(this->file_state.process(result.bytes_ready) == Progress::Error) { + return false; + } + } + + else { + return false; + } + } + return true; + } + + void CDFileProcessor :: setup(const volatile AutoLBAEntry* lba, JobArray jobs, const BufferConfiguration& buf_cfg) { + this->jobs = jobs; + CDFileProcessor::start_cur_job(const_cast(lba), buf_cfg); + } + + void CDFileProcessor :: shutdown() { + CD::internal::end_read_file(); + } + + Progress CDFileProcessor :: process() { + const auto cur_state = CD::internal::read_current_state(); + CDFileProcessor::process_data(); + switch(cur_state) { + case CD::internal::State::Done: + /* + We are done now! + The user decides if he wants the next value + */ + //while(this->file_state.process(0) != Progress::Done); + return Progress::Done; + + case CD::internal::State::BufferFull: + /* We processed data and unpause the CD drive */ + CD::internal::continue_reading(); + return Progress::InProgress; + + case CD::internal::State::Reading: + return Progress::InProgress; + + case CD::internal::State::Error: + default: + /* Error for real */ + return Progress::Error; + } + } } \ No newline at end of file diff --git a/src/Library/src/File/Processor/custom_processor.cpp b/src/Library/src/File/Processor/custom_processor.cpp index 4f1cb308..7580a542 100644 --- a/src/Library/src/File/Processor/custom_processor.cpp +++ b/src/Library/src/File/Processor/custom_processor.cpp @@ -1,10 +1,10 @@ -#include -#include - -namespace JabyEngine { - namespace FileProcessor { - State __weak create_custom(const uint32_t* data_adr, const CDFileType_t& file_type, const CDFile::Payload& payload) { - return FileProcessor::create(data_adr, Nothing()); - } - } +#include +#include + +namespace JabyEngine { + namespace FileProcessor { + State __weak create_custom(const uint32_t* data_adr, const CDFileType_t& file_type, const CDFile::Payload& payload) { + return FileProcessor::create(data_adr, Nothing()); + } + } } \ No newline at end of file diff --git a/src/Library/src/File/Processor/vag_processor.cpp b/src/Library/src/File/Processor/vag_processor.cpp index 66098ed7..89f89f0a 100644 --- a/src/Library/src/File/Processor/vag_processor.cpp +++ b/src/Library/src/File/Processor/vag_processor.cpp @@ -1,79 +1,79 @@ -#include "../../../internal-include/SPU/spu_internal.hpp" -#include -#include -#include -#include -#include - -namespace JabyEngine { - namespace FileProcessor { - struct VAGHeader { - char id[4]; - uint32_t version; - uint32_t reserved; - uint32_t sample_size; - uint32_t sample_frequency; - uint8_t reserved_2[12]; - char name[16]; - - constexpr uint32_t get_version() const { - return read_be(this->version); - } - - constexpr uint32_t get_sample_size() const { - return read_be(this->sample_size); - } - - constexpr uint32_t get_sample_frequency() const { - return read_be(this->sample_frequency); - } - }; - - struct VAGState { - uint32_t voice_id; - size_t words_left; - SPU::SimpleVolume inital_vol; - - static constexpr VAGState create(uint32_t voice_id, SPU::SimpleVolume inital_vol) { - return VAGState{.voice_id = voice_id, .words_left = 0, .inital_vol = inital_vol}; - } - }; - - static Progress parse_sample(State::CDDataProcessor& data_proc, VAGState& state) { - const auto [words_to_use, is_last] = Helper::DMA::WordsReady::calculate(data_proc, state.words_left); - const auto words_used = Helper::DMA::send_words(words_to_use, is_last); - - state.words_left -= words_used; - - data_proc.processed(words_used*sizeof(uint32_t)); - return is_last ? Progress::Done : Progress::InProgress; - } - - static Progress parse_header(State::CDDataProcessor& data_proc, VAGState& state) { - if(data_proc.data_bytes >= sizeof(VAGHeader)) { - const auto& header = *reinterpret_cast(data_proc.data_adr); - const auto words = bytes_to_words(header.get_sample_size()); - const auto bytes = words_to_bytes(words); - - state.words_left = words; - - auto sram_adr = SPU::voice[state.voice_id].allocate(SPU_IO_Values::SampleRate::from_HZ(header.get_sample_frequency()), bytes); - - SPU::voice[state.voice_id].set_volume(state.inital_vol, state.inital_vol); - - data_proc.processed(sizeof(VAGHeader)); - SPU::internal::DMA::Receive::prepare(); - SPU::internal::DMA::Receive::set_dst(sram_adr); - SPU::internal::DMA::Receive::set_src(reinterpret_cast(data_proc.data_adr)); - - return Helper::exchange_and_execute_process_function(parse_sample, data_proc, state); - } - - return Progress::InProgress; - } - - State create(const uint32_t* data_adr, const VAG& file) { - return State::from(VAGState::create(file.voice_number, file.inital_stereo_vol), data_adr, parse_header); - } - } +#include "../../../internal-include/SPU/spu_internal.hpp" +#include +#include +#include +#include +#include + +namespace JabyEngine { + namespace FileProcessor { + struct VAGHeader { + char id[4]; + uint32_t version; + uint32_t reserved; + uint32_t sample_size; + uint32_t sample_frequency; + uint8_t reserved_2[12]; + char name[16]; + + constexpr uint32_t get_version() const { + return read_be(this->version); + } + + constexpr uint32_t get_sample_size() const { + return read_be(this->sample_size); + } + + constexpr uint32_t get_sample_frequency() const { + return read_be(this->sample_frequency); + } + }; + + struct VAGState { + uint32_t voice_id; + size_t words_left; + SPU::SimpleVolume inital_vol; + + static constexpr VAGState create(uint32_t voice_id, SPU::SimpleVolume inital_vol) { + return VAGState{.voice_id = voice_id, .words_left = 0, .inital_vol = inital_vol}; + } + }; + + static Progress parse_sample(State::CDDataProcessor& data_proc, VAGState& state) { + const auto [words_to_use, is_last] = Helper::DMA::WordsReady::calculate(data_proc, state.words_left); + const auto words_used = Helper::DMA::send_words(words_to_use, is_last); + + state.words_left -= words_used; + + data_proc.processed(words_used*sizeof(uint32_t)); + return is_last ? Progress::Done : Progress::InProgress; + } + + static Progress parse_header(State::CDDataProcessor& data_proc, VAGState& state) { + if(data_proc.data_bytes >= sizeof(VAGHeader)) { + const auto& header = *reinterpret_cast(data_proc.data_adr); + const auto words = bytes_to_words(header.get_sample_size()); + const auto bytes = words_to_bytes(words); + + state.words_left = words; + + auto sram_adr = SPU::voice[state.voice_id].allocate(SPU_IO_Values::SampleRate::from_HZ(header.get_sample_frequency()), bytes); + + SPU::voice[state.voice_id].set_volume(state.inital_vol, state.inital_vol); + + data_proc.processed(sizeof(VAGHeader)); + SPU::internal::DMA::Receive::prepare(); + SPU::internal::DMA::Receive::set_dst(sram_adr); + SPU::internal::DMA::Receive::set_src(reinterpret_cast(data_proc.data_adr)); + + return Helper::exchange_and_execute_process_function(parse_sample, data_proc, state); + } + + return Progress::InProgress; + } + + State create(const uint32_t* data_adr, const VAG& file) { + return State::from(VAGState::create(file.voice_number, file.inital_stereo_vol), data_adr, parse_header); + } + } } \ No newline at end of file diff --git a/src/Library/src/GPU/gpu.cpp b/src/Library/src/GPU/gpu.cpp index d7a86db6..323047df 100644 --- a/src/Library/src/GPU/gpu.cpp +++ b/src/Library/src/GPU/gpu.cpp @@ -1,119 +1,119 @@ -#include "../../internal-include/GPU/gpu_internal.hpp" -#include -#include -#include - -namespace JabyEngine { - namespace GPU { - uint8_t Display :: current_id = 0; - namespace internal { - #ifdef __SUPPORT_PS3__ - uintptr_t DMA :: MADR = 0; - #endif // __SUPPORT_PS3__ - - static SysCall::InterruptVerifierResult interrupt_verifier(); - static void interrupt_handler(uint32_t); - - auto irq_callback = SysCall::InterruptCallback::from(interrupt_verifier, interrupt_handler); - VSyncCallback vsync_callback = nullptr; - static uint8_t vsync_counter = 0; - bool vsync_lock_callback = false; - - static SysCall::InterruptVerifierResult interrupt_verifier() { - if(Interrupt::is_irq(Interrupt::VBlank)) { - Interrupt::ack_irq(Interrupt::VBlank); - return SysCall::InterruptVerifierResult::ExecuteHandler; - } - - else { - return SysCall::InterruptVerifierResult::SkipHandler; - } - } - - static void interrupt_handler(uint32_t) { - vsync_counter++; - MasterTime::value++; - - if(vsync_callback && !vsync_lock_callback) { - vsync_callback(); - } - //Callback::internal::VSync::execute(); - SysCall::ReturnFromException(); - } - - uint32_t Display :: exchange_buffer_and_display() { - static constexpr uint16_t TexturePageHeight = 256; - - const uint16_t draw_area_y = (TexturePageHeight*PublicDisplay::current_id); - - GPU::internal::set_draw_area(GPU::PositionU16::create(0, draw_area_y)); - PublicDisplay::current_id ^= 1; - GPU_IO::GP1.set_display_area(GPU::PositionU16::create(0, static_cast((TexturePageHeight*PublicDisplay::current_id)))); - return draw_area_y; - } - - void wait_vsync(uint8_t syncs) { - volatile auto& vsync_count = reinterpret_cast(vsync_counter); - - const uint8_t vsync_dst_value = vsync_count + syncs; - while(vsync_count != vsync_dst_value); - } - - void render(const uint32_t* data, size_t words) { - wait_ready_for_CMD(); - for(size_t n = 0; n < words; n++) { - GPU_IO::GP0.write({data[n]}); - } - } - - void render_dma(const uint32_t* data) { - // DPCR already enabled - DMA_IO::GPU.wait(); - GPU_IO::GP1.set_dma_direction(GPU_IO_Values::GPUSTAT::DMADirection::CPU2GPU); - DMA_IO::GPU.set_adr(reinterpret_cast(data)); - DMA_IO::GPU.block_ctrl.write(DMA_IO_Values::BCR::SyncMode2::for_gpu_cmd()); - - wait_ready_for_CMD(); - DMA_IO::GPU.channel_ctrl.write(DMA_IO_Values::CHCHR::StartGPULinked()); - } - } - - void Display :: set_offset(int16_t x, int16_t y) { - // Does not matter really - The original offset is good enough - #ifdef __ADJUST_PS3_SCREEN_OFFSET__ - static constexpr auto PS3_CorrectionX = 2; - static constexpr auto PS3_CorrectionY = 1; - #else - static constexpr auto PS3_CorrectionX = 0; - static constexpr auto PS3_CorrectionY = 0; - #endif // __ADJUST_PS3_SCREEN_OFFSET__ - - x += (internal::Display::DisplayRange.x + Configuration::DisplayDefaultOffset.x); - y += (internal::Display::DisplayRange.y + Configuration::DisplayDefaultOffset.y); - - GPU_IO::GP1.set_horizontal_display_range((x << 3), (x + Display::Width + PS3_CorrectionX) << 3); - GPU_IO::GP1.set_vertical_display_range( y, y + Display::Height + PS3_CorrectionY); - } - - void set_vsync_callback(VSyncCallback callback) { - internal::vsync_callback = callback; - } - - void swap_buffers(bool clear_screen) { - const int16_t draw_offset_y = internal::Display::exchange_buffer_and_display(); - internal::set_draw_offset(GPU::PositionI16::create(0, draw_offset_y)); - if(clear_screen) { - internal::quick_fill_fast(Color24::Black(), AreaU16::create(0, static_cast(draw_offset_y), Display::Width, Display::Height)); - } - } - - uint8_t swap_buffers_vsync(uint8_t syncs, bool clear_screen) { - // Waits for finish FIFO - internal::wait_ready_for_CMD(); - internal::wait_vsync(syncs); - - swap_buffers(clear_screen); - return Display::current_id; - } - } +#include "../../internal-include/GPU/gpu_internal.hpp" +#include +#include +#include + +namespace JabyEngine { + namespace GPU { + uint8_t Display :: current_id = 0; + namespace internal { + #ifdef __SUPPORT_PS3__ + uintptr_t DMA :: MADR = 0; + #endif // __SUPPORT_PS3__ + + static SysCall::InterruptVerifierResult interrupt_verifier(); + static void interrupt_handler(uint32_t); + + auto irq_callback = SysCall::InterruptCallback::from(interrupt_verifier, interrupt_handler); + VSyncCallback vsync_callback = nullptr; + static uint8_t vsync_counter = 0; + bool vsync_lock_callback = false; + + static SysCall::InterruptVerifierResult interrupt_verifier() { + if(Interrupt::is_irq(Interrupt::VBlank)) { + Interrupt::ack_irq(Interrupt::VBlank); + return SysCall::InterruptVerifierResult::ExecuteHandler; + } + + else { + return SysCall::InterruptVerifierResult::SkipHandler; + } + } + + static void interrupt_handler(uint32_t) { + vsync_counter++; + MasterTime::value++; + + if(vsync_callback && !vsync_lock_callback) { + vsync_callback(); + } + //Callback::internal::VSync::execute(); + SysCall::ReturnFromException(); + } + + uint32_t Display :: exchange_buffer_and_display() { + static constexpr uint16_t TexturePageHeight = 256; + + const uint16_t draw_area_y = (TexturePageHeight*PublicDisplay::current_id); + + GPU::internal::set_draw_area(GPU::PositionU16::create(0, draw_area_y)); + PublicDisplay::current_id ^= 1; + GPU_IO::GP1.set_display_area(GPU::PositionU16::create(0, static_cast((TexturePageHeight*PublicDisplay::current_id)))); + return draw_area_y; + } + + void wait_vsync(uint8_t syncs) { + volatile auto& vsync_count = reinterpret_cast(vsync_counter); + + const uint8_t vsync_dst_value = vsync_count + syncs; + while(vsync_count != vsync_dst_value); + } + + void render(const uint32_t* data, size_t words) { + wait_ready_for_CMD(); + for(size_t n = 0; n < words; n++) { + GPU_IO::GP0.write({data[n]}); + } + } + + void render_dma(const uint32_t* data) { + // DPCR already enabled + DMA_IO::GPU.wait(); + GPU_IO::GP1.set_dma_direction(GPU_IO_Values::GPUSTAT::DMADirection::CPU2GPU); + DMA_IO::GPU.set_adr(reinterpret_cast(data)); + DMA_IO::GPU.block_ctrl.write(DMA_IO_Values::BCR::SyncMode2::for_gpu_cmd()); + + wait_ready_for_CMD(); + DMA_IO::GPU.channel_ctrl.write(DMA_IO_Values::CHCHR::StartGPULinked()); + } + } + + void Display :: set_offset(int16_t x, int16_t y) { + // Does not matter really - The original offset is good enough + #ifdef __ADJUST_PS3_SCREEN_OFFSET__ + static constexpr auto PS3_CorrectionX = 2; + static constexpr auto PS3_CorrectionY = 1; + #else + static constexpr auto PS3_CorrectionX = 0; + static constexpr auto PS3_CorrectionY = 0; + #endif // __ADJUST_PS3_SCREEN_OFFSET__ + + x += (internal::Display::DisplayRange.x + Configuration::DisplayDefaultOffset.x); + y += (internal::Display::DisplayRange.y + Configuration::DisplayDefaultOffset.y); + + GPU_IO::GP1.set_horizontal_display_range((x << 3), (x + Display::Width + PS3_CorrectionX) << 3); + GPU_IO::GP1.set_vertical_display_range( y, y + Display::Height + PS3_CorrectionY); + } + + void set_vsync_callback(VSyncCallback callback) { + internal::vsync_callback = callback; + } + + void swap_buffers(bool clear_screen) { + const int16_t draw_offset_y = internal::Display::exchange_buffer_and_display(); + internal::set_draw_offset(GPU::PositionI16::create(0, draw_offset_y)); + if(clear_screen) { + internal::quick_fill_fast(Color24::Black(), AreaU16::create(0, static_cast(draw_offset_y), Display::Width, Display::Height)); + } + } + + uint8_t swap_buffers_vsync(uint8_t syncs, bool clear_screen) { + // Waits for finish FIFO + internal::wait_ready_for_CMD(); + internal::wait_vsync(syncs); + + swap_buffers(clear_screen); + return Display::current_id; + } + } } \ No newline at end of file diff --git a/src/Library/src/GTE/gte.cpp b/src/Library/src/GTE/gte.cpp index 5ec27167..83dc9820 100644 --- a/src/Library/src/GTE/gte.cpp +++ b/src/Library/src/GTE/gte.cpp @@ -1,129 +1,129 @@ -#include - -static int32_t hisin(int32_t value) { - static constexpr int32_t qN = 13; - static constexpr int32_t qA = 12; - static constexpr int32_t B = 19900; - static constexpr int32_t C = 3516; - - const auto c = value << (30 - qN); // Semi-circle info into carry. - - value -= 1< cosine calc - value = value << (31 - qN); // Mask with PI - value = value >> (31 - qN); // Note: SIGNED shift! (to qN) - value = value*value >> (2*qN - 14); // x=x^2 To Q14 - - auto result = B - (value*C >> 14); // B - x^2*C - result = (1 << qA) - (value*result >> 16); // A - x^2*(B-x^2*C) - - return c >= 0 ? result : -result; -} - -gte_float sin(deg_t value) { - return gte_float{.raw = hisin(value.raw)}; -} - -gte_float cos(deg_t value) { - return gte_float{.raw = hisin(value.raw + (deg_t::full_circle/4))}; -} - -namespace JabyEngine { - namespace GTE { - namespace MatrixHelper { - struct SinCosPair { - int16_t sin; - int16_t cos; - - static SinCosPair create_for(deg_t value) { - return SinCosPair{ - .sin = static_cast(::sin(value)), - .cos = static_cast(::cos(value)), - }; - } - }; - } - - static MATRIX Stack[StackSize]; - static MATRIX* FreeStackEntry = Stack; - - ROTMATRIX& multiply_matrix(const ROTMATRIX& m0, const ROTMATRIX& m1, ROTMATRIX& result) { - set_rot_matrix(m0); - - JabyEngine::GTE::ldclmv(m1, 0); - JabyEngine::GTE::rtir(); - JabyEngine::GTE::stclmv(result, 0); - - JabyEngine::GTE::ldclmv(m1, 1); - JabyEngine::GTE::rtir(); - JabyEngine::GTE::stclmv(result, 1); - - JabyEngine::GTE::ldclmv(m1, 2); - JabyEngine::GTE::rtir(); - JabyEngine::GTE::stclmv(result, 2); - - return result; - } - - void set_matrix(const MATRIX& matrix) { - set_rot_matrix(matrix.rotation); - set_trans_vector(matrix.transfer); - } - - MATRIX get_matrix() { - MATRIX matrix; - - get_rot_matrix(matrix.rotation); - get_trans_vector(matrix.transfer); - return matrix; - } - - void push_matrix() { - *FreeStackEntry = get_matrix(); - FreeStackEntry++; - } - - void push_matrix_and_set(const MATRIX& matrix) { - push_matrix(); - set_matrix(matrix); - } - - void pop_matrix() { - FreeStackEntry--; - set_matrix(*FreeStackEntry); - } - - MATRIX get_and_pop_matrix() { - const auto matrix = get_matrix(); - pop_matrix(); - - return matrix; - } - - ROTMATRIX ROTMATRIX :: rotated(deg_t x, deg_t y, deg_t z) { - using namespace MatrixHelper; - - const auto sincos_x = SinCosPair::create_for(x); - const auto sincos_y = SinCosPair::create_for(y); - const auto sincos_z = SinCosPair::create_for(z); - - auto rotX = ROTMATRIX::identity(); - rotX.matrix[1][1] = sincos_x.cos; rotX.matrix[1][2] = -sincos_x.sin; - rotX.matrix[2][1] = sincos_x.sin; rotX.matrix[2][2] = sincos_x.cos; - - auto rotY = ROTMATRIX::identity(); - rotY.matrix[0][0] = sincos_y.cos; rotY.matrix[0][2] = sincos_y.sin; - rotY.matrix[2][0] = -sincos_y.sin; rotY.matrix[2][2] = sincos_y.cos; - - auto rotZ = ROTMATRIX::identity(); - rotZ.matrix[0][0] = sincos_z.cos; rotZ.matrix[0][1] = -sincos_z.sin; - rotZ.matrix[1][0] = sincos_z.sin; rotZ.matrix[1][1] = sincos_z.cos; - - push_matrix(); - multiply_matrix(rotX, rotY, rotX); - multiply_matrix(rotX, rotZ, rotX); - pop_matrix(); - - return rotX; - } - } +#include + +static int32_t hisin(int32_t value) { + static constexpr int32_t qN = 13; + static constexpr int32_t qA = 12; + static constexpr int32_t B = 19900; + static constexpr int32_t C = 3516; + + const auto c = value << (30 - qN); // Semi-circle info into carry. + + value -= 1< cosine calc + value = value << (31 - qN); // Mask with PI + value = value >> (31 - qN); // Note: SIGNED shift! (to qN) + value = value*value >> (2*qN - 14); // x=x^2 To Q14 + + auto result = B - (value*C >> 14); // B - x^2*C + result = (1 << qA) - (value*result >> 16); // A - x^2*(B-x^2*C) + + return c >= 0 ? result : -result; +} + +gte_float sin(deg_t value) { + return gte_float{.raw = hisin(value.raw)}; +} + +gte_float cos(deg_t value) { + return gte_float{.raw = hisin(value.raw + (deg_t::full_circle/4))}; +} + +namespace JabyEngine { + namespace GTE { + namespace MatrixHelper { + struct SinCosPair { + int16_t sin; + int16_t cos; + + static SinCosPair create_for(deg_t value) { + return SinCosPair{ + .sin = static_cast(::sin(value)), + .cos = static_cast(::cos(value)), + }; + } + }; + } + + static MATRIX Stack[StackSize]; + static MATRIX* FreeStackEntry = Stack; + + ROTMATRIX& multiply_matrix(const ROTMATRIX& m0, const ROTMATRIX& m1, ROTMATRIX& result) { + set_rot_matrix(m0); + + JabyEngine::GTE::ldclmv(m1, 0); + JabyEngine::GTE::rtir(); + JabyEngine::GTE::stclmv(result, 0); + + JabyEngine::GTE::ldclmv(m1, 1); + JabyEngine::GTE::rtir(); + JabyEngine::GTE::stclmv(result, 1); + + JabyEngine::GTE::ldclmv(m1, 2); + JabyEngine::GTE::rtir(); + JabyEngine::GTE::stclmv(result, 2); + + return result; + } + + void set_matrix(const MATRIX& matrix) { + set_rot_matrix(matrix.rotation); + set_trans_vector(matrix.transfer); + } + + MATRIX get_matrix() { + MATRIX matrix; + + get_rot_matrix(matrix.rotation); + get_trans_vector(matrix.transfer); + return matrix; + } + + void push_matrix() { + *FreeStackEntry = get_matrix(); + FreeStackEntry++; + } + + void push_matrix_and_set(const MATRIX& matrix) { + push_matrix(); + set_matrix(matrix); + } + + void pop_matrix() { + FreeStackEntry--; + set_matrix(*FreeStackEntry); + } + + MATRIX get_and_pop_matrix() { + const auto matrix = get_matrix(); + pop_matrix(); + + return matrix; + } + + ROTMATRIX ROTMATRIX :: rotated(deg_t x, deg_t y, deg_t z) { + using namespace MatrixHelper; + + const auto sincos_x = SinCosPair::create_for(x); + const auto sincos_y = SinCosPair::create_for(y); + const auto sincos_z = SinCosPair::create_for(z); + + auto rotX = ROTMATRIX::identity(); + rotX.matrix[1][1] = sincos_x.cos; rotX.matrix[1][2] = -sincos_x.sin; + rotX.matrix[2][1] = sincos_x.sin; rotX.matrix[2][2] = sincos_x.cos; + + auto rotY = ROTMATRIX::identity(); + rotY.matrix[0][0] = sincos_y.cos; rotY.matrix[0][2] = sincos_y.sin; + rotY.matrix[2][0] = -sincos_y.sin; rotY.matrix[2][2] = sincos_y.cos; + + auto rotZ = ROTMATRIX::identity(); + rotZ.matrix[0][0] = sincos_z.cos; rotZ.matrix[0][1] = -sincos_z.sin; + rotZ.matrix[1][0] = sincos_z.sin; rotZ.matrix[1][1] = sincos_z.cos; + + push_matrix(); + multiply_matrix(rotX, rotY, rotX); + multiply_matrix(rotX, rotZ, rotX); + pop_matrix(); + + return rotX; + } + } } \ No newline at end of file diff --git a/src/Library/src/Periphery/periphery.cpp b/src/Library/src/Periphery/periphery.cpp index 82d4bf28..44579548 100644 --- a/src/Library/src/Periphery/periphery.cpp +++ b/src/Library/src/Periphery/periphery.cpp @@ -1,136 +1,136 @@ -#include "../../internal-include/periphery_internal.hpp" -#include -#include - -namespace JabyEngine { - namespace Periphery { - // Controllers are checked every alternating frame - static uint8_t cur_controller_port = 0; - RawController controller[PortCount][DeviceCount]; - - struct ControllerHelper { - static bool is_config(const RawController &cont) { - return (static_cast(cont.header.state) & 0xF); - } - - static void advance_config(RawController &cont) { - cont.header.state = static_cast((static_cast(cont.header.state) << 1)); - } - - static uint8_t* raw_device_data(RawController &cont) { - return reinterpret_cast(&cont.button.currentState); - } - }; - - static void set_config_command(RawController::State state, uint8_t (&header)[3], uint8_t (&data)[6]) { - static constexpr uint32_t CMDIDX = 1; - - switch(state) { - case RawController::State::EnterConfigMode: - static constexpr uint8_t EnterCFGModeCMD = 0x1; - - header[CMDIDX] = 0x43; - data[0] = EnterCFGModeCMD; - break; - - case RawController::State::LockAnalog: - static constexpr uint8_t valID = 0; - static constexpr uint8_t selID = 1; - - header[CMDIDX] = 0x44; - data[valID] = static_cast(LED::State::On); - data[selID] = static_cast(LED::Lock::On); - break; - - case RawController::State::UnlockRumble: - header[CMDIDX] = 0x4D; - - data[1] = 0x1; - for(int32_t n = 2; n < 6; n++) { - data[n] = 0xFF; - } - break; - - case RawController::State::ExitConfigMode: - header[CMDIDX] = 0x43; - break; - } - } - - static size_t send_data(const uint8_t* header, uint8_t* headerResponse, const uint8_t* data, uint8_t* response) { - const uint8_t *src = header; - uint8_t *dst = headerResponse; - size_t size = 3; - - for(size_t n = 0; n < size; n++) { - Periphery::send_byte(*src); - Periphery::acknowledge(); - *dst = Periphery::read_byte(); - - if(n == 2) { - const uint8_t id = headerResponse[1]; - size += (id == 0xFF) ? 0 : ((id & 0xF) << 1); - - src = data; - dst = response; - } - - else { - src++; - dst++; - } - - busy_loop(15); - } - return size; - } - - void query_controller() { - static constexpr auto TypeIDX = 1; - - SysCall::EnterCriticalSection(); - Periphery::connect_to(cur_controller_port); - for(uint32_t id = 0; id < Periphery::DeviceCount; id++) { - auto &cur_controller = controller[cur_controller_port][id]; - - uint8_t header[] = {static_cast((id + 1)), 0x42, 0x0}; - uint8_t data[] = {cur_controller.header.rumble0, cur_controller.header.rumble1, 0x0, 0x0, 0x0, 0x0}; - - // Can this move to the if?? - set_config_command(cur_controller.header.state, header, data); - if(ControllerHelper::is_config(cur_controller)) { - send_data(header, header, data, data); - ControllerHelper::advance_config(cur_controller); - } - - else { - cur_controller.button.exchange_state(); - - send_data(header, header, data, ControllerHelper::raw_device_data(cur_controller)); - const bool isValidController = (header[TypeIDX] != 0xFF); - - if(header[TypeIDX] != cur_controller.header.type) { - cur_controller.header.type = header[TypeIDX]; - cur_controller.header.state = isValidController ? RawController::State::EnterConfigMode : RawController::State::Disconnected; - - /*if(!isValidController) - { - printf("Disconnected!\n"); - } - - else - { - printf("ID: 0x%02X 0x%04X\n", header[TypeIDX], contData.button); - }*/ - } - } - } - Periphery::close_connection(); - - if(Configuration::Periphery::include_portB()) { - cur_controller_port ^= 0x1; - } - SysCall::ExitCriticalSection(); - } - } +#include "../../internal-include/periphery_internal.hpp" +#include +#include + +namespace JabyEngine { + namespace Periphery { + // Controllers are checked every alternating frame + static uint8_t cur_controller_port = 0; + RawController controller[PortCount][DeviceCount]; + + struct ControllerHelper { + static bool is_config(const RawController &cont) { + return (static_cast(cont.header.state) & 0xF); + } + + static void advance_config(RawController &cont) { + cont.header.state = static_cast((static_cast(cont.header.state) << 1)); + } + + static uint8_t* raw_device_data(RawController &cont) { + return reinterpret_cast(&cont.button.currentState); + } + }; + + static void set_config_command(RawController::State state, uint8_t (&header)[3], uint8_t (&data)[6]) { + static constexpr uint32_t CMDIDX = 1; + + switch(state) { + case RawController::State::EnterConfigMode: + static constexpr uint8_t EnterCFGModeCMD = 0x1; + + header[CMDIDX] = 0x43; + data[0] = EnterCFGModeCMD; + break; + + case RawController::State::LockAnalog: + static constexpr uint8_t valID = 0; + static constexpr uint8_t selID = 1; + + header[CMDIDX] = 0x44; + data[valID] = static_cast(LED::State::On); + data[selID] = static_cast(LED::Lock::On); + break; + + case RawController::State::UnlockRumble: + header[CMDIDX] = 0x4D; + + data[1] = 0x1; + for(int32_t n = 2; n < 6; n++) { + data[n] = 0xFF; + } + break; + + case RawController::State::ExitConfigMode: + header[CMDIDX] = 0x43; + break; + } + } + + static size_t send_data(const uint8_t* header, uint8_t* headerResponse, const uint8_t* data, uint8_t* response) { + const uint8_t *src = header; + uint8_t *dst = headerResponse; + size_t size = 3; + + for(size_t n = 0; n < size; n++) { + Periphery::send_byte(*src); + Periphery::acknowledge(); + *dst = Periphery::read_byte(); + + if(n == 2) { + const uint8_t id = headerResponse[1]; + size += (id == 0xFF) ? 0 : ((id & 0xF) << 1); + + src = data; + dst = response; + } + + else { + src++; + dst++; + } + + busy_loop(15); + } + return size; + } + + void query_controller() { + static constexpr auto TypeIDX = 1; + + SysCall::EnterCriticalSection(); + Periphery::connect_to(cur_controller_port); + for(uint32_t id = 0; id < Periphery::DeviceCount; id++) { + auto &cur_controller = controller[cur_controller_port][id]; + + uint8_t header[] = {static_cast((id + 1)), 0x42, 0x0}; + uint8_t data[] = {cur_controller.header.rumble0, cur_controller.header.rumble1, 0x0, 0x0, 0x0, 0x0}; + + // Can this move to the if?? + set_config_command(cur_controller.header.state, header, data); + if(ControllerHelper::is_config(cur_controller)) { + send_data(header, header, data, data); + ControllerHelper::advance_config(cur_controller); + } + + else { + cur_controller.button.exchange_state(); + + send_data(header, header, data, ControllerHelper::raw_device_data(cur_controller)); + const bool isValidController = (header[TypeIDX] != 0xFF); + + if(header[TypeIDX] != cur_controller.header.type) { + cur_controller.header.type = header[TypeIDX]; + cur_controller.header.state = isValidController ? RawController::State::EnterConfigMode : RawController::State::Disconnected; + + /*if(!isValidController) + { + printf("Disconnected!\n"); + } + + else + { + printf("ID: 0x%02X 0x%04X\n", header[TypeIDX], contData.button); + }*/ + } + } + } + Periphery::close_connection(); + + if(Configuration::Periphery::include_portB()) { + cur_controller_port ^= 0x1; + } + SysCall::ExitCriticalSection(); + } + } } \ No newline at end of file diff --git a/src/Library/src/SPU/spu.cpp b/src/Library/src/SPU/spu.cpp index a8ddc2ac..61a88170 100644 --- a/src/Library/src/SPU/spu.cpp +++ b/src/Library/src/SPU/spu.cpp @@ -1,31 +1,31 @@ -#include "../../internal-include/SPU/spu_internal.hpp" -#include "../../internal-include/SPU/spu_mmu.hpp" -#include -#include -#include - -#include - -namespace JabyEngine { - namespace SPU { - SRAMAdr Voice :: allocate(size_t size) { - Voice::stop(); - const auto voice_id = Voice::get_id(); - const auto adr = SRAMAdr{static_cast(reinterpret_cast(SPU_MMU::allocate(voice_id, size)))}; - - SPU_IO::Voice[voice_id].adr.write(adr); - return adr; - } - - SRAMAdr Voice :: allocate(SPU_IO_Values::SampleRate frequency, size_t size) { - const auto result = Voice::allocate(size); - Voice::set_sample_rate(frequency); - return result; - } - - void Voice :: deallocate() { - Voice::stop(); - SPU_MMU::deallocate(Voice::get_id()); - } - } +#include "../../internal-include/SPU/spu_internal.hpp" +#include "../../internal-include/SPU/spu_mmu.hpp" +#include +#include +#include + +#include + +namespace JabyEngine { + namespace SPU { + SRAMAdr Voice :: allocate(size_t size) { + Voice::stop(); + const auto voice_id = Voice::get_id(); + const auto adr = SRAMAdr{static_cast(reinterpret_cast(SPU_MMU::allocate(voice_id, size)))}; + + SPU_IO::Voice[voice_id].adr.write(adr); + return adr; + } + + SRAMAdr Voice :: allocate(SPU_IO_Values::SampleRate frequency, size_t size) { + const auto result = Voice::allocate(size); + Voice::set_sample_rate(frequency); + return result; + } + + void Voice :: deallocate() { + Voice::stop(); + SPU_MMU::deallocate(Voice::get_id()); + } + } } \ No newline at end of file diff --git a/src/Library/src/SPU/spu_mmu.cpp b/src/Library/src/SPU/spu_mmu.cpp index 7692ee75..e6628fdd 100644 --- a/src/Library/src/SPU/spu_mmu.cpp +++ b/src/Library/src/SPU/spu_mmu.cpp @@ -1,136 +1,136 @@ -#include "../../internal-include/SPU/spu_mmu.hpp" -#include -#include -#include -#include -#include -#ifdef __DEBUG_SPU_MMU__ - #include -#endif // __DEBUG_SPU_MMU__ - -namespace JabyEngine { - namespace SPU_MMU { - namespace SPU_MemoryMap = SPU_IO_Values::MemoryMap; - - struct SPUMemory { - const uint8_t* adr; - size_t size; - - static SPUMemory create(size_t size) { - return SPUMemory{.adr = reinterpret_cast(SPU_MemoryMap::ADPCM), .size = size}; - } - - constexpr void clear() { - this->adr = nullptr; - this->size = 0; - } - - constexpr const uint8_t* get_end_adr() const { - return (this->adr + this->size); - } - - constexpr bool is_free() const { - return this->adr == nullptr; - } - - constexpr bool intersects(const SPUMemory& other) const { - const auto* min = max_of(this->adr, other.adr); - const auto* max = min_of(this->get_end_adr(), other.get_end_adr()); - return min < max; - } - }; - - struct AllocatedVoice { - SPUMemory memory; - AllocatedVoice* next_entry; - }; - - struct VoiceManager { - struct Iterator { - AllocatedVoice* *prev_voice; - AllocatedVoice* current_voice; - - void next() { - this->prev_voice = &this->current_voice->next_entry; - this->current_voice = this->current_voice->next_entry; - } - - bool has_next() const { - return this->current_voice; - } - - operator bool() const { - return Iterator::has_next(); - } - }; - - AllocatedVoice allocated_voice_buffer[SPU_IO::VoiceCount + SPU_IO::ReverbCount] = {0}; - AllocatedVoice* first_allocated_voice = nullptr; - - Iterator iterator() { - return Iterator{.prev_voice = &this->first_allocated_voice, .current_voice = this->first_allocated_voice}; - } - - AllocatedVoice& get_voice(uint8_t id) { - return this->allocated_voice_buffer[id]; - } - }; - - static VoiceManager voice_mgr; - static const uint8_t* reverb_adr = reinterpret_cast(SPU_MemoryMap::End); - // ^ change this to allocate reverb - - using MemoryFoundCallback = const uint8_t* (AllocatedVoice& new_entry, AllocatedVoice* &prev_entry, AllocatedVoice* next_entry); - - static const uint8_t* verify_and_add(AllocatedVoice& new_entry, AllocatedVoice* &prev_entry, AllocatedVoice* next_entry) { - if(new_entry.memory.adr >= reverb_adr) { - return nullptr; - } - - prev_entry = &new_entry; - new_entry.next_entry = next_entry; - return new_entry.memory.adr; - } - - static const uint8_t* find_first_fit(AllocatedVoice &new_entry, MemoryFoundCallback memory_found) { - auto iterator = voice_mgr.iterator(); - while(iterator) { - if(!iterator.current_voice->memory.intersects(new_entry.memory)) { - break; - } - new_entry.memory.adr = iterator.current_voice->memory.get_end_adr(); - iterator.next(); - } - - return memory_found(new_entry, *iterator.prev_voice, iterator.current_voice); - } - - const uint8_t* allocate(uint8_t voice, size_t size) { - auto& voice_entry = voice_mgr.get_voice(voice); - if(!voice_entry.memory.is_free()) { - deallocate(voice); - } - - voice_entry.memory = SPUMemory::create(size); - const auto* mem_adr = find_first_fit(voice_entry, verify_and_add); - #ifdef __DEBUG_SPU_MMU__ - printf("SPU: Allocated %i @0x%p to 0x%p (%i bytes)\n", voice, mem_adr, (mem_adr + size), size); - #endif // __DEBUG_SPU_MMU__ - return mem_adr; - } - - void deallocate(uint8_t voice) { - auto* voice_adr = &voice_mgr.get_voice(voice); - auto iterator = voice_mgr.iterator(); - - voice_adr->memory.clear(); - while(iterator) { - if(iterator.current_voice == voice_adr) { - *iterator.prev_voice = voice_adr->next_entry; - break; - } - iterator.next(); - } - } - } +#include "../../internal-include/SPU/spu_mmu.hpp" +#include +#include +#include +#include +#include +#ifdef __DEBUG_SPU_MMU__ + #include +#endif // __DEBUG_SPU_MMU__ + +namespace JabyEngine { + namespace SPU_MMU { + namespace SPU_MemoryMap = SPU_IO_Values::MemoryMap; + + struct SPUMemory { + const uint8_t* adr; + size_t size; + + static SPUMemory create(size_t size) { + return SPUMemory{.adr = reinterpret_cast(SPU_MemoryMap::ADPCM), .size = size}; + } + + constexpr void clear() { + this->adr = nullptr; + this->size = 0; + } + + constexpr const uint8_t* get_end_adr() const { + return (this->adr + this->size); + } + + constexpr bool is_free() const { + return this->adr == nullptr; + } + + constexpr bool intersects(const SPUMemory& other) const { + const auto* min = max_of(this->adr, other.adr); + const auto* max = min_of(this->get_end_adr(), other.get_end_adr()); + return min < max; + } + }; + + struct AllocatedVoice { + SPUMemory memory; + AllocatedVoice* next_entry; + }; + + struct VoiceManager { + struct Iterator { + AllocatedVoice* *prev_voice; + AllocatedVoice* current_voice; + + void next() { + this->prev_voice = &this->current_voice->next_entry; + this->current_voice = this->current_voice->next_entry; + } + + bool has_next() const { + return this->current_voice; + } + + operator bool() const { + return Iterator::has_next(); + } + }; + + AllocatedVoice allocated_voice_buffer[SPU_IO::VoiceCount + SPU_IO::ReverbCount] = {0}; + AllocatedVoice* first_allocated_voice = nullptr; + + Iterator iterator() { + return Iterator{.prev_voice = &this->first_allocated_voice, .current_voice = this->first_allocated_voice}; + } + + AllocatedVoice& get_voice(uint8_t id) { + return this->allocated_voice_buffer[id]; + } + }; + + static VoiceManager voice_mgr; + static const uint8_t* reverb_adr = reinterpret_cast(SPU_MemoryMap::End); + // ^ change this to allocate reverb + + using MemoryFoundCallback = const uint8_t* (AllocatedVoice& new_entry, AllocatedVoice* &prev_entry, AllocatedVoice* next_entry); + + static const uint8_t* verify_and_add(AllocatedVoice& new_entry, AllocatedVoice* &prev_entry, AllocatedVoice* next_entry) { + if(new_entry.memory.adr >= reverb_adr) { + return nullptr; + } + + prev_entry = &new_entry; + new_entry.next_entry = next_entry; + return new_entry.memory.adr; + } + + static const uint8_t* find_first_fit(AllocatedVoice &new_entry, MemoryFoundCallback memory_found) { + auto iterator = voice_mgr.iterator(); + while(iterator) { + if(!iterator.current_voice->memory.intersects(new_entry.memory)) { + break; + } + new_entry.memory.adr = iterator.current_voice->memory.get_end_adr(); + iterator.next(); + } + + return memory_found(new_entry, *iterator.prev_voice, iterator.current_voice); + } + + const uint8_t* allocate(uint8_t voice, size_t size) { + auto& voice_entry = voice_mgr.get_voice(voice); + if(!voice_entry.memory.is_free()) { + deallocate(voice); + } + + voice_entry.memory = SPUMemory::create(size); + const auto* mem_adr = find_first_fit(voice_entry, verify_and_add); + #ifdef __DEBUG_SPU_MMU__ + printf("SPU: Allocated %i @0x%p to 0x%p (%i bytes)\n", voice, mem_adr, (mem_adr + size), size); + #endif // __DEBUG_SPU_MMU__ + return mem_adr; + } + + void deallocate(uint8_t voice) { + auto* voice_adr = &voice_mgr.get_voice(voice); + auto iterator = voice_mgr.iterator(); + + voice_adr->memory.clear(); + while(iterator) { + if(iterator.current_voice == voice_adr) { + *iterator.prev_voice = voice_adr->next_entry; + break; + } + iterator.next(); + } + } + } } \ No newline at end of file diff --git a/src/Library/src/System/callbacks.cxx b/src/Library/src/System/callbacks.cxx index 5a8f7f4a..0aa5b2f3 100644 --- a/src/Library/src/System/callbacks.cxx +++ b/src/Library/src/System/callbacks.cxx @@ -1,44 +1,44 @@ -#include "../../internal-include/System/callbacks_internal.hpp" -#include "../../internal-include/CD/cd_internal.hpp" -#include - -namespace JabyEngine { - namespace Callback { - // Marked deprecated currently - /*using Function = VSyncCallback::Function; - Function VSyncCallback :: callback = nullptr;*/ - - namespace internal { - namespace VSync { - SysCall::ThreadHandle thread_handle = 0; - uint32_t stack[StackSize] = {0}; - - void routine() { - while(true) { - // Marked deprecated currently - /*if(VSyncCallback::callback) { - VSyncCallback::callback(); - }*/ - SysCall::ChangeThread(MainThread::Handle); - } - } - } - - namespace CD { - namespace CD_IRQ = JabyEngine::CD::internal::IRQ; - - SysCall::ThreadHandle thread_handle = 0; - uint32_t stack[StackSize]; - - void routine(uint32_t irq) { - while(true) { - const auto old_status = CD_IO::IndexStatus.read(); - CD_IRQ::process(irq); - CD_IO::IndexStatus.write(old_status); - irq = Callback::internal::CD::resume(); - } - } - } - } - } +#include "../../internal-include/System/callbacks_internal.hpp" +#include "../../internal-include/CD/cd_internal.hpp" +#include + +namespace JabyEngine { + namespace Callback { + // Marked deprecated currently + /*using Function = VSyncCallback::Function; + Function VSyncCallback :: callback = nullptr;*/ + + namespace internal { + namespace VSync { + SysCall::ThreadHandle thread_handle = 0; + uint32_t stack[StackSize] = {0}; + + void routine() { + while(true) { + // Marked deprecated currently + /*if(VSyncCallback::callback) { + VSyncCallback::callback(); + }*/ + SysCall::ChangeThread(MainThread::Handle); + } + } + } + + namespace CD { + namespace CD_IRQ = JabyEngine::CD::internal::IRQ; + + SysCall::ThreadHandle thread_handle = 0; + uint32_t stack[StackSize]; + + void routine(uint32_t irq) { + while(true) { + const auto old_status = CD_IO::IndexStatus.read(); + CD_IRQ::process(irq); + CD_IO::IndexStatus.write(old_status); + irq = Callback::internal::CD::resume(); + } + } + } + } + } } \ No newline at end of file diff --git a/src/Library/src/System/string.cpp b/src/Library/src/System/string.cpp index fa264af1..32c2f0f0 100644 --- a/src/Library/src/System/string.cpp +++ b/src/Library/src/System/string.cpp @@ -1,63 +1,63 @@ -#include - -int strncmp(const char* s1, const char* s2, size_t n) { - if(n == 0) { - return 0; - } - - do { - if(*s1 != *s2++) { - return (*(unsigned char *)s1 - *(unsigned char *)--s2); - } - - if(*s1++ == 0) { - break; - } - } while(--n != 0); - return 0; -} - -size_t strlen(const char *str) { - const char* end = str; - - for(; *end; ++end); - return(end - str); -} - -template -static void* core_memset(T* dst, int val, size_t &len) { - while(len >= sizeof(T)) { - *dst++ = val; - len -= sizeof(T); - } - - return dst; -} - -static void* simple_memset(void* dest, int val, size_t len) { - core_memset(static_cast(dest), val, len); - return dest; -} - -static void* cplx_memset(void* dst, int val, size_t len) { - void*const org_dst = dst; - - if(reinterpret_cast(dst) & 0x2 == 0) { - dst = core_memset(static_cast(dst), val, len); - } - - if(reinterpret_cast(dst) & 0x1 == 0) { - dst = core_memset(static_cast(dst), val, len); - } - - if(len > 0) { - simple_memset(dst, val, len); - } - return org_dst; -} - -extern "C" { - void* memset(void* dest, int val, size_t len) { - return simple_memset(dest, val, len); - } +#include + +int strncmp(const char* s1, const char* s2, size_t n) { + if(n == 0) { + return 0; + } + + do { + if(*s1 != *s2++) { + return (*(unsigned char *)s1 - *(unsigned char *)--s2); + } + + if(*s1++ == 0) { + break; + } + } while(--n != 0); + return 0; +} + +size_t strlen(const char *str) { + const char* end = str; + + for(; *end; ++end); + return(end - str); +} + +template +static void* core_memset(T* dst, int val, size_t &len) { + while(len >= sizeof(T)) { + *dst++ = val; + len -= sizeof(T); + } + + return dst; +} + +static void* simple_memset(void* dest, int val, size_t len) { + core_memset(static_cast(dest), val, len); + return dest; +} + +static void* cplx_memset(void* dst, int val, size_t len) { + void*const org_dst = dst; + + if(reinterpret_cast(dst) & 0x2 == 0) { + dst = core_memset(static_cast(dst), val, len); + } + + if(reinterpret_cast(dst) & 0x1 == 0) { + dst = core_memset(static_cast(dst), val, len); + } + + if(len > 0) { + simple_memset(dst, val, len); + } + return org_dst; +} + +extern "C" { + void* memset(void* dest, int val, size_t len) { + return simple_memset(dest, val, len); + } } \ No newline at end of file diff --git a/src/Library/src/System/syscall.cpp b/src/Library/src/System/syscall.cpp index e28d2fad..d2d05c85 100644 --- a/src/Library/src/System/syscall.cpp +++ b/src/Library/src/System/syscall.cpp @@ -1,8 +1,8 @@ -#include -#include - -namespace JabyEngine { - namespace BIOS { - const Version version = {0}; - } +#include +#include + +namespace JabyEngine { + namespace BIOS { + const Version version = {0}; + } } \ No newline at end of file diff --git a/src/Library/src/Timer/high_res_timer.cpp b/src/Library/src/Timer/high_res_timer.cpp index 2d9436cd..2af0aefb 100644 --- a/src/Library/src/Timer/high_res_timer.cpp +++ b/src/Library/src/Timer/high_res_timer.cpp @@ -1,27 +1,27 @@ -#include -#include -#include - -namespace JabyEngine { - volatile uint16_t HighResTime :: global_counter_10ms = 0; - - namespace Timer { - static SysCall::InterruptVerifierResult interrupt_verifier() { - if(Interrupt::is_irq(Interrupt::Timer2)) { - Interrupt::ack_irq(Interrupt::Timer2); - return SysCall::InterruptVerifierResult::ExecuteHandler; - } - - else { - return SysCall::InterruptVerifierResult::SkipHandler; - } - } - - static void interrupt_handler(uint32_t) { - HighResTime::global_counter_10ms = HighResTime::global_counter_10ms + 1; - SysCall::ReturnFromException(); - } - - auto irq_callback = SysCall::InterruptCallback::from(interrupt_verifier, interrupt_handler); - } +#include +#include +#include + +namespace JabyEngine { + volatile uint16_t HighResTime :: global_counter_10ms = 0; + + namespace Timer { + static SysCall::InterruptVerifierResult interrupt_verifier() { + if(Interrupt::is_irq(Interrupt::Timer2)) { + Interrupt::ack_irq(Interrupt::Timer2); + return SysCall::InterruptVerifierResult::ExecuteHandler; + } + + else { + return SysCall::InterruptVerifierResult::SkipHandler; + } + } + + static void interrupt_handler(uint32_t) { + HighResTime::global_counter_10ms = HighResTime::global_counter_10ms + 1; + SysCall::ReturnFromException(); + } + + auto irq_callback = SysCall::InterruptCallback::from(interrupt_verifier, interrupt_handler); + } } \ No newline at end of file diff --git a/src/Library/src/syscall_printf.s b/src/Library/src/syscall_printf.s index 57322d6e..71e9cd26 100644 --- a/src/Library/src/syscall_printf.s +++ b/src/Library/src/syscall_printf.s @@ -1,11 +1,11 @@ - .set push - .set noreorder - .section .text, "ax", @progbits - .align 2 - .global _ZN10JabyEngine7SysCall6printfEPKcz - .type _ZN10JabyEngine7SysCall6printfEPKcz, @function - -_ZN10JabyEngine7SysCall6printfEPKcz: - li $t2, 0xa0 - jr $t2 - li $t1, 0x3f + .set push + .set noreorder + .section .text, "ax", @progbits + .align 2 + .global _ZN10JabyEngine7SysCall6printfEPKcz + .type _ZN10JabyEngine7SysCall6printfEPKcz, @function + +_ZN10JabyEngine7SysCall6printfEPKcz: + li $t2, 0xa0 + jr $t2 + li $t1, 0x3f diff --git a/src/Tools/Common.mk b/src/Tools/Common.mk index 25fca883..c8293407 100644 --- a/src/Tools/Common.mk +++ b/src/Tools/Common.mk @@ -1,34 +1,34 @@ -BUILD_PROFILE ?= debug -CARGO_CMD ?= build -WINDOWS_TARGET ?= x86_64-pc-windows-gnu -UNIX_TARGET ?= x86_64-unknown-linux-gnu - -WINDOWS_ARTIFACT = ./target/$(WINDOWS_TARGET)/$(BUILD_PROFILE)/$(ARTIFACT).exe -UNIX_ARTIFACT = ./target/$(UNIX_TARGET)/$(BUILD_PROFILE)/$(ARTIFACT) - -define cp_artifact - $(if $(findstring build,$(CARGO_CMD)), - @mkdir -p $(dir $(1)) - @cp $(1) $(2) - ) -endef - -define cargo_windows_default - $(if $(findstring upgrade,$(CARGO_CMD)), - cargo $(CARGO_CMD) --$(BUILD_PROFILE), - - cargo $(CARGO_CMD) --$(BUILD_PROFILE) --target=$(WINDOWS_TARGET) - $(call cp_artifact,$(WINDOWS_ARTIFACT), ../../../bin/$(ARTIFACT).exe) - ) -endef - -define cargo_unix_default - $(if $(findstring upgrade,$(CARGO_CMD)), - cargo $(CARGO_CMD) --$(BUILD_PROFILE), - - cargo $(CARGO_CMD) --$(BUILD_PROFILE) --target=$(UNIX_TARGET) - $(call cp_artifact,$(UNIX_ARTIFACT), ../../../bin/$(ARTIFACT)) - ) -endef - +BUILD_PROFILE ?= debug +CARGO_CMD ?= build +WINDOWS_TARGET ?= x86_64-pc-windows-gnu +UNIX_TARGET ?= x86_64-unknown-linux-gnu + +WINDOWS_ARTIFACT = ./target/$(WINDOWS_TARGET)/$(BUILD_PROFILE)/$(ARTIFACT).exe +UNIX_ARTIFACT = ./target/$(UNIX_TARGET)/$(BUILD_PROFILE)/$(ARTIFACT) + +define cp_artifact + $(if $(findstring build,$(CARGO_CMD)), + @mkdir -p $(dir $(1)) + @cp $(1) $(2) + ) +endef + +define cargo_windows_default + $(if $(findstring upgrade,$(CARGO_CMD)), + cargo $(CARGO_CMD) --$(BUILD_PROFILE), + + cargo $(CARGO_CMD) --$(BUILD_PROFILE) --target=$(WINDOWS_TARGET) + $(call cp_artifact,$(WINDOWS_ARTIFACT), ../../../bin/$(ARTIFACT).exe) + ) +endef + +define cargo_unix_default + $(if $(findstring upgrade,$(CARGO_CMD)), + cargo $(CARGO_CMD) --$(BUILD_PROFILE), + + cargo $(CARGO_CMD) --$(BUILD_PROFILE) --target=$(UNIX_TARGET) + $(call cp_artifact,$(UNIX_ARTIFACT), ../../../bin/$(ARTIFACT)) + ) +endef + # Windows build requires "rustup target add x86_64-pc-windows-gnu" and "sudo apt-get install mingw-w64" \ No newline at end of file diff --git a/src/Tools/Makefile b/src/Tools/Makefile index e78b7f49..74695256 100644 --- a/src/Tools/Makefile +++ b/src/Tools/Makefile @@ -1,9 +1,9 @@ -SUPPORT_PROJECTS = cdtypes tool_helper -PROJECTS = cpp_out psxfileconv mkoverlay psxcdgen_ex psxreadmap wslpath -.PHONY: $(PROJECTS) - -$(foreach var,$(PROJECTS),$(var)): - $(MAKE) -C ./$@ $(MAKECMDGOALS) - -all-windows: $(PROJECTS) +SUPPORT_PROJECTS = cdtypes tool_helper +PROJECTS = cpp_out psxfileconv mkoverlay psxcdgen_ex psxreadmap wslpath +.PHONY: $(PROJECTS) + +$(foreach var,$(PROJECTS),$(var)): + $(MAKE) -C ./$@ $(MAKECMDGOALS) + +all-windows: $(PROJECTS) all: $(PROJECTS) \ No newline at end of file diff --git a/src/Tools/Tests/ISO_Planschbecken.xml b/src/Tools/Tests/ISO_Planschbecken.xml index 3f9e3fdb..a7a9448d 100644 --- a/src/Tools/Tests/ISO_Planschbecken.xml +++ b/src/Tools/Tests/ISO_Planschbecken.xml @@ -1,20 +1,20 @@ - - - Jaby Wuff - - - - ../Tests/Test.mk - ../Tests/Test.mk - ../Tests/Test.mk - ../Tests/Test.mk - ../Tests/ISO_Planschbecken.xml - - ../Tests/ISO_Planschbecken.xml - - - ../../../../JabyAdventure/application/bin/PSX-release/Overlay.main_area - + + + Jaby Wuff + + + + ../Tests/Test.mk + ../Tests/Test.mk + ../Tests/Test.mk + ../Tests/Test.mk + ../Tests/ISO_Planschbecken.xml + + ../Tests/ISO_Planschbecken.xml + + + ../../../../JabyAdventure/application/bin/PSX-release/Overlay.main_area + \ No newline at end of file diff --git a/src/Tools/Tools.code-workspace b/src/Tools/Tools.code-workspace index 0ce65be7..825be1e4 100644 --- a/src/Tools/Tools.code-workspace +++ b/src/Tools/Tools.code-workspace @@ -1,58 +1,58 @@ -{ - "folders": [ - { - "path": "." - } - ], - "settings": { - "cargo_task": [ - "./ all!All", - "cpp_out all!cpp_out", - "mkoverlay all!mkoverlay", - "psxcdgen_ex all!psxcdgen_ex", - "psxcdread all!psxcdread", - "psxfileconv all!psxfileconv", - "psxreadmap all!psxreadmap", - "wslpath all!wslpath", - ] - }, - "tasks": { - "version": "2.0.0", - "tasks": [ - { - "label": "cargo", - "type": "shell", - "group": { - "kind": "build" - }, - "command": "../../scripts/podman_jaby_engine.sh ../../:src/Tools make -C ${input:linux_cargo_task} CARGO_CMD=${input:cargo cmd} BUILD_PROFILE=${input:build cfg}", - "problemMatcher": [] - } - ], - "inputs": [ - { - "id": "linux_cargo_task", - "type": "command", - "command": "shellCommand.execute", - "args": { - "command": "echo ${config:cargo_task} | tr , \\\\n", - "fieldSeparator": "!" - } - }, - { - "id": "build cfg", - "type": "pickString", - "options": ["debug", "release", "compatible", "incompatible"], - "default": "release", - "description": "build configuration" - }, - { - "id": "cargo cmd", - "type":"pickString", - "options": ["build", "check", "upgrade", "clean", "run", "tree"], - "default": "build", - "description": "cargo command to run" - } - ] - } +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "cargo_task": [ + "./ all!All", + "cpp_out all!cpp_out", + "mkoverlay all!mkoverlay", + "psxcdgen_ex all!psxcdgen_ex", + "psxcdread all!psxcdread", + "psxfileconv all!psxfileconv", + "psxreadmap all!psxreadmap", + "wslpath all!wslpath", + ] + }, + "tasks": { + "version": "2.0.0", + "tasks": [ + { + "label": "cargo", + "type": "shell", + "group": { + "kind": "build" + }, + "command": "../../scripts/podman_jaby_engine.sh ../../:src/Tools make -C ${input:linux_cargo_task} CARGO_CMD=${input:cargo cmd} BUILD_PROFILE=${input:build cfg}", + "problemMatcher": [] + } + ], + "inputs": [ + { + "id": "linux_cargo_task", + "type": "command", + "command": "shellCommand.execute", + "args": { + "command": "echo ${config:cargo_task} | tr , \\\\n", + "fieldSeparator": "!" + } + }, + { + "id": "build cfg", + "type": "pickString", + "options": ["debug", "release", "compatible", "incompatible"], + "default": "release", + "description": "build configuration" + }, + { + "id": "cargo cmd", + "type":"pickString", + "options": ["build", "check", "upgrade", "clean", "run", "tree"], + "default": "build", + "description": "cargo command to run" + } + ] + } } \ No newline at end of file diff --git a/src/Tools/cdtypes/Makefile b/src/Tools/cdtypes/Makefile index d2909708..5ef54cc6 100644 --- a/src/Tools/cdtypes/Makefile +++ b/src/Tools/cdtypes/Makefile @@ -1,13 +1,13 @@ -include ../Common.mk - -ARTIFACT = cdtypes - -.PHONY: $(WINDOWS_ARTIFACT) $(UNIX_ARTIFACT) -$(WINDOWS_ARTIFACT): - $(call cargo_windows_default) - -$(UNIX_ARTIFACT): - $(call cargo_unix_default) - -all-windows: $(WINDOWS_ARTIFACT) +include ../Common.mk + +ARTIFACT = cdtypes + +.PHONY: $(WINDOWS_ARTIFACT) $(UNIX_ARTIFACT) +$(WINDOWS_ARTIFACT): + $(call cargo_windows_default) + +$(UNIX_ARTIFACT): + $(call cargo_unix_default) + +all-windows: $(WINDOWS_ARTIFACT) all: $(UNIX_ARTIFACT) \ No newline at end of file diff --git a/src/Tools/cpp_out/Makefile b/src/Tools/cpp_out/Makefile index d9336e6c..9b285173 100644 --- a/src/Tools/cpp_out/Makefile +++ b/src/Tools/cpp_out/Makefile @@ -1,13 +1,13 @@ -include ../Common.mk - -ARTIFACT = cpp_out - -.PHONY: $(WINDOWS_ARTIFACT) $(UNIX_ARTIFACT) -$(WINDOWS_ARTIFACT): - $(call cargo_windows_default) - -$(UNIX_ARTIFACT): - $(call cargo_unix_default) - -all-windows: $(WINDOWS_ARTIFACT) +include ../Common.mk + +ARTIFACT = cpp_out + +.PHONY: $(WINDOWS_ARTIFACT) $(UNIX_ARTIFACT) +$(WINDOWS_ARTIFACT): + $(call cargo_windows_default) + +$(UNIX_ARTIFACT): + $(call cargo_unix_default) + +all-windows: $(WINDOWS_ARTIFACT) all: $(UNIX_ARTIFACT) \ No newline at end of file diff --git a/src/Tools/cpp_out/src/main.rs b/src/Tools/cpp_out/src/main.rs index 9d4063ed..db756662 100644 --- a/src/Tools/cpp_out/src/main.rs +++ b/src/Tools/cpp_out/src/main.rs @@ -1,52 +1,52 @@ -use clap::{Parser}; -use cpp_out::{Configuration, Error, FileType}; -use std::path::PathBuf; -use tool_helper::exit_with_error; - -#[derive(Parser)] -#[clap(about = "Output a file content or stdin to a c++ header/source file", long_about = None)] -struct CommandLine { - #[clap(value_parser)] - input_file: Option, - - #[clap(short='n', long="name")] - data_name: String, - - #[clap(short='o')] - output_file: PathBuf, -} - -fn configurate(cmd: &mut CommandLine) -> Result { - let file_name = tool_helper::get_file_name_from_path_buf(&cmd.output_file, "output")?; - let extension = tool_helper::os_str_to_string(Error::ok_or_new(cmd.output_file.extension(), ||"File extension required for output".to_owned())?, "extension")?.to_ascii_lowercase(); - let file_type = Error::ok_or_new({ - match extension.as_ref() { - "h" => Some(FileType::CHeader), - "hpp" => Some(FileType::CPPHeader), - "c" => Some(FileType::CSource), - "cpp" => Some(FileType::CPPSource), - _ => None - } - }, ||format!("{} unkown file extension", extension))?; - - Ok(Configuration{file_name, data_name: std::mem::take(&mut cmd.data_name), line_feed: cpp_out::LineFeed::Windows, file_type}) -} - -fn run_main(mut cmd: CommandLine) -> Result<(), Error> { - let cfg = configurate(&mut cmd)?; - let input = tool_helper::open_input(&cmd.input_file)?; - let output = tool_helper::open_output(&Some(cmd.output_file))?; - - return cpp_out::convert(cfg, input, output); -} - -fn main() { - match CommandLine::try_parse() { - Ok(cmd) => { - if let Err(error) = run_main(cmd) { - exit_with_error(error) - } - }, - Err(error) => println!("{}", error) - } +use clap::{Parser}; +use cpp_out::{Configuration, Error, FileType}; +use std::path::PathBuf; +use tool_helper::exit_with_error; + +#[derive(Parser)] +#[clap(about = "Output a file content or stdin to a c++ header/source file", long_about = None)] +struct CommandLine { + #[clap(value_parser)] + input_file: Option, + + #[clap(short='n', long="name")] + data_name: String, + + #[clap(short='o')] + output_file: PathBuf, +} + +fn configurate(cmd: &mut CommandLine) -> Result { + let file_name = tool_helper::get_file_name_from_path_buf(&cmd.output_file, "output")?; + let extension = tool_helper::os_str_to_string(Error::ok_or_new(cmd.output_file.extension(), ||"File extension required for output".to_owned())?, "extension")?.to_ascii_lowercase(); + let file_type = Error::ok_or_new({ + match extension.as_ref() { + "h" => Some(FileType::CHeader), + "hpp" => Some(FileType::CPPHeader), + "c" => Some(FileType::CSource), + "cpp" => Some(FileType::CPPSource), + _ => None + } + }, ||format!("{} unkown file extension", extension))?; + + Ok(Configuration{file_name, data_name: std::mem::take(&mut cmd.data_name), line_feed: cpp_out::LineFeed::Windows, file_type}) +} + +fn run_main(mut cmd: CommandLine) -> Result<(), Error> { + let cfg = configurate(&mut cmd)?; + let input = tool_helper::open_input(&cmd.input_file)?; + let output = tool_helper::open_output(&Some(cmd.output_file))?; + + return cpp_out::convert(cfg, input, output); +} + +fn main() { + match CommandLine::try_parse() { + Ok(cmd) => { + if let Err(error) = run_main(cmd) { + exit_with_error(error) + } + }, + Err(error) => println!("{}", error) + } } \ No newline at end of file diff --git a/src/Tools/mkoverlay/Makefile b/src/Tools/mkoverlay/Makefile index 5df9b213..837b303d 100644 --- a/src/Tools/mkoverlay/Makefile +++ b/src/Tools/mkoverlay/Makefile @@ -1,13 +1,13 @@ -include ../Common.mk - -ARTIFACT = mkoverlay - -.PHONY: $(WINDOWS_ARTIFACT) $(UNIX_ARTIFACT) -$(WINDOWS_ARTIFACT): - $(call cargo_windows_default) - -$(UNIX_ARTIFACT): - $(call cargo_unix_default) - -all-windows: $(WINDOWS_ARTIFACT) +include ../Common.mk + +ARTIFACT = mkoverlay + +.PHONY: $(WINDOWS_ARTIFACT) $(UNIX_ARTIFACT) +$(WINDOWS_ARTIFACT): + $(call cargo_windows_default) + +$(UNIX_ARTIFACT): + $(call cargo_unix_default) + +all-windows: $(WINDOWS_ARTIFACT) all: $(UNIX_ARTIFACT) \ No newline at end of file diff --git a/src/Tools/mkoverlay/src/main.rs b/src/Tools/mkoverlay/src/main.rs index 51261492..3f25cf54 100644 --- a/src/Tools/mkoverlay/src/main.rs +++ b/src/Tools/mkoverlay/src/main.rs @@ -1,51 +1,51 @@ -use clap::Parser; -use mkoverlay::types::OverlayDesc; -use std::path::PathBuf; -use tool_helper::{Error, exit_with_error, format_if_error, open_input, open_output}; - -#[derive(Parser)] -#[clap(about = "Creates a linker script and makefile part for the JabyEngine toolchain", long_about = None)] -struct CommandLine { - #[clap(long="mk-file", help="Output path for the makefile")] - mk_file_output: Option, - - #[clap(long="ld-script", help="Output path for the linker script file")] - ld_file_output: Option, - - #[clap(value_parser, help="Input JSON for creating the files")] - input: Option -} - -fn parse_input(input: Option) -> Result { - if let Some(input) = input { - let input = format_if_error!(open_input(&Some(input)), "Opening input file failed with: {error_text}")?; - format_if_error!(mkoverlay::types::json_reader::read_config(input), "Parsing JSON file failed with: {error_text}") - } - - else { - Ok(OverlayDesc::new()) - } -} - -fn run_main(cmd_line: CommandLine) -> Result<(), Error> { - let input = parse_input(cmd_line.input)?; - let mut mk_output = format_if_error!(open_output(&cmd_line.mk_file_output), "Opening file for writing makefile failed with: {error_text}")?; - let mut ld_output = format_if_error!(open_output(&cmd_line.ld_file_output), "Opening file for writing linkerfile failed with: {error_text}")?; - - format_if_error!(mkoverlay::creator::makefile::write(&mut mk_output, &input), "Writing makefile failed with: {error_text}")?; - format_if_error!(mkoverlay::creator::ldscript::write(&mut ld_output, &input), "Writing ld script failed with: {error_text}") -} - -fn main() { - match CommandLine::try_parse() { - Ok(cmd_line) => { - match run_main(cmd_line) { - Ok(_) => (), - Err(error) => exit_with_error(error) - } - }, - Err(error) => { - println!("{}", error) - } - } +use clap::Parser; +use mkoverlay::types::OverlayDesc; +use std::path::PathBuf; +use tool_helper::{Error, exit_with_error, format_if_error, open_input, open_output}; + +#[derive(Parser)] +#[clap(about = "Creates a linker script and makefile part for the JabyEngine toolchain", long_about = None)] +struct CommandLine { + #[clap(long="mk-file", help="Output path for the makefile")] + mk_file_output: Option, + + #[clap(long="ld-script", help="Output path for the linker script file")] + ld_file_output: Option, + + #[clap(value_parser, help="Input JSON for creating the files")] + input: Option +} + +fn parse_input(input: Option) -> Result { + if let Some(input) = input { + let input = format_if_error!(open_input(&Some(input)), "Opening input file failed with: {error_text}")?; + format_if_error!(mkoverlay::types::json_reader::read_config(input), "Parsing JSON file failed with: {error_text}") + } + + else { + Ok(OverlayDesc::new()) + } +} + +fn run_main(cmd_line: CommandLine) -> Result<(), Error> { + let input = parse_input(cmd_line.input)?; + let mut mk_output = format_if_error!(open_output(&cmd_line.mk_file_output), "Opening file for writing makefile failed with: {error_text}")?; + let mut ld_output = format_if_error!(open_output(&cmd_line.ld_file_output), "Opening file for writing linkerfile failed with: {error_text}")?; + + format_if_error!(mkoverlay::creator::makefile::write(&mut mk_output, &input), "Writing makefile failed with: {error_text}")?; + format_if_error!(mkoverlay::creator::ldscript::write(&mut ld_output, &input), "Writing ld script failed with: {error_text}") +} + +fn main() { + match CommandLine::try_parse() { + Ok(cmd_line) => { + match run_main(cmd_line) { + Ok(_) => (), + Err(error) => exit_with_error(error) + } + }, + Err(error) => { + println!("{}", error) + } + } } \ No newline at end of file diff --git a/src/Tools/psxcdgen_ex/Makefile b/src/Tools/psxcdgen_ex/Makefile index 5f824357..52ea264b 100644 --- a/src/Tools/psxcdgen_ex/Makefile +++ b/src/Tools/psxcdgen_ex/Makefile @@ -1,13 +1,13 @@ -include ../Common.mk - -ARTIFACT = psxcdgen_ex - -.PHONY: $(WINDOWS_ARTIFACT) $(UNIX_ARTIFACT) -$(WINDOWS_ARTIFACT): - $(call cargo_windows_default) - -$(UNIX_ARTIFACT): - $(call cargo_unix_default) - -all-windows: $(WINDOWS_ARTIFACT) +include ../Common.mk + +ARTIFACT = psxcdgen_ex + +.PHONY: $(WINDOWS_ARTIFACT) $(UNIX_ARTIFACT) +$(WINDOWS_ARTIFACT): + $(call cargo_windows_default) + +$(UNIX_ARTIFACT): + $(call cargo_unix_default) + +all-windows: $(WINDOWS_ARTIFACT) all: $(UNIX_ARTIFACT) \ No newline at end of file diff --git a/src/Tools/psxcdgen_ex/src/config_reader/mod.rs b/src/Tools/psxcdgen_ex/src/config_reader/mod.rs index 9ae17022..77adc9db 100644 --- a/src/Tools/psxcdgen_ex/src/config_reader/mod.rs +++ b/src/Tools/psxcdgen_ex/src/config_reader/mod.rs @@ -1,88 +1,88 @@ -use super::types::LicenseFile; -use super::Error; -use std::path::PathBuf; -mod xml; - -pub enum LZ4State { - None, - AlreadyCompressed, - Compress, -} - -pub struct CDAudioFile { - pub file_path: PathBuf, - pub align: bool, -} - -impl CDAudioFile { - pub fn new(file_path: PathBuf, align: bool) -> CDAudioFile { - CDAudioFile{file_path, align} - } -} - -pub struct Configuration { - pub publisher: Option, - pub license_file: LicenseFile, - pub backup_license_file: LicenseFile, - pub root: Directory, - pub cd_audio_files: Vec, - pub lead_out_sectors: Option, -} - -impl Configuration { - pub fn new() -> Configuration { - Configuration{publisher: None, license_file: LicenseFile::None, backup_license_file: LicenseFile::None, root: Directory::new("root", false), cd_audio_files: Vec::new(), lead_out_sectors: None} - } -} - -pub struct CommonProperties { - pub name: String, - pub is_hidden: bool, - pub lz4_state: LZ4State, - pub padded_size: Option, -} - -pub enum FileKind { - Regular, - Main(PathBuf), - Overlay(PathBuf), - XAAudio(Vec), -} - -pub struct File { - pub common: CommonProperties, - pub path: PathBuf, - pub kind: FileKind -} -pub struct Directory { - pub name: String, - pub is_hidden: bool, - member: Vec, -} - -impl Directory { - pub fn new(name: &str, is_hidden: bool) -> Directory { - Directory{name: String::from(name), is_hidden, member: Vec::new()} - } - - pub fn add_file(&mut self, file: File) { - self.member.push(DirMember::File(file)); - } - - pub fn add_dir(&mut self, dir: Directory) { - self.member.push(DirMember::Directory(dir)); - } - - pub fn into_iter(self) -> std::vec::IntoIter { - self.member.into_iter() - } -} - -pub enum DirMember { - File(File), - Directory(Directory), -} - -pub fn parse_xml(xml: String) -> Result { - Ok(xml::parse(xml)?) +use super::types::LicenseFile; +use super::Error; +use std::path::PathBuf; +mod xml; + +pub enum LZ4State { + None, + AlreadyCompressed, + Compress, +} + +pub struct CDAudioFile { + pub file_path: PathBuf, + pub align: bool, +} + +impl CDAudioFile { + pub fn new(file_path: PathBuf, align: bool) -> CDAudioFile { + CDAudioFile{file_path, align} + } +} + +pub struct Configuration { + pub publisher: Option, + pub license_file: LicenseFile, + pub backup_license_file: LicenseFile, + pub root: Directory, + pub cd_audio_files: Vec, + pub lead_out_sectors: Option, +} + +impl Configuration { + pub fn new() -> Configuration { + Configuration{publisher: None, license_file: LicenseFile::None, backup_license_file: LicenseFile::None, root: Directory::new("root", false), cd_audio_files: Vec::new(), lead_out_sectors: None} + } +} + +pub struct CommonProperties { + pub name: String, + pub is_hidden: bool, + pub lz4_state: LZ4State, + pub padded_size: Option, +} + +pub enum FileKind { + Regular, + Main(PathBuf), + Overlay(PathBuf), + XAAudio(Vec), +} + +pub struct File { + pub common: CommonProperties, + pub path: PathBuf, + pub kind: FileKind +} +pub struct Directory { + pub name: String, + pub is_hidden: bool, + member: Vec, +} + +impl Directory { + pub fn new(name: &str, is_hidden: bool) -> Directory { + Directory{name: String::from(name), is_hidden, member: Vec::new()} + } + + pub fn add_file(&mut self, file: File) { + self.member.push(DirMember::File(file)); + } + + pub fn add_dir(&mut self, dir: Directory) { + self.member.push(DirMember::Directory(dir)); + } + + pub fn into_iter(self) -> std::vec::IntoIter { + self.member.into_iter() + } +} + +pub enum DirMember { + File(File), + Directory(Directory), +} + +pub fn parse_xml(xml: String) -> Result { + Ok(xml::parse(xml)?) } \ No newline at end of file diff --git a/src/Tools/psxcdgen_ex/src/config_reader/xml.rs b/src/Tools/psxcdgen_ex/src/config_reader/xml.rs index 97d7d990..f5d1405d 100644 --- a/src/Tools/psxcdgen_ex/src/config_reader/xml.rs +++ b/src/Tools/psxcdgen_ex/src/config_reader/xml.rs @@ -1,315 +1,315 @@ -use cdtypes::types::time::Time; -use std::path::PathBuf; -use tool_helper::{format_if_error, path_with_env_from, print_warning, string_with_env_from}; -use crate::{config_reader::Directory, types::LicenseFile}; - -use super::{CDAudioFile, CommonProperties, Configuration, Error, File, FileKind, LZ4State}; - -mod license_tag { - pub const NAME: &'static str = "License"; - pub mod attribute { - pub const ALT_LOGO: &'static str = "alt-logo"; - pub const ALT_TEXT: &'static str = "alt-text"; - } -} - -mod root_tag { - pub const NAME: &'static str = "PSXCD"; - pub mod attribute {} -} - -mod filesystem_tag { - pub const NAME: &'static str = "Filesystem"; - pub mod attribute { - pub const LEAD_OUT:&'static str = "lead-out"; - } -} - -mod file_and_directory_attribute { - pub const NAME: &'static str = "name"; - pub const HIDDEN: &'static str = "hidden"; - pub const PADDED_SIZE: &'static str = "padded_size"; - pub const LBA_SOURCE: &'static str = "lba_source"; - pub const LZ4_STATE: &'static str = "lz4"; -} - -mod interleaved_file_tag { - pub const NAME: &'static str = "InterleavedFile"; - pub mod attribute {} -} - -mod cdda_tag { - pub const NAME: &'static str = "AudioTrack"; - pub mod attribute {} -} - -mod alt_license_tag { - pub const NAME: &'static str = "AltLicense"; - pub mod attribute { - pub const TEXT: &'static str = "text"; - } -} - -pub fn parse(xml: String) -> Result { - let mut config = Configuration::new(); - let parser = format_if_error!(roxmltree::Document::parse(xml.as_str()), "Parsing XML file failed with: {error_text}")?; - let children = parser.root().children(); - - for node in children { - if node.is_element() && node.tag_name().name() == root_tag::NAME { - parse_root(node, &mut config)?; - } - } - - Ok(config) -} - -fn parse_root(root: roxmltree::Node, config: &mut Configuration) -> Result<(), Error> { - let mut parsed_track = false; - - for node in root.children() { - if node.is_element() { - match node.tag_name().name() { - "Description" => parse_description(node, config), - filesystem_tag::NAME => { - if !parsed_track { - parsed_track = true; - parse_track(node, config) - } - - else { - Err(Error::from_text(format!("Found more than 1 filesystem. Multi filesystem discs are not supported"))) - } - }, - cdda_tag::NAME => parse_cd_audio(node, config), - _ => Ok(()) - }?; - } - } - Ok(()) -} - -fn parse_description(description: roxmltree::Node, config: &mut Configuration) -> Result<(), Error> { - fn parse_license_path(license: roxmltree::Node) -> (LicenseFile, LicenseFile) { - let required_lic_file = LicenseFile::from_authentic_option(path_from_node(&license, license_tag::NAME).ok()); - let alt_logo = { - if let Some(path) = license.attribute(license_tag::attribute::ALT_LOGO) { - Some(path_with_env_from(path)) - } - - else { - None - } - }; - let alt_text = license.attribute(license_tag::attribute::ALT_TEXT); - (required_lic_file, LicenseFile::from_tmd_option(alt_logo, alt_text)) - } - - fn parse_altlicense_path(license: roxmltree::Node) -> LicenseFile { - LicenseFile::from_tmd_option(path_from_node(&license, alt_license_tag::NAME).ok(), license.attribute(alt_license_tag::attribute::TEXT)) - } - - for node in description.descendants() { - if node.is_element() { - match node.tag_name().name() { - "Publisher" => config.publisher = Some(String::from(node.text().unwrap_or_default())), - license_tag::NAME => (config.license_file, config.backup_license_file) = parse_license_path(node), - alt_license_tag::NAME => { - if matches!(config.license_file, LicenseFile::None) { - config.license_file = parse_altlicense_path(node) - } - - else { - print_warning("Alternate license ignored because a (alternate) license was already provided".to_owned()) - } - }, - _ => () - } - } - } - Ok(()) -} - -fn parse_track(track: roxmltree::Node, config: &mut Configuration) -> Result<(), Error> { - fn parse_regular_file(file: roxmltree::Node, is_hidden: bool) -> Result { - let common = read_common_properties(&file, is_hidden, None)?; - let path = path_from_node(&file, &common.name)?; - - Ok(File{common, path, kind: FileKind::Regular}) - } - - fn parse_main_file(file: roxmltree::Node) -> Result { - if let Some(lba_path) = file.attribute(file_and_directory_attribute::LBA_SOURCE) { - let common = read_common_properties(&file, false, Some(LZ4State::None))?; - let path = path_from_node(&file, &common.name)?; - - Ok(File{common, path, kind: FileKind::Main(PathBuf::from(lba_path))}) - } - - else { - tool_helper::print_warning(format!("The main file should always contain the \"{}\" attribute, even when just empty", file_and_directory_attribute::LBA_SOURCE)); - parse_regular_file(file, false) - } - } - - fn parse_overlay_file(file: roxmltree::Node, is_hidden: bool) -> Result { - // v They will be compressed automatically - let common = read_common_properties(&file, is_hidden, Some(LZ4State::AlreadyCompressed))?; - let path = path_from_node(&file, &common.name)?; - let lba_source = { - if let Some(lba_source) = file.attribute(file_and_directory_attribute::LBA_SOURCE) { - lba_source - } - - else { - tool_helper::print_warning(format!("Overlays should always contain the \"{}\" attribute, even when just empty", file_and_directory_attribute::LBA_SOURCE)); - "" - } - }; - Ok(File{common, path, kind: FileKind::Overlay(PathBuf::from(lba_source))}) - } - - fn parse_interleaved(file: roxmltree::Node, is_hidden: bool) -> Result { - // v Never compress interleaved files - let common = read_common_properties(&file, is_hidden, Some(LZ4State::None))?; - let channel = { - let mut channel = Vec::new(); - for node in file.children() { - if node.is_element() && node.tag_name().name() == "Channel" { - channel.push(path_from_node(&node, "Channel")?); - } - } - - channel - }; - - Ok(File{common, path: PathBuf::new(), kind: FileKind::XAAudio(channel)}) - } - - fn parse_file_system(cur_node: roxmltree::Node, root: &mut Directory, mut is_hidden: bool) -> Result<(), Error> { - for node in cur_node.children() { - if node.is_element() { - match node.tag_name().name() { - "File" => root.add_file(parse_regular_file(node, is_hidden)?), - "Main" => root.add_file(parse_main_file(node)?), - "Overlay" => root.add_file(parse_overlay_file(node, is_hidden)?), - interleaved_file_tag::NAME => root.add_file(parse_interleaved(node, is_hidden)?), - "Directory" => { - is_hidden |= parse_boolean_attribute(&node, file_and_directory_attribute::HIDDEN)?; - let mut new_dir = Directory::new(node.attribute(file_and_directory_attribute::NAME).unwrap_or_default(), is_hidden); - - parse_file_system(node, &mut new_dir, is_hidden)?; - root.add_dir(new_dir); - }, - _ => (), - } - } - } - - Ok(()) - } - - fn get_lead_out_sectors(track: roxmltree::Node) -> Result, Error> { - const MIN_OPTION_NAME:&'static str = "minutes"; - const SECOND_OPTION_NAME:&'static str = "seconds"; - const SECTOR_OPTION_NAME:&'static str = "sectors"; - - fn parse_split<'a>(who: &'a str, str_opt: Option<&'a str>) -> Result { - match str_opt.unwrap_or("0").parse::() { - Ok(num) => Ok(num), - Err(error) => Err(Error::from_text(format!("Failed converting \"{}\" option for \"{}\" attribute \"{}\": {}", who, filesystem_tag::NAME, filesystem_tag::attribute::LEAD_OUT, error))) - } - } - - //--------------------------------------------------------------------- - - if let Some(length_str) = track.attribute(filesystem_tag::attribute::LEAD_OUT) { - let mut pieces = length_str.split(':'); - let (mins, seconds, sectors) = ( - parse_split(MIN_OPTION_NAME, pieces.next())?, - parse_split(SECOND_OPTION_NAME, pieces.next())?, - parse_split(SECTOR_OPTION_NAME, pieces.next())? - ); - - Ok(Some(Time::from_mss(mins, seconds, sectors).as_sectors())) - } - - else { - Ok(None) - } - } - - config.lead_out_sectors = get_lead_out_sectors(track)?; - parse_file_system(track, &mut config.root, false) -} - -fn parse_cd_audio(cdda: roxmltree::Node, config: &mut Configuration) -> Result<(), Error> { - config.cd_audio_files.push(CDAudioFile::new(path_from_node(&cdda, "CD Audio file")?, parse_boolean_attribute(&cdda, "align")?)); - Ok(()) -} - -fn read_common_properties(xml: &roxmltree::Node, is_hidden: bool, force_lz4_state: Option) -> Result { - let lz4_state = { - if let Some(forced_lz4_state) = force_lz4_state { - forced_lz4_state - } - - else { - if let Some(state_str) = xml.attribute(file_and_directory_attribute::LZ4_STATE) { - match state_str.to_lowercase().as_str() { - "yes" => LZ4State::Compress, - "already" => LZ4State::AlreadyCompressed, - _ => LZ4State::None, - } - } - - else { - LZ4State::None - } - } - }; - - Ok(CommonProperties{ - name: string_with_env_from(xml.attribute(file_and_directory_attribute::NAME).unwrap_or_default()), - is_hidden: is_hidden | parse_boolean_attribute(&xml, file_and_directory_attribute::HIDDEN)?, - lz4_state, - padded_size: read_padded_size(&xml)? - }) -} - -fn read_padded_size(xml: &roxmltree::Node) -> Result, Error> { - if let Some(padded_attr) = xml.attribute(file_and_directory_attribute::PADDED_SIZE) { - let padded_size = format_if_error!(padded_attr.parse::(), "Failed reading \"{}\" as padded size: {error_text}", padded_attr)?; - Ok(Some(padded_size)) - } - - else { - Ok(None) - } -} - -fn parse_boolean_attribute(xml: &roxmltree::Node, attribute_name: &str) -> Result { - if let Some(bool_str) = xml.attribute(attribute_name) { - match bool_str { - "true" | "1" => Ok(true), - "false" | "0" => Ok(false), - _ => { - return Err(Error::from_text(format!("Attribute \"{}\" expects either true,false or 1,0 as valid attributes - found {}", attribute_name, bool_str))); - } - } - } - - else { - Ok(false) - } -} - -fn path_from_node(node: &roxmltree::Node, name: &str) -> Result { - if let Some(path) = node.text() { - Ok(path_with_env_from(path.trim())) - } - - else { - Err(Error::from_text(format!("No path specified for {}", name))) - } +use cdtypes::types::time::Time; +use std::path::PathBuf; +use tool_helper::{format_if_error, path_with_env_from, print_warning, string_with_env_from}; +use crate::{config_reader::Directory, types::LicenseFile}; + +use super::{CDAudioFile, CommonProperties, Configuration, Error, File, FileKind, LZ4State}; + +mod license_tag { + pub const NAME: &'static str = "License"; + pub mod attribute { + pub const ALT_LOGO: &'static str = "alt-logo"; + pub const ALT_TEXT: &'static str = "alt-text"; + } +} + +mod root_tag { + pub const NAME: &'static str = "PSXCD"; + pub mod attribute {} +} + +mod filesystem_tag { + pub const NAME: &'static str = "Filesystem"; + pub mod attribute { + pub const LEAD_OUT:&'static str = "lead-out"; + } +} + +mod file_and_directory_attribute { + pub const NAME: &'static str = "name"; + pub const HIDDEN: &'static str = "hidden"; + pub const PADDED_SIZE: &'static str = "padded_size"; + pub const LBA_SOURCE: &'static str = "lba_source"; + pub const LZ4_STATE: &'static str = "lz4"; +} + +mod interleaved_file_tag { + pub const NAME: &'static str = "InterleavedFile"; + pub mod attribute {} +} + +mod cdda_tag { + pub const NAME: &'static str = "AudioTrack"; + pub mod attribute {} +} + +mod alt_license_tag { + pub const NAME: &'static str = "AltLicense"; + pub mod attribute { + pub const TEXT: &'static str = "text"; + } +} + +pub fn parse(xml: String) -> Result { + let mut config = Configuration::new(); + let parser = format_if_error!(roxmltree::Document::parse(xml.as_str()), "Parsing XML file failed with: {error_text}")?; + let children = parser.root().children(); + + for node in children { + if node.is_element() && node.tag_name().name() == root_tag::NAME { + parse_root(node, &mut config)?; + } + } + + Ok(config) +} + +fn parse_root(root: roxmltree::Node, config: &mut Configuration) -> Result<(), Error> { + let mut parsed_track = false; + + for node in root.children() { + if node.is_element() { + match node.tag_name().name() { + "Description" => parse_description(node, config), + filesystem_tag::NAME => { + if !parsed_track { + parsed_track = true; + parse_track(node, config) + } + + else { + Err(Error::from_text(format!("Found more than 1 filesystem. Multi filesystem discs are not supported"))) + } + }, + cdda_tag::NAME => parse_cd_audio(node, config), + _ => Ok(()) + }?; + } + } + Ok(()) +} + +fn parse_description(description: roxmltree::Node, config: &mut Configuration) -> Result<(), Error> { + fn parse_license_path(license: roxmltree::Node) -> (LicenseFile, LicenseFile) { + let required_lic_file = LicenseFile::from_authentic_option(path_from_node(&license, license_tag::NAME).ok()); + let alt_logo = { + if let Some(path) = license.attribute(license_tag::attribute::ALT_LOGO) { + Some(path_with_env_from(path)) + } + + else { + None + } + }; + let alt_text = license.attribute(license_tag::attribute::ALT_TEXT); + (required_lic_file, LicenseFile::from_tmd_option(alt_logo, alt_text)) + } + + fn parse_altlicense_path(license: roxmltree::Node) -> LicenseFile { + LicenseFile::from_tmd_option(path_from_node(&license, alt_license_tag::NAME).ok(), license.attribute(alt_license_tag::attribute::TEXT)) + } + + for node in description.descendants() { + if node.is_element() { + match node.tag_name().name() { + "Publisher" => config.publisher = Some(String::from(node.text().unwrap_or_default())), + license_tag::NAME => (config.license_file, config.backup_license_file) = parse_license_path(node), + alt_license_tag::NAME => { + if matches!(config.license_file, LicenseFile::None) { + config.license_file = parse_altlicense_path(node) + } + + else { + print_warning("Alternate license ignored because a (alternate) license was already provided".to_owned()) + } + }, + _ => () + } + } + } + Ok(()) +} + +fn parse_track(track: roxmltree::Node, config: &mut Configuration) -> Result<(), Error> { + fn parse_regular_file(file: roxmltree::Node, is_hidden: bool) -> Result { + let common = read_common_properties(&file, is_hidden, None)?; + let path = path_from_node(&file, &common.name)?; + + Ok(File{common, path, kind: FileKind::Regular}) + } + + fn parse_main_file(file: roxmltree::Node) -> Result { + if let Some(lba_path) = file.attribute(file_and_directory_attribute::LBA_SOURCE) { + let common = read_common_properties(&file, false, Some(LZ4State::None))?; + let path = path_from_node(&file, &common.name)?; + + Ok(File{common, path, kind: FileKind::Main(PathBuf::from(lba_path))}) + } + + else { + tool_helper::print_warning(format!("The main file should always contain the \"{}\" attribute, even when just empty", file_and_directory_attribute::LBA_SOURCE)); + parse_regular_file(file, false) + } + } + + fn parse_overlay_file(file: roxmltree::Node, is_hidden: bool) -> Result { + // v They will be compressed automatically + let common = read_common_properties(&file, is_hidden, Some(LZ4State::AlreadyCompressed))?; + let path = path_from_node(&file, &common.name)?; + let lba_source = { + if let Some(lba_source) = file.attribute(file_and_directory_attribute::LBA_SOURCE) { + lba_source + } + + else { + tool_helper::print_warning(format!("Overlays should always contain the \"{}\" attribute, even when just empty", file_and_directory_attribute::LBA_SOURCE)); + "" + } + }; + Ok(File{common, path, kind: FileKind::Overlay(PathBuf::from(lba_source))}) + } + + fn parse_interleaved(file: roxmltree::Node, is_hidden: bool) -> Result { + // v Never compress interleaved files + let common = read_common_properties(&file, is_hidden, Some(LZ4State::None))?; + let channel = { + let mut channel = Vec::new(); + for node in file.children() { + if node.is_element() && node.tag_name().name() == "Channel" { + channel.push(path_from_node(&node, "Channel")?); + } + } + + channel + }; + + Ok(File{common, path: PathBuf::new(), kind: FileKind::XAAudio(channel)}) + } + + fn parse_file_system(cur_node: roxmltree::Node, root: &mut Directory, mut is_hidden: bool) -> Result<(), Error> { + for node in cur_node.children() { + if node.is_element() { + match node.tag_name().name() { + "File" => root.add_file(parse_regular_file(node, is_hidden)?), + "Main" => root.add_file(parse_main_file(node)?), + "Overlay" => root.add_file(parse_overlay_file(node, is_hidden)?), + interleaved_file_tag::NAME => root.add_file(parse_interleaved(node, is_hidden)?), + "Directory" => { + is_hidden |= parse_boolean_attribute(&node, file_and_directory_attribute::HIDDEN)?; + let mut new_dir = Directory::new(node.attribute(file_and_directory_attribute::NAME).unwrap_or_default(), is_hidden); + + parse_file_system(node, &mut new_dir, is_hidden)?; + root.add_dir(new_dir); + }, + _ => (), + } + } + } + + Ok(()) + } + + fn get_lead_out_sectors(track: roxmltree::Node) -> Result, Error> { + const MIN_OPTION_NAME:&'static str = "minutes"; + const SECOND_OPTION_NAME:&'static str = "seconds"; + const SECTOR_OPTION_NAME:&'static str = "sectors"; + + fn parse_split<'a>(who: &'a str, str_opt: Option<&'a str>) -> Result { + match str_opt.unwrap_or("0").parse::() { + Ok(num) => Ok(num), + Err(error) => Err(Error::from_text(format!("Failed converting \"{}\" option for \"{}\" attribute \"{}\": {}", who, filesystem_tag::NAME, filesystem_tag::attribute::LEAD_OUT, error))) + } + } + + //--------------------------------------------------------------------- + + if let Some(length_str) = track.attribute(filesystem_tag::attribute::LEAD_OUT) { + let mut pieces = length_str.split(':'); + let (mins, seconds, sectors) = ( + parse_split(MIN_OPTION_NAME, pieces.next())?, + parse_split(SECOND_OPTION_NAME, pieces.next())?, + parse_split(SECTOR_OPTION_NAME, pieces.next())? + ); + + Ok(Some(Time::from_mss(mins, seconds, sectors).as_sectors())) + } + + else { + Ok(None) + } + } + + config.lead_out_sectors = get_lead_out_sectors(track)?; + parse_file_system(track, &mut config.root, false) +} + +fn parse_cd_audio(cdda: roxmltree::Node, config: &mut Configuration) -> Result<(), Error> { + config.cd_audio_files.push(CDAudioFile::new(path_from_node(&cdda, "CD Audio file")?, parse_boolean_attribute(&cdda, "align")?)); + Ok(()) +} + +fn read_common_properties(xml: &roxmltree::Node, is_hidden: bool, force_lz4_state: Option) -> Result { + let lz4_state = { + if let Some(forced_lz4_state) = force_lz4_state { + forced_lz4_state + } + + else { + if let Some(state_str) = xml.attribute(file_and_directory_attribute::LZ4_STATE) { + match state_str.to_lowercase().as_str() { + "yes" => LZ4State::Compress, + "already" => LZ4State::AlreadyCompressed, + _ => LZ4State::None, + } + } + + else { + LZ4State::None + } + } + }; + + Ok(CommonProperties{ + name: string_with_env_from(xml.attribute(file_and_directory_attribute::NAME).unwrap_or_default()), + is_hidden: is_hidden | parse_boolean_attribute(&xml, file_and_directory_attribute::HIDDEN)?, + lz4_state, + padded_size: read_padded_size(&xml)? + }) +} + +fn read_padded_size(xml: &roxmltree::Node) -> Result, Error> { + if let Some(padded_attr) = xml.attribute(file_and_directory_attribute::PADDED_SIZE) { + let padded_size = format_if_error!(padded_attr.parse::(), "Failed reading \"{}\" as padded size: {error_text}", padded_attr)?; + Ok(Some(padded_size)) + } + + else { + Ok(None) + } +} + +fn parse_boolean_attribute(xml: &roxmltree::Node, attribute_name: &str) -> Result { + if let Some(bool_str) = xml.attribute(attribute_name) { + match bool_str { + "true" | "1" => Ok(true), + "false" | "0" => Ok(false), + _ => { + return Err(Error::from_text(format!("Attribute \"{}\" expects either true,false or 1,0 as valid attributes - found {}", attribute_name, bool_str))); + } + } + } + + else { + Ok(false) + } +} + +fn path_from_node(node: &roxmltree::Node, name: &str) -> Result { + if let Some(path) = node.text() { + Ok(path_with_env_from(path.trim())) + } + + else { + Err(Error::from_text(format!("No path specified for {}", name))) + } } \ No newline at end of file diff --git a/src/Tools/psxcdgen_ex/src/encoder/cd.rs b/src/Tools/psxcdgen_ex/src/encoder/cd.rs index f4d6e8b5..87c9932e 100644 --- a/src/Tools/psxcdgen_ex/src/encoder/cd.rs +++ b/src/Tools/psxcdgen_ex/src/encoder/cd.rs @@ -1,634 +1,634 @@ -use super::{*, SectorWriter, {CDDATrack, CDDesc, Error}}; -use super::super::types::{FileType, helper::{DirectoryRecordMember, PathTableMember}, layout::Layout, *}; -use builder::SubModeBuilder; -use cdtypes::types::{cdstring::{AString, DString}, date::*, dir_record::*, helper::{round_bytes_mode2_form1, sector_count_mode2_form1, sector_count_mode2_form2}, lsb_msb::*, path_table::*, pvd as cd_pvd, sector::Mode2Form1}; -use tool_helper::{BufferedInputFile, format_if_error, open_input_file_buffered, print_warning}; -use std::{io::{Read, Seek, SeekFrom}, path::PathBuf}; - -const ROOT_DIR_NAME:&'static str = "\x00"; - -pub mod size_of { - use cdtypes::types::{sector::Mode0, helper::{sector_count_mode2_form1, sector_count_mode2_form2}}; - use crate::types::FileType; - use super::{Directory, File, FullSizeInfo, RealSizeInfo, SizeInfo, PathTable}; - - pub const SYSTEM_AREA_SECTOR_COUNT:usize = 16; - pub const PVD_SECTOR_COUNT:usize = 2; - - pub const fn system_area() -> SizeInfo { - SizeInfo{ - real_size: RealSizeInfo{bytes: None, sectors: SYSTEM_AREA_SECTOR_COUNT}, - full_size: FullSizeInfo{bytes: None, sectors: SYSTEM_AREA_SECTOR_COUNT} - } - } - - pub const fn pvd() -> SizeInfo { - SizeInfo{ - real_size: RealSizeInfo{bytes: None, sectors: PVD_SECTOR_COUNT}, - full_size: FullSizeInfo{bytes: None, sectors: PVD_SECTOR_COUNT} - } - } - - pub fn path_tables(root: &Directory) -> SizeInfo { - let path_table_size = PathTable::calculate_size_for(root); - SizeInfo{ - real_size: RealSizeInfo{bytes: Some(path_table_size), sectors: sector_count_mode2_form1(path_table_size)}, - full_size: FullSizeInfo{bytes: Some(path_table_size), sectors: sector_count_mode2_form1(path_table_size)} - } - } - - pub fn directory(dir: &Directory) -> SizeInfo { - let real_size_bytes = dir.properties.borrow().get_real_size(); - let full_size_bytes = dir.get_extended_size(); - SizeInfo{ - real_size: RealSizeInfo{bytes: Some(real_size_bytes), sectors: sector_count_mode2_form1(real_size_bytes)}, - full_size: FullSizeInfo{bytes: Some(full_size_bytes), sectors: sector_count_mode2_form1(full_size_bytes)} - } - } - - pub fn file(file: &File) -> SizeInfo { - let real_size_bytes = file.properties.get_real_size(); - let full_size_bytes = file.get_extended_size(); - if matches!(file.content, FileType::XAAudio(_)) { - SizeInfo{ - real_size: RealSizeInfo{bytes: Some(real_size_bytes), sectors: sector_count_mode2_form2(real_size_bytes)}, - full_size: FullSizeInfo{bytes: Some(full_size_bytes), sectors: sector_count_mode2_form2(full_size_bytes)} - } - } - - else { - SizeInfo{ - real_size: RealSizeInfo{bytes: Some(real_size_bytes), sectors: sector_count_mode2_form1(real_size_bytes)}, - full_size: FullSizeInfo{bytes: Some(full_size_bytes), sectors: sector_count_mode2_form1(full_size_bytes)} - } - } - } - - pub fn lead_out(sectors: usize) -> SizeInfo { - SizeInfo{ - real_size: RealSizeInfo{bytes: Some(sectors*Mode0::DATA_SIZE), sectors}, - full_size: FullSizeInfo{bytes: Some(sectors*Mode0::DATA_SIZE), sectors} - } - } -} - -pub fn calculate_length_for(element: &Layout) -> SizeInfo { - match element { - Layout::SystemArea(_) => size_of::system_area(), - Layout::PVD(_) => size_of::pvd(), - Layout::PathTables(root, _) => size_of::path_tables(&root.borrow()), - Layout::Directory(dir) => size_of::directory(&dir.borrow()), - Layout::File(file) => size_of::file(&file.borrow()), - } -} - -pub fn calculate_lbas(cd_desc: &mut CDDesc) { - let mut cur_lba = 0; - let track_offset = LBA::FIRST_TRACK_OFFSET; - - cd_desc.vol_sector_count = 0; - CDDesc::for_each_dir_mut(cd_desc.root.clone(), &|dir| {dir.update_content_size();}); - - for element in cd_desc.get_memory_layout() { - fn update_lba(properties: &mut Properties, cur_lba: usize, track_offset: usize, content_sector_size: usize) -> usize { - properties.lba.overwrite(cur_lba, track_offset); - cur_lba + content_sector_size - } - - let element_size_info = calculate_length_for(&element); - match element { - Layout::SystemArea(system_area) => { - let mut system_area = system_area.borrow_mut(); - - system_area.lba.overwrite(cur_lba, track_offset); - cur_lba += element_size_info.full_size.sectors; - }, - - Layout::PVD(pvd) => { - let mut pvd = pvd.borrow_mut(); - - pvd.lba.overwrite(cur_lba, track_offset); - cur_lba += element_size_info.full_size.sectors; - }, - - Layout::PathTables(_, path_table) => { - let mut path_table = path_table.borrow_mut(); - - path_table.lba.overwrite(cur_lba, track_offset); - path_table.size_bytes = element_size_info.full_size.bytes.unwrap_or(0); - - cur_lba += element_size_info.full_size.sectors*4; - }, - - Layout::Directory(dir) => { - let dir = dir.borrow_mut(); - let mut properties = dir.properties.borrow_mut(); - - cd_desc.vol_sector_count += element_size_info.full_size.sectors; - if properties.is_hidden { - properties.lba.overwrite(0, 0); - } - - else { - cur_lba = update_lba(&mut properties, cur_lba, track_offset, element_size_info.full_size.sectors); - } - }, - - Layout::File(file) => { - let mut file = file.borrow_mut(); - - cd_desc.vol_sector_count += element_size_info.full_size.sectors; - cur_lba = update_lba(&mut file.properties, cur_lba, track_offset, element_size_info.full_size.sectors); - } - } - } -} - -pub fn encode_image(cd_desc: &CDDesc, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { - let vol_sector_count = cd_desc.vol_sector_count; - - for element in cd_desc.get_memory_layout() { - match element { - Layout::SystemArea(system_area) => process_system_area(&mut system_area.borrow_mut(), sec_writer)?, - Layout::PVD(pvd) => process_pvd(&pvd.borrow(), cd_desc.path_table.clone(), cd_desc.root.clone(), vol_sector_count, sec_writer)?, - Layout::PathTables(root, path_table) => process_path_table(&path_table.borrow(), root, sec_writer)?, - Layout::Directory(dir) => process_directory_record(&dir.borrow(), sec_writer)?, - Layout::File(file) => process_file(&file.borrow(), sec_writer)?, - } - } - - process_lead_out(cd_desc.lead_out_sectors, sec_writer)?; - process_end_dummy_section(cd_desc.end_dummy_padding, sec_writer)?; - process_cd_da(&cd_desc.cd_da_tracks, sec_writer) -} - -fn process_system_area(system_area: &SystemArea, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { - fn write_data_zeros(sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { - write_dummy(sec_writer, 4) - } - - fn write_audio_zeros(sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { - for _ in 0..4 { - let sector = { - let mut sector = builder::create_xa_audio_zero(0); - - sector.sub_header.sub_mode.clear_audio(); - sector - }; - sec_writer.write_cd_xa_audio(sector)?; - } - - Ok(()) - } - - fn write_license_string_raw(sec_writer: &mut dyn SectorWriter, data: &[u8; Mode2Form1::DATA_SIZE]) -> Result { - let sub_mode = SubModeBuilder::new_mode1().create(); - let sector = builder::create_xa_data_for_raw(sub_mode, data); - - sec_writer.write_cd_xa_data(sector) - } - - fn write_license_file(sec_writer: &mut dyn SectorWriter, mut license_file: BufferedInputFile) -> Result<(), Error> { - fn write_license_string(sec_writer: &mut dyn SectorWriter, license_file: &mut BufferedInputFile) -> Result<(), Error> { - const LICENSE_STRING_START:u64 = 0x2488; - - if license_file.get_ref().metadata()?.len() < LICENSE_STRING_START { - return Err(Error::from_str("License file to short to contain license string. Is this is a valid license file?")); - } - - let mut license_string_buffer = [0u8; Mode2Form1::DATA_SIZE]; - - license_file.seek(SeekFrom::Start(LICENSE_STRING_START))?; - license_file.read(&mut license_string_buffer)?; - - write_license_string_raw(sec_writer, &license_string_buffer)?; - Ok(()) - } - - fn write_license_logo(sec_writer: &mut dyn SectorWriter, license_file: &mut BufferedInputFile) -> Result<(), Error> { - const LICENSE_LOGO_START:u64 = 0x2DA8; - - license_file.seek(SeekFrom::Start(LICENSE_LOGO_START))?; - for _ in 0..7 { - const LICENSE_SECTOR_REST:i64 = 0x120; - - if license_file.get_ref().metadata()?.len() < license_file.stream_position()? + LICENSE_SECTOR_REST as u64 { - return Err(Error::from_str("License file to short to contain license logo. Is this is a valid license file?")); - } - - let mut license_logo_buffer = [0u8; Mode2Form1::DATA_SIZE]; - - license_file.read(&mut license_logo_buffer)?; - license_file.seek(SeekFrom::Current(LICENSE_SECTOR_REST))?; - - let sub_mode = SubModeBuilder::new_mode1().create(); - let sector = builder::create_xa_data_for_raw(sub_mode, &license_logo_buffer); - - sec_writer.write_cd_xa_data(sector)?; - } - Ok(()) - } - - format_if_error!(write_data_zeros(sec_writer), "Writing license data zeros failed with: {error_text}")?; - format_if_error!(write_license_string(sec_writer, &mut license_file), "Writing license string from file failed with: {error_text}")?; - format_if_error!(write_license_logo(sec_writer, &mut license_file), "Writing license logo from file failed with: {error_text}")?; - format_if_error!(write_audio_zeros(sec_writer), "Writing license audio zeros failed with: {error_text}") - } - - fn write_tmd_file(sec_writer: &mut dyn SectorWriter, tmd_file: BufferedInputFile, lic_text: &Option) -> Result<(), Error> { - fn write_license_string(sec_writer: &mut dyn SectorWriter, text: &str) -> Result<(), Error> { - let text_len = text.len(); - - if text_len <= Mode2Form1::DATA_SIZE { - let mut license_string_buffer = [0u8; Mode2Form1::DATA_SIZE]; - - license_string_buffer[..text_len].copy_from_slice(text[0..text_len].as_bytes()); - write_license_string_raw(sec_writer, &license_string_buffer)?; - Ok(()) - } - - else { - Err(Error::from_text(format!("License string \"{}\" is longer then supported length {}", text, Mode2Form1::DATA_SIZE))) - } - } - - fn write_license_logo(sec_writer: &mut dyn SectorWriter, mut tmd_file: BufferedInputFile) -> Result<(), Error> { - const SECTOR_COUNT:usize = 11 - 5 + 1; - - let bytes = { - let mut bytes = vec![]; - tmd_file.read_to_end(&mut bytes)?; - bytes - }; - let mut sectors = builder::create_xa_data_for_vec(Some(SubModeBuilder::new_mode1().create()), &bytes, 0xFFu8); - if sectors.len() > SECTOR_COUNT { - return Err(Error::from_str("Provided TMD file for alt-license is larger then 8 sectors of data")); - } - - while sectors.len() < SECTOR_COUNT { - sectors.push(builder::create_xa_data_zero()); - } - - for sector in sectors { - sec_writer.write_cd_xa_data(sector)?; - } - Ok(()) - } - - let lic_text = { - if let Some(lic_text) = lic_text { - lic_text.as_ref() - } - - else { - "" - } - }; - - format_if_error!(write_data_zeros(sec_writer), "Writing alt-license data zeros failed with: {error_text}")?; - format_if_error!(write_license_string(sec_writer, lic_text), "Writing alt-license string from file failed with: {error_text}")?; - format_if_error!(write_license_logo(sec_writer, tmd_file), "Writing alt-license logo from file failed with: {error_text}")?; - format_if_error!(write_audio_zeros(sec_writer), "Writing alt-license audio zeros failed with: {error_text}") - } - - let system_area_lba = system_area.lba.get_track_relative(); - if system_area_lba != 0 { - return Err(Error::from_text(format!("System Area required to start at sector 0 of Track - found LBA: {}", system_area_lba))); - } - - fn write_tmd_license(sec_writer: &mut dyn SectorWriter, tmd_path: &PathBuf, lic_text: &Option) -> Result<(), Error> { - print_warning(format!("WARNING: An alternative license file was provided. {}", NOT_BOOTING_CD_STR)); - let tmd_file = format_if_error!(open_input_file_buffered(tmd_path), "Loading TMD file from {} failed with: {error_text}", tmd_path.to_string_lossy())?; - write_tmd_file(sec_writer, tmd_file, lic_text) - } - - const NOT_BOOTING_CD_STR:&'static str = "Some emulators (No$PSX) and some consoles (japanese/some european PS1; All PS3) will not boot this CD."; - match &system_area.license_file { - LicenseFile::Authentic(license_path) => { - match open_input_file_buffered(license_path) { - Ok(license_file) => write_license_file(sec_writer, license_file), - Err(error) => { - let err_str = format!("Loading license file from {} failed with: {}", license_path.to_string_lossy(), error); - if let LicenseFile::TMD(tmd_path, lic_text) = &system_area.backup_license_file { - print_warning(format!("{}. Now using backup license information", err_str)); - write_tmd_license(sec_writer, tmd_path, lic_text) - } - - else { - Err(Error::from_text(err_str)) - } - } - } - }, - LicenseFile::TMD(tmd_path, lic_text) => write_tmd_license(sec_writer, tmd_path, lic_text), - LicenseFile::None => { - // No license specified - filling it with zeros - print_warning(format!("WARNING: No license file provided. {}", NOT_BOOTING_CD_STR)); - write_dummy(sec_writer, size_of::SYSTEM_AREA_SECTOR_COUNT) - }, - } -} - -fn process_pvd(pvd: &PrimaryVolumeDescriptor, path_table: SharedPtr, root_dir: SharedPtr, vol_sector_count: usize, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { - const PLAYSATATION_STR:&'static str = "PLAYSTATION"; - - let path_table = validate_and_unwrap_path_table(&path_table)?; - let root_dir = root_dir.borrow(); - let pvd_lba = pvd.lba.get_track_relative(); - - if pvd_lba != 16 { - return Err(Error::from_text(format!("PVD required to start at sector 16 of Track - found LBA: {}", pvd_lba))); - } - - let mut cd_pvd = cd_pvd::PrimaryVolumeDescriptor::new(); - let now = Date::now(); - - //Config pvd here - cd_pvd.system_id = AString::from_str(PLAYSATATION_STR)?; - cd_pvd.volume_id = DString::from_str("PSX")?; - cd_pvd.vol_space_size.write(vol_sector_count as u32); - - //Set PathTable values - cd_pvd.path_table_size.write(path_table.size_bytes as u32); - cd_pvd.path_table_1.write(path_table.get_track_rel_lba_for(1, sector_count_mode2_form1) as u32); - cd_pvd.path_table_2.write(path_table.get_track_rel_lba_for(2, sector_count_mode2_form1) as u32); - cd_pvd.path_table_3.write(path_table.get_track_rel_lba_for(3, sector_count_mode2_form1) as u32); - cd_pvd.path_table_4.write(path_table.get_track_rel_lba_for(4, sector_count_mode2_form1) as u32); - - //Set Root Directory Record - write_dir_record(&mut cd_pvd.root_dir_record, &DirectoryRecordMember::new_dir(ROOT_DIR_NAME.to_owned(), &root_dir.properties.borrow()), false)?; - - //Set other stuff - cd_pvd.publisher_id = AString::from_str(pvd.publisher.as_str())?; - cd_pvd.data_preparer = AString::from_str("JABYENGINE PSXCDGEN_EX")?; - cd_pvd.app_id = AString::from_str(PLAYSATATION_STR)?; - - cd_pvd.vol_create_time = now; - - cd_pvd.cd_xa_id = ['C' as u8, 'D' as u8, '-' as u8, 'X' as u8, 'A' as u8, '0' as u8, '0' as u8, '1' as u8]; - - //Write PVD and VDT - sec_writer.write_cd_xa_data(builder::create_xa_data_for(SubModeBuilder::new_mode1().set_eor().create(), &cd_pvd))?; - sec_writer.write_cd_xa_data(builder::create_xa_data_for(SubModeBuilder::new_mode1().set_eor().set_eof().create(), &cd_pvd::VolumeDescriptorTerminator::new()))?; - Ok(()) -} - -fn process_path_table(path_table: &PathTable, root_dir: SharedPtr, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { - macro_rules! write_path_table_twice { - ($table:ident) => { - for sector in $table.clone() { - sec_writer.write_cd_xa_data(sector)?; - } - - for sector in $table { - sec_writer.write_cd_xa_data(sector)?; - } - }; - } - let mut bytes_used = 0; - let mut path_table_raw_l = vec![0u8; path_table.size_bytes]; - let mut path_table_raw_b = vec![0u8; path_table.size_bytes]; - - validate_path_table(path_table)?; - let path_table = PathTable::collect_member(&root_dir.borrow()); - - for entry in path_table { - bytes_used += unsafe{update_path_table_entry(std::mem::transmute::<&mut u8, &mut PathTableL>(&mut path_table_raw_l[bytes_used]), std::mem::transmute::<&mut u8, &mut PathTableB>(&mut path_table_raw_b[bytes_used]), entry)?}; - } - - let path_table_l = builder::create_xa_data_for_vec(None, &path_table_raw_l, 0x0u8); - let path_table_b = builder::create_xa_data_for_vec(None, &path_table_raw_b, 0x0u8); - - write_path_table_twice!(path_table_l); - write_path_table_twice!(path_table_b); - - Ok(()) -} - -fn process_directory_record(dir: &Directory, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { - if dir.properties.borrow().is_hidden { - return Ok(()); - } - - let properties = dir.properties.borrow(); - if !properties.is_size_valid() { - return Err(create_wrong_padding_error("Dir", dir.name.to_string(), properties.get_padded_size(), properties.get_real_size())); - } - - let mut dir_record = vec![0u8; properties.get_real_size()]; - let dir_length = dir_record.len(); - let mut raw_data = &mut dir_record[0..dir_length]; - - for member in dir.collect_member() { - let raw_data_len = raw_data.len(); - let bytes_written = write_dir_record(raw_data, &member, true)?; - - raw_data = &mut raw_data[bytes_written..raw_data_len]; - } - - let dir_record_sectors = builder::create_xa_data_for_vec(None, &dir_record, 0x0u8); - let dir_record_sector_count = dir_record_sectors.len(); - - if dir_record_sector_count > 1 { - return Err(Error::from_text(format!("Directory Record for {} spans {} sectors but PSX doesn't support more then one sector", dir.name.as_str().unwrap_or(""), dir_record_sector_count))); - } - - for sector in dir_record_sectors { - sec_writer.write_cd_xa_data(sector)?; - } - - let extended_sector_count = sector_count_mode2_form1(dir.properties.borrow().get_padded_size()) - dir_record_sector_count; - write_dummy(sec_writer, extended_sector_count) -} - -fn process_file(file: &File, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { - fn process_regular_file(content: &RawData, sec_writer: &mut dyn SectorWriter, padded_size: usize) -> Result<(), Error> { - let content_sectors = builder::create_xa_data_for_vec(None, content, 0x0u8); - let content_sector_count = content_sectors.len(); - - for sector in content_sectors { - sec_writer.write_cd_xa_data(sector)?; - } - - let extended_sector_count = sector_count_mode2_form1(padded_size) - content_sector_count; - write_dummy(sec_writer, extended_sector_count) - } - - fn process_cd_xa_file(content: &Vec, sec_writer: &mut dyn SectorWriter, padded_size: usize) -> Result<(), Error> { - let content_sectors = builder::create_xa_audio_for(content); - let content_sector_count = content_sectors.len(); - - for sector in content_sectors { - sec_writer.write_interleaved(sector)?; - } - - let extended_sector_count = sector_count_mode2_form2(padded_size) - content_sector_count; - for _ in 0..extended_sector_count { - sec_writer.write_cd_xa_audio(builder::create_xa_audio_zero(0))?; - } - - Ok(()) - } - - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - if !file.properties.is_size_valid() { - return Err(create_wrong_padding_error("File", file.name.to_string(), file.properties.get_padded_size(), file.properties.get_real_size())); - } - - match &file.content { - FileType::Regular(raw) => process_regular_file(raw, sec_writer, file.properties.get_padded_size()), - FileType::XAAudio(raw) => process_cd_xa_file(raw, sec_writer, file.properties.get_padded_size()), - FileType::Main(_, _) => Err(Error::from_str("Trying to encode an unprocessed main file")), - FileType::Overlay(_, _) => Err(Error::from_str("Trying to encode an unprocessed overlay file")), - } -} - -fn write_dummy(sec_writer: &mut dyn SectorWriter, sectors: usize) -> Result<(), Error> { - for _ in 0..sectors { - sec_writer.write_cd_xa_data(builder::create_xa_data_zero())?; - } - Ok(()) -} - -fn process_lead_out(sectors: usize, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { - for _ in 0..sectors { - sec_writer.write_empty(builder::create_mode0_zero())?; - } - Ok(()) -} - -fn process_end_dummy_section(padding: usize, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { - // The padding required for the PS3 - write_dummy(sec_writer, sector_count_mode2_form1(padding)) -} - -fn process_cd_da(cd_da_tracks: &Vec, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { - for cd_da_track in cd_da_tracks { - // The padding required for CDDA to start on a full second - if cd_da_track.align { - let missing_sectors = sec_writer.sectors_to_next_second(); - write_dummy(sec_writer, missing_sectors)?; - } - - sec_writer.cd_da_start()?; - for audio in builder::create_audio_for_vec(&cd_da_track.samples) { - sec_writer.write_audio(audio)?; - } - } - Ok(()) -} - -fn validate_path_table(path_table: &PathTable) -> Result<(), Error> { - if path_table.size_bytes > Mode2Form1::DATA_SIZE { - Err(Error::from_text(format!("Path Tables are not allowed to be bigger then {} bytes - Path Table has {} bytes", Mode2Form1::DATA_SIZE, path_table.size_bytes))) - } - - else { - Ok(()) - } -} - -fn validate_and_unwrap_path_table(path_table: &SharedPtr) -> Result, Error> { - let path_table = path_table.borrow(); - - validate_path_table(&path_table)?; - Ok(path_table) -} - -fn update_path_table_entry(path_table_l: &mut PathTableL, path_table_b: &mut PathTableB, entry: PathTableMember) -> Result { - let name_len = entry.name.len(); - if name_len > 8 { - return Err(Error::from_text(format!("Directory name can not exceed size of 8 characters but folder {} has {} characters", entry.name, name_len))); - } - - unsafe{ - let name = entry.name.as_str(); - - path_table_l.new(name); - path_table_b.new(name); - } - - path_table_l.directory_logical_block.write(entry.track_rel_lba as u32); - path_table_b.directory_logical_block.write(entry.track_rel_lba as u32); - path_table_l.parent_table_id.write(entry.parent_table_id as u16); - path_table_b.parent_table_id.write(entry.parent_table_id as u16); - - Ok(path_table_l.get_size()) -} - -fn create_dir_record_raw<'a>(dst: &'a mut [u8], name: &str, track_rel_lba: u32, size_bytes: u32, system_use: Option) -> Result<&'a mut DirectoryRecord, Error> { - let has_system_use = system_use.is_some(); - let bytes_needed = DirectoryRecord::calculate_size_for(name, has_system_use); - - if dst.len() < bytes_needed { - return Err(Error::from_text(format!("DirectoryRecord for entry {} needs {} bytes but {} bytes were provided", name, bytes_needed, dst.len()))); - } - - unsafe { - let dir_record = std::mem::transmute::<&mut u8, &mut DirectoryRecord>(&mut dst[0]); - dir_record.new(name, has_system_use); - - dir_record.data_block_number.write(track_rel_lba); - dir_record.data_size.write(size_bytes); - dir_record.time_stamp = SmallDate::now(); - - if let Some(system_use) = system_use { - if let Some(record_system_use) = dir_record.get_cdxa_system_use_mut() { - *record_system_use = system_use; - } - } - - Ok(dir_record) - } -} - -fn write_dir_record(dir_record: &mut [u8], dir_member: &DirectoryRecordMember, has_system_use: bool) -> Result { - match dir_member { - DirectoryRecordMember::Directory{name, track_rel_lba, real_size} => { - let system_use = { - if has_system_use { - let mut system_use = CDXASystemUse::default(); - - system_use.file_attribute.set_mode2(); - system_use.file_attribute.set_directory(); - - Some(system_use) - } - - else { - None - } - }; - - let dir_record = create_dir_record_raw(dir_record, name.as_str(), *track_rel_lba as u32, round_bytes_mode2_form1(*real_size as usize) as u32, system_use)?; - - dir_record.set_directory(); - return Ok(dir_record.length[0] as usize); - }, - - DirectoryRecordMember::File{name, track_rel_lba, real_size} => { - let system_use = { - if has_system_use { - let mut system_use = CDXASystemUse::default(); - - system_use.file_attribute.set_mode2(); - Some(system_use) - } - - else { - None - } - }; - - let dir_record = create_dir_record_raw(dir_record, name.as_str(), *track_rel_lba as u32, *real_size as u32, system_use)?; - - dir_record.set_file(); - return Ok(dir_record.length[0] as usize); - } - } -} - -fn create_wrong_padding_error(for_who: &str, name: String, padded_size: usize, real_size: usize) -> Error { - Error::from_text(format!("Encoding-Error for {} {}: Padded size ({}) is smaller then the original size ({}).", for_who, name, padded_size, real_size)) +use super::{*, SectorWriter, {CDDATrack, CDDesc, Error}}; +use super::super::types::{FileType, helper::{DirectoryRecordMember, PathTableMember}, layout::Layout, *}; +use builder::SubModeBuilder; +use cdtypes::types::{cdstring::{AString, DString}, date::*, dir_record::*, helper::{round_bytes_mode2_form1, sector_count_mode2_form1, sector_count_mode2_form2}, lsb_msb::*, path_table::*, pvd as cd_pvd, sector::Mode2Form1}; +use tool_helper::{BufferedInputFile, format_if_error, open_input_file_buffered, print_warning}; +use std::{io::{Read, Seek, SeekFrom}, path::PathBuf}; + +const ROOT_DIR_NAME:&'static str = "\x00"; + +pub mod size_of { + use cdtypes::types::{sector::Mode0, helper::{sector_count_mode2_form1, sector_count_mode2_form2}}; + use crate::types::FileType; + use super::{Directory, File, FullSizeInfo, RealSizeInfo, SizeInfo, PathTable}; + + pub const SYSTEM_AREA_SECTOR_COUNT:usize = 16; + pub const PVD_SECTOR_COUNT:usize = 2; + + pub const fn system_area() -> SizeInfo { + SizeInfo{ + real_size: RealSizeInfo{bytes: None, sectors: SYSTEM_AREA_SECTOR_COUNT}, + full_size: FullSizeInfo{bytes: None, sectors: SYSTEM_AREA_SECTOR_COUNT} + } + } + + pub const fn pvd() -> SizeInfo { + SizeInfo{ + real_size: RealSizeInfo{bytes: None, sectors: PVD_SECTOR_COUNT}, + full_size: FullSizeInfo{bytes: None, sectors: PVD_SECTOR_COUNT} + } + } + + pub fn path_tables(root: &Directory) -> SizeInfo { + let path_table_size = PathTable::calculate_size_for(root); + SizeInfo{ + real_size: RealSizeInfo{bytes: Some(path_table_size), sectors: sector_count_mode2_form1(path_table_size)}, + full_size: FullSizeInfo{bytes: Some(path_table_size), sectors: sector_count_mode2_form1(path_table_size)} + } + } + + pub fn directory(dir: &Directory) -> SizeInfo { + let real_size_bytes = dir.properties.borrow().get_real_size(); + let full_size_bytes = dir.get_extended_size(); + SizeInfo{ + real_size: RealSizeInfo{bytes: Some(real_size_bytes), sectors: sector_count_mode2_form1(real_size_bytes)}, + full_size: FullSizeInfo{bytes: Some(full_size_bytes), sectors: sector_count_mode2_form1(full_size_bytes)} + } + } + + pub fn file(file: &File) -> SizeInfo { + let real_size_bytes = file.properties.get_real_size(); + let full_size_bytes = file.get_extended_size(); + if matches!(file.content, FileType::XAAudio(_)) { + SizeInfo{ + real_size: RealSizeInfo{bytes: Some(real_size_bytes), sectors: sector_count_mode2_form2(real_size_bytes)}, + full_size: FullSizeInfo{bytes: Some(full_size_bytes), sectors: sector_count_mode2_form2(full_size_bytes)} + } + } + + else { + SizeInfo{ + real_size: RealSizeInfo{bytes: Some(real_size_bytes), sectors: sector_count_mode2_form1(real_size_bytes)}, + full_size: FullSizeInfo{bytes: Some(full_size_bytes), sectors: sector_count_mode2_form1(full_size_bytes)} + } + } + } + + pub fn lead_out(sectors: usize) -> SizeInfo { + SizeInfo{ + real_size: RealSizeInfo{bytes: Some(sectors*Mode0::DATA_SIZE), sectors}, + full_size: FullSizeInfo{bytes: Some(sectors*Mode0::DATA_SIZE), sectors} + } + } +} + +pub fn calculate_length_for(element: &Layout) -> SizeInfo { + match element { + Layout::SystemArea(_) => size_of::system_area(), + Layout::PVD(_) => size_of::pvd(), + Layout::PathTables(root, _) => size_of::path_tables(&root.borrow()), + Layout::Directory(dir) => size_of::directory(&dir.borrow()), + Layout::File(file) => size_of::file(&file.borrow()), + } +} + +pub fn calculate_lbas(cd_desc: &mut CDDesc) { + let mut cur_lba = 0; + let track_offset = LBA::FIRST_TRACK_OFFSET; + + cd_desc.vol_sector_count = 0; + CDDesc::for_each_dir_mut(cd_desc.root.clone(), &|dir| {dir.update_content_size();}); + + for element in cd_desc.get_memory_layout() { + fn update_lba(properties: &mut Properties, cur_lba: usize, track_offset: usize, content_sector_size: usize) -> usize { + properties.lba.overwrite(cur_lba, track_offset); + cur_lba + content_sector_size + } + + let element_size_info = calculate_length_for(&element); + match element { + Layout::SystemArea(system_area) => { + let mut system_area = system_area.borrow_mut(); + + system_area.lba.overwrite(cur_lba, track_offset); + cur_lba += element_size_info.full_size.sectors; + }, + + Layout::PVD(pvd) => { + let mut pvd = pvd.borrow_mut(); + + pvd.lba.overwrite(cur_lba, track_offset); + cur_lba += element_size_info.full_size.sectors; + }, + + Layout::PathTables(_, path_table) => { + let mut path_table = path_table.borrow_mut(); + + path_table.lba.overwrite(cur_lba, track_offset); + path_table.size_bytes = element_size_info.full_size.bytes.unwrap_or(0); + + cur_lba += element_size_info.full_size.sectors*4; + }, + + Layout::Directory(dir) => { + let dir = dir.borrow_mut(); + let mut properties = dir.properties.borrow_mut(); + + cd_desc.vol_sector_count += element_size_info.full_size.sectors; + if properties.is_hidden { + properties.lba.overwrite(0, 0); + } + + else { + cur_lba = update_lba(&mut properties, cur_lba, track_offset, element_size_info.full_size.sectors); + } + }, + + Layout::File(file) => { + let mut file = file.borrow_mut(); + + cd_desc.vol_sector_count += element_size_info.full_size.sectors; + cur_lba = update_lba(&mut file.properties, cur_lba, track_offset, element_size_info.full_size.sectors); + } + } + } +} + +pub fn encode_image(cd_desc: &CDDesc, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { + let vol_sector_count = cd_desc.vol_sector_count; + + for element in cd_desc.get_memory_layout() { + match element { + Layout::SystemArea(system_area) => process_system_area(&mut system_area.borrow_mut(), sec_writer)?, + Layout::PVD(pvd) => process_pvd(&pvd.borrow(), cd_desc.path_table.clone(), cd_desc.root.clone(), vol_sector_count, sec_writer)?, + Layout::PathTables(root, path_table) => process_path_table(&path_table.borrow(), root, sec_writer)?, + Layout::Directory(dir) => process_directory_record(&dir.borrow(), sec_writer)?, + Layout::File(file) => process_file(&file.borrow(), sec_writer)?, + } + } + + process_lead_out(cd_desc.lead_out_sectors, sec_writer)?; + process_end_dummy_section(cd_desc.end_dummy_padding, sec_writer)?; + process_cd_da(&cd_desc.cd_da_tracks, sec_writer) +} + +fn process_system_area(system_area: &SystemArea, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { + fn write_data_zeros(sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { + write_dummy(sec_writer, 4) + } + + fn write_audio_zeros(sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { + for _ in 0..4 { + let sector = { + let mut sector = builder::create_xa_audio_zero(0); + + sector.sub_header.sub_mode.clear_audio(); + sector + }; + sec_writer.write_cd_xa_audio(sector)?; + } + + Ok(()) + } + + fn write_license_string_raw(sec_writer: &mut dyn SectorWriter, data: &[u8; Mode2Form1::DATA_SIZE]) -> Result { + let sub_mode = SubModeBuilder::new_mode1().create(); + let sector = builder::create_xa_data_for_raw(sub_mode, data); + + sec_writer.write_cd_xa_data(sector) + } + + fn write_license_file(sec_writer: &mut dyn SectorWriter, mut license_file: BufferedInputFile) -> Result<(), Error> { + fn write_license_string(sec_writer: &mut dyn SectorWriter, license_file: &mut BufferedInputFile) -> Result<(), Error> { + const LICENSE_STRING_START:u64 = 0x2488; + + if license_file.get_ref().metadata()?.len() < LICENSE_STRING_START { + return Err(Error::from_str("License file to short to contain license string. Is this is a valid license file?")); + } + + let mut license_string_buffer = [0u8; Mode2Form1::DATA_SIZE]; + + license_file.seek(SeekFrom::Start(LICENSE_STRING_START))?; + license_file.read(&mut license_string_buffer)?; + + write_license_string_raw(sec_writer, &license_string_buffer)?; + Ok(()) + } + + fn write_license_logo(sec_writer: &mut dyn SectorWriter, license_file: &mut BufferedInputFile) -> Result<(), Error> { + const LICENSE_LOGO_START:u64 = 0x2DA8; + + license_file.seek(SeekFrom::Start(LICENSE_LOGO_START))?; + for _ in 0..7 { + const LICENSE_SECTOR_REST:i64 = 0x120; + + if license_file.get_ref().metadata()?.len() < license_file.stream_position()? + LICENSE_SECTOR_REST as u64 { + return Err(Error::from_str("License file to short to contain license logo. Is this is a valid license file?")); + } + + let mut license_logo_buffer = [0u8; Mode2Form1::DATA_SIZE]; + + license_file.read(&mut license_logo_buffer)?; + license_file.seek(SeekFrom::Current(LICENSE_SECTOR_REST))?; + + let sub_mode = SubModeBuilder::new_mode1().create(); + let sector = builder::create_xa_data_for_raw(sub_mode, &license_logo_buffer); + + sec_writer.write_cd_xa_data(sector)?; + } + Ok(()) + } + + format_if_error!(write_data_zeros(sec_writer), "Writing license data zeros failed with: {error_text}")?; + format_if_error!(write_license_string(sec_writer, &mut license_file), "Writing license string from file failed with: {error_text}")?; + format_if_error!(write_license_logo(sec_writer, &mut license_file), "Writing license logo from file failed with: {error_text}")?; + format_if_error!(write_audio_zeros(sec_writer), "Writing license audio zeros failed with: {error_text}") + } + + fn write_tmd_file(sec_writer: &mut dyn SectorWriter, tmd_file: BufferedInputFile, lic_text: &Option) -> Result<(), Error> { + fn write_license_string(sec_writer: &mut dyn SectorWriter, text: &str) -> Result<(), Error> { + let text_len = text.len(); + + if text_len <= Mode2Form1::DATA_SIZE { + let mut license_string_buffer = [0u8; Mode2Form1::DATA_SIZE]; + + license_string_buffer[..text_len].copy_from_slice(text[0..text_len].as_bytes()); + write_license_string_raw(sec_writer, &license_string_buffer)?; + Ok(()) + } + + else { + Err(Error::from_text(format!("License string \"{}\" is longer then supported length {}", text, Mode2Form1::DATA_SIZE))) + } + } + + fn write_license_logo(sec_writer: &mut dyn SectorWriter, mut tmd_file: BufferedInputFile) -> Result<(), Error> { + const SECTOR_COUNT:usize = 11 - 5 + 1; + + let bytes = { + let mut bytes = vec![]; + tmd_file.read_to_end(&mut bytes)?; + bytes + }; + let mut sectors = builder::create_xa_data_for_vec(Some(SubModeBuilder::new_mode1().create()), &bytes, 0xFFu8); + if sectors.len() > SECTOR_COUNT { + return Err(Error::from_str("Provided TMD file for alt-license is larger then 8 sectors of data")); + } + + while sectors.len() < SECTOR_COUNT { + sectors.push(builder::create_xa_data_zero()); + } + + for sector in sectors { + sec_writer.write_cd_xa_data(sector)?; + } + Ok(()) + } + + let lic_text = { + if let Some(lic_text) = lic_text { + lic_text.as_ref() + } + + else { + "" + } + }; + + format_if_error!(write_data_zeros(sec_writer), "Writing alt-license data zeros failed with: {error_text}")?; + format_if_error!(write_license_string(sec_writer, lic_text), "Writing alt-license string from file failed with: {error_text}")?; + format_if_error!(write_license_logo(sec_writer, tmd_file), "Writing alt-license logo from file failed with: {error_text}")?; + format_if_error!(write_audio_zeros(sec_writer), "Writing alt-license audio zeros failed with: {error_text}") + } + + let system_area_lba = system_area.lba.get_track_relative(); + if system_area_lba != 0 { + return Err(Error::from_text(format!("System Area required to start at sector 0 of Track - found LBA: {}", system_area_lba))); + } + + fn write_tmd_license(sec_writer: &mut dyn SectorWriter, tmd_path: &PathBuf, lic_text: &Option) -> Result<(), Error> { + print_warning(format!("WARNING: An alternative license file was provided. {}", NOT_BOOTING_CD_STR)); + let tmd_file = format_if_error!(open_input_file_buffered(tmd_path), "Loading TMD file from {} failed with: {error_text}", tmd_path.to_string_lossy())?; + write_tmd_file(sec_writer, tmd_file, lic_text) + } + + const NOT_BOOTING_CD_STR:&'static str = "Some emulators (No$PSX) and some consoles (japanese/some european PS1; All PS3) will not boot this CD."; + match &system_area.license_file { + LicenseFile::Authentic(license_path) => { + match open_input_file_buffered(license_path) { + Ok(license_file) => write_license_file(sec_writer, license_file), + Err(error) => { + let err_str = format!("Loading license file from {} failed with: {}", license_path.to_string_lossy(), error); + if let LicenseFile::TMD(tmd_path, lic_text) = &system_area.backup_license_file { + print_warning(format!("{}. Now using backup license information", err_str)); + write_tmd_license(sec_writer, tmd_path, lic_text) + } + + else { + Err(Error::from_text(err_str)) + } + } + } + }, + LicenseFile::TMD(tmd_path, lic_text) => write_tmd_license(sec_writer, tmd_path, lic_text), + LicenseFile::None => { + // No license specified - filling it with zeros + print_warning(format!("WARNING: No license file provided. {}", NOT_BOOTING_CD_STR)); + write_dummy(sec_writer, size_of::SYSTEM_AREA_SECTOR_COUNT) + }, + } +} + +fn process_pvd(pvd: &PrimaryVolumeDescriptor, path_table: SharedPtr, root_dir: SharedPtr, vol_sector_count: usize, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { + const PLAYSATATION_STR:&'static str = "PLAYSTATION"; + + let path_table = validate_and_unwrap_path_table(&path_table)?; + let root_dir = root_dir.borrow(); + let pvd_lba = pvd.lba.get_track_relative(); + + if pvd_lba != 16 { + return Err(Error::from_text(format!("PVD required to start at sector 16 of Track - found LBA: {}", pvd_lba))); + } + + let mut cd_pvd = cd_pvd::PrimaryVolumeDescriptor::new(); + let now = Date::now(); + + //Config pvd here + cd_pvd.system_id = AString::from_str(PLAYSATATION_STR)?; + cd_pvd.volume_id = DString::from_str("PSX")?; + cd_pvd.vol_space_size.write(vol_sector_count as u32); + + //Set PathTable values + cd_pvd.path_table_size.write(path_table.size_bytes as u32); + cd_pvd.path_table_1.write(path_table.get_track_rel_lba_for(1, sector_count_mode2_form1) as u32); + cd_pvd.path_table_2.write(path_table.get_track_rel_lba_for(2, sector_count_mode2_form1) as u32); + cd_pvd.path_table_3.write(path_table.get_track_rel_lba_for(3, sector_count_mode2_form1) as u32); + cd_pvd.path_table_4.write(path_table.get_track_rel_lba_for(4, sector_count_mode2_form1) as u32); + + //Set Root Directory Record + write_dir_record(&mut cd_pvd.root_dir_record, &DirectoryRecordMember::new_dir(ROOT_DIR_NAME.to_owned(), &root_dir.properties.borrow()), false)?; + + //Set other stuff + cd_pvd.publisher_id = AString::from_str(pvd.publisher.as_str())?; + cd_pvd.data_preparer = AString::from_str("JABYENGINE PSXCDGEN_EX")?; + cd_pvd.app_id = AString::from_str(PLAYSATATION_STR)?; + + cd_pvd.vol_create_time = now; + + cd_pvd.cd_xa_id = ['C' as u8, 'D' as u8, '-' as u8, 'X' as u8, 'A' as u8, '0' as u8, '0' as u8, '1' as u8]; + + //Write PVD and VDT + sec_writer.write_cd_xa_data(builder::create_xa_data_for(SubModeBuilder::new_mode1().set_eor().create(), &cd_pvd))?; + sec_writer.write_cd_xa_data(builder::create_xa_data_for(SubModeBuilder::new_mode1().set_eor().set_eof().create(), &cd_pvd::VolumeDescriptorTerminator::new()))?; + Ok(()) +} + +fn process_path_table(path_table: &PathTable, root_dir: SharedPtr, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { + macro_rules! write_path_table_twice { + ($table:ident) => { + for sector in $table.clone() { + sec_writer.write_cd_xa_data(sector)?; + } + + for sector in $table { + sec_writer.write_cd_xa_data(sector)?; + } + }; + } + let mut bytes_used = 0; + let mut path_table_raw_l = vec![0u8; path_table.size_bytes]; + let mut path_table_raw_b = vec![0u8; path_table.size_bytes]; + + validate_path_table(path_table)?; + let path_table = PathTable::collect_member(&root_dir.borrow()); + + for entry in path_table { + bytes_used += unsafe{update_path_table_entry(std::mem::transmute::<&mut u8, &mut PathTableL>(&mut path_table_raw_l[bytes_used]), std::mem::transmute::<&mut u8, &mut PathTableB>(&mut path_table_raw_b[bytes_used]), entry)?}; + } + + let path_table_l = builder::create_xa_data_for_vec(None, &path_table_raw_l, 0x0u8); + let path_table_b = builder::create_xa_data_for_vec(None, &path_table_raw_b, 0x0u8); + + write_path_table_twice!(path_table_l); + write_path_table_twice!(path_table_b); + + Ok(()) +} + +fn process_directory_record(dir: &Directory, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { + if dir.properties.borrow().is_hidden { + return Ok(()); + } + + let properties = dir.properties.borrow(); + if !properties.is_size_valid() { + return Err(create_wrong_padding_error("Dir", dir.name.to_string(), properties.get_padded_size(), properties.get_real_size())); + } + + let mut dir_record = vec![0u8; properties.get_real_size()]; + let dir_length = dir_record.len(); + let mut raw_data = &mut dir_record[0..dir_length]; + + for member in dir.collect_member() { + let raw_data_len = raw_data.len(); + let bytes_written = write_dir_record(raw_data, &member, true)?; + + raw_data = &mut raw_data[bytes_written..raw_data_len]; + } + + let dir_record_sectors = builder::create_xa_data_for_vec(None, &dir_record, 0x0u8); + let dir_record_sector_count = dir_record_sectors.len(); + + if dir_record_sector_count > 1 { + return Err(Error::from_text(format!("Directory Record for {} spans {} sectors but PSX doesn't support more then one sector", dir.name.as_str().unwrap_or(""), dir_record_sector_count))); + } + + for sector in dir_record_sectors { + sec_writer.write_cd_xa_data(sector)?; + } + + let extended_sector_count = sector_count_mode2_form1(dir.properties.borrow().get_padded_size()) - dir_record_sector_count; + write_dummy(sec_writer, extended_sector_count) +} + +fn process_file(file: &File, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { + fn process_regular_file(content: &RawData, sec_writer: &mut dyn SectorWriter, padded_size: usize) -> Result<(), Error> { + let content_sectors = builder::create_xa_data_for_vec(None, content, 0x0u8); + let content_sector_count = content_sectors.len(); + + for sector in content_sectors { + sec_writer.write_cd_xa_data(sector)?; + } + + let extended_sector_count = sector_count_mode2_form1(padded_size) - content_sector_count; + write_dummy(sec_writer, extended_sector_count) + } + + fn process_cd_xa_file(content: &Vec, sec_writer: &mut dyn SectorWriter, padded_size: usize) -> Result<(), Error> { + let content_sectors = builder::create_xa_audio_for(content); + let content_sector_count = content_sectors.len(); + + for sector in content_sectors { + sec_writer.write_interleaved(sector)?; + } + + let extended_sector_count = sector_count_mode2_form2(padded_size) - content_sector_count; + for _ in 0..extended_sector_count { + sec_writer.write_cd_xa_audio(builder::create_xa_audio_zero(0))?; + } + + Ok(()) + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + if !file.properties.is_size_valid() { + return Err(create_wrong_padding_error("File", file.name.to_string(), file.properties.get_padded_size(), file.properties.get_real_size())); + } + + match &file.content { + FileType::Regular(raw) => process_regular_file(raw, sec_writer, file.properties.get_padded_size()), + FileType::XAAudio(raw) => process_cd_xa_file(raw, sec_writer, file.properties.get_padded_size()), + FileType::Main(_, _) => Err(Error::from_str("Trying to encode an unprocessed main file")), + FileType::Overlay(_, _) => Err(Error::from_str("Trying to encode an unprocessed overlay file")), + } +} + +fn write_dummy(sec_writer: &mut dyn SectorWriter, sectors: usize) -> Result<(), Error> { + for _ in 0..sectors { + sec_writer.write_cd_xa_data(builder::create_xa_data_zero())?; + } + Ok(()) +} + +fn process_lead_out(sectors: usize, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { + for _ in 0..sectors { + sec_writer.write_empty(builder::create_mode0_zero())?; + } + Ok(()) +} + +fn process_end_dummy_section(padding: usize, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { + // The padding required for the PS3 + write_dummy(sec_writer, sector_count_mode2_form1(padding)) +} + +fn process_cd_da(cd_da_tracks: &Vec, sec_writer: &mut dyn SectorWriter) -> Result<(), Error> { + for cd_da_track in cd_da_tracks { + // The padding required for CDDA to start on a full second + if cd_da_track.align { + let missing_sectors = sec_writer.sectors_to_next_second(); + write_dummy(sec_writer, missing_sectors)?; + } + + sec_writer.cd_da_start()?; + for audio in builder::create_audio_for_vec(&cd_da_track.samples) { + sec_writer.write_audio(audio)?; + } + } + Ok(()) +} + +fn validate_path_table(path_table: &PathTable) -> Result<(), Error> { + if path_table.size_bytes > Mode2Form1::DATA_SIZE { + Err(Error::from_text(format!("Path Tables are not allowed to be bigger then {} bytes - Path Table has {} bytes", Mode2Form1::DATA_SIZE, path_table.size_bytes))) + } + + else { + Ok(()) + } +} + +fn validate_and_unwrap_path_table(path_table: &SharedPtr) -> Result, Error> { + let path_table = path_table.borrow(); + + validate_path_table(&path_table)?; + Ok(path_table) +} + +fn update_path_table_entry(path_table_l: &mut PathTableL, path_table_b: &mut PathTableB, entry: PathTableMember) -> Result { + let name_len = entry.name.len(); + if name_len > 8 { + return Err(Error::from_text(format!("Directory name can not exceed size of 8 characters but folder {} has {} characters", entry.name, name_len))); + } + + unsafe{ + let name = entry.name.as_str(); + + path_table_l.new(name); + path_table_b.new(name); + } + + path_table_l.directory_logical_block.write(entry.track_rel_lba as u32); + path_table_b.directory_logical_block.write(entry.track_rel_lba as u32); + path_table_l.parent_table_id.write(entry.parent_table_id as u16); + path_table_b.parent_table_id.write(entry.parent_table_id as u16); + + Ok(path_table_l.get_size()) +} + +fn create_dir_record_raw<'a>(dst: &'a mut [u8], name: &str, track_rel_lba: u32, size_bytes: u32, system_use: Option) -> Result<&'a mut DirectoryRecord, Error> { + let has_system_use = system_use.is_some(); + let bytes_needed = DirectoryRecord::calculate_size_for(name, has_system_use); + + if dst.len() < bytes_needed { + return Err(Error::from_text(format!("DirectoryRecord for entry {} needs {} bytes but {} bytes were provided", name, bytes_needed, dst.len()))); + } + + unsafe { + let dir_record = std::mem::transmute::<&mut u8, &mut DirectoryRecord>(&mut dst[0]); + dir_record.new(name, has_system_use); + + dir_record.data_block_number.write(track_rel_lba); + dir_record.data_size.write(size_bytes); + dir_record.time_stamp = SmallDate::now(); + + if let Some(system_use) = system_use { + if let Some(record_system_use) = dir_record.get_cdxa_system_use_mut() { + *record_system_use = system_use; + } + } + + Ok(dir_record) + } +} + +fn write_dir_record(dir_record: &mut [u8], dir_member: &DirectoryRecordMember, has_system_use: bool) -> Result { + match dir_member { + DirectoryRecordMember::Directory{name, track_rel_lba, real_size} => { + let system_use = { + if has_system_use { + let mut system_use = CDXASystemUse::default(); + + system_use.file_attribute.set_mode2(); + system_use.file_attribute.set_directory(); + + Some(system_use) + } + + else { + None + } + }; + + let dir_record = create_dir_record_raw(dir_record, name.as_str(), *track_rel_lba as u32, round_bytes_mode2_form1(*real_size as usize) as u32, system_use)?; + + dir_record.set_directory(); + return Ok(dir_record.length[0] as usize); + }, + + DirectoryRecordMember::File{name, track_rel_lba, real_size} => { + let system_use = { + if has_system_use { + let mut system_use = CDXASystemUse::default(); + + system_use.file_attribute.set_mode2(); + Some(system_use) + } + + else { + None + } + }; + + let dir_record = create_dir_record_raw(dir_record, name.as_str(), *track_rel_lba as u32, *real_size as u32, system_use)?; + + dir_record.set_file(); + return Ok(dir_record.length[0] as usize); + } + } +} + +fn create_wrong_padding_error(for_who: &str, name: String, padded_size: usize, real_size: usize) -> Error { + Error::from_text(format!("Encoding-Error for {} {}: Padded size ({}) is smaller then the original size ({}).", for_who, name, padded_size, real_size)) } \ No newline at end of file diff --git a/src/Tools/psxcdgen_ex/src/main.rs b/src/Tools/psxcdgen_ex/src/main.rs index 13e63f9c..0082b9f0 100644 --- a/src/Tools/psxcdgen_ex/src/main.rs +++ b/src/Tools/psxcdgen_ex/src/main.rs @@ -1,62 +1,62 @@ -use clap::Parser; -use psxcdgen_ex::{file_writer::{ImageType, write_image}, config_reader}; -use std::path::PathBuf; -use tool_helper::{Error, exit_with_error, read_file_to_string}; - -#[derive(Parser)] -#[clap(about = "Creates an ISO image from a description file", long_about = None)] -struct CommandLine { - #[clap(value_enum, value_parser, help="Specifies the disc image type")] - output_type: ImageType, - - #[clap(short='o', help="Output path; Some OUTPUT_TYPE might create additional files with different endings")] - output_file: PathBuf, - - #[clap(long="list", id="Path to file", help="If set will list the CD content to stdout; With path will output list to file")] - list_content: Option>, - - #[clap(value_parser, help="Input XML path for creating the image")] - input_file: PathBuf, -} - -fn run_main(cmd_line: CommandLine) -> Result<(), Error> { - const PKG_MINIMUM_CONTENT_SIZE:usize = 512*1024; - - let (mut desc, lba_embedded_files) = psxcdgen_ex::process(config_reader::parse_xml(read_file_to_string(&cmd_line.input_file)?)?)?; - let file_map = desc.create_file_map(); - - psxcdgen_ex::process_files(file_map, lba_embedded_files)?; - let content_size = desc.get_content_size(); - if content_size < PKG_MINIMUM_CONTENT_SIZE { - let missing_size = PKG_MINIMUM_CONTENT_SIZE - content_size; - desc.end_dummy_padding = missing_size; - tool_helper::print_warning(format!("Content size {}b smaller then {}b.\nCD will be padded with {}b to work as a .pkg", content_size, PKG_MINIMUM_CONTENT_SIZE, missing_size)); - } - - if desc.lead_out_sectors == 0 { - tool_helper::print_warning(format!("Consider adding a 2 second lead-out to your track (Add attribute 'lead-out=\"0:2:0\"' to your Track) for supporting the PS3")); - } - - write_image(&desc, cmd_line.output_type, cmd_line.output_file)?; - - if let Some(list_content_option) = cmd_line.list_content { - psxcdgen_ex::dump_content(&desc, tool_helper::open_output(&list_content_option)?) - } - - else { - Ok(()) - } -} - -fn main() { - match CommandLine::try_parse() { - Ok(cmd_line) => { - if let Err(error) = run_main(cmd_line) { - exit_with_error(error) - } - }, - Err(error) => { - println!("{}", error) - } - } +use clap::Parser; +use psxcdgen_ex::{file_writer::{ImageType, write_image}, config_reader}; +use std::path::PathBuf; +use tool_helper::{Error, exit_with_error, read_file_to_string}; + +#[derive(Parser)] +#[clap(about = "Creates an ISO image from a description file", long_about = None)] +struct CommandLine { + #[clap(value_enum, value_parser, help="Specifies the disc image type")] + output_type: ImageType, + + #[clap(short='o', help="Output path; Some OUTPUT_TYPE might create additional files with different endings")] + output_file: PathBuf, + + #[clap(long="list", id="Path to file", help="If set will list the CD content to stdout; With path will output list to file")] + list_content: Option>, + + #[clap(value_parser, help="Input XML path for creating the image")] + input_file: PathBuf, +} + +fn run_main(cmd_line: CommandLine) -> Result<(), Error> { + const PKG_MINIMUM_CONTENT_SIZE:usize = 512*1024; + + let (mut desc, lba_embedded_files) = psxcdgen_ex::process(config_reader::parse_xml(read_file_to_string(&cmd_line.input_file)?)?)?; + let file_map = desc.create_file_map(); + + psxcdgen_ex::process_files(file_map, lba_embedded_files)?; + let content_size = desc.get_content_size(); + if content_size < PKG_MINIMUM_CONTENT_SIZE { + let missing_size = PKG_MINIMUM_CONTENT_SIZE - content_size; + desc.end_dummy_padding = missing_size; + tool_helper::print_warning(format!("Content size {}b smaller then {}b.\nCD will be padded with {}b to work as a .pkg", content_size, PKG_MINIMUM_CONTENT_SIZE, missing_size)); + } + + if desc.lead_out_sectors == 0 { + tool_helper::print_warning(format!("Consider adding a 2 second lead-out to your track (Add attribute 'lead-out=\"0:2:0\"' to your Track) for supporting the PS3")); + } + + write_image(&desc, cmd_line.output_type, cmd_line.output_file)?; + + if let Some(list_content_option) = cmd_line.list_content { + psxcdgen_ex::dump_content(&desc, tool_helper::open_output(&list_content_option)?) + } + + else { + Ok(()) + } +} + +fn main() { + match CommandLine::try_parse() { + Ok(cmd_line) => { + if let Err(error) = run_main(cmd_line) { + exit_with_error(error) + } + }, + Err(error) => { + println!("{}", error) + } + } } \ No newline at end of file diff --git a/src/Tools/psxcdgen_ex/src/types/overlay/main.rs b/src/Tools/psxcdgen_ex/src/types/overlay/main.rs index 7417c63c..a1f6f48e 100644 --- a/src/Tools/psxcdgen_ex/src/types/overlay/main.rs +++ b/src/Tools/psxcdgen_ex/src/types/overlay/main.rs @@ -1,7 +1,7 @@ -use crate::types::RawData; - -pub fn skip_to_lba_area(content: &mut RawData) -> &mut [u8] { - const PSX_HEADER_SIZE:usize = 2048; - - &mut content[PSX_HEADER_SIZE..] +use crate::types::RawData; + +pub fn skip_to_lba_area(content: &mut RawData) -> &mut [u8] { + const PSX_HEADER_SIZE:usize = 2048; + + &mut content[PSX_HEADER_SIZE..] } \ No newline at end of file diff --git a/src/Tools/psxcdread/Makefile b/src/Tools/psxcdread/Makefile index 2da0ca78..e7db97d4 100644 --- a/src/Tools/psxcdread/Makefile +++ b/src/Tools/psxcdread/Makefile @@ -1,13 +1,13 @@ -include ../Common.mk - -ARTIFACT = psxcdread - -.PHONY: $(WINDOWS_ARTIFACT) $(UNIX_ARTIFACT) -$(WINDOWS_ARTIFACT): - $(call cargo_windows_default) - -$(UNIX_ARTIFACT): - $(call cargo_unix_default) - -all-windows: $(WINDOWS_ARTIFACT) +include ../Common.mk + +ARTIFACT = psxcdread + +.PHONY: $(WINDOWS_ARTIFACT) $(UNIX_ARTIFACT) +$(WINDOWS_ARTIFACT): + $(call cargo_windows_default) + +$(UNIX_ARTIFACT): + $(call cargo_unix_default) + +all-windows: $(WINDOWS_ARTIFACT) all: $(UNIX_ARTIFACT) \ No newline at end of file diff --git a/src/Tools/psxfileconv/Makefile b/src/Tools/psxfileconv/Makefile index 8f91f632..fa4a7469 100644 --- a/src/Tools/psxfileconv/Makefile +++ b/src/Tools/psxfileconv/Makefile @@ -1,13 +1,13 @@ -include ../Common.mk - -ARTIFACT = psxfileconv - -.PHONY: $(WINDOWS_ARTIFACT) $(UNIX_ARTIFACT) -$(WINDOWS_ARTIFACT): - $(call cargo_windows_default) - -$(UNIX_ARTIFACT): - $(call cargo_unix_default) - -all-windows: $(WINDOWS_ARTIFACT) +include ../Common.mk + +ARTIFACT = psxfileconv + +.PHONY: $(WINDOWS_ARTIFACT) $(UNIX_ARTIFACT) +$(WINDOWS_ARTIFACT): + $(call cargo_windows_default) + +$(UNIX_ARTIFACT): + $(call cargo_unix_default) + +all-windows: $(WINDOWS_ARTIFACT) all: $(UNIX_ARTIFACT) \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/audio/mod.rs b/src/Tools/psxfileconv/src/audio/mod.rs index 243d7e8d..3817660a 100644 --- a/src/Tools/psxfileconv/src/audio/mod.rs +++ b/src/Tools/psxfileconv/src/audio/mod.rs @@ -1,2 +1,2 @@ -pub mod xa; +pub mod xa; pub mod vag; \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/audio/vag/mod.rs b/src/Tools/psxfileconv/src/audio/vag/mod.rs index af632358..e77b4d23 100644 --- a/src/Tools/psxfileconv/src/audio/vag/mod.rs +++ b/src/Tools/psxfileconv/src/audio/vag/mod.rs @@ -1,169 +1,169 @@ -pub mod types; - -use clap::Args; -use std::{io::Write, str::FromStr}; -use tool_helper::{Error, Input}; -use types::{LPC, MonoADPCMIterator, VAGADPCM, VAGHeader}; - -#[derive(Args)] -pub struct Arguments { - #[clap(long, help="Specify the file name to be embedded in the header", default_value = "File name without extensions up to 16 characters")] - name: Option, - #[clap(short='l', help="Set a loop at the specified time", value_name = ":.[-:.]", value_parser = clap::value_parser!(Loop))] - r#loop: Option -} - -#[derive(Clone)] -pub struct Loop { - start_time_sec: f64, - end_time_sec: Option, -} - -impl Loop { - const END_DELIMITER: char = '-'; - const MIN_DELIMITER: char = ':'; - - fn parse(str: Option<&str>) -> Result, String> { - fn print_sec_conversion_error(str: &str, error: &dyn core::fmt::Display) -> String { - format!("Converting specified seconds \"{}\" failed with: {}", str, error) - } - - if let Some(str) = str { - let time = { - if let Some(min_delim_idx) = str.find(Self::MIN_DELIMITER) { - let (min, sec) = str.split_at(min_delim_idx); - let min = min.parse::().map_err(|e| format!("Converting specified minutes \"{}\" failed with: {}", min, e))?; - let sec = sec.trim_start_matches(Self::MIN_DELIMITER).parse::().map_err(|e| print_sec_conversion_error(sec, &e))?; - - (min*60) as f64 + sec - } - - else { - str.parse::().map_err(|e| print_sec_conversion_error(str, &e))? - } - }; - Ok(Some(time)) - } - - else { - Ok(None) - } - } -} - -impl FromStr for Loop { - type Err = String; - - fn from_str(arg: &str) -> Result { - let mut args = arg.split(Self::END_DELIMITER); - let start_time_sec = Self::parse(args.next()).map_err(|e| format!("{}", e))?.ok_or_else(|| format!("A start time is required for a loop"))?; - let end_time_sec = Self::parse(args.next()).map_err(|e| format!("{}", e))?; - - Ok(Loop{start_time_sec, end_time_sec}) - } -} - -struct LoopInfo { - start_sample: usize, - end_sample: usize, -} - -impl LoopInfo { - fn create(r#loop: &Loop, sample_frequency: u32, vagadpcm_count: usize) -> LoopInfo { - fn calculate_sample(time_sec: f64, vag_frequency: f64) -> usize { - (time_sec*vag_frequency) as usize - } - - let sample_frequency = sample_frequency as f64 / VAGADPCM::ADPCM_SAMPLES_PER_VAGADPCM as f64; - let start_sample = calculate_sample(r#loop.start_time_sec, sample_frequency); - let end_sample = { - if let Some(end_time_sec) = r#loop.end_time_sec { - let end_sample = calculate_sample(end_time_sec, sample_frequency); - if end_sample > vagadpcm_count {vagadpcm_count} else {end_sample} - } - - else { - vagadpcm_count - } - }; - - LoopInfo{start_sample, end_sample} - } - - fn is_loop_start_reached(&self, sample: usize) -> bool { - self.start_sample == sample - } - - fn is_loop_end_reached(&self, sample: usize) -> bool { - self.end_sample == sample - } -} - -pub fn convert(args: Arguments, output_file_path: &Option, input: Input, output: &mut dyn Write) -> Result<(), Error> { - let mut wav_file = hound::WavReader::new(input)?; - let wav_header = wav_file.spec(); - - validate(&wav_header)?; - - let vagadpcm_samples = VAGHeader::expected_vagadpcm_samples(wav_file.len()) + 1; - let sample_info = args.r#loop.map(|v| LoopInfo::create(&v, wav_header.sample_rate, vagadpcm_samples as usize)); - let mut lpc = LPC::empty(); - - tool_helper::raw::write_raw(output, &VAGHeader::create(vagadpcm_samples, wav_header.sample_rate, &get_name_for_file_header(args.name, output_file_path))?)?; - for (sample_id, adpcm_sample) in MonoADPCMIterator::create(wav_file.samples::()).enumerate() { - let (mut vagadpcm, new_lpc) = VAGADPCM::create(adpcm_sample?, lpc); - - if let Some(sample_info) = &sample_info { - if sample_info.is_loop_start_reached(sample_id) { - vagadpcm = vagadpcm.set_loop_start(); - } - - if sample_info.is_loop_end_reached(sample_id + 1) { - vagadpcm = vagadpcm.set_loop_end_repeat(); - } - } - - tool_helper::raw::write_raw(output, &vagadpcm)?; - lpc = new_lpc; - } - - if sample_info.is_none() { - tool_helper::raw::write_raw(output, &VAGADPCM::end())?; - } - Ok(()) -} - -fn validate(wav_header: &hound::WavSpec) -> Result<(), Error> { - if wav_header.sample_format != hound::SampleFormat::Int { - return Err(Error::from_str("VAG: Only integer samples are supported as input.")); - } - - if wav_header.bits_per_sample != 16 { - return Err(Error::from_str("VAG: Only 16bits samples are currently supported as input.")); - } - - if wav_header.channels != 1 { - return Err(Error::from_str("VAG: Only mono samples are currently supported")); - } - - Ok(()) -} - -fn get_name_for_file_header(name: Option, output_file_path: &Option) -> String { - if let Some(name) = name { - return name; - } - - if let Some(output_file_path) = output_file_path { - if let Some(file_name) = output_file_path.file_name() { - let mut string = file_name.to_string_lossy().to_string(); - - if let Some(idx) = string.rfind('.') { - string.replace_range(idx.., ""); - } - return string; - } - } - - return "".to_owned(); +pub mod types; + +use clap::Args; +use std::{io::Write, str::FromStr}; +use tool_helper::{Error, Input}; +use types::{LPC, MonoADPCMIterator, VAGADPCM, VAGHeader}; + +#[derive(Args)] +pub struct Arguments { + #[clap(long, help="Specify the file name to be embedded in the header", default_value = "File name without extensions up to 16 characters")] + name: Option, + #[clap(short='l', help="Set a loop at the specified time", value_name = ":.[-:.]", value_parser = clap::value_parser!(Loop))] + r#loop: Option +} + +#[derive(Clone)] +pub struct Loop { + start_time_sec: f64, + end_time_sec: Option, +} + +impl Loop { + const END_DELIMITER: char = '-'; + const MIN_DELIMITER: char = ':'; + + fn parse(str: Option<&str>) -> Result, String> { + fn print_sec_conversion_error(str: &str, error: &dyn core::fmt::Display) -> String { + format!("Converting specified seconds \"{}\" failed with: {}", str, error) + } + + if let Some(str) = str { + let time = { + if let Some(min_delim_idx) = str.find(Self::MIN_DELIMITER) { + let (min, sec) = str.split_at(min_delim_idx); + let min = min.parse::().map_err(|e| format!("Converting specified minutes \"{}\" failed with: {}", min, e))?; + let sec = sec.trim_start_matches(Self::MIN_DELIMITER).parse::().map_err(|e| print_sec_conversion_error(sec, &e))?; + + (min*60) as f64 + sec + } + + else { + str.parse::().map_err(|e| print_sec_conversion_error(str, &e))? + } + }; + Ok(Some(time)) + } + + else { + Ok(None) + } + } +} + +impl FromStr for Loop { + type Err = String; + + fn from_str(arg: &str) -> Result { + let mut args = arg.split(Self::END_DELIMITER); + let start_time_sec = Self::parse(args.next()).map_err(|e| format!("{}", e))?.ok_or_else(|| format!("A start time is required for a loop"))?; + let end_time_sec = Self::parse(args.next()).map_err(|e| format!("{}", e))?; + + Ok(Loop{start_time_sec, end_time_sec}) + } +} + +struct LoopInfo { + start_sample: usize, + end_sample: usize, +} + +impl LoopInfo { + fn create(r#loop: &Loop, sample_frequency: u32, vagadpcm_count: usize) -> LoopInfo { + fn calculate_sample(time_sec: f64, vag_frequency: f64) -> usize { + (time_sec*vag_frequency) as usize + } + + let sample_frequency = sample_frequency as f64 / VAGADPCM::ADPCM_SAMPLES_PER_VAGADPCM as f64; + let start_sample = calculate_sample(r#loop.start_time_sec, sample_frequency); + let end_sample = { + if let Some(end_time_sec) = r#loop.end_time_sec { + let end_sample = calculate_sample(end_time_sec, sample_frequency); + if end_sample > vagadpcm_count {vagadpcm_count} else {end_sample} + } + + else { + vagadpcm_count + } + }; + + LoopInfo{start_sample, end_sample} + } + + fn is_loop_start_reached(&self, sample: usize) -> bool { + self.start_sample == sample + } + + fn is_loop_end_reached(&self, sample: usize) -> bool { + self.end_sample == sample + } +} + +pub fn convert(args: Arguments, output_file_path: &Option, input: Input, output: &mut dyn Write) -> Result<(), Error> { + let mut wav_file = hound::WavReader::new(input)?; + let wav_header = wav_file.spec(); + + validate(&wav_header)?; + + let vagadpcm_samples = VAGHeader::expected_vagadpcm_samples(wav_file.len()) + 1; + let sample_info = args.r#loop.map(|v| LoopInfo::create(&v, wav_header.sample_rate, vagadpcm_samples as usize)); + let mut lpc = LPC::empty(); + + tool_helper::raw::write_raw(output, &VAGHeader::create(vagadpcm_samples, wav_header.sample_rate, &get_name_for_file_header(args.name, output_file_path))?)?; + for (sample_id, adpcm_sample) in MonoADPCMIterator::create(wav_file.samples::()).enumerate() { + let (mut vagadpcm, new_lpc) = VAGADPCM::create(adpcm_sample?, lpc); + + if let Some(sample_info) = &sample_info { + if sample_info.is_loop_start_reached(sample_id) { + vagadpcm = vagadpcm.set_loop_start(); + } + + if sample_info.is_loop_end_reached(sample_id + 1) { + vagadpcm = vagadpcm.set_loop_end_repeat(); + } + } + + tool_helper::raw::write_raw(output, &vagadpcm)?; + lpc = new_lpc; + } + + if sample_info.is_none() { + tool_helper::raw::write_raw(output, &VAGADPCM::end())?; + } + Ok(()) +} + +fn validate(wav_header: &hound::WavSpec) -> Result<(), Error> { + if wav_header.sample_format != hound::SampleFormat::Int { + return Err(Error::from_str("VAG: Only integer samples are supported as input.")); + } + + if wav_header.bits_per_sample != 16 { + return Err(Error::from_str("VAG: Only 16bits samples are currently supported as input.")); + } + + if wav_header.channels != 1 { + return Err(Error::from_str("VAG: Only mono samples are currently supported")); + } + + Ok(()) +} + +fn get_name_for_file_header(name: Option, output_file_path: &Option) -> String { + if let Some(name) = name { + return name; + } + + if let Some(output_file_path) = output_file_path { + if let Some(file_name) = output_file_path.file_name() { + let mut string = file_name.to_string_lossy().to_string(); + + if let Some(idx) = string.rfind('.') { + string.replace_range(idx.., ""); + } + return string; + } + } + + return "".to_owned(); } \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/audio/vag/types.rs b/src/Tools/psxfileconv/src/audio/vag/types.rs index 9821dbc2..9a63558a 100644 --- a/src/Tools/psxfileconv/src/audio/vag/types.rs +++ b/src/Tools/psxfileconv/src/audio/vag/types.rs @@ -1,226 +1,226 @@ -use bitflags::bitflags; -use tool_helper::{raw::RawConversion, Error}; - -#[repr(packed)] -#[derive(Clone)] -pub struct VAGHeader { - _id: [u8; 4], - version: u32, - _reserved: u32, - data_size: u32, - sampling_frequency: u32, - _reserved2: [u8; 12], - _name: [u8; 16] -} - -impl VAGHeader { - const SIZE: usize = std::mem::size_of::(); - const ID: [u8; 4] = ['V' as u8, 'A' as u8, 'G' as u8, 'p' as u8]; - const VERSION: u32 = 0x02; - const RESERVED: u32 = 0; - const RESERVED2: [u8; 12] = [0; 12]; - - pub fn expected_vagadpcm_samples(adpcm_samples: u32) -> u32 { - ((adpcm_samples as usize + (VAGADPCM::ADPCM_SAMPLES_PER_VAGADPCM - 1))/VAGADPCM::ADPCM_SAMPLES_PER_VAGADPCM) as u32 - } - - pub fn create(vagadpcm_samples: u32, sampling_frequency: u32, name: &str) -> Result { - let data_size = vagadpcm_samples*VAGADPCM::SIZE as u32; - let name = { - if !name.is_ascii() { - return Err(Error::from_text(format!("File name {} is not ascii", name))); - } - - let name_length = if name.len() > 16 {16} else {name.len()}; - let mut new_name = [0u8; 16]; - - new_name[..name_length].copy_from_slice(&name.as_bytes()[..name_length]); - new_name - }; - - Ok(VAGHeader{ - _id: VAGHeader::ID, - version: VAGHeader::VERSION, - _reserved: VAGHeader::RESERVED, - data_size: data_size, - sampling_frequency: sampling_frequency, - _reserved2: VAGHeader::RESERVED2, - _name: name - }) - } -} - -impl RawConversion<{VAGHeader::SIZE}> for VAGHeader { - fn convert_to_raw(&self) -> [u8; VAGHeader::SIZE] { - unsafe { - let mut vag_header = self.clone(); - - vag_header.version = self.version.to_be(); - vag_header.data_size = self.data_size.to_be(); - vag_header.sampling_frequency = self.sampling_frequency.to_be(); - - let data: [u8; VAGHeader::SIZE] = std::mem::transmute(vag_header); - data - } - } -} - -bitflags! { - struct VAGFlagBits : u8 { - const LoopEnd = (1 << 0); - const Repeat = (1 << 1); - const LoopStart = (1 << 2); - } -} - -pub struct VAGADPCM { - data: [u32; 4] -} - -impl VAGADPCM { - const SIZE: usize = std::mem::size_of::(); - pub(super) const ADPCM_SAMPLES_PER_VAGADPCM:usize = 28; - - pub fn empty() -> VAGADPCM { - VAGADPCM{data: [0; 4]} - } - - fn create_for_filter_shift(filter: u32, shift: u32) -> VAGADPCM { - VAGADPCM{data: [(12 - shift) | filter << 4, 0, 0, 0]} - } - - pub fn end() -> VAGADPCM { - VAGADPCM::empty().set_loop_self() - } - - pub fn create(samples: ADPCMSampleForVag, lpc_tap: LPC) -> (VAGADPCM, LPC) { - fn cap_value(value: i32, min: i32, max: i32) -> i32 { - if value < min { - min - } - - else if value > max { - max - } - - else { - value - } - } - let mut best_frame = VAGADPCM::empty(); - let mut best_tap = LPC::empty(); - let mut best_error = std::u64::MAX as u64; - - for (filter_id, filter) in LPC::FILTERS.iter().enumerate() { - for shift in 0..=12 { - let mut this_frame = VAGADPCM::create_for_filter_shift(filter_id as u32, shift); - let this_tap = lpc_tap.clone(); - let mut this_error = 0; - - for (sample_id, sample) in samples.iter().enumerate() { - let x = *sample as i32; - let p = (this_tap.first*filter.first + this_tap.second*filter.second + 32) >> 6; - let r = x - p; - let q = cap_value((r + (((1 << shift) - (r < 0) as i32) >> 1)) >> shift, -8, 7); - let y = cap_value(p + (q << shift), std::i16::MIN as i32, std::i16::MAX as i32); - let e = y - x; - - this_frame.data[(sample_id+4)/8] |= ((q&0xF) << (((sample_id + 4)%8)*4)) as u32; - this_error += (e*e) as u64; - } - - if this_error < best_error { - best_tap = this_tap; - best_error = this_error; - best_frame = this_frame; - } - } - } - (best_frame, best_tap) - } - - fn set_vag_flags(&mut self, flags: VAGFlagBits) { - let mut first_sample = self.data[0].to_ne_bytes(); - - first_sample[1] = flags.bits(); - self.data[0] = u32::from_ne_bytes(first_sample); - } - - pub fn set_loop_start(mut self) -> Self { - self.set_vag_flags(VAGFlagBits::LoopStart); - self - } - - pub fn set_loop_end_repeat(mut self) -> Self { - self.set_vag_flags(VAGFlagBits::LoopEnd | VAGFlagBits::Repeat); - self - } - - pub fn set_loop_self(mut self) -> Self { - self.set_vag_flags(VAGFlagBits::LoopStart | VAGFlagBits::LoopEnd); - self - } -} - -impl RawConversion<{VAGADPCM::SIZE}> for VAGADPCM { - fn convert_to_raw(&self) -> [u8; VAGADPCM::SIZE] { - unsafe { - let data: [u8; VAGADPCM::SIZE] = std::mem::transmute_copy(&self as &VAGADPCM); - data - } - } -} - -#[derive(Clone)] -pub struct LPC { - first: i32, - second: i32 -} - -impl LPC { - const FILTERS: [LPC; 5] = [ - LPC{first: 0, second: 0}, - LPC{first: 60, second: 0}, - LPC{first: 115, second: -52}, - LPC{first: 98, second: -55}, - LPC{first: 122, second: -60} - ]; - - pub fn empty() -> LPC { - LPC{first: 0, second: 0} - } -} - -pub type ADPCMSampleForVag = [i16; VAGADPCM::ADPCM_SAMPLES_PER_VAGADPCM]; - -pub struct MonoADPCMIterator>> { - iter: I -} - -impl>> MonoADPCMIterator{ - pub fn create(iter: I) -> MonoADPCMIterator { - MonoADPCMIterator{iter} - } -} - -impl>> std::iter::Iterator for MonoADPCMIterator { - type Item = Result<[i16; VAGADPCM::ADPCM_SAMPLES_PER_VAGADPCM], Error>; - - fn next(&mut self) -> Option { - const STREAM_GONE_ERROR: &'static str = "Reading ADPCM sample failed"; - - if let Some(next_sample) = self.iter.next() { - let Ok(next_sample) = next_sample else {return Some(Err(Error::from_str(STREAM_GONE_ERROR)));}; - - let mut sample = [0;VAGADPCM::ADPCM_SAMPLES_PER_VAGADPCM]; - sample[0] = next_sample; - - for idx in 1..VAGADPCM::ADPCM_SAMPLES_PER_VAGADPCM { - let Ok(next_sample) = self.iter.next().unwrap_or(Ok(0)) else {return Some(Err(Error::from_str(STREAM_GONE_ERROR)));}; - sample[idx] = next_sample; - } - return Some(Ok(sample)); - } - None - } +use bitflags::bitflags; +use tool_helper::{raw::RawConversion, Error}; + +#[repr(packed)] +#[derive(Clone)] +pub struct VAGHeader { + _id: [u8; 4], + version: u32, + _reserved: u32, + data_size: u32, + sampling_frequency: u32, + _reserved2: [u8; 12], + _name: [u8; 16] +} + +impl VAGHeader { + const SIZE: usize = std::mem::size_of::(); + const ID: [u8; 4] = ['V' as u8, 'A' as u8, 'G' as u8, 'p' as u8]; + const VERSION: u32 = 0x02; + const RESERVED: u32 = 0; + const RESERVED2: [u8; 12] = [0; 12]; + + pub fn expected_vagadpcm_samples(adpcm_samples: u32) -> u32 { + ((adpcm_samples as usize + (VAGADPCM::ADPCM_SAMPLES_PER_VAGADPCM - 1))/VAGADPCM::ADPCM_SAMPLES_PER_VAGADPCM) as u32 + } + + pub fn create(vagadpcm_samples: u32, sampling_frequency: u32, name: &str) -> Result { + let data_size = vagadpcm_samples*VAGADPCM::SIZE as u32; + let name = { + if !name.is_ascii() { + return Err(Error::from_text(format!("File name {} is not ascii", name))); + } + + let name_length = if name.len() > 16 {16} else {name.len()}; + let mut new_name = [0u8; 16]; + + new_name[..name_length].copy_from_slice(&name.as_bytes()[..name_length]); + new_name + }; + + Ok(VAGHeader{ + _id: VAGHeader::ID, + version: VAGHeader::VERSION, + _reserved: VAGHeader::RESERVED, + data_size: data_size, + sampling_frequency: sampling_frequency, + _reserved2: VAGHeader::RESERVED2, + _name: name + }) + } +} + +impl RawConversion<{VAGHeader::SIZE}> for VAGHeader { + fn convert_to_raw(&self) -> [u8; VAGHeader::SIZE] { + unsafe { + let mut vag_header = self.clone(); + + vag_header.version = self.version.to_be(); + vag_header.data_size = self.data_size.to_be(); + vag_header.sampling_frequency = self.sampling_frequency.to_be(); + + let data: [u8; VAGHeader::SIZE] = std::mem::transmute(vag_header); + data + } + } +} + +bitflags! { + struct VAGFlagBits : u8 { + const LoopEnd = (1 << 0); + const Repeat = (1 << 1); + const LoopStart = (1 << 2); + } +} + +pub struct VAGADPCM { + data: [u32; 4] +} + +impl VAGADPCM { + const SIZE: usize = std::mem::size_of::(); + pub(super) const ADPCM_SAMPLES_PER_VAGADPCM:usize = 28; + + pub fn empty() -> VAGADPCM { + VAGADPCM{data: [0; 4]} + } + + fn create_for_filter_shift(filter: u32, shift: u32) -> VAGADPCM { + VAGADPCM{data: [(12 - shift) | filter << 4, 0, 0, 0]} + } + + pub fn end() -> VAGADPCM { + VAGADPCM::empty().set_loop_self() + } + + pub fn create(samples: ADPCMSampleForVag, lpc_tap: LPC) -> (VAGADPCM, LPC) { + fn cap_value(value: i32, min: i32, max: i32) -> i32 { + if value < min { + min + } + + else if value > max { + max + } + + else { + value + } + } + let mut best_frame = VAGADPCM::empty(); + let mut best_tap = LPC::empty(); + let mut best_error = std::u64::MAX as u64; + + for (filter_id, filter) in LPC::FILTERS.iter().enumerate() { + for shift in 0..=12 { + let mut this_frame = VAGADPCM::create_for_filter_shift(filter_id as u32, shift); + let this_tap = lpc_tap.clone(); + let mut this_error = 0; + + for (sample_id, sample) in samples.iter().enumerate() { + let x = *sample as i32; + let p = (this_tap.first*filter.first + this_tap.second*filter.second + 32) >> 6; + let r = x - p; + let q = cap_value((r + (((1 << shift) - (r < 0) as i32) >> 1)) >> shift, -8, 7); + let y = cap_value(p + (q << shift), std::i16::MIN as i32, std::i16::MAX as i32); + let e = y - x; + + this_frame.data[(sample_id+4)/8] |= ((q&0xF) << (((sample_id + 4)%8)*4)) as u32; + this_error += (e*e) as u64; + } + + if this_error < best_error { + best_tap = this_tap; + best_error = this_error; + best_frame = this_frame; + } + } + } + (best_frame, best_tap) + } + + fn set_vag_flags(&mut self, flags: VAGFlagBits) { + let mut first_sample = self.data[0].to_ne_bytes(); + + first_sample[1] = flags.bits(); + self.data[0] = u32::from_ne_bytes(first_sample); + } + + pub fn set_loop_start(mut self) -> Self { + self.set_vag_flags(VAGFlagBits::LoopStart); + self + } + + pub fn set_loop_end_repeat(mut self) -> Self { + self.set_vag_flags(VAGFlagBits::LoopEnd | VAGFlagBits::Repeat); + self + } + + pub fn set_loop_self(mut self) -> Self { + self.set_vag_flags(VAGFlagBits::LoopStart | VAGFlagBits::LoopEnd); + self + } +} + +impl RawConversion<{VAGADPCM::SIZE}> for VAGADPCM { + fn convert_to_raw(&self) -> [u8; VAGADPCM::SIZE] { + unsafe { + let data: [u8; VAGADPCM::SIZE] = std::mem::transmute_copy(&self as &VAGADPCM); + data + } + } +} + +#[derive(Clone)] +pub struct LPC { + first: i32, + second: i32 +} + +impl LPC { + const FILTERS: [LPC; 5] = [ + LPC{first: 0, second: 0}, + LPC{first: 60, second: 0}, + LPC{first: 115, second: -52}, + LPC{first: 98, second: -55}, + LPC{first: 122, second: -60} + ]; + + pub fn empty() -> LPC { + LPC{first: 0, second: 0} + } +} + +pub type ADPCMSampleForVag = [i16; VAGADPCM::ADPCM_SAMPLES_PER_VAGADPCM]; + +pub struct MonoADPCMIterator>> { + iter: I +} + +impl>> MonoADPCMIterator{ + pub fn create(iter: I) -> MonoADPCMIterator { + MonoADPCMIterator{iter} + } +} + +impl>> std::iter::Iterator for MonoADPCMIterator { + type Item = Result<[i16; VAGADPCM::ADPCM_SAMPLES_PER_VAGADPCM], Error>; + + fn next(&mut self) -> Option { + const STREAM_GONE_ERROR: &'static str = "Reading ADPCM sample failed"; + + if let Some(next_sample) = self.iter.next() { + let Ok(next_sample) = next_sample else {return Some(Err(Error::from_str(STREAM_GONE_ERROR)));}; + + let mut sample = [0;VAGADPCM::ADPCM_SAMPLES_PER_VAGADPCM]; + sample[0] = next_sample; + + for idx in 1..VAGADPCM::ADPCM_SAMPLES_PER_VAGADPCM { + let Ok(next_sample) = self.iter.next().unwrap_or(Ok(0)) else {return Some(Err(Error::from_str(STREAM_GONE_ERROR)));}; + sample[idx] = next_sample; + } + return Some(Ok(sample)); + } + None + } } \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/audio/xa/mod.rs b/src/Tools/psxfileconv/src/audio/xa/mod.rs index f34dc4c2..3fec1b05 100644 --- a/src/Tools/psxfileconv/src/audio/xa/mod.rs +++ b/src/Tools/psxfileconv/src/audio/xa/mod.rs @@ -1,39 +1,39 @@ -mod raw_audio; -mod xa_audio; - -use clap::{Args, ValueEnum}; -use std::io::Write; -use tool_helper::{Error, Input}; -use xa_audio::{LOW_FREQUENCY, HIGH_FREQUENCY}; - -#[derive(Args, Clone)] -pub struct Arguments { - #[clap(short='f', long="frequency", value_enum, value_parser, default_value_t=Frequency::High)] - frequency: Frequency, - #[clap(short='b', long="bitdepth", value_enum, value_parser, default_value_t=SampleDepth::Normal)] - sample_depth: SampleDepth, -} - -#[derive(Copy, Clone, ValueEnum)] -pub enum Frequency { - High, - Low, -} - -#[derive(Copy, Clone, ValueEnum)] -pub enum SampleDepth { - Normal, - High -} - -pub fn convert(args: Arguments, input: Input, output: &mut dyn Write) -> Result<(), Error> { - let prepared_xa_audio = raw_audio::load_as_i16_audio(input, frequency_to_value(args.frequency))?; - xa_audio::encode(prepared_xa_audio, output, &args) -} - -fn frequency_to_value(requested_freq: Frequency) -> u32 { - match requested_freq { - Frequency::High => HIGH_FREQUENCY, - Frequency::Low => LOW_FREQUENCY, - } +mod raw_audio; +mod xa_audio; + +use clap::{Args, ValueEnum}; +use std::io::Write; +use tool_helper::{Error, Input}; +use xa_audio::{LOW_FREQUENCY, HIGH_FREQUENCY}; + +#[derive(Args, Clone)] +pub struct Arguments { + #[clap(short='f', long="frequency", value_enum, value_parser, default_value_t=Frequency::High)] + frequency: Frequency, + #[clap(short='b', long="bitdepth", value_enum, value_parser, default_value_t=SampleDepth::Normal)] + sample_depth: SampleDepth, +} + +#[derive(Copy, Clone, ValueEnum)] +pub enum Frequency { + High, + Low, +} + +#[derive(Copy, Clone, ValueEnum)] +pub enum SampleDepth { + Normal, + High +} + +pub fn convert(args: Arguments, input: Input, output: &mut dyn Write) -> Result<(), Error> { + let prepared_xa_audio = raw_audio::load_as_i16_audio(input, frequency_to_value(args.frequency))?; + xa_audio::encode(prepared_xa_audio, output, &args) +} + +fn frequency_to_value(requested_freq: Frequency) -> u32 { + match requested_freq { + Frequency::High => HIGH_FREQUENCY, + Frequency::Low => LOW_FREQUENCY, + } } \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/audio/xa/raw_audio/error.rs b/src/Tools/psxfileconv/src/audio/xa/raw_audio/error.rs index c3045e78..87980c8d 100644 --- a/src/Tools/psxfileconv/src/audio/xa/raw_audio/error.rs +++ b/src/Tools/psxfileconv/src/audio/xa/raw_audio/error.rs @@ -1,35 +1,35 @@ -use super::Error; -use symphonia::core::errors::Error as SymError; -use rubato::{ResampleError, ResamplerConstructionError}; - -fn generic_map_error(action: &str, error_str: String) -> Error { - Error::from_text(format!("symphonia error: {} during {}", error_str, action)) -} - -pub fn probe(error: SymError) -> Error { - generic_map_error("probing of input", error.to_string()) -} - -pub fn decoder(error: SymError) -> Error { - generic_map_error("finding codec", error.to_string()) -} - -pub fn next_packet(error: SymError) -> Error { - generic_map_error("getting next raw packet", error.to_string()) -} - -pub fn decode(error: SymError) -> Error { - generic_map_error("decoding of raw packet", error.to_string()) -} - -pub fn resampler_construction(error: ResamplerConstructionError) -> Error { - generic_map_error("creating resampler", error.to_string()) -} - -pub fn resample(error: ResampleError) -> Error { - generic_map_error("resampling", error.to_string()) -} - -pub fn find_track() -> Error { - Error::from_str("symphonia error: No audio track located") +use super::Error; +use symphonia::core::errors::Error as SymError; +use rubato::{ResampleError, ResamplerConstructionError}; + +fn generic_map_error(action: &str, error_str: String) -> Error { + Error::from_text(format!("symphonia error: {} during {}", error_str, action)) +} + +pub fn probe(error: SymError) -> Error { + generic_map_error("probing of input", error.to_string()) +} + +pub fn decoder(error: SymError) -> Error { + generic_map_error("finding codec", error.to_string()) +} + +pub fn next_packet(error: SymError) -> Error { + generic_map_error("getting next raw packet", error.to_string()) +} + +pub fn decode(error: SymError) -> Error { + generic_map_error("decoding of raw packet", error.to_string()) +} + +pub fn resampler_construction(error: ResamplerConstructionError) -> Error { + generic_map_error("creating resampler", error.to_string()) +} + +pub fn resample(error: ResampleError) -> Error { + generic_map_error("resampling", error.to_string()) +} + +pub fn find_track() -> Error { + Error::from_str("symphonia error: No audio track located") } \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/audio/xa/raw_audio/mod.rs b/src/Tools/psxfileconv/src/audio/xa/raw_audio/mod.rs index bcdc3208..60a506c1 100644 --- a/src/Tools/psxfileconv/src/audio/xa/raw_audio/mod.rs +++ b/src/Tools/psxfileconv/src/audio/xa/raw_audio/mod.rs @@ -1,238 +1,238 @@ -mod error; - -use rubato::{FftFixedInOut, Resampler}; -use symphonia::core::{ - audio::{AudioBuffer, Layout, SampleBuffer, Signal, SignalSpec}, - codecs::{Decoder, DecoderOptions, CODEC_TYPE_NULL}, - errors::Error as SymError, - formats::{FormatOptions, FormatReader}, - io::MediaSourceStream, - meta::MetadataOptions, - probe::Hint -}; -use tool_helper::{Error, Input}; - -#[derive(Copy, Clone, PartialEq)] -pub enum Orality { - Stereo, - Mono, -} - -pub struct CDAudioSamples { - samples: Vec::, - orality: Orality, -} - -impl CDAudioSamples { - pub fn new(samples: Vec, channels: usize) -> Result { - let orality = match channels { - 0 => return Err(Error::from_str("Input file has no audio channels")), - 1 => Orality::Mono, - 2 => Orality::Stereo, - _ => return Err(Error::from_str("Only Mono and Stereo input are supported")), - }; - Ok(CDAudioSamples{samples, orality}) - } - - pub fn samples(&self) -> &Vec:: { - &self.samples - } - - pub fn orality(&self) -> Orality { - self.orality.clone() - } -} - -struct InternalAudioSamples { - planar_samples: Vec>, - frequency: u32, -} - -impl InternalAudioSamples { - pub fn new(planar_samples: Vec>, frequency: u32) -> Result { - if planar_samples.len() < 1 || planar_samples.len() > 2{ - Err(Error::from_str("Audio samples need to be either mono or stereo")) - } - - else { - Ok(InternalAudioSamples{planar_samples, frequency}) - } - } - - pub fn into_audio_buffer(self) -> AudioBuffer { - let duration = self.sample_len() as u64; - let mut new_audio_buffer = AudioBuffer::new(duration, SignalSpec::new_with_layout(self.frequency, if self.planar_samples.len() == 1 {Layout::Mono} else {Layout::Stereo})); - - new_audio_buffer.render_silence(None); - for (channel_idx, channel) in self.planar_samples.into_iter().enumerate() { - let dst_channel = new_audio_buffer.chan_mut(channel_idx); - for (sample_idx, sample) in channel.into_iter().enumerate() { - dst_channel[sample_idx] = sample; - } - } - new_audio_buffer - } - - pub fn sample_len(&self) -> usize { - self.planar_samples[0].len() - } - - pub fn channels(&self) -> usize { - self.planar_samples.len() - } - - pub fn planar_slices(&self) -> Vec<&[f32]> { - let mut planar_slices = Vec::new(); - - for channel in &self.planar_samples { - planar_slices.push(channel.as_slice()); - } - planar_slices - } -} - -pub fn load_as_i16_audio(input: Input, target_frequency: u32) -> Result { - let raw_audio = load_raw_audio(input)?; - let raw_audio = resample(raw_audio, target_frequency)?; - - down_sample_interleave(raw_audio) -} - -fn load_raw_audio(input: Input) -> Result { - let media_stream = MediaSourceStream::new(Box::new(load_to_ram(input)?), Default::default()); - let format = symphonia::default::get_probe().format(&Hint::new(), media_stream, &FormatOptions::default(), &MetadataOptions::default()).map_err(error::probe)?.format; - let track = format.tracks().iter().find(|t| t.codec_params.codec != CODEC_TYPE_NULL).ok_or_else(error::find_track)?; - - // Create a decoder for the track. - let decoder = symphonia::default::get_codecs().make(&track.codec_params, &DecoderOptions::default()).map_err(error::decoder)?; - let track_id = track.id; - - decode(format, decoder, track_id) -} - -fn decode(mut format: Box, mut decoder: Box, track_id: u32) -> Result { - let mut samples = Vec::new(); - let mut channel_count = 0; - let mut frequency = 0; - let mut read_buffer = None; - - loop { - // Get the next packet from the media format. - let packet = match format.next_packet() { - Ok(packet) => packet, - Err(err) => { - if let SymError::IoError(io_err) = &err { - if io_err.kind() == std::io::ErrorKind::UnexpectedEof { - return InternalAudioSamples::new(samples, frequency); - } - } - return Err(error::next_packet(err)); - } - }; - - // Consume any new metadata that has been read since the last packet. - format.metadata().skip_to_latest(); - - // If the packet does not belong to the selected track, skip over it. - if packet.track_id() != track_id { - continue; - } - - // Decode the packet into audio samples. - let packet = decoder.decode(&packet).map_err(error::decode)?; - if read_buffer.is_none() { - let duration = packet.capacity() as u64; - let specs = packet.spec(); - - channel_count = specs.channels.count(); - frequency = specs.rate; - read_buffer = Some(SampleBuffer::::new(duration, packet.spec().clone())); - - for _ in 0..channel_count { - samples.push(Vec::new()); - } - } - - if let Some(read_buffer) = &mut read_buffer { - read_buffer.copy_planar_ref(packet); - let cur_samples = read_buffer.samples(); - let mut cur_samples = cur_samples.chunks(cur_samples.len()/channel_count); - - for dst_sample in &mut samples { - dst_sample.extend(cur_samples.next().ok_or_else(|| Error::from_str("Not enough channels in input as expected"))?); - } - } - } -} - -fn resample(input: InternalAudioSamples, target_frequency: u32) -> Result { - const HIGH_QUALITY_CHUNKS:usize = (1024*10)*100; - fn process_partial(input_option: Option<&[&[f32]]>, resampler: &mut FftFixedInOut, planar_output: &mut Vec>) -> Result<(), Error> { - let new_samples = resampler.process_partial(input_option, None).map_err(error::resample)?; - for (channel, channel_samples) in new_samples.into_iter().enumerate() { - planar_output[channel].extend(channel_samples.iter()); - } - Ok(()) - } - - let chunk_size = HIGH_QUALITY_CHUNKS; - let mut planar_input = input.planar_slices(); - let mut resampler = FftFixedInOut::::new(input.frequency as usize, target_frequency as usize, chunk_size, input.channels()).map_err(error::resampler_construction)?; - let delay = resampler.output_delay(); - let mut sample_len = input.sample_len(); - let new_sample_len = (sample_len as f64*(target_frequency as f64/input.frequency as f64)) as usize; - let mut planar_output = { - let mut planar_output = Vec::new(); - - for _ in 0..planar_input.len() { - planar_output.push(Vec::::new()); - } - planar_output - }; - - loop { - let next_input_frames = resampler.input_frames_next(); - if next_input_frames > sample_len { - if sample_len > 0 { - // Still frames left - process_partial(Some(&planar_input), &mut resampler, &mut planar_output)?; - } - break; - } - - let new_samples = resampler.process(&planar_input, None).map_err(error::resample)?; - for (channel, slice) in planar_input.iter_mut().enumerate() { - *slice = &slice[next_input_frames..]; - planar_output[channel].extend(new_samples[channel].iter()); - } - sample_len -= next_input_frames; - } - - if planar_output[0].len() < delay + new_sample_len { - // Flush - process_partial(None, &mut resampler, &mut planar_output)?; - } - - for channel in &mut planar_output { - let start = delay; - let end = start + new_sample_len; - *channel = channel[start..end].into(); - } - InternalAudioSamples::new(planar_output, target_frequency) -} - -fn down_sample_interleave(input: InternalAudioSamples) -> Result { - let channels = input.channels(); - let audio_buffer = input.into_audio_buffer(); - let mut sample_buffer = SampleBuffer::::new(audio_buffer.capacity() as u64, audio_buffer.spec().clone()); - - sample_buffer.copy_interleaved_typed::(&audio_buffer); - CDAudioSamples::new(sample_buffer.samples().to_vec(), channels) -} - -fn load_to_ram(mut input: Input) -> Result>, Error> { - let mut buffer = Vec::default(); - - input.read_to_end(&mut buffer)?; - Ok(std::io::Cursor::new(buffer)) +mod error; + +use rubato::{FftFixedInOut, Resampler}; +use symphonia::core::{ + audio::{AudioBuffer, Layout, SampleBuffer, Signal, SignalSpec}, + codecs::{Decoder, DecoderOptions, CODEC_TYPE_NULL}, + errors::Error as SymError, + formats::{FormatOptions, FormatReader}, + io::MediaSourceStream, + meta::MetadataOptions, + probe::Hint +}; +use tool_helper::{Error, Input}; + +#[derive(Copy, Clone, PartialEq)] +pub enum Orality { + Stereo, + Mono, +} + +pub struct CDAudioSamples { + samples: Vec::, + orality: Orality, +} + +impl CDAudioSamples { + pub fn new(samples: Vec, channels: usize) -> Result { + let orality = match channels { + 0 => return Err(Error::from_str("Input file has no audio channels")), + 1 => Orality::Mono, + 2 => Orality::Stereo, + _ => return Err(Error::from_str("Only Mono and Stereo input are supported")), + }; + Ok(CDAudioSamples{samples, orality}) + } + + pub fn samples(&self) -> &Vec:: { + &self.samples + } + + pub fn orality(&self) -> Orality { + self.orality.clone() + } +} + +struct InternalAudioSamples { + planar_samples: Vec>, + frequency: u32, +} + +impl InternalAudioSamples { + pub fn new(planar_samples: Vec>, frequency: u32) -> Result { + if planar_samples.len() < 1 || planar_samples.len() > 2{ + Err(Error::from_str("Audio samples need to be either mono or stereo")) + } + + else { + Ok(InternalAudioSamples{planar_samples, frequency}) + } + } + + pub fn into_audio_buffer(self) -> AudioBuffer { + let duration = self.sample_len() as u64; + let mut new_audio_buffer = AudioBuffer::new(duration, SignalSpec::new_with_layout(self.frequency, if self.planar_samples.len() == 1 {Layout::Mono} else {Layout::Stereo})); + + new_audio_buffer.render_silence(None); + for (channel_idx, channel) in self.planar_samples.into_iter().enumerate() { + let dst_channel = new_audio_buffer.chan_mut(channel_idx); + for (sample_idx, sample) in channel.into_iter().enumerate() { + dst_channel[sample_idx] = sample; + } + } + new_audio_buffer + } + + pub fn sample_len(&self) -> usize { + self.planar_samples[0].len() + } + + pub fn channels(&self) -> usize { + self.planar_samples.len() + } + + pub fn planar_slices(&self) -> Vec<&[f32]> { + let mut planar_slices = Vec::new(); + + for channel in &self.planar_samples { + planar_slices.push(channel.as_slice()); + } + planar_slices + } +} + +pub fn load_as_i16_audio(input: Input, target_frequency: u32) -> Result { + let raw_audio = load_raw_audio(input)?; + let raw_audio = resample(raw_audio, target_frequency)?; + + down_sample_interleave(raw_audio) +} + +fn load_raw_audio(input: Input) -> Result { + let media_stream = MediaSourceStream::new(Box::new(load_to_ram(input)?), Default::default()); + let format = symphonia::default::get_probe().format(&Hint::new(), media_stream, &FormatOptions::default(), &MetadataOptions::default()).map_err(error::probe)?.format; + let track = format.tracks().iter().find(|t| t.codec_params.codec != CODEC_TYPE_NULL).ok_or_else(error::find_track)?; + + // Create a decoder for the track. + let decoder = symphonia::default::get_codecs().make(&track.codec_params, &DecoderOptions::default()).map_err(error::decoder)?; + let track_id = track.id; + + decode(format, decoder, track_id) +} + +fn decode(mut format: Box, mut decoder: Box, track_id: u32) -> Result { + let mut samples = Vec::new(); + let mut channel_count = 0; + let mut frequency = 0; + let mut read_buffer = None; + + loop { + // Get the next packet from the media format. + let packet = match format.next_packet() { + Ok(packet) => packet, + Err(err) => { + if let SymError::IoError(io_err) = &err { + if io_err.kind() == std::io::ErrorKind::UnexpectedEof { + return InternalAudioSamples::new(samples, frequency); + } + } + return Err(error::next_packet(err)); + } + }; + + // Consume any new metadata that has been read since the last packet. + format.metadata().skip_to_latest(); + + // If the packet does not belong to the selected track, skip over it. + if packet.track_id() != track_id { + continue; + } + + // Decode the packet into audio samples. + let packet = decoder.decode(&packet).map_err(error::decode)?; + if read_buffer.is_none() { + let duration = packet.capacity() as u64; + let specs = packet.spec(); + + channel_count = specs.channels.count(); + frequency = specs.rate; + read_buffer = Some(SampleBuffer::::new(duration, packet.spec().clone())); + + for _ in 0..channel_count { + samples.push(Vec::new()); + } + } + + if let Some(read_buffer) = &mut read_buffer { + read_buffer.copy_planar_ref(packet); + let cur_samples = read_buffer.samples(); + let mut cur_samples = cur_samples.chunks(cur_samples.len()/channel_count); + + for dst_sample in &mut samples { + dst_sample.extend(cur_samples.next().ok_or_else(|| Error::from_str("Not enough channels in input as expected"))?); + } + } + } +} + +fn resample(input: InternalAudioSamples, target_frequency: u32) -> Result { + const HIGH_QUALITY_CHUNKS:usize = (1024*10)*100; + fn process_partial(input_option: Option<&[&[f32]]>, resampler: &mut FftFixedInOut, planar_output: &mut Vec>) -> Result<(), Error> { + let new_samples = resampler.process_partial(input_option, None).map_err(error::resample)?; + for (channel, channel_samples) in new_samples.into_iter().enumerate() { + planar_output[channel].extend(channel_samples.iter()); + } + Ok(()) + } + + let chunk_size = HIGH_QUALITY_CHUNKS; + let mut planar_input = input.planar_slices(); + let mut resampler = FftFixedInOut::::new(input.frequency as usize, target_frequency as usize, chunk_size, input.channels()).map_err(error::resampler_construction)?; + let delay = resampler.output_delay(); + let mut sample_len = input.sample_len(); + let new_sample_len = (sample_len as f64*(target_frequency as f64/input.frequency as f64)) as usize; + let mut planar_output = { + let mut planar_output = Vec::new(); + + for _ in 0..planar_input.len() { + planar_output.push(Vec::::new()); + } + planar_output + }; + + loop { + let next_input_frames = resampler.input_frames_next(); + if next_input_frames > sample_len { + if sample_len > 0 { + // Still frames left + process_partial(Some(&planar_input), &mut resampler, &mut planar_output)?; + } + break; + } + + let new_samples = resampler.process(&planar_input, None).map_err(error::resample)?; + for (channel, slice) in planar_input.iter_mut().enumerate() { + *slice = &slice[next_input_frames..]; + planar_output[channel].extend(new_samples[channel].iter()); + } + sample_len -= next_input_frames; + } + + if planar_output[0].len() < delay + new_sample_len { + // Flush + process_partial(None, &mut resampler, &mut planar_output)?; + } + + for channel in &mut planar_output { + let start = delay; + let end = start + new_sample_len; + *channel = channel[start..end].into(); + } + InternalAudioSamples::new(planar_output, target_frequency) +} + +fn down_sample_interleave(input: InternalAudioSamples) -> Result { + let channels = input.channels(); + let audio_buffer = input.into_audio_buffer(); + let mut sample_buffer = SampleBuffer::::new(audio_buffer.capacity() as u64, audio_buffer.spec().clone()); + + sample_buffer.copy_interleaved_typed::(&audio_buffer); + CDAudioSamples::new(sample_buffer.samples().to_vec(), channels) +} + +fn load_to_ram(mut input: Input) -> Result>, Error> { + let mut buffer = Vec::default(); + + input.read_to_end(&mut buffer)?; + Ok(std::io::Cursor::new(buffer)) } \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/audio/xa/xa_audio/mod.rs b/src/Tools/psxfileconv/src/audio/xa/xa_audio/mod.rs index f6764021..3d747be8 100644 --- a/src/Tools/psxfileconv/src/audio/xa/xa_audio/mod.rs +++ b/src/Tools/psxfileconv/src/audio/xa/xa_audio/mod.rs @@ -1,20 +1,20 @@ -mod xapcm; - -use super::Arguments; -use super::raw_audio::CDAudioSamples; -use cdtypes::types::sector::{Mode2Form2, SECTOR_SIZE}; -use std::io::Write; -use tool_helper::Error; - -pub const HIGH_FREQUENCY:u32 = 37_800; -pub const LOW_FREQUENCY:u32 = 18_900; - -pub fn encode(input: CDAudioSamples, output: &mut dyn Write, arguments: &Arguments) -> Result<(), Error> { - let mut encoder = xapcm::Encoder::new(&input, arguments.frequency, arguments.sample_depth); - - while let Some(xa_sector) = encoder.encode_next_xa_sector()? { - let xa_sector = unsafe {std::mem::transmute::(xa_sector)}; - output.write(&xa_sector)?; - } - Ok(()) +mod xapcm; + +use super::Arguments; +use super::raw_audio::CDAudioSamples; +use cdtypes::types::sector::{Mode2Form2, SECTOR_SIZE}; +use std::io::Write; +use tool_helper::Error; + +pub const HIGH_FREQUENCY:u32 = 37_800; +pub const LOW_FREQUENCY:u32 = 18_900; + +pub fn encode(input: CDAudioSamples, output: &mut dyn Write, arguments: &Arguments) -> Result<(), Error> { + let mut encoder = xapcm::Encoder::new(&input, arguments.frequency, arguments.sample_depth); + + while let Some(xa_sector) = encoder.encode_next_xa_sector()? { + let xa_sector = unsafe {std::mem::transmute::(xa_sector)}; + output.write(&xa_sector)?; + } + Ok(()) } \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/audio/xa/xa_audio/xapcm.rs b/src/Tools/psxfileconv/src/audio/xa/xa_audio/xapcm.rs index a53ce7f6..8bca998b 100644 --- a/src/Tools/psxfileconv/src/audio/xa/xa_audio/xapcm.rs +++ b/src/Tools/psxfileconv/src/audio/xa/xa_audio/xapcm.rs @@ -1,313 +1,313 @@ -use crate::audio::xa::{raw_audio::{CDAudioSamples, Orality}, Frequency, SampleDepth}; -use cdtypes::types::sector::{Mode2Form2, XAADPCMBitsPerSample, XAADPCMSampleRate, XAADPCMSound}; -use tool_helper::Error; - -pub struct Encoder<'a> { - left: ChannelState, - right: ChannelState, - source: &'a[i16], - frequency: Frequency, - sample_depth: SampleDepth, - orality: Orality, - samples_per_block: i32, - sample_limit: i32 -} - -impl<'a> Encoder<'a> { - const BLOCKS_PER_SECTOR:usize = 18; - const XA_ADPCM_FILTER_COUNT: i32 = 4; - const FILTER_K1: [i16; 5] = [0, 60, 115, 98, 122]; - const FILTER_K2: [i16; 5] = [0, 0, -52, -55, -60]; - - pub fn new(cd_sample: &CDAudioSamples, frequency: Frequency, sample_depth: SampleDepth) -> Encoder { - let orality = cd_sample.orality(); - let (samples_per_block, sample_limit) = Self::samples_per_block_and_limit(&cd_sample.samples(), sample_depth, orality); - - Encoder{left: ChannelState::default(), right: ChannelState::default(), source: &cd_sample.samples(), frequency, sample_depth, orality, samples_per_block, sample_limit} - } - - pub fn encode_next_xa_sector(&mut self) -> Result, Error> { - if self.source.is_empty() { - return Ok(None); - } - - let mut sector = self.create_new_sector(); - let mut dst = &mut sector.data[0..]; - - for _ in 0..Self::BLOCKS_PER_SECTOR { - if self.source.len() < self.samples_per_block as usize { - self.source = &self.source[self.source.len()..]; - break; - } - - self.encode_xa(&self.source[0..], self.sample_limit, dst)?; - - self.sample_limit -= self.samples_per_block; - self.source = &self.source[self.samples_per_block as usize..]; - dst = &mut dst[0x80..]; - } - - sector.finalize(); - Ok(Some(sector)) - } - - fn create_new_sector(&self) -> Mode2Form2 { - let mut sector = Mode2Form2::new(); - let sub_mode = &mut sector.sub_header.sub_mode; - let coding_info = &mut sector.sub_header.coding_info; - - sub_mode.set_real_time(); - - coding_info.set_sound_type(match self.orality { - Orality::Mono => XAADPCMSound::Mono, - Orality::Stereo => XAADPCMSound::Stereo - }); - coding_info.set_sample_rate(match self.frequency { - Frequency::Low => XAADPCMSampleRate::Freq18900Hz, - Frequency::High => XAADPCMSampleRate::Freq37800Hz, - }); - coding_info.set_bits_per_sample(match self.sample_depth { - SampleDepth::Normal => XAADPCMBitsPerSample::Normal, - SampleDepth::High => XAADPCMBitsPerSample::High, - }); - - sector - } - - fn encode_xa(&mut self, samples: &[i16], sample_limit: i32, data: &mut [u8]) -> Result<(), Error> { - const SHIFT_RANGE_4BPS: i32 = 12; - const SHIFT_RANGE_8BPS: i32 = 8; - - let channels = [&mut self.left, &mut self.right]; - match self.sample_depth { - SampleDepth::Normal => { - let (modulo, offset) = if self.orality == Orality::Stereo {(2, &STEREO_4BIT)} else {(1, &MONO_4BIT)}; - let (first_offset, second_offset) = offset; - - for (offset_idx, offset_set) in [first_offset, second_offset].iter().enumerate() { - for (idx, offset) in offset_set.iter().enumerate() { - let byte = Self::encode(channels[idx%modulo], &samples[offset.sample..], sample_limit + offset.sample_limit, offset.pitch, &mut data[offset.data..], offset.data_shift, offset.data_pitch, Self::XA_ADPCM_FILTER_COUNT, SHIFT_RANGE_4BPS)?; - data[idx + (offset_idx*8)] = byte; - data[idx + 4 + (offset_idx*8)] = byte; - } - } - }, - SampleDepth::High => { - let (modulo, offset_set) = if self.orality == Orality::Stereo {(2, &STEREO_8BIT)} else {(1, &MONO_8BIT)}; - for (idx, offset) in offset_set.iter().enumerate() { - let byte = Self::encode(channels[idx%modulo], &samples[offset.sample..], sample_limit + offset.sample_limit, offset.pitch, &mut data[offset.data..], offset.data_shift, offset.data_pitch, Self::XA_ADPCM_FILTER_COUNT, SHIFT_RANGE_8BPS)?; - data[idx] = byte; - data[idx + 4] = byte; - } - } - } - - Ok(()) - } - - fn encode(channel_state: &mut ChannelState, samples: &[i16], sample_limit: i32, pitch: i32, data: &mut [u8], data_shift: i32, data_pitch: i32, filter_count: i32, shift_range: i32) -> Result { - let mut best_mse = 1i64 << 50i64; - let mut best_filer = 0; - let mut best_sample_shift = 0; - - for filter in 0..filter_count { - let true_min_shift = Self::find_min_shift(channel_state, samples, sample_limit, pitch, filter, shift_range)?; - - // Testing has shown that the optimal shift can be off the true minimum shift - // by 1 in *either* direction. - // This is NOT the case when dither is used. - let min_shift = if true_min_shift - 1 < 0 {0} else {true_min_shift - 1}; - let max_shift = if true_min_shift + 1 > shift_range {shift_range} else {true_min_shift + 1}; - - for sample_shift in min_shift..=max_shift { - let mut proposed = channel_state.clone(); - Self::attempt_encode(&mut proposed, samples, sample_limit, pitch, data, data_shift, data_pitch, filter, sample_shift, shift_range)?; - if best_mse > proposed.mse { - best_mse = proposed.mse; - best_filer = filter; - best_sample_shift = sample_shift; - } - } - } - - Self::attempt_encode(channel_state, samples, sample_limit, pitch, data, data_shift, data_pitch, best_filer, best_sample_shift, shift_range) - } - - fn attempt_encode(out_channel_state: &mut ChannelState, samples: &[i16], sample_limit: i32, pitch: i32, data: &mut [u8], data_shift: i32, data_pitch: i32, filter: i32, sample_shift: i32, shift_range: i32) -> Result { - let sample_mask = (0xFFFF >> shift_range) as u8; - let nondata_mask = (!(sample_mask << data_shift)) as u8; - - let min_shift = sample_shift; - let k1 = Self::FILTER_K1[filter as usize] as i32; - let k2 = Self::FILTER_K2[filter as usize] as i32; - - let hdr = ((min_shift & 0x0F) | ((filter as i32) << 4)) as u8; - - out_channel_state.mse = 0; - - for i in 0..28 { - let sample = (if i >= sample_limit {0} else {samples[(i*pitch) as usize] as i32}) + out_channel_state.qerr; - let previous_value = (k1*out_channel_state.prev1 + k2*out_channel_state.prev2 + (1 << 5)) >> 6; - - let mut sample_enc = sample - previous_value; - sample_enc <<= min_shift; - sample_enc += 1 << (shift_range - 1); - sample_enc >>= shift_range; - - if sample_enc < (std::i16::MIN as i32 >> shift_range) {sample_enc = std::i16::MIN as i32 >> shift_range} - if sample_enc > (std::i16::MAX as i32 >> shift_range) {sample_enc = std::i16::MAX as i32 >> shift_range} - sample_enc &= sample_mask as i32; - - let mut sample_dec = (((sample_enc & sample_mask as i32) << shift_range) as i16) as i32; - sample_dec >>= min_shift; - sample_dec += previous_value; - if sample_dec > std::i16::MAX as i32 {sample_dec = std::i16::MAX as i32} - if sample_dec < std::i16::MIN as i32 {sample_dec = std::i16::MIN as i32} - - let sample_error = sample_dec - sample; - if sample_error >= (1 << 30) || sample_error <= -(1 << 30) { - return Err(Error::from_text(format!("Sample error exceeds 30bit: {}", sample_error))); - } - - data[(i*data_pitch) as usize] = ((data[(i*data_pitch) as usize] & nondata_mask) as i32 | (sample_enc << data_shift)) as u8; - - out_channel_state.mse += (sample_error as u64*sample_error as u64) as i64; - out_channel_state.prev2 = out_channel_state.prev1; - out_channel_state.prev1 = sample_dec; - } - - Ok(hdr) - } - - fn find_min_shift(channel_state: &ChannelState, samples: &[i16], sample_limit: i32, pitch: i32, filter: i32, shift_range: i32) -> Result { - /* - Assumption made: - There is value in shifting right one step further to allow the nibbles to clip. - However, given a possible shift value, there is no value in shifting one step less. - - Having said that, this is not a completely accurate model of the encoder, - so maybe we will need to shift one step less. - */ - - let mut prev1 = channel_state.prev1; - let mut prev2 = channel_state.prev2; - let k1 = Self::FILTER_K1[filter as usize] as i32; - let k2 = Self::FILTER_K2[filter as usize] as i32; - let mut right_shift = 0; - let mut s_min = 0; - let mut s_max = 0; - - for i in 0..28 { - let raw_sample = if i >= sample_limit {0} else {samples[(i*pitch) as usize]} as i32; - let prev_values = (k1*prev1 + k2*prev2 + (1 << 5)) >> 6; - let sample = raw_sample - prev_values; - - if sample < s_min { - s_min = sample; - } - - if sample > s_max { - s_max = sample; - } - - prev2 = prev1; - prev1 = raw_sample; - } - - while right_shift < shift_range && (s_max >> right_shift) > (std::i16::MAX as i32 >> shift_range) { - right_shift += 1; - } - - while right_shift < shift_range && (s_min >> right_shift) < (std::i16::MIN as i32 >> shift_range) { - right_shift += 1; - } - - let min_shift = shift_range - right_shift; - if 0 <= min_shift && min_shift <= shift_range { - Ok(min_shift) - } - - else { - Err(Error::from_text(format!("0 <= {} && {} <= {} was not satisfied with min_shift: {}", min_shift, min_shift, shift_range, min_shift))) - } - } - - fn samples_per_block_and_limit(input: &[i16], sample_depth: SampleDepth, orality: Orality) -> (i32, i32) { - let samples_per_block = match sample_depth { - SampleDepth::Normal => 224, - SampleDepth::High => 112, - }; - - let sample_limit = match orality { - Orality::Stereo => input.len()*2, - Orality::Mono => input.len(), - }; - - (samples_per_block, sample_limit as i32) - } -} - -#[derive(Clone)] -struct ChannelState { - qerr: i32, // quanitisation error - mse: i64, // mean square error - prev1: i32, - prev2: i32 -} - -impl std::default::Default for ChannelState { - fn default() -> Self { - ChannelState{qerr: 0, mse: 0, prev1: 0, prev2: 0} - } -} - -struct EncodingOffsets { - sample: usize, - sample_limit: i32, - pitch: i32, - data: usize, - data_shift: i32, - data_pitch: i32, -} - -const STEREO_4BIT: ([EncodingOffsets; 4], [EncodingOffsets; 4]) = ( - [ - EncodingOffsets{sample: 0, sample_limit: 0, pitch: 2, data: 0x10, data_shift: 0, data_pitch: 4}, - EncodingOffsets{sample: 1, sample_limit: 0, pitch: 2, data: 0x10, data_shift: 4, data_pitch: 4}, - EncodingOffsets{sample: 56, sample_limit: -28, pitch: 2, data: 0x11, data_shift: 0, data_pitch: 4}, - EncodingOffsets{sample: 56 + 1, sample_limit: -28, pitch: 2, data: 0x11, data_shift: 4, data_pitch: 4}, - ], - [ - EncodingOffsets{sample: 56*2, sample_limit: -28*2, pitch: 2, data: 0x12, data_shift: 0, data_pitch: 4}, - EncodingOffsets{sample: 56*2 + 1, sample_limit: -28*2, pitch: 2, data: 0x12, data_shift: 4, data_pitch: 4}, - EncodingOffsets{sample: 56*3, sample_limit: -28*3, pitch: 2, data: 0x13, data_shift: 0, data_pitch: 4}, - EncodingOffsets{sample: 56*3 + 1, sample_limit: -28*3, pitch: 2, data: 0x13, data_shift: 4, data_pitch: 4} - ] -); -const MONO_4BIT: ([EncodingOffsets; 4], [EncodingOffsets; 4]) = ( - [ - EncodingOffsets{sample: 0, sample_limit: 0, pitch: 1, data: 0x10, data_shift: 0, data_pitch: 4}, - EncodingOffsets{sample: 28, sample_limit: -28, pitch: 1, data: 0x10, data_shift: 4, data_pitch: 4}, - EncodingOffsets{sample: 28*2, sample_limit: -28*2, pitch: 1, data: 0x11, data_shift: 0, data_pitch: 4}, - EncodingOffsets{sample: 28*3, sample_limit: -28*3, pitch: 1, data: 0x11, data_shift: 4, data_pitch: 4}, - ], - [ - EncodingOffsets{sample: 28*4, sample_limit: -28*4, pitch: 1, data: 0x12, data_shift: 0, data_pitch: 4}, - EncodingOffsets{sample: 28*5, sample_limit: -28*5, pitch: 1, data: 0x12, data_shift: 4, data_pitch: 4}, - EncodingOffsets{sample: 28*6, sample_limit: -28*6, pitch: 1, data: 0x13, data_shift: 0, data_pitch: 4}, - EncodingOffsets{sample: 28*7, sample_limit: -28*7, pitch: 1, data: 0x13, data_shift: 4, data_pitch: 4} - ] -); - -const STEREO_8BIT: [EncodingOffsets;4] = [ - EncodingOffsets{sample: 0, sample_limit: 0, pitch: 2, data: 0x10, data_shift: 0, data_pitch: 4}, - EncodingOffsets{sample: 1, sample_limit: 0, pitch: 2, data: 0x11, data_shift: 0, data_pitch: 4}, - EncodingOffsets{sample: 56, sample_limit: -28, pitch: 2, data: 0x12, data_shift: 0, data_pitch: 4}, - EncodingOffsets{sample: 56 + 1, sample_limit: -28, pitch: 2, data: 0x13, data_shift: 0, data_pitch: 4}, -]; -const MONO_8BIT: [EncodingOffsets;4] = [ - EncodingOffsets{sample: 0, sample_limit: 0, pitch: 1, data: 0x10, data_shift: 0, data_pitch: 4}, - EncodingOffsets{sample: 28, sample_limit: -28, pitch: 1, data: 0x11, data_shift: 0, data_pitch: 4}, - EncodingOffsets{sample: 28*2, sample_limit: -28*2, pitch: 1, data: 0x12, data_shift: 0, data_pitch: 4}, - EncodingOffsets{sample: 28*3, sample_limit: -28*3, pitch: 1, data: 0x13, data_shift: 0, data_pitch: 4}, +use crate::audio::xa::{raw_audio::{CDAudioSamples, Orality}, Frequency, SampleDepth}; +use cdtypes::types::sector::{Mode2Form2, XAADPCMBitsPerSample, XAADPCMSampleRate, XAADPCMSound}; +use tool_helper::Error; + +pub struct Encoder<'a> { + left: ChannelState, + right: ChannelState, + source: &'a[i16], + frequency: Frequency, + sample_depth: SampleDepth, + orality: Orality, + samples_per_block: i32, + sample_limit: i32 +} + +impl<'a> Encoder<'a> { + const BLOCKS_PER_SECTOR:usize = 18; + const XA_ADPCM_FILTER_COUNT: i32 = 4; + const FILTER_K1: [i16; 5] = [0, 60, 115, 98, 122]; + const FILTER_K2: [i16; 5] = [0, 0, -52, -55, -60]; + + pub fn new(cd_sample: &CDAudioSamples, frequency: Frequency, sample_depth: SampleDepth) -> Encoder { + let orality = cd_sample.orality(); + let (samples_per_block, sample_limit) = Self::samples_per_block_and_limit(&cd_sample.samples(), sample_depth, orality); + + Encoder{left: ChannelState::default(), right: ChannelState::default(), source: &cd_sample.samples(), frequency, sample_depth, orality, samples_per_block, sample_limit} + } + + pub fn encode_next_xa_sector(&mut self) -> Result, Error> { + if self.source.is_empty() { + return Ok(None); + } + + let mut sector = self.create_new_sector(); + let mut dst = &mut sector.data[0..]; + + for _ in 0..Self::BLOCKS_PER_SECTOR { + if self.source.len() < self.samples_per_block as usize { + self.source = &self.source[self.source.len()..]; + break; + } + + self.encode_xa(&self.source[0..], self.sample_limit, dst)?; + + self.sample_limit -= self.samples_per_block; + self.source = &self.source[self.samples_per_block as usize..]; + dst = &mut dst[0x80..]; + } + + sector.finalize(); + Ok(Some(sector)) + } + + fn create_new_sector(&self) -> Mode2Form2 { + let mut sector = Mode2Form2::new(); + let sub_mode = &mut sector.sub_header.sub_mode; + let coding_info = &mut sector.sub_header.coding_info; + + sub_mode.set_real_time(); + + coding_info.set_sound_type(match self.orality { + Orality::Mono => XAADPCMSound::Mono, + Orality::Stereo => XAADPCMSound::Stereo + }); + coding_info.set_sample_rate(match self.frequency { + Frequency::Low => XAADPCMSampleRate::Freq18900Hz, + Frequency::High => XAADPCMSampleRate::Freq37800Hz, + }); + coding_info.set_bits_per_sample(match self.sample_depth { + SampleDepth::Normal => XAADPCMBitsPerSample::Normal, + SampleDepth::High => XAADPCMBitsPerSample::High, + }); + + sector + } + + fn encode_xa(&mut self, samples: &[i16], sample_limit: i32, data: &mut [u8]) -> Result<(), Error> { + const SHIFT_RANGE_4BPS: i32 = 12; + const SHIFT_RANGE_8BPS: i32 = 8; + + let channels = [&mut self.left, &mut self.right]; + match self.sample_depth { + SampleDepth::Normal => { + let (modulo, offset) = if self.orality == Orality::Stereo {(2, &STEREO_4BIT)} else {(1, &MONO_4BIT)}; + let (first_offset, second_offset) = offset; + + for (offset_idx, offset_set) in [first_offset, second_offset].iter().enumerate() { + for (idx, offset) in offset_set.iter().enumerate() { + let byte = Self::encode(channels[idx%modulo], &samples[offset.sample..], sample_limit + offset.sample_limit, offset.pitch, &mut data[offset.data..], offset.data_shift, offset.data_pitch, Self::XA_ADPCM_FILTER_COUNT, SHIFT_RANGE_4BPS)?; + data[idx + (offset_idx*8)] = byte; + data[idx + 4 + (offset_idx*8)] = byte; + } + } + }, + SampleDepth::High => { + let (modulo, offset_set) = if self.orality == Orality::Stereo {(2, &STEREO_8BIT)} else {(1, &MONO_8BIT)}; + for (idx, offset) in offset_set.iter().enumerate() { + let byte = Self::encode(channels[idx%modulo], &samples[offset.sample..], sample_limit + offset.sample_limit, offset.pitch, &mut data[offset.data..], offset.data_shift, offset.data_pitch, Self::XA_ADPCM_FILTER_COUNT, SHIFT_RANGE_8BPS)?; + data[idx] = byte; + data[idx + 4] = byte; + } + } + } + + Ok(()) + } + + fn encode(channel_state: &mut ChannelState, samples: &[i16], sample_limit: i32, pitch: i32, data: &mut [u8], data_shift: i32, data_pitch: i32, filter_count: i32, shift_range: i32) -> Result { + let mut best_mse = 1i64 << 50i64; + let mut best_filer = 0; + let mut best_sample_shift = 0; + + for filter in 0..filter_count { + let true_min_shift = Self::find_min_shift(channel_state, samples, sample_limit, pitch, filter, shift_range)?; + + // Testing has shown that the optimal shift can be off the true minimum shift + // by 1 in *either* direction. + // This is NOT the case when dither is used. + let min_shift = if true_min_shift - 1 < 0 {0} else {true_min_shift - 1}; + let max_shift = if true_min_shift + 1 > shift_range {shift_range} else {true_min_shift + 1}; + + for sample_shift in min_shift..=max_shift { + let mut proposed = channel_state.clone(); + Self::attempt_encode(&mut proposed, samples, sample_limit, pitch, data, data_shift, data_pitch, filter, sample_shift, shift_range)?; + if best_mse > proposed.mse { + best_mse = proposed.mse; + best_filer = filter; + best_sample_shift = sample_shift; + } + } + } + + Self::attempt_encode(channel_state, samples, sample_limit, pitch, data, data_shift, data_pitch, best_filer, best_sample_shift, shift_range) + } + + fn attempt_encode(out_channel_state: &mut ChannelState, samples: &[i16], sample_limit: i32, pitch: i32, data: &mut [u8], data_shift: i32, data_pitch: i32, filter: i32, sample_shift: i32, shift_range: i32) -> Result { + let sample_mask = (0xFFFF >> shift_range) as u8; + let nondata_mask = (!(sample_mask << data_shift)) as u8; + + let min_shift = sample_shift; + let k1 = Self::FILTER_K1[filter as usize] as i32; + let k2 = Self::FILTER_K2[filter as usize] as i32; + + let hdr = ((min_shift & 0x0F) | ((filter as i32) << 4)) as u8; + + out_channel_state.mse = 0; + + for i in 0..28 { + let sample = (if i >= sample_limit {0} else {samples[(i*pitch) as usize] as i32}) + out_channel_state.qerr; + let previous_value = (k1*out_channel_state.prev1 + k2*out_channel_state.prev2 + (1 << 5)) >> 6; + + let mut sample_enc = sample - previous_value; + sample_enc <<= min_shift; + sample_enc += 1 << (shift_range - 1); + sample_enc >>= shift_range; + + if sample_enc < (std::i16::MIN as i32 >> shift_range) {sample_enc = std::i16::MIN as i32 >> shift_range} + if sample_enc > (std::i16::MAX as i32 >> shift_range) {sample_enc = std::i16::MAX as i32 >> shift_range} + sample_enc &= sample_mask as i32; + + let mut sample_dec = (((sample_enc & sample_mask as i32) << shift_range) as i16) as i32; + sample_dec >>= min_shift; + sample_dec += previous_value; + if sample_dec > std::i16::MAX as i32 {sample_dec = std::i16::MAX as i32} + if sample_dec < std::i16::MIN as i32 {sample_dec = std::i16::MIN as i32} + + let sample_error = sample_dec - sample; + if sample_error >= (1 << 30) || sample_error <= -(1 << 30) { + return Err(Error::from_text(format!("Sample error exceeds 30bit: {}", sample_error))); + } + + data[(i*data_pitch) as usize] = ((data[(i*data_pitch) as usize] & nondata_mask) as i32 | (sample_enc << data_shift)) as u8; + + out_channel_state.mse += (sample_error as u64*sample_error as u64) as i64; + out_channel_state.prev2 = out_channel_state.prev1; + out_channel_state.prev1 = sample_dec; + } + + Ok(hdr) + } + + fn find_min_shift(channel_state: &ChannelState, samples: &[i16], sample_limit: i32, pitch: i32, filter: i32, shift_range: i32) -> Result { + /* + Assumption made: + There is value in shifting right one step further to allow the nibbles to clip. + However, given a possible shift value, there is no value in shifting one step less. + + Having said that, this is not a completely accurate model of the encoder, + so maybe we will need to shift one step less. + */ + + let mut prev1 = channel_state.prev1; + let mut prev2 = channel_state.prev2; + let k1 = Self::FILTER_K1[filter as usize] as i32; + let k2 = Self::FILTER_K2[filter as usize] as i32; + let mut right_shift = 0; + let mut s_min = 0; + let mut s_max = 0; + + for i in 0..28 { + let raw_sample = if i >= sample_limit {0} else {samples[(i*pitch) as usize]} as i32; + let prev_values = (k1*prev1 + k2*prev2 + (1 << 5)) >> 6; + let sample = raw_sample - prev_values; + + if sample < s_min { + s_min = sample; + } + + if sample > s_max { + s_max = sample; + } + + prev2 = prev1; + prev1 = raw_sample; + } + + while right_shift < shift_range && (s_max >> right_shift) > (std::i16::MAX as i32 >> shift_range) { + right_shift += 1; + } + + while right_shift < shift_range && (s_min >> right_shift) < (std::i16::MIN as i32 >> shift_range) { + right_shift += 1; + } + + let min_shift = shift_range - right_shift; + if 0 <= min_shift && min_shift <= shift_range { + Ok(min_shift) + } + + else { + Err(Error::from_text(format!("0 <= {} && {} <= {} was not satisfied with min_shift: {}", min_shift, min_shift, shift_range, min_shift))) + } + } + + fn samples_per_block_and_limit(input: &[i16], sample_depth: SampleDepth, orality: Orality) -> (i32, i32) { + let samples_per_block = match sample_depth { + SampleDepth::Normal => 224, + SampleDepth::High => 112, + }; + + let sample_limit = match orality { + Orality::Stereo => input.len()*2, + Orality::Mono => input.len(), + }; + + (samples_per_block, sample_limit as i32) + } +} + +#[derive(Clone)] +struct ChannelState { + qerr: i32, // quanitisation error + mse: i64, // mean square error + prev1: i32, + prev2: i32 +} + +impl std::default::Default for ChannelState { + fn default() -> Self { + ChannelState{qerr: 0, mse: 0, prev1: 0, prev2: 0} + } +} + +struct EncodingOffsets { + sample: usize, + sample_limit: i32, + pitch: i32, + data: usize, + data_shift: i32, + data_pitch: i32, +} + +const STEREO_4BIT: ([EncodingOffsets; 4], [EncodingOffsets; 4]) = ( + [ + EncodingOffsets{sample: 0, sample_limit: 0, pitch: 2, data: 0x10, data_shift: 0, data_pitch: 4}, + EncodingOffsets{sample: 1, sample_limit: 0, pitch: 2, data: 0x10, data_shift: 4, data_pitch: 4}, + EncodingOffsets{sample: 56, sample_limit: -28, pitch: 2, data: 0x11, data_shift: 0, data_pitch: 4}, + EncodingOffsets{sample: 56 + 1, sample_limit: -28, pitch: 2, data: 0x11, data_shift: 4, data_pitch: 4}, + ], + [ + EncodingOffsets{sample: 56*2, sample_limit: -28*2, pitch: 2, data: 0x12, data_shift: 0, data_pitch: 4}, + EncodingOffsets{sample: 56*2 + 1, sample_limit: -28*2, pitch: 2, data: 0x12, data_shift: 4, data_pitch: 4}, + EncodingOffsets{sample: 56*3, sample_limit: -28*3, pitch: 2, data: 0x13, data_shift: 0, data_pitch: 4}, + EncodingOffsets{sample: 56*3 + 1, sample_limit: -28*3, pitch: 2, data: 0x13, data_shift: 4, data_pitch: 4} + ] +); +const MONO_4BIT: ([EncodingOffsets; 4], [EncodingOffsets; 4]) = ( + [ + EncodingOffsets{sample: 0, sample_limit: 0, pitch: 1, data: 0x10, data_shift: 0, data_pitch: 4}, + EncodingOffsets{sample: 28, sample_limit: -28, pitch: 1, data: 0x10, data_shift: 4, data_pitch: 4}, + EncodingOffsets{sample: 28*2, sample_limit: -28*2, pitch: 1, data: 0x11, data_shift: 0, data_pitch: 4}, + EncodingOffsets{sample: 28*3, sample_limit: -28*3, pitch: 1, data: 0x11, data_shift: 4, data_pitch: 4}, + ], + [ + EncodingOffsets{sample: 28*4, sample_limit: -28*4, pitch: 1, data: 0x12, data_shift: 0, data_pitch: 4}, + EncodingOffsets{sample: 28*5, sample_limit: -28*5, pitch: 1, data: 0x12, data_shift: 4, data_pitch: 4}, + EncodingOffsets{sample: 28*6, sample_limit: -28*6, pitch: 1, data: 0x13, data_shift: 0, data_pitch: 4}, + EncodingOffsets{sample: 28*7, sample_limit: -28*7, pitch: 1, data: 0x13, data_shift: 4, data_pitch: 4} + ] +); + +const STEREO_8BIT: [EncodingOffsets;4] = [ + EncodingOffsets{sample: 0, sample_limit: 0, pitch: 2, data: 0x10, data_shift: 0, data_pitch: 4}, + EncodingOffsets{sample: 1, sample_limit: 0, pitch: 2, data: 0x11, data_shift: 0, data_pitch: 4}, + EncodingOffsets{sample: 56, sample_limit: -28, pitch: 2, data: 0x12, data_shift: 0, data_pitch: 4}, + EncodingOffsets{sample: 56 + 1, sample_limit: -28, pitch: 2, data: 0x13, data_shift: 0, data_pitch: 4}, +]; +const MONO_8BIT: [EncodingOffsets;4] = [ + EncodingOffsets{sample: 0, sample_limit: 0, pitch: 1, data: 0x10, data_shift: 0, data_pitch: 4}, + EncodingOffsets{sample: 28, sample_limit: -28, pitch: 1, data: 0x11, data_shift: 0, data_pitch: 4}, + EncodingOffsets{sample: 28*2, sample_limit: -28*2, pitch: 1, data: 0x12, data_shift: 0, data_pitch: 4}, + EncodingOffsets{sample: 28*3, sample_limit: -28*3, pitch: 1, data: 0x13, data_shift: 0, data_pitch: 4}, ]; \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/images/args.rs b/src/Tools/psxfileconv/src/images/args.rs index b4849a95..edcad51f 100644 --- a/src/Tools/psxfileconv/src/images/args.rs +++ b/src/Tools/psxfileconv/src/images/args.rs @@ -1,69 +1,69 @@ -use clap::{Args, ValueEnum}; -use std::str::FromStr; - -#[derive(Args)] -pub struct Arguments { - #[clap(value_enum, value_parser)] - pub color_depth: ColorType, - - #[clap(value_enum, value_parser, default_value_t=ClutAlignment::None)] - pub clut_align: ClutAlignment, - - #[clap(long="semi-trans", default_value_t=false)] - pub semi_transparent: bool, - - #[clap(long="color-trans", default_value_t=false)] - pub transparent_palette: bool -} - -#[derive(Clone)] -pub struct Point { - pub x: u16, - pub y: u16, -} - -impl Point { - pub const POINT_VALUE_NAME:&'static str = "{x,y}"; -} - -impl std::default::Default for Point { - fn default() -> Self { - Point{x: 0, y: 0} - } -} - -impl ToString for Point { - fn to_string(&self) -> std::string::String { - "{0,0}".to_owned() - } -} - -impl FromStr for Point { - type Err = String; - - fn from_str(s: &str) -> Result { - let values:Vec<&str> = s.split(&['{', ',', '}']).filter_map(|value| if value.is_empty() {None} else {Some(value)}).collect(); - - if values.len() != 2 { - return Err(format!("Two values expected for Point but found {}", values.len())); - } - - let x = values[0].parse().map_err(|e| format!("Failed converting 'x' for Point: {e}"))?; - let y = values[1].parse().map_err(|e| format!("Failed converting 'y' for Point: {e}"))?; - Ok(Point{x, y}) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] -pub enum ColorType{ - Clut4, - Clut8, - Full16, -} - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] -pub enum ClutAlignment { - None, - Linear, - Block +use clap::{Args, ValueEnum}; +use std::str::FromStr; + +#[derive(Args)] +pub struct Arguments { + #[clap(value_enum, value_parser)] + pub color_depth: ColorType, + + #[clap(value_enum, value_parser, default_value_t=ClutAlignment::None)] + pub clut_align: ClutAlignment, + + #[clap(long="semi-trans", default_value_t=false)] + pub semi_transparent: bool, + + #[clap(long="color-trans", default_value_t=false)] + pub transparent_palette: bool +} + +#[derive(Clone)] +pub struct Point { + pub x: u16, + pub y: u16, +} + +impl Point { + pub const POINT_VALUE_NAME:&'static str = "{x,y}"; +} + +impl std::default::Default for Point { + fn default() -> Self { + Point{x: 0, y: 0} + } +} + +impl ToString for Point { + fn to_string(&self) -> std::string::String { + "{0,0}".to_owned() + } +} + +impl FromStr for Point { + type Err = String; + + fn from_str(s: &str) -> Result { + let values:Vec<&str> = s.split(&['{', ',', '}']).filter_map(|value| if value.is_empty() {None} else {Some(value)}).collect(); + + if values.len() != 2 { + return Err(format!("Two values expected for Point but found {}", values.len())); + } + + let x = values[0].parse().map_err(|e| format!("Failed converting 'x' for Point: {e}"))?; + let y = values[1].parse().map_err(|e| format!("Failed converting 'y' for Point: {e}"))?; + Ok(Point{x, y}) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] +pub enum ColorType{ + Clut4, + Clut8, + Full16, +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] +pub enum ClutAlignment { + None, + Linear, + Block } \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/images/mod.rs b/src/Tools/psxfileconv/src/images/mod.rs index 71b86bd2..c1298034 100644 --- a/src/Tools/psxfileconv/src/images/mod.rs +++ b/src/Tools/psxfileconv/src/images/mod.rs @@ -1,150 +1,150 @@ -pub mod args; -pub mod color_clut; -pub mod color_full16; -pub mod reduced_tim; -pub mod tim; -pub mod types; - -use args::{ColorType, ClutAlignment, Point}; -use color_clut::{IndexedImage, OutputType}; -use color_full16::{RgbaImage, RgbImage}; -use types::{Color as PSXColor, HeaderEncoder, PSXImageConverter, Rect}; -use image::{DynamicImage, io::Reader as ImageReader}; -use std::io::{Cursor, Write}; -use tool_helper::{Error, Input}; - -fn modify_palette(mut image: IndexedImage, clut_align: ClutAlignment, semi_transparent: bool, transparent_palette: bool) -> IndexedImage { - if semi_transparent { - for color in image.palette.iter_mut() { - *color = PSXColor::semi_transparent(color.get_red(), color.get_green(), color.get_blue()); - } - } - - if transparent_palette { - if clut_align == ClutAlignment::Block { - for color in image.palette.iter_mut().step_by(16) { - *color = PSXColor::transparent(); - } - } - - else { - if let Some(first_color) = image.palette.get_mut(0) { - *first_color = PSXColor::transparent(); - } - } - } - image -} - -fn encode(header_conv: &mut dyn HeaderEncoder, image: T, tex_pos: Point, clut_pos: Point, color_depth: ColorType, clut_align: ClutAlignment, output: &mut dyn Write) -> Result<(), Error> { - let (width, height) = { - fn return_error(clut_type: u32, div: u32, width: u16, height: u16) -> Result<(u16, u16), Error> { - return Err(Error::from_callback(|| {format!("CLUT {} images require a width divideable by {} (found width: {}/{}={}, height: {})", clut_type, div, width, div, (width as f32/div as f32), height)})); - } - - let width = image.width(); - let height = image.height(); - match color_depth { - ColorType::Clut4 => { - if width & 3 == 0 { - Ok((width/4, height)) - } - - else { - return_error(4, 4, width, height) - } - }, - ColorType::Clut8 => { - if width & 1 == 0 { - Ok((width/2, height)) - } - - else { - return_error(8, 2, width, height) - } - }, - ColorType::Full16 => { - Ok((width, height)) - } - } - }?; - let palette = image.get_palette(); - let (pal_width, pal_height) = { - if let Some(palette) = &palette { - let pal_length_adjusted = { - let pal_length = palette.len(); - if pal_length <= 16 { - 16u16 - } - - else { - 256u16 - } - }; - match clut_align { - ClutAlignment::None | - ClutAlignment::Linear => (pal_length_adjusted, 1u16), - ClutAlignment::Block => (16u16, pal_length_adjusted/16u16), - } - } - - else { - (0u16, 0u16) - } - }; - - header_conv.encode_settings(color_depth, Rect::new(tex_pos.x, tex_pos.y, width, height), Rect::new(clut_pos.x, clut_pos.y, pal_width, pal_height))?; - - header_conv.write_header(output)?; - header_conv.write_clut_header(output)?; - if let Some(palette) = palette { - let mut color_count = pal_width*pal_height; - for color in palette { - tool_helper::raw::write_raw(output, color)?; - color_count -= 1; - } - - while color_count > 0 { - tool_helper::raw::write_raw(output, &PSXColor::black())?; - color_count -= 1; - } - } - - header_conv.write_pixel_header(output)?; - for color in image { - tool_helper::raw::write_raw(output, &color)?; - } - - Ok(()) -} - -fn convert_full16(header_conv: &mut dyn HeaderEncoder, input: Input, output: &mut dyn Write, tex_pos: Point) -> Result<(), Error> { - match ImageReader::new(Cursor::new(tool_helper::input_to_vec(input)?)).with_guessed_format()?.decode() { - Ok(image) => { - match image { - DynamicImage::ImageRgb8(image) => encode(header_conv, RgbImage::new(image), tex_pos, Point::default(), ColorType::Full16, ClutAlignment::None, output), - DynamicImage::ImageRgba8(image) => encode(header_conv, RgbaImage::new(image), tex_pos, Point::default(), ColorType::Full16, ClutAlignment::None, output), - - _ => Err(Error::from_str("Only RGB and RGBA images are supported for 16bit encoding")) - } - }, - Err(error) => Err(Error::from_error(error)) - } -} - -fn convert_palette_based(header_conv: &mut dyn HeaderEncoder, input: Input, output: &mut dyn Write, tex_pos: Point, clut_pos: Point, color_type: ColorType, clut_align: ClutAlignment, semi_transparent: bool, transparent_palette: bool) -> Result<(), Error> { - match png::Decoder::new(input).read_info() { - Ok(reader) => { - let output_type = { - match color_type { - ColorType::Clut4 => OutputType::FourBit, - ColorType::Clut8 => OutputType::EightBit, - _ => return Err(Error::from_str("ColorType not supported")) - } - }; - - encode(header_conv, modify_palette(IndexedImage::new(reader, output_type)?, clut_align, semi_transparent, transparent_palette), tex_pos, clut_pos, color_type, clut_align, output) - }, - Err(error) => Err(Error::from_error(error)) - } +pub mod args; +pub mod color_clut; +pub mod color_full16; +pub mod reduced_tim; +pub mod tim; +pub mod types; + +use args::{ColorType, ClutAlignment, Point}; +use color_clut::{IndexedImage, OutputType}; +use color_full16::{RgbaImage, RgbImage}; +use types::{Color as PSXColor, HeaderEncoder, PSXImageConverter, Rect}; +use image::{DynamicImage, io::Reader as ImageReader}; +use std::io::{Cursor, Write}; +use tool_helper::{Error, Input}; + +fn modify_palette(mut image: IndexedImage, clut_align: ClutAlignment, semi_transparent: bool, transparent_palette: bool) -> IndexedImage { + if semi_transparent { + for color in image.palette.iter_mut() { + *color = PSXColor::semi_transparent(color.get_red(), color.get_green(), color.get_blue()); + } + } + + if transparent_palette { + if clut_align == ClutAlignment::Block { + for color in image.palette.iter_mut().step_by(16) { + *color = PSXColor::transparent(); + } + } + + else { + if let Some(first_color) = image.palette.get_mut(0) { + *first_color = PSXColor::transparent(); + } + } + } + image +} + +fn encode(header_conv: &mut dyn HeaderEncoder, image: T, tex_pos: Point, clut_pos: Point, color_depth: ColorType, clut_align: ClutAlignment, output: &mut dyn Write) -> Result<(), Error> { + let (width, height) = { + fn return_error(clut_type: u32, div: u32, width: u16, height: u16) -> Result<(u16, u16), Error> { + return Err(Error::from_callback(|| {format!("CLUT {} images require a width divideable by {} (found width: {}/{}={}, height: {})", clut_type, div, width, div, (width as f32/div as f32), height)})); + } + + let width = image.width(); + let height = image.height(); + match color_depth { + ColorType::Clut4 => { + if width & 3 == 0 { + Ok((width/4, height)) + } + + else { + return_error(4, 4, width, height) + } + }, + ColorType::Clut8 => { + if width & 1 == 0 { + Ok((width/2, height)) + } + + else { + return_error(8, 2, width, height) + } + }, + ColorType::Full16 => { + Ok((width, height)) + } + } + }?; + let palette = image.get_palette(); + let (pal_width, pal_height) = { + if let Some(palette) = &palette { + let pal_length_adjusted = { + let pal_length = palette.len(); + if pal_length <= 16 { + 16u16 + } + + else { + 256u16 + } + }; + match clut_align { + ClutAlignment::None | + ClutAlignment::Linear => (pal_length_adjusted, 1u16), + ClutAlignment::Block => (16u16, pal_length_adjusted/16u16), + } + } + + else { + (0u16, 0u16) + } + }; + + header_conv.encode_settings(color_depth, Rect::new(tex_pos.x, tex_pos.y, width, height), Rect::new(clut_pos.x, clut_pos.y, pal_width, pal_height))?; + + header_conv.write_header(output)?; + header_conv.write_clut_header(output)?; + if let Some(palette) = palette { + let mut color_count = pal_width*pal_height; + for color in palette { + tool_helper::raw::write_raw(output, color)?; + color_count -= 1; + } + + while color_count > 0 { + tool_helper::raw::write_raw(output, &PSXColor::black())?; + color_count -= 1; + } + } + + header_conv.write_pixel_header(output)?; + for color in image { + tool_helper::raw::write_raw(output, &color)?; + } + + Ok(()) +} + +fn convert_full16(header_conv: &mut dyn HeaderEncoder, input: Input, output: &mut dyn Write, tex_pos: Point) -> Result<(), Error> { + match ImageReader::new(Cursor::new(tool_helper::input_to_vec(input)?)).with_guessed_format()?.decode() { + Ok(image) => { + match image { + DynamicImage::ImageRgb8(image) => encode(header_conv, RgbImage::new(image), tex_pos, Point::default(), ColorType::Full16, ClutAlignment::None, output), + DynamicImage::ImageRgba8(image) => encode(header_conv, RgbaImage::new(image), tex_pos, Point::default(), ColorType::Full16, ClutAlignment::None, output), + + _ => Err(Error::from_str("Only RGB and RGBA images are supported for 16bit encoding")) + } + }, + Err(error) => Err(Error::from_error(error)) + } +} + +fn convert_palette_based(header_conv: &mut dyn HeaderEncoder, input: Input, output: &mut dyn Write, tex_pos: Point, clut_pos: Point, color_type: ColorType, clut_align: ClutAlignment, semi_transparent: bool, transparent_palette: bool) -> Result<(), Error> { + match png::Decoder::new(input).read_info() { + Ok(reader) => { + let output_type = { + match color_type { + ColorType::Clut4 => OutputType::FourBit, + ColorType::Clut8 => OutputType::EightBit, + _ => return Err(Error::from_str("ColorType not supported")) + } + }; + + encode(header_conv, modify_palette(IndexedImage::new(reader, output_type)?, clut_align, semi_transparent, transparent_palette), tex_pos, clut_pos, color_type, clut_align, output) + }, + Err(error) => Err(Error::from_error(error)) + } } \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/images/reduced_tim/mod.rs b/src/Tools/psxfileconv/src/images/reduced_tim/mod.rs index 6db242b1..c4496e42 100644 --- a/src/Tools/psxfileconv/src/images/reduced_tim/mod.rs +++ b/src/Tools/psxfileconv/src/images/reduced_tim/mod.rs @@ -1,16 +1,16 @@ -pub mod types; - -use super::args::{ColorType, Point}; -use std::io::Write; -use types::Header; -use tool_helper::{Error, Input}; - -pub type Arguments = super::args::Arguments; - -pub fn convert(args: Arguments, input: Input, output: &mut dyn Write) -> Result<(), Error> { - let mut header_conv = Header::default(); - match args.color_depth { - ColorType::Full16 => super::convert_full16(&mut header_conv, input, output, Point::default()), - _ => super::convert_palette_based(&mut header_conv, input, output, Point::default(), Point::default(), args.color_depth, args.clut_align, args.semi_transparent, args.transparent_palette), - } +pub mod types; + +use super::args::{ColorType, Point}; +use std::io::Write; +use types::Header; +use tool_helper::{Error, Input}; + +pub type Arguments = super::args::Arguments; + +pub fn convert(args: Arguments, input: Input, output: &mut dyn Write) -> Result<(), Error> { + let mut header_conv = Header::default(); + match args.color_depth { + ColorType::Full16 => super::convert_full16(&mut header_conv, input, output, Point::default()), + _ => super::convert_palette_based(&mut header_conv, input, output, Point::default(), Point::default(), args.color_depth, args.clut_align, args.semi_transparent, args.transparent_palette), + } } \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/images/reduced_tim/types.rs b/src/Tools/psxfileconv/src/images/reduced_tim/types.rs index 5c91093d..c2f867b7 100644 --- a/src/Tools/psxfileconv/src/images/reduced_tim/types.rs +++ b/src/Tools/psxfileconv/src/images/reduced_tim/types.rs @@ -1,63 +1,63 @@ -use super::super::{args::ColorType, types::{HeaderEncoder, set_member_value, Rect}}; -use std::io::Write; -use tool_helper::{bits::BitRange, raw::RawConversion, Error}; - -#[repr(packed(1))] -pub struct Header { - value: u32 -} - -impl Header { - const TEX_WIDTH_BIT_RANGE: BitRange = BitRange::from_to(0, 8); - const TEX_HEIGHT_BIT_RANGE: BitRange = BitRange::from_to(9, 16); - const CLUT_WIDTH_BIT_RANGE: BitRange = BitRange::from_to(17, 22); - const CLUT_HEIGHT_BIT_RANGE: BitRange = BitRange::from_to(23, 31); -} - -impl Default for Header { - fn default() -> Self { - Header{value: 0} - } -} - -impl HeaderEncoder for Header { - fn encode_settings(&mut self, _color_type: ColorType, tex_rect: Rect, clut_rect: Rect) -> Result<(), Error> { - let clut_width = clut_rect.width; - let clut_height = clut_rect.height; - let tex_width = tex_rect.width; - let tex_height = tex_rect.height; - - if tex_width & 1 == 1 || tex_height & 1 == 1 { - Err(Error::from_text(format!("Image size (width: {}, height: {}) needs to be even", tex_width, tex_height))) - } - - else { - let value = set_member_value!(set_member_value!(set_member_value!(set_member_value!(0, - tex_width, 1, u32), - tex_height, 1, u32), - clut_width, 4, u32), - clut_height, 0, u32); - - self.value = value; - Ok(()) - } - } - - fn write_header(&self, output: &mut dyn Write) -> Result { - Ok(output.write(&self.convert_to_raw())?) - } - - fn write_clut_header(&self, _output: &mut dyn Write) -> Result { - Ok(0) - } - - fn write_pixel_header(&self, _output: &mut dyn Write) -> Result { - Ok(0) - } -} - -impl RawConversion<4> for Header { - fn convert_to_raw(&self) -> [u8; 4] { - self.value.to_le_bytes() - } +use super::super::{args::ColorType, types::{HeaderEncoder, set_member_value, Rect}}; +use std::io::Write; +use tool_helper::{bits::BitRange, raw::RawConversion, Error}; + +#[repr(packed(1))] +pub struct Header { + value: u32 +} + +impl Header { + const TEX_WIDTH_BIT_RANGE: BitRange = BitRange::from_to(0, 8); + const TEX_HEIGHT_BIT_RANGE: BitRange = BitRange::from_to(9, 16); + const CLUT_WIDTH_BIT_RANGE: BitRange = BitRange::from_to(17, 22); + const CLUT_HEIGHT_BIT_RANGE: BitRange = BitRange::from_to(23, 31); +} + +impl Default for Header { + fn default() -> Self { + Header{value: 0} + } +} + +impl HeaderEncoder for Header { + fn encode_settings(&mut self, _color_type: ColorType, tex_rect: Rect, clut_rect: Rect) -> Result<(), Error> { + let clut_width = clut_rect.width; + let clut_height = clut_rect.height; + let tex_width = tex_rect.width; + let tex_height = tex_rect.height; + + if tex_width & 1 == 1 || tex_height & 1 == 1 { + Err(Error::from_text(format!("Image size (width: {}, height: {}) needs to be even", tex_width, tex_height))) + } + + else { + let value = set_member_value!(set_member_value!(set_member_value!(set_member_value!(0, + tex_width, 1, u32), + tex_height, 1, u32), + clut_width, 4, u32), + clut_height, 0, u32); + + self.value = value; + Ok(()) + } + } + + fn write_header(&self, output: &mut dyn Write) -> Result { + Ok(output.write(&self.convert_to_raw())?) + } + + fn write_clut_header(&self, _output: &mut dyn Write) -> Result { + Ok(0) + } + + fn write_pixel_header(&self, _output: &mut dyn Write) -> Result { + Ok(0) + } +} + +impl RawConversion<4> for Header { + fn convert_to_raw(&self) -> [u8; 4] { + self.value.to_le_bytes() + } } \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/images/tim/mod.rs b/src/Tools/psxfileconv/src/images/tim/mod.rs index d08ad1a0..6c92f05e 100644 --- a/src/Tools/psxfileconv/src/images/tim/mod.rs +++ b/src/Tools/psxfileconv/src/images/tim/mod.rs @@ -1,29 +1,29 @@ -pub mod types; - -use super::args::{ColorType, Point}; -use clap::Args; -use std::io::Write; -use types::Header; -use tool_helper::{Error, Input}; - -#[derive(Args)] -pub struct Arguments { - #[clap(flatten)] - global: super::args::Arguments, - - #[clap(long, value_parser, default_value_t, value_name = Point::POINT_VALUE_NAME)] - clut_pos: Point, - - #[clap(long, value_parser, default_value_t, value_name = Point::POINT_VALUE_NAME)] - tex_pos: Point, -} - -pub fn convert(args: Arguments, input: Input, output: &mut dyn Write) -> Result<(), Error> { - let global_args = args.global; - let mut header_conv = Header::default(); - - match global_args.color_depth { - ColorType::Full16 => super::convert_full16(&mut header_conv, input, output, args.tex_pos), - _ => super::convert_palette_based(&mut header_conv, input, output, args.tex_pos, args.clut_pos, global_args.color_depth, global_args.clut_align, global_args.semi_transparent, global_args.transparent_palette), - } +pub mod types; + +use super::args::{ColorType, Point}; +use clap::Args; +use std::io::Write; +use types::Header; +use tool_helper::{Error, Input}; + +#[derive(Args)] +pub struct Arguments { + #[clap(flatten)] + global: super::args::Arguments, + + #[clap(long, value_parser, default_value_t, value_name = Point::POINT_VALUE_NAME)] + clut_pos: Point, + + #[clap(long, value_parser, default_value_t, value_name = Point::POINT_VALUE_NAME)] + tex_pos: Point, +} + +pub fn convert(args: Arguments, input: Input, output: &mut dyn Write) -> Result<(), Error> { + let global_args = args.global; + let mut header_conv = Header::default(); + + match global_args.color_depth { + ColorType::Full16 => super::convert_full16(&mut header_conv, input, output, args.tex_pos), + _ => super::convert_palette_based(&mut header_conv, input, output, args.tex_pos, args.clut_pos, global_args.color_depth, global_args.clut_align, global_args.semi_transparent, global_args.transparent_palette), + } } \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/images/tim/types.rs b/src/Tools/psxfileconv/src/images/tim/types.rs index 93c4eaff..a0155236 100644 --- a/src/Tools/psxfileconv/src/images/tim/types.rs +++ b/src/Tools/psxfileconv/src/images/tim/types.rs @@ -1,100 +1,100 @@ -use super::super::{args::ColorType, types::{HeaderEncoder, Rect}}; -use std::io::Write; -use tool_helper::{bits::{Bit, BitRange}, raw::RawConversion, Error}; - - -pub struct Header { - flag: u32, - clut_block: DataBlock, - pixel_block: DataBlock, -} - -impl Header { - const ID_VALUE: u32 = BitRange::from_to(0, 7).as_value(0x10) as u32; - const ID_VERSION_VALUE:u32 = BitRange::from_to(8, 15).as_value(0x0) as u32; - - const FLAG_PMODE_BIT_RANGE: BitRange = BitRange::from_to(0, 2); - const FLAG_CF_BIT: Bit = Bit::at(3); - - const ID:u32 = Self::ID_VALUE | Self::ID_VERSION_VALUE; -} - -impl Default for Header { - fn default() -> Self { - Header{flag: 0, clut_block: DataBlock::default(), pixel_block: DataBlock::default()} - } -} - -impl HeaderEncoder for Header { - fn encode_settings(&mut self, color_type: ColorType, tex_rect: Rect, clut_rect: Rect) -> Result<(), Error> { - self.flag = match color_type { - ColorType::Clut4 => (Self::FLAG_PMODE_BIT_RANGE.as_value(0x0) | Self::FLAG_CF_BIT.as_value(true)) as u32, - ColorType::Clut8 => (Self::FLAG_PMODE_BIT_RANGE.as_value(0x1) | Self::FLAG_CF_BIT.as_value(true)) as u32, - ColorType::Full16 => (Self::FLAG_PMODE_BIT_RANGE.as_value(0x2) | Self::FLAG_CF_BIT.as_value(false)) as u32, - }; - - self.clut_block = DataBlock::new(clut_rect); - self.pixel_block = DataBlock::new(tex_rect); - Ok(()) - } - - fn write_header(&self, output: &mut dyn Write) -> Result { - let bytes = output.write(&Header::ID.to_le_bytes())?; - Ok(bytes + output.write(&self.flag.to_le_bytes())?) - } - - fn write_clut_header(&self, output: &mut dyn Write) -> Result { - if self.clut_block.w > 0 { - Ok(output.write(&self.clut_block.convert_to_raw())?) - } - - else { - Ok(0) - } - } - - fn write_pixel_header(&self, output: &mut dyn Write) -> Result { - Ok(output.write(&self.pixel_block.convert_to_raw())?) - } -} - -pub struct DataBlock { - bytes: u32, - x: u16, - y: u16, - w: u16, - h: u16, -} - -impl DataBlock { - const RAW_HEADER_SIZE: usize = (4*std::mem::size_of::()) + std::mem::size_of::(); - - pub fn new(rect: Rect) -> DataBlock { - let x = rect.x; - let y = rect.y; - let w = rect.width; - let h = rect.height; - - let bytes = ((w as usize*h as usize*std::mem::size_of::()) + Self::RAW_HEADER_SIZE) as u32; - DataBlock{bytes, x, y, w, h} - } -} - -impl std::default::Default for DataBlock { - fn default() -> Self { - DataBlock{bytes: 0, x: 0, y: 0, w: 0, h: 0} - } -} - -impl RawConversion<{Self::RAW_HEADER_SIZE}> for DataBlock { - fn convert_to_raw(&self) -> [u8; Self::RAW_HEADER_SIZE] { - let mut raw = [0u8; Self::RAW_HEADER_SIZE]; - - raw[ 0..4].copy_from_slice(&self.bytes.to_le_bytes()); - raw[ 4..6].copy_from_slice(&self.x.to_le_bytes()); - raw[ 6..8].copy_from_slice(&self.y.to_le_bytes()); - raw[ 8..10].copy_from_slice(&self.w.to_le_bytes()); - raw[10..12].copy_from_slice(&self.h.to_le_bytes()); - raw - } +use super::super::{args::ColorType, types::{HeaderEncoder, Rect}}; +use std::io::Write; +use tool_helper::{bits::{Bit, BitRange}, raw::RawConversion, Error}; + + +pub struct Header { + flag: u32, + clut_block: DataBlock, + pixel_block: DataBlock, +} + +impl Header { + const ID_VALUE: u32 = BitRange::from_to(0, 7).as_value(0x10) as u32; + const ID_VERSION_VALUE:u32 = BitRange::from_to(8, 15).as_value(0x0) as u32; + + const FLAG_PMODE_BIT_RANGE: BitRange = BitRange::from_to(0, 2); + const FLAG_CF_BIT: Bit = Bit::at(3); + + const ID:u32 = Self::ID_VALUE | Self::ID_VERSION_VALUE; +} + +impl Default for Header { + fn default() -> Self { + Header{flag: 0, clut_block: DataBlock::default(), pixel_block: DataBlock::default()} + } +} + +impl HeaderEncoder for Header { + fn encode_settings(&mut self, color_type: ColorType, tex_rect: Rect, clut_rect: Rect) -> Result<(), Error> { + self.flag = match color_type { + ColorType::Clut4 => (Self::FLAG_PMODE_BIT_RANGE.as_value(0x0) | Self::FLAG_CF_BIT.as_value(true)) as u32, + ColorType::Clut8 => (Self::FLAG_PMODE_BIT_RANGE.as_value(0x1) | Self::FLAG_CF_BIT.as_value(true)) as u32, + ColorType::Full16 => (Self::FLAG_PMODE_BIT_RANGE.as_value(0x2) | Self::FLAG_CF_BIT.as_value(false)) as u32, + }; + + self.clut_block = DataBlock::new(clut_rect); + self.pixel_block = DataBlock::new(tex_rect); + Ok(()) + } + + fn write_header(&self, output: &mut dyn Write) -> Result { + let bytes = output.write(&Header::ID.to_le_bytes())?; + Ok(bytes + output.write(&self.flag.to_le_bytes())?) + } + + fn write_clut_header(&self, output: &mut dyn Write) -> Result { + if self.clut_block.w > 0 { + Ok(output.write(&self.clut_block.convert_to_raw())?) + } + + else { + Ok(0) + } + } + + fn write_pixel_header(&self, output: &mut dyn Write) -> Result { + Ok(output.write(&self.pixel_block.convert_to_raw())?) + } +} + +pub struct DataBlock { + bytes: u32, + x: u16, + y: u16, + w: u16, + h: u16, +} + +impl DataBlock { + const RAW_HEADER_SIZE: usize = (4*std::mem::size_of::()) + std::mem::size_of::(); + + pub fn new(rect: Rect) -> DataBlock { + let x = rect.x; + let y = rect.y; + let w = rect.width; + let h = rect.height; + + let bytes = ((w as usize*h as usize*std::mem::size_of::()) + Self::RAW_HEADER_SIZE) as u32; + DataBlock{bytes, x, y, w, h} + } +} + +impl std::default::Default for DataBlock { + fn default() -> Self { + DataBlock{bytes: 0, x: 0, y: 0, w: 0, h: 0} + } +} + +impl RawConversion<{Self::RAW_HEADER_SIZE}> for DataBlock { + fn convert_to_raw(&self) -> [u8; Self::RAW_HEADER_SIZE] { + let mut raw = [0u8; Self::RAW_HEADER_SIZE]; + + raw[ 0..4].copy_from_slice(&self.bytes.to_le_bytes()); + raw[ 4..6].copy_from_slice(&self.x.to_le_bytes()); + raw[ 6..8].copy_from_slice(&self.y.to_le_bytes()); + raw[ 8..10].copy_from_slice(&self.w.to_le_bytes()); + raw[10..12].copy_from_slice(&self.h.to_le_bytes()); + raw + } } \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/lib.rs b/src/Tools/psxfileconv/src/lib.rs index 02d1320e..5da340bc 100644 --- a/src/Tools/psxfileconv/src/lib.rs +++ b/src/Tools/psxfileconv/src/lib.rs @@ -1,3 +1,3 @@ -pub mod audio; -pub mod images; +pub mod audio; +pub mod images; pub mod nothing; \ No newline at end of file diff --git a/src/Tools/psxfileconv/src/nothing/mod.rs b/src/Tools/psxfileconv/src/nothing/mod.rs index 390c74fe..0c9e8a56 100644 --- a/src/Tools/psxfileconv/src/nothing/mod.rs +++ b/src/Tools/psxfileconv/src/nothing/mod.rs @@ -1,7 +1,7 @@ -use std::io::Write; -use tool_helper::{Error, Input}; - -pub fn copy(input: &mut Input, output: &mut dyn Write) -> Result<(), Error> { - std::io::copy(input, output)?; - Ok(()) +use std::io::Write; +use tool_helper::{Error, Input}; + +pub fn copy(input: &mut Input, output: &mut dyn Write) -> Result<(), Error> { + std::io::copy(input, output)?; + Ok(()) } \ No newline at end of file diff --git a/src/Tools/psxreadmap/Makefile b/src/Tools/psxreadmap/Makefile index b7ff0de0..2bb6d498 100644 --- a/src/Tools/psxreadmap/Makefile +++ b/src/Tools/psxreadmap/Makefile @@ -1,13 +1,13 @@ -include ../Common.mk - -ARTIFACT = psxreadmap - -.PHONY: $(WINDOWS_ARTIFACT) $(UNIX_ARTIFACT) -$(WINDOWS_ARTIFACT): - $(call cargo_windows_default) - -$(UNIX_ARTIFACT): - $(call cargo_unix_default) - -all-windows: $(WINDOWS_ARTIFACT) +include ../Common.mk + +ARTIFACT = psxreadmap + +.PHONY: $(WINDOWS_ARTIFACT) $(UNIX_ARTIFACT) +$(WINDOWS_ARTIFACT): + $(call cargo_windows_default) + +$(UNIX_ARTIFACT): + $(call cargo_unix_default) + +all-windows: $(WINDOWS_ARTIFACT) all: $(UNIX_ARTIFACT) \ No newline at end of file diff --git a/src/Tools/psxreadmap/src/main.rs b/src/Tools/psxreadmap/src/main.rs index 0a3d3f09..89878e45 100644 --- a/src/Tools/psxreadmap/src/main.rs +++ b/src/Tools/psxreadmap/src/main.rs @@ -1,117 +1,117 @@ -use clap::Parser; -use crossterm::{event::{self, Event as CEvent, KeyboardEnhancementFlags, KeyEventKind, PushKeyboardEnhancementFlags}, execute, terminal}; -use psxreadmap::{ConsoleUI, Event, EventReceiver, Terminal, load_memory_map, UIState}; -use std::{io::{self, Stdout}, path::PathBuf, sync::mpsc, thread, time::{Duration, Instant}}; -use tool_helper::{Error, exit_with_error, open_output}; -use ratatui::backend::CrosstermBackend; - -pub const RUN_DUMP_TOOL_IN_WSL:bool = cfg!(windows); - -#[derive(Parser)] -#[clap(about = "Opens and scans an ELF file to print extended memory information", long_about = None)] -struct CommandLine { - #[clap(value_parser, help="Input ELF file for scannning")] - input: PathBuf, - #[clap(long="wsl", help="Run \"objdump\" in WSL", default_value_t=RUN_DUMP_TOOL_IN_WSL)] - use_wsl: bool, - #[clap(long="raw", default_value_t=false)] - raw_dump: bool, - #[clap(short='o', help="Output a memory map file with running the tool")] - output: Option -} - -pub fn main() { - match CommandLine::try_parse() { - Ok(cmd_line) => { - match run_main(cmd_line) { - Ok(_) => (), - Err(error) => exit_with_error(error) - } - }, - Err(error) => { - println!("{})", error) - } - } -} - -fn run_main(cmd: CommandLine) -> Result<(), Error> { - if cmd.raw_dump { - psxreadmap::get_tool_output(cmd.use_wsl, cmd.input, open_output(&cmd.output)?)?; - return Ok(()); - } - - let memory_map = load_memory_map(cmd.use_wsl, cmd.input)?; dump_memory_map(cmd.output, &memory_map)?; - let rx = start_event_loop(); - let terminal = setup_console()?; - let mut console_ui = ConsoleUI::new(rx, terminal); - - console_ui.update_data(memory_map)?; - loop { - match console_ui.update()? { - UIState::Alive => (), - UIState::Render => {console_ui.render()?;} - UIState::Terminated => break - } - } - - console_ui.close() -} - -fn dump_memory_map(output: Option, memory_map: &readmap::types::MemoryMap) -> Result<(), Error> { - if let Some(output) = output { - let output = tool_helper::open_output(&Some(output))?; - - readmap::dump::write(output, &memory_map)?; - } - - Ok(()) -} - -fn start_event_loop() -> EventReceiver { - // Set up a mpsc (multiproducer, single consumer) channel to communicate between the input handler and the rendering loop. - let (tx, rx) = mpsc::channel(); - let tick_rate = Duration::from_millis(200); - thread::spawn(move || { - let mut last_tick = Instant::now(); - - tx.send(Event::ForceRender).expect("Send ForceRender command!"); - loop { - let timeout = tick_rate.checked_sub(last_tick.elapsed()).unwrap_or_else(|| Duration::from_secs(0)); - if event::poll(timeout).expect("Event poll working") { - if let CEvent::Key(key) = event::read().expect("Can read key input") { - if key.kind == KeyEventKind::Release { - tx.send(Event::Input(key)).expect("Can send KeyInput"); - } - } - } - - if last_tick.elapsed() >= tick_rate { - if let Ok(_) = tx.send(Event::Tick) { - last_tick = Instant::now(); - } - } - } - }); - - rx -} - -fn setup_console() -> Result { - fn open_stdout() -> Result { - let mut stdout = io::stdout(); - if cfg!(unix) { - execute!(stdout, PushKeyboardEnhancementFlags(KeyboardEnhancementFlags::REPORT_EVENT_TYPES))?; - } - Ok(stdout) - } - - terminal::enable_raw_mode()?; - - // Setup Crossterm for the Terminal - let stdout = open_stdout()?; - let backend = CrosstermBackend::new(stdout); - let mut terminal = Terminal::new(backend)?; - - terminal.clear()?; - Ok(terminal) +use clap::Parser; +use crossterm::{event::{self, Event as CEvent, KeyboardEnhancementFlags, KeyEventKind, PushKeyboardEnhancementFlags}, execute, terminal}; +use psxreadmap::{ConsoleUI, Event, EventReceiver, Terminal, load_memory_map, UIState}; +use std::{io::{self, Stdout}, path::PathBuf, sync::mpsc, thread, time::{Duration, Instant}}; +use tool_helper::{Error, exit_with_error, open_output}; +use ratatui::backend::CrosstermBackend; + +pub const RUN_DUMP_TOOL_IN_WSL:bool = cfg!(windows); + +#[derive(Parser)] +#[clap(about = "Opens and scans an ELF file to print extended memory information", long_about = None)] +struct CommandLine { + #[clap(value_parser, help="Input ELF file for scannning")] + input: PathBuf, + #[clap(long="wsl", help="Run \"objdump\" in WSL", default_value_t=RUN_DUMP_TOOL_IN_WSL)] + use_wsl: bool, + #[clap(long="raw", default_value_t=false)] + raw_dump: bool, + #[clap(short='o', help="Output a memory map file with running the tool")] + output: Option +} + +pub fn main() { + match CommandLine::try_parse() { + Ok(cmd_line) => { + match run_main(cmd_line) { + Ok(_) => (), + Err(error) => exit_with_error(error) + } + }, + Err(error) => { + println!("{})", error) + } + } +} + +fn run_main(cmd: CommandLine) -> Result<(), Error> { + if cmd.raw_dump { + psxreadmap::get_tool_output(cmd.use_wsl, cmd.input, open_output(&cmd.output)?)?; + return Ok(()); + } + + let memory_map = load_memory_map(cmd.use_wsl, cmd.input)?; dump_memory_map(cmd.output, &memory_map)?; + let rx = start_event_loop(); + let terminal = setup_console()?; + let mut console_ui = ConsoleUI::new(rx, terminal); + + console_ui.update_data(memory_map)?; + loop { + match console_ui.update()? { + UIState::Alive => (), + UIState::Render => {console_ui.render()?;} + UIState::Terminated => break + } + } + + console_ui.close() +} + +fn dump_memory_map(output: Option, memory_map: &readmap::types::MemoryMap) -> Result<(), Error> { + if let Some(output) = output { + let output = tool_helper::open_output(&Some(output))?; + + readmap::dump::write(output, &memory_map)?; + } + + Ok(()) +} + +fn start_event_loop() -> EventReceiver { + // Set up a mpsc (multiproducer, single consumer) channel to communicate between the input handler and the rendering loop. + let (tx, rx) = mpsc::channel(); + let tick_rate = Duration::from_millis(200); + thread::spawn(move || { + let mut last_tick = Instant::now(); + + tx.send(Event::ForceRender).expect("Send ForceRender command!"); + loop { + let timeout = tick_rate.checked_sub(last_tick.elapsed()).unwrap_or_else(|| Duration::from_secs(0)); + if event::poll(timeout).expect("Event poll working") { + if let CEvent::Key(key) = event::read().expect("Can read key input") { + if key.kind == KeyEventKind::Release { + tx.send(Event::Input(key)).expect("Can send KeyInput"); + } + } + } + + if last_tick.elapsed() >= tick_rate { + if let Ok(_) = tx.send(Event::Tick) { + last_tick = Instant::now(); + } + } + } + }); + + rx +} + +fn setup_console() -> Result { + fn open_stdout() -> Result { + let mut stdout = io::stdout(); + if cfg!(unix) { + execute!(stdout, PushKeyboardEnhancementFlags(KeyboardEnhancementFlags::REPORT_EVENT_TYPES))?; + } + Ok(stdout) + } + + terminal::enable_raw_mode()?; + + // Setup Crossterm for the Terminal + let stdout = open_stdout()?; + let backend = CrosstermBackend::new(stdout); + let mut terminal = Terminal::new(backend)?; + + terminal.clear()?; + Ok(terminal) } \ No newline at end of file diff --git a/src/Tools/tool_helper/Makefile b/src/Tools/tool_helper/Makefile index 4f2f74f4..096c5700 100644 --- a/src/Tools/tool_helper/Makefile +++ b/src/Tools/tool_helper/Makefile @@ -1,13 +1,13 @@ -include ../Common.mk - -ARTIFACT = tool_helper - -.PHONY: $(WINDOWS_ARTIFACT) $(UNIX_ARTIFACT) -$(WINDOWS_ARTIFACT): - $(call cargo_windows_default) - -$(UNIX_ARTIFACT): - $(call cargo_unix_default) - -all-windows: $(WINDOWS_ARTIFACT) +include ../Common.mk + +ARTIFACT = tool_helper + +.PHONY: $(WINDOWS_ARTIFACT) $(UNIX_ARTIFACT) +$(WINDOWS_ARTIFACT): + $(call cargo_windows_default) + +$(UNIX_ARTIFACT): + $(call cargo_unix_default) + +all-windows: $(WINDOWS_ARTIFACT) all: $(UNIX_ARTIFACT) \ No newline at end of file diff --git a/src/Tools/tool_helper/src/lib.rs b/src/Tools/tool_helper/src/lib.rs index 1e515631..09dca68d 100644 --- a/src/Tools/tool_helper/src/lib.rs +++ b/src/Tools/tool_helper/src/lib.rs @@ -1,267 +1,267 @@ -use colored::*; -use envmnt::{ExpandOptions, ExpansionType}; -use std::{boxed::Box, fs::OpenOptions, io::{BufRead, BufReader, BufWriter, Read, Write}, path::PathBuf, str::FromStr}; - -pub mod bits; -pub mod compress; -pub mod raw; -pub mod vec_helper; - -pub type BufferedInputFile = BufReader; -pub type Output = Box; -pub type Input = Box; - -#[macro_export] -macro_rules! format_if_error { - ($result:expr, $format_text:literal) => { - tool_helper::callback_if_any_error($result, |error_text| { - format!($format_text, error_text=error_text) - }) - }; - ($result:expr, $format_text:literal, $($arg:expr)*) => { - tool_helper::callback_if_any_error($result, |error_text| { - format!($format_text, $($arg),*, error_text=error_text) - }) - }; -} - -#[macro_export] -macro_rules! format_if_error_drop_cause { - ($result:expr, $format_text:literal) => { - tool_helper::callback_if_any_error($result, |error_text| { - format!($format_text) - }) - }; - ($result:expr, $format_text:literal, $($arg:expr)*) => { - tool_helper::callback_if_any_error($result, |error_text| { - format!($format_text, $($arg),*) - }) - }; -} - -const DEFAULT_ENV_EXPAND_OPTIONS : ExpandOptions = ExpandOptions{expansion_type: Some(ExpansionType::All), default_to_empty: false}; - -pub struct Error { - pub exit_code: i32, - pub text: String, -} - -impl Error { - const DEFAULT_EXITCODE:i32 = -1; - - pub fn from_str(str: &str) -> Error { - Self::from_text(str.to_owned()) - } - - pub fn from_text(text: String) -> Error { - Error{exit_code: Self::DEFAULT_EXITCODE, text} - } - - pub fn from_error(error: T) -> Error where T: std::fmt::Display { - Error::from_text(error.to_string()) - } - - pub fn from_core_error(error: T) -> Error where T: core::fmt::Display { - Error::from_text(error.to_string()) - } - - pub fn from_callback(callback: F) -> Error where F: Fn() -> String { - Error::from_text(callback()) - } - - pub fn not_implemented(function: &str) -> Error { - Error::from_text(format!("{} not implemented yet", function)) - } - - pub fn try_or_new(result: std::result::Result) -> Result where S: std::fmt::Display { - match result { - Ok(value) => Ok(value), - Err(error) => Err(Error{exit_code: Self::DEFAULT_EXITCODE, text: error.to_string()}), - } - } - - pub fn ok_or_new(option: Option, error_text: F) -> Result where F: Fn () -> String{ - Ok(option.ok_or(Error::from_callback(error_text))?) - } - - pub fn print_generic_to_std_err(object: &T) { - eprintln!("{}", format!("ERROR: {}", object).red()); - } - - pub fn print_to_std_err(&self) { - Self::print_generic_to_std_err(self) - } -} - -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.text) - } -} - -impl std::convert::From for Error { - fn from(error: std::io::Error) -> Self { - Error{exit_code: -1, text: error.to_string()} - } -} - -impl std::convert::From for Error { - fn from(error: cdtypes::Error) -> Self { - Error::from_error(error) - } -} - -impl std::convert::From for Error { - fn from(error: std::convert::Infallible) -> Self { - Error::from_error(error) - } -} - -impl std::convert::From for Error { - fn from(error: std::sync::mpsc::RecvError) -> Self { - Error::from_error(error) - } -} - -impl std::convert::From for Error { - fn from(error: hound::Error) -> Self { - Error::from_error(error) - } -} - -pub fn exit_with_error(error: Error) { - error.print_to_std_err(); - std::process::exit(error.exit_code); -} - -pub fn print_warning(str: String) { - eprintln!("{}", str.yellow()); -} - -pub fn prefix_if_error(prefix: &str, result: Result) -> Result { - match result { - Ok(value) => Ok(value), - Err(mut error) => { - let mut new_text = String::from(prefix); - - new_text.push_str(error.text.as_str()); - error.text = new_text; - Err(error) - }, - } -} - -pub fn callback_if_error String, T>(result: Result, callback: F) -> Result { - match result { - Ok(value) => Ok(value), - Err(mut error) => { - error.text = callback(error.text); - - Err(error) - } - } -} - -pub fn callback_if_any_error String, T, E: std::string::ToString>(result: Result, callback: F) -> Result { - match result { - Ok(value) => Ok(value), - Err(error) => { - Err(Error::from_text(callback(error.to_string()))) - } - } -} - -pub fn string_with_env_from(str: &str) -> String { - String::from(envmnt::expand(str, Some(DEFAULT_ENV_EXPAND_OPTIONS))) -} - -pub fn path_with_env_from(path: &str) -> PathBuf { - PathBuf::from(envmnt::expand(path, Some(DEFAULT_ENV_EXPAND_OPTIONS))) -} - -pub fn open_output_file(output_path: &PathBuf) -> Result, Error> { - Ok(std::io::BufWriter::new(std::fs::File::create(win_or_wsl_path(output_path)?)?)) -} - -pub fn open_output(output_file: &Option) -> Result { - match output_file { - Some(output_path) => Ok(Box::new(open_output_file(&output_path)?)), - None => Ok(Box::new(BufWriter::new(std::io::stdout()))), - } -} - -pub fn open_input(input_file: &Option) -> Result { - match input_file { - Some(input_path) => Ok(Box::new(open_input_file_buffered(&input_path)?)), - None => Ok(Box::new(BufReader::new(std::io::stdin()))), - } -} - -pub fn open_input_file_buffered(input_path: &PathBuf) -> Result { - Ok(BufReader::new(std::fs::File::open(win_or_wsl_path(input_path)?)?)) -} - -pub fn os_str_to_string(input: &std::ffi::OsStr, name: &str) -> Result { - Ok(Error::ok_or_new(input.to_str(), ||format!("Converting {} to UTF-8 failed", name))?.to_owned()) -} - -pub fn get_file_name_from_path_buf(input: &PathBuf, name: &str) -> Result { - os_str_to_string(Error::ok_or_new(input.file_name(), ||format!("No {} file name found", name))?, name) -} - -pub fn input_to_vec(input: Input) -> Result, Error> { - let mut data = Vec::new(); - - for byte in input.bytes() { - data.push(byte?); - } - - Ok(data) -} - -pub fn read_file(file_path: &PathBuf) -> Result, Error> { - if let Some(ext) = file_path.extension() { - if ext == "subst" { - // File needs substitution! - let file_content = read_file_to_string(file_path)?; - return Ok(string_with_env_from(&file_content).into_bytes()); - } - } - - match std::fs::read(win_or_wsl_path(file_path)?) { - Ok(data) => Ok(data), - Err(error) => create_file_read_error(file_path, error), - } -} - -pub fn read_file_to_string(file_path: &PathBuf) -> Result { - match std::fs::read_to_string(win_or_wsl_path(file_path)?) { - Ok(string) => Ok(string), - Err(error) => create_file_read_error(file_path, error), - } -} - -pub fn write_file(file_path: &PathBuf, data: Vec) -> Result<(), Error> { - let mut file = OpenOptions::new().read(true).write(true).truncate(true).create(true).open(file_path)?; - - file.write_all(data.as_slice())?; - Ok(()) -} - -fn create_file_read_error(file_path: &PathBuf, error: std::io::Error) -> Result { - Err(Error::from_text(format!("Failed reading file {} with error: \"{}\"", file_path.display(), error))) -} - -fn win_or_wsl_path(path: &PathBuf) -> Result { - let path = path.clone(); - if path.exists() { - Ok(path) - } - - else { - match path.into_os_string().into_string() { - Ok(path) => Ok(PathBuf::from_str(wslpath::force_convert(path).as_str())?), - Err(error) => Err(Error::from_text(format!("Failed converting {:?} to string for win/wsl mapping", error))) - } - } +use colored::*; +use envmnt::{ExpandOptions, ExpansionType}; +use std::{boxed::Box, fs::OpenOptions, io::{BufRead, BufReader, BufWriter, Read, Write}, path::PathBuf, str::FromStr}; + +pub mod bits; +pub mod compress; +pub mod raw; +pub mod vec_helper; + +pub type BufferedInputFile = BufReader; +pub type Output = Box; +pub type Input = Box; + +#[macro_export] +macro_rules! format_if_error { + ($result:expr, $format_text:literal) => { + tool_helper::callback_if_any_error($result, |error_text| { + format!($format_text, error_text=error_text) + }) + }; + ($result:expr, $format_text:literal, $($arg:expr)*) => { + tool_helper::callback_if_any_error($result, |error_text| { + format!($format_text, $($arg),*, error_text=error_text) + }) + }; +} + +#[macro_export] +macro_rules! format_if_error_drop_cause { + ($result:expr, $format_text:literal) => { + tool_helper::callback_if_any_error($result, |error_text| { + format!($format_text) + }) + }; + ($result:expr, $format_text:literal, $($arg:expr)*) => { + tool_helper::callback_if_any_error($result, |error_text| { + format!($format_text, $($arg),*) + }) + }; +} + +const DEFAULT_ENV_EXPAND_OPTIONS : ExpandOptions = ExpandOptions{expansion_type: Some(ExpansionType::All), default_to_empty: false}; + +pub struct Error { + pub exit_code: i32, + pub text: String, +} + +impl Error { + const DEFAULT_EXITCODE:i32 = -1; + + pub fn from_str(str: &str) -> Error { + Self::from_text(str.to_owned()) + } + + pub fn from_text(text: String) -> Error { + Error{exit_code: Self::DEFAULT_EXITCODE, text} + } + + pub fn from_error(error: T) -> Error where T: std::fmt::Display { + Error::from_text(error.to_string()) + } + + pub fn from_core_error(error: T) -> Error where T: core::fmt::Display { + Error::from_text(error.to_string()) + } + + pub fn from_callback(callback: F) -> Error where F: Fn() -> String { + Error::from_text(callback()) + } + + pub fn not_implemented(function: &str) -> Error { + Error::from_text(format!("{} not implemented yet", function)) + } + + pub fn try_or_new(result: std::result::Result) -> Result where S: std::fmt::Display { + match result { + Ok(value) => Ok(value), + Err(error) => Err(Error{exit_code: Self::DEFAULT_EXITCODE, text: error.to_string()}), + } + } + + pub fn ok_or_new(option: Option, error_text: F) -> Result where F: Fn () -> String{ + Ok(option.ok_or(Error::from_callback(error_text))?) + } + + pub fn print_generic_to_std_err(object: &T) { + eprintln!("{}", format!("ERROR: {}", object).red()); + } + + pub fn print_to_std_err(&self) { + Self::print_generic_to_std_err(self) + } +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.text) + } +} + +impl std::convert::From for Error { + fn from(error: std::io::Error) -> Self { + Error{exit_code: -1, text: error.to_string()} + } +} + +impl std::convert::From for Error { + fn from(error: cdtypes::Error) -> Self { + Error::from_error(error) + } +} + +impl std::convert::From for Error { + fn from(error: std::convert::Infallible) -> Self { + Error::from_error(error) + } +} + +impl std::convert::From for Error { + fn from(error: std::sync::mpsc::RecvError) -> Self { + Error::from_error(error) + } +} + +impl std::convert::From for Error { + fn from(error: hound::Error) -> Self { + Error::from_error(error) + } +} + +pub fn exit_with_error(error: Error) { + error.print_to_std_err(); + std::process::exit(error.exit_code); +} + +pub fn print_warning(str: String) { + eprintln!("{}", str.yellow()); +} + +pub fn prefix_if_error(prefix: &str, result: Result) -> Result { + match result { + Ok(value) => Ok(value), + Err(mut error) => { + let mut new_text = String::from(prefix); + + new_text.push_str(error.text.as_str()); + error.text = new_text; + Err(error) + }, + } +} + +pub fn callback_if_error String, T>(result: Result, callback: F) -> Result { + match result { + Ok(value) => Ok(value), + Err(mut error) => { + error.text = callback(error.text); + + Err(error) + } + } +} + +pub fn callback_if_any_error String, T, E: std::string::ToString>(result: Result, callback: F) -> Result { + match result { + Ok(value) => Ok(value), + Err(error) => { + Err(Error::from_text(callback(error.to_string()))) + } + } +} + +pub fn string_with_env_from(str: &str) -> String { + String::from(envmnt::expand(str, Some(DEFAULT_ENV_EXPAND_OPTIONS))) +} + +pub fn path_with_env_from(path: &str) -> PathBuf { + PathBuf::from(envmnt::expand(path, Some(DEFAULT_ENV_EXPAND_OPTIONS))) +} + +pub fn open_output_file(output_path: &PathBuf) -> Result, Error> { + Ok(std::io::BufWriter::new(std::fs::File::create(win_or_wsl_path(output_path)?)?)) +} + +pub fn open_output(output_file: &Option) -> Result { + match output_file { + Some(output_path) => Ok(Box::new(open_output_file(&output_path)?)), + None => Ok(Box::new(BufWriter::new(std::io::stdout()))), + } +} + +pub fn open_input(input_file: &Option) -> Result { + match input_file { + Some(input_path) => Ok(Box::new(open_input_file_buffered(&input_path)?)), + None => Ok(Box::new(BufReader::new(std::io::stdin()))), + } +} + +pub fn open_input_file_buffered(input_path: &PathBuf) -> Result { + Ok(BufReader::new(std::fs::File::open(win_or_wsl_path(input_path)?)?)) +} + +pub fn os_str_to_string(input: &std::ffi::OsStr, name: &str) -> Result { + Ok(Error::ok_or_new(input.to_str(), ||format!("Converting {} to UTF-8 failed", name))?.to_owned()) +} + +pub fn get_file_name_from_path_buf(input: &PathBuf, name: &str) -> Result { + os_str_to_string(Error::ok_or_new(input.file_name(), ||format!("No {} file name found", name))?, name) +} + +pub fn input_to_vec(input: Input) -> Result, Error> { + let mut data = Vec::new(); + + for byte in input.bytes() { + data.push(byte?); + } + + Ok(data) +} + +pub fn read_file(file_path: &PathBuf) -> Result, Error> { + if let Some(ext) = file_path.extension() { + if ext == "subst" { + // File needs substitution! + let file_content = read_file_to_string(file_path)?; + return Ok(string_with_env_from(&file_content).into_bytes()); + } + } + + match std::fs::read(win_or_wsl_path(file_path)?) { + Ok(data) => Ok(data), + Err(error) => create_file_read_error(file_path, error), + } +} + +pub fn read_file_to_string(file_path: &PathBuf) -> Result { + match std::fs::read_to_string(win_or_wsl_path(file_path)?) { + Ok(string) => Ok(string), + Err(error) => create_file_read_error(file_path, error), + } +} + +pub fn write_file(file_path: &PathBuf, data: Vec) -> Result<(), Error> { + let mut file = OpenOptions::new().read(true).write(true).truncate(true).create(true).open(file_path)?; + + file.write_all(data.as_slice())?; + Ok(()) +} + +fn create_file_read_error(file_path: &PathBuf, error: std::io::Error) -> Result { + Err(Error::from_text(format!("Failed reading file {} with error: \"{}\"", file_path.display(), error))) +} + +fn win_or_wsl_path(path: &PathBuf) -> Result { + let path = path.clone(); + if path.exists() { + Ok(path) + } + + else { + match path.into_os_string().into_string() { + Ok(path) => Ok(PathBuf::from_str(wslpath::force_convert(path).as_str())?), + Err(error) => Err(Error::from_text(format!("Failed converting {:?} to string for win/wsl mapping", error))) + } + } } \ No newline at end of file diff --git a/src/Tools/tool_helper/src/vec_helper.rs b/src/Tools/tool_helper/src/vec_helper.rs index ed90eb7d..05fe382a 100644 --- a/src/Tools/tool_helper/src/vec_helper.rs +++ b/src/Tools/tool_helper/src/vec_helper.rs @@ -1,9 +1,9 @@ -use super::Error; -use std::str; - -pub fn to_string(output: Vec) -> Result { - match str::from_utf8(&output) { - Ok(str) => Ok(str.to_owned()), - Err(_) => Err(Error::from_str("Invalid UTF8 sequence")) - } +use super::Error; +use std::str; + +pub fn to_string(output: Vec) -> Result { + match str::from_utf8(&output) { + Ok(str) => Ok(str.to_owned()), + Err(_) => Err(Error::from_str("Invalid UTF8 sequence")) + } } \ No newline at end of file diff --git a/src/Tools/wslpath/Makefile b/src/Tools/wslpath/Makefile index cd0fb766..186cec6d 100644 --- a/src/Tools/wslpath/Makefile +++ b/src/Tools/wslpath/Makefile @@ -1,13 +1,13 @@ -include ../Common.mk - -ARTIFACT = wslpath - -.PHONY: $(WINDOWS_ARTIFACT) $(UNIX_ARTIFACT) -$(WINDOWS_ARTIFACT): - $(call cargo_windows_default) - -$(UNIX_ARTIFACT): - $(call cargo_unix_default) - -all-windows: $(WINDOWS_ARTIFACT) +include ../Common.mk + +ARTIFACT = wslpath + +.PHONY: $(WINDOWS_ARTIFACT) $(UNIX_ARTIFACT) +$(WINDOWS_ARTIFACT): + $(call cargo_windows_default) + +$(UNIX_ARTIFACT): + $(call cargo_unix_default) + +all-windows: $(WINDOWS_ARTIFACT) all: $(UNIX_ARTIFACT) \ No newline at end of file diff --git a/support/include/FontWriter/Type/types.hpp b/support/include/FontWriter/Type/types.hpp index c1fb91f7..8543121f 100644 --- a/support/include/FontWriter/Type/types.hpp +++ b/support/include/FontWriter/Type/types.hpp @@ -1,59 +1,59 @@ -#pragma once -#include -#include -#include - -namespace JabyEngine { - using FontPrimitive = GPU::SPRT::Linked; - - struct FontInfo { - struct RenderInfo { - GPU::SizeU8 font_size; - GPU::SizeU8 kern_size; - - static constexpr RenderInfo empty() { - return RenderInfo{.font_size = Make::SizeU8(), .kern_size = Make::SizeU8()}; - } - }; - - GPU::SizeU16 texture_size; - RenderInfo render_info; - - static constexpr FontInfo create(GPU::SizeU16 texture_size, GPU::SizeU8 font_size, GPU::SizeU8 kern_size) { - return FontInfo{.texture_size = texture_size, .render_info = {.font_size = font_size, .kern_size = kern_size}}; - } - - static constexpr FontInfo create(GPU::SizeU16 texture_size, GPU::SizeU8 font_size) { - return FontInfo::create(texture_size, font_size, font_size); - } - - constexpr GPU::SizeU16 get_font_size() const { - return GPU::SizeU16::from(this->render_info.font_size); - } - - constexpr GPU::SizeU16 get_kern_size() const { - return GPU::SizeU16::from(this->render_info.kern_size); - } - - template - constexpr size_t estimate_str_render_length(const char (&str)[Size]) const { - return (Size - 1)*FontInfo::get_kern_size().width; - } - }; - - struct Cursor { - GPU::PositionI16 pos; - uint8_t wiggle_count; - - static constexpr Cursor create(GPU::PositionI16 pos, uint8_t wiggle_count = 0) { - return Cursor{.pos = pos, .wiggle_count = wiggle_count}; - } - - constexpr Cursor& change_position(GPU::PositionI16 pos) { - this->pos = pos; - return *this; - } - }; - - using Wiggle = GPU::PositionI8[8]; -} +#pragma once +#include +#include +#include + +namespace JabyEngine { + using FontPrimitive = GPU::SPRT::Linked; + + struct FontInfo { + struct RenderInfo { + GPU::SizeU8 font_size; + GPU::SizeU8 kern_size; + + static constexpr RenderInfo empty() { + return RenderInfo{.font_size = Make::SizeU8(), .kern_size = Make::SizeU8()}; + } + }; + + GPU::SizeU16 texture_size; + RenderInfo render_info; + + static constexpr FontInfo create(GPU::SizeU16 texture_size, GPU::SizeU8 font_size, GPU::SizeU8 kern_size) { + return FontInfo{.texture_size = texture_size, .render_info = {.font_size = font_size, .kern_size = kern_size}}; + } + + static constexpr FontInfo create(GPU::SizeU16 texture_size, GPU::SizeU8 font_size) { + return FontInfo::create(texture_size, font_size, font_size); + } + + constexpr GPU::SizeU16 get_font_size() const { + return GPU::SizeU16::from(this->render_info.font_size); + } + + constexpr GPU::SizeU16 get_kern_size() const { + return GPU::SizeU16::from(this->render_info.kern_size); + } + + template + constexpr size_t estimate_str_render_length(const char (&str)[Size]) const { + return (Size - 1)*FontInfo::get_kern_size().width; + } + }; + + struct Cursor { + GPU::PositionI16 pos; + uint8_t wiggle_count; + + static constexpr Cursor create(GPU::PositionI16 pos, uint8_t wiggle_count = 0) { + return Cursor{.pos = pos, .wiggle_count = wiggle_count}; + } + + constexpr Cursor& change_position(GPU::PositionI16 pos) { + this->pos = pos; + return *this; + } + }; + + using Wiggle = GPU::PositionI8[8]; +} diff --git a/support/include/FontWriter/font_writer.hpp b/support/include/FontWriter/font_writer.hpp index 68cd2e6a..21b765a9 100644 --- a/support/include/FontWriter/font_writer.hpp +++ b/support/include/FontWriter/font_writer.hpp @@ -1,62 +1,62 @@ -#pragma once -#include "Type/types.hpp" -#include - -namespace JabyEngine { - class FontWriter { - private: - #define __write_impl(start, color, wiggle) \ - va_list list; \ - va_start(list, start); \ - FontWriter::write(cursor, str, color, wiggle, list); \ - va_end(list) - - GPU::TexPage::Linked tex_page[2]; - FontInfo::RenderInfo render_info; - GPU::PageClut clut; - GPU::Link* last_primitive; - - public: - static constexpr FontWriter empty() { - FontWriter instance; - - instance.tex_page[0] = {0}; - instance.tex_page[1] = {0}; - instance.render_info = FontInfo::RenderInfo::empty(); - instance.clut = Make::PageClut(); - instance.last_primitive = nullptr; - return instance; - } - - void setup(const SimpleTIM& vram_dst, const FontInfo::RenderInfo& font_render_info); - - void setup(const SimpleTIM& vram_dst, const FontInfo& font_info) { - FontWriter::setup(vram_dst, font_info.render_info); - } - - void clear(); - - void write(Cursor& cursor, const char* str, ...) { - __write_impl(str, GPU::Color24::Grey(), nullptr); - } - void write(Cursor& cursor, const char* str, GPU::Color24 color, ...) { - __write_impl(color, color, nullptr); - } - void write(Cursor& cursor, const char* str, GPU::Color24 color, const Wiggle* wiggle, ...) { - __write_impl(wiggle, color, wiggle); - } - void write(Cursor& cursor, const char* str, GPU::Color24 color, const Wiggle* wiggle, va_list list); - void render(); - - #undef __write_impl - }; - - struct GlobalFontPrimitivePool { - static void setup(FontPrimitive* start, size_t length); - - template - static void setup(FontPrimitive (&buffer)[Size]) { - GlobalFontPrimitivePool::setup(buffer, Size); - } - }; +#pragma once +#include "Type/types.hpp" +#include + +namespace JabyEngine { + class FontWriter { + private: + #define __write_impl(start, color, wiggle) \ + va_list list; \ + va_start(list, start); \ + FontWriter::write(cursor, str, color, wiggle, list); \ + va_end(list) + + GPU::TexPage::Linked tex_page[2]; + FontInfo::RenderInfo render_info; + GPU::PageClut clut; + GPU::Link* last_primitive; + + public: + static constexpr FontWriter empty() { + FontWriter instance; + + instance.tex_page[0] = {0}; + instance.tex_page[1] = {0}; + instance.render_info = FontInfo::RenderInfo::empty(); + instance.clut = Make::PageClut(); + instance.last_primitive = nullptr; + return instance; + } + + void setup(const SimpleTIM& vram_dst, const FontInfo::RenderInfo& font_render_info); + + void setup(const SimpleTIM& vram_dst, const FontInfo& font_info) { + FontWriter::setup(vram_dst, font_info.render_info); + } + + void clear(); + + void write(Cursor& cursor, const char* str, ...) { + __write_impl(str, GPU::Color24::Grey(), nullptr); + } + void write(Cursor& cursor, const char* str, GPU::Color24 color, ...) { + __write_impl(color, color, nullptr); + } + void write(Cursor& cursor, const char* str, GPU::Color24 color, const Wiggle* wiggle, ...) { + __write_impl(wiggle, color, wiggle); + } + void write(Cursor& cursor, const char* str, GPU::Color24 color, const Wiggle* wiggle, va_list list); + void render(); + + #undef __write_impl + }; + + struct GlobalFontPrimitivePool { + static void setup(FontPrimitive* start, size_t length); + + template + static void setup(FontPrimitive (&buffer)[Size]) { + GlobalFontPrimitivePool::setup(buffer, Size); + } + }; } \ No newline at end of file diff --git a/support/include/FontWriter/fonts.hpp b/support/include/FontWriter/fonts.hpp index f8645092..95b0360f 100644 --- a/support/include/FontWriter/fonts.hpp +++ b/support/include/FontWriter/fonts.hpp @@ -1,16 +1,16 @@ -#pragma once -#include "Type/types.hpp" -#include - -namespace JabyEngine { - struct DefaultFont { - static constexpr auto Info = FontInfo::create(Make::SizeU16(64, 80), Make::SizeU8(12, 16)); - - static void load(uint32_t* work_area, SimpleTIM vram_dst); - }; - - struct BIOSFont { - static constexpr auto Info = FontInfo::create(Make::SizeU16(64, 96), Make::SizeU8(16, 16), Make::SizeU8(12, 16)); - static constexpr auto TIM = SimpleTIM::create(JabyEngine::GPU::BIOS_Font::TextureLoadPos.x, JabyEngine::GPU::BIOS_Font::TextureLoadPos.y, JabyEngine::GPU::BIOS_Font::CLUTLoadPos.x, JabyEngine::GPU::BIOS_Font::CLUTLoadPos.y); - }; +#pragma once +#include "Type/types.hpp" +#include + +namespace JabyEngine { + struct DefaultFont { + static constexpr auto Info = FontInfo::create(Make::SizeU16(64, 80), Make::SizeU8(12, 16)); + + static void load(uint32_t* work_area, SimpleTIM vram_dst); + }; + + struct BIOSFont { + static constexpr auto Info = FontInfo::create(Make::SizeU16(64, 96), Make::SizeU8(16, 16), Make::SizeU8(12, 16)); + static constexpr auto TIM = SimpleTIM::create(JabyEngine::GPU::BIOS_Font::TextureLoadPos.x, JabyEngine::GPU::BIOS_Font::TextureLoadPos.y, JabyEngine::GPU::BIOS_Font::CLUTLoadPos.x, JabyEngine::GPU::BIOS_Font::CLUTLoadPos.y); + }; } \ No newline at end of file diff --git a/support/src/FontWriter/Makefile b/support/src/FontWriter/Makefile index a9921bf2..98f7add2 100644 --- a/support/src/FontWriter/Makefile +++ b/support/src/FontWriter/Makefile @@ -1,41 +1,41 @@ -include $(JABY_ENGINE_DIR)/mkfile/common/RebuildTarget.mk - -ARTIFACT = libFontWriter -BUILD_DIR = bin - -DEFAULT_FONT_IMAGE = src/default_font_data.hpp - -CCFLAGS += -I../../include -I$(JABY_ENGINE_DIR)/include -CCFLAGS += -save-temps=obj - -include $(JABY_ENGINE_DIR)/mkfile/common/Wildcard.mk -SRCS = $(call rwildcard, src, c cpp s) - -include $(JABY_ENGINE_DIR)/mkfile/Makefile -LIB_DIR = ../../lib/$(CONFIG_NAME) - -LIB_OBJS = $(filter-out $(MAIN_BOOT_OBJ) $(OVERLAY_BOOT_OBJ),$(OBJS)) - -#$(info $$var is [${MAIN_BOOT_OBJ}]) -#$(info $$var2 is [${LIB_OBJS}]) - -$(DEFAULT_FONT_IMAGE): ressources/DefaultFont.png - psxfileconv --lz4 $< simple-tim clut4 --semi-trans --color-trans | cpp_out --name default_font_data -o $@ - -#Linking rule -$(TARGET).a: $(LIB_OBJS) - @mkdir -p $(dir $@) - $(AR) rcs $(TARGET).a $(LIB_OBJS) - -#Copy rules -$(LIB_DIR)/$(ARTIFACT).a: $(TARGET).a - @mkdir -p $(LIB_DIR) - cp $(TARGET).a $(LIB_DIR)/$(ARTIFACT).a - -#Rules section for default compilation and linking -all: $(DEFAULT_FONT_IMAGE) $(LIB_DIR)/$(ARTIFACT).a - -clean: - rm -fr $(DEFAULT_FONT_IMAGE) - rm -fr $(OUTPUT_DIR) +include $(JABY_ENGINE_DIR)/mkfile/common/RebuildTarget.mk + +ARTIFACT = libFontWriter +BUILD_DIR = bin + +DEFAULT_FONT_IMAGE = src/default_font_data.hpp + +CCFLAGS += -I../../include -I$(JABY_ENGINE_DIR)/include +CCFLAGS += -save-temps=obj + +include $(JABY_ENGINE_DIR)/mkfile/common/Wildcard.mk +SRCS = $(call rwildcard, src, c cpp s) + +include $(JABY_ENGINE_DIR)/mkfile/Makefile +LIB_DIR = ../../lib/$(CONFIG_NAME) + +LIB_OBJS = $(filter-out $(MAIN_BOOT_OBJ) $(OVERLAY_BOOT_OBJ),$(OBJS)) + +#$(info $$var is [${MAIN_BOOT_OBJ}]) +#$(info $$var2 is [${LIB_OBJS}]) + +$(DEFAULT_FONT_IMAGE): ressources/DefaultFont.png + psxfileconv --lz4 $< simple-tim clut4 --semi-trans --color-trans | cpp_out --name default_font_data -o $@ + +#Linking rule +$(TARGET).a: $(LIB_OBJS) + @mkdir -p $(dir $@) + $(AR) rcs $(TARGET).a $(LIB_OBJS) + +#Copy rules +$(LIB_DIR)/$(ARTIFACT).a: $(TARGET).a + @mkdir -p $(LIB_DIR) + cp $(TARGET).a $(LIB_DIR)/$(ARTIFACT).a + +#Rules section for default compilation and linking +all: $(DEFAULT_FONT_IMAGE) $(LIB_DIR)/$(ARTIFACT).a + +clean: + rm -fr $(DEFAULT_FONT_IMAGE) + rm -fr $(OUTPUT_DIR) rm -fr $(LIB_DIR)/$(ARTIFACT).a \ No newline at end of file diff --git a/support/src/FontWriter/src/default_font.cpp b/support/src/FontWriter/src/default_font.cpp index df8b90dc..0967d93a 100644 --- a/support/src/FontWriter/src/default_font.cpp +++ b/support/src/FontWriter/src/default_font.cpp @@ -1,24 +1,24 @@ -#include "default_font_data.hpp" -#include -#include -#include -#include - -namespace JabyEngine { - static size_t decompress_font(uint32_t* work_area) { - LZ4Decompressor lz4_decomp(reinterpret_cast(work_area)); - - const auto [progress, bytes_ready] = lz4_decomp.process(ArrayRange(default_font_data, sizeof(default_font_data)), true); - if(progress == Progress::Error) { - return 0; - } - return bytes_ready; - } - - void DefaultFont :: load(uint32_t* work_area, SimpleTIM vram_dst) { - const auto bytes_ready = decompress_font(work_area); - - auto processor = FileProcessor::create(work_area, vram_dst); - processor.process(bytes_ready); - } +#include "default_font_data.hpp" +#include +#include +#include +#include + +namespace JabyEngine { + static size_t decompress_font(uint32_t* work_area) { + LZ4Decompressor lz4_decomp(reinterpret_cast(work_area)); + + const auto [progress, bytes_ready] = lz4_decomp.process(ArrayRange(default_font_data, sizeof(default_font_data)), true); + if(progress == Progress::Error) { + return 0; + } + return bytes_ready; + } + + void DefaultFont :: load(uint32_t* work_area, SimpleTIM vram_dst) { + const auto bytes_ready = decompress_font(work_area); + + auto processor = FileProcessor::create(work_area, vram_dst); + processor.process(bytes_ready); + } } \ No newline at end of file diff --git a/support/src/FontWriter/src/font_writer.cpp b/support/src/FontWriter/src/font_writer.cpp index 87140214..06bcfddc 100644 --- a/support/src/FontWriter/src/font_writer.cpp +++ b/support/src/FontWriter/src/font_writer.cpp @@ -1,155 +1,155 @@ -#include "include/global_primitive_buffer.hpp" -#include -#include -#include - -namespace JabyEngine { - static constexpr auto ITOABufferSize = 32; - - // Can we not find a better version of this? - static char* simple_itoa(char (&buffer)[ITOABufferSize], bool is_neg, uint32_t value, uint32_t base) { - // v terminating 0 and space for sign - int i = ITOABufferSize - 2; - - if(value == 0) { - buffer[0] = '0'; - buffer[1] = '\0'; - return buffer; - } - - for(; value && i; i--, value /= base) { - char chr = '0' + value%base; - if(chr > '9') { - chr += ('A' - '9' - 1); - } - buffer[i] = chr; - } - - buffer[ITOABufferSize - 1] = '\0'; - if(is_neg) { - buffer[i] = '-'; - return &buffer[i]; - } - return &buffer[i + 1]; - } - - static const char* simple_itoa(char (&buffer)[ITOABufferSize], int32_t value, uint32_t base) { - const auto is_neg = value < 0; - if(is_neg) { - value *= -1; - } - return simple_itoa(buffer, is_neg, value, base); - } - - static const char* simple_ptoa(char (&buffer)[ITOABufferSize], void* value) { - // v terminating 0 - static constexpr auto BufferStartID = ITOABufferSize - 1 - 8; - - char* str = simple_itoa(buffer, false, reinterpret_cast(value), 16); - while(str > &buffer[BufferStartID]) { - str--; - *str = '0'; - } - return &buffer[BufferStartID]; - } - - void FontWriter :: setup(const SimpleTIM& vram_dst, const FontInfo::RenderInfo& font_render_info) { - for(auto& tex_page : this->tex_page) { - tex_page = Make::TexPage(vram_dst.get_texture_position(), GPU::TextureColorMode::clut4).linked(); - } - this->render_info = font_render_info; - this->clut = Make::PageClut(vram_dst.get_clut_position()); - this->last_primitive = nullptr; - } - - void FontWriter :: clear() { - this->last_primitive = &this->tex_page[GPU::update_id()]; - } - - void FontWriter :: write(Cursor& cursor, const char* str, GPU::Color24 color, const Wiggle* wiggle, va_list list) { - static const auto exchang_str = [](const char* str, const char* new_str) -> pair { - return {str + 1, new_str}; - }; - - if(!this->last_primitive) { - FontWriter::clear(); - } - - const auto sprt_size = GPU::SizeI16::from(this->render_info.font_size); - const auto row_count = 256/sprt_size.width; - const auto push_char = [&](Cursor& cursor, char cur_char) -> bool { - auto& primitive = GlobalPrimitiveFactory.new_primitive(); - - primitive->position = cursor.pos; - primitive->size = sprt_size; - if(wiggle) { - const auto [off_x, off_y] = (*wiggle)[(cursor.wiggle_count++)&0x7]; - primitive->position.move(off_x, off_y); - } - primitive->tex_offset = GPU::PageOffset::from_tile_id(cur_char - '!', row_count, sprt_size); - primitive->clut = this->clut; - primitive->color = color; - - this->last_primitive->concat(primitive); - this->last_primitive = &primitive; - cursor.pos.move(this->render_info.kern_size.width, 0); - return true; - }; - const auto old_x = cursor.pos.x; - const char* prev_str = nullptr; - char buffer[32]; - - while(true) { - auto cur_char = *str++; - switch(cur_char) { - case '\0': - if(prev_str) { - str = prev_str; - prev_str = nullptr; - continue; - } - return; - - case '\n': - cursor.pos.x = old_x; - cursor.pos.y += this->render_info.kern_size.height; - continue; - - case ' ': - cursor.pos.x += this->render_info.kern_size.width; - continue; - - case '%': - switch(*str) { - case '%': - str++; - break; - - case 'i': - tie(prev_str, str) = exchang_str(str, simple_itoa(buffer, va_arg(list, int), 10)); - continue; - - case 'p': - tie(prev_str, str) = exchang_str(str, simple_ptoa(buffer, va_arg(list, void*))); - continue; - - case 's': - tie(prev_str, str) = exchang_str(str, va_arg(list, const char*)); - continue; - } - - default: - if(!push_char(cursor, cur_char)) { - return; - } - } - } - } - - void FontWriter :: render() { - this->last_primitive->terminate(); - this->last_primitive = nullptr; - - GPU::render(this->tex_page[GPU::render_id()]); - } +#include "include/global_primitive_buffer.hpp" +#include +#include +#include + +namespace JabyEngine { + static constexpr auto ITOABufferSize = 32; + + // Can we not find a better version of this? + static char* simple_itoa(char (&buffer)[ITOABufferSize], bool is_neg, uint32_t value, uint32_t base) { + // v terminating 0 and space for sign + int i = ITOABufferSize - 2; + + if(value == 0) { + buffer[0] = '0'; + buffer[1] = '\0'; + return buffer; + } + + for(; value && i; i--, value /= base) { + char chr = '0' + value%base; + if(chr > '9') { + chr += ('A' - '9' - 1); + } + buffer[i] = chr; + } + + buffer[ITOABufferSize - 1] = '\0'; + if(is_neg) { + buffer[i] = '-'; + return &buffer[i]; + } + return &buffer[i + 1]; + } + + static const char* simple_itoa(char (&buffer)[ITOABufferSize], int32_t value, uint32_t base) { + const auto is_neg = value < 0; + if(is_neg) { + value *= -1; + } + return simple_itoa(buffer, is_neg, value, base); + } + + static const char* simple_ptoa(char (&buffer)[ITOABufferSize], void* value) { + // v terminating 0 + static constexpr auto BufferStartID = ITOABufferSize - 1 - 8; + + char* str = simple_itoa(buffer, false, reinterpret_cast(value), 16); + while(str > &buffer[BufferStartID]) { + str--; + *str = '0'; + } + return &buffer[BufferStartID]; + } + + void FontWriter :: setup(const SimpleTIM& vram_dst, const FontInfo::RenderInfo& font_render_info) { + for(auto& tex_page : this->tex_page) { + tex_page = Make::TexPage(vram_dst.get_texture_position(), GPU::TextureColorMode::clut4).linked(); + } + this->render_info = font_render_info; + this->clut = Make::PageClut(vram_dst.get_clut_position()); + this->last_primitive = nullptr; + } + + void FontWriter :: clear() { + this->last_primitive = &this->tex_page[GPU::update_id()]; + } + + void FontWriter :: write(Cursor& cursor, const char* str, GPU::Color24 color, const Wiggle* wiggle, va_list list) { + static const auto exchang_str = [](const char* str, const char* new_str) -> pair { + return {str + 1, new_str}; + }; + + if(!this->last_primitive) { + FontWriter::clear(); + } + + const auto sprt_size = GPU::SizeI16::from(this->render_info.font_size); + const auto row_count = 256/sprt_size.width; + const auto push_char = [&](Cursor& cursor, char cur_char) -> bool { + auto& primitive = GlobalPrimitiveFactory.new_primitive(); + + primitive->position = cursor.pos; + primitive->size = sprt_size; + if(wiggle) { + const auto [off_x, off_y] = (*wiggle)[(cursor.wiggle_count++)&0x7]; + primitive->position.move(off_x, off_y); + } + primitive->tex_offset = GPU::PageOffset::from_tile_id(cur_char - '!', row_count, sprt_size); + primitive->clut = this->clut; + primitive->color = color; + + this->last_primitive->concat(primitive); + this->last_primitive = &primitive; + cursor.pos.move(this->render_info.kern_size.width, 0); + return true; + }; + const auto old_x = cursor.pos.x; + const char* prev_str = nullptr; + char buffer[32]; + + while(true) { + auto cur_char = *str++; + switch(cur_char) { + case '\0': + if(prev_str) { + str = prev_str; + prev_str = nullptr; + continue; + } + return; + + case '\n': + cursor.pos.x = old_x; + cursor.pos.y += this->render_info.kern_size.height; + continue; + + case ' ': + cursor.pos.x += this->render_info.kern_size.width; + continue; + + case '%': + switch(*str) { + case '%': + str++; + break; + + case 'i': + tie(prev_str, str) = exchang_str(str, simple_itoa(buffer, va_arg(list, int), 10)); + continue; + + case 'p': + tie(prev_str, str) = exchang_str(str, simple_ptoa(buffer, va_arg(list, void*))); + continue; + + case 's': + tie(prev_str, str) = exchang_str(str, va_arg(list, const char*)); + continue; + } + + default: + if(!push_char(cursor, cur_char)) { + return; + } + } + } + } + + void FontWriter :: render() { + this->last_primitive->terminate(); + this->last_primitive = nullptr; + + GPU::render(this->tex_page[GPU::render_id()]); + } } \ No newline at end of file diff --git a/support/src/FontWriter/src/global_primitive_buffer.cpp b/support/src/FontWriter/src/global_primitive_buffer.cpp index a8513066..52887672 100644 --- a/support/src/FontWriter/src/global_primitive_buffer.cpp +++ b/support/src/FontWriter/src/global_primitive_buffer.cpp @@ -1,16 +1,16 @@ -#include "include/global_primitive_buffer.hpp" -#include - -namespace JabyEngine { - PrimitiveFactory GlobalPrimitiveFactory = PrimitiveFactory::empty(); - - void GlobalFontPrimitivePool :: setup(FontPrimitive* start, size_t length) { - const auto*const buffer_end = start + length; - - for(auto* cur_prim = start; cur_prim < buffer_end; cur_prim++) { - *cur_prim = FontPrimitive::create(Make::SPRT(Make::AreaI16(), Make::OffsetPageWithClut())); - } - - GlobalPrimitiveFactory = PrimitiveFactory::create(start, length); - } +#include "include/global_primitive_buffer.hpp" +#include + +namespace JabyEngine { + PrimitiveFactory GlobalPrimitiveFactory = PrimitiveFactory::empty(); + + void GlobalFontPrimitivePool :: setup(FontPrimitive* start, size_t length) { + const auto*const buffer_end = start + length; + + for(auto* cur_prim = start; cur_prim < buffer_end; cur_prim++) { + *cur_prim = FontPrimitive::create(Make::SPRT(Make::AreaI16(), Make::OffsetPageWithClut())); + } + + GlobalPrimitiveFactory = PrimitiveFactory::create(start, length); + } } \ No newline at end of file diff --git a/support/src/FontWriter/src/include/global_primitive_buffer.hpp b/support/src/FontWriter/src/include/global_primitive_buffer.hpp index 7f7a8b55..f1bf7d68 100644 --- a/support/src/FontWriter/src/include/global_primitive_buffer.hpp +++ b/support/src/FontWriter/src/include/global_primitive_buffer.hpp @@ -1,29 +1,29 @@ -#pragma once -#include - -namespace JabyEngine { - struct PrimitiveFactory { - FontPrimitive* start_adr; - FontPrimitive* end_adr; - FontPrimitive* cur_element; - - static constexpr PrimitiveFactory empty() { - return PrimitiveFactory{.start_adr = nullptr, .end_adr = nullptr, .cur_element = nullptr}; - } - - static constexpr PrimitiveFactory create(FontPrimitive* start, size_t length) { - return PrimitiveFactory{.start_adr = start, .end_adr = start + length, .cur_element = start}; - } - - FontPrimitive& new_primitive() { - auto& new_primitive = *this->cur_element++; - if(this->cur_element == this->end_adr) { - this->cur_element = this->start_adr; - } - - return new_primitive; - } - }; - - extern PrimitiveFactory GlobalPrimitiveFactory; +#pragma once +#include + +namespace JabyEngine { + struct PrimitiveFactory { + FontPrimitive* start_adr; + FontPrimitive* end_adr; + FontPrimitive* cur_element; + + static constexpr PrimitiveFactory empty() { + return PrimitiveFactory{.start_adr = nullptr, .end_adr = nullptr, .cur_element = nullptr}; + } + + static constexpr PrimitiveFactory create(FontPrimitive* start, size_t length) { + return PrimitiveFactory{.start_adr = start, .end_adr = start + length, .cur_element = start}; + } + + FontPrimitive& new_primitive() { + auto& new_primitive = *this->cur_element++; + if(this->cur_element == this->end_adr) { + this->cur_element = this->start_adr; + } + + return new_primitive; + } + }; + + extern PrimitiveFactory GlobalPrimitiveFactory; } \ No newline at end of file diff --git a/support/src/Makefile b/support/src/Makefile index dc95c529..c521abbb 100644 --- a/support/src/Makefile +++ b/support/src/Makefile @@ -1,6 +1,6 @@ -.PHONY: FontWriter - -FontWriter: - $(MAKE) -C $(JABY_ENGINE_DIR)/support/src/FontWriter $(MAKECMDGOALS) - +.PHONY: FontWriter + +FontWriter: + $(MAKE) -C $(JABY_ENGINE_DIR)/support/src/FontWriter $(MAKECMDGOALS) + all: FontWriter \ No newline at end of file diff --git a/template/JabyEngine-PSX_Game/iso/Makefile b/template/JabyEngine-PSX_Game/iso/Makefile index 925d0bd1..23283935 100644 --- a/template/JabyEngine-PSX_Game/iso/Makefile +++ b/template/JabyEngine-PSX_Game/iso/Makefile @@ -1,2 +1,2 @@ -include $(JABY_ENGINE_DIR)/mkfile/ISOMakefile.mk +include $(JABY_ENGINE_DIR)/mkfile/ISOMakefile.mk include $(JABY_ENGINE_DIR)/mkfile/common/RebuildTarget.mk \ No newline at end of file