diff --git a/build-image.bat b/build-image.bat new file mode 100644 index 0000000..343d3fb --- /dev/null +++ b/build-image.bat @@ -0,0 +1,18 @@ +echo off + +REM Copy all of the assets into the ProDOS image for emulator testing +REM +REM Pass the path of the Cadius tool as the first argument (%1) + +set CADIUS="%1" +set IMAGE=".\\emu\\Target.2mg" +set FOLDER="/GTEDEV/Toolbox" + +REM Cadius does not overwrite files, so clear the root folder first +%CADIUS% DELETEFOLDER %IMAGE% %FOLDER% +%CADIUS% CREATEFOLDER %IMAGE% %FOLDER% + +REM Now copy files and folders as needed +%CADIUS% ADDFILE %IMAGE% %FOLDER% .\src\GTETool + +REM Copy in the image assets diff --git a/demos/tool/App.Main.s b/demos/tool/App.Main.s new file mode 100644 index 0000000..7f89d59 --- /dev/null +++ b/demos/tool/App.Main.s @@ -0,0 +1,83 @@ + REL + DSK MAINSEG + + use Locator.Macs + use Load.Macs + use Mem.Macs + use Misc.Macs + use Util.Macs + use EDS.GSOS.Macs + +_GTEStartUp MAC + UserTool $02A0 + <<< + +; Typical init + phk + plb + + jsr ToolStartUp ; Start up the basic tools: Locator, Memory Manager, Misc + jsr GTEStartUp + + _QuitGS qtRec + + bcs Fatal +Fatal brk $00 +qtRec adrl $0000 + da $00 + +ToolStartUp + _TLStartUp ; normal tool initialization + pha + _MMStartUp + pla + sta MasterId ; our master handle references the memory allocated to us + ora #$0100 ; set auxID = $01 (valid values $01-0f) + sta UserId ; any memory we request must use our own id + + _MTStartUp + rts + +; Load the GTE User Tool and register it +GTEStartUp + pea $0000 + pea $0000 + pea $0000 + pea $0000 + pea $0000 ; result space + + lda UserId + pha + + pea #^ToolPath + pea #ToolPath + pea $0001 ; do not load into special memory + pea $0001 ; GS/OS string for the argument + _InitialLoad2 + + ply + pla ; Address of the loaded tool + plx + ply + ply + + pea $8000 ; User toolset + pea $00A0 ; Set the tool set number + phx + pha ; Address of function pointer table + _SetTSPtr + + clc ; Give GTE a page of direct page memory + tdc + adc #$0100 + pha + lda UserId + pha + _GTEStartUp + + rts + + +MasterId ds 2 +UserId ds 2 +ToolPath strl '9:GTETool' \ No newline at end of file diff --git a/demos/tool/App.s b/demos/tool/App.s new file mode 100644 index 0000000..3bd4b35 --- /dev/null +++ b/demos/tool/App.s @@ -0,0 +1,10 @@ +; IIgs Sprite Testbed + + TYP $B3 ; S16 file + DSK GTEToolDemo + XPL + +; Segment #1 -- Main execution block + + ASM App.Main.s + SNA Main diff --git a/demos/tool/GTEToolDemo b/demos/tool/GTEToolDemo new file mode 100644 index 0000000..466b7a7 Binary files /dev/null and b/demos/tool/GTEToolDemo differ diff --git a/demos/tool/_FileInformation.txt b/demos/tool/_FileInformation.txt new file mode 100644 index 0000000..f79c6dd --- /dev/null +++ b/demos/tool/_FileInformation.txt @@ -0,0 +1 @@ +GTEToolDemo=Type(B3),AuxType(0000),VersionCreate(70),MinVersion(BE),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000) diff --git a/demos/tool/build-image.bat b/demos/tool/build-image.bat new file mode 100644 index 0000000..5546b72 --- /dev/null +++ b/demos/tool/build-image.bat @@ -0,0 +1,19 @@ +echo off + +REM Copy all of the assets into the ProDOS image for emulator testing +REM +REM Pass the path of the Cadius tool as the first argument (%1) + +set CADIUS="%1" +set IMAGE="..\\..\\emu\\Target.2mg" +set FOLDER="/GTEDEV/Tool" + +REM Cadius does not overwrite files, so clear the root folder first +%CADIUS% DELETEFOLDER %IMAGE% %FOLDER% +%CADIUS% CREATEFOLDER %IMAGE% %FOLDER% + +REM Now copy files and folders as needed +%CADIUS% ADDFILE %IMAGE% %FOLDER% .\GTEToolDemo +%CADIUS% ADDFILE %IMAGE% %FOLDER% ..\..\src\GTETool + +REM Copy in the image assets diff --git a/demos/tool/package.json b/demos/tool/package.json new file mode 100644 index 0000000..18de1c0 --- /dev/null +++ b/demos/tool/package.json @@ -0,0 +1,30 @@ +{ + "name": "gte-toolbox-demo", + "version": "1.0.0", + "description": "A testbed for developing a toolbox wrapper around the GTE library", + "main": "index.js", + "config": { + "merlin32": "C:\\Programs\\IIgsXDev\\bin\\Merlin32-1.1.10.exe", + "cadius": "C:\\Programs\\IIgsXDev\\bin\\Cadius.exe", + "gsport": "C:\\Programs\\gsport\\gsport_0.31\\GSPort.exe", + "macros": "../../macros", + "crossrunner": "C:\\Programs\\Crossrunner\\Crossrunner.exe" + }, + "scripts": { + "test": "npm run build && build-image.bat %npm_package_config_cadius% && %npm_package_config_gsport%", + "debug": "%npm_package_config_crossrunner% GTEToolTest -Source GTEToolTest_S02_MAINSEG_Output.txt -Debug -CompatibilityLayer", + "build": "%npm_package_config_merlin32% -V %npm_package_config_macros% App.s" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/lscharen/iigs-game-engine.git" + }, + "author": "Lucas Scharenbroich", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/lscharen/iigs-game-engine/issues" + }, + "homepage": "https://github.com/lscharen/iigs-game-engine#readme", + "devDependencies": { + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..6391504 --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "generic-tile-engine", + "version": "1.0.0", + "description": "A tile-base game engine for the Apple IIgs", + "main": "index.js", + "config": { + "merlin32": "C:\\Programs\\IIgsXDev\\bin\\Merlin32-1.1.10.exe", + "cadius": "C:\\Programs\\IIgsXDev\\bin\\Cadius.exe", + "gsport": "C:\\Programs\\gsport\\gsport_0.31\\GSPort.exe", + "macros": "./macros", + "crossrunner": "C:\\Programs\\Crossrunner\\Crossrunner.exe" + }, + "scripts": { + "test": "npm run build && build-image.bat %npm_package_config_cadius% && %npm_package_config_gsport%", + "build": "%npm_package_config_merlin32% -V %npm_package_config_macros% ./src/Master.s" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/lscharen/iigs-game-engine.git" + }, + "author": "Lucas Scharenbroich", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/lscharen/iigs-game-engine/issues" + }, + "homepage": "https://github.com/lscharen/iigs-game-engine#readme", + "devDependencies": { + } +} diff --git a/src/Core.s b/src/Core.s index 3b2a66d..619f4ac 100644 --- a/src/Core.s +++ b/src/Core.s @@ -8,94 +8,6 @@ use .\Defs.s -; Feature flags -NO_INTERRUPTS equ 1 ; turn off for crossrunner debugging -NO_MUSIC equ 1 ; turn music + tool loading off - -; External data space provided by the main program segment -tiledata EXT -TileStore EXT - -; Sprite plane data and mask banks are provided as an exteral segment -; -; The sprite data holds a set of pre-rendered sprites that are optimized to support the rendering pipeline. There -; are four copies of each sprite, along with the cooresponding mask laid out into 4x4 tile regions where the -; empty row and column is shared between adjacent blocks. -; -; Logically, the memory is laid out as 4 columns of sprites and 4 rows. -; -; +---+---+---+---+---+---+---+---+---+---+---+---+-... -; | | | | | | | | | | | | | ... -; +---+---+---+---+---+---+---+---+---+---+---+---+-... -; | | 0 | 0 | | 1 | 1 | | 2 | 2 | | 3 | 3 | ... -; +---+---+---+---+---+---+---+---+---+---+---+---+-... -; | | 0 | 0 | | 1 | 1 | | 2 | 2 | | 3 | 3 | ... -; +---+---+---+---+---+---+---+---+---+---+---+---+-... -; | | | | | | | | | | | | | ... -; +---+---+---+---+---+---+---+---+---+---+---+---+-... -; | | 4 | 4 | | 5 | 5 | | 6 | 6 | | 7 | 7 | ... -; +---+---+---+---+---+---+---+---+---+---+---+---+-... -; | | 4 | 4 | | 5 | 5 | | 6 | 6 | | 7 | 7 | ... -; +---+---+---+---+---+---+---+---+---+---+---+---+-... -; | | | | | | | | | | | | | ... -; +---+---+---+---+---+---+---+---+---+---+---+---+-... -; -; For each sprite, when it needs to be copied into an on-screen tile, it could exist at any offset compared to its -; natural alignment. By having a buffer around the sprite data, an address pointer can be set to a different origin -; and a simple 8x8 block copy can cut out the appropriate bit of the sprite. For example, here is a zoomed-in look -; at a sprite with an offset, O, at (-2,-3). As shown, by selecting an appropriate origin, just the top corner -; of the sprite data will be copied. -; -; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+.. -; | | || | || | | | || | | | | -; +---+-- O----------------+ --+---++---+---+---+---++---+---+---+---+.. -; | | | | | || | | | || | | | | -; +---+-- | | --+---++---+---+---+---++---+---+---+---+.. -; | | | | | || | | | || | | | | -; +---+-- | | --+---++---+---+---+---++---+---+---+---+.. -; | | | | | || | | | || | | | | -; +===+== | ++===+== | ==+===++===+===+===+===++===+===+===+===+.. -; | | | || | S | S | S || S | S | S | || | | | | -; +---+-- +----------------+ --+---++---+---+---+---++---+---+---+---+.. -; | | || S | S S | S || S | S | S | S || | | | | -; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+.. -; | | | | || S | S | S | S || S | S | S | S || | | | | -; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+.. -; | | | | || S | S | S | S || S | S | S | S || | | | | -; +===+===+===+===++===+===+===+===++===+===+===+===++===+===+===+===+.. -; | | | | || S | S | S | S || S | S | S | S || | | | | -; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+.. -; | | | | || S | S | S | S || S | S | S | S || | | | | -; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+.. -; | | | | || S | S | S | S || S | S | S | S || | | | | -; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+.. -; | | | | || | S | S | S || S | S | S | || | | | | -; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+.. -; . . . . . . . . . . . . . . . . . -; -; Each sprite will take up, effectively 9 tiles of storage space per -; instance (plus edges) and there are 4 instances for the H/V bits -; and 4 more for the masks. This results in a need for 43,264 bytes -; for all 16 sprites. - -spritedata EXT -spritemask EXT - -; If there are overlays, they are provided as an external -Overlay EXT - -; Core engine functionality. The idea is that that source file can be PUT into -; a main source file and all of the functionality will be available. -; -; There are some constancts that must be externally defined that can affect how -; the GTE runtime works -; -; NO_MUSIC : Set to non-zero to avoid using any source -; NO_INTERRUPTS : Set to non-zero to avoid installing custom interrupt handlers - - mx %00 - -; High-Level StartUp and ShutDown functions EngineStartUp ENT phb phk @@ -103,41 +15,23 @@ EngineStartUp ENT jsr ToolStartUp ; Start up the toolbox tools we rely on jsr _CoreStartUp + jsr SoundStartUp ; Start up any sound/music tools plb rtl -_CoreStartUp - jsr SoundStartUp ; Start up any sound/music tools - jsr IntStartUp ; Enable certain iterrupts - - jsr InitMemory ; Allocate and initialize memory for the engine - jsr EngineReset ; All of the resources are allocated, put the engine in a known state - - jsr InitGraphics ; Initialize all of the graphics-related data - nop - jsr InitSprites ; Initialize the sprite subsystem - jsr InitTiles ; Initialize the tile subsystem - - jsr InitTimers ; Initialize the timer subsystem - rts - EngineShutDown ENT phb phk plb + jsr SoundShutDown jsr _CoreShutDown jsr ToolShutDown plb rtl -_CoreShutDown - jsr IntShutDown - jsr SoundShutDown - rts - ToolStartUp _TLStartUp ; normal tool initialization pha @@ -152,7 +46,7 @@ ToolStartUp rts MasterId ds 2 -UserId ds 2 +;UserId ds 2 ; Fatal error handler invoked by the _Err macro PgmDeath tax @@ -168,9 +62,6 @@ PgmDeath0 pha ContDeath ldx #$1503 jsl $E10000 -ToolShutDown - rts - ; Use Tool222 (NinjaTrackerPlus) for music playback SoundStartUp lda #NO_MUSIC @@ -194,299 +85,10 @@ SoundShutDown :no_music rts -; Install interrupt handlers. We use the VBL interrupt to keep animations -; moving at a consistent rate, regarless of the rendered frame rate. The -; one-second timer is generally just used for counters and as a handy -; frames-per-second trigger. -IntStartUp - lda #NO_INTERRUPTS - bne :no_interrupts - PushLong #0 - pea $0015 ; Get the existing 1-second interrupt handler and save - _GetVector - PullLong OldOneSecVec - - pea $0015 ; Set the new handler and enable interrupts - PushLong #OneSecHandler - _SetVector - - pea $0006 - _IntSource - - PushLong #VBLTASK ; Also register a Heart Beat Task - _SetHeartBeat - -:no_interrupts - rts - -IntShutDown - lda #NO_INTERRUPTS - bne :no_interrupts - - pea $0007 ; disable 1-second interrupts - _IntSource - - PushLong #VBLTASK ; Remove our heartbeat task - _DelHeartBeat - - pea $0015 - PushLong OldOneSecVec ; Reset the interrupt vector - _SetVector - -:no_interrupts - rts - - -; Interrupt handlers. We install a heartbeat (1/60th second and a 1-second timer) -OneSecHandler mx %11 - phb - pha - phk - plb - - rep #$20 - inc OneSecondCounter - sep #$20 - - ldal $E0C032 - and #%10111111 ;clear IRQ source - stal $E0C032 - - pla - plb - clc - rtl - mx %00 - -OneSecondCounter ENT - dw 0 -OldOneSecVec ds 4 - -VBLTASK hex 00000000 - dw 0 - hex 5AA5 - -; Reset the engine to a known state -; Blitter initialization -EngineReset - stz ScreenHeight - stz ScreenWidth - stz ScreenY0 - stz ScreenY1 - stz ScreenX0 - stz ScreenX1 - stz ScreenTileHeight - stz ScreenTileWidth - stz StartX - stz OldStartX - stz StartXMod164 - - stz StartY - stz OldStartY - stz StartYMod208 - - stz EngineMode - stz DirtyBits - stz LastRender - stz LastPatchOffset - stz BG1StartX - stz BG1StartXMod164 - stz BG1StartY - stz BG1StartYMod208 - stz BG1OffsetIndex - - stz BG0TileOriginX - stz BG0TileOriginY - stz OldBG0TileOriginX - stz OldBG0TileOriginY - - stz BG1TileOriginX - stz BG1TileOriginY - stz OldBG1TileOriginX - stz OldBG1TileOriginY - - stz TileMapWidth - stz TileMapHeight - stz TileMapPtr - stz TileMapPtr+2 - stz FringeMapPtr - stz FringeMapPtr+2 - - stz BG1TileMapWidth - stz BG1TileMapHeight - stz BG1TileMapPtr - stz BG1TileMapPtr+2 - - stz SCBArrayPtr - stz SCBArrayPtr+2 - - stz SpriteBanks - stz SpriteMap - stz ActiveSpriteCount - - stz OneSecondCounter - - lda #13 - sta tmp15 - stz tmp14 - -:loop - ldx #BlitBuff - lda #^BlitBuff - ldy tmp14 - jsr BuildBank - - lda tmp14 - clc - adc #4 - sta tmp14 - - dec tmp15 - bne :loop - - rts - -; Allow the user to dynamically select one of the pre-configured screen sizes, or pass -; in a specific width and height. The screen is automatically centered. If this is -; not desired, then SetScreenRect should be used directly -; -; 0. Full Screen : 40 x 25 320 x 200 (32,000 bytes (100.0%)) -; 1. Sword of Sodan : 34 x 24 272 x 192 (26,112 bytes ( 81.6%)) -; 2. ~NES : 32 x 25 256 x 200 (25,600 bytes ( 80.0%)) -; 3. Task Force : 32 x 22 256 x 176 (22,528 bytes ( 70.4%)) -; 4. Defender of the World : 35 x 20 280 x 160 (22,400 bytes ( 70.0%)) -; 5. Rastan : 32 x 20 256 x 160 (20,480 bytes ( 64.0%)) -; 6. Game Boy Advanced : 30 x 20 240 x 160 (19,200 bytes ( 60.0%)) -; 7. Ancient Land of Y's : 36 x 16 288 x 128 (18,432 bytes ( 57.6%)) -; 8. Game Boy Color : 20 x 18 160 x 144 (11,520 bytes ( 36.0%)) -; 9. Agony (Amiga) : 36 x 24 288 x 192 (27,648 bytes ( 86.4%)) -; 10. Atari Lynx : 20 x 13 160 x 102 (8,160 bytes ( 25.5%)) -; -; X = mode number OR width in pixels (must be multiple of 2) -; Y = height in pixels (if X > 8) - -ScreenModeWidth dw 320,272,256,256,280,256,240,288,160,288,160,320 -ScreenModeHeight dw 200,192,200,176,160,160,160,128,144,192,102,1 - -SetScreenMode ENT - phb - phk - plb - jsr _SetScreenMode - plb - rtl - -_SetScreenMode - cpx #11 - bcs :direct ; if x > 10, then assume X and Y are the dimensions - - txa - asl - tax - - ldy ScreenModeHeight,x - lda ScreenModeWidth,x - tax - -:direct cpy #201 - bcs :exit - - cpx #321 - bcs :exit - - txa - lsr - pha ; Save X (width / 2) and Y (height) - phy - - lda #160 ; Center the screen - sec - sbc 3,s - lsr - xba - pha ; Save half the origin coordinate - - lda #200 - sec - sbc 3,s ; This is now Y because of the PHA above - lsr - ora 1,s - - plx ; Throw-away to pop the stack - ply - plx - - jsr SetScreenRect - jmp FillScreen ; tail return -:exit - rts - - -WaitForKey sep #$20 - stal KBD_STROBE_REG ; clear the strobe -:WFK ldal KBD_REG - bpl :WFK - rep #$20 - and #$007F - rts - -ClearKbdStrobe sep #$20 - stal KBD_STROBE_REG - rep #$20 - rts - -; Read the keyboard and paddle controls and return in a game-controller-like format -LastKey db 0 -ReadControl ENT - jsr _ReadControl - rtl - -_ReadControl - pea $0000 ; low byte = key code, high byte = %------AB - - sep #$20 - ldal OPTION_KEY_REG ; 'B' button - and #$80 - beq :BNotDown - - lda #PAD_BUTTON_B - ora 2,s - sta 2,s - -:BNotDown - ldal COMMAND_KEY_REG - and #$80 - beq :ANotDown - - lda #PAD_BUTTON_A - ora 2,s - sta 2,s - -:ANotDown - ldal KBD_STROBE_REG ; read the keyboard - bit #$80 - beq :KbdNotDwn ; check the key-down status - and #$7f - ora 1,s - sta 1,s - - cmpl LastKey - beq :KbdDown - stal LastKey - - lda #PAD_KEY_DOWN ; set the keydown flag - ora 2,s - sta 2,s - bra :KbdDown - -:KbdNotDwn - lda #0 - stal LastKey -:KbdDown - rep #$20 - pla +ToolShutDown rts + put CoreImpl.s put blitter/Template.s put Memory.s diff --git a/src/CoreImpl.s b/src/CoreImpl.s new file mode 100644 index 0000000..b4708ed --- /dev/null +++ b/src/CoreImpl.s @@ -0,0 +1,369 @@ +; Feature flags +NO_INTERRUPTS equ 1 ; turn off for crossrunner debugging +NO_MUSIC equ 1 ; turn music + tool loading off + +; External data space provided by the main program segment +tiledata EXT +TileStore EXT + +; Sprite plane data and mask banks are provided as an external segment +; +; The sprite data holds a set of pre-rendered sprites that are optimized to support the rendering pipeline. There +; are four copies of each sprite, along with the cooresponding mask laid out into 4x4 tile regions where the +; empty row and column is shared between adjacent blocks. +; +; Logically, the memory is laid out as 4 columns of sprites and 4 rows. +; +; +---+---+---+---+---+---+---+---+---+---+---+---+-... +; | | | | | | | | | | | | | ... +; +---+---+---+---+---+---+---+---+---+---+---+---+-... +; | | 0 | 0 | | 1 | 1 | | 2 | 2 | | 3 | 3 | ... +; +---+---+---+---+---+---+---+---+---+---+---+---+-... +; | | 0 | 0 | | 1 | 1 | | 2 | 2 | | 3 | 3 | ... +; +---+---+---+---+---+---+---+---+---+---+---+---+-... +; | | | | | | | | | | | | | ... +; +---+---+---+---+---+---+---+---+---+---+---+---+-... +; | | 4 | 4 | | 5 | 5 | | 6 | 6 | | 7 | 7 | ... +; +---+---+---+---+---+---+---+---+---+---+---+---+-... +; | | 4 | 4 | | 5 | 5 | | 6 | 6 | | 7 | 7 | ... +; +---+---+---+---+---+---+---+---+---+---+---+---+-... +; | | | | | | | | | | | | | ... +; +---+---+---+---+---+---+---+---+---+---+---+---+-... +; +; For each sprite, when it needs to be copied into an on-screen tile, it could exist at any offset compared to its +; natural alignment. By having a buffer around the sprite data, an address pointer can be set to a different origin +; and a simple 8x8 block copy can cut out the appropriate bit of the sprite. For example, here is a zoomed-in look +; at a sprite with an offset, O, at (-2,-3). As shown, by selecting an appropriate origin, just the top corner +; of the sprite data will be copied. +; +; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+.. +; | | || | || | | | || | | | | +; +---+-- O----------------+ --+---++---+---+---+---++---+---+---+---+.. +; | | | | | || | | | || | | | | +; +---+-- | | --+---++---+---+---+---++---+---+---+---+.. +; | | | | | || | | | || | | | | +; +---+-- | | --+---++---+---+---+---++---+---+---+---+.. +; | | | | | || | | | || | | | | +; +===+== | ++===+== | ==+===++===+===+===+===++===+===+===+===+.. +; | | | || | S | S | S || S | S | S | || | | | | +; +---+-- +----------------+ --+---++---+---+---+---++---+---+---+---+.. +; | | || S | S S | S || S | S | S | S || | | | | +; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+.. +; | | | | || S | S | S | S || S | S | S | S || | | | | +; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+.. +; | | | | || S | S | S | S || S | S | S | S || | | | | +; +===+===+===+===++===+===+===+===++===+===+===+===++===+===+===+===+.. +; | | | | || S | S | S | S || S | S | S | S || | | | | +; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+.. +; | | | | || S | S | S | S || S | S | S | S || | | | | +; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+.. +; | | | | || S | S | S | S || S | S | S | S || | | | | +; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+.. +; | | | | || | S | S | S || S | S | S | || | | | | +; +---+---+---+---++---+---+---+---++---+---+---+---++---+---+---+---+.. +; . . . . . . . . . . . . . . . . . +; +; Each sprite will take up, effectively 9 tiles of storage space per +; instance (plus edges) and there are 4 instances for the H/V bits +; and 4 more for the masks. This results in a need for 43,264 bytes +; for all 16 sprites. + +spritedata EXT +spritemask EXT + +; If there are overlays, they are provided as an external +Overlay EXT + +; Core engine functionality. The idea is that that source file can be PUT into +; a main source file and all of the functionality will be available. +; +; There are some constancts that must be externally defined that can affect how +; the GTE runtime works +; +; NO_MUSIC : Set to non-zero to avoid using any source +; NO_INTERRUPTS : Set to non-zero to avoid installing custom interrupt handlers + + mx %00 + +; A = memory manager userId +; X = tool number +_CoreStartUp + sta UserId ; This is the first thing to do + stx ToolNum + + jsr IntStartUp ; Enable certain iterrupts + + jsr InitMemory ; Allocate and initialize memory for the engine + jsr EngineReset ; All of the resources are allocated, put the engine in a known state + +; jsr InitGraphics ; Initialize all of the graphics-related data +; jsr InitSprites ; Initialize the sprite subsystem +; jsr InitTiles ; Initialize the tile subsystem + + jsr InitTimers ; Initialize the timer subsystem + +_CoreShutDown + jsr IntShutDown + rts + +; Install interrupt handlers. We use the VBL interrupt to keep animations +; moving at a consistent rate, regarless of the rendered frame rate. The +; one-second timer is generally just used for counters and as a handy +; frames-per-second trigger. +IntStartUp + lda #NO_INTERRUPTS + bne :no_interrupts + PushLong #0 + pea $0015 ; Get the existing 1-second interrupt handler and save + _GetVector + PullLong OldOneSecVec + + pea $0015 ; Set the new handler and enable interrupts + PushLong #OneSecHandler + _SetVector + + pea $0006 + _IntSource + + PushLong #VBLTASK ; Also register a Heart Beat Task + _SetHeartBeat + +:no_interrupts + rts + +IntShutDown + lda #NO_INTERRUPTS + bne :no_interrupts + + pea $0007 ; disable 1-second interrupts + _IntSource + + PushLong #VBLTASK ; Remove our heartbeat task + _DelHeartBeat + + pea $0015 + PushLong OldOneSecVec ; Reset the interrupt vector + _SetVector + +:no_interrupts + rts + + +; Interrupt handlers. We install a heartbeat (1/60th second and a 1-second timer) +OneSecHandler mx %11 + phb + pha + phk + plb + + rep #$20 + inc OneSecondCounter + sep #$20 + + ldal $E0C032 + and #%10111111 ;clear IRQ source + stal $E0C032 + + pla + plb + clc + rtl + mx %00 + +OneSecondCounter ENT + dw 0 +OldOneSecVec ds 4 + +VBLTASK hex 00000000 + dw 0 + hex 5AA5 + +; Reset the engine to a known state +; Blitter initialization +EngineReset + stz ScreenHeight + stz ScreenWidth + stz ScreenY0 + stz ScreenY1 + stz ScreenX0 + stz ScreenX1 + stz ScreenTileHeight + stz ScreenTileWidth + stz StartX + stz OldStartX + stz StartXMod164 + + stz StartY + stz OldStartY + stz StartYMod208 + + stz EngineMode + stz DirtyBits + stz LastRender + stz LastPatchOffset + stz BG1StartX + stz BG1StartXMod164 + stz BG1StartY + stz BG1StartYMod208 + stz BG1OffsetIndex + + stz BG0TileOriginX + stz BG0TileOriginY + stz OldBG0TileOriginX + stz OldBG0TileOriginY + + stz BG1TileOriginX + stz BG1TileOriginY + stz OldBG1TileOriginX + stz OldBG1TileOriginY + + stz TileMapWidth + stz TileMapHeight + stz TileMapPtr + stz TileMapPtr+2 + stz FringeMapPtr + stz FringeMapPtr+2 + + stz BG1TileMapWidth + stz BG1TileMapHeight + stz BG1TileMapPtr + stz BG1TileMapPtr+2 + + stz SCBArrayPtr + stz SCBArrayPtr+2 + + stz SpriteBanks + stz SpriteMap + stz ActiveSpriteCount + + stz OneSecondCounter + + lda #13 + sta tmp15 + stz tmp14 + +:loop + ldx #BlitBuff + lda #^BlitBuff + ldy tmp14 +; jsr BuildBank + + lda tmp14 + clc + adc #4 + sta tmp14 + + dec tmp15 + bne :loop + + rts + + +WaitForKey sep #$20 + stal KBD_STROBE_REG ; clear the strobe +:WFK ldal KBD_REG + bpl :WFK + rep #$20 + and #$007F + rts + +ClearKbdStrobe sep #$20 + stal KBD_STROBE_REG + rep #$20 + rts + +; Read the keyboard and paddle controls and return in a game-controller-like format +LastKey db 0 +ReadControl ENT + jsr _ReadControl + rtl + +_ReadControl + pea $0000 ; low byte = key code, high byte = %------AB + + sep #$20 + ldal OPTION_KEY_REG ; 'B' button + and #$80 + beq :BNotDown + + lda #PAD_BUTTON_B + ora 2,s + sta 2,s + +:BNotDown + ldal COMMAND_KEY_REG + and #$80 + beq :ANotDown + + lda #PAD_BUTTON_A + ora 2,s + sta 2,s + +:ANotDown + ldal KBD_STROBE_REG ; read the keyboard + bit #$80 + beq :KbdNotDwn ; check the key-down status + and #$7f + ora 1,s + sta 1,s + + cmpl LastKey + beq :KbdDown + stal LastKey + + lda #PAD_KEY_DOWN ; set the keydown flag + ora 2,s + sta 2,s + bra :KbdDown + +:KbdNotDwn + lda #0 + stal LastKey +:KbdDown + rep #$20 + pla + rts + + +; Helper function to take a local pixel coordinate [0, ScreenWidth-1],[0, ScreenHeight-1] and return the +; row and column in the tile store that is corresponds to. This takes into consideration the StartX and +; StartY offsets. +; +; This is more specialized than the code in the _MarkDirtySprite routine below since it does not deal with +; negative or off-screen values. +_OriginToTileStore + lda StartYMod208 + lsr + lsr + and #$FFFE ; Store the pre-multiplied by 2 for indexing + tay + lda StartXMod164 + lsr + and #$FFFE ; Same pre-multiply by 2 for later + tax + rts + +; X = local x-coordinate (0, playfield width) +; Y = local y-coordinate (0, playfield height) +_LocalToTileStore + clc + tya + adc StartYMod208 ; Adjust for the scroll offset + cmp #208 ; check if we went too far positive + bcc *+5 + sbc #208 + lsr + lsr + and #$FFFE ; Store the pre-multiplied by 2 for indexing + tay + + clc + txa + adc StartXMod164 + cmp #164 + bcc *+5 + sbc #164 + lsr + and #$FFFE ; Same pre-multiply by 2 for later + tax + rts \ No newline at end of file diff --git a/src/Defs.s b/src/Defs.s index d2d8017..2f5e12c 100644 --- a/src/Defs.s +++ b/src/Defs.s @@ -88,7 +88,9 @@ BankLoad equ 104 TileStoreBankAndBank01 equ 106 TileStoreBankAndTileDataBank equ 108 TileStoreBankDoubled equ 110 -Next equ 112 +UserId equ 112 ; Memory manager user Id to use +ToolNum equ 114 ; Tool number assigned to us +Next equ 116 activeSpriteList equ 128 ; 32 bytes for the active sprite list (can persist across frames) ; tiletmp equ 178 ; 16 bytes of temp storage for the tile renderers diff --git a/src/Graphics.s b/src/Graphics.s index 5fe5f94..1ef1656 100644 --- a/src/Graphics.s +++ b/src/Graphics.s @@ -24,6 +24,82 @@ DefaultPalette dw $0000,$007F,$0090,$0FF0 dw $0fa9,$0ff0,$00e0,$04DF dw $0d00,$078f,$0ccc,$0FFF + +; Allow the user to dynamically select one of the pre-configured screen sizes, or pass +; in a specific width and height. The screen is automatically centered. If this is +; not desired, then SetScreenRect should be used directly +; +; 0. Full Screen : 40 x 25 320 x 200 (32,000 bytes (100.0%)) +; 1. Sword of Sodan : 34 x 24 272 x 192 (26,112 bytes ( 81.6%)) +; 2. ~NES : 32 x 25 256 x 200 (25,600 bytes ( 80.0%)) +; 3. Task Force : 32 x 22 256 x 176 (22,528 bytes ( 70.4%)) +; 4. Defender of the World : 35 x 20 280 x 160 (22,400 bytes ( 70.0%)) +; 5. Rastan : 32 x 20 256 x 160 (20,480 bytes ( 64.0%)) +; 6. Game Boy Advanced : 30 x 20 240 x 160 (19,200 bytes ( 60.0%)) +; 7. Ancient Land of Y's : 36 x 16 288 x 128 (18,432 bytes ( 57.6%)) +; 8. Game Boy Color : 20 x 18 160 x 144 (11,520 bytes ( 36.0%)) +; 9. Agony (Amiga) : 36 x 24 288 x 192 (27,648 bytes ( 86.4%)) +; 10. Atari Lynx : 20 x 13 160 x 102 (8,160 bytes ( 25.5%)) +; +; X = mode number OR width in pixels (must be multiple of 2) +; Y = height in pixels (if X > 8) + +ScreenModeWidth dw 320,272,256,256,280,256,240,288,160,288,160,320 +ScreenModeHeight dw 200,192,200,176,160,160,160,128,144,192,102,1 + +SetScreenMode ENT + phb + phk + plb + jsr _SetScreenMode + plb + rtl + +_SetScreenMode + cpx #11 + bcs :direct ; if x > 10, then assume X and Y are the dimensions + + txa + asl + tax + + ldy ScreenModeHeight,x + lda ScreenModeWidth,x + tax + +:direct cpy #201 + bcs :exit + + cpx #321 + bcs :exit + + txa + lsr + pha ; Save X (width / 2) and Y (height) + phy + + lda #160 ; Center the screen + sec + sbc 3,s + lsr + xba + pha ; Save half the origin coordinate + + lda #200 + sec + sbc 3,s ; This is now Y because of the PHA above + lsr + ora 1,s + + plx ; Throw-away to pop the stack + ply + plx + + jsr SetScreenRect + jmp FillScreen ; tail return +:exit + rts + ; Return the current border color ($0 - $F) in the accumulator _GetBorderColor lda #0000 sep #$20 diff --git a/src/Master.s b/src/Master.s new file mode 100644 index 0000000..223034c --- /dev/null +++ b/src/Master.s @@ -0,0 +1,34 @@ +; IIgs Generic Tile Engine User Toolset + + TYP $BA ; TOL file + DSK GTETool + XPL + +; Main toolbox interface and code + + ASM Tool.s + SNA Main + +; 64KB Tile Memory + + ASM static\TileData.s + KND #$1001 ; Type and Attributes ($10=Static,$01=Data) + SNA TDATA + +; 64KB Sprite Plane Data + + ASM static\SprData.s + KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data) + SNA SDATA + +;64KB Sprite Mask Data + + ASM static\SprMask.s + KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data) + SNA SMASK + +; 64KB Tile Store + + ASM static\TileStore.s + KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data) + SNA TSTORE diff --git a/src/Sprite.s b/src/Sprite.s index a3bcb89..b659ed8 100644 --- a/src/Sprite.s +++ b/src/Sprite.s @@ -62,9 +62,9 @@ InitSprites ; covering the exact same tiles. -; Render a sprite stamp into the sprite buffer. Stamps exits independent of the sprites +; Render a sprite stamp into the sprite buffer. Stamps exist independent of the sprites ; and sprite reference a specific stamp. This is necessary because it's common for a -; spite to change its graphic as its animating, but it is too costly to have to set up +; sprite to change its graphic as its animating, but it is too costly to have to set up ; the stamp every time. So this allows users to create stamps in advance and then ; assign them to the sprites as needed. ; diff --git a/src/Sprite2.s b/src/Sprite2.s index 9d83bea..404ade4 100644 --- a/src/Sprite2.s +++ b/src/Sprite2.s @@ -16,49 +16,6 @@ ColLeft equ tmp9 SpriteBit equ tmp10 ; set the bit of the value that if the current sprite index VBuffOrigin equ tmp11 -; Helper function to take a local pixel coordinate [0, ScreenWidth-1],[0, ScreenHeight-1] and return the -; row and column in the tile store that is corresponds to. This takes into consideration the StartX and -; StartY offsets. -; -; This is more specialized than the code in the _MarkDirtySprite routine below since it does not deal with -; negative or off-screen values. -_OriginToTileStore - lda StartYMod208 - lsr - lsr - and #$FFFE ; Store the pre-multiplied by 2 for indexing - tay - lda StartXMod164 - lsr - and #$FFFE ; Same pre-multiply by 2 for later - tax - rts - -; X = local x-coordinate (0, playfield width) -; Y = local y-coordinate (0, playfield height) -_LocalToTileStore - clc - tya - adc StartYMod208 ; Adjust for the scroll offset - cmp #208 ; check if we went too far positive - bcc *+5 - sbc #208 - lsr - lsr - and #$FFFE ; Store the pre-multiplied by 2 for indexing - tay - - clc - txa - adc StartXMod164 - cmp #164 - bcc *+5 - sbc #164 - lsr - and #$FFFE ; Same pre-multiply by 2 for later - tax - rts - ; Marks a sprite as dirty. The work here is mapping from local screen coordinates to the ; tile store indices. The first step is to adjust the sprite coordinates based on the current ; code field offsets and then cache variations of this value needed in the rest of the subroutine diff --git a/src/Tool.s b/src/Tool.s index c1ba0dd..2fdf11e 100644 --- a/src/Tool.s +++ b/src/Tool.s @@ -3,10 +3,19 @@ ; Ref: Toolbox Reference, Volume 2, Appendix A ; Ref: IIgs Tech Note #73 +; use Load.Macs.s + use Mem.Macs.s + use Misc.Macs.s + use Util.Macs + use Locator.Macs + use Core.MACS.s + + use Defs.s + ToStrip equ $E10184 _CallTable - dw {_CTEnd-_CallTable}/4,0 + adrl {_CTEnd-_CallTable}/4 adrl _TSBootInit-1 adrl _TSStartUp-1 adrl _TSShutDown-1 @@ -25,40 +34,58 @@ _TSBootInit clc rtl -; Call the regular GTE startup function after setting the Work Area Point (WAP). The caller much provide -; one page of Bank 0 memory for the tool set's private use +; Call the regular GTE startup function after setting the Work Area Pointer (WAP). The caller must provide +; one page of Bank 0 memory for the tool set's private use and a userId to use for allocating memory ; -; X = +; X = tool set number in low byte and function umber in high byte +; +; StartUp(dPageAddr, userId) _TSStartUp -:zpToUse equ 7 - pea #$8000 +rtll = 1 +rtl2 = rtl1+3 +userId = 7 +zpToUse = userId+2 + txa - and #$00FF - pha + and #$00FF ; Get just the tool number + tax - pea $0000 - lda :zpToUse+6,s - pha + lda userId,s ; Get the userId for memory allocations + tay + lda zpToUse,s ; Get the direct page address + + phd ; Save the current direct page + tcd ; Set to our working direct page space + + tya ; A = memory manager user Id, X = tool number + jsr _CoreStartUp ; Initialize the library + +; SetWAP(userOrSystem, tsNum, waptPtr) + + pea #$8000 ; $8000 = user tool set + pei ToolNum ; Push the tool number from the direct page + pea $0000 ; High word of WAP is zero (bank 0) + phd ; Low word of WAP is the direct page _SetWAP - jsr _CoreStartUp + pld ; Restore the caller's direct page + + lda #0 + clc + rtl _TSShutDown cmp #0 ; Acc is low word of the WAP (direct page) beq :inactive phd - pha - pld ; Set the direct page for the toolset + tcd ; Set the direct page for the toolset - phx ; Preserve the X register - jsr _CoreShutDown ; Shut down GTE - pla + jsr _CoreShutDown ; Shut down the library pea $8000 - and #$00FF - pha + pei ToolNum pea $0000 ; Set WAP to null pea $0000 _SetWAP @@ -71,7 +98,7 @@ _TSShutDown rtl _TSVersion - lda #$0100 ; Version 1 + lda #$0100 ; Version 1 sta 7,s lda #0 @@ -101,31 +128,45 @@ _TSReserved sec rtl +; SetScreenMode(width, height) _TSSetScreenMode - phd ; Preserve the direct page - pha - pld +:height equ 9 +:width equ 11 - lda 9,s + phd ; Preserve the direct page + tcd ; Set the tool set direct pafe from WAP + + lda :height,s tay - lda 9,s + lda :width,s tax - jsr _SetScreenMode - pld +; jsr _SetScreenMode ; Not implemented yet + + pld ; Restore direct page ldx #0 ; No error ldy #4 ; Remove the 4 input bytes jml ToStrip _TSReadControl +:output equ 9 + phd ; Preserve the direct page - pha - pld + tcd jsr _ReadControl - sta 9,s + sta :output,s pld ldx #0 ; No error ldy #0 ; Remove zero input bytes jml ToStrip + +; Insert the core GTE functions + + put CoreImpl.s + put Memory.s + put Timer.s +; put Graphics.s +; put blitter/Template.s + put blitter/Tables.s diff --git a/src/_FileInformation.txt b/src/_FileInformation.txt new file mode 100644 index 0000000..54452a1 --- /dev/null +++ b/src/_FileInformation.txt @@ -0,0 +1,2 @@ +Tool=Type(00),AuxType(0000),VersionCreate(70),MinVersion(BE),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000) +GTETool=Type(BA),AuxType(0000),VersionCreate(70),MinVersion(BE),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000) diff --git a/src/blitter/Tables.s b/src/blitter/Tables.s index 44bf70c..bbe0a3d 100644 --- a/src/blitter/Tables.s +++ b/src/blitter/Tables.s @@ -19,25 +19,26 @@ ; ; Remember, because the data is pushed on to the stack, the last instruction, which is ; in the highest memory location, pushed data that apepars on the left edge of the screen. -PER_TILE_SIZE equ 3 -]step equ 0 - dw CODE_TOP ; There is a spot where we load Col2CodeOffet-2,x -Col2CodeOffset lup 82 - dw CODE_TOP+{{81-]step}*PER_TILE_SIZE} -]step equ ]step+1 - --^ - dw CODE_TOP+{81*PER_TILE_SIZE} +;PER_TILE_SIZE equ 3 +;]step equ 0 + +; dw CODE_TOP ; There is a spot where we load Col2CodeOffet-2,x +;Col2CodeOffset lup 82 +; dw CODE_TOP+{{81-]step}*PER_TILE_SIZE} +;]step equ ]step+1 +; --^ +; dw CODE_TOP+{81*PER_TILE_SIZE} ; A parallel table to Col2CodeOffset that holds the offset to the exception handler address for each column -SNIPPET_SIZE equ 32 -]step equ 0 - dw SNIPPET_BASE -JTableOffset lup 82 - dw SNIPPET_BASE+{{81-]step}*SNIPPET_SIZE} -]step equ ]step+1 - --^ - dw SNIPPET_BASE+{81*SNIPPET_SIZE} +;SNIPPET_SIZE equ 32 +;]step equ 0 +; dw SNIPPET_BASE +;JTableOffset lup 82 +; dw SNIPPET_BASE+{{81-]step}*SNIPPET_SIZE} +;]step equ ]step+1 +; --^ +; dw SNIPPET_BASE+{81*SNIPPET_SIZE} ; Table of BRA instructions that are used to exit the code field. Separate tables for ; even and odd aligned cases. diff --git a/src/blitter/Template.s b/src/blitter/Template.s index 82446a8..651d62e 100644 --- a/src/blitter/Template.s +++ b/src/blitter/Template.s @@ -155,7 +155,6 @@ SetScreenRect sty ScreenHeight ; Save the screen height and cpx #TILE_STORE_SIZE-2 bcc :tsloop -; Return rts ; Generalized routine that calculates the on-screen address of the tiles and takes the diff --git a/src/blitter/Tiles.s b/src/blitter/Tiles.s index 45c45ac..0a9f66e 100644 --- a/src/blitter/Tiles.s +++ b/src/blitter/Tiles.s @@ -74,7 +74,7 @@ _GetBaseTileAddr asl ; x64 asl ; x128 rts - + ; On entry ; ; B is set to the correct BG1 data bank @@ -102,9 +102,14 @@ _RenderTileBG1 ; Given an address to a Tile Store record, dispatch to the appropriate tile renderer. The Tile ; Store record contains all of the low-level information that's needed to call the renderer. ; +; There are two execution paths that are handled here. First, if there is no sprite, then +; the tile data is read directly and written into the code field in a single pass. If there +; are sprites that overlap the tile, then the sprite data is combined with the tile data +; and written to a temporary direct page buffer. If +; ; This routine sets the direct page register to the second page since we use that space to ; build and cache tile and sprite data, when necessary -; Y = address of tile + _RenderTile2 lda TileStore+TS_SPRITE_FLAG,x ; This is a bitfield of all the sprites that intersect this tile, only care if non-zero or not bne do_dirty_sprite @@ -159,10 +164,19 @@ do_dirty_sprite pei TileStoreBankAndTileDataBank ; Special value that has the TileStore bank in LSB and TileData bank in MSB plb -; Cache a couple of values into the direct page, but preserve the Accumulator +; Cache a couple of values into the direct page that are used across all copy routines - ldy TileStore+TS_TILE_ADDR,x ; load the address of this tile's data (pre-calculated) - sty tileAddr + lda TileStore+TS_TILE_ADDR,y ; load the address of this tile's data (pre-calculated) + sta tileAddr + + ldx TileStore+TS_VBUFF_ADDR_COUNT,y + jmp (dirty_sprite_dispatch,x) +dirty_sprite_dispatch + da CopyNoSprites + da CopyOneSprite + da CopyTwoSprites + da CopyThreeSprites + da CopyFourSprites ; MAX, don't bother with more than 4 sprites per tile ; This is very similar to the code in the dirty tile renderer, but we can't reuse ; because that code draws directly to the graphics screen, and this code draws @@ -243,7 +257,15 @@ do_dirty_sprite ; We set up direct page pointers to the mask bank and use the bank register for the ; data. -CopyFourSpritesAbove +CopyFourSprites + lda TileStore+TS_VBUFF_ADDR_0,y + sta spriteIdx + lda TileStore+TS_VBUFF_ADDR_1,y + sta spriteIdx+4 + lda TileStore+TS_VBUFF_ADDR_2,y + sta spriteIdx+8 + lda TileStore+TS_VBUFF_ADDR_3,y + sta spriteIdx+12 ; Copy three sprites into a temporary direct page buffer LDA_IL equ $A7 ; lda [dp] @@ -252,6 +274,13 @@ AND_IL equ $27 ; and [dp] AND_ILY equ $37 ; and [dp],y CopyThreeSprites + lda TileStore+TS_VBUFF_ADDR_0,y + sta spriteIdx + lda TileStore+TS_VBUFF_ADDR_1,y + sta spriteIdx+4 + lda TileStore+TS_VBUFF_ADDR_2,y + sta spriteIdx+8 + ]line equ 0 lup 8 ldy #]line*SPRITE_PLANE_SPAN @@ -285,6 +314,11 @@ CopyThreeSprites ; Copy two sprites into a temporary direct page buffer CopyTwoSprites + lda TileStore+TS_VBUFF_ADDR_0,y + sta spriteIdx + lda TileStore+TS_VBUFF_ADDR_1,y + sta spriteIdx+4 + ]line equ 0 lup 8 ldy #]line*SPRITE_PLANE_SPAN @@ -311,9 +345,56 @@ CopyTwoSprites ; jmp FinishTile ; Copy a single piece of sprite data into a temporary direct page . X = spriteIdx +; +; X register is the offset of the underlying tile data +; Y register is the line offset into the sprite data and mask buffers +; There is a pointer for each sprite on the direct page that can be used +; to access both the data and mask components of a sprite +; The Data Bank reigster points to the sprite data +; +; ldal tiledata,x +; and [spriteIdx],y +; ora (spriteIdx),y +; sta tmp_sprite_data +; +; For multiple sprites, we can chain together the and/ora instructions to stack the sprites +; +; ldal tiledata,x +; and [spriteIdx],y +; ora (spriteIdx),y +; and [spriteIdx+4],y +; ora (spriteIdx+4),y +; and [spriteIdx+8],y +; ora (spriteIdx+8),y +; sta tmp_sprite_data +; +; When the sprites need to be drawn on top of the background, then change the order of operations +; +; lda (spriteIdx),y +; and [spriteIdx+4],y +; ora (spriteIdx+4),y +; and [spriteIdx+8],y +; ora (spriteIdx+8),y +; sta tmp_sprite_data +; andl tiledata+32,x +; oral tiledata,x +; CopyOneSprite + clc + lda TileStore+TS_VBUFF_ADDR_0,y + sta spriteIdx + adc #2 + sta spriteIdx+4 + ]line equ 0 lup 8 + ldal tiledata,x + and [spriteIdx] + ora (spriteIdx) + sta tmp_sprite_data+{]line*4} + + + ldal spritedata+{]line*SPRITE_PLANE_SPAN},x sta tmp_sprite_data+{]line*4} ldal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x diff --git a/src/static/SprData.s b/src/static/SprData.s new file mode 100644 index 0000000..0c3b85e --- /dev/null +++ b/src/static/SprData.s @@ -0,0 +1,3 @@ +; sprite stamp pixel data +spritedata ENT + ds 65536 \ No newline at end of file diff --git a/src/static/SprMask.s b/src/static/SprMask.s new file mode 100644 index 0000000..13de529 --- /dev/null +++ b/src/static/SprMask.s @@ -0,0 +1,3 @@ +; sprite stamp masks +spritemask ENT + ds 65536 \ No newline at end of file diff --git a/src/static/TileData.s b/src/static/TileData.s new file mode 100644 index 0000000..233da6c --- /dev/null +++ b/src/static/TileData.s @@ -0,0 +1,3 @@ +; Bank of memory that holds the 8x8 tile data +tiledata ENT + ds 65536 \ No newline at end of file diff --git a/src/static/TileStore.s b/src/static/TileStore.s new file mode 100644 index 0000000..101700f --- /dev/null +++ b/src/static/TileStore.s @@ -0,0 +1,3 @@ +; Bank of memory that holds the core sprite and tile store data structures +TileStore ENT + ds 65536 \ No newline at end of file