diff --git a/Samples/ASCII - Fonts/.vscode/c_cpp_properties.json b/Samples/ASCII - Fonts/.vscode/c_cpp_properties.json new file mode 100644 index 00000000..d9f92c7e --- /dev/null +++ b/Samples/ASCII - Fonts/.vscode/c_cpp_properties.json @@ -0,0 +1,36 @@ +{ + "configurations": [ + { + "name": "Saturn", + "includePath": [ + "${workspaceFolder}/../../saturnringlib", + "${workspaceFolder}/../../modules/sgl/INC", + "${workspaceFolder}/../../modules/tlsf", + "${workspaceFolder}/../../modules/SaturnMathPP", + "${workspaceFolder}/../../Compiler/sh2eb-elf/sh-elf/include", + "${workspaceFolder}/../../Compiler/sh2eb-elf/sh-elf/include/c++/14.2.0", + "${workspaceFolder}/../../saturnringlib/**" + ], + "compilerPath": "${workspaceFolder}/../../Compiler/sh2eb-elf/bin/sh-elf-gcc-14.2.0.exe", + "cStandard": "c23", + "cppStandard": "c++23", + "intelliSenseMode": "gcc-x86", + "defines": [ + "__STDC_HOSTED__=0", + "SRL_CUSTOM_SGL_WORK_AREA=0", + "SRL_MALLOC_MEMORY=131072", + "SRL_MAX_TEXTURES=100", + "SRL_MODE_PAL", + "SRL_FRAMERATE=0", + "SRL_MAX_CD_BACKGROUND_JOBS=1", + "SRL_MAX_CD_FILES=255", + "SRL_MAX_CD_RETRIES=5", + "SRL_DEBUG_MAX_PRINT_LENGTH=45", + "SRL_USE_SGL_SOUND_DRIVER=1", + "SRL_ENABLE_FREQ_ANALYSIS=1", + "DEBUG" + ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/Samples/ASCII - Fonts/.vscode/extensions.json b/Samples/ASCII - Fonts/.vscode/extensions.json new file mode 100644 index 00000000..610a551b --- /dev/null +++ b/Samples/ASCII - Fonts/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "ms-vscode.cpptools" + ] +} \ No newline at end of file diff --git a/Samples/ASCII - Fonts/.vscode/settings.json b/Samples/ASCII - Fonts/.vscode/settings.json new file mode 100644 index 00000000..2177b80d --- /dev/null +++ b/Samples/ASCII - Fonts/.vscode/settings.json @@ -0,0 +1,42 @@ +{ + "files.exclude": { + "**/*.o": true, + "**/*.bat": true, + "[Cc][Dd]/[Bb]uild[Dd]rop**" : true, + }, + "files.watcherExclude": { + "**/*.o": true, + "**/*.bat": true, + "[Cc][Dd]/[Bb]uild[Dd]rop**" : true, + }, + "C_Cpp.loggingLevel": "Debug", + "files.associations": { + "*.embeddedhtml": "html", + "*.H": "c", + "*.C": "c", + "*.def": "c", + "*.h": "c", + "*.c": "c", + "*.HPP": "cpp", + "*.CXX": "cpp", + "*.hpp": "cpp", + "*.cxx": "cpp", + "functional": "cpp", + "vector": "cpp" + }, + "cmake.configureOnOpen": false, + "makefile.makefilePath": "./makefile", + "C_Cpp.default.cppStandard": "c++23", + "C_Cpp.default.cStandard": "c17", + "C_Cpp.formatting": "vcFormat", + "C_Cpp.vcFormat.newLine.beforeOpenBrace.function": "newLine", + "C_Cpp.vcFormat.newLine.beforeOpenBrace.block": "newLine", + "C_Cpp.vcFormat.newLine.beforeOpenBrace.namespace": "newLine", + "C_Cpp.vcFormat.newLine.beforeOpenBrace.type": "newLine", + "C_Cpp.vcFormat.newLine.beforeOpenBrace.lambda": "newLine", + "C_Cpp.vcFormat.indent.lambdaBracesWhenParameter": false, + "C_Cpp.inlayHints.autoDeclarationTypes.enabled": true, + "C_Cpp.inlayHints.autoDeclarationTypes.showOnLeft": true, + "C_Cpp.inlayHints.referenceOperator.enabled": true, + "C_Cpp.inlayHints.referenceOperator.showSpace": true +} diff --git a/Samples/ASCII - Fonts/.vscode/tasks.json b/Samples/ASCII - Fonts/.vscode/tasks.json new file mode 100644 index 00000000..fb205970 --- /dev/null +++ b/Samples/ASCII - Fonts/.vscode/tasks.json @@ -0,0 +1,63 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Run with Mednafen", + "type": "shell", + "command": "./run_with_mednafen.bat", + "problemMatcher": [], + "presentation": { + "showReuseMessage": false, + "clear": true + }, + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "Compile [DEBUG]", + "type": "shell", + "command": "./compile.bat debug", + "problemMatcher": [], + "presentation": { + "showReuseMessage": false, + "clear": true + }, + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "Compile [RELEASE]", + "type": "shell", + "command": "./compile.bat release", + "problemMatcher": [], + "presentation": { + "showReuseMessage": false, + "clear": true + }, + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "Clean", + "type": "shell", + "command": "./clean.bat", + "problemMatcher": [], + "presentation": { + "showReuseMessage": false, + "clear": true + }, + "group": { + "kind": "build", + "isDefault": true + } + }, + ] +} diff --git a/Samples/ASCII - Fonts/cd/data/FONT1.tga b/Samples/ASCII - Fonts/cd/data/FONT1.tga new file mode 100644 index 00000000..caa39011 Binary files /dev/null and b/Samples/ASCII - Fonts/cd/data/FONT1.tga differ diff --git a/Samples/ASCII - Fonts/clean.bat b/Samples/ASCII - Fonts/clean.bat new file mode 100644 index 00000000..235cac2d --- /dev/null +++ b/Samples/ASCII - Fonts/clean.bat @@ -0,0 +1,3 @@ +:; "../../tools/scripts/make.sh" clean; exit; +@ECHO Off +"../../tools/scripts/make.bat" clean \ No newline at end of file diff --git a/Samples/ASCII - Fonts/compile.bat b/Samples/ASCII - Fonts/compile.bat new file mode 100644 index 00000000..13cda258 --- /dev/null +++ b/Samples/ASCII - Fonts/compile.bat @@ -0,0 +1,3 @@ +:; "../../tools/scripts/make.sh" $1; exit; +@ECHO Off +"../../tools/scripts/make.bat" %1 \ No newline at end of file diff --git a/Samples/ASCII - Fonts/makefile b/Samples/ASCII - Fonts/makefile new file mode 100644 index 00000000..ade1ce59 --- /dev/null +++ b/Samples/ASCII - Fonts/makefile @@ -0,0 +1,35 @@ +# Configuration +SRL_MAX_TEXTURES = 100 # Number of VDP1 texture slots +SRL_MODE = NTSC # Valid options are PAL or NTSC +SRL_HIGH_RES = 0 # 480i mode +SRL_FRAMERATE = 1 # Framerate control (0=dynamic, 1=< 60/value) +SRL_MAX_CD_BACKGROUND_JOBS = 1 # Maximum number of files GFS can open at once +SRL_MAX_CD_FILES = 256 # Maximum number of files on a CD +SRL_MAX_CD_RETRIES = 5 # Number of times to retry on unsuccessful read + +# Sound driver specific configuration +SRL_USE_SGL_SOUND_DRIVER = 0 # Set to 1 if you want to use SGL sound driver, this will copy necessary files into the CD folder +SRL_ENABLE_FREQ_ANALYSIS = 0 # Set to 1 if you want to enable frequency analysis for CD audio, this will load a DSP program into effect slot 1, SGL sound driver must be enabled + +# SGL configuration +SGL_MAX_VERTICES = 2500 # Number of vertices that can be used +SGL_MAX_POLYGONS = 1500 # Number of polygons that can be used +SGL_MAX_EVENTS = 1 # Number of events that can be used +SGL_MAX_WORKS = 1 # Number of works that can be used + +# Disk name +CD_NAME = VDP2_ScrollScreen + +# Directory build will be placed into +BUILD_DROP = ./BuildDrop + +# SRL installation directory +SRL_INSTALL_ROOT ?= ../.. + +# Find all .c and .cxx files +SOURCES = $(patsubst ./%,%,$(shell find src/ -name '*.c')) +SOURCES += $(patsubst ./%,%,$(shell find src/ -name '*.cxx')) + +# Include shared makefile +SDK_ROOT = $(SRL_INSTALL_ROOT)/saturnringlib +include $(SDK_ROOT)/shared.mk \ No newline at end of file diff --git a/Samples/ASCII - Fonts/run_with_mednafen.bat b/Samples/ASCII - Fonts/run_with_mednafen.bat new file mode 100644 index 00000000..108b6e9f --- /dev/null +++ b/Samples/ASCII - Fonts/run_with_mednafen.bat @@ -0,0 +1,3 @@ +:; "../../tools/scripts/run.sh" mednafen; exit; +@ECHO Off +"../../tools/scripts/run.bat" mednafen \ No newline at end of file diff --git a/Samples/ASCII - Fonts/src/main.cxx b/Samples/ASCII - Fonts/src/main.cxx new file mode 100644 index 00000000..4041fa10 --- /dev/null +++ b/Samples/ASCII - Fonts/src/main.cxx @@ -0,0 +1,93 @@ +/*VDP2 Scroll Layer Demo: +This Demo provides a sample of using the SRL::ASCII module to load custom fonts +and swap between multiple fonts and color palettes. The system is largely meant +to display debug messages to developers, but can be used for simple dialog +systems as well. +However because The characters printed are fixed to a tilemap grid, font +formatting features such as variable width characters and kerning are not +possible with this system. Fonts are limited to 16 color 8x8 characters. +*/ +#include + +using namespace SRL::Types; +using namespace SRL::Input; +using namespace SRL::Math; + +//A custom 16 color palette to load for a font: +HighColor CustomPalette[16] = +{ + HighColor::Colors::Black,//note: index 0 color in a palette will be transparent + HighColor::Colors::Red, + HighColor::Colors::Green, + HighColor::Colors::Blue, + HighColor::Colors::White, + HighColor::Colors::Magenta, + HighColor::Colors::Yellow, + HighColor::Colors::Black, + HighColor::Colors::Black, + HighColor::Colors::Black, + HighColor::Colors::Black, + HighColor::Colors::Black, + HighColor::Colors::Black, + HighColor::Colors::Black, + HighColor::Colors::Black, + HighColor::Colors::Black, +}; + +int main() +{ + + SRL::Core::Initialize(HighColor(20,10,50)); + + /* During initialization, SRL loads the SGL font to font index 0. + By default print statements will display using font index 0, palette index 0:*/ + + SRL::Debug::Print(1,2,"SRL Ascii Font Demo"); + SRL::Debug::Print(1,7,"This is the Default SGL Font"); + + /*The font system can use the first 8 16 color palettes in CRAM (0-7). + So we can load additional palettes to use with fonts: */ + + //reserve CRAM palette 1 for a font palette: + SRL::CRAM::SetBankUsedState(1, SRL::CRAM::TextureColorMode::Paletted16, true); + SRL::CRAM::Palette MyPalette(SRL::CRAM::TextureColorMode::Paletted16, 1); + + //load custom colors to CRAM palette 1 + MyPalette.Load(CustomPalette,16); + + //Switch the current font palette: + SRL::ASCII::SetPalette(1); + + //Now subsequent print statments will use palette 1: + SRL::Debug::Print(1,10, "This is a custom font palette-"); + SRL::Debug::Print(1,11, "8 palettes can display simultaneously!"); + + //Switch back to palette 0 + SRL::ASCII::SetPalette(0); + + /*Custom fonts can also be used. Up to 6 can be loaded and displayed at once (0-5). + The system loads 8x8 character ASCII tables from a bitmap source. + -Ensure the source is 4bpp (16 color) and the table begins with + one whitespace character followed by the standard Ascii characters. See the + included image in the CD::Data folder for an example of the proper table format. + -Only 7bit ascii tables (first 128 characters) are supported.*/ + + //load bitmap of the custom font to work ram + SRL::Bitmap::TGA* CustomFont = new SRL::Bitmap::TGA("FONT1.TGA"); + + //load custom font to Ascii index 1: + SRL::ASCII::LoadFont(CustomFont, 1); + + //Now we can switch to the new font like we switched palettes: + SRL::ASCII::SetFont(1); + SRL::Debug::Print(1,14,"This is a custom font-"); + SRL::Debug::Print(1,15,"6 fonts can display simultaneously!"); + + //Main Game Loop + while(1) + { + //Print statments will remain on screen until SRL::ASCII::Clear() is Called + SRL::Core::Synchronize(); + } + return 0; +} diff --git a/Samples/VDP1 - 3D - Smooth teapot/src/main.cxx b/Samples/VDP1 - 3D - Smooth teapot/src/main.cxx index 7bb0742d..361e7454 100644 --- a/Samples/VDP1 - 3D - Smooth teapot/src/main.cxx +++ b/Samples/VDP1 - 3D - Smooth teapot/src/main.cxx @@ -75,7 +75,7 @@ int main() // Initializes gouraud table work area SRL::Scene3D::LightInitGouraudTable(0, vertWork, workTable, polygons); - + // Sets current light shading table SRL::Scene3D::LightSetGouraudTable(shadingTable); diff --git a/Samples/VDP2 - ColorCalc/src/main.cxx b/Samples/VDP2 - ColorCalc/src/main.cxx index c6f59792..a6ca87ec 100644 --- a/Samples/VDP2 - ColorCalc/src/main.cxx +++ b/Samples/VDP2 - ColorCalc/src/main.cxx @@ -1,7 +1,7 @@ /*VDP2 Color Calculation Demo: This Demo Shows The use of VDP2 Color Calculation and Priority through SRL and demonstrates its effect by creating an interactive version of color calculation diagrams found in the - VDP2 Users Manual. +VDP2 Users Manual. A Blue Triangle, Green Square, and Red Circle are displayed on 3 separate VDP2 ScrollScreens. Priorities are set such that the Triangle draws on top, Square draws in middle, and Circle draws @@ -161,7 +161,6 @@ class UiManager SRL::Debug::Print(0,CursorLine+5,"->"); } - }; int main() diff --git a/Samples/VDP2 - Layers/cd/data/FOGRGB.bin b/Samples/VDP2 - Layers/cd/data/FOGRGB.bin deleted file mode 100644 index ff1c6a16..00000000 Binary files a/Samples/VDP2 - Layers/cd/data/FOGRGB.bin and /dev/null differ diff --git a/Samples/VDP2 - Layers/src/main.cxx b/Samples/VDP2 - Layers/src/main.cxx index f42746d2..a720a473 100644 --- a/Samples/VDP2 - Layers/src/main.cxx +++ b/Samples/VDP2 - Layers/src/main.cxx @@ -22,16 +22,18 @@ using namespace SRL::Math; int main() { - - SRL::Core::Initialize(HighColor(20,10,50)); Digital port0(0); // Initialize gamepad on port 0 SRL::Tilemap::Interfaces::CubeTile* TestTilebin = new SRL::Tilemap::Interfaces::CubeTile("SPACE.BIN");//Load tilemap from cd to work RAM + + SRL::Tilemap::TilemapInfo TestInfo = TestTilebin->GetInfo(); + SRL::VDP2::NBG0::LoadTilemap(*TestTilebin);//Transfer tilemap from work RAM to VDP2 VRAM and register with NBG0 - delete TestTilebin;//free work RAM + delete TestTilebin;//free work RAM + TestTilebin = new SRL::Tilemap::Interfaces::CubeTile("FOG256.BIN");//Load fog tilemap from cd to work RAM SRL::VDP2::NBG1::LoadTilemap(*TestTilebin);//Transfer tilemap from work RAM to VDP2 VRAM and register with NBG1 delete TestTilebin;//free work RAM @@ -60,14 +62,14 @@ int main() SRL::VDP2::NBG2::SetPosition(Nbg2Position);//Set the static screen position for SRL Logo SRL::VDP2::NBG2::ScrollEnable();//enable display of NBG2 - SRL::Debug::Print(1,3,"VDP2 ScrollScreen Sample"); + SRL::Debug::Print(1,3,"VDP2 ScrollScreen Layers Sample"); //Main Game Loop while(1) { //move positions of NBG0 and NBG1 scrolls: Nbg0Position += Vector2D(1.0, 1.0); - Nbg1Position += Vector2D(-2.0, 1.0); + Nbg1Position += Vector2D(1.0, 0.0); SRL::VDP2::NBG0::SetPosition(Nbg0Position); SRL::VDP2::NBG1::SetPosition(Nbg1Position); diff --git a/Samples/VDP2 - RBG0 Rotation Parameters/.vscode/c_cpp_properties.json b/Samples/VDP2 - RBG0 Rotation Parameters/.vscode/c_cpp_properties.json new file mode 100644 index 00000000..d9f92c7e --- /dev/null +++ b/Samples/VDP2 - RBG0 Rotation Parameters/.vscode/c_cpp_properties.json @@ -0,0 +1,36 @@ +{ + "configurations": [ + { + "name": "Saturn", + "includePath": [ + "${workspaceFolder}/../../saturnringlib", + "${workspaceFolder}/../../modules/sgl/INC", + "${workspaceFolder}/../../modules/tlsf", + "${workspaceFolder}/../../modules/SaturnMathPP", + "${workspaceFolder}/../../Compiler/sh2eb-elf/sh-elf/include", + "${workspaceFolder}/../../Compiler/sh2eb-elf/sh-elf/include/c++/14.2.0", + "${workspaceFolder}/../../saturnringlib/**" + ], + "compilerPath": "${workspaceFolder}/../../Compiler/sh2eb-elf/bin/sh-elf-gcc-14.2.0.exe", + "cStandard": "c23", + "cppStandard": "c++23", + "intelliSenseMode": "gcc-x86", + "defines": [ + "__STDC_HOSTED__=0", + "SRL_CUSTOM_SGL_WORK_AREA=0", + "SRL_MALLOC_MEMORY=131072", + "SRL_MAX_TEXTURES=100", + "SRL_MODE_PAL", + "SRL_FRAMERATE=0", + "SRL_MAX_CD_BACKGROUND_JOBS=1", + "SRL_MAX_CD_FILES=255", + "SRL_MAX_CD_RETRIES=5", + "SRL_DEBUG_MAX_PRINT_LENGTH=45", + "SRL_USE_SGL_SOUND_DRIVER=1", + "SRL_ENABLE_FREQ_ANALYSIS=1", + "DEBUG" + ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/Samples/VDP2 - RBG0 Rotation Parameters/.vscode/extensions.json b/Samples/VDP2 - RBG0 Rotation Parameters/.vscode/extensions.json new file mode 100644 index 00000000..610a551b --- /dev/null +++ b/Samples/VDP2 - RBG0 Rotation Parameters/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "ms-vscode.cpptools" + ] +} \ No newline at end of file diff --git a/Samples/VDP2 - RBG0 Rotation Parameters/.vscode/settings.json b/Samples/VDP2 - RBG0 Rotation Parameters/.vscode/settings.json new file mode 100644 index 00000000..2177b80d --- /dev/null +++ b/Samples/VDP2 - RBG0 Rotation Parameters/.vscode/settings.json @@ -0,0 +1,42 @@ +{ + "files.exclude": { + "**/*.o": true, + "**/*.bat": true, + "[Cc][Dd]/[Bb]uild[Dd]rop**" : true, + }, + "files.watcherExclude": { + "**/*.o": true, + "**/*.bat": true, + "[Cc][Dd]/[Bb]uild[Dd]rop**" : true, + }, + "C_Cpp.loggingLevel": "Debug", + "files.associations": { + "*.embeddedhtml": "html", + "*.H": "c", + "*.C": "c", + "*.def": "c", + "*.h": "c", + "*.c": "c", + "*.HPP": "cpp", + "*.CXX": "cpp", + "*.hpp": "cpp", + "*.cxx": "cpp", + "functional": "cpp", + "vector": "cpp" + }, + "cmake.configureOnOpen": false, + "makefile.makefilePath": "./makefile", + "C_Cpp.default.cppStandard": "c++23", + "C_Cpp.default.cStandard": "c17", + "C_Cpp.formatting": "vcFormat", + "C_Cpp.vcFormat.newLine.beforeOpenBrace.function": "newLine", + "C_Cpp.vcFormat.newLine.beforeOpenBrace.block": "newLine", + "C_Cpp.vcFormat.newLine.beforeOpenBrace.namespace": "newLine", + "C_Cpp.vcFormat.newLine.beforeOpenBrace.type": "newLine", + "C_Cpp.vcFormat.newLine.beforeOpenBrace.lambda": "newLine", + "C_Cpp.vcFormat.indent.lambdaBracesWhenParameter": false, + "C_Cpp.inlayHints.autoDeclarationTypes.enabled": true, + "C_Cpp.inlayHints.autoDeclarationTypes.showOnLeft": true, + "C_Cpp.inlayHints.referenceOperator.enabled": true, + "C_Cpp.inlayHints.referenceOperator.showSpace": true +} diff --git a/Samples/VDP2 - RBG0 Rotation Parameters/.vscode/tasks.json b/Samples/VDP2 - RBG0 Rotation Parameters/.vscode/tasks.json new file mode 100644 index 00000000..fb205970 --- /dev/null +++ b/Samples/VDP2 - RBG0 Rotation Parameters/.vscode/tasks.json @@ -0,0 +1,63 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Run with Mednafen", + "type": "shell", + "command": "./run_with_mednafen.bat", + "problemMatcher": [], + "presentation": { + "showReuseMessage": false, + "clear": true + }, + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "Compile [DEBUG]", + "type": "shell", + "command": "./compile.bat debug", + "problemMatcher": [], + "presentation": { + "showReuseMessage": false, + "clear": true + }, + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "Compile [RELEASE]", + "type": "shell", + "command": "./compile.bat release", + "problemMatcher": [], + "presentation": { + "showReuseMessage": false, + "clear": true + }, + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "Clean", + "type": "shell", + "command": "./clean.bat", + "problemMatcher": [], + "presentation": { + "showReuseMessage": false, + "clear": true + }, + "group": { + "kind": "build", + "isDefault": true + } + }, + ] +} diff --git a/Samples/VDP2 - RBG0 Rotation Parameters/cd/data/CLOUDS.bin b/Samples/VDP2 - RBG0 Rotation Parameters/cd/data/CLOUDS.bin new file mode 100644 index 00000000..b8d1206d Binary files /dev/null and b/Samples/VDP2 - RBG0 Rotation Parameters/cd/data/CLOUDS.bin differ diff --git a/Samples/VDP2 - RBG0 Rotation/cd/data/TESTN.bin b/Samples/VDP2 - RBG0 Rotation Parameters/cd/data/GROUND.bin similarity index 100% rename from Samples/VDP2 - RBG0 Rotation/cd/data/TESTN.bin rename to Samples/VDP2 - RBG0 Rotation Parameters/cd/data/GROUND.bin diff --git a/Samples/VDP2 - RBG0 Rotation Parameters/cd/data/TILE.bin b/Samples/VDP2 - RBG0 Rotation Parameters/cd/data/TILE.bin new file mode 100644 index 00000000..c07fda53 Binary files /dev/null and b/Samples/VDP2 - RBG0 Rotation Parameters/cd/data/TILE.bin differ diff --git a/Samples/VDP2 - RBG0 Rotation Parameters/cd/data/overworld_tileset_grass.aseprite b/Samples/VDP2 - RBG0 Rotation Parameters/cd/data/overworld_tileset_grass.aseprite new file mode 100644 index 00000000..a9b31793 Binary files /dev/null and b/Samples/VDP2 - RBG0 Rotation Parameters/cd/data/overworld_tileset_grass.aseprite differ diff --git a/Samples/VDP2 - RBG0 Rotation Parameters/cd/data/testgrass.aseprite b/Samples/VDP2 - RBG0 Rotation Parameters/cd/data/testgrass.aseprite new file mode 100644 index 00000000..18364c29 Binary files /dev/null and b/Samples/VDP2 - RBG0 Rotation Parameters/cd/data/testgrass.aseprite differ diff --git a/Samples/VDP2 - RBG0 Rotation Parameters/cd/data/testgrass2.aseprite b/Samples/VDP2 - RBG0 Rotation Parameters/cd/data/testgrass2.aseprite new file mode 100644 index 00000000..0ff6d57e Binary files /dev/null and b/Samples/VDP2 - RBG0 Rotation Parameters/cd/data/testgrass2.aseprite differ diff --git a/Samples/VDP2 - RBG0 Rotation Parameters/clean.bat b/Samples/VDP2 - RBG0 Rotation Parameters/clean.bat new file mode 100644 index 00000000..235cac2d --- /dev/null +++ b/Samples/VDP2 - RBG0 Rotation Parameters/clean.bat @@ -0,0 +1,3 @@ +:; "../../tools/scripts/make.sh" clean; exit; +@ECHO Off +"../../tools/scripts/make.bat" clean \ No newline at end of file diff --git a/Samples/VDP2 - RBG0 Rotation Parameters/compile.bat b/Samples/VDP2 - RBG0 Rotation Parameters/compile.bat new file mode 100644 index 00000000..13cda258 --- /dev/null +++ b/Samples/VDP2 - RBG0 Rotation Parameters/compile.bat @@ -0,0 +1,3 @@ +:; "../../tools/scripts/make.sh" $1; exit; +@ECHO Off +"../../tools/scripts/make.bat" %1 \ No newline at end of file diff --git a/Samples/VDP2 - RBG0 Rotation Parameters/makefile b/Samples/VDP2 - RBG0 Rotation Parameters/makefile new file mode 100644 index 00000000..ade1ce59 --- /dev/null +++ b/Samples/VDP2 - RBG0 Rotation Parameters/makefile @@ -0,0 +1,35 @@ +# Configuration +SRL_MAX_TEXTURES = 100 # Number of VDP1 texture slots +SRL_MODE = NTSC # Valid options are PAL or NTSC +SRL_HIGH_RES = 0 # 480i mode +SRL_FRAMERATE = 1 # Framerate control (0=dynamic, 1=< 60/value) +SRL_MAX_CD_BACKGROUND_JOBS = 1 # Maximum number of files GFS can open at once +SRL_MAX_CD_FILES = 256 # Maximum number of files on a CD +SRL_MAX_CD_RETRIES = 5 # Number of times to retry on unsuccessful read + +# Sound driver specific configuration +SRL_USE_SGL_SOUND_DRIVER = 0 # Set to 1 if you want to use SGL sound driver, this will copy necessary files into the CD folder +SRL_ENABLE_FREQ_ANALYSIS = 0 # Set to 1 if you want to enable frequency analysis for CD audio, this will load a DSP program into effect slot 1, SGL sound driver must be enabled + +# SGL configuration +SGL_MAX_VERTICES = 2500 # Number of vertices that can be used +SGL_MAX_POLYGONS = 1500 # Number of polygons that can be used +SGL_MAX_EVENTS = 1 # Number of events that can be used +SGL_MAX_WORKS = 1 # Number of works that can be used + +# Disk name +CD_NAME = VDP2_ScrollScreen + +# Directory build will be placed into +BUILD_DROP = ./BuildDrop + +# SRL installation directory +SRL_INSTALL_ROOT ?= ../.. + +# Find all .c and .cxx files +SOURCES = $(patsubst ./%,%,$(shell find src/ -name '*.c')) +SOURCES += $(patsubst ./%,%,$(shell find src/ -name '*.cxx')) + +# Include shared makefile +SDK_ROOT = $(SRL_INSTALL_ROOT)/saturnringlib +include $(SDK_ROOT)/shared.mk \ No newline at end of file diff --git a/Samples/VDP2 - RBG0 Rotation Parameters/run_with_mednafen.bat b/Samples/VDP2 - RBG0 Rotation Parameters/run_with_mednafen.bat new file mode 100644 index 00000000..108b6e9f --- /dev/null +++ b/Samples/VDP2 - RBG0 Rotation Parameters/run_with_mednafen.bat @@ -0,0 +1,3 @@ +:; "../../tools/scripts/run.sh" mednafen; exit; +@ECHO Off +"../../tools/scripts/run.bat" mednafen \ No newline at end of file diff --git a/Samples/VDP2 - RBG0 Rotation Parameters/src/main.cxx b/Samples/VDP2 - RBG0 Rotation Parameters/src/main.cxx new file mode 100644 index 00000000..89da6ece --- /dev/null +++ b/Samples/VDP2 - RBG0 Rotation Parameters/src/main.cxx @@ -0,0 +1,102 @@ +/*VDP2 Scroll Layer Demo: +This Demo shows how to Load and display 2 Tilemaps on RBG0 simultaneously using the primary and secondary +Rotation Parameters. +*/ +#include + +using namespace SRL::Types; +using namespace SRL::Input; +using namespace SRL::Math; + +int main() +{ + SRL::Core::Initialize(HighColor(20,10,50)); + Digital port0(0); // Initialize gamepad on port 0 + + // variables to store current position/ rotation of the 2 RBG0 tilemaps: + Vector3D Rbg0PositionPrimary(0.0,80.0,80.0);//80 units below camera for ground + Vector3D Rbg0PositionSecondary(0.0,-80.0,300.0);//80 units above camera for clouds + Angle Rbg0RotationSecondary = Angle::FromDegrees(0.0);//Just for fun, we will also make the clouds rotate + + SRL::Tilemap::Interfaces::CubeTile* TestTilebin= new SRL::Tilemap::Interfaces::CubeTile("GROUND.BIN");//Load ground tilemap from cd to work RAM + + SRL::Tilemap::Interfaces::CubeTile *TestTilebinB= new SRL::Tilemap::Interfaces::CubeTile("CLOUDS.BIN");//Load fog tilemap from cd to work RAM + + //This new overload allows loading 2 tilemaps for RBG0 and initializing their rotation modes all in one go: + SRL::VDP2::RBG0::LoadTilemap(*TestTilebin,*TestTilebinB, SRL::VDP2::RotationMode::TwoAxis,SRL::VDP2::RotationMode::TwoAxis); + + delete TestTilebin;//free work RAM + delete TestTilebinB;//free work RAM + + //----------------------------------------------------------------------------------------------------------------------- + /*Example of laying out a multi plane tilemap in a 4x4 grid for the Primary Tilemap*/ + uint8_t mapLayout[4][4] = + { + 0,1,2,3, + 0,1,2,3, + 0,1,2,3, + 0,1,2,3, + }; + + SRL::VDP2::RBG0::SetPlanes(mapLayout,SRL::VDP2::RotationParameter::Primary);//set the multi-plane layout of Primary Tilemap + + //------------------------------------------------------------------------------------------------------------------------ + //set initial perspective for the Primary and secondary tilemap rotations: + SRL::Scene3D::LoadIdentity(); + + SRL::Scene3D::PushMatrix(); + { + SRL::Scene3D::Translate(Rbg0PositionPrimary); + SRL::Scene3D::RotateX(Angle::FromDegrees(-90.0)); + SRL::VDP2::RBG0::SetCurrentTransform(SRL::VDP2::RotationParameter::Primary); + } + + SRL::Scene3D::PushMatrix(); + { + SRL::Scene3D::Translate(Rbg0PositionSecondary); + SRL::Scene3D::RotateX(Angle::FromDegrees(90.0)); + SRL::VDP2::RBG0::SetCurrentTransform(SRL::VDP2::RotationParameter::Secondary); + } + SRL::Scene3D::PopMatrix(); + + /*Using SetParameterMode() here is not strictly necessary in our example because PerspectiveSwitch + is the default setting when loading 2 tilemaps, but use it if you want a different setting:*/ + SRL::VDP2::RBG0::SetParameterMode(SRL::VDP2::SwitchMode::PerspectiveSwitch); + + SRL::VDP2::RBG0::TransparentDisable();//Turn off transparent pixels on RBG0 + + SRL::VDP2::RBG0::ScrollEnable();//Display RBG0 on screen + + SRL::Debug::Print(1,3,"VDP2 Rotation Parameters Sample"); + + while(1) + { + //Demonstrate independent manipulation of Primary and Secondary tilemaps + Rbg0PositionPrimary.Z-=Fxp(1.0);//scroll ground towards camera + Rbg0PositionPrimary.X-=Fxp(1.0);//scroll ground towards camera + Rbg0RotationSecondary+=Angle::FromDegrees(0.1);//rotate clouds + + //set transform of primary tilemap: + SRL::Scene3D::LoadIdentity(); + SRL::Scene3D::PushMatrix(); + { + SRL::Scene3D::Translate(Rbg0PositionPrimary); + SRL::Scene3D::RotateX(Angle::FromDegrees(-90.0));//'floor' is always rotated -90 degrees X from its default + SRL::VDP2::RBG0::SetCurrentTransform(SRL::VDP2::RotationParameter::Primary); + } + SRL::Scene3D::PopMatrix(); + + //set perspective matrix of secondary tilemap: + SRL::Scene3D::PushMatrix(); + { + SRL::Scene3D::Translate(Rbg0PositionSecondary); + SRL::Scene3D::RotateX(Angle::FromDegrees(90.0));//ceilng is always rotated +90 degrees X from its default + SRL::Scene3D::RotateZ(Rbg0RotationSecondary); + SRL::VDP2::RBG0::SetCurrentTransform(SRL::VDP2::RotationParameter::Secondary); + } + SRL::Scene3D::PopMatrix(); + + SRL::Core::Synchronize(); + } + return 0; +} diff --git a/Samples/VDP2 - RBG0 Rotation/cd/data/CLD.bin b/Samples/VDP2 - RBG0 Rotation/cd/data/CLD.bin deleted file mode 100644 index 8f013a5d..00000000 Binary files a/Samples/VDP2 - RBG0 Rotation/cd/data/CLD.bin and /dev/null differ diff --git a/Samples/VDP2 - RBG0 Rotation/cd/data/CLD2.bin b/Samples/VDP2 - RBG0 Rotation/cd/data/CLD2.bin deleted file mode 100644 index ac8c3e06..00000000 Binary files a/Samples/VDP2 - RBG0 Rotation/cd/data/CLD2.bin and /dev/null differ diff --git a/Samples/VDP2 - RBG0 Rotation/cd/data/ELF_S.TGA b/Samples/VDP2 - RBG0 Rotation/cd/data/ELF_S.TGA deleted file mode 100644 index 1c2ead36..00000000 Binary files a/Samples/VDP2 - RBG0 Rotation/cd/data/ELF_S.TGA and /dev/null differ diff --git a/Samples/VDP2 - RBG0 Rotation/cd/data/FOG.tga b/Samples/VDP2 - RBG0 Rotation/cd/data/FOG.tga deleted file mode 100644 index e06486bf..00000000 Binary files a/Samples/VDP2 - RBG0 Rotation/cd/data/FOG.tga and /dev/null differ diff --git a/Samples/VDP2 - RBG0 Rotation/cd/data/TEST.TGA b/Samples/VDP2 - RBG0 Rotation/cd/data/TEST.TGA deleted file mode 100644 index 35821073..00000000 Binary files a/Samples/VDP2 - RBG0 Rotation/cd/data/TEST.TGA and /dev/null differ diff --git a/Samples/VDP2 - RBG0 Rotation/cd/data/TESTN2.bin b/Samples/VDP2 - RBG0 Rotation/cd/data/TESTN2.bin deleted file mode 100644 index cf14cb12..00000000 Binary files a/Samples/VDP2 - RBG0 Rotation/cd/data/TESTN2.bin and /dev/null differ diff --git a/Samples/VDP2 - RBG0 Rotation/cd/data/TESTN3.bin b/Samples/VDP2 - RBG0 Rotation/cd/data/TESTN3.bin deleted file mode 100644 index a01cd018..00000000 Binary files a/Samples/VDP2 - RBG0 Rotation/cd/data/TESTN3.bin and /dev/null differ diff --git a/Samples/VDP2 - RBG0 Rotation/src/main.cxx b/Samples/VDP2 - RBG0 Rotation/src/main.cxx index 66a94752..efed8c83 100644 --- a/Samples/VDP2 - RBG0 Rotation/src/main.cxx +++ b/Samples/VDP2 - RBG0 Rotation/src/main.cxx @@ -1,8 +1,14 @@ /*VDP2 Rotation Demo: -This Demo Demonstrates how to configure a rotating scroll and provides an interactive -showcase of the differences in rotation behavior between rotation modes. Since VRAM demands -increase with the number of rotation axis used, It is recommended to select the minimum -Number of Axis Required for your desired use case. +This Demo shows how to configure a rotating scroll on RBG0 and provides an interactive +showcase of the differences in rotation behavior and perspective between +1 axis, 2 axis, and 3 axis rotation modes. Since VDP2 VRAM demands +increase with the number of rotation axis used, it is recommended to select the minimum +number of axis required for your desired use case. A blue polygon is drawn in the center +of the screen alligned to the same starting axis as the RBG0 plane (facing out of the screen). +This demonstrates that 3D transforms effect both polygons and RBG0 identically when within +the valid rotation axis for the selected mode, but will not align when rotation +occurs along an invalid axis for the selected rotation mode. With 3 axis rotation selected +for RBG0, the polygon plane and RBG0 plane will always align. */ #include @@ -10,11 +16,38 @@ using namespace SRL::Types; using namespace SRL::Math::Types; using namespace SRL::Input; +//---------------------------------------------------------------------------------------------------- +// Mesh data for a single polygon plane + +Vector3D TestVerts[] = +{ + Vector3D(-40.0,-140.0,0.0), + Vector3D(-40.0,-60.0,0.0), + Vector3D(40.0,-60.0,0.0), + Vector3D(40.0,-140.0,0.0), +}; + +Polygon TestPolys[] = +{ + Polygon(Vector3D(0.0,0.0,-1.0),(uint16_t[4]){0, 1, 2, 3}), +}; + +Attribute TestAttr[] = +{ + Attribute(Attribute::FaceVisibility::DoubleSided,Attribute::SortMode::Maximum, + No_Texture,HighColor(0,0,255),No_Gouraud,CL32KRGB,sprPolygon,No_Option), +}; +Mesh TestMesh = Mesh(4,TestVerts, 1, TestPolys,TestAttr); + +//------------------------------------------------------------------------------------------------------- +//Function to swap between the 3 available rotation modes + static void LoadRBG0(uint8_t config, SRL::Tilemap::ITilemap* map) { SRL::VDP2::RBG0::ScrollDisable();//turn off scroll display so we dont see junk when loading to VRAM - SRL::VDP2::ClearVRAM();//Clearing VDP2 VRAM because use differs between Rotation Modes - SRL::VDP2::RBG0::LoadTilemap(*map);//Transfer Tilemap to VRAM again + SRL::VDP2::ClearVRAM();//Clearing VDP2 VRAM because its use differs between Rotation Modes + SRL::VDP2::RBG0::LoadTilemap(*map);//Transfer Tilemap to VRAM again since we cleared it + switch (config) { case 0: @@ -28,49 +61,45 @@ static void LoadRBG0(uint8_t config, SRL::Tilemap::ITilemap* map) case 1: /*configure RBG0 with 2 Axis rotation: -X and Z axis rotation displays correctly while Y rotation causes scaling/skewing - -Snes Mode7 style effect like Mario Kart/F-Zero - -Works for 3D ground in games where there is no rolling around camera's axis*/ + -SNES Mode 7 style floor effect like Mario Kart/F-Zero + -Works for 3D ground/cieling pland in games where there is no rolling around the camera's axis*/ SRL::VDP2::RBG0::SetRotationMode(SRL::VDP2::RotationMode::TwoAxis); SRL::Debug::Print(1,5,"Rotation Mode "); break; case 2: /*configure RBG0 with 3 Axis Rotation: - -Full 3D rotation + -Full 3D rotation on all axis (SNES couldn't do this!) -Works for 3D flight sims or other games where camera rolling is desired*/ SRL::VDP2::RBG0::SetRotationMode(SRL::VDP2::RotationMode::ThreeAxis); SRL::Debug::Print(1,5,"Rotation Mode "); break; } - slBMPaletteRbg0(9); + SRL::VDP2::RBG0::ScrollEnable();//Turn Scroll Display back on } int main() { SRL::Core::Initialize(HighColor(20,10,50)); - - Digital port0(0); // Initialize gamepad on port 0 - int8_t CurrentMode = 0; - - SRL::Tilemap::Interfaces::CubeTile* TestTilebin = new SRL::Tilemap::Interfaces::CubeTile("FOGRGB.BIN");//Load tilemap from cd to main RAM - - LoadRBG0(0, TestTilebin); + int8_t CurrentMode = 0;//variable to store which rotation mode is selected + SRL::Tilemap::Interfaces::CubeTile* TestTilebin = new SRL::Tilemap::Interfaces::CubeTile("FOG256.BIN");//Load tilemap from cd to work RAM + LoadRBG0(CurrentMode, TestTilebin);//Load tilemap from work RAM to VDP2 VRAM and configure it to start in Single Axis mode - //SRL::VDP2::RBG0::SetPriority(SRL::VDP2::Priority::Layer2);//set RBG0 priority - //SRL::VDP2::RBG0::ScrollEnable();//enable display of RBG0 - - //variables to store current RBG0 rotation - int16_t angY = (int16_t)DEGtoANG(0.1); - int16_t angZ = (int16_t)DEGtoANG(0.0); - int16_t angX = (int16_t)DEGtoANG(0.0); + //variables to store current RBG0 position and rotation + Vector3D RBG0position = Vector3D(0.0,100.0,160.0); + Angle angX = Angle::FromDegrees(0.0); + Angle angY = Angle::FromDegrees(0.1); + Angle angZ = Angle::FromDegrees(0.0); + + //Print title and demo controls on screen SRL::Debug::Print(1,3,"Rotating Scroll Modes Sample"); SRL::Debug::Print(1, 6, ""); SRL::Debug::Print(1, 7, ""); SRL::Debug::Print(1, 8, ""); - + //Main Game Loop while(1) { @@ -95,27 +124,38 @@ int main() } //Update Rotations based on user input - if (port0.IsHeld(Digital::Button::X)) angX += DEGtoANG(0.3); - else if (port0.IsHeld(Digital::Button::A)) angX -= DEGtoANG(0.3); + if (port0.IsHeld(Digital::Button::X)) angX += Angle::FromDegrees(0.3); + else if (port0.IsHeld(Digital::Button::A)) angX -= Angle::FromDegrees(0.3); - if (port0.IsHeld(Digital::Button::Y)) angY += DEGtoANG(0.3); - else if (port0.IsHeld(Digital::Button::B)) angY -= DEGtoANG(0.3); + if (port0.IsHeld(Digital::Button::Y)) angY +=Angle::FromDegrees(0.3); + else if (port0.IsHeld(Digital::Button::B)) angY -= Angle::FromDegrees(0.3); - if (port0.IsHeld(Digital::Button::Z)) angZ += DEGtoANG(0.3); - else if (port0.IsHeld(Digital::Button::C)) angZ -= DEGtoANG(0.3); + if (port0.IsHeld(Digital::Button::Z)) angZ += Angle::FromDegrees(0.3); + else if (port0.IsHeld(Digital::Button::C)) angZ -=Angle::FromDegrees(0.3); } - //Rotate current matrix and Set it in rotation parameters - slPushMatrix(); + /*Rotate current matrix and Set it in rotation parameters. + RBG0 plane gets its position, rotation, and scale based on the same Matrix that SRL::Scene3D uses. + + -NOTE: because this is Euler rotation, the order they are applied matters (Rot(XYZ) is not equal to Rot(YXZ)). + A different order of rotations might change which axis preserve the correct perspective of RBG0 in 2 Axis mode. + With the standard XYZ ordering below, X and Z rotations preserve perspective in 2 axis mode*/ + SRL::Scene3D::PushMatrix(); { - slTranslate(toFIXED(0.0), toFIXED(100), MsScreenDist); - slRotY(angY); - slRotX(angX); - slRotZ(angZ); + SRL::Scene3D::Translate(RBG0position); + + SRL::Scene3D::RotateX(angX); + SRL::Scene3D::RotateY(angY); + SRL::Scene3D::RotateZ(angZ); + + //Apply the current matrix transform to RBG0: SRL::VDP2::RBG0::SetCurrentTransform(); + //To demonstrate that the transform applies the same to polygons, draw a polygon plane using the same matrix: + SRL::Scene3D::DrawMesh(TestMesh); + } - slPopMatrix(); + SRL::Scene3D::PopMatrix(); SRL::Core::Synchronize(); } diff --git a/saturnringlib/srl_mesh.hpp b/saturnringlib/srl_mesh.hpp index feb00ca8..6fffb8e8 100644 --- a/saturnringlib/srl_mesh.hpp +++ b/saturnringlib/srl_mesh.hpp @@ -39,7 +39,7 @@ namespace SRL::Types /** @brief Use the average position of 4 points */ - Center = SORT_CEN + Center = SORT_CEN }; /** @brief Quad display mode diff --git a/saturnringlib/srl_scene2d.hpp b/saturnringlib/srl_scene2d.hpp index d6977378..80166907 100644 --- a/saturnringlib/srl_scene2d.hpp +++ b/saturnringlib/srl_scene2d.hpp @@ -488,7 +488,7 @@ namespace SRL (Scene2D::Effects.Clipping << 9) | (Scene2D::Effects.ScreenDoors << 8) | - colorMode | + colorMode | (Scene2D::Effects.EndCode ? ECenb : ECdis) | (Scene2D::Effects.HighSpeedShrink ? HSSon : HSSoff) | (Scene2D::Effects.DisablePreClipping ? Pclpoff : Pclpon) | diff --git a/saturnringlib/srl_scene3d.hpp b/saturnringlib/srl_scene3d.hpp index a90a05a2..dc9608aa 100644 --- a/saturnringlib/srl_scene3d.hpp +++ b/saturnringlib/srl_scene3d.hpp @@ -85,7 +85,7 @@ namespace SRL */ static void LightInitGouraudTable(uint32_t gouraudRamOffset, uint8_t* vertexCalculationBuffer, Types::HighColor* tableStorage, uint32_t maxPolygons) { - slInitGouraud((GOURAUDTBL*)tableStorage, maxPolygons, 0xe000 + (gouraudRamOffset << 2), vertexCalculationBuffer); + slInitGouraud((GOURAUDTBL*)tableStorage, maxPolygons, 0xe000 + (gouraudRamOffset<<2) , vertexCalculationBuffer); } /** @brief Set custom light gouraud table. Affects quads with SRL::Types::Attribute::DisplayOption::EnableGouraud option set diff --git a/saturnringlib/srl_tilemap.hpp b/saturnringlib/srl_tilemap.hpp index 063a6031..72c2e9d6 100644 --- a/saturnringlib/srl_tilemap.hpp +++ b/saturnringlib/srl_tilemap.hpp @@ -115,10 +115,10 @@ namespace SRL::Tilemap } }; - /** @brief Unsigned 8 bit coordinates for tiles withing a page of a tilemap + /** @brief Unsigned 16 bit coordinates for tiles withing a page of a tilemap * @note Coordinates [0,0] represent top left corner of a page (same as Print coordinates) * @note Coordinates are in tile units, which can be either 8x8 or 16x16 pixels. - * Max allowed coordinates in a page vary by Tile Size (64 for 8x8 tiles, 32 for 16x16) + * Max coordinates in a page vary by Tile Size (64 for 8x8 tiles, 32 for 16x16) */ struct Coord { diff --git a/saturnringlib/srl_tilemap_interfaces.hpp b/saturnringlib/srl_tilemap_interfaces.hpp index b63be490..31c23f05 100644 --- a/saturnringlib/srl_tilemap_interfaces.hpp +++ b/saturnringlib/srl_tilemap_interfaces.hpp @@ -322,7 +322,7 @@ namespace SRL::Tilemap::Interfaces return this->info; } - /** @brief Copies a rectangular selection of Tilemap data between 2 pages in the tilemap + /** @brief Copies a rectangular selection of Tilemap data between 2 pages in the tilemap * @param sourcePage Index of the Tilemap Page to copy from * @param topLeft Page Coordinates of Top left of region to Copy * @param botRight Page Coordinates of Bottom Right of region Copy @@ -334,7 +334,7 @@ namespace SRL::Tilemap::Interfaces // Check that requested page indicies exist in this map: if (!this->mapData || sourcePage >= this->numPages || destPage >= numPages) - { + { return; } @@ -488,10 +488,12 @@ namespace SRL::Tilemap::Interfaces // Load file uint8_t* imageData = (uint8_t*)(stream + 32); uint32_t* headerData = (uint32_t*)stream; + this->info.CellByteSize = headerData[1]; + uint32_t celSize = this->info.CellByteSize; uint32_t mapSize = headerData[2]; - + //decode color mode switch (headerData[4]) { diff --git a/saturnringlib/srl_vdp2.hpp b/saturnringlib/srl_vdp2.hpp index 6cb0837a..c4789882 100644 --- a/saturnringlib/srl_vdp2.hpp +++ b/saturnringlib/srl_vdp2.hpp @@ -8,11 +8,6 @@ #include "srl_cd.hpp" #include "srl_tilemap_interfaces.hpp" -/*I'm running into an issue with getting Bitmaps working for RBG0. Does anyone know -what SGL function if any is supposed to set the RAM contol register associated with reserving -a bank in bitmaps case? None of the bitmap functions appear to set the bits. I can get it to work by -manually setting the bits in VDP2_RAMCTL system variable... - */ namespace SRL { /** @brief VDP2 control @@ -34,6 +29,7 @@ namespace SRL Layer6 = 6, Layer7 = 7, }; + /** @brief Options for using color offsets on Scroll Screens * * @details Scroll and sprite screens can apply one of 2 color offsets @@ -63,6 +59,21 @@ namespace SRL B0 = 2, B1 = 3, }; + + /** @brief Used to set the minimum allowed scale for NBG0 and NBG1 scrolls + */ + enum class ScaleLimit: uint16_t + { + /** @brief Set minimum scale to 1x (default) + */ + One = ZOOM_1, + /** @brief Set minimum scale to 1/2x + */ + Half = ZOOM_HALF, + /** @brief Set minimum scale to 1/4x + */ + Quarter = ZOOM_QUARTER, + }; /** @brief converts an SRL TextureColorMode enum to its corresponding SGL macro for VDP2 * @param colorMode the colorMode to convert @@ -84,17 +95,17 @@ namespace SRL */ friend class VDP2; - /** @brief Bottom RAM bank zones + /** @brief Absolute Bottom Address of RAM bank zones */ inline static uint8_t* bankBot[4] = { (uint8_t*)VDP2_VRAM_A0,(uint8_t*)VDP2_VRAM_A1,(uint8_t*)VDP2_VRAM_B0,(uint8_t*)VDP2_VRAM_B1 }; - /** @brief Top RAM bank zones + /** @brief Abolute Top Address of RAM bank zones */ inline static uint8_t* bankTop[4] = { (uint8_t*)VDP2_VRAM_A1,(uint8_t*)VDP2_VRAM_B0,(uint8_t*)VDP2_VRAM_B1,(uint8_t*)(VDP2_VRAM_B1 + 0x18000) }; /** @brief Currently allocated bottom RAM bank zones */ - inline static uint8_t* currentBot[4] = { (uint8_t*)VDP2_VRAM_A0,(uint8_t*)VDP2_VRAM_A1,(uint8_t*)VDP2_VRAM_B0,(uint8_t*)VDP2_VRAM_B1 };; + inline static uint8_t* currentBot[4] = { (uint8_t*)VDP2_VRAM_A0,(uint8_t*)VDP2_VRAM_A1,(uint8_t*)VDP2_VRAM_B0,(uint8_t*)VDP2_VRAM_B1 }; /** @brief Currently allocated top RAM bank zones */ @@ -105,6 +116,13 @@ namespace SRL */ inline static int8_t bankCycles[4] = { -1,-1,-1,2 };//why will init to 0 not work? + /** @brief Indicates if map data has been stored in bank A0 by a previous allocation + */ + inline static bool MapBankA0 = false; + /** @brief Indicates if map data has been stored in bank B0 by a previous allocation + */ + inline static bool MapBankB0 = false; + public: /** @brief Gets current amount of free VRAM in a bank * @param bank the VRAM bank to get free space in @@ -116,14 +134,14 @@ namespace SRL } /** @brief Linearly Allocates Vram in a bank and returns address to start of allocation. Allocation fails if - * there is not enough free space in the bank or if access requires too many cycles. + * there is not enough free space in the bank or if access requires too many cycle slots. * @param size Number of bytes to allocate * @param boundary Byte Boundary that the allocation should be aligned to (must be multiple of 32 for all VDP2 Data types) * @param bank The VRAM bank to allocate in - * @param cycles (Optional) Number of Bank Cycles this data will require to access during frame(0-8). + * @param cycles (Optional)The Number of Access Slots in a bank's Cycle Pattern that the data will require during display. * @return void* start of the Allocated region in VRAM (nullptr if allocation failed) * @note Any VRAM padded to maintain alignment to a requested boundary is rendered inaccessible to further - * allocations until VRAM is cleared and reset. + * allocations until VRAM is reset through VDP2::ClearVram(). */ inline static void* Allocate(uint32_t size, uint32_t boundary, VDP2::VramBank bank, uint8_t cycles = 0) { @@ -154,6 +172,8 @@ namespace SRL * @param info Tile cell data description * @param screen The screen identifier * @return Pointer to the allocated memory + * @note The Maximum supported allocation size is 0x20000 bytes (1 Bank).Single Allocations + * can not be spit between multiple banks */ inline static void* AutoAllocateCell(Tilemap::TilemapInfo& info, uint16_t screen) { @@ -161,10 +181,10 @@ namespace SRL if (screen == scnRBG0) // Reserve all 8 cycles of a bank { - alloc = VRAM::Allocate(info.CellByteSize, 32, VramBank::A0, 8); - if (alloc == nullptr) alloc = VRAM::Allocate(info.CellByteSize, 32, VramBank::A1, 8); - if (alloc == nullptr) alloc = VRAM::Allocate(info.CellByteSize, 32, VramBank::B0, 8); - if (alloc == nullptr) alloc = VRAM::Allocate(info.CellByteSize, 32, VramBank::B1, 8); + //alloc = VRAM::Allocate(info.CellByteSize, 32, VramBank::A0, 8); + alloc = VRAM::Allocate(info.CellByteSize, 32, VramBank::A1, 8); + //if (alloc == nullptr) alloc = VRAM::Allocate(info.CellByteSize, 32, VramBank::B0, 8); + //if (alloc == nullptr) alloc = VRAM::Allocate(info.CellByteSize, 32, VramBank::B1, 8); if (alloc == nullptr) SRL::Debug::Assert("RBG Cell Allocation failed: insufficient VRAM"); } else // Base cycle requirement on color type @@ -199,13 +219,15 @@ namespace SRL * @param screen The screen identifier * @param size optional pointer to pass the resulting allocation size back to * @return Pointer to the allocated memory + * @note The Maximum supported allocation size is 0x20000 bytes (1 Bank).Single Allocations + * can not be spit between multiple banks */ inline static void* AutoAllocateMap(Tilemap::TilemapInfo& info, int16_t screen,int* size = nullptr ) { void* alloc = nullptr; uint32_t page_sz = 0x800; uint32_t sz = (info.MapHeight * info.MapWidth) << 1; - + if (info.CharSize == CHAR_SIZE_1x1) page_sz <<= 2; if (info.MapMode == PNB_2WORD) @@ -216,17 +238,30 @@ namespace SRL if (info.PlaneSize == PL_SIZE_2x2) page_sz <<= 2; else if (info.PlaneSize == PL_SIZE_2x1) page_sz <<= 1; - + //if(info.MapByteSize)sz = info.MapByteSize; if (screen == scnRBG0) // Reserve all 8 cycles of bank 0 { alloc = VRAM::Allocate(sz, page_sz, VramBank::A0, 8); if (alloc == nullptr) Debug::Assert("RBG Map Allocation failed: insufficient VRAM"); - else if(size!=nullptr)*size = sz; + else + { + if(size!=nullptr)*size = sz; + MapBankA0 = true; + } } else // Reserve 1 cycle in bank B1 (or B0 if it doesn't conflict with RBG0 map) { - if (bankCycles[0]!=7) alloc = VRAM::Allocate(sz, page_sz, VramBank::A0, 1); - if(!alloc) alloc = VRAM::Allocate(sz, page_sz, VramBank::B1, 1); + alloc = VRAM::Allocate(sz, page_sz, VramBank::B1, 1); + if (alloc == nullptr && MapBankA0==false) + { + alloc = VRAM::Allocate(sz, page_sz, VramBank::B0, 1); + if(alloc)MapBankB0 = true; + } + if((alloc == nullptr) && MapBankB0==false) + { + alloc = VRAM::Allocate(sz, page_sz, VramBank::A0, 1); + if(alloc)MapBankA0 = true; + } if (alloc == nullptr) SRL::Debug::Assert("NBG Map Allocation failed: insufficient VRAM"); else if(size!=nullptr)*size = sz; } @@ -240,6 +275,7 @@ namespace SRL * @param size optional pointer to pass the resulting allocation size back from function * @return Pointer to the allocated memory * @note The maximum allocation size supported is 0x40000 bytes (2 banks of VRAM). + * 2 bank allocations must split either betweeen BankA0 and BankA1, Or BankA1 and BankB0. */ inline static void* AutoAllocateBmp(Bitmap::BitmapInfo& info, int16_t screen, int* size = nullptr) { @@ -275,19 +311,21 @@ namespace SRL } else if(sz>131072)//case: bmp requires 2 out of the 4 VRAM banks { - if((uint32_t)bankBot[0]==VDP2_VRAM_A0 && (uint32_t)bankBot[1]==VDP2_VRAM_A1) + if((uint32_t)currentBot[0]==VDP2_VRAM_A0 && (uint32_t)currentBot[1]==VDP2_VRAM_A1) { + alloc = VRAM::Allocate(131072, 32, VramBank::A0, numCycles); VRAM::Allocate(131072, 32, VramBank::A1, numCycles); } - else if((uint32_t)bankBot[1]==VDP2_VRAM_A1 && (uint32_t)bankBot[2]==VDP2_VRAM_B0) + else if((uint32_t)currentBot[1]==VDP2_VRAM_A1 && (uint32_t)currentBot[2]==VDP2_VRAM_B0) { + alloc = VRAM::Allocate(131072, 32, VramBank::A1, numCycles); VRAM::Allocate(131072, 32, VramBank::B0, numCycles); } else { - Debug::Assert("Bmp Allocation Failed: Insufficient VRAM"); + Debug::Assert("Bmp Allocation Failed: Insufficient VRAM Available"); return nullptr; } } @@ -298,10 +336,10 @@ namespace SRL if (alloc == nullptr) alloc = VRAM::Allocate(sz, 32, VramBank::B0,numCycles); if (alloc == nullptr) alloc = VRAM::Allocate(sz, 32, VramBank::A1, numCycles); if (alloc == nullptr) alloc = VRAM::Allocate(sz, 32, VramBank::B1, numCycles); - if (alloc == nullptr) SRL::Debug::Assert("Bmp Allocation failed: insufficient VRAM"); + if (alloc == nullptr) SRL::Debug::Assert("Bmp Allocation failed: insufficient VRAM Available"); } if(size) *size = sz; - // SRL::Debug::Print(3,17,"Size = %d",size); + // SRL::Debug::Print(3,18,"Address: %x",(uint32_t)alloc-VDP2_VRAM_A0); return alloc; } @@ -335,7 +373,7 @@ namespace SRL /** @brief Bitfield recording all Scroll Screens That Disable transparent pixels */ - inline static uint16_t TransparentScrolls = 0; + inline static uint16_t TransparentScrolls = SPRON; /** @brief Functionality available to all Scroll Screen interfaces */ @@ -435,18 +473,22 @@ namespace SRL * if there is not enough VRAM/cycles available to allocate. * * @param tilemap The Tilemap to load + * @param loadPalette (optional: default = true) Auto load the Tilemap's palette to CRAM if present. + * If a CRAM palette is already assigned, loads to that bank, overwriting existing data. + * If a CRAM palette is not already assigned, attempts to assign palette and asserts if unavailable. + * * @note Manual VRAM allocation is for advanced use cases and is NOT verified for proper bank alignment. * @note Does not turn Scroll Display on- once loaded use ScrollEnable() to display a Scroll Screen. * @note As RBG0 must reserve dedicated VRAM banks always perform loading/allocation * for RBG0 before NBG0-3 screens if using it. */ - inline static void LoadTilemap(SRL::Tilemap::ITilemap& tilemap) + inline static void LoadTilemap(SRL::Tilemap::ITilemap& tilemap, bool loadPalette = true) { SRL::Tilemap::TilemapInfo myInfo = tilemap.GetInfo(); ScreenType::Info = tilemap.GetInfo(); int autoMapSize = 0; - if ((uint32_t)ScreenType::MapAddress < VDP2_VRAM_A0) + if ((uint32_t)ScreenType::MapAddress < VDP2_VRAM_A0|| (uint32_t)ScreenType::MapAddress>=(VDP2_VRAM_B1 + 0x18000)) { ScreenType::MapAddress = VRAM::AutoAllocateMap(myInfo, ScreenType::ScreenID,&autoMapSize); if ((uint32_t)ScreenType::MapAddress < VDP2_VRAM_A0) return; @@ -459,13 +501,13 @@ namespace SRL return; } - if ((uint32_t)ScreenType::CellAddress < VDP2_VRAM_A0) + if ((uint32_t)ScreenType::CellAddress < VDP2_VRAM_A0||(uint32_t)ScreenType::CellAddress>=(VDP2_VRAM_B1 + 0x18000)) { ScreenType::CellAddress = VRAM::AutoAllocateCell(myInfo, ScreenType::ScreenID); if ((uint32_t)ScreenType::CellAddress < VDP2_VRAM_A0) { - SRL::Debug::Assert("Tilemap Load Failed- CEL DATA exceeds existing VRAM allocation"); + //SRL::Debug::Assert("Tilemap Load Failed- CEL DATA exceeds existing VRAM allocation"); return; } else ScreenType::CellAllocSize = myInfo.CellByteSize; @@ -477,7 +519,7 @@ namespace SRL } int colorID = 0; - if (ScreenType::Info.ColorMode != SRL::CRAM::TextureColorMode::RGB555) + if (loadPalette && ScreenType::Info.ColorMode != SRL::CRAM::TextureColorMode::RGB555) { if(ScreenType::TilePalette.GetData()==nullptr) { @@ -524,7 +566,7 @@ namespace SRL ScreenType::CellAllocSize = size; return address; } - + /** @brief Manually Sets VRAM area for Map Data (Advanced Use Cases) * @details This function manually sets an area in VRAM for a scroll's Map Data to be loaded to. Unless the * Address is obtained from VDP2::VRAM::Allocate() the VRAM allocator will be bypassed entirely. @@ -544,6 +586,40 @@ namespace SRL return Address; } + /** @brief Manually sets the CRAM palette index for this scrollScreen(Advanced Use Cases) + * @details Shallow copies the specified palette handler to the ScrollScreen's + * TilePalette, forcing it to register with the specified palette. Use in cases + * where the user desires more control over palette placement in CRAM, such as palette + * sharing between tilemaps. + * @note when set this way, multiple sources may be able to write to the same palette. + * specify the LoadPalette parameter as false when using ScrollScreen::LoadTilemap() + * to ensure pre-existing palette is not overwritten during loading. + */ + inline static void SetPalette(CRAM::Palette palette) + { + ScreenType::TilePalette = palette; + } + + /** @brief Registers the ScrollScreen to Display SRL's Debug Ascii Scroll + * @details A scrollscreen that is Registered to the Ascii Scroll will remain + * registered even if VDP2::ClearVRAM() is called. It will automatically unregister + * and revert to normal loading when it's LoadTilemap()/LoadBitmap() method is next called. + * @note -The Ascii Scroll is not compatible with Rotation Scroll RBG0. + * @note -The Ascii Scroll was designed to have its position fixed on screen, and may display garbage + * data in the margins if its position is offset or used in High res mode without proper scaling. + * @note -The Ascii scroll data is stored outside The VRAM Alloacator's valid memory region, so + * can not be written to with the standard ScrollScreen loading functions. Manage loading + * fonts with the SRL::ASCII module instead. + */ + inline static void RegisterAsciiScroll() + { + SRL::Tilemap::TilemapInfo AsciiInfo(CRAM::TextureColorMode::Paletted16, PNB_1WORD|CN_10BIT, + CHAR_SIZE_1x1,PL_SIZE_1x1,1,1,0); + SetCellAddress((void*)(VDP2_VRAM_B1 + 0x1D000),0); + SetMapAddress((void*)(VDP2_VRAM_B1 + 0x1E000),0); + ScreenType::Init(AsciiInfo); + } + /** @brief Registers Scroll in VDP2 cycle pattern to enable display of this Scroll Screen * @details Asserts when registration of a scroll fails due to cycle pattern conflicts. * Possible causes: @@ -643,7 +719,7 @@ namespace SRL * @details This Function takes the opacity specified as a fixed point value and converts it to * one of the 32 color calculation ratios that a scroll screen can use (value is floored to the nearest ratio). * Color Calculation is turned on if Opacity < 1.0, or off if Opacity>= 1.0. Color calculation is unchanged if value is negative. - * @note Color ratios only apply to highest priority pixels in frame + * @note Color ratios only apply to highest priority pixels in the frame * @note When VDP2 ColorCalcMode is set to UseColorAddition, all scrolls with opacity < 1.0 will use color addition * in place of their specified ratios. * @param opacity Fxp decimal value between 0.0 and 1.0 representing pixel opacity for the scroll screen (Default 1.0) @@ -666,9 +742,10 @@ namespace SRL } /** @brief Set the Display Priority of a Scroll Screen - * @note Higher value layers display on top of lower layers. - * @note When 2 or more scroll screens are assigned the same layer, their priority resolves as - * SPRITE>RBG0>NBG0>NBG1>NBG2>NBG3. + * @note -Higher priority values display on top of lower priorities. Setting Priority::Layer0 + * disables display of a scroll screen without unregistering it. + * @note -When 2 or more scroll screens are assigned the same layer, their priority resolves as + * SPRITE > RBG0 > NBG0 > NBG1 > NBG2 > NBG3. * @param pr The Priority Layer for the Scroll Screen */ inline static void SetPriority(SRL::VDP2::Priority pr) { slPriority(ScreenType::ScreenID, (uint16_t)pr); } @@ -767,7 +844,6 @@ namespace SRL return paletteOffset; } - private: /** @brief Copies Cell data to VRAM (adapted from SGL samples). * @param CellData Cell Data to copy. @@ -786,8 +862,8 @@ namespace SRL * @param info Tilemap data config. * @param mapData Map data to copy to VRAM. * @param mapAdr VRAM address to copy map to . - * @param mapoff offset added when Cell data does not start at bank boundary . * @param paloff Palette index in CRAM. + * @param mapoff offset added when Cell data does not start at bank boundary . */ inline static void Map2VRAM(SRL::Tilemap::TilemapInfo& info, uint16_t* mapData, void* mapAdr, uint8_t paloff, uint32_t mapoff) { @@ -799,7 +875,7 @@ namespace SRL { for (uint16_t j = 0; j < info.MapWidth; j++) { - if (info.MapMode) *VRAM++ = ((*mapData++) + mapoff) | (paloff << 12); // 1WORD data + if (info.MapMode) *VRAM++ = ((*mapData++) + mapoff) | (paloff << 12); // 1WORD datal else *VRAM32++ = ((*Data32++) + mapoff) | (paloff << 20); // 2WORD data } } @@ -830,10 +906,9 @@ namespace SRL * @param bmp Pointer to the bitmap interface to load from. * @note If source Bitmap size is not equal to one of the container sizes, excess VRAM will be wasted. * To conserve VRAM, consider converting to tilemap format with Bmp2Tile for smaller images when possible. - * @note RBG0 only supports the 512x256 and 512x512 containers. Because RBG0 does not need to reserve an extra bank - * for map data in this mode, this is one case where using the bitmap format may save VRAM resources over tilemaps. + * @note RBG0 only supports the 512x256 and 512x512 containers. */ - inline static void LoadBitmap(SRL::Bitmap::IBitmap* bmp) + inline static void LoadBitmap(SRL::Bitmap::IBitmap* bmp, bool loadPalette = true) { SRL::Bitmap::BitmapInfo myInfo = bmp->GetInfo(); int autoSize = 0; @@ -847,11 +922,11 @@ namespace SRL SRL::Debug::Assert("Bitmap Allocation Failed"); return; } - VRAM::Blank(ScreenType::CellAddress,ScreenType::CellAllocSize); + //VRAM::Blank(ScreenType::CellAddress,ScreenType::CellAllocSize); Bmp2VRAM(bmp->GetData(),ScreenType::CellAddress,myInfo); int colorID = -1; - if (myInfo.Palette!=nullptr && myInfo.Palette->Count!=0) + if (loadPalette && myInfo.Palette!=nullptr && myInfo.Palette->Count!=0) { if(ScreenType::TilePalette.GetData()==nullptr) { @@ -866,7 +941,6 @@ namespace SRL //handle 16 color palette mapping to the allowed banks if(GetSGLColorMode(col) == 0) { - SRL::Debug::Print(0,20,"4bpp"); for(int i = 0;i<8; ++i) { if(!SRL::CRAM::GetBankUsedState(i<<4, col)) @@ -885,7 +959,7 @@ namespace SRL } SRL::CRAM::SetBankUsedState(colorID, col, true); ScreenType::TilePalette = SRL::CRAM::Palette(col, colorID); - SRL::Debug::Print(0,21,"Pal: %d",(int)ScreenType::TilePalette.GetData()-VDP2_COLRAM); + ScreenType::TilePalette.Load(myInfo.Palette->Colors, myInfo.Palette->Count); } ScreenType::TilePalette.Load(myInfo.Palette->Colors, myInfo.Palette->Count); @@ -894,13 +968,13 @@ namespace SRL } /** @brief Copies Bmp data to VRAM - * @param BmpData Data to copy. - * @param BmpAdr VRAM address to copy to. + * @param bmpData Source address of Data to copy. + * @param bmpAdr VRAM address to copy to. * @param info info about bmp * @note When the source image does not completely fill the container the * transfer will pad each line of the image to allign to the container width. * However the padded VRAM is not cleared when using this function, so may display - * garbage data. Use VDP2::VRAM::Blank() beforehand to clear all data to zero if desired. + * garbage data. Use VDP2::VRAM::Blank() beforehand to clear VRAM area to zeros if desired. */ inline static void Bmp2VRAM(void* bmpData, void* bmpAdr, SRL::Bitmap::BitmapInfo info) { @@ -968,7 +1042,6 @@ namespace SRL else slBMPaletteNbg0(NBG0::TilePalette.GetId()); } - /** @brief Set the 2x2 grid of planes for the layer * @param a First plane * @param b Second plane @@ -981,13 +1054,25 @@ namespace SRL * @param pos Fixed Point X and Y Screen Position */ static void SetPosition(Math::Vector2D& pos) { slScrPosNbg0(pos.X.RawValue(), pos.Y.RawValue()); } - + /** @brief Sets the Scale of NBG0 Screen display * @param scl Fixed Point X an Y scaling values - * @note The minimum scale that can be displayed is determined by The Scale Limit, Scaling values - * lower than the minimum will be clamped to the minimum + * @note The minimum scale that can be displayed is determined by the Scale Limit , Scaling values + * lower than the minimum will be clamped to the minimum (see SetScaleLimit() for more details) */ static void SetScale(Math::Vector2D& scl) { slScrScaleNbg0(scl.X.RawValue(), scl.Y.RawValue()); } + + /** @brief Sets the minimum scale that the ScrollScreen can display + * @details NBG0 can scale its displayed tilemap or bitmap up freely, but has + * a minimum default scale of 1x due to cycle pattern limits. + * This minimum can be changed to 1/2x or 1/4x for further reduction at the + * cost of increasing its required cycle accesses( By 2x for 1/2x scaling or 4x + * for 1/4x scaling) + * @note -If the number of cycle access required for scaling is too large, it can interfere with + * registering scrolls for display with ScrollEnable(). + * @note -Only 8bpp and 4bpp data supports 1/2x scaling, and only 4bpp supports 1/4x scaling + */ + static void SetScaleLimit(VDP2::ScaleLimit limit){slZoomModeNbg0((uint16_t)limit); } }; /** @brief NBG1 interface @@ -1038,16 +1123,28 @@ namespace SRL static void SetPlanes(void* a, void* b, void* c, void* d) { slMapNbg1(a, b, c, d); } /** @brief Sets the Screen Position of NBG Scroll Screen - * @param pos Fixed Point X and Y Screen Position + * @param pos Fixed Point X and Y Offset of Scoll Position relative to screen */ static void SetPosition(Math::Vector2D& pos) { slScrPosNbg1(pos.X.RawValue(), pos.Y.RawValue()); } /** @brief Sets the Scale of NBG1 Screen display - * @param scl Fixed Point X an Y scaling values + * @param scl Fixed Point X and Y scaling values * @note The minimum scale that can be displayed is determined by The Scale Limit, Scaling values * lower than the minimum will be clamped to the minimum */ static void SetScale(Math::Vector2D& scl) { slScrScaleNbg1(scl.X.RawValue(), scl.Y.RawValue()); } + + /** @brief Sets the minimum scale that the ScrollScreen can display + * @details NBG1 can scale its displayed tilemap or bitmap up freely, but has + * a default minimum scale of 1x due to cycle pattern limits. + * This minimum can be changed to 1/2x or 1/4x for further reduction at the + * cost of increasing its required cycle accesses( By 2x for 1/2x scaling or 4x + * for 1/4x scaling) + * @note -If the number of cycle access required for scaling is too large, it can interfere with + * registering scrolls for display with ScrollEnable(). + * @note -Only 8bpp and 4bpp data supports 1/2x scaling, and only 4bpp supports 1/4x scaling + */ + static void SetScaleLimit(VDP2::ScaleLimit limit){slZoomModeNbg1((uint16_t)limit); } }; /** @brief NBG2 interface @@ -1123,8 +1220,8 @@ namespace SRL static void SetPosition(Math::Vector2D& pos) { slScrPosNbg3(pos.X.RawValue(), pos.Y.RawValue()); } }; - /** @brief setting for RBG0,1 rotation constraints - * @note more axis require more VRAM resources + /** @brief Settings for RBG0 rotation constraints + * @note More simulated axis of rotation require more VDP2 VRAM resources to display. */ enum class RotationMode { @@ -1133,45 +1230,254 @@ namespace SRL */ OneAxis, - /** @brief 3d rotation with pitch and yaw, but no roll (modified per line) - * @note Requires 0x2000-0x18000 bytes in arbitrary VRAM Bank (No cycles) + /** @brief 3d rotation with pitch and yaw, but no roll (scale modified per line) + * @note Requires 0x2000-0x18000 bytes in arbitrary VRAM Bank (No cycle slots required) */ TwoAxis, - /** @brief Full 3d rotation with pitch, yaw and roll (modified per pixel) - * @note Requires 0x2000-0x18000 bytes in Reserved VRAM bank (8 cycles) + /** @brief Full 3d rotation with pitch, yaw and roll (scale modified per pixel) + * @note Requires 0x2000-0x18000 bytes in Reserved VRAM bank (all 8 cycle slots required) */ ThreeAxis, }; + /** @brief Options for treating display of rotation parameters outside of the + * main tilemap/bitmap area. + * @details when 3d rotation and scaling is simulated, some perspectives may display + * areas on screen that extend beyond the 4x4 plane area defined by the tilemap data. + * Use these options with RBG0::SetOverDisplayA/B to specify what to display in + * those areas. + */ + enum class OverPattern + { + + /** @brief Screen areas outside the map repeat the full tilemap pattern (Default) + */ + RepeatMap, + + /** @brief Screen areas outside the map repeat a single selectable tile from the map's tileset. + * @note Not available in Bitmap Mode + */ + RepeatTile, + + /** @brief Screen areas outside the map area are treated as transparent pixels + */ + Transparent, + + /** @brief Areas outside a 512x512 square centered at coordintate [256,256] + * are made transparent regardless of the underlying map area + */ + Transparent512x512, + + }; + + /** @brief Options for switching between the 2 Rotation parameters available for RBG0 display + */ + enum class SwitchMode + { + /** @brief Only display Primary Tilemap and rotation params + */ + OnlyPrimary = 0, + + /** @brief Only display Secondary Tilemap and rotation params + */ + OnlySecondary = 1, + + /** @brief Switch RBG0 Tilemap display based on perspective of Tilemap A + * @details In regions of the screen beyond the Primary Parameter's simulated 'horizon'*, + * the Secondary Parameter will be displayed instead. + * @note -*(More technically, any screen coordinate where the scaling coefficient + * read for the primary parameter has its high bit set to 1 will display Parameter B data instead). + * @note - Only Parameter A can display 3 Axis (Per Dot) Rotation in this mode. + */ + PerspectiveSwitch, + + /** @brief Switch RBG0 rotation display based on a VDP2 window + * @details Rotation A displays in regions inside the selected VDP2 window While + * Rotation B displays outside the window + * @note - This is the only avaiable mode where Primary and Secondary Parameters can + * Simultaneously display 3 Axis (Per Dot) Rotation. + */ + WindowSwitch, + + }; + + /** @brief Used to select between the 2 Rotation Parameters on RBG0: Primary or Secondary. + * Primary rotation parameter controls the display of the Primary Tilemap, Secondary Parameter controls + * display of the Secondary Tilemap. + */ + enum class RotationParameter : uint16_t + { + /** @brief Select Primary Rotation Parameter (RA) + */ + Primary = RA, + /** @brief Select Secondary Rotation Parameter (RB) + */ + Secondary = RB, + }; + /** @brief RBG0 interface * @details Rotating Background Scroll 0: * -Available color depths: Paletted16, Paletted256, RBG555 - * -Available modes: Tilemap, Bitmap + * -Available image modes: Tilemap, Bitmap * -Available features: Scrolling, Scaling, Rotation, - * -Coefficient table allows per line and per pixel scaling - * to simulate perspective + * -Reading a coefficient table from VRAM allows per-line/per-pixel scaling + * to simulate a 3D plane. + * -simulate up to 2 planes using separate rotation parameters and tilemaps */ class RBG0 : public BmpScreen { + + private: + /** @brief Initializes the Tilemap settings for Secondary Tilemap on Rotation parameter B + * @param info Tilemap info to initialize with + * @note Initialization fails if the tilemap's data format does not match the primary tilemap + */ + inline static bool InitB(SRL::Tilemap::TilemapInfo info) + { + if(info.MapMode!= RBG0::Info.MapMode || info.SGLColorMode()!=RBG0::Info.SGLColorMode()||info.CharSize!=RBG0::Info.CharSize) + { + SRL::Debug::Assert("RBG0 Secondary Tilemap Init Failed: Format does not match primary tilemap"); + return false; + } + slPlaneRB(info.PlaneSize); + sl1MapRB(MapAddressRB); + return true; + } + + /** @brief Function to Load tilemap to VRAM for use with Rotation Parameter RB, called in Overloads of Load tilemap. + * Because RB data can not be loaded without RA data present, This is never explicitly called alone by user. Instead + * it is called within RBG0's LoadTilemap overloads which allow loading both tilemaps at once. + */ + inline static void LoadTilemapB(SRL::Tilemap::ITilemap& tilemap, VDP2::SwitchMode mode = VDP2::SwitchMode::PerspectiveSwitch, bool LoadPalette = true) + { + SRL::Tilemap::TilemapInfo info = tilemap.GetInfo(); + + uint32_t page_sz = 0x800; + uint32_t sz = (info.MapHeight * info.MapWidth) << 1; + if (info.CharSize == CHAR_SIZE_1x1) page_sz <<= 2; + if (info.MapMode == PNB_2WORD) + { + sz <<= 1; + page_sz <<= 1; + } + + if (info.PlaneSize == PL_SIZE_2x2) page_sz <<= 2; + else if (info.PlaneSize == PL_SIZE_2x1) page_sz <<= 1; + + if(MapAddressRB<(void*)VDP2_VRAM_A0) + { + MapAddressRB = VRAM::Allocate(sz, page_sz, VramBank::A0, 0); + MapAllocSizeB = sz; + } + + if(CellAddressRB<(void*)VDP2_VRAM_A0) + { + CellAddressRB = VRAM::Allocate(info.CellByteSize, 32, VramBank::A1, 0); + CellAllocSizeB = info.CellByteSize; + } + + if(MapAddressRB==nullptr||CellAddressRB==nullptr||MapAllocSizeB::LoadTilemap; + /** @brief VRAM Address of RBG0 Coefficient table */ - inline static void* KtableAddress = (void*)(VDP2_VRAM_A0 - 1); - + inline static void* KtableAddress = (void*)(VDP2_VRAM_A0 - 1); + /** @brief VRAM Address of RBG0 Coefficient table B + */ + inline static void* KtableAddressB = (void*)(VDP2_VRAM_A0 - 1); + /** @brief VRAM Address of TilemapB map data + */ + inline static void* MapAddressRB = (void*)(VDP2_VRAM_A0 - 1); + /** @brief VRAM Address of TilemapB cell data + */ + inline static void* CellAddressRB = (void*)(VDP2_VRAM_A0 - 1); + /** @brief Size of Map B allocation + */ + inline static uint32_t MapAllocSizeB; + /** @brief Size of Cell B allocation + */ + inline static int32_t CellAllocSizeB; + /* @brief The Palette handler for LoadTilemapB + */ + inline static CRAM::Palette TilePaletteB = CRAM::Palette(); + + + void* SetCellAddress(void* address, int size, VDP2::RotationParameter param =VDP2::RotationParameter::Primary) + { + if(param==VDP2::RotationParameter::Primary) + { + RBG0::CellAddress = address; + RBG0::CellAllocSize = size; + } + else + { + RBG0::CellAddressRB = address; + RBG0::CellAllocSizeB = size; + } + return address; + } + /** @brief Initializes the ScrollScreen's tilemap specifications + * @details Initailization is performed automatically when using the built in + * LoadTilemap functions. This function is only required when performing custom loading + * routines. Ensure that VRAM for Cell and Map data has already been allocated before calling. * @param info Tile map info + * @note This function initializes both rotation parameters using the same + * source tilemap. To use a secondary tilemap in RB, use the respective + * overloads */ inline static void Init(SRL::Tilemap::TilemapInfo& info) { slRparaMode(RA); slOverRA(0); + slOverRB(0); slCharRbg0(info.SGLColorMode(), info.CharSize); slPageRbg0(RBG0::CellAddress, (void*)RBG0::TilePalette.GetData(), info.MapMode); slPlaneRA(info.PlaneSize); + slPlaneRB(info.PlaneSize); sl1MapRA(RBG0::MapAddress); + sl1MapRB(RBG0::MapAddress); } + /** @brief Initializes the ScrollScreen's bitmap specifications + * @details Initailization is performed automatically when using the built in + * LoadBitmap function. This function is only required when performing custom loading + * routines. Ensure that VRAM has already been allocated before calling. * @param info bitmap info */ static void Init(SRL::Bitmap::BitmapInfo& info) @@ -1180,7 +1486,8 @@ namespace SRL slOverRA(0); uint16_t sglFlag = info.Height<=256? 0x2 : 0x6; sglFlag |= info.Width<= 512 ? 0 : 1<<3; - slPageRbg0(RBG0::CellAddress, (void*)RBG0::TilePalette.GetData(), RBG0::Info.MapMode); + //VDP2_RAMCTL &= 0xff00; + slPageRbg0(RBG0::CellAddress, (void*)RBG0::TilePalette.GetData(), RBG0::Info.MapMode);//this is required to reserve the VRAM bank slBitMapRbg0(GetSGLColorMode(info.ColorMode), sglFlag, RBG0::CellAddress); if(info.ColorMode==SRL::CRAM::TextureColorMode::Paletted16) { @@ -1188,94 +1495,252 @@ namespace SRL } else slBMPaletteRbg0(RBG0::TilePalette.GetId()); } - /** @brief Select what type of rotation to use for the rotating scroll (Call before Loading RBG0) - * @param mode The RotationMode to use for this scroll - * @param vblank Chose to update VRAM at VBLANK to reduce amount of coefficient - * data required for rotation of a plane (default = true) - * @note when 2 or 3 axis rotation is Selected, VRAM will be allocated to store - * necessary coefficient data. If Vblank is set false, all coefficients will be - * statically stored in VRAM as a 0x18000 byte table. If Vblank is set true, only - * the coefficients necessary for the current frame will be dynamically written - * to VRAM at Vblank, reducing VRAM footprint to 0x2000 bytes per - * rotation parameter but increasing required Vblank overhead. + + /** @brief Overload initializes Primary and Secondary rotation parameters to separate source tilemaps + * @details Initailization is performed automatically when using the built in + * LoadTilemap functions. This function is only required when performing custom loading + * routines. Ensure that VRAM for Cell and Map data has already been allocated before calling. + * @note Initialization for Secondary fails if it does not share the same configuration as Primary for + * color depth, tile size, and map data type. + * @param infoA Tilemap info of primary tilemap to initialize + * @param infoB Tilemap info of secondary tilemap to initialize + */ + static void Init(SRL::Tilemap::TilemapInfo& infoA,SRL::Tilemap::TilemapInfo& infoB) + { + RBG0::Init(infoA); + RBG0::InitB(infoB); + } + + /** @brief Simultaneously Configures the desired rotation mode and loads primary tilemap + * @details Overload to load the primary tilemap and configure its rotation + * with one function. Calls SetRotationMode() followed by LoadTilemap(). + * @param tilemap The tilemap to load + * @param mode The rotation mode to configure for the tilemap (See SetRotationMode for details) + * @param LoadPalette (optional) enable/disable auto loading of palette data (default = true) + */ + inline static void LoadTilemap(SRL::Tilemap::ITilemap& tilemap,VDP2::RotationMode mode, bool LoadPalette = true) + { + SetRotationMode(mode); + LoadTilemap(tilemap,LoadPalette); + } + + /** @brief Load and configure both a Primary and Secondary Tilemap + * @details Overload to load and configure both primary and secondary tilemaps on RBG0. + * The SwitchMode will be initialized to UsePerspective. Use SetSwitchMode() after loading + * to change the setting if desired. + * @param tilemapA The tilemap to load to Primary Tilemap (A) + * @param tilemapB The tilemap to load to Secondary Tilemap (B) + * @param modeA The rotation mode to configure for primary map (RA) + * @param modeB The rotation mode to configure for secondary map (RB) + * @param LoadPalette (optional) set false to disable auto loading of palette data (default = true) + * @note -Due to shared registers, the Secondary Tilemap must have the same underlying data format as the + * Primary Tilemap (color depth, tile size, map data type). Furthermore its data must be able to fit within the same + * Reserved VRAM banks as the corresponding primary data ((celDataA + celDataB) <= 0x20000 bytes and (mapDataA+mapDataB)<=0x20000 bytes). + * @note -See VDP2::Switchmode documentation for limits on rotation modes for A and B under various conditions. + */ + inline static void LoadTilemap(SRL::Tilemap::ITilemap& tilemapA,SRL::Tilemap::ITilemap& tilemapB, VDP2::RotationMode modeA,VDP2::RotationMode modeB, bool LoadPalette = true) + { + SetRotationMode(modeA,modeB,false); + LoadTilemap(tilemapA,LoadPalette); + LoadTilemapB(tilemapB); + } + + /** @brief Sets How screen regions outside the tilemap area are displayed by the rotation parameters + * @param param The Tilemap/Rotation Parameter that is being set(primary or secondary) + * @param mode the display mode to select + * @param tileIndex (Optional) The tile index to display in exterior regions if RepeatTile is + * selected as mode (defaults to tile 0 if not specified) + * @note See OverPattern documentatioin for descriptions of available modes + */ + inline static void SetOverDisplay(VDP2::RotationParameter param, VDP2::OverPattern mode, uint16_t tileIndex = 0) + { + if(param == VDP2::RotationParameter::Primary) + { + slOverPatRA(tileIndex); + slOverRA((uint16_t)mode); + } + else + { + slOverPatRB(tileIndex); + slOverRB((uint16_t)mode); + } + } + + /** @brief Sets the condition for switching between display of Primary and Secondary parameters/Tilemaps on screen. + * @param mode the display mode to select + * @note See VDP2::SwitchMode documentation for description of available modes + * @note If a mode is selected that includes display of Secondary Parameter (RB) when no + * secondary tilemap has been loaded, it will use the same + * source tilemap as the primary parameter. + */ + inline static void SetParameterMode(SwitchMode mode) + { + slRparaMode((uint16_t)mode); + } + + /** @brief Select what type of rotation to use for the rotating scroll. + * @details This initializes both Primary and Secondary parameters to the same mode. + * Use the overload to initialize separate modes for each. + * @param mode The RotationMode to use for RBG0 + * @param vblank (Optional) Chose to update VRAM at VBLANK to reduce amount of stored coefficient + * data required (default = true). + * When 2 or 3 axis rotation is selected, VRAM is allocated to store the + * required scaling coefficients. If vblank is set false, all possible coefficients will be + * statically stored in VRAM as a 0x18000 byte table. If vblank is set true, + * select coefficients for the next frame's perspective will be dynamically written + * to VRAM during Vblank, reducing the VRAM footprint to 0x2000 bytes per + * rotation parameter. If this transfer can not complete within the Vblank window + * screen tearing may be visible in the plane. */ inline static void SetRotationMode(VDP2::RotationMode mode, bool vblank = true) { - //slRparaInitSet((ROTSCROLL*)(VDP2_VRAM_B1 + 0x1ff00)); + //Allocate coeficient tables if necessary for either param: + uint16_t kflag =0; + if(mode!=VDP2::RotationMode::OneAxis) + { + if(vblank==true) + { + VDP2::RBG0::KtableAddress = VDP2::VRAM::Allocate(0x4000, 0x20000, VDP2::VramBank::B0, 0); + VDP2::RBG0::KtableAddressB =(void*)((uint32_t)VDP2::RBG0::KtableAddress+0x2000); + } + else + { + VDP2::RBG0::KtableAddress = VDP2::VRAM::Allocate(0x18000, 0x20000, VDP2::VramBank::B0, 0); + VDP2::RBG0::KtableAddressB = VDP2::RBG0::KtableAddress; + slMakeKtable(VDP2::RBG0::KtableAddress); + kflag = K_FIX; + } + } + //set mode of params A and B switch (mode) { case RotationMode::OneAxis: slKtableRA(nullptr, K_OFF); - //VDP2_RAMCTL &= 0xffcf; // Bypasses problem in slKtableRA: this never resets if K_DOT was previously specified + slKtableRB(nullptr, K_OFF); break; - case RotationMode::TwoAxis: - if (!vblank) + case RotationMode::TwoAxis: + slKtableRA((void*)VDP2::RBG0::KtableAddress, kflag|K_LINE | K_2WORD | K_ON); + slKtableRB((void*)VDP2::RBG0::KtableAddressB, kflag|K_LINE | K_2WORD | K_ON); + break; + + case RotationMode::ThreeAxis: + slKtableRA((void*)VDP2::RBG0::KtableAddress, kflag | K_DOT | K_2WORD | K_ON); + slKtableRB((void*)VDP2::RBG0::KtableAddressB, kflag | K_DOT | K_2WORD | K_ON); + break; + } + } + + /** @brief Overload to select separate rotation modes for both the primary and secondary + * rotating planes. + * @param modeA The RotationMode to use for primary tilemap + * @param modeB The RotationMode to use for secondary tilemap + * @param vblank (Optional) Chose to update VRAM at VBLANK to reduce amount of stored coefficient + * data required (default = true). + * When 2 or 3 axis rotation is selected, VRAM is allocated to store the + * required scaling coefficients. If vblank is set false, all possible coefficients will be + * statically stored in VRAM as a 0x18000 byte table. If vblank is set true, + * select coefficients for the next frame's perspective will be dynamically written + * to VRAM during Vblank, reducing the VRAM footprint to 0x2000 bytes per + * rotation parameter. If this transfer can not complete within the Vblank window + * screen tearing may be visible in the plane. + */ + inline static void SetRotationMode(VDP2::RotationMode modeA, VDP2::RotationMode modeB, bool vblank = true) + { + uint16_t kflag =0; + //Allocate coeficient tables if necessary for either param: + if(modeA!=VDP2::RotationMode::OneAxis||modeB!=VDP2::RotationMode::OneAxis) + { + if(vblank==true) { - VDP2::RBG0::KtableAddress = VDP2::VRAM::Allocate(0x18000, 0x20000, VDP2::VramBank::B0, 0); - slMakeKtable((void*)VDP2::RBG0::KtableAddress); - slKtableRA((void*)VDP2::RBG0::KtableAddress, K_FIX | K_LINE | K_2WORD | K_ON); + VDP2::RBG0::KtableAddress = VDP2::VRAM::Allocate(0x4000, 0x20000, VDP2::VramBank::B0, 0); + VDP2::RBG0::KtableAddressB = (void*)((uint32_t)VDP2::RBG0::KtableAddress+0x2000); } else { - VDP2::RBG0::KtableAddress = VDP2::VRAM::Allocate(0x2000, 0x20000, VDP2::VramBank::B0, 0); - slKtableRA((void*)VDP2::RBG0::KtableAddress, K_LINE | K_2WORD | K_ON); + VDP2::RBG0::KtableAddress = VDP2::VRAM::Allocate(0x18000, 0x20000, VDP2::VramBank::B0, 0); + VDP2::RBG0::KtableAddressB = VDP2::RBG0::KtableAddress; + slMakeKtable(VDP2::RBG0::KtableAddress); + kflag = K_FIX; } + } - //VDP2_RAMCTL &= 0xffcf;//Bypasses problem in slKtableRA: this never resets if K_DOT was previously specified + //set mode of param B + switch (modeB) + { + case RotationMode::OneAxis: + slKtableRB(nullptr, K_OFF); break; - case RotationMode::ThreeAxis: - if (!vblank) - { - VDP2::RBG0::KtableAddress = VDP2::VRAM::Allocate(0x18000, 0x20000, VDP2::VramBank::B0, 8); - slMakeKtable((void*)VDP2::RBG0::KtableAddress); - slKtableRA((void*)VDP2::RBG0::KtableAddress, K_FIX | K_DOT | K_2WORD | K_ON); - } - else - { - VDP2::RBG0::KtableAddress = VDP2::VRAM::Allocate(0x2000, 0x20000, VDP2::VramBank::B0, 8); - slKtableRA((void*)VDP2::RBG0::KtableAddress, K_DOT | K_2WORD | K_ON); - } + case RotationMode::TwoAxis: + slKtableRB((void*)VDP2::RBG0::KtableAddressB, kflag |K_LINE | K_2WORD | K_ON); + break; + case RotationMode::ThreeAxis: + slKtableRB((void*)VDP2::RBG0::KtableAddressB, kflag | K_DOT | K_2WORD | K_ON); + break; + } + //set mode of param A + switch (modeA) + { + case RotationMode::OneAxis: + slKtableRA(nullptr, K_OFF); + break; + + case RotationMode::TwoAxis: + slKtableRA((void*)VDP2::RBG0::KtableAddress, kflag|K_LINE | K_2WORD | K_ON); + break; + + case RotationMode::ThreeAxis: + slKtableRA((void*)VDP2::RBG0::KtableAddress, kflag| K_DOT | K_2WORD | K_ON); break; } } - /** @brief Writes the current matrix transform to RBG0RA Rotation parameters - * to update its position and perspective + /** @brief Writes the current matrix transform to RBG0 rotation parameters + * to update its perspective + * @param param selects which rotation parameter to write the matrix to (optional- defaults to Primary) */ - inline static void SetCurrentTransform() + inline static void SetCurrentTransform(VDP2::RotationParameter param = VDP2::RotationParameter::Primary) { - slCurRpara(RA); + slCurRpara((uint16_t)param); slPushMatrix(); { slScrMatConv(); slScrMatSet(); } slPopMatrix(); + slCurRpara(RA); } /** @brief Sets the plane of Tilemap Data to be displayed * @param a,b,c,d Page Table addresses of the planes to display - * @note Multi Plane Maps are not supported yet for RBG0, only plane a is used + * @note Multi Plane maps must be set with the 16 plane overload of this function */ static void SetPlanes(void* a, void* b, void* c, void* d) { sl1MapRA(a); + sl1MapRB(b); } - /** @brief Sets the plane of Tilemap Data to be displayed with 16 planes - * @param layout 4x4 array of uint8_t indices representing the index of each plane in the map layout - * @note Unlike NBG scrolls RBG0 only loads with the default tiling of 1 plane. Use this - * function after loading to set the arrangement of multi plane tilemaps within a 4x4 grid. + /** @brief Sets the layout of Tilemaps comprised of multiple planes from a 4x4 grid of plane indices + * @details Unlike NBG scrolls RBG0 only loads with the default repetition of 1 plane of tilemap data. Use this + * function after loading to set the layout planes of larger multi-plane tilemaps within a 4x4 grid: + * |a,b,c,d| + * |e,f,g,h| + * |i,j,k,l| + * |m,n,o,p| + * @param layout 4x4 array of uint8_t indices representing the index of each plane in the map data + * (index 0 = first plane of the map data, increments by 1 per plane of map data stored) + * @param param The Rotation parameter whose map is being set: primary or secondary (defaults to primary) * @note No check is performed to ensure the indecies entered are within the bounds of * the scroll's map data. Specifying indices larger than the number of planes loaded * will result in the diplay of garbage data in those portions of the map */ - static void SetPlanes(const uint8_t layout[4][4]) + static void SetPlanes(const uint8_t layout[4][4], VDP2::RotationParameter param = VDP2::RotationParameter::Primary) { + uint32_t offset = (param==VDP2::RotationParameter::Primary) ? ((uint32_t)RBG0::MapAddress & 0x1ffff)>>11 : ((uint32_t)RBG0::MapAddressRB & 0x1ffff)>>11; uint8_t sz = (VDP2::RBG0::Info.CharSize==CHAR_SIZE_1x1) ? 4:1; uint8_t sLayout[4][4] = {}; if (VDP2::RBG0::Info.MapMode == PNB_2WORD) sz <<= 1; @@ -1283,12 +1748,12 @@ namespace SRL else if (VDP2::RBG0::Info.PlaneSize == PL_SIZE_2x1)sz <<= 1; for (size_t i = 0; i < 4; ++i) { for (size_t j = 0; j < 4; ++j) { - sLayout[i][j] = layout[i][j] * sz; + sLayout[i][j] = (layout[i][j] * sz)+(uint8_t)offset; } } - sl16MapRA((uint8_t*)sLayout); + if(param==VDP2::RotationParameter::Primary)sl16MapRA((uint8_t*)sLayout); + else sl16MapRB((uint8_t*)sLayout); } - }; /** @brief Sprite Color Calculation Conditions (See SpriteLayer::SetColorCondition() for details) @@ -1319,11 +1784,11 @@ namespace SRL Bank3 = scnSPR3, Bank4 = scnSPR4, Bank5 = scnSPR5, - Bank6 = scnSPR6, + Bank6 = scnSPR6, Bank7 = scnSPR7, }; - /** @brief Interface to control VDP2 settings for the Sprite Layer (data from VDP1 framebuffer), + /** @brief Interface to control VDP2 settings for the Sprite Layer (data from the VDP1 framebuffer), * such as Display priority and VDP2 color calculation) */ class SpriteLayer @@ -1349,13 +1814,13 @@ namespace SRL * @details This Function takes the opacity specified as a fixed point value and converts it to * one of the 32 color calculation ratios that the system can use (value is floored to the nearest ratio). * It then sets the ratio in the specified sprite cc register (cc register 0 if not specified) - * @note Color ratios only apply to highest priority pixels in frame - * @note When Color Calc is ON, max opacity is ~(0.97). Fully opaque sprites must select with color condition - * @note When ColorCalcMode is set to UseColorAddition, The Opacity levels are ignored and Color addition is applied - * to all sprites whose priority meets the color condition (see SpriteLayer::SetColorCondition() for details) - * @note RGB sprites always use the opacity set in CC register[bank0] - * @note Does NOT turn color calc ON or OFF for the Sprite Layer(use SpriteLayer::ColorCalcON,OFF()) - * @note available cc registers vary by Palette code config- default allows all 8 banks + * @note -Color ratios only apply to highest priority pixels in frame + * @note -When Color Calc is ON, max opacity is ~(0.97). Fully opaque sprites must be excluded by the color condition. + * @note -When ColorCalcMode is set to UseColorAddition, The Opacity levels are ignored + * and Color addition is applied to all sprites whose priority meets the color condition (see SpriteLayer::SetColorCondition() for details) + * @note -RGB sprites always use the opacity set in CC register[bank0] + * @note -Does NOT turn color calc ON or OFF for the Sprite Layer(use SpriteLayer::ColorCalcON,OFF()) + * @note -available cc registers vary by Palette code config- default allows selecting all 8 banks * @param opacity Fxp decimal value between 0.0 and 1.0 representing pixel opacity of the cc register * @param bank (optional) which of the 8 CC registers to Set the opacity in (defaults to 0) */ @@ -1373,13 +1838,13 @@ namespace SRL /** @brief Set the priority Layers That sprites can select from in PR registers * @details This function sets one of the 8 priority registers that a Palette sprite can reference (default bank0) - * @note available registers vary by Palette code config- default can only pull from bank0 and bank1 - * @note RGB sprites always use the priority from bank0 - * @note During VDP2 init, priority bank0 and bank1 are initialized to Layer3 and Layer4 respectively - * @note Changing these priorities will result in differing behavior for sprite color calculation - * (See SpriteLayer::SetColorCondition() for more details) + * @note -available registers vary by Palette code config- default can only pull from bank0 and bank1 + * @note -RGB sprites always use the priority from bank0 + * @note -During VDP2 init, priority bank0 and bank1 are initialized to Layer3 and Layer4 respectively + * @note -Changing these priorities will result in differing behavior for sprite color calculation + * (See documentation of SpriteLayer::SetColorCondition() for more details) * @param pr enum VDP2::Priority Layer - * @param bank (optional) enum VDP2::SpriteBank designating which priority bank to write to + * @param bank (optional) enum VDP2::SpriteBank designating which priority bank to write to (default = Bank0) */ inline static void SetPriority(SRL::VDP2::Priority pr, VDP2::SpriteBank bank = VDP2::SpriteBank::Bank0) { @@ -1387,12 +1852,12 @@ namespace SRL } /** @brief Set conditions under which VDP2 color calculation is performed on sprites based on their priority. - * @details Sets up the condition that allows only select sprites to receive Half Transparent + * @details Sets up a condition that allows only select sprites to receive Half Transparent * color calculation with VDP2 layers. To make a sprite fully opaque, selectively turn color calculation off for it by - * assigning it to use a Priority Bank containing a priority layer that does not satisfy the Color Condition. - * The default VDP2 initialization uses ColorCondition::PriorityEquals Priority::Layer4, - * with SpriteBank0 set to Layer3 and SpriteBank1 set to Layer4. With this config RGB sprites receive no VDP2 - * color calculation, while Palette sprites only receive color calculation when they select priority from SpriteBank1 + * assigning it to use a Priority Bank containing a layer that does not satisfy the chosen Color Condition. + * The default VDP2 initialization uses [ColorCondition::PriorityEquals] [Priority::Layer4], + * with Priority Bank0 set to Layer3 and Priority Bank1 set to Layer4. With this config RGB sprites receive no VDP2 + * color calculation, while Palette sprites only receive color calculation when they select priority from Bank1 * @param Condition The type of condition that VDP2 Color Calculation will follow. * @param TestValue The Layer that a sprite's priority will be tested against in the condition. */ @@ -1404,56 +1869,65 @@ namespace SRL }; /** @brief Clear all VDP2 VRAM allocations and reset all Scroll Screen VRAM References, as well - * as all CRAM allocations associated with VDP2 Scroll Screens - * @note, When Loading a new set of Data and Configurations for Scroll Screens with auto allocation, Call this first - * to ensure old data is freed + * as all CRAM allocations associated with VDP2 Scroll Screens if desired. + * @note When Loading a new set of Data and Configurations for Scroll Screens with auto allocation, Call this first + * to ensure old data is freed + * @param FreePalettes (optional: default = true) additionally free all CRAM pallets currently registered to ScrollScreens */ - inline static void ClearVRAM() + inline static void ClearVRAM(bool FreePalettes = true) { //reset ScrollScreen VRAM References - VDP2::NBG0::MapAddress = (void*)(VDP2_VRAM_A0 - 1); - VDP2::NBG0::CellAddress = (void*)(VDP2_VRAM_A0 - 1); - VDP2::NBG0::LineAddress = (void*)(VDP2_VRAM_A0 - 1); - - if (VDP2::NBG0::TilePalette.GetData()) + if((int)NBG0::MapAddress<(VDP2_VRAM_B1+0x18000)) { - SRL::CRAM::SetBankUsedState(VDP2::NBG0::TilePalette.GetId(), VDP2::RBG0::TilePalette.GetMode(), false); - VDP2::NBG0::TilePalette = SRL::CRAM::Palette(); + VDP2::NBG0::MapAddress = (void*)(VDP2_VRAM_A0 - 1); + VDP2::NBG0::CellAddress = (void*)(VDP2_VRAM_A0 - 1); + VDP2::NBG0::LineAddress = (void*)(VDP2_VRAM_A0 - 1); + if (FreePalettes && VDP2::NBG0::TilePalette.GetData()) + { + SRL::CRAM::SetBankUsedState(VDP2::NBG0::TilePalette.GetId(), VDP2::RBG0::TilePalette.GetMode(), false); + VDP2::NBG0::TilePalette = SRL::CRAM::Palette(); + } } - VDP2::NBG1::MapAddress = (void*)(VDP2_VRAM_A0 - 1); - VDP2::NBG1::CellAddress = (void*)(VDP2_VRAM_A0 - 1); - VDP2::NBG1::LineAddress = (void*)(VDP2_VRAM_A0 - 1); - - if (VDP2::NBG1::TilePalette.GetData()) + if((int)NBG1::MapAddress<(VDP2_VRAM_B1+0x18000)) { - SRL::CRAM::SetBankUsedState(VDP2::NBG1::TilePalette.GetId(), VDP2::RBG0::TilePalette.GetMode(), false); - VDP2::NBG1::TilePalette = SRL::CRAM::Palette(); + VDP2::NBG1::MapAddress = (void*)(VDP2_VRAM_A0 - 1); + VDP2::NBG1::CellAddress = (void*)(VDP2_VRAM_A0 - 1); + VDP2::NBG1::LineAddress = (void*)(VDP2_VRAM_A0 - 1); + if (FreePalettes && VDP2::NBG1::TilePalette.GetData()) + { + SRL::CRAM::SetBankUsedState(VDP2::NBG1::TilePalette.GetId(), VDP2::RBG0::TilePalette.GetMode(), false); + VDP2::NBG1::TilePalette = SRL::CRAM::Palette(); + } } - VDP2::NBG2::MapAddress = (void*)(VDP2_VRAM_A0 - 1); - VDP2::NBG2::CellAddress = (void*)(VDP2_VRAM_A0 - 1); - - if (VDP2::NBG2::TilePalette.GetData()) + if((int)NBG2::MapAddress<(VDP2_VRAM_B1+0x18000)) { - SRL::CRAM::SetBankUsedState(VDP2::NBG2::TilePalette.GetId(), VDP2::RBG0::TilePalette.GetMode(), false); - VDP2::NBG2::TilePalette = SRL::CRAM::Palette(); + VDP2::NBG2::MapAddress = (void*)(VDP2_VRAM_A0 - 1); + VDP2::NBG2::CellAddress = (void*)(VDP2_VRAM_A0 - 1); + if (FreePalettes && VDP2::NBG2::TilePalette.GetData()) + { + SRL::CRAM::SetBankUsedState(VDP2::NBG2::TilePalette.GetId(), VDP2::RBG0::TilePalette.GetMode(), false); + VDP2::NBG2::TilePalette = SRL::CRAM::Palette(); + } } - VDP2::NBG3::MapAddress = (void*)(VDP2_VRAM_A0 - 1); - VDP2::NBG3::CellAddress = (void*)(VDP2_VRAM_A0 - 1); - - if (VDP2::NBG3::TilePalette.GetData()) + if((int)NBG3::MapAddress<(VDP2_VRAM_B1+0x18000)) { - SRL::CRAM::SetBankUsedState(VDP2::NBG3::TilePalette.GetId(), VDP2::RBG0::TilePalette.GetMode(), false); - VDP2::NBG3::TilePalette = SRL::CRAM::Palette(); + VDP2::NBG3::MapAddress = (void*)(VDP2_VRAM_A0 - 1); + VDP2::NBG3::CellAddress = (void*)(VDP2_VRAM_A0 - 1); + if (FreePalettes && VDP2::NBG3::TilePalette.GetData()) + { + SRL::CRAM::SetBankUsedState(VDP2::NBG3::TilePalette.GetId(), VDP2::RBG0::TilePalette.GetMode(), false); + VDP2::NBG3::TilePalette = SRL::CRAM::Palette(); + } } VDP2::RBG0::MapAddress = (void*)(VDP2_VRAM_A0 - 1); VDP2::RBG0::CellAddress = (void*)(VDP2_VRAM_A0 - 1); VDP2::RBG0::KtableAddress = (void*)(VDP2_VRAM_A0 - 1); - if (VDP2::RBG0::TilePalette.GetData()) + if (FreePalettes && VDP2::RBG0::TilePalette.GetData()) { SRL::CRAM::SetBankUsedState(VDP2::RBG0::TilePalette.GetId(), VDP2::RBG0::TilePalette.GetMode(), false); VDP2::RBG0::TilePalette = SRL::CRAM::Palette(); @@ -1468,8 +1942,10 @@ namespace SRL } // Clear Rotation control bits of VDP2_RAMCTL VDP2_RAMCTL &= 0xff00; - //leave cylces reserved for ASCII - VDP2::VRAM::bankCycles[3] = 1; + //Clear MapBank Flags: + VDP2::VRAM::MapBankA0 = VDP2::VRAM::MapBankB0 = false; + //keep 2 cycle slots reserved for ASCII + VDP2::VRAM::bankCycles[3] = 2; } /** @brief Set the back color @@ -1526,14 +2002,17 @@ namespace SRL SRL::VDP2::NBG3::ScrollEnable(); SRL::VDP2::NBG0::ScrollDisable(); // We don't want this on by default anymore // Fix param table at top of VRAM outside range of allocator - now user calls to slPerspective will always update here: + SRL::VDP2::SpriteLayer::SetPriority(VDP2::Priority::Layer3,VDP2::SpriteBank::Bank0); + SRL::VDP2::SpriteLayer::SetPriority(VDP2::Priority::Layer4,VDP2::SpriteBank::Bank0); slRparaInitSet((ROTSCROLL*)(VDP2_VRAM_B1 + 0x1ff00)); + VDP2_RAMCTL&=0xff00; } /** @brief Data structure of a VDP2 color offset to be set in Offset A or Offset B - * @details The offset data that will be set is a signed 9 bit value per color channel. + * @details The offset data is a signed 9 bit value per color channel. * The valid range of inputs is -255 to +255. The sign determines whether the color offset - * is additive or subtractive. Values outside the range will be clamped on initialization. - * See SetColorOffsetA and SetColorOffsetB for more details. + * is additive or subtractive on that channel. Values outside the range will be clamped on initialization. + * See SetColorOffsetA and SetColorOffsetB for more details on setting up a VDP2 color offset. */ struct ColorOffset { @@ -1640,7 +2119,7 @@ namespace SRL slColOffsetB(offset.Red, offset.Green, offset.Blue); } - /** @brief Basic Options for behavior of VDP2 Half Transparent Color Calculation + /** @brief Options for behavior of VDP2 Half Transparent Color Calculation */ enum class ColorCalcMode : uint16_t { @@ -1657,7 +2136,7 @@ namespace SRL UseColorAddition = 0x100, }; - /** @brief Sets VDP2 Half Transparent Color Calculation Mode (only one mode can be used at once) + /** @brief Sets VDP2 Half Transparent Color Calculation Mode (only one mode can be used at a time) * @param mode The VDP2 color calculation mode to use * @param extend Designates whether to extend color calculation to the top 3 Layer Priories instead of just top 2 * @note Extended color calculation has many restrictions detailed in VDP2 users manual- not all color modes can support