Merge branch 'master' into create-orca-c-demo
This commit is contained in:
commit
cf9759b7df
|
@ -4,4 +4,5 @@ emu
|
|||
*_Output.txt
|
||||
src/GTETestApp
|
||||
*.2mg
|
||||
Tool160.SHK
|
||||
Tool160.SHK
|
||||
src/Tool160
|
|
@ -0,0 +1,185 @@
|
|||
/* ********************************************************************
|
||||
|
||||
GTE is copyright Lucas Scharenbroich and licensed under the Apache-2.0
|
||||
License.
|
||||
|
||||
The following GTE function definitions are taken from the GTE Toolbox
|
||||
documentation:
|
||||
https://lscharen.github.io/iigs-game-engine/toolboxref.html
|
||||
|
||||
And from the GTE Macros:
|
||||
https://github.com/lscharen/iigs-game-engine/blob/d7be9f1be44748b0180c930b1f90b144cda661ea/macros/GTE.Macs.s
|
||||
|
||||
The contents of this file are a derivite work from GTE intended to
|
||||
ease the process of calling GTE / Tool 160 from ORCA/C and are believed
|
||||
to be permitted under the terms of the Apache-2.0 License.
|
||||
|
||||
********************************************************************* */
|
||||
|
||||
#ifndef _GTE_HEADER_INCLUDE_
|
||||
#define _GTE_HEADER_INCLUDE_
|
||||
|
||||
#include <types.h>
|
||||
|
||||
/*
|
||||
GTE_IS_SYSTEM_TOOLS_INSTALL is a boolean toggle for controlling what the application assumes about the location of the GTE tool.
|
||||
|
||||
If GTE is installed in System:Tools, GTE_IS_SYSTEM_TOOLS_INSTALL must be defined.
|
||||
Otherwise, GTE_IS_SYSTEM_TOOLS_INSTALL must be undefined.
|
||||
|
||||
This will control which header file is used as well as the calls used to load the tool during application startup.
|
||||
*/
|
||||
// #define GTE_IS_SYSTEM_TOOLS_INSTALL 1
|
||||
|
||||
#ifdef GTE_IS_SYSTEM_TOOLS_INSTALL
|
||||
#define tool_dispatcher dispatcher
|
||||
#else
|
||||
#define tool_dispatcher 0xE10008L
|
||||
#endif // GTE_IS_SYSTEM_TOOLS_INSTALL
|
||||
|
||||
typedef struct TileMapInfo {
|
||||
Word width;
|
||||
Word height;
|
||||
Pointer tileMapPtr;
|
||||
} TileMapInfo;
|
||||
|
||||
typedef struct ScreenInfo {
|
||||
Word x;
|
||||
Word y;
|
||||
Word width;
|
||||
Word height;
|
||||
} ScreenInfo;
|
||||
|
||||
/* GTE Housekeeping Routines */
|
||||
extern pascal void GTEBootInit(void) inline(0x01A0, tool_dispatcher);
|
||||
extern pascal void GTEStartUp(Word dPageAddr, Word capFlags, Word userID) inline(0x02A0, tool_dispatcher);
|
||||
extern pascal void GTEShutDown(void) inline(0x03A0, tool_dispatcher);
|
||||
extern pascal Word GTEVersion(void) inline(0x04A0, tool_dispatcher);
|
||||
extern pascal void GTEReset(void) inline(0x05A0, tool_dispatcher);
|
||||
extern pascal Word GTEStatus(void) inline(0x06A0, tool_dispatcher);
|
||||
|
||||
|
||||
/* GTE Sprite Routines */
|
||||
extern pascal void GTECreateSpriteStamp(Word spriteDescriptor, Word vBuffAddr) inline(0x0FA0, tool_dispatcher);
|
||||
extern pascal Word GTECompileSpriteStamp(Word spriteDescriptor, Word vBuffAddr) inline(0x2DA0, tool_dispatcher);
|
||||
extern pascal void GTEAddSprite(Word spriteSlot, Word spriteFlags, Word vBuffAddr, Word x, Word y) inline(0x10A0, tool_dispatcher);
|
||||
extern pascal void GTEMoveSprite(Word spriteSlot, Word x, Word y) inline(0x11A0, tool_dispatcher);
|
||||
extern pascal void GTEUpdateSprite(Word spriteSlot, Word spriteFlags, Word vBuffAddr) inline(0x12A0, tool_dispatcher);
|
||||
extern pascal void GTERemoveSprite(Word spriteSlot) inline(0x13A0, tool_dispatcher);
|
||||
|
||||
|
||||
/* GTE Tile Routines */
|
||||
extern pascal void GTELoadTileSet(Word start, Word finish, Pointer tileSetPtr) inline(0x0EA0, tool_dispatcher);
|
||||
extern pascal void GTEFillTileStore(Word tileID) inline(0x25A0, tool_dispatcher);
|
||||
extern pascal void GTESetTile(Word xTile, Word yTile, Word tileID) inline(0x0BA0, tool_dispatcher);
|
||||
extern pascal void GTECopyTileToDynamic(Word tileID, Word dynID) inline(0x15A0, tool_dispatcher);
|
||||
extern pascal Word GTEGetTileAt(Word x, Word y) inline(0x1CA0, tool_dispatcher);
|
||||
extern pascal Pointer GTEGetTileDataAddr() inline(0x24A0, tool_dispatcher);
|
||||
|
||||
|
||||
/* GTE Primary Background Routines */
|
||||
extern pascal void GTESetBG0Origin(Word x, Word y) inline(0x0CA0, tool_dispatcher);
|
||||
extern pascal void GTERender(Word flags) inline(0x0DA0, tool_dispatcher);
|
||||
extern pascal void GTERefresh() inline(0x26A0, tool_dispatcher);
|
||||
extern pascal struct TileMapInfo GTEGetBG0TileMapInfo() inline(0x19A0, tool_dispatcher);
|
||||
extern pascal void GTESetBG0TileMapInfo(Word width, Word height, Pointer tileMapPtr) inline(0x1DA0, tool_dispatcher);
|
||||
|
||||
|
||||
/* GTE Secondary Background Routines */
|
||||
extern pascal void GTESetBG1Origin(Word x, Word y) inline(0x1BA0, tool_dispatcher);
|
||||
extern pascal void GTECopyPicToBG1(Word width, Word height, Word stride, Pointer picPtr) inline(0x17A0, tool_dispatcher);
|
||||
extern pascal void GTESetBG1TileMapInfo(Word width, Word height, Pointer tileMapPtr) inline(0x1EA0, tool_dispatcher);
|
||||
|
||||
|
||||
/* GTE Global State Functions */
|
||||
extern pascal void GTESetScreenMode(Word width, Word height) inline(0x0AA0, tool_dispatcher);
|
||||
extern pascal void GTESetPalette(Word palNum, Pointer palettePtr) inline(0x16A0, tool_dispatcher);
|
||||
extern pascal void GTEBindSCBArray(Pointer scbPtr) inline(0x18A0, tool_dispatcher);
|
||||
extern pascal struct ScreenInfo GTEGetScreenInfo() inline(0x1AA0, tool_dispatcher);
|
||||
extern pascal void GTESetBG1Displacement(Word offset) inline(0x27A0, tool_dispatcher);
|
||||
extern pascal void GTESetBG1Rotation(Word rotIndex) inline(0x28A0, tool_dispatcher);
|
||||
extern pascal void GTEClearBG1Buffer(Word value) inline(0x29A0, tool_dispatcher);
|
||||
|
||||
|
||||
/* GTE Misc. Functions */
|
||||
extern pascal Word GTEReadControl(void) inline(0x09A0, tool_dispatcher);
|
||||
extern pascal Word GTEGetSeconds(void) inline(0x14A0, tool_dispatcher);
|
||||
extern pascal Pointer GTEGetAddress(Word tableId) inline(0x2CA0, tool_dispatcher);
|
||||
extern pascal void GTESetAddress(Word tableId, Pointer pointer) inline(0x2EA0, tool_dispatcher);
|
||||
|
||||
|
||||
/* GTE Timer Functions */
|
||||
extern pascal Word GTEAddTimer(Word numTicks, Pointer callback, Word flags) inline(0x1FA0, tool_dispatcher);
|
||||
extern pascal Word GTERemoveTimer(Word timerID) inline(0x20A0, tool_dispatcher);
|
||||
extern pascal Word GTEStartScript(Word numTicks, Pointer scriptAddr) inline(0x21A0, tool_dispatcher);
|
||||
|
||||
|
||||
/* GTE Overlay Functions */
|
||||
extern pascal Word GTESetOverlay(Word top, Word bottom, Pointer procPtr) inline(0x22A0, tool_dispatcher);
|
||||
extern pascal Word GTEClearOverlay() inline(0x23A0, tool_dispatcher);
|
||||
|
||||
|
||||
/* ReadControl return value bits */
|
||||
#define PAD_BUTTON_B 0x0100
|
||||
#define PAD_BUTTON_A 0x0200
|
||||
#define PAD_KEY_DOWN 0x0400
|
||||
|
||||
/* GTE EngineMode definitions */
|
||||
#define ENGINE_MODE_TWO_LAYER 0x0001
|
||||
#define ENGINE_MODE_DYN_TILES 0x0002
|
||||
#define ENGINE_MODE_BNK0_BUFF 0x0004
|
||||
#define ENGINE_MODE_USER_TOOL 0x8000 /* Communicate if GTE is loaded as a system tool, or a user tool */
|
||||
|
||||
/* GTE Render Flags */
|
||||
#define RENDER_ALT_BG1 0x0001
|
||||
#define RENDER_BG1_HORZ_OFFSET 0x0002
|
||||
#define RENDER_BG1_VERT_OFFSET 0x0004
|
||||
#define RENDER_BG1_ROTATION 0x0008
|
||||
#define RENDER_PER_SCANLINE 0x0010
|
||||
#define RENDER_WITH_SHADOWING 0x0020
|
||||
#define RENDER_SPRITES_SORTED 0x0040
|
||||
|
||||
/* Overlay flags */
|
||||
#define OVERLAY_MASKED 0x0000 /* Overlay has a mask, so the background must be draw first */
|
||||
#define OVERLAY_SOLID 0x8000 /* Overlay covers the scan line and is fully opaque */
|
||||
#define OVERLAY_ABOVE 0x0000 /* Overlay is drawn above scanline sprites */
|
||||
#define OVERLAY_BELOW 0x4000 /* Overlay is drawn below scanline sprites */
|
||||
|
||||
/* GetAddress table IDs */
|
||||
#define scanlineHorzOffset 0x0001
|
||||
#define scanlineHorzOffset2 0x0002
|
||||
|
||||
/* CopyPicToBG1 flags */
|
||||
#define COPY_PIC_NORMAL 0x0000 /* Copy into BG1 buffer in "normal mode" */
|
||||
#define COPY_PIC_SCANLINE 0x0001 /* Copy in a way to support BG1 + RENDER_PER_SCANLINE. */
|
||||
|
||||
/* GTE Tile Constants */
|
||||
#define TILE_PRIORITY_BIT 0x4000 /* Put tile on top of sprite */
|
||||
#define TILE_FRINGE_BIT 0x2000 /* Unused */
|
||||
#define TILE_SOLID_BIT 0x1000 /* Hint bit used in TWO_LAYER_MODE to optimize rendering */
|
||||
#define TILE_DYN_BIT 0x0800 /* Is this a Dynamic Tile? */
|
||||
#define TILE_VFLIP_BIT 0x0400
|
||||
#define TILE_HFLIP_BIT 0x0200
|
||||
#define TILE_ID_MASK 0x01FF
|
||||
#define TILE_CTRL_MASK 0xFE00
|
||||
|
||||
/* GTE Sprite Constants */
|
||||
#define GTE_SPRITE_COMPILES 0x4000
|
||||
#define GTE_SPRITE_HIDE 0x2000
|
||||
#define GTE_SPRITE_16X16 0x1800
|
||||
#define GTE_SPRITE_16X8 0x1000
|
||||
#define GTE_SPRITE_8X16 0x0800
|
||||
#define GTE_SPRITE_8X8 0x0000
|
||||
#define GTE_SPRITE_VFLIP 0x0400
|
||||
#define GTE_SPRITE_HFLIP 0x0200
|
||||
|
||||
/* GTE Sprint Stamp Storage Parameters */
|
||||
#define GTE_VBUFF_STRIDE_BYTES (12 * 4) /* Each line has 4 slots of 16 pixels + 8 buffer pixels */
|
||||
#define GTE_VBUFF_TILE_ROW_BYTES (8 * GTE_VBUFF_STRIDE_BYTES) /* Each row is comprised of 8 lines */
|
||||
#define GTE_VBUFF_TILE_COL_BYTES (4)
|
||||
#define GTE_VBUFF_SPRITE_STEP (GTE_VBUFF_TILE_ROW_BYTES*3) /* Allocate space for 16 rows + 8 rows of buffer */
|
||||
#define GTE_VBUFF_SPRITE_START (GTE_VBUFF_TILE_ROW_BYTES+4) /* Start at an offset so $0000 can be used as an empty value */
|
||||
#define GTE_VBUFF_SLOT_COUNT (48) /* Have space for this many stamps */
|
||||
|
||||
|
||||
#endif /* _GTE_HEADER_INCLUDE_ */
|
|
@ -21,7 +21,11 @@ Each demo application has a build script that also builds the toolset and copies
|
|||
|
||||
## Dependencies
|
||||
|
||||
GTE uses the [merlin32](https://brutaldeluxe.fr/products/crossdevtools/merlin/) assembler to compile its source into GS/OS OMF files and [Cadius](https://brutaldeluxe.fr/products/crossdevtools/cadius/index.html) to copy those files onto a ProDOS disk image. The paths to these tool can be set in the `package.json` file.
|
||||
* node
|
||||
* merlin32 (1.1.10+)
|
||||
* cadius
|
||||
|
||||
GTE uses the [merlin32](https://brutaldeluxe.fr/products/crossdevtools/merlin/) [1.1.10](https://github.com/digarok/merlin32/releases/tag/v1.1.10) assembler to compile its source into GS/OS OMF files and [Cadius](https://brutaldeluxe.fr/products/crossdevtools/cadius/index.html) to copy those files onto a ProDOS disk image. The paths to these tool can be set in the `package.json` file.
|
||||
|
||||
An empty 2MG disk image is included in `emu/Target.2mg` and is used as the default location for copying demo applications. This image can be mounted in any IIgs emulator.
|
||||
|
||||
|
@ -30,7 +34,6 @@ An empty 2MG disk image is included in `emu/Target.2mg` and is used as the defau
|
|||
Build of demo app in the IIgs Finder
|
||||
</p>
|
||||
|
||||
|
||||
# Documentation
|
||||
|
||||
Please refer to the <a href="https://lscharen.github.io/iigs-game-engine/toolboxref.html">GTE Toolbox documentation</a>.
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
GTETool.SHK=Type(E0),AuxType(8002),VersionCreate(00),MinVersion(87),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000)
|
||||
Tool160.SHK=Type(E0),AuxType(8002),VersionCreate(00),MinVersion(B8),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000)
|
||||
CCode.SHK=Type(E0),AuxType(8002),VersionCreate(00),MinVersion(9C),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000)
|
||||
ChrisV.SHK=Type(E0),AuxType(8002),VersionCreate(00),MinVersion(BC),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
App
|
||||
main
|
||||
*.root
|
||||
*.sym
|
||||
*.a
|
|
@ -0,0 +1 @@
|
|||
App=Type(B3),AuxType(0000),VersionCreate(70),MinVersion(BE),Access(E3)
|
Binary file not shown.
After Width: | Height: | Size: 847 B |
|
@ -0,0 +1,17 @@
|
|||
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/ChrisV"
|
||||
|
||||
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% .\App
|
||||
%CADIUS% ADDFILE %IMAGE% %FOLDER% ..\..\src\Tool160
|
|
@ -0,0 +1,165 @@
|
|||
/* ********************************************************************
|
||||
|
||||
GTE is copyright Lucas Scharenbroich and licensed under the Apache-2.0
|
||||
License.
|
||||
|
||||
The following GTE function definitions are taken from the GTE Toolbox
|
||||
documentation:
|
||||
https://lscharen.github.io/iigs-game-engine/toolboxref.html
|
||||
|
||||
And from the GTE Macros:
|
||||
https://github.com/lscharen/iigs-game-engine/blob/d7be9f1be44748b0180c930b1f90b144cda661ea/macros/GTE.Macs.s
|
||||
|
||||
The contents of this file are a derivite work from GTE intended to
|
||||
ease the process of calling GTE / Tool 160 from ORCA/C and are believed
|
||||
to be permitted under the terms of the Apache-2.0 License.
|
||||
|
||||
********************************************************************* */
|
||||
|
||||
#ifndef _GTE_HEADER_INCLUDE_
|
||||
#define _GTE_HEADER_INCLUDE_
|
||||
|
||||
#include <types.h>
|
||||
|
||||
/*
|
||||
GTE_IS_SYSTEM_TOOLS_INSTALL is a boolean toggle for controlling what the application assumes about the location of the GTE tool.
|
||||
|
||||
If GTE is installed in System:Tools, GTE_IS_SYSTEM_TOOLS_INSTALL must be defined.
|
||||
Otherwise, GTE_IS_SYSTEM_TOOLS_INSTALL must be undefined.
|
||||
|
||||
This will control which header file is used as well as the calls used to load the tool during application startup.
|
||||
*/
|
||||
// #define GTE_IS_SYSTEM_TOOLS_INSTALL 1
|
||||
|
||||
#ifdef GTE_IS_SYSTEM_TOOLS_INSTALL
|
||||
#define tool_dispatcher dispatcher
|
||||
#else
|
||||
#define tool_dispatcher 0xE10008L
|
||||
#endif // GTE_IS_SYSTEM_TOOLS_INSTALL
|
||||
|
||||
typedef struct TileMapInfo {
|
||||
Word width;
|
||||
Word height;
|
||||
Pointer tileMapPtr;
|
||||
} TileMapInfo;
|
||||
|
||||
typedef struct ScreenInfo {
|
||||
Word x;
|
||||
Word y;
|
||||
Word width;
|
||||
Word height;
|
||||
} ScreenInfo;
|
||||
|
||||
/* GTE Housekeeping Routines */
|
||||
extern pascal void GTEBootInit(void) inline(0x01A0, tool_dispatcher);
|
||||
extern pascal void GTEStartUp(Word dPageAddr, Word capFlags, Word userID) inline(0x02A0, tool_dispatcher);
|
||||
extern pascal void GTEShutDown(void) inline(0x03A0, tool_dispatcher);
|
||||
extern pascal Word GTEVersion(void) inline(0x04A0, tool_dispatcher);
|
||||
extern pascal void GTEReset(void) inline(0x05A0, tool_dispatcher);
|
||||
extern pascal Word GTEStatus(void) inline(0x06A0, tool_dispatcher);
|
||||
|
||||
|
||||
/* GTE Sprite Routines */
|
||||
extern pascal void GTECreateSpriteStamp(Word spriteDescriptor, Word vBuffAddr) inline(0x0FA0, tool_dispatcher);
|
||||
extern pascal void GTEAddSprite(Word spriteSlot, Word spriteFlags, Word vBuffAddr, Word x, Word y) inline(0x10A0, tool_dispatcher);
|
||||
extern pascal void GTEMoveSprite(Word spriteSlot, Word x, Word y) inline(0x11A0, tool_dispatcher);
|
||||
extern pascal void GTEUpdateSprite(Word spriteSlot, Word spriteFlags, Word vBuffAddr) inline(0x12A0, tool_dispatcher);
|
||||
extern pascal void GTERemoveSprite(Word spriteSlot) inline(0x13A0, tool_dispatcher);
|
||||
|
||||
|
||||
/* GTE Tile Routines */
|
||||
extern pascal void GTELoadTileSet(Word start, Word finish, Pointer tileSetPtr) inline(0x0EA0, tool_dispatcher);
|
||||
extern pascal void GTEFillTileStore(Word tileID) inline(0x25A0, tool_dispatcher);
|
||||
extern pascal void GTESetTile(Word xTile, Word yTile, Word tileID) inline(0x0BA0, tool_dispatcher);
|
||||
extern pascal void GTECopyTileToDynamic(Word tileID, Word dynID) inline(0x15A0, tool_dispatcher);
|
||||
extern pascal Word GTEGetTileAt(Word x, Word y) inline(0x1CA0, tool_dispatcher);
|
||||
extern pascal Pointer GTEGetTileDataAddr() inline(0x24A0, tool_dispatcher);
|
||||
|
||||
|
||||
/* GTE Primary Background Routines */
|
||||
extern pascal void GTESetBG0Origin(Word x, Word y) inline(0x0CA0, tool_dispatcher);
|
||||
extern pascal void GTERender(Word flags) inline(0x0DA0, tool_dispatcher);
|
||||
extern pascal void GTERefresh() inline(0x26A0, tool_dispatcher);
|
||||
extern pascal struct TileMapInfo GTEGetBG0TileMapInfo() inline(0x19A0, tool_dispatcher);
|
||||
extern pascal void GTESetBG0TileMapInfo(Word width, Word height, Pointer tileMapPtr) inline(0x1DA0, tool_dispatcher);
|
||||
|
||||
|
||||
/* GTE Secondary Background Routines */
|
||||
extern pascal void GTESetBG1Origin(Word x, Word y) inline(0x1BA0, tool_dispatcher);
|
||||
extern pascal void GTECopyPicToBG1(Word width, Word height, Word stride, Pointer picPtr) inline(0x17A0, tool_dispatcher);
|
||||
extern pascal void GTESetBG1TileMapInfo(Word width, Word height, Pointer tileMapPtr) inline(0x1EA0, tool_dispatcher);
|
||||
|
||||
|
||||
/* GTE Global State Functions */
|
||||
extern pascal void GTESetScreenMode(Word width, Word height) inline(0x0AA0, tool_dispatcher);
|
||||
extern pascal void GTESetPalette(Word palNum, Pointer palettePtr) inline(0x16A0, tool_dispatcher);
|
||||
extern pascal void GTEBindSCBArray(Pointer scbPtr) inline(0x18A0, tool_dispatcher);
|
||||
extern pascal struct ScreenInfo GTEGetScreenInfo() inline(0x1AA0, tool_dispatcher);
|
||||
extern pascal void GTESetBG1Displacement(Word offset) inline(0x27A0, tool_dispatcher);
|
||||
extern pascal void GTESetBG1Rotation(Word rotIndex) inline(0x28A0, tool_dispatcher);
|
||||
extern pascal void GTEClearBG1Buffer(Word value) inline(0x29A0, tool_dispatcher);
|
||||
|
||||
|
||||
/* GTE Misc. Functions */
|
||||
extern pascal Word GTEReadControl(void) inline(0x09A0, tool_dispatcher);
|
||||
extern pascal Word GTEGetSeconds(void) inline(0x14A0, tool_dispatcher);
|
||||
|
||||
|
||||
/* GTE Timer Functions */
|
||||
extern pascal Word GTEAddTimer(Word numTicks, Pointer callback, Word flags) inline(0x1FA0, tool_dispatcher);
|
||||
extern pascal Word GTERemoveTimer(Word timerID) inline(0x20A0, tool_dispatcher);
|
||||
extern pascal Word GTEStartScript(Word numTicks, Pointer scriptAddr) inline(0x21A0, tool_dispatcher);
|
||||
|
||||
|
||||
/* GTE Overlay Functions */
|
||||
extern pascal Word GTESetOverlay(Word top, Word bottom, Pointer procPtr) inline(0x22A0, tool_dispatcher);
|
||||
extern pascal Word GTEClearOverlay() inline(0x23A0, tool_dispatcher);
|
||||
|
||||
|
||||
/* ReadControl return value bits */
|
||||
#define PAD_BUTTON_B 0x0100
|
||||
#define PAD_BUTTON_A 0x0200
|
||||
#define PAD_KEY_DOWN 0x0400
|
||||
|
||||
/* GTE EngineMode definitions */
|
||||
#define ENGINE_MODE_TWO_LAYER 0x0001
|
||||
#define ENGINE_MODE_DYN_TILES 0x0002
|
||||
#define ENGINE_MODE_BNK0_BUFF 0x0004
|
||||
#define ENGINE_MODE_USER_TOOL 0x8000 /* Communicate if GTE is loaded as a system tool, or a user tool */
|
||||
|
||||
/* GTE Render Flags */
|
||||
#define RENDER_ALT_BG1 0x0001
|
||||
#define RENDER_BG1_HORZ_OFFSET 0x0002
|
||||
#define RENDER_BG1_VERT_OFFSET 0x0004
|
||||
#define RENDER_BG1_ROTATION 0x0008
|
||||
|
||||
/* GTE Tile Constants */
|
||||
#define TILE_PRIORITY_BIT 0x4000 /* Put tile on top of sprite */
|
||||
#define TILE_FRINGE_BIT 0x2000 /* Unused */
|
||||
#define TILE_SOLID_BIT 0x1000 /* Hint bit used in TWO_LAYER_MODE to optimize rendering */
|
||||
#define TILE_DYN_BIT 0x0800 /* Is this a Dynamic Tile? */
|
||||
#define TILE_VFLIP_BIT 0x0400
|
||||
#define TILE_HFLIP_BIT 0x0200
|
||||
#define TILE_ID_MASK 0x01FF
|
||||
#define TILE_CTRL_MASK 0xFE00
|
||||
|
||||
/* GTE Sprite Constants */
|
||||
#define GTE_SPRITE_HIDE 0x2000
|
||||
#define GTE_SPRITE_16X16 0x1800
|
||||
#define GTE_SPRITE_16X8 0x1000
|
||||
#define GTE_SPRITE_8X16 0x0800
|
||||
#define GTE_SPRITE_8X8 0x0000
|
||||
#define GTE_SPRITE_VFLIP 0x0400
|
||||
#define GTE_SPRITE_HFLIP 0x0200
|
||||
|
||||
|
||||
/* GTE Sprint Stamp Storage Parameters */
|
||||
#define GTE_VBUFF_STRIDE_BYTES (12 * 4) /* Each line has 4 slots of 16 pixels + 8 buffer pixels */
|
||||
#define GTE_VBUFF_TILE_ROW_BYTES (8 * GTE_VBUFF_STRIDE_BYTES) /* Each row is comprised of 8 lines */
|
||||
#define GTE_VBUFF_TILE_COL_BYTES (4)
|
||||
#define GTE_VBUFF_SPRITE_STEP (GTE_VBUFF_TILE_ROW_BYTES*3) /* Allocate space for 16 rows + 8 rows of buffer */
|
||||
#define GTE_VBUFF_SPRITE_START (GTE_VBUFF_TILE_ROW_BYTES+4) /* Start at an offset so $0000 can be used as an empty value */
|
||||
#define GTE_VBUFF_SLOT_COUNT (48) /* Have space for this many stamps */
|
||||
|
||||
|
||||
#endif /* _GTE_HEADER_INCLUDE_ */
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"name": "chrisv-c-demo",
|
||||
"version": "1.0.0",
|
||||
"description": "Using GTE from C",
|
||||
"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",
|
||||
"png2iigs": "../../tools/png2iigs.js"
|
||||
},
|
||||
"scripts": {
|
||||
"gsport": "%npm_package_config_gsport%",
|
||||
"test:all": "npm run build && npm run build:image && %npm_package_config_gsport%",
|
||||
"build": "npm run build:tool && npm run build:sys16",
|
||||
"test": "npm run build:sys16 && npm run build:image && %npm_package_config_gsport%",
|
||||
"build:image": "build-image.bat %npm_package_config_cadius%",
|
||||
"build:sys16": "iix compile foo.c test.c && iix -DKeepType=S16 link test foo keep=App",
|
||||
"build:tiles": "node %npm_package_config_png2iigs% ./assets/tileset.png --format orcac --max-tiles 160 --as-tile-data --verbose > tileData.c",
|
||||
"build:tool": "%npm_package_config_merlin32% -V %npm_package_config_macros% ../../src/Master.s",
|
||||
"debug": "%npm_package_config_crossrunner% ./App -Debug -CompatibilityLayer"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
#include <loader.h>
|
||||
#include <locator.h>
|
||||
#include <memory.h>
|
||||
#include <misctool.h>
|
||||
#include <types.h>
|
||||
|
||||
/* #define GTE_IS_SYSTEM_TOOLS_INSTALL 1 */
|
||||
#include "gte.h"
|
||||
|
||||
#ifdef GTE_IS_SYSTEM_TOOLS_INSTALL
|
||||
#define ENGINE_STARTUP_MODE 0x0000
|
||||
#else
|
||||
#define ENGINE_STARTUP_MODE ENGINE_MODE_USER_TOOL
|
||||
#endif
|
||||
|
||||
/* toolbox fail handler */
|
||||
#define TOOLFAIL(string) if (toolerror()) SysFailMgr(toolerror(), "\p" string "\n\r Error Code -> $");
|
||||
|
||||
/* path to the local GTE toolset */
|
||||
Str32 toolPath = {9, "1/Tool160" };
|
||||
|
||||
/* Helper function to load GTE as a user tool or system tool */
|
||||
#ifdef GTE_IS_SYSTEM_TOOLS_INSTALL
|
||||
void LoadGTEToolSet(Word unused) {
|
||||
LoadOneTool(160, 0);
|
||||
TOOLFAIL("Unable to load GTE toolset");
|
||||
}
|
||||
#else
|
||||
void LoadGTEToolSet(Word userId) {
|
||||
InitialLoadOutputRec loadRec;
|
||||
|
||||
// Load the tool from the local directory
|
||||
loadRec = InitialLoad(userId, (Pointer) (&toolPath), 1);
|
||||
TOOLFAIL("Unable to load Tool160 from local path");
|
||||
|
||||
// Install the tool using the user tool vector
|
||||
SetTSPtr(0x8000, 160, loadRec.startAddr);
|
||||
TOOLFAIL("Could not install tool");
|
||||
}
|
||||
#endif // GTE_IS_SYSTEM_TOOLS_INSTALL
|
||||
|
||||
#ifdef GTE_IS_SYSTEM_TOOLS_INSTALL
|
||||
void UnloadGTEToolSet() {
|
||||
UnloadOneTool(160);
|
||||
TOOLFAIL("Unable to unload GTE toolset");
|
||||
}
|
||||
#else
|
||||
void UnloadGTEToolSet() {
|
||||
}
|
||||
#endif // GTE_IS_SYSTEM_TOOLS_INSTALL
|
||||
|
||||
extern Byte tiles[];
|
||||
extern Word tilesPalette[16];
|
||||
|
||||
void main(void) {
|
||||
Word userId;
|
||||
Word tileId;
|
||||
Word controlMask, keyPress;
|
||||
Handle dpHandle;
|
||||
Word dpAddr;
|
||||
int a, b;
|
||||
|
||||
TLStartUp();
|
||||
TOOLFAIL("Unable to start tool locator");
|
||||
|
||||
userId = MMStartUp();
|
||||
TOOLFAIL("Unable to start memory manager");
|
||||
|
||||
MTStartUp();
|
||||
TOOLFAIL("Unable to start misc tools");
|
||||
|
||||
LoadGTEToolSet(userId);
|
||||
|
||||
dpHandle = NewHandle(0x200L, userId, attrBank + attrPage + attrFixed + attrLocked + attrNoCross, 0);
|
||||
TOOLFAIL("Could not allocate direct page memory for GTE");
|
||||
dpAddr = (Word) (*dpHandle);
|
||||
|
||||
GTEStartUp(dpAddr, (Word) ENGINE_STARTUP_MODE, userId);
|
||||
|
||||
/* GTESetScreenMode(160, 200); /* 160x200 is the default screen mode */
|
||||
GTESetPalette(0, (Pointer)tilesPalette);
|
||||
GTELoadTileSet(0, 160, tiles); /* Load in the tiles */
|
||||
|
||||
GTEFillTileStore(1);
|
||||
GTERender(0);
|
||||
|
||||
for (a = 3; a < 18; a++) {
|
||||
GTESetTile(a, a, 5);
|
||||
}
|
||||
GTESetTile(1, 0, 34);
|
||||
GTESetTile(2, 0, 33);
|
||||
GTERender(0);
|
||||
|
||||
GTESetTile(0, 3, 3);
|
||||
GTESetTile(0, 4, 4);
|
||||
for (b = 4; b < 6; b++) {
|
||||
for (a = 1; a < 10; a++) {
|
||||
GTESetBG0Origin(a, b);
|
||||
tileId = (((b - 1) * 32) + a) | TILE_SOLID_BIT | TILE_HFLIP_BIT;
|
||||
GTESetTile(a, b, tileId);
|
||||
GTERender(0);
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
controlMask = GTEReadControl();
|
||||
keyPress = controlMask & 0x007F;
|
||||
} while (keyPress != 'Q');
|
||||
|
||||
GTEShutDown();
|
||||
UnloadGTEToolSet();
|
||||
|
||||
DisposeHandle(dpHandle);
|
||||
MTShutDown();
|
||||
MMShutDown(userId);
|
||||
TLShutDown();
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -35,8 +35,18 @@ MaxGlobalX equ 16
|
|||
MaxGlobalY equ 18
|
||||
MaxBG0X equ 20
|
||||
MaxBG0Y equ 22
|
||||
frameCount equ 24
|
||||
OldOneSecondCounter equ 26
|
||||
appTmp0 equ 28
|
||||
seg1x equ 30
|
||||
seg2x equ 32
|
||||
seg3x equ 34
|
||||
seg4x equ 36 ; BG1 x-pos
|
||||
frameCountTotal equ 38
|
||||
PlayerX equ 40
|
||||
PlayerY equ 42
|
||||
PlayerXVel equ 44
|
||||
PlayerYVel equ 46
|
||||
|
||||
phk
|
||||
plb
|
||||
|
@ -47,15 +57,9 @@ appTmp0 equ 28
|
|||
|
||||
_MTStartUp ; GTE requires the miscellaneous toolset to be running
|
||||
|
||||
lda #0 ; Engine in Fast Mode
|
||||
lda #ENGINE_MODE_USER_TOOL+ENGINE_MODE_TWO_LAYER ; Engine in Fast Mode as a User Tool
|
||||
jsr GTEStartUp ; Load and install the GTE User Tool
|
||||
|
||||
; Initialize local variables
|
||||
|
||||
stz StartX
|
||||
stz StartY
|
||||
stz frameCount
|
||||
|
||||
; Initialize the graphics screen playfield
|
||||
|
||||
pea #160
|
||||
|
@ -64,6 +68,8 @@ appTmp0 equ 28
|
|||
|
||||
; Load a tileset
|
||||
|
||||
pea 0
|
||||
pea 256
|
||||
pea #^tiledata
|
||||
pea #tiledata
|
||||
_GTELoadTileSet
|
||||
|
@ -73,10 +79,38 @@ appTmp0 equ 28
|
|||
pea #TileSetPalette
|
||||
_GTESetPalette
|
||||
|
||||
pea $0
|
||||
_GTEClearBG1Buffer
|
||||
|
||||
; Set up our level data
|
||||
|
||||
jsr BG0SetUp
|
||||
; jsr BG0SetUp
|
||||
pea 416
|
||||
pea 30
|
||||
pea ^App_TileMapBG0
|
||||
pea App_TileMapBG0+{10*416}
|
||||
_GTESetBG0TileMapInfo
|
||||
|
||||
stz seg1x
|
||||
stz seg2x
|
||||
stz seg3x
|
||||
stz seg4x
|
||||
|
||||
jsr SetLimits
|
||||
jsr DoLoadBG1
|
||||
|
||||
; Initialize local variables
|
||||
|
||||
lda #56
|
||||
sta StartX
|
||||
lda #0
|
||||
sta StartY
|
||||
stz frameCount
|
||||
stz frameCountTotal
|
||||
|
||||
pei StartX
|
||||
pei StartY
|
||||
_GTESetBG0Origin
|
||||
|
||||
lda #193 ; Tile ID of '0'
|
||||
jsr InitOverlay ; Initialize the status bar
|
||||
|
@ -86,6 +120,59 @@ appTmp0 equ 28
|
|||
sta OldOneSecondCounter
|
||||
jsr UdtOverlay
|
||||
|
||||
; Create some sprites
|
||||
lda #16
|
||||
sta PlayerX
|
||||
|
||||
lda MaxGlobalY
|
||||
sec
|
||||
sbc #48 ; 32 for tiles, 16 for sprite
|
||||
lda #48 ; 32 for tiles, 16 for sprite
|
||||
sta PlayerY
|
||||
stz PlayerXVel
|
||||
stz PlayerYVel
|
||||
|
||||
HERO_SIZE equ {SPRITE_16X16}
|
||||
HERO_FLAGS equ HERO_SIZE ; no extra H/V bits for now
|
||||
HERO_FRAME_1 equ HERO_SIZE+145
|
||||
HERO_VBUFF_1 equ VBUFF_SPRITE_START+0*VBUFF_SPRITE_STEP
|
||||
HERO_SLOT equ 1
|
||||
|
||||
pea HERO_FRAME_1
|
||||
pea HERO_VBUFF_1
|
||||
_GTECreateSpriteStamp
|
||||
|
||||
pha ; Space for result
|
||||
pea HERO_SIZE
|
||||
pea HERO_VBUFF_1
|
||||
_GTECompileSpriteStamp
|
||||
pla
|
||||
|
||||
pea HERO_SLOT ; Put the player in slot 1
|
||||
pea HERO_FLAGS+SPRITE_COMPILED ; mark this as a compiled sprite (can only use in RENDER_WITH_SHADOWING mode)
|
||||
pha ; pass in the token of the compiled stamp
|
||||
pei PlayerX
|
||||
pei PlayerY
|
||||
_GTEAddSprite
|
||||
|
||||
; Set up the per-scanline rendering
|
||||
|
||||
lda StartX
|
||||
jsr InitOffsets
|
||||
|
||||
pea #scanlineHorzOffset
|
||||
pea #^BG0Offsets
|
||||
pea #BG0Offsets
|
||||
_GTESetAddress
|
||||
|
||||
pea #scanlineHorzOffset2
|
||||
pea #^BG1Offsets
|
||||
pea #BG1Offsets
|
||||
_GTESetAddress
|
||||
|
||||
pea #RENDER_WITH_SHADOWING ; one regular render to fill the screen with the tilemap
|
||||
_GTERender
|
||||
|
||||
; Set up a very specific test. First, we draw a sprite into the sprite plane, and then
|
||||
; leave it alone. We are just testing the ability to merge sprite plane data into
|
||||
; the play field tiles.
|
||||
|
@ -101,26 +188,15 @@ EvtLoop
|
|||
:do_more
|
||||
cmp #'d'
|
||||
bne :not_d
|
||||
lda StartX
|
||||
cmp MaxBG0X
|
||||
bcc *+5
|
||||
brl :do_render
|
||||
inc StartX
|
||||
pei StartX
|
||||
pei StartY
|
||||
_GTESetBG0Origin
|
||||
jsr DecRanges
|
||||
jsr SetOffsets
|
||||
brl :do_render
|
||||
:not_d
|
||||
|
||||
cmp #'a'
|
||||
bne :not_a
|
||||
lda StartX
|
||||
bne *+5
|
||||
brl :do_render
|
||||
dec StartX
|
||||
pei StartX
|
||||
pei StartY
|
||||
_GTESetBG0Origin
|
||||
jsr IncRanges
|
||||
jsr SetOffsets
|
||||
brl :do_render
|
||||
:not_a
|
||||
|
||||
|
@ -148,12 +224,27 @@ EvtLoop
|
|||
:not_w
|
||||
|
||||
:do_render
|
||||
pea $0000
|
||||
jsr SetBG1Animation ; Update the per-scanline BG1 offsets
|
||||
|
||||
jsr _GetVBLTicks
|
||||
and #$00FC
|
||||
lsr
|
||||
lsr
|
||||
sta PlayerX
|
||||
|
||||
pea HERO_SLOT
|
||||
pei PlayerX
|
||||
pei PlayerY
|
||||
_GTEMoveSprite ; Move the sprite to this local position
|
||||
|
||||
pea #RENDER_PER_SCANLINE
|
||||
; pea #0
|
||||
_GTERender
|
||||
|
||||
; Update the performance counters
|
||||
|
||||
inc frameCount
|
||||
inc frameCountTotal
|
||||
pha
|
||||
_GTEGetSeconds
|
||||
pla
|
||||
|
@ -180,6 +271,13 @@ qtRec adrl $0000
|
|||
; Color palette
|
||||
MyDirectPage ds 2
|
||||
|
||||
_GetVBLTicks
|
||||
PushLong #0
|
||||
_GetTick
|
||||
pla
|
||||
plx
|
||||
rts
|
||||
|
||||
SetLimits
|
||||
pha ; Allocate space for width (in tiles), height (in tiles), pointer
|
||||
pha
|
||||
|
@ -238,7 +336,211 @@ SetLimits
|
|||
|
||||
rts
|
||||
|
||||
frameCount equ 24
|
||||
DecRanges
|
||||
lda seg1x
|
||||
bne *+5
|
||||
lda #164
|
||||
dec
|
||||
sta seg1x
|
||||
bit #1
|
||||
bne :out
|
||||
lda seg2x
|
||||
bne *+5
|
||||
lda #164
|
||||
dec
|
||||
sta seg2x
|
||||
bit #1
|
||||
bne :out
|
||||
lda seg3x
|
||||
bne *+5
|
||||
lda #164
|
||||
dec
|
||||
sta seg3x
|
||||
:out
|
||||
rts
|
||||
|
||||
IncRanges
|
||||
lda seg1x
|
||||
inc
|
||||
cmp #164
|
||||
bcc *+5
|
||||
lda #0
|
||||
sta seg1x
|
||||
bit #1
|
||||
bne :out
|
||||
lda seg2x
|
||||
inc
|
||||
cmp #164
|
||||
bcc *+5
|
||||
lda #0
|
||||
sta seg2x
|
||||
bit #1
|
||||
bne :out
|
||||
lda seg3x
|
||||
inc
|
||||
cmp #164
|
||||
bcc *+5
|
||||
lda #0
|
||||
sta seg3x
|
||||
bit #1
|
||||
bne :out
|
||||
lda seg4x
|
||||
inc
|
||||
cmp #164
|
||||
bcc *+5
|
||||
lda #0
|
||||
sta seg4x
|
||||
:out
|
||||
rts
|
||||
|
||||
|
||||
InitOffsets
|
||||
pha
|
||||
|
||||
ldx #0
|
||||
ldy #40
|
||||
jsr _InitRange
|
||||
ldx #40
|
||||
ldy #80
|
||||
jsr _InitRange
|
||||
ldx #120
|
||||
ldy #88
|
||||
jsr _InitRange
|
||||
jsr _InitBG1
|
||||
|
||||
pla
|
||||
sta seg1x
|
||||
jsr SetOffset1
|
||||
lsr
|
||||
sta seg2x
|
||||
jsr SetOffset2
|
||||
lsr
|
||||
sta seg3x
|
||||
jsr SetOffset3
|
||||
jsr SetBG1Offsets
|
||||
rts
|
||||
|
||||
SetOffsets
|
||||
lda seg1x
|
||||
jsr SetOffset1
|
||||
lda seg2x
|
||||
jsr SetOffset2
|
||||
lda seg3x
|
||||
jsr SetOffset3
|
||||
|
||||
SetBG1Offsets
|
||||
pei seg4x
|
||||
pea 0
|
||||
_GTESetBG1Origin
|
||||
rts
|
||||
|
||||
SetBG1Animation
|
||||
pea #scanlineHorzOffset2
|
||||
pea #^BG1Offsets
|
||||
lda frameCountTotal
|
||||
and #$000F
|
||||
asl
|
||||
adc #BG1Offsets
|
||||
pha
|
||||
_GTESetAddress
|
||||
rts
|
||||
|
||||
SetOffset1
|
||||
ldx #120
|
||||
ldy #88
|
||||
jmp _SetRange
|
||||
SetOffset2
|
||||
ldx #40
|
||||
ldy #80
|
||||
jmp _SetRange
|
||||
SetOffset3
|
||||
ldx #0
|
||||
ldy #40
|
||||
jmp _SetRange
|
||||
|
||||
_SetRange
|
||||
pha
|
||||
|
||||
txa
|
||||
asl
|
||||
tax
|
||||
|
||||
:loop2 lda BG0Offsets,x
|
||||
and #$FF00
|
||||
ora 1,s
|
||||
sta BG0Offsets,x
|
||||
|
||||
dey
|
||||
beq :done
|
||||
|
||||
inx
|
||||
inx
|
||||
cpx #416
|
||||
bcc :loop2
|
||||
:done
|
||||
pla
|
||||
rts
|
||||
|
||||
_offsets dw 0,0,0,1,1,2,3,3,4,4,4,3,3,2,1,1
|
||||
_InitBG1
|
||||
ldx #0
|
||||
ldy #0
|
||||
:loop lda _offsets,y
|
||||
sta BG1Offsets,x
|
||||
iny
|
||||
iny
|
||||
cpy #31
|
||||
bcc *+5
|
||||
ldy #0
|
||||
|
||||
inx
|
||||
inx
|
||||
cpx #448
|
||||
bcc :loop
|
||||
rts
|
||||
|
||||
_InitRange
|
||||
txa
|
||||
asl
|
||||
tax
|
||||
|
||||
tya
|
||||
dec
|
||||
and #$00FF
|
||||
xba
|
||||
|
||||
:loop1 sta BG0Offsets,x
|
||||
sec
|
||||
sbc #$0100
|
||||
dey
|
||||
beq :done
|
||||
inx
|
||||
inx
|
||||
cpx #416
|
||||
bcc :loop1
|
||||
:done
|
||||
rts
|
||||
|
||||
; Load a binary file in the BG1 buffer
|
||||
DoLoadBG1
|
||||
jsr AllocBank ; Alloc 64KB for Load/Unpack
|
||||
sta BankLoad ; Store "Bank Pointer"
|
||||
ldx #BG1DataFile ; Load the background file into the bank
|
||||
jsr LoadFile
|
||||
|
||||
pea #164 ; Fill everything
|
||||
pea #200
|
||||
pea #256
|
||||
lda BankLoad
|
||||
pha
|
||||
pea $0000
|
||||
pea COPY_PIC_SCANLINE ; Copy in a mode that supports per-scanline offsets
|
||||
_GTECopyPicToBG1
|
||||
rts
|
||||
|
||||
BG1DataFile strl '1/bg1.bin'
|
||||
BG0Offsets ds 416
|
||||
BG1Offsets ds 448 ; Make this a bit larger so we can just update a pointer
|
||||
|
||||
PUT ../StartUp.s
|
||||
PUT ../../shell/Overlay.s
|
||||
|
|
|
@ -14,4 +14,5 @@ REM Cadius does not overwrite files, so clear the root folder first
|
|||
|
||||
REM Now copy files and folders as needed
|
||||
%CADIUS% ADDFILE %IMAGE% %FOLDER% .\GTEDemo1
|
||||
%CADIUS% ADDFILE %IMAGE% %FOLDER% .\gen\bg1.bin
|
||||
%CADIUS% ADDFILE %IMAGE% %FOLDER% ..\..\..\src\Tool160
|
||||
|
|
Binary file not shown.
|
@ -61,7 +61,7 @@ Scale equ 56
|
|||
|
||||
_MTStartUp ; GTE requires the miscellaneous toolset to be running
|
||||
|
||||
lda #ENGINE_MODE_TWO_LAYER+ENGINE_MODE_DYN_TILES
|
||||
lda #ENGINE_MODE_USER_TOOL+ENGINE_MODE_TWO_LAYER ; +ENGINE_MODE_DYN_TILES
|
||||
jsr GTEStartUp ; Load and install the GTE User Tool
|
||||
|
||||
; Initialize local variables
|
||||
|
|
|
@ -47,7 +47,7 @@ appTmp0 equ 28
|
|||
|
||||
_MTStartUp ; GTE requires the miscellaneous toolset to be running
|
||||
|
||||
lda #ENGINE_MODE_DYN_TILES ; Engine in Fast Mode
|
||||
lda #ENGINE_MODE_USER_TOOL+ENGINE_MODE_DYN_TILES ; Engine in Fast Mode
|
||||
jsr GTEStartUp ; Load and install the GTE User Tool
|
||||
|
||||
; Initialize local variables
|
||||
|
|
|
@ -56,7 +56,7 @@ appTmp2 equ 32
|
|||
|
||||
_MTStartUp ; GTE requires the miscellaneous toolset to be running
|
||||
|
||||
lda #ENGINE_MODE_DYN_TILES ; Engine in Fast Mode
|
||||
lda #ENGINE_MODE_USER_TOOL+ENGINE_MODE_DYN_TILES ; Engine in Fast Mode
|
||||
jsr GTEStartUp ; Load and install the GTE User Tool
|
||||
|
||||
; Initialize local variables
|
||||
|
|
|
@ -49,7 +49,7 @@ appTmp2 equ 32
|
|||
|
||||
_MTStartUp ; GTE requires the miscellaneous toolset to be running
|
||||
|
||||
lda #ENGINE_MODE_TWO_LAYER+ENGINE_MODE_DYN_TILES
|
||||
lda #ENGINE_MODE_USER_TOOL+ENGINE_MODE_TWO_LAYER ; +ENGINE_MODE_DYN_TILES
|
||||
jsr GTEStartUp ; Load and install the GTE User Tool
|
||||
|
||||
; Initialize local variables
|
||||
|
@ -60,12 +60,14 @@ appTmp2 equ 32
|
|||
|
||||
; Initialize the graphics screen playfield
|
||||
|
||||
pea #320
|
||||
pea #160
|
||||
pea #200
|
||||
_GTESetScreenMode
|
||||
|
||||
; Load a tileset
|
||||
|
||||
pea #0
|
||||
pea #511
|
||||
pea #^tiledata
|
||||
pea #tiledata
|
||||
_GTELoadTileSet
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -14,17 +14,17 @@
|
|||
},
|
||||
"scripts": {
|
||||
"test": "npm run build && npm run build:image && npm run gsport",
|
||||
"gsport": "%npm_package_config_gsport%",
|
||||
"debug": "%npm_package_config_crossrunner% GTEDemo4 -Source GTEDemo4_S02_MAINSEG_Output.txt -Debug -CompatibilityLayer",
|
||||
"gsport": "cross-var $npm_package_config_gsport",
|
||||
"debug": "cross-var $npm_package_config_crossrunner GTEDemo4 -Source GTEDemo4_S02_MAINSEG_Output.txt -Debug -CompatibilityLayer",
|
||||
"build:all": "npm run build:tiles && npm run build:map && npm run build:tool && npm run build:sys16 && npm run build:image",
|
||||
"build:map": "node %npm_package_config_tiled2iigs% ./assets/tiled/yoshi-1.json --force-masked --no-gen-tiles --output-dir ./gen",
|
||||
"build:tiles": "node %npm_package_config_png2iigs% ./assets/tilesets/smw-256x128-4bpp.png --max-tiles 360 --as-tile-data --verbose --transparent-color FF00FF --background-color 216058 > ./gen/App.TileSet.s",
|
||||
"build:tiles:blocky": "node %npm_package_config_png2iigs% ./assets/tilesets/smw-256x128-4bpp.png --max-tiles 360 --as-tile-data --verbose --force-word-alignment --transparent-color FF00FF --background-color 216058 > ./gen/App.TileSet.s",
|
||||
"build:sys16": "%npm_package_config_merlin32% -V %npm_package_config_macros% App.s",
|
||||
"build:map": "cross-var node $npm_package_config_tiled2iigs ./assets/tiled/yoshi-1.json --force-masked --no-gen-tiles --output-dir ./gen",
|
||||
"build:tiles": "cross-var node $npm_package_config_png2iigs ./assets/tilesets/smw-256x128-4bpp.png --max-tiles 360 --as-tile-data --var-name tiledata --verbose --transparent-color FF00FF --background-color 216058 > ./gen/App.TileSet.s",
|
||||
"build:tiles:blocky": "cross-var node $npm_package_config_png2iigs ./assets/tilesets/smw-256x128-4bpp.png --max-tiles 360 --as-tile-data --var-name tiledata --verbose --force-word-alignment --transparent-color FF00FF --background-color 216058 > ./gen/App.TileSet.s",
|
||||
"build:sys16": "cross-var $npm_package_config_merlin32 -V $npm_package_config_macros App.s",
|
||||
"build": "npm run build:tool && npm run build:sys16",
|
||||
"build:tool": "%npm_package_config_merlin32% -V %npm_package_config_macros% ../../../src/Master.s",
|
||||
"build:image": "build-image.bat %npm_package_config_cadius%",
|
||||
"build:background": "node %npm_package_config_png2iigs% ./assets/tilesets/bg1.png ./gen/bg1.bin --force-color-match --palette FF00FF,C14F4A,020202,00E100,C89858,216058,DCE9EE,008000,F80080,F5D56C,20308F,A0CDCC,4080A0,70B0D0"
|
||||
"build:tool": "cross-var $npm_package_config_merlin32 -V $npm_package_config_macros ../../../src/Master.s",
|
||||
"build:image": "cross-var build-image.bat $npm_package_config_cadius",
|
||||
"build:background": "cross-var node $npm_package_config_png2iigs ./assets/tilesets/bg1.png ./gen/bg1.bin --force-color-match --palette FF00FF,C14F4A,020202,00E100,C89858,216058,DCE9EE,008000,F80080,F5D56C,20308F,A0CDCC,4080A0,70B0D0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -37,6 +37,7 @@
|
|||
},
|
||||
"homepage": "https://github.com/lscharen/iigs-game-engine#readme",
|
||||
"devDependencies": {
|
||||
"cross-var": "^1.1.0",
|
||||
"pngjs": "^6.0.0",
|
||||
"string-builder": "^0.1.8",
|
||||
"watch": "latest",
|
||||
|
|
|
@ -36,6 +36,7 @@ MaxGlobalX equ 16
|
|||
MaxGlobalY equ 18
|
||||
MaxBG0X equ 20
|
||||
MaxBG0Y equ 22
|
||||
frameCount equ 24
|
||||
OldOneSecondCounter equ 26
|
||||
appTmp0 equ 28
|
||||
PlayerX equ 30
|
||||
|
@ -49,6 +50,10 @@ LastHFlip equ 44
|
|||
SpriteFrame equ 46
|
||||
SpriteToggle equ 48
|
||||
SpriteCount equ 50
|
||||
PlayerX1 equ 52
|
||||
PlayerY1 equ 54
|
||||
PlayerX2 equ 56
|
||||
PlayerY2 equ 58
|
||||
|
||||
phk
|
||||
plb
|
||||
|
@ -59,10 +64,11 @@ SpriteCount equ 50
|
|||
|
||||
_MTStartUp ; GTE requires the miscellaneous toolset to be running
|
||||
|
||||
lda #0 ; Engine in Fast Mode
|
||||
lda #ENGINE_MODE_USER_TOOL ; Engine in Fast Mode
|
||||
jsr GTEStartUp ; Load and install the GTE User Tool
|
||||
jsr SoundStartUp
|
||||
jsr StartMusic
|
||||
|
||||
; jsr SoundStartUp
|
||||
; jsr StartMusic
|
||||
|
||||
; Initialize local variables
|
||||
|
||||
|
@ -81,6 +87,8 @@ SpriteCount equ 50
|
|||
|
||||
; Load a tileset
|
||||
|
||||
pea #0
|
||||
pea #511
|
||||
pea #^tiledata
|
||||
pea #tiledata
|
||||
_GTELoadTileSet
|
||||
|
@ -108,15 +116,28 @@ SpriteCount equ 50
|
|||
lda #16
|
||||
sta PlayerGlobalX
|
||||
sta PlayerX
|
||||
sta PlayerX1
|
||||
sta PlayerX2
|
||||
|
||||
lda MaxGlobalY
|
||||
sec
|
||||
sbc #48 ; 32 for tiles, 16 for sprite
|
||||
lda #48 ; 32 for tiles, 16 for sprite
|
||||
sta PlayerGlobalY
|
||||
sta PlayerY
|
||||
sta PlayerY1
|
||||
sta PlayerY2
|
||||
|
||||
stz PlayerXVel
|
||||
stz PlayerYVel
|
||||
|
||||
; Set the screen to the bottom-left
|
||||
|
||||
pea $0000
|
||||
lda MaxBG0Y
|
||||
pha
|
||||
_GTESetBG0Origin
|
||||
|
||||
; Create the sprites
|
||||
|
||||
HERO_SIZE equ {SPRITE_16X16}
|
||||
|
@ -131,6 +152,8 @@ HERO_FRAME_4 equ HERO_SIZE+151
|
|||
HERO_VBUFF_4 equ VBUFF_SPRITE_START+3*VBUFF_SPRITE_STEP
|
||||
HERO_SLOT equ 1
|
||||
|
||||
; Create stamps of each sprite
|
||||
|
||||
pea HERO_FRAME_1
|
||||
pea HERO_VBUFF_1
|
||||
_GTECreateSpriteStamp
|
||||
|
@ -147,13 +170,39 @@ HERO_SLOT equ 1
|
|||
pea HERO_VBUFF_4
|
||||
_GTECreateSpriteStamp
|
||||
|
||||
; Compile the sprite stamps and hold the compilation token
|
||||
|
||||
pha ; Space for result
|
||||
pea HERO_SIZE
|
||||
pea HERO_VBUFF_1
|
||||
_GTECompileSpriteStamp
|
||||
pla
|
||||
|
||||
pea HERO_SLOT ; Put the player in slot 1
|
||||
pea HERO_FLAGS
|
||||
pea HERO_VBUFF_1 ; and use this stamp
|
||||
pea HERO_FLAGS+SPRITE_COMPILED ; mark this as a compiled sprite (can only use in RENDER_WITH_SHADOWING mode)
|
||||
pha ; pass in the token of the compiled stamp
|
||||
pei PlayerX
|
||||
pei PlayerY
|
||||
_GTEAddSprite
|
||||
|
||||
; brl Exit
|
||||
|
||||
; Repeat for each stamp. _GTECompileSpriteStamp will return an error if it runs out of memory
|
||||
|
||||
pea HERO_SLOT+1 ; Put the player in slot 1
|
||||
pea HERO_FLAGS
|
||||
pea HERO_VBUFF_1 ; and use this stamp
|
||||
pei PlayerX1
|
||||
pei PlayerY1
|
||||
_GTEAddSprite
|
||||
|
||||
pea HERO_SLOT+2 ; Put the player in slot 1
|
||||
pea HERO_FLAGS
|
||||
pea HERO_VBUFF_1 ; and use this stamp
|
||||
pei PlayerX2
|
||||
pei PlayerY2
|
||||
_GTEAddSprite
|
||||
|
||||
EvtLoop
|
||||
pha
|
||||
_GTEReadControl
|
||||
|
@ -207,7 +256,30 @@ do_render
|
|||
pei PlayerY
|
||||
_GTEMoveSprite ; Move the sprite to this local position
|
||||
|
||||
pea $0000
|
||||
pea HERO_SLOT+1
|
||||
lda PlayerX1
|
||||
sec
|
||||
sbc StartX
|
||||
pha
|
||||
lda PlayerY1
|
||||
sec
|
||||
sbc StartY
|
||||
pha
|
||||
_GTEMoveSprite ; Move the sprite to this local position
|
||||
|
||||
pea HERO_SLOT+2
|
||||
lda PlayerX2
|
||||
sec
|
||||
sbc StartX
|
||||
pha
|
||||
lda PlayerY2
|
||||
sec
|
||||
sbc StartY
|
||||
pha
|
||||
_GTEMoveSprite ; Move the sprite to this local position
|
||||
|
||||
pea #RENDER_WITH_SHADOWING
|
||||
; pea $0000
|
||||
_GTERender
|
||||
|
||||
; Update the performance counters
|
||||
|
@ -226,7 +298,7 @@ do_render
|
|||
|
||||
; Exit code
|
||||
Exit
|
||||
jsr SoundShutDown
|
||||
; jsr SoundShutDown
|
||||
_GTEShutDown
|
||||
Quit
|
||||
_QuitGS qtRec
|
||||
|
@ -383,6 +455,17 @@ UpdatePlayerPos
|
|||
|
||||
ApplyCollisions
|
||||
|
||||
; Move coordinates down the list
|
||||
lda PlayerX1
|
||||
sta PlayerX2
|
||||
lda PlayerY1
|
||||
sta PlayerY2
|
||||
|
||||
lda PlayerGlobalX
|
||||
sta PlayerX1
|
||||
lda PlayerGlobalY
|
||||
sta PlayerY1
|
||||
|
||||
; Convert global to local coordinates
|
||||
|
||||
lda PlayerGlobalX
|
||||
|
@ -468,10 +551,10 @@ ApplyCollisions
|
|||
tax
|
||||
:frame
|
||||
|
||||
pea HERO_SLOT
|
||||
pei LastHFlip
|
||||
phx
|
||||
_GTEUpdateSprite
|
||||
; pea HERO_SLOT
|
||||
; pei LastHFlip
|
||||
; phx
|
||||
; _GTEUpdateSprite
|
||||
|
||||
rts
|
||||
|
||||
|
@ -525,8 +608,6 @@ _GetVBLTicks
|
|||
plx
|
||||
rts
|
||||
|
||||
frameCount equ 24
|
||||
|
||||
MusicFile str '1/overworld.ntp'
|
||||
|
||||
PUT ../StartUp.s
|
||||
|
|
|
@ -49,7 +49,7 @@ appTmp2 equ 32
|
|||
|
||||
_MTStartUp ; GTE requires the miscellaneous toolset to be running
|
||||
|
||||
lda #ENGINE_MODE_TWO_LAYER+ENGINE_MODE_DYN_TILES
|
||||
lda #ENGINE_MODE_USER_TOOL+ENGINE_MODE_TWO_LAYER+ENGINE_MODE_DYN_TILES
|
||||
jsr GTEStartUp ; Load and install the GTE User Tool
|
||||
|
||||
; Initialize local variables
|
||||
|
|
|
@ -60,7 +60,7 @@ SpriteCount equ 54
|
|||
|
||||
_MTStartUp ; GTE requires the miscellaneous toolset to be running
|
||||
|
||||
lda #ENGINE_MODE_TWO_LAYER+ENGINE_MODE_DYN_TILES
|
||||
lda #ENGINE_MODE_USER_TOOL+ENGINE_MODE_TWO_LAYER ; +ENGINE_MODE_DYN_TILES
|
||||
jsr GTEStartUp ; Load and install the GTE User Tool
|
||||
|
||||
; Initialize local variables
|
||||
|
@ -75,12 +75,14 @@ SpriteCount equ 54
|
|||
|
||||
; Initialize the graphics screen playfield
|
||||
|
||||
pea #320
|
||||
pea #160
|
||||
pea #200
|
||||
_GTESetScreenMode
|
||||
|
||||
; Load a tileset
|
||||
|
||||
pea #0
|
||||
pea #511
|
||||
pea #^tiledata
|
||||
pea #tiledata
|
||||
_GTELoadTileSet
|
||||
|
@ -141,6 +143,8 @@ SpriteCount equ 54
|
|||
|
||||
; Create the sprites
|
||||
|
||||
HERO_SIZE equ {SPRITE_16X16}
|
||||
HERO_FLAGS equ HERO_SIZE ; no extra H/V bits for now
|
||||
HERO_FRAME_1 equ {SPRITE_16X16+1}
|
||||
HERO_VBUFF_1 equ VBUFF_SPRITE_START+0*VBUFF_SPRITE_STEP
|
||||
HERO_FRAME_2 equ {SPRITE_16X16+7}
|
||||
|
@ -168,31 +172,71 @@ HERO_SLOT_2 equ 2
|
|||
pea HERO_VBUFF_4
|
||||
_GTECreateSpriteStamp
|
||||
|
||||
pea HERO_FRAME_1
|
||||
DO 0
|
||||
lda #SPRITE_16X16
|
||||
sta SpriteFlags1
|
||||
lda #SPRITE_16X8
|
||||
sta SpriteFlags2
|
||||
ELSE
|
||||
lda #SPRITE_16X16+SPRITE_COMPILED
|
||||
sta SpriteFlags1
|
||||
lda #SPRITE_16X8+SPRITE_COMPILED
|
||||
sta SpriteFlags2
|
||||
|
||||
pha ; Space for result
|
||||
pea HERO_SIZE
|
||||
pea HERO_VBUFF_1
|
||||
_GTECompileSpriteStamp
|
||||
pla
|
||||
sta HeroFrames1+2
|
||||
sta HeroFrames1+6
|
||||
|
||||
pha ; Space for result
|
||||
pea HERO_SIZE
|
||||
pea HERO_VBUFF_2
|
||||
_GTECompileSpriteStamp
|
||||
pla
|
||||
sta HeroFrames1+0
|
||||
sta HeroFrames1+4
|
||||
|
||||
pha ; Space for result
|
||||
pea HERO_SIZE
|
||||
pea HERO_VBUFF_3
|
||||
_GTECompileSpriteStamp
|
||||
pla
|
||||
sta HeroFrames2+2
|
||||
sta HeroFrames2+6
|
||||
|
||||
pha ; Space for result
|
||||
pea HERO_SIZE
|
||||
pea HERO_VBUFF_4
|
||||
_GTECompileSpriteStamp
|
||||
pla
|
||||
sta HeroFrames2+0
|
||||
sta HeroFrames2+4
|
||||
FIN
|
||||
|
||||
pea HERO_SLOT_1 ; Put the player in slot 1
|
||||
lda SpriteFlags1
|
||||
pha
|
||||
lda HeroFrames1
|
||||
pha
|
||||
pei PlayerX
|
||||
pei PlayerY
|
||||
pea HERO_SLOT_1 ; Put the player in slot 1
|
||||
_GTEAddSprite
|
||||
|
||||
pea HERO_SLOT_1
|
||||
pea $0000
|
||||
pea HERO_VBUFF_1 ; and use this stamp
|
||||
_GTEUpdateSprite
|
||||
|
||||
pea HERO_FRAME_2
|
||||
pea HERO_SLOT_2
|
||||
lda SpriteFlags2
|
||||
pha
|
||||
lda HeroFrames2
|
||||
pha
|
||||
pei PlayerX
|
||||
lda PlayerY
|
||||
clc
|
||||
adc #16
|
||||
pha
|
||||
pea HERO_SLOT_2 ; Put the player in slot 1
|
||||
_GTEAddSprite
|
||||
|
||||
pea HERO_SLOT_2
|
||||
pea $0000
|
||||
pea HERO_VBUFF_3 ; and use this stamp
|
||||
_GTEUpdateSprite
|
||||
|
||||
EvtLoop
|
||||
pha
|
||||
_GTEReadControl
|
||||
|
@ -298,7 +342,9 @@ do_render
|
|||
pha
|
||||
_GTESetBG1Origin
|
||||
|
||||
pea #RENDER_BG1_HORZ_OFFSET
|
||||
; pea #RENDER_BG1_HORZ_OFFSET
|
||||
pea #RENDER_WITH_SHADOWING
|
||||
; pea #0
|
||||
_GTERender
|
||||
|
||||
; Update the performance counters
|
||||
|
@ -529,6 +575,10 @@ Fatal brk $00
|
|||
qtRec adrl $0000
|
||||
da $00
|
||||
|
||||
; Sprite VBUFF / Compile tokens
|
||||
SpriteFlags1 ds 2
|
||||
SpriteFlags2 ds 2
|
||||
|
||||
; Color palette
|
||||
MyDirectPage ds 2
|
||||
|
||||
|
|
|
@ -14,17 +14,17 @@
|
|||
},
|
||||
"scripts": {
|
||||
"test": "npm run build && npm run build:image && npm run gsport",
|
||||
"gsport": "%npm_package_config_gsport%",
|
||||
"debug": "%npm_package_config_crossrunner% GTEDemo4 -Source GTEDemo4_S02_MAINSEG_Output.txt -Debug -CompatibilityLayer",
|
||||
"gsport": "cross-var $npm_package_config_gsport",
|
||||
"debug": "cross-var $npm_package_config_crossrunner GTEDemo4 -Source GTEDemo4_S02_MAINSEG_Output.txt -Debug -CompatibilityLayer",
|
||||
"build:all": "npm run build:tiles && npm run build:map && npm run build:tool && npm run build:sys16 && npm run build:image",
|
||||
"build:map": "node %npm_package_config_tiled2iigs% ./assets/tiled/yoshi-1.json --force-masked --no-gen-tiles --output-dir ./gen",
|
||||
"build:tiles": "node %npm_package_config_png2iigs% ./assets/tilesets/smw-256x128-4bpp.png --max-tiles 360 --as-tile-data --verbose --transparent-color FF00FF --background-color 216058 > ./gen/App.TileSet.s",
|
||||
"build:tiles:blocky": "node %npm_package_config_png2iigs% ./assets/tilesets/smw-256x128-4bpp.png --max-tiles 360 --as-tile-data --verbose --force-word-alignment --transparent-color FF00FF --background-color 216058 > ./gen/App.TileSet.s",
|
||||
"build:sys16": "%npm_package_config_merlin32% -V %npm_package_config_macros% App.s",
|
||||
"build:map": "cross-var node $npm_package_config_tiled2iigs ./assets/tiled/yoshi-1.json --force-masked --no-gen-tiles --output-dir ./gen",
|
||||
"build:tiles": "cross-var node $npm_package_config_png2iigs ./assets/tilesets/smw-256x128-4bpp.png --max-tiles 360 --as-tile-data --verbose --transparent-color FF00FF --background-color 216058 > ./gen/App.TileSet.s",
|
||||
"build:tiles:blocky": "cross-var node $npm_package_config_png2iigs ./assets/tilesets/smw-256x128-4bpp.png --max-tiles 360 --as-tile-data --verbose --force-word-alignment --transparent-color FF00FF --background-color 216058 > ./gen/App.TileSet.s",
|
||||
"build:sys16": "cross-var $npm_package_config_merlin32 -V $npm_package_config_macros App.s",
|
||||
"build": "npm run build:tool && npm run build:sys16",
|
||||
"build:tool": "%npm_package_config_merlin32% -V %npm_package_config_macros% ../../../src/Master.s",
|
||||
"build:image": "build-image.bat %npm_package_config_cadius%",
|
||||
"build:background": "node %npm_package_config_png2iigs% ./assets/tilesets/bg1.png ./gen/bg1.bin --force-color-match --palette FF00FF,C14F4A,020202,00E100,C89858,216058,DCE9EE,008000,F80080,F5D56C,20308F,A0CDCC,4080A0,70B0D0"
|
||||
"build:tool": "cross-var $npm_package_config_merlin32 -V $npm_package_config_macros ../../../src/Master.s",
|
||||
"build:image": "cross-var build-image.bat $npm_package_config_cadius",
|
||||
"build:background": "cross-var node $npm_package_config_png2iigs ./assets/tilesets/bg1.png ./gen/bg1.bin --force-color-match --palette FF00FF,C14F4A,020202,00E100,C89858,216058,DCE9EE,008000,F80080,F5D56C,20308F,A0CDCC,4080A0,70B0D0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -37,6 +37,7 @@
|
|||
},
|
||||
"homepage": "https://github.com/lscharen/iigs-game-engine#readme",
|
||||
"devDependencies": {
|
||||
"cross-var": "^1.1.0",
|
||||
"pngjs": "^6.0.0",
|
||||
"string-builder": "^0.1.8",
|
||||
"watch": "latest",
|
||||
|
|
|
@ -301,9 +301,12 @@ DoLoadBG1
|
|||
ldx #BG1AltDataFile
|
||||
jsr LoadFile
|
||||
|
||||
lda altBG1Bank
|
||||
jsl SetBG1Bank
|
||||
|
||||
ldx BankLoad
|
||||
lda #0
|
||||
ldy BG1AltBank
|
||||
ldy BG1DataBank
|
||||
jsl CopyBinToBG1
|
||||
|
||||
rts
|
||||
|
|
|
@ -105,7 +105,7 @@ InitOverlay
|
|||
ldx #r_line+{CHAR_WIDTH*4}
|
||||
jsr _DrawChar
|
||||
|
||||
pea $0000
|
||||
pea $0000 ; logical lines for the overlay bar
|
||||
pea $0008
|
||||
pea #^StatusBar
|
||||
pea #StatusBar
|
||||
|
@ -174,6 +174,8 @@ oneSecondCounter ds 2
|
|||
|
||||
; Draw the overlay
|
||||
; A = address of the left edge of the screen
|
||||
; X = top line to start drawing the overlay (typically 0)
|
||||
; Y = bottom line to stop drawing the overlayer (typically the overlay height set during call to _SetOverlay)
|
||||
StatusBar phb ; Called via JSL
|
||||
phd ; save the direct page register
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
GTETF4
|
|
@ -0,0 +1,126 @@
|
|||
; Test driver to exercise graphics routines.
|
||||
|
||||
REL
|
||||
DSK MAINSEG
|
||||
|
||||
use Locator.Macs
|
||||
use Load.Macs
|
||||
use Mem.Macs
|
||||
use Misc.Macs
|
||||
use Util.Macs
|
||||
use EDS.GSOS.Macs
|
||||
use GTE.Macs
|
||||
|
||||
mx %00
|
||||
|
||||
tiledata EXT ; tileset buffer
|
||||
;TileSetPalette EXT
|
||||
|
||||
; Keycodes
|
||||
LEFT_ARROW equ $08
|
||||
RIGHT_ARROW equ $15
|
||||
UP_ARROW equ $0B
|
||||
DOWN_ARROW equ $0A
|
||||
|
||||
; Direct page space
|
||||
MyUserId equ 0
|
||||
BankLoad equ 2
|
||||
StartX equ 4
|
||||
StartY equ 6
|
||||
TileMapWidth equ 8
|
||||
TileMapHeight equ 10
|
||||
ScreenWidth equ 12
|
||||
ScreenHeight equ 14
|
||||
MaxGlobalX equ 16
|
||||
MaxGlobalY equ 18
|
||||
MaxBG0X equ 20
|
||||
MaxBG0Y equ 22
|
||||
OldOneSecondCounter equ 26
|
||||
appTmp0 equ 28
|
||||
appTmp1 equ 30
|
||||
appTmp2 equ 32
|
||||
|
||||
phk
|
||||
plb
|
||||
|
||||
sta MyUserId ; GS/OS passes the memory manager user ID for the application into the program
|
||||
tdc
|
||||
sta MyDirectPage ; Keep a copy for the overlay callback
|
||||
|
||||
_MTStartUp ; GTE requires the miscellaneous toolset to be running
|
||||
|
||||
lda #ENGINE_MODE_USER_TOOL+ENGINE_MODE_TWO_LAYER
|
||||
jsr GTEStartUp ; Load and install the GTE User Tool
|
||||
|
||||
pea $0000 ; Set the first two tiles
|
||||
pea $0002
|
||||
pea #^TileData
|
||||
pea #TileData
|
||||
_GTELoadTileSet
|
||||
|
||||
pea $0000
|
||||
pea #^TileSetPalette
|
||||
pea #TileSetPalette
|
||||
_GTESetPalette
|
||||
|
||||
; Fill in the field with a checkboard pattern
|
||||
|
||||
stz appTmp1
|
||||
|
||||
:tloop0 stz appTmp0
|
||||
:tloop1 lda appTmp0 ; X
|
||||
pha
|
||||
pei appTmp1 ; Y
|
||||
eor appTmp1
|
||||
and #$0001
|
||||
pha ; tile ID
|
||||
_GTESetTile
|
||||
|
||||
inc appTmp0
|
||||
lda #40
|
||||
cmp appTmp0
|
||||
bcs :tloop1
|
||||
|
||||
inc appTmp1
|
||||
lda #25
|
||||
cmp appTmp1
|
||||
bcs :tloop0
|
||||
|
||||
; Set up a very specific test. First, we draw a sprite into the sprite plane, and then
|
||||
; leave it alone. We are just testing the ability to merge sprite plane data into
|
||||
; the play field tiles.
|
||||
EvtLoop
|
||||
pha
|
||||
_GTEReadControl
|
||||
pla
|
||||
|
||||
jsr HandleKeys ; Do the generic key handlers
|
||||
|
||||
pea #RENDER_PER_SCANLINE ; Scanline rendering
|
||||
; pea $0000
|
||||
_GTERender
|
||||
|
||||
brl EvtLoop
|
||||
|
||||
; Exit code
|
||||
Exit
|
||||
_GTEShutDown
|
||||
Quit
|
||||
_QuitGS qtRec
|
||||
|
||||
bcs Fatal
|
||||
Fatal brk $00
|
||||
|
||||
qtRec adrl $0000
|
||||
da $00
|
||||
|
||||
; Color palette
|
||||
TileSetPalette dw $0000,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF
|
||||
|
||||
MyDirectPage ds 2
|
||||
|
||||
; Stub
|
||||
SetLimits rts
|
||||
|
||||
PUT ../kfest-2022/StartUp.s
|
||||
PUT Tiles.s
|
|
@ -0,0 +1,10 @@
|
|||
; Thunder Force IV Demo
|
||||
|
||||
TYP $B3 ; S16 file
|
||||
DSK GTETF4
|
||||
XPL
|
||||
|
||||
; Segment #1 -- Main execution block
|
||||
|
||||
ASM App.Main.s
|
||||
SNA Main
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
|||
Thunder Force IV scanline demo
|
||||
- q to quit; arrows to scroll, numbers to select screen size
|
||||
- make sure Overlay is present
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
TileData
|
||||
; Reserved space (tile 0 is special...
|
||||
ds 128
|
||||
; Tile ID 1
|
||||
; From image coordinates 0, 0
|
||||
hex ffffffff
|
||||
hex ffffffff
|
||||
hex ffffffff
|
||||
hex ffffffff
|
||||
hex ffffffff
|
||||
hex ffffffff
|
||||
hex ffffffff
|
||||
hex ffffffff
|
||||
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
|
||||
hex ffffffff
|
||||
hex ffffffff
|
||||
hex ffffffff
|
||||
hex ffffffff
|
||||
hex ffffffff
|
||||
hex ffffffff
|
||||
hex ffffffff
|
||||
hex ffffffff
|
||||
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
||||
hex 00000000
|
|
@ -0,0 +1 @@
|
|||
GTETF4=Type(B3),AuxType(0000),VersionCreate(70),MinVersion(BE),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000)
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<tileset version="1.5" tiledversion="1.7.2" name="App.TileSet" tilewidth="8" tileheight="8" tilecount="512" columns="32">
|
||||
<transformations hflip="1" vflip="1" rotate="0" preferuntransformed="0"/>
|
||||
<image source="../tilesets/smb-256-128-4bpp.png" trans="ff00ff" width="256" height="128"/>
|
||||
<tile id="136">
|
||||
<animation>
|
||||
<frame tileid="136" duration="256"/>
|
||||
<frame tileid="138" duration="256"/>
|
||||
<frame tileid="140" duration="256"/>
|
||||
<frame tileid="142" duration="256"/>
|
||||
</animation>
|
||||
</tile>
|
||||
<tile id="137">
|
||||
<animation>
|
||||
<frame tileid="137" duration="256"/>
|
||||
<frame tileid="139" duration="256"/>
|
||||
<frame tileid="141" duration="256"/>
|
||||
<frame tileid="143" duration="256"/>
|
||||
</animation>
|
||||
</tile>
|
||||
<tile id="168">
|
||||
<animation>
|
||||
<frame tileid="168" duration="256"/>
|
||||
<frame tileid="170" duration="256"/>
|
||||
<frame tileid="172" duration="256"/>
|
||||
<frame tileid="174" duration="256"/>
|
||||
</animation>
|
||||
</tile>
|
||||
<tile id="169">
|
||||
<animation>
|
||||
<frame tileid="169" duration="256"/>
|
||||
<frame tileid="171" duration="256"/>
|
||||
<frame tileid="173" duration="256"/>
|
||||
<frame tileid="175" duration="256"/>
|
||||
</animation>
|
||||
</tile>
|
||||
</tileset>
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.5" tiledversion="1.7.2" orientation="orthogonal" renderorder="right-down" width="416" height="30" tilewidth="8" tileheight="8" infinite="0" nextlayerid="4" nextobjectid="2">
|
||||
<editorsettings>
|
||||
<export target="world_1-1.json" format="json"/>
|
||||
</editorsettings>
|
||||
<tileset firstgid="1" source="Overworld.tsx"/>
|
||||
<layer id="1" name="App.TileMapBG0" width="416" height="30">
|
||||
<data encoding="csv">
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,154,153,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,154,153,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,154,153,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,154,153,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,186,186,187,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,186,186,186,186,187,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,186,186,187,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,186,186,186,186,187,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,186,186,187,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,186,186,186,186,187,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,186,186,187,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,186,186,186,186,187,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,60,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,156,157,158,0,0,0,0,0,0,0,0,0,0,0,0,0,153,154,153,154,153,154,0,0,0,0,0,0,0,0,0,0,0,155,156,157,156,157,158,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,156,157,158,0,0,0,0,0,0,0,0,0,0,0,0,0,153,154,153,154,153,154,0,0,0,0,0,0,0,0,0,0,0,155,156,157,156,157,158,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,156,157,158,0,0,0,0,0,0,0,0,0,0,0,0,0,153,154,153,154,153,154,0,0,0,0,0,0,0,0,0,0,0,155,156,157,156,157,158,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,156,157,158,0,0,0,0,0,0,0,0,0,0,0,0,0,153,154,153,154,153,154,0,0,0,0,0,0,0,0,0,0,0,155,156,157,156,157,158,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,56,10,0,0,0,0,0,153,154,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,186,186,187,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,186,186,186,186,186,186,187,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,186,186,187,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,186,186,186,186,186,186,187,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,186,186,187,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,186,186,186,186,186,186,187,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,186,186,187,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,186,186,186,186,186,186,187,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,10,0,0,0,0,185,186,186,187,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,156,157,158,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,156,157,156,157,156,157,158,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,156,157,158,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,156,157,156,157,156,157,158,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,156,157,158,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,156,157,156,157,156,157,158,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,156,157,158,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155,156,157,156,157,156,157,158,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,10,0,0,0,0,155,156,157,158,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,159,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,0,0,0,0,0,0,188,188,188,188,188,188,159,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,159,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,188,188,188,188,188,188,0,0,0,0,0,0,0,0,188,188,159,160,159,160,188,188,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,6,5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,191,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,0,0,0,0,0,0,26,26,26,26,26,26,191,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,191,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,26,26,26,26,26,0,0,0,0,0,0,0,0,26,26,191,192,191,192,26,26,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,7,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,6,5,6,5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,7,8,7,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,6,5,6,5,6,5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,7,8,7,8,7,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,6,5,6,5,6,5,6,5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,7,8,7,8,7,8,7,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,10,0,0,0,0,0,0,0,0,31,32,31,32,31,32,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,159,160,0,0,0,0,0,188,188,159,160,188,188,159,160,188,188,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,12,13,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,12,13,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,188,188,159,160,188,188,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,188,188,0,0,0,0,0,0,0,0,0,0,188,188,188,188,0,0,0,0,0,0,0,0,159,160,0,0,0,0,159,160,0,0,0,0,159,160,0,0,0,0,0,0,0,0,0,0,188,188,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,188,188,188,188,0,0,0,0,0,0,0,0,0,0,0,0,5,6,0,0,0,0,5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,6,5,6,0,0,0,0,5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,188,188,188,188,159,160,188,188,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,6,5,6,5,6,5,6,5,6,5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,10,0,0,0,0,0,0,0,0,26,26,26,26,26,26,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,191,192,0,0,0,0,0,26,26,191,192,26,26,191,192,26,26,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,16,17,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,16,17,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,26,191,192,26,26,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,26,0,0,0,0,0,0,0,0,0,0,26,26,26,26,0,0,0,0,0,0,0,0,191,192,0,0,0,0,191,192,0,0,0,0,191,192,0,0,0,0,0,0,0,0,0,0,26,26,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,26,26,26,0,0,0,0,0,0,0,0,0,0,0,0,7,8,0,0,0,0,7,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,7,8,0,0,0,0,7,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,26,26,26,191,192,26,26,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,7,8,7,8,7,8,7,8,7,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,10,0,0,0,0,0,0,0,0,26,64,26,26,64,26,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,12,13,14,0,0,0,0,0,0,0,0,0,0,0,0,19,20,21,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,20,21,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,6,5,6,0,0,0,0,5,6,5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,6,5,6,5,6,0,0,0,0,5,6,5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,6,5,6,5,6,5,6,5,6,5,6,5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,10,0,0,0,0,0,0,0,0,26,64,26,26,64,26,0,0,0,0,
|
||||
0,0,0,0,49,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,16,17,18,0,0,0,0,0,0,0,0,0,0,0,0,19,20,21,22,0,0,0,0,49,50,0,0,0,0,0,0,0,0,0,0,0,0,19,20,21,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,7,8,0,0,0,0,7,8,7,8,0,0,0,0,0,0,0,0,49,50,0,0,0,0,0,0,7,8,7,8,7,8,0,0,0,0,7,8,7,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,7,8,7,8,7,8,7,8,7,8,7,8,0,0,0,0,0,0,0,0,49,50,0,0,0,0,0,0,9,10,0,0,0,0,0,0,31,32,24,25,24,25,24,25,31,32,0,0,
|
||||
0,0,0,48,21,54,51,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,12,13,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,20,21,22,0,0,0,0,0,0,0,0,0,0,0,0,19,20,21,22,0,0,0,48,21,54,51,0,0,0,0,0,0,0,0,0,0,0,19,20,21,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,21,54,51,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,6,5,6,5,6,0,0,0,0,5,6,5,6,5,6,0,0,0,0,0,48,21,54,51,0,0,0,5,6,5,6,5,6,5,6,0,0,0,0,5,6,5,6,5,6,0,0,0,0,0,0,0,0,0,0,11,12,13,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,12,13,14,0,0,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,0,0,0,0,0,0,0,48,21,54,51,0,0,0,0,0,9,10,0,0,0,0,0,0,26,26,26,26,57,58,26,26,26,26,0,0,
|
||||
0,0,48,21,21,21,21,51,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,2147483697,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,16,17,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,20,21,22,0,0,0,0,0,0,0,0,0,0,0,0,19,20,21,22,0,0,48,21,21,21,21,51,0,0,0,0,0,0,0,0,0,0,19,20,21,22,0,0,0,0,0,0,0,0,0,0,0,0,49,2147483697,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,21,21,21,21,51,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,2147483697,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,7,8,7,8,0,0,0,0,7,8,7,8,7,8,0,0,0,0,48,21,21,21,21,51,0,0,7,8,7,8,7,8,7,8,0,0,0,0,7,8,7,8,7,8,0,0,0,0,0,0,49,2147483697,0,0,15,16,17,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,16,17,18,0,0,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,0,0,0,0,0,0,48,21,21,21,21,51,0,0,0,0,9,10,0,0,0,0,0,0,26,26,26,26,64,64,26,26,26,26,0,0,
|
||||
0,48,21,54,21,21,54,21,51,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,35,34,35,34,35,0,0,0,48,21,54,2147483696,0,0,0,0,0,0,0,0,0,0,0,34,35,0,0,0,0,0,0,19,20,21,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,20,21,22,0,0,0,0,34,35,34,35,0,0,0,0,19,20,21,22,0,48,21,54,21,21,54,21,51,0,0,0,0,0,0,0,0,0,19,20,21,22,0,0,34,35,34,35,34,35,0,0,0,48,21,54,2147483696,0,0,0,0,0,0,0,0,0,0,0,34,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,35,34,35,0,0,0,0,0,0,0,0,0,48,21,54,21,21,54,21,51,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,35,34,35,34,35,0,0,0,48,21,54,2147483696,0,0,0,0,0,0,0,0,0,0,0,34,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,6,5,6,5,6,5,6,34,35,34,35,5,6,5,6,5,6,5,6,0,48,21,54,21,21,54,21,5,6,5,6,5,6,5,6,5,6,0,0,0,0,5,6,5,6,5,6,5,6,0,0,0,48,21,54,2147483696,0,19,20,21,22,0,0,0,0,0,0,34,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,20,21,22,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,5,6,0,0,0,0,0,48,21,54,21,21,54,21,51,0,0,0,5,6,0,0,0,0,0,0,26,26,26,26,64,64,26,26,26,26,0,0,
|
||||
48,21,21,21,21,21,21,21,21,51,0,0,0,0,0,0,0,0,0,0,0,0,0,36,37,37,37,37,37,37,38,0,48,21,21,21,21,2147483696,0,0,0,0,0,0,0,0,0,36,37,37,38,0,0,0,0,0,19,20,21,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,20,21,22,0,0,0,36,37,37,37,37,38,0,0,0,19,20,21,22,48,21,21,21,21,21,21,21,21,51,0,0,0,0,0,0,0,0,19,20,21,22,0,36,37,37,37,37,37,37,38,0,48,21,21,21,21,2147483696,0,0,0,0,0,0,0,0,0,36,37,37,38,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,37,37,37,37,38,0,0,0,0,0,0,0,48,21,21,21,21,21,21,21,21,51,0,0,0,0,0,0,0,0,0,0,0,0,0,36,37,37,37,37,37,37,38,0,48,21,21,21,21,2147483696,0,0,0,0,0,0,0,0,0,36,37,37,38,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,7,8,7,8,7,8,37,37,37,37,7,8,7,8,7,8,7,8,48,21,21,21,21,21,21,21,7,8,7,8,7,8,7,8,7,8,0,0,0,0,7,8,7,8,7,8,7,8,38,0,48,21,21,21,21,2147483696,19,20,21,22,0,0,0,0,0,36,37,37,38,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,20,21,22,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,7,8,0,0,0,0,48,21,21,21,21,21,21,21,21,51,0,0,7,8,0,0,0,0,0,0,26,26,26,26,64,64,26,26,26,26,0,0,
|
||||
1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,0,0,0,0,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,0,0,0,0,0,0,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,0,0,0,0,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
|
||||
3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,0,0,0,0,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,0,0,0,0,0,0,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,0,0,0,0,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,
|
||||
1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,0,0,0,0,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,0,0,0,0,0,0,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,0,0,0,0,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
|
||||
3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,0,0,0,0,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,0,0,0,0,0,0,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,0,0,0,0,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4
|
||||
</data>
|
||||
</layer>
|
||||
</map>
|
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
|
@ -0,0 +1,17 @@
|
|||
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/TF4"
|
||||
|
||||
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% .\GTETF4
|
||||
%CADIUS% ADDFILE %IMAGE% %FOLDER% ..\..\src\Tool160
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"name": "tf4-demo",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"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",
|
||||
"png2iigs": "../../tools/png2iigs.js",
|
||||
"tiled2iigs": "../../tools/tiled2iigs.js"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "npm run build && npm run build:image && npm run gsport",
|
||||
"gsport": "%npm_package_config_gsport%",
|
||||
"debug": "%npm_package_config_crossrunner% GTETestSprites -Source GTETestSprites_S02_MAINSEG_Output.txt -Debug -CompatibilityLayer",
|
||||
"build:all": "npm run build:tiles && npm run build:map && npm run build:tool && npm run build:sys16 && npm run build:image",
|
||||
"build:map": "node %npm_package_config_tiled2iigs% ./assets/tiled/world_1-1.json --empty-tile 33 --no-gen-tiles --output-dir ./gen",
|
||||
"build:map:masked": "node %npm_package_config_tiled2iigs% ./assets/tiled/world_1-1.json --force-masked --empty-tile 33 --no-gen-tiles --output-dir ./gen",
|
||||
"build:tiles": "node %npm_package_config_png2iigs% ./assets/tilesets/smb-256-128-4bpp.png --max-tiles 360 --as-tile-data --transparent-color FF00FF --background-color 6B8CFF --verbose > ./gen/App.TileSet.s",
|
||||
"build:sys16": "%npm_package_config_merlin32% -V %npm_package_config_macros% App.s",
|
||||
"build": "npm run build:tool && npm run build:sys16",
|
||||
"build:tool": "%npm_package_config_merlin32% -V %npm_package_config_macros% ../../src/Master.s",
|
||||
"build:image": "build-image.bat %npm_package_config_cadius%"
|
||||
},
|
||||
"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": {
|
||||
"pngjs": "^6.0.0",
|
||||
"string-builder": "^0.1.8",
|
||||
"watch": "latest",
|
||||
"xml2json": "^0.12.0"
|
||||
}
|
||||
}
|
|
@ -24,40 +24,67 @@ Selected equ 10
|
|||
Flips equ 12
|
||||
DTile equ 14
|
||||
Tmp2 equ 16
|
||||
ScreenWidth equ 18
|
||||
ScreenHeight equ 20
|
||||
SpriteFlags equ 22
|
||||
frameCount equ 24
|
||||
OldOneSecondCounter equ 26
|
||||
SpriteAddr equ 28
|
||||
RenderMode equ 30
|
||||
|
||||
; Control modes
|
||||
DefaultMode equ RENDER_WITH_SHADOWING
|
||||
SlowSprites equ 0
|
||||
|
||||
; Typical init
|
||||
phk
|
||||
plb
|
||||
|
||||
sta MyUserId ; GS/OS passes the memory manager user ID for the application into the program
|
||||
tdc
|
||||
sta MyDirectPage ; Keep a copy for the overlay callback
|
||||
|
||||
_MTStartUp ; GTE requires the miscellaneous toolset to be running
|
||||
|
||||
lda #ENGINE_MODE_USER_TOOL ; +ENGINE_MODE_TWO_LAYER
|
||||
jsr GTEStartUp ; Load and install the GTE User Tool
|
||||
|
||||
; Init local variables
|
||||
|
||||
stz frameCount
|
||||
|
||||
lda #DefaultMode
|
||||
sta RenderMode
|
||||
|
||||
; Initialize the graphics screen to a 256x160 playfield
|
||||
|
||||
pea #320
|
||||
pea #160
|
||||
pea #200
|
||||
_GTESetScreenMode
|
||||
|
||||
; Load a tileset
|
||||
|
||||
pea 0
|
||||
pea 360
|
||||
pea #^TSZelda
|
||||
pea #TSZelda
|
||||
_GTELoadTileSet
|
||||
|
||||
; Set the palette
|
||||
ldx #11*2
|
||||
:ploop
|
||||
lda palette,x
|
||||
stal $E19E00,x
|
||||
dex
|
||||
dex
|
||||
bpl :ploop
|
||||
bra sprt
|
||||
pea $0000
|
||||
pea #^palette
|
||||
pea #palette
|
||||
_GTESetPalette
|
||||
|
||||
palette dw $0000,$08C1,$0C41,$0F93,$0777,$0FDA,$00A0,$0000,$0D20,$0FFF,$023E
|
||||
sprt
|
||||
jsr SetLimits
|
||||
|
||||
lda #193 ; Tile ID of '0'
|
||||
jsr InitOverlay ; Initialize the status bar
|
||||
pha
|
||||
_GTEGetSeconds
|
||||
pla
|
||||
sta OldOneSecondCounter
|
||||
jsr UdtOverlay
|
||||
|
||||
; Create stamps for the sprites we are going to use
|
||||
HERO_SPRITE equ SPRITE_16X16+1
|
||||
|
@ -66,25 +93,38 @@ HERO_SPRITE equ SPRITE_16X16+1
|
|||
pea VBUFF_SPRITE_START ; vbuff address
|
||||
_GTECreateSpriteStamp
|
||||
|
||||
DO SlowSprites
|
||||
lda #SPRITE_16X16
|
||||
sta SpriteFlags
|
||||
lda #VBUFF_SPRITE_START
|
||||
sta SpriteAddr
|
||||
ELSE
|
||||
lda #SPRITE_16X16+SPRITE_COMPILED
|
||||
sta SpriteFlags
|
||||
|
||||
pha ; Space for result
|
||||
pea SPRITE_16X16
|
||||
pea VBUFF_SPRITE_START
|
||||
_GTECompileSpriteStamp
|
||||
pla
|
||||
sta SpriteAddr
|
||||
FIN
|
||||
|
||||
; Create sprites
|
||||
stz Tmp0
|
||||
stz Tmp1
|
||||
stz Tmp1 ; Slot number
|
||||
|
||||
ldx Tmp0
|
||||
:sloop
|
||||
pea HERO_SPRITE ; sprite id
|
||||
pei Tmp1 ; Put the sprite in this slot
|
||||
pei SpriteFlags ; with these flags (h/v flip)
|
||||
pei SpriteAddr
|
||||
lda PlayerX,x
|
||||
pha
|
||||
lda PlayerY,x
|
||||
pha
|
||||
pei Tmp1
|
||||
_GTEAddSprite
|
||||
|
||||
pei Tmp1 ; update the sprite in this slot
|
||||
pea $0000 ; with these flags (h/v flip)
|
||||
pea VBUFF_SPRITE_START ; and use this stamp
|
||||
_GTEUpdateSprite
|
||||
|
||||
inc Tmp1
|
||||
ldx Tmp0
|
||||
inx
|
||||
|
@ -95,80 +135,13 @@ HERO_SPRITE equ SPRITE_16X16+1
|
|||
|
||||
; Manually fill in the 41x26 tiles of the TileStore with a test pattern of trees
|
||||
|
||||
; lda #TILE_DYN_BIT+TILE_PRIORITY_BIT+0 ; fill the screen the the dynamic tile slot 0
|
||||
lda #TILE_DYN_BIT+0 ; fill the screen the the dynamic tile slot 0
|
||||
jsr _fillTileStore
|
||||
; brl :no_trees
|
||||
|
||||
ldx #0
|
||||
ldy #0
|
||||
jsr _drawTree
|
||||
|
||||
ldx #3
|
||||
ldy #0
|
||||
jsr _drawTreeH
|
||||
|
||||
ldx #0
|
||||
ldy #3
|
||||
jsr _drawTreeV
|
||||
|
||||
ldx #3
|
||||
ldy #3
|
||||
jsr _drawTreeHV
|
||||
|
||||
ldx #9
|
||||
ldy #0
|
||||
jsr _drawTree
|
||||
|
||||
ldx #9
|
||||
ldy #3
|
||||
jsr _drawTree
|
||||
|
||||
ldx #12
|
||||
ldy #0
|
||||
jsr _drawTree
|
||||
|
||||
ldx #12
|
||||
ldy #3
|
||||
jsr _drawTree
|
||||
|
||||
ldx #6
|
||||
ldy #0
|
||||
jsr _drawTreeFront
|
||||
|
||||
ldx #6
|
||||
ldy #3
|
||||
jsr _drawTreeFront
|
||||
|
||||
ldx #6
|
||||
ldy #6
|
||||
jsr _drawTreeFront
|
||||
|
||||
ldx #3
|
||||
ldy #6
|
||||
jsr _drawTreeFront
|
||||
|
||||
ldx #0
|
||||
ldy #6
|
||||
jsr _drawTreeFront
|
||||
:no_trees
|
||||
; Set up the dynamic tile
|
||||
lda #65
|
||||
sta DTile
|
||||
|
||||
pei DTile
|
||||
pea $0000
|
||||
_GTECopyTileToDynamic ; Copy DTile into the first dynamic tile slot
|
||||
|
||||
; Initialize the frame counter
|
||||
|
||||
stz FrameCount
|
||||
|
||||
; Set the screen coordinates
|
||||
|
||||
lda #128
|
||||
lda #0
|
||||
sta ScreenX
|
||||
lda #128
|
||||
lda #0
|
||||
sta ScreenY
|
||||
|
||||
stz Selected
|
||||
|
@ -179,309 +152,178 @@ HERO_SPRITE equ SPRITE_16X16+1
|
|||
pha ; space for result, with pattern
|
||||
_GTEReadControl
|
||||
pla
|
||||
and #$00FF
|
||||
cmp #'q'
|
||||
bne :2
|
||||
brl :exit
|
||||
:2
|
||||
; cmp KeyState
|
||||
; beq :evt_loop
|
||||
; sta KeyState
|
||||
; cmp #0
|
||||
; beq :evt_loop
|
||||
|
||||
; cmp #' '
|
||||
; bne :evt_loop ; only advance one frame at a time
|
||||
; brl :next
|
||||
|
||||
:3
|
||||
cmp #'1'
|
||||
bcc :3a
|
||||
cmp #'9'
|
||||
bcs :3a
|
||||
sec
|
||||
sbc #'1'
|
||||
asl
|
||||
sta Selected
|
||||
brl :next
|
||||
|
||||
:3a
|
||||
cmp #'r'
|
||||
bne :3b
|
||||
lda Flips
|
||||
clc
|
||||
adc #SPRITE_HFLIP
|
||||
and #SPRITE_VFLIP+SPRITE_HFLIP
|
||||
sta Flips
|
||||
|
||||
pei Selected ; update the sprite in this slot
|
||||
pei Flips ; with these flags (h/v flip)
|
||||
pea VBUFF_SPRITE_START ; and use this stamp
|
||||
_GTEUpdateSprite
|
||||
|
||||
:3b
|
||||
cmp #'x'
|
||||
bne :3d
|
||||
ldx Selected
|
||||
lda PlayerX,x
|
||||
clc
|
||||
adc PlayerU,x
|
||||
sta PlayerX,x
|
||||
|
||||
lda PlayerY,x
|
||||
clc
|
||||
adc PlayerV,x
|
||||
sta PlayerY,x
|
||||
brl :next
|
||||
:3d
|
||||
cmp #'z'
|
||||
bne :3e
|
||||
ldx Selected
|
||||
lda PlayerX,x
|
||||
sec
|
||||
sbc PlayerU,x
|
||||
sta PlayerX,x
|
||||
|
||||
lda PlayerY,x
|
||||
sec
|
||||
sbc PlayerV,x
|
||||
sta PlayerY,x
|
||||
brl :next
|
||||
:3e
|
||||
cmp #'s'
|
||||
bne :4
|
||||
ldx Selected
|
||||
inc PlayerY,x
|
||||
brl :next
|
||||
:4
|
||||
cmp #'w'
|
||||
bne :5
|
||||
ldx Selected
|
||||
dec PlayerY,x
|
||||
brl :next
|
||||
:5
|
||||
cmp #'d'
|
||||
bne :6
|
||||
ldx Selected
|
||||
inc PlayerX,x
|
||||
brl :next
|
||||
:6
|
||||
cmp #'a'
|
||||
bne :7
|
||||
ldx Selected
|
||||
dec PlayerX,x
|
||||
brl :next
|
||||
:7
|
||||
cmp #$15 ; left = $08, right = $15, up = $0B, down = $0A
|
||||
bne :8
|
||||
inc ScreenX
|
||||
bra :next
|
||||
|
||||
:8 cmp #$08
|
||||
bne :9
|
||||
dec ScreenX
|
||||
brl :next
|
||||
|
||||
:9 cmp #$0B
|
||||
bne :10
|
||||
inc ScreenY
|
||||
brl :next
|
||||
|
||||
:10 cmp #$0A
|
||||
bne :11
|
||||
dec ScreenY
|
||||
brl :next
|
||||
|
||||
:11 cmp #'y'
|
||||
bne :12
|
||||
lda DTile
|
||||
inc
|
||||
jsr HandleKeys ; Do the generic key handlers
|
||||
bcs :do_more
|
||||
brl :do_render
|
||||
:do_more
|
||||
and #$007F
|
||||
sta DTile
|
||||
pha
|
||||
pea $0000
|
||||
_GTECopyTileToDynamic
|
||||
brl :next
|
||||
cmp #'a' ; Put in single-step advance mode
|
||||
bne :skip_a
|
||||
:a_loop
|
||||
jsr :next_frame
|
||||
:a_spin
|
||||
pha ; space for result, with pattern
|
||||
_GTEReadControl
|
||||
pla
|
||||
bit #PAD_KEY_DOWN
|
||||
bne :a_spin
|
||||
and #$007F
|
||||
cmp #'r' ; resume?
|
||||
beq :do_render
|
||||
cmp #'s'
|
||||
beq :toggle_sort
|
||||
cmp #'a'
|
||||
beq :a_loop
|
||||
bra :a_spin
|
||||
:toggle_sort lda RenderMode
|
||||
eor #RENDER_SPRITES_SORTED
|
||||
sta RenderMode
|
||||
pei RenderMode
|
||||
_GTERender
|
||||
bra :a_spin
|
||||
:skip_a
|
||||
|
||||
:do_render jsr :next_frame
|
||||
brl :evt_loop
|
||||
|
||||
:12 cmp #'f'
|
||||
bne :13
|
||||
pea $0000
|
||||
_GTEFillTileStore
|
||||
brl :next
|
||||
|
||||
:13 cmp #'m'
|
||||
bne :next
|
||||
_GTERefresh
|
||||
|
||||
:next
|
||||
; inc ScreenX
|
||||
:next_frame
|
||||
jsr _moveSprites
|
||||
|
||||
inc ScreenX
|
||||
inc ScreenY
|
||||
pei ScreenX
|
||||
pei ScreenY
|
||||
_GTESetBG0Origin
|
||||
|
||||
; brl no_animate
|
||||
|
||||
stz Tmp0
|
||||
stz Tmp1
|
||||
|
||||
ldx Tmp0
|
||||
loopX
|
||||
lda PlayerX,x
|
||||
clc
|
||||
adc PlayerU,x
|
||||
sta PlayerX,x
|
||||
bpl is_posx
|
||||
cmp #-15
|
||||
bcs do_y
|
||||
lda PlayerU,x
|
||||
eor #$FFFF
|
||||
inc
|
||||
sta PlayerU,x
|
||||
bra do_y
|
||||
is_posx cmp #128
|
||||
bcc do_y
|
||||
lda PlayerU,x
|
||||
eor #$FFFF
|
||||
inc
|
||||
sta PlayerU,x
|
||||
|
||||
do_y
|
||||
lda PlayerY,x
|
||||
clc
|
||||
adc PlayerV,x
|
||||
sta PlayerY,x
|
||||
bpl is_posy
|
||||
cmp #-15
|
||||
bcs do_z
|
||||
lda PlayerV,x
|
||||
eor #$FFFF
|
||||
inc
|
||||
sta PlayerV,x
|
||||
bra do_z
|
||||
is_posy cmp #160
|
||||
bcc do_z
|
||||
lda PlayerV,x
|
||||
eor #$FFFF
|
||||
inc
|
||||
sta PlayerV,x
|
||||
do_z
|
||||
inc Tmp1
|
||||
ldx Tmp0
|
||||
inx
|
||||
inx
|
||||
stx Tmp0
|
||||
cpx #MAX_SPRITES*2
|
||||
bcc loopX
|
||||
|
||||
no_animate
|
||||
stz Tmp0
|
||||
stz Tmp1
|
||||
ldx Tmp0
|
||||
loopY
|
||||
pei Tmp1
|
||||
lda PlayerX,x
|
||||
pha
|
||||
lda PlayerY,x
|
||||
pha
|
||||
_GTEMoveSprite
|
||||
|
||||
inc Tmp1
|
||||
ldx Tmp0
|
||||
inx
|
||||
inx
|
||||
stx Tmp0
|
||||
cpx #MAX_SPRITES*2
|
||||
bcc loopY
|
||||
|
||||
pei RenderMode
|
||||
_GTERender
|
||||
inc FrameCount
|
||||
|
||||
; Debug stuff
|
||||
; Update the performance counters
|
||||
|
||||
inc frameCount
|
||||
pha
|
||||
_GTEGetSeconds
|
||||
pla
|
||||
cmp LastSecond
|
||||
beq :no_fps
|
||||
sta LastSecond
|
||||
|
||||
lda FrameCount
|
||||
ldx #0
|
||||
ldy #$FFFF
|
||||
jsr DrawWord
|
||||
|
||||
stz FrameCount
|
||||
:no_fps
|
||||
|
||||
; tdc
|
||||
; ldx #160*32
|
||||
; jsr DrawWord
|
||||
|
||||
brl :evt_loop
|
||||
cmp OldOneSecondCounter
|
||||
beq :noudt
|
||||
sta OldOneSecondCounter
|
||||
jsr UdtOverlay
|
||||
stz frameCount
|
||||
:noudt
|
||||
rts
|
||||
|
||||
; Shut down everything
|
||||
:exit
|
||||
Exit
|
||||
_GTEShutDown
|
||||
_QuitGS qtRec
|
||||
qtRec adrl $0000
|
||||
da $00
|
||||
|
||||
; Array of sprite positions and velocities
|
||||
DO 1
|
||||
PlayerX dw 8,14,29,34,45,67,81,83,92,101,39,22,7,74,111,9
|
||||
PlayerY dw 72,24,13,56,35,72,23,8,93,123,134,87,143,14,46,65
|
||||
PlayerU dw 1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4
|
||||
PlayerV dw 1,1,1,1,2,2,2,4,3,3,3,3,4,4,4,4
|
||||
ELSE
|
||||
PlayerX dw 2,12,22,32,42,52,62,72,2,12,22,32,42,52,62,72,
|
||||
PlayerY dw 24,24,24,24,24,24,24,24,44,44,44,44,44,44,44,44
|
||||
PlayerU dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
PlayerV dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
FIN
|
||||
_moveSprites
|
||||
stz Tmp0
|
||||
:loop
|
||||
ldx Tmp0
|
||||
|
||||
; Load the GTE User Tool and install it
|
||||
GTEStartUp
|
||||
pea $0000
|
||||
_LoaderStatus
|
||||
lda PlayerX,x
|
||||
clc
|
||||
adc PlayerU,x
|
||||
sta PlayerX,x
|
||||
|
||||
bpl :chk_xpos
|
||||
eor #$FFFF
|
||||
inc
|
||||
sta PlayerX,x
|
||||
bra :rev_x
|
||||
:chk_xpos
|
||||
cmp ScreenWidth
|
||||
bcc :ok_x
|
||||
sbc ScreenWidth
|
||||
eor #$FFFF
|
||||
inc
|
||||
clc
|
||||
adc ScreenWidth
|
||||
sta PlayerX,x
|
||||
|
||||
:rev_x
|
||||
lda PlayerU,x ; reverse the velocity
|
||||
eor #$FFFF
|
||||
inc
|
||||
sta PlayerU,x
|
||||
:ok_x
|
||||
|
||||
lda PlayerY,x
|
||||
clc
|
||||
adc PlayerV,x
|
||||
sta PlayerY,x
|
||||
bpl :chk_ypos
|
||||
eor #$FFFF
|
||||
inc
|
||||
sta PlayerY,x
|
||||
bra :rev_y
|
||||
:chk_ypos
|
||||
cmp ScreenHeight
|
||||
bcc :ok_y
|
||||
sbc ScreenHeight
|
||||
eor #$FFFF
|
||||
inc
|
||||
clc
|
||||
adc ScreenHeight
|
||||
sta PlayerY,x
|
||||
|
||||
:rev_y
|
||||
lda PlayerV,x ; reverse the velocity
|
||||
eor #$FFFF
|
||||
inc
|
||||
sta PlayerV,x
|
||||
|
||||
:ok_y
|
||||
txa
|
||||
lsr
|
||||
pha
|
||||
lda PlayerX,x
|
||||
pha
|
||||
lda PlayerY,x
|
||||
pha
|
||||
_GTEMoveSprite
|
||||
|
||||
lda Tmp0
|
||||
inc
|
||||
inc
|
||||
sta Tmp0
|
||||
cmp #2*MAX_SPRITES
|
||||
bcc :loop
|
||||
rts
|
||||
|
||||
; Called by StartUp function callbacks when the screen size changes
|
||||
SetLimits
|
||||
pha ; Allocate space for x, y, width, height
|
||||
pha
|
||||
pha
|
||||
pha
|
||||
_GTEGetScreenInfo
|
||||
pla
|
||||
|
||||
pea $0000
|
||||
pea $0000
|
||||
pea $0000
|
||||
pea $0000
|
||||
pea $0000 ; result space
|
||||
|
||||
lda MyUserId
|
||||
pha
|
||||
|
||||
pea #^ToolPath
|
||||
pea #ToolPath
|
||||
pea $0001 ; do not load into special memory
|
||||
_InitialLoad
|
||||
bcc :ok1
|
||||
brk $01
|
||||
|
||||
:ok1
|
||||
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
|
||||
bcc :ok2
|
||||
brk $02
|
||||
|
||||
:ok2
|
||||
clc ; Give GTE a page of direct page memory
|
||||
tdc
|
||||
adc #$0100
|
||||
pha
|
||||
pea #ENGINE_MODE_DYN_TILES+ENGINE_MODE_TWO_LAYER ; Enable Dynamic Tiles and Two Layer
|
||||
lda MyUserId ; Pass the userId for memory allocation
|
||||
pha
|
||||
_GTEStartUp
|
||||
bcc :ok3
|
||||
brk $03
|
||||
|
||||
:ok3
|
||||
pla ; Discard screen corner
|
||||
pla
|
||||
sec
|
||||
sbc #8
|
||||
sta ScreenWidth ; Pre-adjust to keep sprites on the visible playfield (for compiled sprites)
|
||||
pla
|
||||
sec
|
||||
sbc #16
|
||||
sta ScreenHeight
|
||||
rts
|
||||
|
||||
_fillTileStore
|
||||
|
@ -490,25 +332,22 @@ _fillTileStore
|
|||
:oloop
|
||||
stz Tmp1
|
||||
:iloop
|
||||
pei Tmp1
|
||||
pei Tmp0
|
||||
pei Tmp2
|
||||
_GTESetTile
|
||||
|
||||
lda Tmp2
|
||||
eor #TILE_PRIORITY_BIT
|
||||
sta Tmp2
|
||||
ldx Tmp1
|
||||
ldy Tmp0
|
||||
jsr _drawTree
|
||||
|
||||
lda Tmp1
|
||||
inc
|
||||
clc
|
||||
adc #2
|
||||
sta Tmp1
|
||||
cmp #41
|
||||
cmp #40
|
||||
bcc :iloop
|
||||
|
||||
lda Tmp0
|
||||
inc
|
||||
clc
|
||||
adc #2
|
||||
sta Tmp0
|
||||
cmp #26
|
||||
cmp #25
|
||||
bcc :oloop
|
||||
rts
|
||||
|
||||
|
@ -645,10 +484,12 @@ _drawTreeHV
|
|||
_GTESetTile
|
||||
rts
|
||||
|
||||
MyDirectPage ds 2
|
||||
MyUserId ds 2
|
||||
ToolPath str '1/Tool160'
|
||||
FrameCount ds 2
|
||||
LastSecond dw 0
|
||||
palette dw $0000,$08C1,$0C41,$0F93,$0777,$0FDA,$00A0,$0000,$0D20,$0FFF,$0FD7,$0F59,$0000,$01CE,$0EDA,$0EEE
|
||||
|
||||
PUT App.Msg.s
|
||||
PUT font.s
|
||||
PUT ../kfest-2022/StartUp.s
|
||||
PUT ../shell/Overlay.s
|
||||
|
||||
; PUT App.Msg.s
|
||||
; PUT font.s
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -24,6 +24,7 @@ GEM
|
|||
http_parser.rb (~> 0)
|
||||
ethon (0.15.0)
|
||||
ffi (>= 1.15.0)
|
||||
eventmachine (1.2.7)
|
||||
eventmachine (1.2.7-x64-mingw32)
|
||||
execjs (2.8.1)
|
||||
faraday (1.10.0)
|
||||
|
@ -49,6 +50,7 @@ GEM
|
|||
faraday-patron (1.0.0)
|
||||
faraday-rack (1.0.0)
|
||||
faraday-retry (1.0.3)
|
||||
ffi (1.15.5)
|
||||
ffi (1.15.5-x64-mingw32)
|
||||
forwardable-extended (2.6.0)
|
||||
gemoji (3.0.1)
|
||||
|
@ -218,13 +220,15 @@ GEM
|
|||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
mercenary (0.3.6)
|
||||
mini_portile2 (2.8.0)
|
||||
minima (2.5.1)
|
||||
jekyll (>= 3.5, < 5.0)
|
||||
jekyll-feed (~> 0.9)
|
||||
jekyll-seo-tag (~> 2.1)
|
||||
minitest (5.15.0)
|
||||
multipart-post (2.2.0)
|
||||
nokogiri (1.12.5-x64-mingw32)
|
||||
nokogiri (1.13.9)
|
||||
mini_portile2 (~> 2.8.0)
|
||||
racc (~> 1.4)
|
||||
octokit (4.24.0)
|
||||
faraday (>= 1, < 3)
|
||||
|
@ -257,7 +261,7 @@ GEM
|
|||
thread_safe (0.3.6)
|
||||
typhoeus (1.4.0)
|
||||
ethon (>= 0.9.0)
|
||||
tzinfo (1.2.9)
|
||||
tzinfo (1.2.10)
|
||||
thread_safe (~> 0.1)
|
||||
tzinfo-data (1.2022.1)
|
||||
tzinfo (>= 1.0.0)
|
||||
|
@ -270,6 +274,7 @@ GEM
|
|||
|
||||
PLATFORMS
|
||||
x64-mingw32
|
||||
x86_64-linux
|
||||
|
||||
DEPENDENCIES
|
||||
github-pages (~> 203)
|
||||
|
|
|
@ -89,7 +89,11 @@ style: toolref
|
|||
</tr>
|
||||
<tr>
|
||||
<td><a href="#GTECreateSpriteStamp">GTECreateSpriteStamp</a></td>
|
||||
<td> Creates a sprite stamp from the tile set</td>
|
||||
<td>Creates a sprite stamp from the tile set</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#GTECompileSpriteStamp">GTECompileSpriteStamp</a></td>
|
||||
<td>Created a compiled sprite from a sprite stamp</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#GTEAddSprite">GTEAddSprite</a></td>
|
||||
|
@ -794,12 +798,12 @@ style: toolref
|
|||
<tr>
|
||||
<td class="bot">width</td>
|
||||
<td><em></em></td>
|
||||
<td><em>Word</em>—Width of the playfield in pixels. Must be even.</td>
|
||||
<td><em>Word</em>—Width of the playfield in bytes. Must be even.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot">height</td>
|
||||
<td><em></em></td>
|
||||
<td><em>Word</em>—Height of the playfield in pixels.</td>
|
||||
<td><em>Word</em>—Height of the playfield in scanlines.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot"></td>
|
||||
|
@ -1207,10 +1211,25 @@ style: toolref
|
|||
<td>Offsets each column of the secondary background's vertical position. Unimplemented.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>RENDER_BG1_ROTATIONT</td>
|
||||
<td>$0004</td>
|
||||
<td>RENDER_BG1_ROTATION</td>
|
||||
<td>$0008</td>
|
||||
<td>Use the internal rotation tables to render the secondary background</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>RENDER_PER_SCANLINE</td>
|
||||
<td>$0010</td>
|
||||
<td>Set individual scanline properties for the primary and secondary backgrounds from a table.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>RENDER_WITH_SHADOWING</td>
|
||||
<td>$0020</td>
|
||||
<td>Uses a rendering mode that does not draw sprites into the tiles but uses shadowing to draw sprites on top of the rendered background and then expose the final composited image. This mode is required to use compiled sprites.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>RENDER_SPRITES_SORTED</td>
|
||||
<td>$0040</td>
|
||||
<td>Draws the sprite in y-sorted order instead of sprite slot order.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -1234,9 +1253,18 @@ style: toolref
|
|||
</p>
|
||||
<p>
|
||||
A tile set is an array of (up to) 512 tile definitions and each tile definition is 128 bytes. The tile definition
|
||||
is comprised of four, 32-byte tiles; a normal tile, its mask, a horizontally flipped versio of the tile and its mask.
|
||||
is comprised of four, 32-byte tiles; a normal tile, its mask, a horizontally flipped version of the tile and its mask.
|
||||
The first 128 bytes of a tileset must be set to zero.
|
||||
</p>
|
||||
<p>
|
||||
The <em>start</em> and <em>finish</em> parameters define a subset of tiles to be copied into the GTE memory
|
||||
buffer. This is most commonly used to load a small number of tiles to avoid needing to store a full set of 512
|
||||
tiles that are mostly unushed. For eample, loading in 16 tiles can be performed as <tt>GTELoadTileSet(0, 17, tilePtr)</tt>.
|
||||
</p>
|
||||
<p>
|
||||
This function can also be used to swap out subsets of tiles on the fly. Any tiles that are replaced which may
|
||||
be on-screen are not automatically refreshed.
|
||||
</p>
|
||||
<div class="section">
|
||||
<h5>Parameters</h5>
|
||||
<table class="stack">
|
||||
|
@ -1252,6 +1280,16 @@ style: toolref
|
|||
<tr>
|
||||
<td class="top">previous contents</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot">start</td>
|
||||
<td></td>
|
||||
<td><em>Word</em>—index of the first tile to copy</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot">finish</td>
|
||||
<td></td>
|
||||
<td><em>Word</em>—terminating index. This tile is not copied.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot">tileSetPtr</td>
|
||||
<td></td>
|
||||
|
@ -1292,7 +1330,9 @@ style: toolref
|
|||
</div>
|
||||
<div class="section">
|
||||
<h5>C</h5>
|
||||
<p><tt>extern pascal void GTELoadTileSet(tileSetPtr)</tt></p>
|
||||
<p><tt>extern pascal void GTELoadTileSet(start, finish, tileSetPtr)</tt></p>
|
||||
<p><tt>Word start;</tt></p>
|
||||
<p><tt>Word finish;</tt></p>
|
||||
<p><tt>Pointer tileSetPtr;</tt></p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1403,6 +1443,90 @@ style: toolref
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="api">
|
||||
<h4 class="tn">$2DXX</h4>
|
||||
<h4 id="GTECompileSpriteStamp">GTECompileSpriteStamp</h4>
|
||||
<p>
|
||||
Creates a compiled sprite in a special compilation buffer from an existing sprite stamp. The return value
|
||||
is an address token that can be passed into the AddSprite function in place of the vBuffAddr parameter as
|
||||
long as the `SPRITE_COMPILED` flag is set.
|
||||
</p>
|
||||
<div class="section">
|
||||
<h5>Parameters</h5>
|
||||
<table class="stack">
|
||||
<colgroup>
|
||||
<col class="col-1">
|
||||
<col class="col-2">
|
||||
<col class="col-3">
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Stack before call</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top">previous contents</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot">wordspace</td>
|
||||
<td></td>
|
||||
<td><em>Word</em>—Space for result</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot">spriteIdent</td>
|
||||
<td></td>
|
||||
<td><em>Word</em>—sprite identifier word</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot">vBuffAddr</td>
|
||||
<td></td>
|
||||
<td><em>Word</em>—Location in the sprite vitual buffer.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot"></td>
|
||||
<td><em>←</em></td>
|
||||
<td><em>SP</em></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table class="stack">
|
||||
<colgroup>
|
||||
<col class="col-1">
|
||||
<col class="col-2">
|
||||
<col class="col-3">
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Stack after call</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="top">previous contents</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot">addr</td>
|
||||
<td></td>
|
||||
<td><em>Word</em>—Location in the sprite compilation buffer.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot"></td>
|
||||
<td><em>←</em></td>
|
||||
<td><em>SP</em></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="section">
|
||||
<h5>Errors</h5>
|
||||
<p>None</p>
|
||||
</div>
|
||||
<div class="section">
|
||||
<h5>C</h5>
|
||||
<p><tt>extern pascal Word GTECompileSpriteStamp(spriteIdent, vBuffAddr)</tt></p>
|
||||
<p><tt>Word spriteIdent;</tt></p>
|
||||
<p><tt>Word vBuffAddr;</tt></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="api">
|
||||
<h4 class="tn">$10XX</h4>
|
||||
<h4 id="GTEAddSprite">GTEAddSprite</h4>
|
||||
|
@ -1430,9 +1554,19 @@ style: toolref
|
|||
<td class="top">previous contents</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot">spriteDescriptor</td>
|
||||
<td class="bot">spriteSlot</td>
|
||||
<td></td>
|
||||
<td><em>Word</em>—Sprite descriptor word that is used to set the status bits.</td>
|
||||
<td><em>Word</em>—The slot to assign the sprite to. There are 16 slots and sprites in lower slots are drawn above the sprites in higher slots.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot">spriteFlags</td>
|
||||
<td></td>
|
||||
<td><em>Word</em>—Sprite flags that define the sprite's properties.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot">vBuffAddr</td>
|
||||
<td></td>
|
||||
<td><em>Word</em>—Sprite address in the VBUFF space, or a compiled sprite address</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot">x</td>
|
||||
|
@ -1444,11 +1578,6 @@ style: toolref
|
|||
<td></td>
|
||||
<td><em>Word</em>—Signed vertical sprite position on the playfield.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot">spriteSlot</td>
|
||||
<td></td>
|
||||
<td><em>Word</em>—The slot to assign the sprite to. There are 16 slots and sprites in lower slots are drawn above the sprites in higher slots.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot"></td>
|
||||
<td><em>←</em></td>
|
||||
|
@ -1484,11 +1613,12 @@ style: toolref
|
|||
</div>
|
||||
<div class="section">
|
||||
<h5>C</h5>
|
||||
<p><tt>extern pascal void GTEAddSprite(spriteDescriptor, x, y, spriteSlot)</tt></p>
|
||||
<p><tt>extern pascal void GTEAddSprite(spriteSlot, spriteFlags, vBuffAddr, x, y)</tt></p>
|
||||
<p><tt>Word spriteSlot;</tt></p>
|
||||
<p><tt>Word spriteDescriptor;</tt></p>
|
||||
<p><tt>Word vBuffAddr;</tt></p>
|
||||
<p><tt>Word x;</tt></p>
|
||||
<p><tt>Word y;</tt></p>
|
||||
<p><tt>Word spriteSlot;</tt></p>
|
||||
</div>
|
||||
<div class="example">
|
||||
<h5>Sprite Descriptor</h5>
|
||||
|
@ -3023,7 +3153,7 @@ style: toolref
|
|||
<div class="api">
|
||||
<h4 class="tn">$24XX</h4>
|
||||
<h4 id="GTEGetTileDataAddr">GTEGetTileDataAddr</h4>
|
||||
<p>This API is under active development at this time.</p>
|
||||
<p>Returns a pointer to the bottom of the internal tile data memory. The data for each tile can be found at offset <tt>N * 128</tt></p>
|
||||
<div class="section">
|
||||
<h5>Parameters</h5>
|
||||
<table class="stack">
|
||||
|
@ -3039,6 +3169,11 @@ style: toolref
|
|||
<tr>
|
||||
<td class="top">previous contents</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot">longspace</td>
|
||||
<td></td>
|
||||
<td><em>Long</em>—Space for result</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot"></td>
|
||||
<td><em>←</em></td>
|
||||
|
@ -3060,6 +3195,11 @@ style: toolref
|
|||
<tr>
|
||||
<td class="top">previous contents</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot">tileDataPtr</td>
|
||||
<td></td>
|
||||
<td><em>Long</em>—<span class="sc">pointer</span> to the tile data</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="bot"></td>
|
||||
<td><em>←</em></td>
|
||||
|
@ -3074,6 +3214,7 @@ style: toolref
|
|||
</div>
|
||||
<div class="section">
|
||||
<h5>C</h5>
|
||||
<p><tt>extern pascal Pointer GTEGetTileDataAddr()</tt></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
****************************************
|
||||
_Err mac
|
||||
bcc NoErr
|
||||
do ]0 ; (DO if true)
|
||||
do ]0 ; (DO if true) Mu
|
||||
jsr PgmDeath ; this is conditionally compiled if
|
||||
str ]1 ; we pass in an error statement
|
||||
else ; (ELSE)
|
||||
|
@ -182,216 +182,3 @@ ScriptStep MAC
|
|||
dw ]1,]2,]3,]4
|
||||
FIN
|
||||
<<<
|
||||
|
||||
; A specialized CopyMaskedWord macro that draws a tile from a direct page workspace. Used
|
||||
; to render fringe tiles and sprite tiles when BG1 is active. If there is no second background,
|
||||
; then one should use the optimized functions which assumes a PEA opcode and only
|
||||
; needs to copy data words
|
||||
;
|
||||
; ]1 : tiledata direct page address , the tilemask direct page address is tiledata + 32
|
||||
; ]2 : code field offset
|
||||
CopyMaskedWordD MAC
|
||||
lda ]1+32 ; load the mask value
|
||||
bne mixed ; a non-zero value may be mixed
|
||||
|
||||
; This is a solid word
|
||||
lda #$00F4 ; PEA instruction
|
||||
sta: ]2,y
|
||||
lda ]1 ; load the tile data
|
||||
sta: ]2+1,y ; PEA operand
|
||||
bra next
|
||||
|
||||
mixed cmp #$FFFF ; All 1's in the mask is fully transparent
|
||||
beq transparent
|
||||
|
||||
; This is the slowest path because there is a *lot* of work to do. So much that it's
|
||||
; worth it to change up the environment to optimize things a bit more.
|
||||
;
|
||||
; Need to fill in the first 10 bytes of the JMP handler with the following code sequence
|
||||
;
|
||||
; lda (00),y
|
||||
; and #MASK
|
||||
; ora #DATA
|
||||
|
||||
lda #$004C ; JMP instruction
|
||||
sta: ]2,y
|
||||
|
||||
ldx _X_REG ; Get the addressing offset
|
||||
ldal JTableOffset,x ; Get the address offset and add to the base address
|
||||
adc _BASE_ADDR ; of the current code field line
|
||||
adc #{]2&$F000} ; adjust for the current row offset
|
||||
sta: ]2+1,y
|
||||
|
||||
tay ; This becomes the new address that we use to patch in
|
||||
txa ; Get the offset and render a LDA (dp),y instruction
|
||||
|
||||
sep #$20
|
||||
sta: $0001,y ; LDA (00),y operand
|
||||
lda #$B1
|
||||
sta: $0000,y ; LDA (00),y opcode
|
||||
lda #$29
|
||||
sta: $0002,y ; AND #$0000 opcode
|
||||
lda #$09
|
||||
sta: $0005,y ; ORA #$0000 opcode
|
||||
rep #$20
|
||||
|
||||
lda ]1+32 ; insert the tile mask and data into the exception
|
||||
sta: $0003,y ; handler.
|
||||
lda ]1
|
||||
sta: $0006,y
|
||||
|
||||
lda #$0D80 ; branch to the prologue (BRA *+15)
|
||||
sta: $0008,y
|
||||
|
||||
ldy _Y_REG ; restore original y-register value and move on
|
||||
bra next
|
||||
|
||||
; This is a transparent word, so just show the second background layer
|
||||
transparent
|
||||
lda #$00B1 ; LDA (dp),y instruction
|
||||
sta: ]2,y
|
||||
lda _X_REG ; X is the logical tile offset (0, 2, 4, ... 82) left-to-right
|
||||
ora #$4800 ; put a PHA after the offset
|
||||
sta: ]2+1,y
|
||||
next
|
||||
eom
|
||||
|
||||
; Macros to use in the Masked Tile renderer
|
||||
;
|
||||
; ]1 : tiledata offset
|
||||
; ]2 : tilemask offset
|
||||
; ]3 : code field offset
|
||||
CopyMaskedWord MAC
|
||||
ldal ]2,x ; load the mask value
|
||||
bne mixed ; a non-zero value may be mixed
|
||||
|
||||
; This is a solid word
|
||||
lda #$00F4 ; PEA instruction
|
||||
sta: ]3,y
|
||||
ldal ]1,x ; load the tile data
|
||||
sta: ]3+1,y ; PEA operand
|
||||
bra next
|
||||
|
||||
mixed cmp #$FFFF ; All 1's in the mask is fully transparent
|
||||
beq transparent
|
||||
|
||||
; This is the slowest path because there is a *lot* of work to do. So much that it's
|
||||
; worth it to change up the environment to optimize things a bit more.
|
||||
;
|
||||
; Need to fill in the first 8 bytes of the JMP handler with the following code sequence
|
||||
;
|
||||
; lda (00),y
|
||||
; and #MASK
|
||||
; ora #DATA
|
||||
|
||||
lda #$004C ; JMP instruction
|
||||
sta: ]3,y
|
||||
|
||||
ldx _X_REG ; Get the addressing offset
|
||||
ldal JTableOffset,x ; Get the address offset and add to the base address
|
||||
ora _BASE_ADDR ; of the current code field row (2 rows per bank) $0000 or $8000
|
||||
ora #{]3&$7000} ; adjust for the current line offset within the row
|
||||
sta: ]3+1,y
|
||||
|
||||
tay ; This becomes the new address that we use to patch in
|
||||
txa ; Get the offset and render a LDA (dp),y instruction
|
||||
|
||||
sep #$20
|
||||
sta: $0001,y ; LDA (00),y operand
|
||||
lda #$B1
|
||||
sta: $0000,y ; LDA (00),y opcode
|
||||
lda #$29
|
||||
sta: $0002,y ; AND #$0000 opcode
|
||||
lda #$09
|
||||
sta: $0005,y ; ORA #$0000 opcode
|
||||
rep #$20
|
||||
|
||||
ldx _T_PTR ; restore the original x-register value
|
||||
ldal ]2,x ; insert the tile mask and data into the exception
|
||||
sta: $0003,y ; handler.
|
||||
ldal ]1,x
|
||||
sta: $0006,y
|
||||
|
||||
; Copy the top 9 bytes down. We have 23 bytes of space and are only using 8. Since 9 + 8 = 17 < 23, we
|
||||
; can save 3 cycles per word by eliminating the BRA instruction
|
||||
|
||||
; lda #$0D80 ; branch to the prologue (BRA *+15)
|
||||
; sta: $0008,y
|
||||
|
||||
lda: $0017,y
|
||||
sta: $0008,y
|
||||
lda: $0019,y
|
||||
sta: $000A,y
|
||||
lda: $001B,y
|
||||
sta: $000C,y
|
||||
lda: $001D,y
|
||||
sta: $000E,y
|
||||
lda: $001E,y
|
||||
sta: $000F,y
|
||||
|
||||
ldy _Y_REG ; restore original y-register value and move on
|
||||
bra next
|
||||
|
||||
; This is a transparent word, so just show the second background layer
|
||||
transparent
|
||||
lda #$00B1 ; LDA (dp),y instruction
|
||||
sta: ]3,y
|
||||
lda _X_REG ; X is the logical tile offset (0, 2, 4, ... 82) left-to-right
|
||||
ora #$4800 ; put a PHA after the offset
|
||||
sta: ]3+1,y
|
||||
next
|
||||
eom
|
||||
|
||||
; Large code blocks that can be used in sprite blitters
|
||||
; ]1: line number
|
||||
OneSpriteToCodeField mac
|
||||
lda blttmp+{]1*4}
|
||||
andl spritemask+{]1*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]1*SPRITE_PLANE_SPAN},x
|
||||
sta: $0004+{]1*$1000},y
|
||||
|
||||
lda blttmp+{]1*4}+2
|
||||
andl spritemask+{]1*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]1*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: $0001+{]1*$1000},y
|
||||
eom
|
||||
|
||||
TwoSpritesToCodeField mac
|
||||
ldy #{]1*SPRITE_PLANE_SPAN}
|
||||
lda blttmp+{]1*4}
|
||||
andl [spritemask_1],y
|
||||
oral [spritedata_1],y
|
||||
andl [spritemask_0],y
|
||||
oral [spritedata_0],y
|
||||
sta: $0004+{]1*$1000},x
|
||||
|
||||
ldy #{]1*SPRITE_PLANE_SPAN}+2
|
||||
lda blttmp+{]1*4}+2
|
||||
andl [spritemask_1],y
|
||||
oral [spritedata_1],y
|
||||
andl [spritemask_0],y
|
||||
oral [spritedata_0],y
|
||||
sta: $0001+{]1*$1000},x
|
||||
eom
|
||||
|
||||
ThreeSpritesToCodeField mac
|
||||
ldy #{]1*SPRITE_PLANE_SPAN}
|
||||
lda blttmp+{]1*4}
|
||||
andl [spritemask_2],y
|
||||
oral [spritedata_2],y
|
||||
andl [spritemask_1],y
|
||||
oral [spritedata_1],y
|
||||
andl [spritemask_0],y
|
||||
oral [spritedata_0],y
|
||||
sta: $0004+{]1*$1000},x
|
||||
|
||||
ldy #{]1*SPRITE_PLANE_SPAN}+2
|
||||
lda blttmp+{]1*4}+2
|
||||
andl [spritemask_2],y
|
||||
oral [spritedata_2],y
|
||||
andl [spritemask_1],y
|
||||
oral [spritedata_1],y
|
||||
andl [spritemask_0],y
|
||||
oral [spritedata_0],y
|
||||
sta: $0001+{]1*$1000},x
|
||||
eom
|
||||
|
|
|
@ -126,6 +126,15 @@ _GTEClearBG1Buffer MAC
|
|||
_GTESetBG1Scale MAC
|
||||
UserTool $2B00+GTEToolNum
|
||||
<<<
|
||||
_GTEGetAddress MAC
|
||||
UserTool $2C00+GTEToolNum
|
||||
<<<
|
||||
_GTECompileSpriteStamp MAC
|
||||
UserTool $2D00+GTEToolNum
|
||||
<<<
|
||||
_GTESetAddress MAC
|
||||
UserTool $2E00+GTEToolNum
|
||||
<<<
|
||||
|
||||
; EngineMode definitions
|
||||
; Script definition
|
||||
|
@ -146,12 +155,30 @@ PAD_KEY_DOWN equ $0400
|
|||
ENGINE_MODE_TWO_LAYER equ $0001
|
||||
ENGINE_MODE_DYN_TILES equ $0002
|
||||
ENGINE_MODE_BNK0_BUFF equ $0004
|
||||
ENGINE_MODE_USER_TOOL equ $8000 ; Communicate if GTE is loaded as a system tool, or a user tool
|
||||
|
||||
; Render flags
|
||||
RENDER_ALT_BG1 equ $0001
|
||||
RENDER_BG1_HORZ_OFFSET equ $0002
|
||||
RENDER_BG1_VERT_OFFSET equ $0004
|
||||
RENDER_BG1_ROTATION equ $0008
|
||||
RENDER_PER_SCANLINE equ $0010
|
||||
RENDER_WITH_SHADOWING equ $0020
|
||||
RENDER_SPRITES_SORTED equ $0040
|
||||
|
||||
; Overlay flags
|
||||
OVERLAY_MASKED equ $0000 ; Overlay has a mask, so the background must be draw first
|
||||
OVERLAY_SOLID equ $8000 ; Overlay covers the scan line and is fully opaque
|
||||
OVERLAY_ABOVE equ $0000 ; Overlay is drawn above scanline sprites
|
||||
OVERLAY_BELOW equ $4000 ; Overlay is drawn below scanline sprites
|
||||
|
||||
; GetAddress table IDs
|
||||
scanlineHorzOffset equ $0001
|
||||
scanlineHorzOffset2 equ $0002
|
||||
|
||||
; CopyPicToBG1 flags
|
||||
COPY_PIC_NORMAL equ $0000 ; Copy into BG1 buffer in "normal mode"
|
||||
COPY_PIC_SCANLINE equ $0001 ; Copy in a way to support BG1 + RENDER_PER_SCANLINE.
|
||||
|
||||
; Tile constants
|
||||
; TILE_RESERVED_BIT equ $8000
|
||||
|
@ -164,8 +191,8 @@ TILE_HFLIP_BIT equ $0200
|
|||
TILE_ID_MASK equ $01FF
|
||||
TILE_CTRL_MASK equ $FE00
|
||||
|
||||
|
||||
; Sprite constants
|
||||
SPRITE_COMPILED equ $4000 ; This is a compiled sprite
|
||||
SPRITE_HIDE equ $2000
|
||||
SPRITE_16X16 equ $1800
|
||||
SPRITE_16X8 equ $1000
|
||||
|
|
|
@ -1,8 +1,192 @@
|
|||
{
|
||||
"name": "generic-tile-engine",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "generic-tile-engine",
|
||||
"version": "1.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"pngjs": "^6.0.0",
|
||||
"string-builder": "^0.1.8",
|
||||
"watch": "latest",
|
||||
"xml2json": "^0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/exec-sh": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz",
|
||||
"integrity": "sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"merge": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/hoek": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz",
|
||||
"integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==",
|
||||
"deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/isemail": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz",
|
||||
"integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"punycode": "2.x.x"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/joi": {
|
||||
"version": "13.7.0",
|
||||
"resolved": "https://registry.npmjs.org/joi/-/joi-13.7.0.tgz",
|
||||
"integrity": "sha512-xuY5VkHfeOYK3Hdi91ulocfuFopwgbSORmIwzcwHKESQhC7w1kD5jaVSPnqDxS2I8t3RZ9omCKAxNwXN5zG1/Q==",
|
||||
"deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"hoek": "5.x.x",
|
||||
"isemail": "3.x.x",
|
||||
"topo": "3.x.x"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/joi/node_modules/hoek": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.4.tgz",
|
||||
"integrity": "sha512-Alr4ZQgoMlnere5FZJsIyfIjORBqZll5POhDsF4q64dPuJR6rNxXdDxtHSQq8OXRurhmx+PWYEE8bXRROY8h0w==",
|
||||
"deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/merge": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz",
|
||||
"integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/nan": {
|
||||
"version": "2.16.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz",
|
||||
"integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/node-expat": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/node-expat/-/node-expat-2.4.0.tgz",
|
||||
"integrity": "sha512-X8Y/Zk/izfNgfayeOeUGqze7KlaOwVJ9SDTjHUMKd0hu0aFTRpLlLCBwmx79cTPiQWD24I1YOafF+U+rTvEMfQ==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"bindings": "^1.5.0",
|
||||
"nan": "^2.13.2"
|
||||
}
|
||||
},
|
||||
"node_modules/pngjs": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz",
|
||||
"integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/string-builder": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/string-builder/-/string-builder-0.1.8.tgz",
|
||||
"integrity": "sha512-0pUtikmhChLaf+uLqzYTgzTCQc4jAjaWHolxPGq3D77SgSoTqkOlv0RVF3XwDxMR9x/y1WPPwkTNalZCA9DGnQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/topo": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz",
|
||||
"integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==",
|
||||
"deprecated": "This module has moved and is now available at @hapi/topo. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"hoek": "6.x.x"
|
||||
}
|
||||
},
|
||||
"node_modules/topo/node_modules/hoek": {
|
||||
"version": "6.1.3",
|
||||
"resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz",
|
||||
"integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==",
|
||||
"deprecated": "This module has moved and is now available at @hapi/hoek. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/watch": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/watch/-/watch-1.0.2.tgz",
|
||||
"integrity": "sha512-1u+Z5n9Jc1E2c7qDO8SinPoZuHj7FgbgU1olSFoyaklduDvvtX7GMMtlE6OC9FTXq4KvNAOfj6Zu4vI1e9bAKA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"exec-sh": "^0.2.0",
|
||||
"minimist": "^1.2.0"
|
||||
},
|
||||
"bin": {
|
||||
"watch": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.1.95"
|
||||
}
|
||||
},
|
||||
"node_modules/xml2json": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/xml2json/-/xml2json-0.12.0.tgz",
|
||||
"integrity": "sha512-EPJHRWJnJUYbJlzR4pBhZODwWdi2IaYGtDdteJi0JpZ4OD31IplWALuit8r73dJuM4iHZdDVKY1tLqY2UICejg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"hoek": "^4.2.1",
|
||||
"joi": "^13.1.2",
|
||||
"node-expat": "^2.3.18"
|
||||
},
|
||||
"bin": {
|
||||
"xml2json": "bin/xml2json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"bindings": {
|
||||
"version": "1.5.0",
|
||||
|
|
126
src/Core.s
126
src/Core.s
|
@ -1,126 +0,0 @@
|
|||
use Util.Macs.s
|
||||
use Load.Macs.s
|
||||
use Locator.Macs.s
|
||||
use Mem.Macs.s
|
||||
use Misc.Macs.s
|
||||
use Tool222.MACS.s
|
||||
use Core.MACS.s
|
||||
|
||||
use .\Defs.s
|
||||
|
||||
EngineStartUp ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
|
||||
jsr ToolStartUp ; Start up the toolbox tools we rely on
|
||||
jsr _CoreStartUp
|
||||
jsr SoundStartUp ; Start up any sound/music tools
|
||||
|
||||
plb
|
||||
rtl
|
||||
|
||||
EngineShutDown ENT
|
||||
phb
|
||||
phk
|
||||
plb
|
||||
|
||||
jsr SoundShutDown
|
||||
jsr _CoreShutDown
|
||||
jsr ToolShutDown
|
||||
|
||||
plb
|
||||
rtl
|
||||
|
||||
ToolStartUp
|
||||
_TLStartUp ; normal tool initialization
|
||||
pha
|
||||
_MMStartUp
|
||||
_Err ; should never happen
|
||||
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
|
||||
|
||||
MasterId ds 2
|
||||
|
||||
; Fatal error handler invoked by the _Err macro
|
||||
PgmDeath tax
|
||||
pla
|
||||
inc
|
||||
phx
|
||||
phk
|
||||
pha
|
||||
bra ContDeath
|
||||
PgmDeath0 pha
|
||||
pea $0000
|
||||
pea $0000
|
||||
ContDeath ldx #$1503
|
||||
jsl $E10000
|
||||
|
||||
; Use Tool222 (NinjaTrackerPlus) for music playback
|
||||
SoundStartUp
|
||||
lda #NO_MUSIC
|
||||
bne :no_music
|
||||
|
||||
pea $00DE
|
||||
pea $0000
|
||||
_LoadOneTool
|
||||
_Err
|
||||
|
||||
lda UserId
|
||||
pha
|
||||
_NTPStartUp
|
||||
:no_music
|
||||
rts
|
||||
|
||||
SoundShutDown
|
||||
lda #NO_MUSIC
|
||||
bne :no_music
|
||||
_NTPShutDown
|
||||
:no_music
|
||||
rts
|
||||
|
||||
ToolShutDown
|
||||
rts
|
||||
|
||||
put CoreImpl.s
|
||||
put blitter/Template.s
|
||||
|
||||
put Memory.s
|
||||
put Graphics.s
|
||||
put Sprite.s
|
||||
put blitter/Tiles.s
|
||||
put Sprite2.s
|
||||
put SpriteRender.s
|
||||
put Render.s
|
||||
put Timer.s
|
||||
put Script.s
|
||||
put blitter/Blitter.s
|
||||
put blitter/Horz.s
|
||||
put blitter/PEISlammer.s
|
||||
put blitter/Tables.s
|
||||
put blitter/Tiles00000.s ; normal tiles
|
||||
put blitter/Tiles00001.s ; dynamic tiles
|
||||
put blitter/Tiles00010.s ; normal masked tiles
|
||||
put blitter/Tiles00011.s ; dynamic masked tiles
|
||||
|
||||
put blitter/Tiles10000.s ; normal tiles + sprites
|
||||
put blitter/Tiles10001.s ; dynamic tiles + sprites
|
||||
put blitter/Tiles10010.s ; normal masked tiles + sprites
|
||||
put blitter/Tiles10011.s ; dynamic masked tiles + sprites
|
||||
|
||||
put blitter/Tiles11000.s ; normal high priority tiles + sprites
|
||||
put blitter/Tiles11001.s ; dynamic high priority tiles + sprites
|
||||
put blitter/Tiles11010.s ; normal high priority masked tiles + sprites
|
||||
put blitter/Tiles11011.s ; dynamic high priority masked tiles + sprites
|
||||
|
||||
put blitter/TilesBG1.s
|
||||
put blitter/Vert.s
|
||||
put blitter/BG0.s
|
||||
put blitter/BG1.s
|
||||
put blitter/SCB.s
|
||||
put TileMap.s
|
|
@ -225,6 +225,8 @@ EngineReset
|
|||
stz BG1TileMapPtr
|
||||
stz BG1TileMapPtr+2
|
||||
|
||||
stz CompileBankTop
|
||||
|
||||
stz SCBArrayPtr
|
||||
stz SCBArrayPtr+2
|
||||
|
||||
|
@ -238,6 +240,7 @@ EngineReset
|
|||
sta tmp15
|
||||
stz tmp14
|
||||
|
||||
; Rebuild all of the bank blitters
|
||||
:loop
|
||||
ldx #BlitBuff
|
||||
lda #^BlitBuff
|
||||
|
@ -252,6 +255,15 @@ EngineReset
|
|||
dec tmp15
|
||||
bne :loop
|
||||
|
||||
; Set the scanline tables to reasonable default values
|
||||
; ldx #{416*2}-2
|
||||
; lda #0
|
||||
;:sxm_loop
|
||||
; sta StartXMod164Arr,x
|
||||
; dex
|
||||
; dex
|
||||
; bpl :sxm_loop
|
||||
|
||||
rts
|
||||
|
||||
|
||||
|
|
73
src/Defs.s
73
src/Defs.s
|
@ -40,12 +40,12 @@ EngineMode equ 20 ; Defined the mode/capabilities that ar
|
|||
; bit 2: 0 = No static buffer, 1 = Allocation Bank 00 space for a static screen buffer
|
||||
DirtyBits equ 22 ; Identify values that have changed between frames
|
||||
|
||||
BG1DataBank equ 24 ; Data bank that holds BG1 layer data
|
||||
BG1AltBank equ 26 ; Alternate BG1 bank
|
||||
CompileBank0 equ 24 ; Always zero to allow [CompileBank0],y addressing
|
||||
CompileBank equ 26 ; Data bank that holds compiled sprite code
|
||||
|
||||
BlitterDP equ 28 ; Direct page address the holder blitter data
|
||||
BlitterDP equ 28 ; Direct page address that holds blitter data
|
||||
|
||||
OldStartX equ 30
|
||||
OldStartX equ 30 ; Used to track deltas between frames
|
||||
OldStartY equ 32
|
||||
|
||||
LastPatchOffset equ 34 ; Offset into code field that was patched with BRA instructions
|
||||
|
@ -61,7 +61,7 @@ BG1StartYMod208 equ 46
|
|||
OldBG1StartX equ 48
|
||||
OldBG1StartY equ 50
|
||||
|
||||
BG1OffsetIndex equ 52
|
||||
BG1OffsetIndex equ 52 ; Utility index for scanline effect in BG1
|
||||
|
||||
BG0TileOriginX equ 54 ; Coordinate in the tile map that corresponds to the top-left corner
|
||||
BG0TileOriginY equ 56
|
||||
|
@ -73,22 +73,22 @@ BG1TileOriginY equ 64
|
|||
OldBG1TileOriginX equ 66
|
||||
OldBG1TileOriginY equ 68
|
||||
|
||||
TileMapWidth equ 70
|
||||
TileMapWidth equ 70 ; Pointer to memory holding the tile map for the primary background
|
||||
TileMapHeight equ 72
|
||||
TileMapPtr equ 74
|
||||
FringeMapPtr equ 78
|
||||
|
||||
BG1TileMapWidth equ 82
|
||||
BG1TileMapHeight equ 84
|
||||
BG1TileMapPtr equ 86
|
||||
BG1TileMapPtr equ 86 ; Pointer to memory holding the tile map for the secondary background
|
||||
|
||||
SCBArrayPtr equ 90 ; Used for palette binding
|
||||
SpriteBanks equ 94 ; Bank bytes for the sprite data and sprite mask
|
||||
LastRender equ 96 ; Record which render function was last executed
|
||||
; gap
|
||||
CompileBankTop equ 98 ; First free byte i nthe compile bank. Grows upward in memeory.
|
||||
SpriteMap equ 100 ; Bitmap of open sprite slots.
|
||||
ActiveSpriteCount equ 102
|
||||
BankLoad equ 104
|
||||
BG1DataBank equ 104 ; Data bank that holds BG1 layer data
|
||||
TileStoreBankAndBank01 equ 106
|
||||
TileStoreBankAndTileDataBank equ 108
|
||||
TileStoreBankDoubled equ 110
|
||||
|
@ -102,7 +102,9 @@ RenderFlags equ 124 ; Flags passed to the Render() function
|
|||
BG1Scaling equ 126
|
||||
|
||||
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
|
||||
|
||||
; Free space from 160 to 192
|
||||
|
||||
blttmp equ 192 ; 32 bytes of local cache/scratch space for blitter
|
||||
|
||||
tmp8 equ 224 ; another 16 bytes of temporary space to be used as scratch
|
||||
|
@ -166,12 +168,22 @@ SPRITE_VBUFF_PTR equ 224 ; 32 bytes of adjusted pointers to VBuf
|
|||
ENGINE_MODE_TWO_LAYER equ $0001
|
||||
ENGINE_MODE_DYN_TILES equ $0002
|
||||
ENGINE_MODE_BNK0_BUFF equ $0004
|
||||
ENGINE_MODE_USER_TOOL equ $8000 ; Communicate if GTE is loaded as a system tool, or a user tool
|
||||
|
||||
; Render flags
|
||||
RENDER_ALT_BG1 equ $0001
|
||||
RENDER_BG1_HORZ_OFFSET equ $0002
|
||||
RENDER_BG1_VERT_OFFSET equ $0004
|
||||
RENDER_BG1_ROTATION equ $0008
|
||||
RENDER_PER_SCANLINE equ $0010
|
||||
RENDER_WITH_SHADOWING equ $0020
|
||||
RENDER_SPRITES_SORTED equ $0040 ; Draw the sprites in y-sorted order. Otherwise, use the index.
|
||||
|
||||
; Overlay flags
|
||||
OVERLAY_MASKED equ $0000 ; Overlay has a mask, so the background must be draw first
|
||||
OVERLAY_SOLID equ $8000 ; Overlay covers the scan line and is fully opaque
|
||||
OVERLAY_ABOVE equ $0000 ; Overlay is drawn above scanline sprites
|
||||
OVERLAY_BELOW equ $4000 ; Overlay is drawn below scanline sprites
|
||||
|
||||
; DirtyBits definitions
|
||||
DIRTY_BIT_BG0_X equ $0001
|
||||
|
@ -182,6 +194,14 @@ DIRTY_BIT_BG0_REFRESH equ $0010
|
|||
DIRTY_BIT_BG1_REFRESH equ $0020
|
||||
DIRTY_BIT_SPRITE_ARRAY equ $0040
|
||||
|
||||
; GetAddress table IDs
|
||||
scanlineHorzOffset equ $0001 ; Table of 416 words, a double-array of scanline offset values. Values must be in range [0, 163]
|
||||
scanlineHorzOffset2 equ $0002 ; Table of 416 words, a double-array of scanline offset values. Values must be in range [0, 163]
|
||||
|
||||
; CopyPicToBG1 flags
|
||||
COPY_PIC_NORMAL equ $0000 ; Copy into BG1 buffer in "normal mode" treating the buffer as a 164x208 pixmap with stride of 256
|
||||
COPY_PIC_SCANLINE equ $0001 ; Copy in a way to support BG1 + RENDER_PER_SCANLINE. Pixmap is double-width, 327x200 with stride of 327
|
||||
|
||||
; Script definition
|
||||
YIELD equ $8000
|
||||
JUMP equ $4000
|
||||
|
@ -197,25 +217,27 @@ PAD_BUTTON_A equ $0200
|
|||
PAD_KEY_DOWN equ $0400
|
||||
|
||||
; Tile constants
|
||||
; TILE_RESERVED_BIT equ $8000
|
||||
TILE_PRIORITY_BIT equ $4000 ; Put tile on top of sprite
|
||||
TILE_DAMAGED_BIT equ $8000 ; Mark a tile as damaged (internal only)
|
||||
TILE_PRIORITY_BIT equ $4000 ; Put tile on top of sprite (unimplemented)
|
||||
TILE_FRINGE_BIT equ $2000 ; Unused
|
||||
TILE_SOLID_BIT equ $1000 ; Hint bit used in TWO_LAYER_MODE to optimize rendering
|
||||
TILE_DYN_BIT equ $0800 ; Is this a Dynamic Tile?
|
||||
TILE_VFLIP_BIT equ $0400
|
||||
TILE_HFLIP_BIT equ $0200
|
||||
TILE_ID_MASK equ $01FF
|
||||
TILE_CTRL_MASK equ $FE00
|
||||
; TILE_PROC_MASK equ $F800 ; Select tile proc for rendering
|
||||
TILE_CTRL_MASK equ $7E00
|
||||
; TILE_PROC_MASK equ $7800 ; Select tile proc for rendering
|
||||
|
||||
; Sprite constants
|
||||
SPRITE_HIDE equ $2000
|
||||
SPRITE_OVERLAY equ $8000 ; This is an overlay record. Stored as a sprite for render ordering purposes
|
||||
SPRITE_COMPILED equ $4000 ; This is a compiled sprite (SPRITE_DISP points to a routine in the compiled cache bank)
|
||||
SPRITE_HIDE equ $2000 ; Do not render the sprite
|
||||
SPRITE_16X16 equ $1800 ; 16 pixels wide x 16 pixels tall
|
||||
SPRITE_16X8 equ $1000 ; 16 pixels wide x 8 pixels tall
|
||||
SPRITE_8X16 equ $0800 ; 8 pixels wide x 16 pixels tall
|
||||
SPRITE_8X8 equ $0000 ; 8 pixels wide x 8 pixels tall
|
||||
SPRITE_VFLIP equ $0400
|
||||
SPRITE_HFLIP equ $0200
|
||||
SPRITE_VFLIP equ $0400 ; Flip the sprite vertically
|
||||
SPRITE_HFLIP equ $0200 ; Flip the sprite horizontally
|
||||
|
||||
; Stamp storage parameters
|
||||
VBUFF_STRIDE_BYTES equ {12*4} ; Each line has 4 slots of 16 pixels + 8 buffer pixels
|
||||
|
@ -263,11 +285,26 @@ VBuffArray EXT
|
|||
_stamp_step EXT
|
||||
VBuffVertTableSelect EXT
|
||||
VBuffHorzTableSelect EXT
|
||||
Overlays EXT
|
||||
; Overlays EXT
|
||||
BG1YCache EXT
|
||||
ScalingTables EXT
|
||||
NumHandles EXT
|
||||
Handles EXT
|
||||
|
||||
;StartXMod164Arr EXT
|
||||
;LastPatchOffsetArr EXT
|
||||
|
||||
_SortedHead EXT
|
||||
_ShadowListCount EXT
|
||||
_ShadowListTop EXT
|
||||
_ShadowListBottom EXT
|
||||
_DirectListCount EXT
|
||||
_DirectListTop EXT
|
||||
_DirectListBottom EXT
|
||||
|
||||
StartXMod164Tbl EXT
|
||||
LastOffsetTbl EXT
|
||||
BG1StartXMod164Tbl EXT
|
||||
|
||||
; Tool error codes
|
||||
NO_TIMERS_AVAILABLE equ 10
|
||||
|
|
|
@ -0,0 +1,271 @@
|
|||
; Large, unrolled loops for setting values in the code field that would be used by the Horz.s
|
||||
; and Vert.s code.
|
||||
;
|
||||
; The utility of these functions is that they do not need to do any sort of bank switching and
|
||||
; can update all of the play field lines in a single call. The downside is that they take up
|
||||
; significantly more space, need large auxiliary tables, and must be patched after the code
|
||||
; field memory is allocated.
|
||||
;
|
||||
; Probably still worth it....
|
||||
|
||||
BlitBuff EXT
|
||||
|
||||
; Patch the fast copy routines with the allocated memory addresses
|
||||
InitFastCopies
|
||||
|
||||
; Fist, patch the cttc routine
|
||||
|
||||
ldy #0
|
||||
ldx #0
|
||||
|
||||
:loop1
|
||||
lda BlitBuff+2,y ; Get the bank of each in the accumulatow low byte
|
||||
|
||||
sep #$20
|
||||
]line equ 0
|
||||
lup 16
|
||||
stal cttc_start+{]line*7}+4,x
|
||||
stal cttc_start+{{]line+208}*7}+4,x
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rep #$20
|
||||
|
||||
txa
|
||||
clc
|
||||
adc #7*16
|
||||
tax
|
||||
|
||||
tya
|
||||
clc
|
||||
adc #4
|
||||
tay
|
||||
|
||||
cpy #13*4
|
||||
bcs *+5
|
||||
brl :loop1
|
||||
|
||||
; Next, patch the two store routines
|
||||
|
||||
ldy #0
|
||||
ldx #0
|
||||
|
||||
:loop2
|
||||
lda BlitBuff+2,y ; Get the bank of each in the accumulatow low byte
|
||||
|
||||
sep #$20
|
||||
]line equ 0
|
||||
lup 16
|
||||
stal store_start+{]line*4}+1,x
|
||||
stal store_start+{{]line+208}*4}+1,x
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rep #$20
|
||||
|
||||
txa
|
||||
clc
|
||||
adc #4*16
|
||||
tax
|
||||
|
||||
tya
|
||||
clc
|
||||
adc #4
|
||||
tay
|
||||
|
||||
cpy #13*4
|
||||
bcs *+5
|
||||
brl :loop2
|
||||
|
||||
rtl
|
||||
|
||||
|
||||
; Function to load data from an array and store in the code field. Assume that the
|
||||
; bank register is already set to the bank of the srcAddr data
|
||||
srcAddr equ 0
|
||||
destOffset equ 2
|
||||
|
||||
CopyTblToCode
|
||||
ldal entry_7,x ; This is the entry point
|
||||
stal cttc_jump+1
|
||||
|
||||
txa ; Set the Y register to srcAddr - 2*start to compensate for the
|
||||
eor #$FFFF ; offset in the code. This does mean that the array we are copying
|
||||
sec ; cannot by near the beginning of the bank
|
||||
adc srcAddr
|
||||
tyx ; put the ending offset in X
|
||||
tay
|
||||
|
||||
ldal entry_7,x
|
||||
tax
|
||||
lda #$0060
|
||||
stal {cttc_start&$FF0000}+3,x ; patch at the next STAL instruction because the high byte is always zero
|
||||
|
||||
ldx destOffset ; byte offset within each line
|
||||
cttc_jump jsr $0000
|
||||
|
||||
lda #$009F ; restore the STAL opcode
|
||||
stal {cttc_start&$FF0000}+3,x
|
||||
|
||||
rtl
|
||||
|
||||
; Define the 416 addresses for each copy
|
||||
entry_7
|
||||
]line equ 0
|
||||
lup 416
|
||||
da cttc_start+{]line*7}
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
; Generate the code that performs the copy.
|
||||
cttc_unit mac
|
||||
lda: {]1*32}+{]2*2},y
|
||||
stal $000000+{]2*$1000},x
|
||||
<<<
|
||||
|
||||
cttc_start
|
||||
]bank equ 0
|
||||
lup 26
|
||||
cttc_unit ]bank;0
|
||||
cttc_unit ]bank;1
|
||||
cttc_unit ]bank;2
|
||||
cttc_unit ]bank;3
|
||||
cttc_unit ]bank;4
|
||||
cttc_unit ]bank;5
|
||||
cttc_unit ]bank;6
|
||||
cttc_unit ]bank;7
|
||||
cttc_unit ]bank;8
|
||||
cttc_unit ]bank;9
|
||||
cttc_unit ]bank;10
|
||||
cttc_unit ]bank;11
|
||||
cttc_unit ]bank;12
|
||||
cttc_unit ]bank;13
|
||||
cttc_unit ]bank;14
|
||||
cttc_unit ]bank;15
|
||||
]bank equ ]bank+1
|
||||
--^
|
||||
rts
|
||||
|
||||
Store8Bits
|
||||
txa
|
||||
asl
|
||||
adc #store_start
|
||||
stal s8b_jump+1
|
||||
|
||||
tya
|
||||
asl
|
||||
tax
|
||||
lda #$0060
|
||||
stal {store_start&$FF0000},x
|
||||
|
||||
ldx destOffset ; byte offset within each line
|
||||
lda srcAddr
|
||||
sep #$20
|
||||
s8b_jump jsr $0000
|
||||
|
||||
lda #$9F ; restore the STAL opcode
|
||||
stal {store_start&$FF0000},x
|
||||
rep #$20
|
||||
|
||||
rtl
|
||||
|
||||
Store16Bits
|
||||
txa
|
||||
asl
|
||||
adc #store_start
|
||||
stal s16b_jump+1
|
||||
|
||||
tya
|
||||
asl
|
||||
tax
|
||||
lda #$0060
|
||||
stal {store_start&$FF0000},x
|
||||
|
||||
ldx destOffset ; byte offset within each line
|
||||
lda srcAddr
|
||||
s16b_jump jsr $0000
|
||||
|
||||
lda #$009F ; restore the STAL opcode
|
||||
stal {store_start&$FF0000},x
|
||||
rtl
|
||||
|
||||
store_start
|
||||
lup 26
|
||||
stal $000000,x
|
||||
stal $001000,x
|
||||
stal $002000,x
|
||||
stal $003000,x
|
||||
stal $004000,x
|
||||
stal $005000,x
|
||||
stal $006000,x
|
||||
stal $007000,x
|
||||
stal $008000,x
|
||||
stal $009000,x
|
||||
stal $00A000,x
|
||||
stal $00B000,x
|
||||
stal $00C000,x
|
||||
stal $00D000,x
|
||||
stal $00E000,x
|
||||
stal $00F000,x
|
||||
--^
|
||||
rts
|
||||
|
||||
|
||||
CodeCopy8
|
||||
txa
|
||||
asl
|
||||
adc #store_start
|
||||
stal cc8_jump+1
|
||||
|
||||
tya
|
||||
asl
|
||||
tax
|
||||
lda #$0060
|
||||
stal {store8_start&$FF0000},x
|
||||
|
||||
ldx destOffset ; byte offset within each line
|
||||
lda srcAddr
|
||||
cc8_jump jsr $0000
|
||||
|
||||
lda #$009F ; restore the STAL opcode
|
||||
stal {store8_start&$FF0000},x
|
||||
rtl
|
||||
|
||||
store8_start
|
||||
lup 26
|
||||
pea $0000
|
||||
plb
|
||||
plb
|
||||
|
||||
lda $0000,y
|
||||
stal $000000,x
|
||||
lda $0000,y
|
||||
stal $001000,x
|
||||
lda $0000,y
|
||||
stal $002000,x
|
||||
lda $0000,y
|
||||
stal $003000,x
|
||||
lda $0000,y
|
||||
stal $004000,x
|
||||
lda $0000,y
|
||||
stal $005000,x
|
||||
lda $0000,y
|
||||
stal $006000,x
|
||||
lda $0000,y
|
||||
stal $007000,x
|
||||
lda $0000,y
|
||||
stal $008000,x
|
||||
lda $0000,y
|
||||
stal $009000,x
|
||||
lda $0000,y
|
||||
stal $00A000,x
|
||||
lda $0000,y
|
||||
stal $00B000,x
|
||||
lda $0000,y
|
||||
stal $00C000,x
|
||||
lda $C000,y
|
||||
stal $00D000,x
|
||||
lda $E000,y
|
||||
stal $00E000,x
|
||||
lda $F000,y
|
||||
stal $00F000,x
|
||||
--^
|
||||
rts
|
|
@ -4,13 +4,15 @@ InitGraphics
|
|||
jsr _ShadowOn
|
||||
jsr _GrafOn
|
||||
lda #0
|
||||
jsr _ClearToColor
|
||||
lda #0
|
||||
jsr _SetSCBs
|
||||
ldx #DefaultPalette
|
||||
lda #0
|
||||
jsr _SetPalette
|
||||
|
||||
ldx #SHR_LINE_WIDTH
|
||||
ldy #SHR_SCREEN_HEIGHT
|
||||
jsr _SetScreenMode
|
||||
|
||||
jsr _InitBG0 ; Initialize the background layer
|
||||
|
||||
lda EngineMode
|
||||
|
|
15
src/Master.s
15
src/Master.s
|
@ -11,28 +11,28 @@
|
|||
|
||||
; 64KB Tile Memory
|
||||
|
||||
ASM static\TileData.s
|
||||
ASM static/TileData.s
|
||||
KND #$1001 ; Type and Attributes ($10=Static,$01=Data)
|
||||
ALI BANK
|
||||
SNA TDATA
|
||||
|
||||
; 64KB Sprite Plane Data
|
||||
|
||||
ASM static\SprData.s
|
||||
ASM static/SprData.s
|
||||
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
|
||||
ALI BANK
|
||||
SNA SDATA
|
||||
|
||||
; 64KB Sprite Mask Data
|
||||
|
||||
ASM static\SprMask.s
|
||||
ASM static/SprMask.s
|
||||
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
|
||||
ALI BANK
|
||||
SNA SMASK
|
||||
|
||||
; 64KB Tile Store
|
||||
|
||||
ASM static\TileStore.s
|
||||
ASM static/TileStore.s
|
||||
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
|
||||
ALI BANK
|
||||
SNA TSTORE
|
||||
|
@ -43,3 +43,10 @@
|
|||
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
|
||||
ALI BANK
|
||||
SNA ROTDATA
|
||||
|
||||
; Additional code
|
||||
|
||||
ASM FastCopies.s
|
||||
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
|
||||
ALI BANK
|
||||
SNA FASTCPY
|
||||
|
|
17
src/Memory.s
17
src/Memory.s
|
@ -28,9 +28,7 @@ InitMemory lda EngineMode
|
|||
_TrackHandle ; returns LONG Handle on stack
|
||||
plx ; base address of the new handle
|
||||
pla ; high address 00XX of the new handle (bank)
|
||||
; _Deref
|
||||
; stx Buff00
|
||||
; sta Buff00+2
|
||||
|
||||
:no_bnk0_buff
|
||||
|
||||
PushLong #0 ; space for result
|
||||
|
@ -41,9 +39,6 @@ InitMemory lda EngineMode
|
|||
_TrackHandle ; returns LONG Handle on stack
|
||||
plx ; base address of the new handle
|
||||
pla ; high address 00XX of the new handle (bank)
|
||||
; _Deref
|
||||
; stx Buff01
|
||||
; sta Buff01+2
|
||||
|
||||
PushLong #0 ; space for result
|
||||
|
||||
|
@ -64,16 +59,20 @@ InitMemory lda EngineMode
|
|||
_Deref
|
||||
stx BlitterDP
|
||||
|
||||
; Allocate banks of memory for BG1
|
||||
; Allocate banks of memory for BG1. If the user wants to swap between multiple BG1 banks, then they need to be allocated
|
||||
; outside of GTE and selected using the GTESetBG1Bank() function. Passing a zero for that function's argument will
|
||||
; always set the bank to the allocated bank number. Bank 00 and Bank 01 are illegal values.
|
||||
|
||||
lda EngineMode
|
||||
bit #ENGINE_MODE_TWO_LAYER
|
||||
beq :no_bg1
|
||||
jsr AllocOneBank2
|
||||
sta BG1DataBank
|
||||
:no_bg1
|
||||
|
||||
jsr AllocOneBank2
|
||||
sta BG1AltBank
|
||||
:no_bg1
|
||||
sta CompileBank
|
||||
stz CompileBank0
|
||||
|
||||
; Allocate the 13 banks of memory we need and store in double-length array
|
||||
]step equ 0
|
||||
|
|
648
src/Render.s
648
src/Render.s
|
@ -8,8 +8,15 @@
|
|||
; and internal data structure to properly render the play field. Then the update pipeline is
|
||||
; executed.
|
||||
;
|
||||
; Everything is composited into the tiles in the playfield and then the screen is rendered in
|
||||
; a single pass.
|
||||
; There are two major rendering modes: a composited mode and a scanline mode. The composited mode
|
||||
; will render all of the sprites into the playfield tiles, and then perform a single blit to update
|
||||
; the entire playfield. The scanline mode utilized shadowing and blits the background scanlines
|
||||
; on sprite lines first, then draws the sprites and finally exposes the updated scanlines.
|
||||
;
|
||||
; The composited mode has the advantages of being able to render sprites behind tile data as well
|
||||
; as avoiding most overdraw. The scanline mode is able to draw sprites correctly even when scanline
|
||||
; effect are used on the background and has lower overhead, which can make it faster in some cases,
|
||||
; even with the additional overdraw.
|
||||
;
|
||||
; TODO -- actually check the dirty bits and be selective on what gets updated. For example, if
|
||||
; only the Y position changes, then we should only need to set new values on the
|
||||
|
@ -51,9 +58,10 @@ _Render
|
|||
jsr _UpdateBG0TileMap ; and the tile maps. These subroutines build up a list of tiles
|
||||
; jsr _UpdateBG1TileMap ; that need to be updated in the code field
|
||||
|
||||
jsr _ApplyTiles ; This function actually draws the new tiles into the code field
|
||||
|
||||
jsr _ApplyTiles ; This function actually draws the new tiles into the code field
|
||||
jsr _ApplyBG0XPos ; Patch the code field instructions with exit BRA opcode
|
||||
|
||||
lda #RENDER_BG1_ROTATION
|
||||
bit RenderFlags
|
||||
bne :skip_bg1_x
|
||||
|
@ -63,7 +71,7 @@ _Render
|
|||
; The code fields are locked in now and ready to be rendered. See if there is an overlay or any
|
||||
; other reason to render with shadowing off. Otherwise, just do things quickly.
|
||||
|
||||
lda Overlays
|
||||
lda Overlays+OVERLAY_ID
|
||||
beq :no_ovrly
|
||||
|
||||
jsr _ShadowOff
|
||||
|
@ -72,8 +80,9 @@ _Render
|
|||
; optimization that can be done here is that the lines can be rendered in any order
|
||||
; since it is not shown on-screen yet.
|
||||
|
||||
ldx Overlays+2 ; Blit the full virtual buffer to the screen
|
||||
ldy Overlays+4
|
||||
ldx Overlays+OVERLAY_TOP ; Blit the full virtual buffer to the screen
|
||||
ldy Overlays+OVERLAY_BOTTOM
|
||||
iny
|
||||
jsr _BltRange
|
||||
|
||||
; Turn shadowing back on
|
||||
|
@ -82,14 +91,10 @@ _Render
|
|||
|
||||
; Now render all of the remaining lines in top-to-bottom (or bottom-to-top) order
|
||||
|
||||
ldx #0
|
||||
ldy Overlays+2
|
||||
beq :skip
|
||||
jsr _BltRange
|
||||
:skip
|
||||
jsr _DoOverlay
|
||||
|
||||
ldx Overlays+4
|
||||
ldx Overlays+OVERLAY_BOTTOM
|
||||
inx
|
||||
cpx ScreenHeight
|
||||
beq :done
|
||||
ldy ScreenHeight
|
||||
|
@ -131,14 +136,14 @@ _Render
|
|||
rts
|
||||
|
||||
_DoOverlay
|
||||
lda Overlays+6
|
||||
lda Overlays+OVERLAY_PROC
|
||||
stal :disp+1
|
||||
lda Overlays+7
|
||||
lda Overlays+OVERLAY_PROC+1
|
||||
stal :disp+2
|
||||
|
||||
lda ScreenY0 ; pass the address of the first line of the overlay
|
||||
clc
|
||||
adc Overlays+2
|
||||
adc Overlays+OVERLAY_TOP
|
||||
asl
|
||||
tax
|
||||
lda ScreenAddr,x
|
||||
|
@ -147,6 +152,61 @@ _DoOverlay
|
|||
:disp jsl $000000
|
||||
rts
|
||||
|
||||
|
||||
; Use the per-scanline tables to set the screen. This is really meant to be used without the built-in tilemap
|
||||
; support and is more of a low-level way to control the background rendering
|
||||
_RenderScanlines
|
||||
lda BG1YTable ; Make sure we're in the right mode (0 = scanline mode, $1800 = normal mode)
|
||||
beq :ytbl_ok
|
||||
lda #1
|
||||
jsr _ResetBG1YTable
|
||||
:ytbl_ok
|
||||
|
||||
jsr _ApplyBG0YPos ; Set stack addresses for the virtual lines to the physical screen
|
||||
jsr _ApplyScanlineBG1YPos ; Set the y-register values of the blitter
|
||||
|
||||
; _ApplyBG0Xpos need to be split because we have to set the offsets, then draw in any updated tiles, and
|
||||
; finally patch out the code field. Right now, the BRA operand is getting overwritten by tile data.
|
||||
|
||||
jsr _ApplyBG0XPosPre
|
||||
jsr _ApplyBG1XPosPre
|
||||
|
||||
jsr _ApplyScanlineBG0XPos ; Patch the code field instructions with exit BRA opcode
|
||||
jsr _ApplyScanlineBG1XPos
|
||||
|
||||
jsr _BuildShadowList ; Create the rages based on the sorted sprite y-values
|
||||
|
||||
jsr _ShadowOff ; Turn off shadowing and draw all the scanlines with sprites on them
|
||||
jsr _DrawShadowList
|
||||
jsr _DrawDirectSprites ; Draw the sprites directly to the Bank $01 graphics buffer (skipping the render-to-tile step)
|
||||
|
||||
jsr _ShadowOn ; Turn shadowing back on
|
||||
jsr _DrawFinalPass
|
||||
|
||||
lda StartYMod208 ; Restore the fields back to their original state
|
||||
ldx ScreenHeight
|
||||
jsr _RestoreScanlineBG0Opcodes
|
||||
|
||||
lda StartY
|
||||
sta OldStartY
|
||||
lda StartX
|
||||
sta OldStartX
|
||||
|
||||
lda BG1StartY
|
||||
sta OldBG1StartY
|
||||
lda BG1StartX
|
||||
sta OldBG1StartX
|
||||
|
||||
stz DirtyBits
|
||||
stz LastRender ; Mark that a full render was just performed
|
||||
|
||||
lda SpriteRemovedFlag ; If any sprite was removed, set the rebuild flag
|
||||
beq :no_removal
|
||||
lda #DIRTY_BIT_SPRITE_ARRAY
|
||||
sta DirtyBits
|
||||
:no_removal
|
||||
rts
|
||||
|
||||
; Run through all of the tiles on the DirtyTile list and render them
|
||||
_ApplyTiles
|
||||
ldx DirtyTileCount
|
||||
|
@ -213,3 +273,561 @@ _ApplyDirtyTiles
|
|||
stz DirtyTileCount ; Reset the dirty tile count
|
||||
rts
|
||||
|
||||
; This rendering mode turns off shadowing and draws all of the relevant background lines and then
|
||||
; draws sprites on top of the background before turning shadowing on and exposing the lines to the
|
||||
; screen. Even though entire lines are drawn twice, it's so efficient that it is often faster
|
||||
; than using all of the logic to draw/erase tiles in the TileBuffer, even though less visible words
|
||||
; are touched.
|
||||
;
|
||||
; This mode is also necessary if per-scanling rendering it used since sprites would not look correct
|
||||
; if each line had independent offsets.
|
||||
_RenderWithShadowing
|
||||
sta RenderFlags
|
||||
jsr _DoTimers ; Run any pending timer tasks
|
||||
|
||||
jsr _ApplyBG0YPos ; Set stack addresses for the virtual lines to the physical screen
|
||||
jsr _ApplyBG1YPos ; Set the y-register values of the blitter
|
||||
|
||||
; _ApplyBG0Xpos need to be split because we have to set the offsets, then draw in any updated tiles, and
|
||||
; finally patch out the code field. Right now, the BRA operand is getting overwritten by tile data.
|
||||
|
||||
jsr _ApplyBG0XPosPre
|
||||
jsr _ApplyBG1XPosPre
|
||||
|
||||
jsr _UpdateBG0TileMap ; and the tile maps. These subroutines build up a list of tiles
|
||||
; jsr _UpdateBG1TileMap ; that need to be updated in the code field
|
||||
|
||||
jsr _ApplyTiles ; This function actually draws the new tiles into the code field
|
||||
|
||||
jsr _ApplyBG0XPos ; Patch the code field instructions with exit BRA opcode
|
||||
jsr _ApplyBG1XPos ; Update the direct page value based on the horizontal position
|
||||
|
||||
; At this point, everything in the background has been rendered into the code field. Next, we need
|
||||
; to create priority lists of scanline ranges.
|
||||
|
||||
jsr _BuildShadowList ; Create the rages based on the sorted sprite y-values
|
||||
|
||||
jsr _ShadowOff ; Turn off shadowing and draw all the scanlines with sprites on them
|
||||
jsr _DrawShadowList
|
||||
jsr _DrawDirectSprites ; Draw the sprites directly to the Bank $01 graphics buffer (skipping the render-to-tile step)
|
||||
|
||||
jsr _ShadowOn ; Turn shadowing back on
|
||||
; jsr _DrawComplementList ; Alternate drawing scanlines and PEI slam to expose the full fram
|
||||
jsr _DrawFinalPass
|
||||
|
||||
;
|
||||
; The objects that need to be reasoned about are
|
||||
;
|
||||
; 1. Sprites
|
||||
; 2. Overlays
|
||||
; a. Solid High Priority
|
||||
; b. Solid Low Priority
|
||||
; c. Masked High Priority
|
||||
; d. Masked Low Priority
|
||||
; 3. Background
|
||||
;
|
||||
; Notes:
|
||||
;
|
||||
; A High Priority overlay is rendered above the sprites
|
||||
; A Low Priority overlay is rendered below the sprites
|
||||
; A Solid High Priority overlay obscured everything and if the only thing drawn on the scanline
|
||||
;
|
||||
; The order of draw oprations is:
|
||||
;
|
||||
; 1. Turn off shadowing
|
||||
; 2. Draw the background for scanlines with (Sprites OR a Masked Low Priority overlay) AND NOT a Solid Low Priority overlay
|
||||
; 3. Draw the Solid Low Priority overlays
|
||||
; 4. Draw the Sprites
|
||||
; 5. Draw the Masked Low Priority overlays
|
||||
; 6. Turn on shadowing
|
||||
; 7. Draw, in top-to-bottom order
|
||||
; a. Background lines not drawn yet
|
||||
; b. PEI Slam lines with (Sprites OR a Masked Low Priority Overlay) AND NOT a High Priority overlay
|
||||
; c. High Priority overlays
|
||||
;
|
||||
; The work of this routine is to quickly build a sorted list of scanline ranges that can the appropriate
|
||||
; sub-renderer
|
||||
|
||||
; jsr BuildShadowSegments
|
||||
;
|
||||
; The trick is to create a bit-field mapping for the different actions to define
|
||||
|
||||
; lda Overlays
|
||||
; beq :no_ovrly
|
||||
;
|
||||
; jsr _ShadowOff
|
||||
|
||||
; Shadowing is turned off. Render all of the scan lines that need a second pass. One
|
||||
; optimization that can be done here is that the lines can be rendered in any order
|
||||
; since it is not shown on-screen yet.
|
||||
|
||||
; ldx Overlays+OVERLAY_TOP ; Blit the full virtual buffer to the screen
|
||||
; ldy Overlays+OVERLAY_BOTTOM
|
||||
; jsr _BltRange
|
||||
|
||||
; Turn shadowing back on
|
||||
|
||||
; jsr _ShadowOn
|
||||
|
||||
; Now render all of the remaining lines in top-to-bottom (or bottom-to-top) order
|
||||
|
||||
; ldx #0
|
||||
; ldy Overlays+OVERLAY_TOP
|
||||
; beq :skip
|
||||
; jsr _BltRange
|
||||
;:skip
|
||||
; jsr _DoOverlay
|
||||
|
||||
; ldx Overlays+OVERLAY_BOTTOM
|
||||
; cpx ScreenHeight
|
||||
; beq :done
|
||||
; ldy ScreenHeight
|
||||
; jsr _BltRange
|
||||
; bra :done
|
||||
|
||||
;:no_ovrly
|
||||
|
||||
; ldx #0 ; Blit the full virtual buffer to the screen
|
||||
; ldy ScreenHeight
|
||||
; jsr _BltRange
|
||||
|
||||
;:done
|
||||
|
||||
; ldx #0
|
||||
; ldy ScreenHeight
|
||||
; jsr _BltSCB
|
||||
|
||||
lda StartYMod208 ; Restore the fields back to their original state
|
||||
ldx ScreenHeight
|
||||
jsr _RestoreBG0Opcodes
|
||||
|
||||
lda StartY
|
||||
sta OldStartY
|
||||
lda StartX
|
||||
sta OldStartX
|
||||
|
||||
lda BG1StartY
|
||||
sta OldBG1StartY
|
||||
lda BG1StartX
|
||||
sta OldBG1StartX
|
||||
|
||||
stz DirtyBits
|
||||
stz LastRender ; Mark that a full render was just performed
|
||||
|
||||
lda SpriteRemovedFlag ; If any sprite was removed, set the rebuild flag
|
||||
beq :no_removal
|
||||
lda #DIRTY_BIT_SPRITE_ARRAY
|
||||
sta DirtyBits
|
||||
:no_removal
|
||||
rts
|
||||
|
||||
; Look at the overlay list and the sprite list and figure out which scanline ranges need to be
|
||||
; blitted in what order. We try to build all of the scan line segments lists because that
|
||||
; saves the work of re-scanning the lists.
|
||||
;
|
||||
; The semgent list definitions are:
|
||||
;
|
||||
; BLIT_W_SHADOW_OF
|
||||
BuildShadowSegments
|
||||
; ldx _SortedHead
|
||||
; bmi :no_sprite
|
||||
;:loop
|
||||
; lda _Sprites+CLIP_TOP,x
|
||||
; lda _Sprites+SORTED_NEXT,x
|
||||
; tax
|
||||
; bpl :loop
|
||||
;
|
||||
; lda #0 ; Start at the top of the
|
||||
|
||||
rts
|
||||
|
||||
; Function to iterate through the sprite list and build a merged scanline list of sprites. Once this is
|
||||
; done, we re-scan the list to build the complement for scanlines that do not need shadowing.
|
||||
_BuildShadowList
|
||||
|
||||
ldy #0 ; This is the index into the list of shadow segments
|
||||
|
||||
ldx _SortedHead
|
||||
bmi :empty
|
||||
bra :insert
|
||||
|
||||
; Start of loop
|
||||
:advance
|
||||
iny
|
||||
iny
|
||||
|
||||
:insert
|
||||
lda _Sprites+SPRITE_CLIP_TOP,x ; Load the sprite's top line
|
||||
sta _ShadowListTop,y ; Set the top entry of the list to the sprite top
|
||||
|
||||
lda _Sprites+SPRITE_CLIP_BOTTOM,x ; Optimistically set the end of the segment to the bottom of this sprite
|
||||
inc ; Clip values are on the scanline, so add one to make it a proper interval
|
||||
|
||||
:replace
|
||||
sta _ShadowListBottom,y
|
||||
:skip
|
||||
lda _Sprites+SORTED_NEXT,x ; If there another sprite in the list?
|
||||
bmi :no_more_sprites ; If not, we can finish up
|
||||
|
||||
tax
|
||||
lda _ShadowListBottom,y ; If the bottom of the current sprite is _less than_ the top of the next
|
||||
cmp _Sprites+SPRITE_CLIP_TOP,x ; sprite, then there is a gap and we create a new entry
|
||||
bcc :advance
|
||||
|
||||
lda _Sprites+SPRITE_CLIP_BOTTOM,x ; Get the bottom value of the next sprite.
|
||||
inc
|
||||
cmp _ShadowListBottom,y ; If it extends the segment then replace the value, otherwise skip
|
||||
bcc :skip
|
||||
bra :replace
|
||||
|
||||
:no_more_sprites
|
||||
iny ; Set the list count to N * 2
|
||||
iny
|
||||
:empty
|
||||
sty _ShadowListCount
|
||||
rts
|
||||
|
||||
; Run through the shadow list and make a complementary list, e.g
|
||||
; [[0, 7], [12, 19]] -> [[7, 12], [19, end]]
|
||||
; [[2, 10], [20, 40]] -> [[0, 2], [10, 20], [40, end]]
|
||||
|
||||
_ComplementList
|
||||
ldy #0
|
||||
tyx
|
||||
|
||||
lda _ShadowListCount
|
||||
beq :empty_list
|
||||
|
||||
lda _ShadowListTop
|
||||
beq :loop
|
||||
|
||||
stz _DirectListTop
|
||||
sta _DirectListBottom
|
||||
|
||||
inx
|
||||
inx
|
||||
|
||||
:loop
|
||||
lda _ShadowListBottom,y
|
||||
sta _DirectListTop,x
|
||||
|
||||
iny ; Move to the next shadow list record
|
||||
iny
|
||||
cpy _ShadowListCount ; Are there any other segments to process
|
||||
bcs :eol
|
||||
|
||||
lda _ShadowListTop,y
|
||||
sta _DirectListBottom,x ; Finish the direct list entry
|
||||
|
||||
inx
|
||||
inx
|
||||
bra :loop
|
||||
|
||||
:eol
|
||||
lda ScreenHeight
|
||||
sta _DirectListBottom,x
|
||||
|
||||
inx ; Set the count to N * 2
|
||||
inx
|
||||
stx _DirectListCount
|
||||
rts
|
||||
|
||||
:empty_list
|
||||
lda #1
|
||||
sta _DirectListCount
|
||||
stz _DirectListTop
|
||||
lda ScreenHeight
|
||||
sta _DirectListBottom
|
||||
rts
|
||||
|
||||
; Iterate through the shadow list and call _BltRange on each
|
||||
_DrawShadowList
|
||||
ldx #0
|
||||
bra :start
|
||||
|
||||
:loop
|
||||
phx ; Save the index
|
||||
lda _ShadowListTop,x
|
||||
ldy _ShadowListBottom,x
|
||||
tax
|
||||
jsr _BltRange
|
||||
|
||||
plx
|
||||
inx
|
||||
inx
|
||||
:start
|
||||
cpx _ShadowListCount
|
||||
bcc :loop
|
||||
|
||||
rts
|
||||
|
||||
; Run through the list of sprites that are not IS_OFFSCREEN and not OVERLAYS and draw them directly to the graphics screen. We can use
|
||||
; compiled sprites here, with limitations.
|
||||
_DrawDirectSprites
|
||||
lda RenderFlags
|
||||
bit #RENDER_SPRITES_SORTED
|
||||
bne :sorted
|
||||
|
||||
; Shift through the sprites
|
||||
|
||||
lda SpriteMap
|
||||
beq :empty
|
||||
sta tmp15
|
||||
ldx #0
|
||||
|
||||
:iloop
|
||||
lsr tmp15
|
||||
bcc :next
|
||||
jsr :render
|
||||
|
||||
:next inx
|
||||
inx
|
||||
lda tmp15
|
||||
bne :iloop
|
||||
rts
|
||||
|
||||
:sorted
|
||||
ldx _SortedHead
|
||||
bmi :empty
|
||||
|
||||
:loop
|
||||
jsr :render
|
||||
lda _Sprites+SORTED_NEXT,x ; If there another sprite in the list?
|
||||
tax
|
||||
bpl :loop
|
||||
:empty
|
||||
rts
|
||||
|
||||
:render
|
||||
lda _Sprites+SPRITE_ID,x
|
||||
bit #SPRITE_OVERLAY
|
||||
beq *+3
|
||||
rts
|
||||
lda _Sprites+SPRITE_STATUS,x
|
||||
bit #SPRITE_STATUS_HIDDEN
|
||||
beq *+3
|
||||
rts
|
||||
phx
|
||||
jsr _DrawStampToScreen
|
||||
plx
|
||||
rts
|
||||
|
||||
|
||||
; Run through the sorted list and perform a final render the jumps between calling _PEISlam for shadowed lines,
|
||||
; _BltRange for clean backgrounds and Overlays as needed.
|
||||
;
|
||||
; The trick here is to merge runs of shared render types.
|
||||
;
|
||||
; Loop invariant: X-register is the current object index, Y-register is the next object index
|
||||
;
|
||||
; TODO: This does not yet handle the case of a narrow overlay in the middle of a sprite. The second half of the sprite will not be exposed
|
||||
; by a PEISlam.
|
||||
;
|
||||
; e.g. |--- Overlay ---|
|
||||
; |-------------- Sprite ----------------|
|
||||
;
|
||||
; Output Should be |-- PEI --||--- Overlay ---||--- PEI --|
|
||||
; But currently is |-- PEI --||--- Overlay ---|
|
||||
|
||||
_DrawFinalPass
|
||||
:curr_top equ tmp0
|
||||
:curr_bottom equ tmp1
|
||||
:curr_type equ tmp2
|
||||
|
||||
ldx _SortedHead
|
||||
bmi :empty
|
||||
|
||||
lda _Sprites+SPRITE_CLIP_TOP,x ; Load the first object's top edge
|
||||
beq :loop ; If it's at the top edge of the screen, proceed. Othrewise _BltRange the top range
|
||||
|
||||
ldx #0
|
||||
tay
|
||||
jsr _BltRange
|
||||
ldx _SortedHead ; Reload the register
|
||||
|
||||
:loop
|
||||
lda _Sprites+SPRITE_ID,x ; Save the type of the current segment. Do this first because it can be skipped
|
||||
and #SPRITE_OVERLAY ; when merging ranges of the same type
|
||||
sta :curr_type
|
||||
|
||||
lda _Sprites+SPRITE_CLIP_TOP,x
|
||||
sta :curr_top
|
||||
lda _Sprites+SPRITE_CLIP_BOTTOM,x ; Optimistically set the end of the segment to the bottom of this object
|
||||
inc ; Clip values are on the scanline, so add one to make it a proper interval
|
||||
|
||||
:update
|
||||
sta :curr_bottom
|
||||
|
||||
:skip
|
||||
ldy _Sprites+SORTED_NEXT,x ; If there another object in the list?
|
||||
bmi :no_more ; If not, we can finish up
|
||||
|
||||
lda :curr_bottom ; If the bottom of the current object is _less than_ the top of the next
|
||||
cmp _Sprites+SPRITE_CLIP_TOP,y ; sprite, then there is a gap and we can draw the current object and a
|
||||
bcc :advance ; _BltRange up to the next one
|
||||
|
||||
; Here, we've established that there is another object segment that starts at or within the bounds of the current
|
||||
; object. If they are of the same type, then we can merge them and look at the next object in the list; treating
|
||||
; the merges range as a larger, single object range.
|
||||
;
|
||||
; If they are different, then clip the current object range to the top of the next one, render the current object
|
||||
; range and then take the new object as the current one.
|
||||
;
|
||||
; If the first object extends past the second, we are going to miss the remainder of that object. We really need a
|
||||
; stack to put it on so that it can eventually be processed later.
|
||||
|
||||
lda _Sprites+SPRITE_ID,y
|
||||
and #SPRITE_OVERLAY
|
||||
cmp :curr_type
|
||||
bne :no_merge
|
||||
|
||||
tyx ; Move the next index into the current
|
||||
lda _Sprites+SPRITE_CLIP_BOTTOM,y ; Get the bottom value of the next sprite.
|
||||
inc
|
||||
cmp :curr_bottom ; If it extends the segment then replace the bottom value, otherwise skip. In
|
||||
bcc :skip ; either case, the type and top value remain the same
|
||||
bra :update
|
||||
|
||||
; This is a simpler version of the 'advance' below. In this case there are overlapping ranges, so we just need to draw a
|
||||
; clipped version of the top range and then restart the loop with the next range.
|
||||
:no_merge
|
||||
lda _Sprites+SPRITE_CLIP_TOP,y ; Get the top of the next segment
|
||||
sta :curr_bottom ; Use it as the bottom of the current segment
|
||||
phy ; Save the next index...
|
||||
jsr :PEIOrOverlay ; Draw the current segment type
|
||||
plx ; ...and restore as the current
|
||||
bra :loop ; Start again
|
||||
|
||||
:advance
|
||||
phy
|
||||
jsr :PEIOrOverlay ; Draw the appropriate filler
|
||||
lda 1,s
|
||||
tax
|
||||
ldy _Sprites+SPRITE_CLIP_TOP,x ; Draw the background in between
|
||||
ldx :curr_bottom
|
||||
; brk $34
|
||||
jsr _BltRange
|
||||
plx
|
||||
bra :loop
|
||||
|
||||
; List is empty, so just do one big _BltRange with a tail call
|
||||
:empty
|
||||
ldx #0
|
||||
:no_more2
|
||||
ldy ScreenHeight
|
||||
jmp _BltRange
|
||||
|
||||
; Found the end of the list. Draw current object and then blit the rest of the screen
|
||||
:no_more
|
||||
jsr :PEIOrOverlay
|
||||
ldx :curr_bottom
|
||||
cpx ScreenHeight
|
||||
bcc :no_more2
|
||||
rts
|
||||
|
||||
; Help to select between calling an Overlay or PEISlam routine
|
||||
:PEIOrOverlay
|
||||
lda :curr_type
|
||||
bne :overlay
|
||||
|
||||
ldx :curr_top
|
||||
ldy :curr_bottom
|
||||
jmp _PEISlam
|
||||
:overlay
|
||||
lda _Sprites+OVERLAY_PROC,x
|
||||
stal :disp+1
|
||||
lda _Sprites+OVERLAY_PROC+1,x
|
||||
stal :disp+2
|
||||
|
||||
lda ScreenY0 ; pass the address of the first line of the overlay
|
||||
clc
|
||||
adc _Sprites+OVERLAY_TOP,x
|
||||
asl
|
||||
tax
|
||||
lda ScreenAddr,x
|
||||
clc
|
||||
adc ScreenX0
|
||||
ldx :curr_top
|
||||
ldy :curr_bottom
|
||||
; brk $33
|
||||
|
||||
:disp jsl $000000
|
||||
rts
|
||||
|
||||
|
||||
_DrawComplementList
|
||||
|
||||
ldx #0
|
||||
|
||||
lda _DirectListCount ; Skip empty lists
|
||||
beq :out
|
||||
|
||||
lda _DirectListTop ; If the first segment starts at 0, begin with _BltRange
|
||||
beq :blt_range
|
||||
|
||||
lda #0
|
||||
bra :pei_first
|
||||
|
||||
:blt_range
|
||||
phx
|
||||
lda _DirectListTop,x
|
||||
ldy _DirectListBottom,x
|
||||
tax
|
||||
jsr _BltRange
|
||||
plx
|
||||
|
||||
lda _DirectListBottom,x ; Grab a copy of the bottom of the blit range
|
||||
inx
|
||||
inx ; Advance to the next entry
|
||||
cpx _DirectListCount
|
||||
bcs :last ; Done, so check if there is any remaining part of the screen to slam
|
||||
|
||||
:pei_first
|
||||
phx
|
||||
ldy _DirectListTop,x
|
||||
tax
|
||||
jsr _PEISlam
|
||||
plx
|
||||
bra :blt_range
|
||||
|
||||
:last
|
||||
cmp ScreenHeight ; If the bottom on the last segment didn't come to the bottom of the
|
||||
bcs :out ; screen, then expose that range
|
||||
tax
|
||||
ldy ScreenHeight
|
||||
jsr _PEISlam
|
||||
:out
|
||||
rts
|
||||
|
||||
; Helper to set a palette index on a range of SCBs to help show which actions are applied to which lines
|
||||
DebugSCBs
|
||||
phx
|
||||
phy
|
||||
sep #$30 ; short m/x
|
||||
|
||||
pha ; save the SCB value
|
||||
|
||||
phx
|
||||
tya
|
||||
sec
|
||||
sbc 1,s
|
||||
tay ; number of scanlines
|
||||
|
||||
pla
|
||||
clc
|
||||
adc ScreenY0
|
||||
tax ; physical line index
|
||||
|
||||
pla
|
||||
:loop
|
||||
stal SHR_SCB,x
|
||||
inx
|
||||
dey
|
||||
bne :loop
|
||||
|
||||
rep #$30
|
||||
ply
|
||||
plx
|
||||
rts
|
||||
|
||||
|
||||
|
|
447
src/Sprite.s
447
src/Sprite.s
|
@ -150,7 +150,7 @@ ROW_BYTES equ 384 ; VBUFF_TILE_ROW_BYTES
|
|||
; a. If it is not marked in the DirtyTile list
|
||||
; * Clear its bit from the TileStore's TS_SPRITE_FLAG
|
||||
; * Add the tile to the DirtyTile list
|
||||
;t
|
||||
;
|
||||
; 2. If a sprite is marked as SPRITE_STATUS_REMOVED, then
|
||||
; A. Clear its bit from the SpriteBits bitmap
|
||||
; B. For each tile the sprite overlaps with:
|
||||
|
@ -223,10 +223,11 @@ _DoPhase1
|
|||
trb SpriteMap
|
||||
lda #SPRITE_STATUS_EMPTY ; Mark as empty so no error if we try to Add a sprite here again
|
||||
sta _Sprites+SPRITE_STATUS,y
|
||||
jmp _ClearSpriteFromTileStore ; Clear the tile flags, add to the dirty tile list and done
|
||||
|
||||
tyx
|
||||
jsr _DeleteSprite ; Remove sprite from linked list
|
||||
txy ; Restore y-register
|
||||
:hidden
|
||||
jmp _ClearSpriteFromTileStore
|
||||
jmp _ClearSpriteFromTileStore ; Clear the tile flags, add to the dirty tile list and done
|
||||
|
||||
:no_clear
|
||||
|
||||
|
@ -330,7 +331,7 @@ phase1 dw :phase1_0
|
|||
; the stamp every time. So this allows users to create stamps in advance and then
|
||||
; assign them to the sprites as needed.
|
||||
;
|
||||
; Note that the user had full freedom to create a stamp at any VBUFF address, however,
|
||||
; Note that the user has full freedom to create a stamp at any VBUFF address, however,
|
||||
; without leaving a buffer around each stamp, graphical corruption will occur. It is
|
||||
; recommended that the defines for VBUFF_SPRITE_START, VBUFF_TILE_ROW_BYTES and
|
||||
; VBUFF_TILE_COL_BYTES to calculate tile-aligned corner locations to lay out the
|
||||
|
@ -361,8 +362,8 @@ _CreateSpriteStamp
|
|||
; 01 - 8x16 (1x2 tiles)
|
||||
; 10 - 16x8 (2x1 tiles)
|
||||
; 11 - 16x16 (2x2 tiles)
|
||||
; Bit 13 : Show/Hid sprite
|
||||
; Bit 14 : Reserved. Must be zero.
|
||||
; Bit 13 : Show/Hide sprite during rendering
|
||||
; Bit 14 : Mark sprite as a compile sprite. SPRITE_DISP is treated as a compilation token.
|
||||
; Bit 15 : Reserved. Must be zero.
|
||||
; TBD: Bit 15 : Low Sprite priority. Draws behind high priority tiles.
|
||||
;
|
||||
|
@ -370,7 +371,7 @@ _CreateSpriteStamp
|
|||
; the vertical tiles are taken from tileId + 32. This is why tile sheets should be saved
|
||||
; with a width of 256 pixels.
|
||||
;
|
||||
; A = vbuffAddress
|
||||
; A = Sprite ID / Flags
|
||||
; Y = High Byte = x-pos, Low Byte = y-pos
|
||||
; X = Sprite Slot (0 - 15)
|
||||
_AddSprite
|
||||
|
@ -383,10 +384,11 @@ _AddSprite
|
|||
|
||||
sta _Sprites+SPRITE_ID,x ; Keep a copy of the full descriptor
|
||||
|
||||
lda #SPRITE_STATUS_ADDED
|
||||
lda #SPRITE_STATUS_ADDED ; Used to initialize the SPRITE_STATUS
|
||||
sta _Sprites+SPRITE_STATUS,x
|
||||
|
||||
stz _Sprites+VBUFF_ADDR,x ; Clear the VBUFF address, just to initialize it
|
||||
lda #$FFFF
|
||||
sta _Sprites+VBUFF_ADDR,x ; Clear the VBUFF address, just to initialize it
|
||||
|
||||
phy
|
||||
tya
|
||||
|
@ -397,8 +399,6 @@ _AddSprite
|
|||
and #$00FF
|
||||
sta _Sprites+SPRITE_X,x ; X coordinate
|
||||
|
||||
jsr _PrecalcAllSpriteInfo ; Cache sprite property values (simple stuff)
|
||||
|
||||
; Mark the dirty bit to indicate that the active sprite list needs to be rebuilt in the next
|
||||
; render call
|
||||
|
||||
|
@ -408,8 +408,292 @@ _AddSprite
|
|||
lda _SpriteBits,x ; Get the bit flag for this sprite slot
|
||||
tsb SpriteMap ; Mark it in the sprite map bit field
|
||||
|
||||
rts
|
||||
jsr _PrecalcSpriteSize ; Cache sprite property values
|
||||
jsr _PrecalcSpriteBounds
|
||||
|
||||
jsr _InsertSprite ; Insert it into the sorted list
|
||||
jmp _Validate
|
||||
|
||||
; _SortSprite
|
||||
;
|
||||
; Given a sprite's index, i, update the sprite permutation array such that p[j] = i where
|
||||
; the sprite is the j.th sprite ordered by the SPRITE_CLIP_TOP value. It is important to
|
||||
; note that the sorted sprite order does not impact rendering order (that is determined by
|
||||
; the sprite index position), but is only used to calculate region of the screen to update
|
||||
; and, in the future, may be useful for isometric perspectives where sorting order *is*
|
||||
; determined by y-position
|
||||
;
|
||||
; X = current sprite index
|
||||
;
|
||||
; The sorting strategy is to
|
||||
;
|
||||
; a) check if the current slot's y-pos is greater than the next item. If yes, then search forward
|
||||
; b) check if the current slot's y-pos is less than the prev item. If yes, then search in reverse
|
||||
; c) sprite is in the correct location
|
||||
;
|
||||
; The heuristic in play here is that, usually sprites will only move one position in the sorted order
|
||||
; between frames, if at all.
|
||||
_SortSprite
|
||||
lda _Sprites+SPRITE_CLIP_TOP,x
|
||||
|
||||
ldy _Sprites+SORTED_PREV,x
|
||||
bmi :chk_fwd
|
||||
cmp _Sprites+SPRITE_CLIP_TOP,y
|
||||
bcc :scan_bkwd ; The current node needs to move to an lower position
|
||||
|
||||
:chk_fwd
|
||||
ldy _Sprites+SORTED_NEXT,x ; If there is nothing ahead of the current node, we're done
|
||||
bmi :early_out
|
||||
cmp _Sprites+SPRITE_CLIP_TOP,y ; If the current node is <= the next node, we're done
|
||||
bcc :early_out
|
||||
bne :scan_fwd
|
||||
|
||||
:early_out
|
||||
rts
|
||||
|
||||
; Look to move the sprite into a later position
|
||||
:scan_fwd
|
||||
lda _Sprites+SORTED_NEXT,y ; Need to step forward; if we're at the end, then insert here
|
||||
bmi :insert_end
|
||||
tay
|
||||
lda _Sprites+SPRITE_CLIP_TOP,y ; Check against the next node. If it's less that current, keep going
|
||||
cmp _Sprites+SPRITE_CLIP_TOP,x
|
||||
bcc :scan_fwd
|
||||
|
||||
; Put X before Y
|
||||
;
|
||||
; Change
|
||||
; a <=> x <=> b
|
||||
; c <=> y <=> d
|
||||
;
|
||||
; Into
|
||||
; a <=> b and c <=> x <=> y <=> d
|
||||
:insert_before
|
||||
jsr _ReleaseNode
|
||||
|
||||
tya
|
||||
sta _Sprites+SORTED_NEXT,x ; Link X to Y
|
||||
|
||||
lda _Sprites+SORTED_PREV,y
|
||||
sta _Sprites+SORTED_PREV,x ; Link X to C
|
||||
|
||||
txa ; Link Y to X
|
||||
sta _Sprites+SORTED_PREV,y
|
||||
|
||||
ldy _Sprites+SORTED_PREV,x ; Link C to X
|
||||
sta _Sprites+SORTED_NEXT,y
|
||||
rts
|
||||
|
||||
; Move X to the end of the list. Y point to the last element
|
||||
;
|
||||
; ; Change
|
||||
; a <=> x <=> b
|
||||
; y -> nil
|
||||
;
|
||||
; Into
|
||||
; a <=> b and y <=> x -> nil
|
||||
:insert_end
|
||||
jsr _ReleaseNode
|
||||
|
||||
lda #$FFFF
|
||||
sta _Sprites+SORTED_NEXT,x
|
||||
tya
|
||||
sta _Sprites+SORTED_PREV,x
|
||||
txa
|
||||
sta _Sprites+SORTED_NEXT,y
|
||||
rts
|
||||
|
||||
; Look to move the sprite into an earlier position
|
||||
:scan_bkwd
|
||||
lda _Sprites+SORTED_PREV,y ; Need to step backward; if we're at the beginning, then insert here
|
||||
bmi :insert_front
|
||||
tay
|
||||
lda _Sprites+SPRITE_CLIP_TOP,x ; Check against the next node. If it's less that current, keep going
|
||||
cmp _Sprites+SPRITE_CLIP_TOP,y
|
||||
bcc :scan_bkwd
|
||||
|
||||
; Put X after Y
|
||||
;
|
||||
; Change
|
||||
; a <=> x <=> b
|
||||
; c <=> y <=> d
|
||||
;
|
||||
; Into
|
||||
; a <=> b and c <=> y <=> x <=> d
|
||||
:insert_after
|
||||
jsr _ReleaseNode
|
||||
|
||||
tya
|
||||
sta _Sprites+SORTED_PREV,x ; c <=> y <-- x --- d
|
||||
|
||||
lda _Sprites+SORTED_NEXT,y ; c <=> y <-- x --> d
|
||||
sta _Sprites+SORTED_NEXT,x
|
||||
|
||||
txa
|
||||
ldx _Sprites+SORTED_NEXT,y
|
||||
sta _Sprites+SORTED_NEXT,y ; c <=> y <=> x --> d
|
||||
|
||||
sta _Sprites+SORTED_PREV,x ; c <=> y <=> x <=> d
|
||||
rts
|
||||
|
||||
; Move X to the front of the list. Y points to the first element
|
||||
;
|
||||
; ; Change
|
||||
; a <=> x <=> b
|
||||
; head -> y
|
||||
;
|
||||
; Into
|
||||
; a <=> b and head -> x <=> y
|
||||
:insert_front
|
||||
jsr _ReleaseNode
|
||||
|
||||
stx _SortedHead
|
||||
txa
|
||||
sta _Sprites+SORTED_PREV,y
|
||||
lda #$FFFF
|
||||
sta _Sprites+SORTED_PREV,x
|
||||
tya
|
||||
sta _Sprites+SORTED_NEXT,x
|
||||
|
||||
:done
|
||||
rts
|
||||
|
||||
; Take the node pointed at X and remove it from the doubly-linked list.
|
||||
_ReleaseNode
|
||||
phy
|
||||
jsr _DeleteSprite
|
||||
ply
|
||||
rts
|
||||
|
||||
; Add a new sprite into the sorted double-linked list
|
||||
_InsertSprite
|
||||
lda _SortedHead ; If the list is empty, just insert the sprite index
|
||||
bmi :empty
|
||||
|
||||
tay ; Check the first item
|
||||
lda _Sprites+SPRITE_CLIP_TOP,x
|
||||
cmp _Sprites+SPRITE_CLIP_TOP,y
|
||||
bcc :insert_head
|
||||
|
||||
:next
|
||||
lda _Sprites+SORTED_NEXT,y
|
||||
bmi :insert_tail
|
||||
|
||||
tay
|
||||
lda _Sprites+SPRITE_CLIP_TOP,x
|
||||
cmp _Sprites+SPRITE_CLIP_TOP,y
|
||||
bcs :next
|
||||
|
||||
lda _Sprites+SORTED_PREV,y
|
||||
sta _Sprites+SORTED_PREV,x ; [p] <-- [c] [n]
|
||||
|
||||
tya
|
||||
sta _Sprites+SORTED_NEXT,x ; [p] <-- [c] --> [n]
|
||||
|
||||
txa
|
||||
ldx _Sprites+SORTED_PREV,y ; get ref to the [p]revious node
|
||||
sta _Sprites+SORTED_PREV,y ; [p] <-- [c] <=> [n]
|
||||
|
||||
sta _Sprites+SORTED_NEXT,x ; [p] <=> [c] <=> [n]
|
||||
|
||||
rts
|
||||
|
||||
:insert_head
|
||||
stx _SortedHead
|
||||
lda #$FFFF
|
||||
sta _Sprites+SORTED_PREV,x
|
||||
tya
|
||||
sta _Sprites+SORTED_NEXT,x
|
||||
txa
|
||||
sta _Sprites+SORTED_PREV,y
|
||||
rts
|
||||
|
||||
:insert_tail
|
||||
txa
|
||||
sta _Sprites+SORTED_NEXT,y
|
||||
tya
|
||||
sta _Sprites+SORTED_PREV,x
|
||||
lda #$FFFF
|
||||
sta _Sprites+SORTED_NEXT,x
|
||||
rts
|
||||
|
||||
:empty
|
||||
sta _Sprites+SORTED_NEXT,x
|
||||
sta _Sprites+SORTED_PREV,x
|
||||
stx _SortedHead
|
||||
rts
|
||||
|
||||
; Remove a sprite from the double-linked list
|
||||
_DeleteSprite
|
||||
ldy _Sprites+SORTED_NEXT,x
|
||||
bmi :remove_tail
|
||||
|
||||
cpx _SortedHead
|
||||
beq :remove_head
|
||||
|
||||
lda _Sprites+SORTED_PREV,x
|
||||
sta _Sprites+SORTED_PREV,y
|
||||
|
||||
tay
|
||||
lda _Sprites+SORTED_NEXT,x
|
||||
sta _Sprites+SORTED_NEXT,y
|
||||
rts
|
||||
|
||||
:remove_head
|
||||
sty _SortedHead
|
||||
lda #$FFFF
|
||||
sta _Sprites+SORTED_PREV,y
|
||||
rts
|
||||
|
||||
:remove_tail
|
||||
ldy _Sprites+SORTED_PREV,x
|
||||
bmi :make_empty
|
||||
|
||||
lda #$FFFF
|
||||
sta _Sprites+SORTED_NEXT,y
|
||||
rts
|
||||
|
||||
:make_empty
|
||||
lda #$FFFF
|
||||
sta _SortedHead
|
||||
rts
|
||||
|
||||
; Validate the integrity of the linked list
|
||||
_Validate
|
||||
:prev equ tmp0
|
||||
:curr equ tmp1
|
||||
|
||||
ldy #$FFFF
|
||||
ldx _SortedHead
|
||||
bmi :done
|
||||
:loop
|
||||
sty :prev
|
||||
stx :curr
|
||||
|
||||
lda _Sprites+SORTED_PREV,x
|
||||
cmp :prev
|
||||
beq *+4
|
||||
brk $08
|
||||
|
||||
cpy #$FFFF
|
||||
beq :skip
|
||||
lda _Sprites+SORTED_NEXT,y
|
||||
cmp :curr
|
||||
beq *+4
|
||||
brk $06
|
||||
|
||||
lda _Sprites+SPRITE_CLIP_TOP,x
|
||||
cmp _Sprites+SPRITE_CLIP_TOP,y
|
||||
bcs *+4
|
||||
brk $0A
|
||||
:skip
|
||||
txy
|
||||
lda _Sprites+SORTED_NEXT,x
|
||||
tax
|
||||
bpl :loop
|
||||
|
||||
:done
|
||||
rts
|
||||
; Macro to make the unrolled loop more concise
|
||||
;
|
||||
; 1. Load the tile store address from a fixed offset
|
||||
|
@ -643,25 +927,131 @@ _CacheSpriteBanks
|
|||
|
||||
rts
|
||||
|
||||
; Precalculate some cached values for a sprite. These are *only* to make other part of code,
|
||||
; Precalculate some cached values for a sprite. These are *only* to make other parts of code,
|
||||
; specifically the draw/erase routines more efficient.
|
||||
;
|
||||
; There are variations of this routine based on whether we are adding a new sprite, updating
|
||||
; it's tile information, or changing its position.
|
||||
;
|
||||
; X = sprite index
|
||||
_PrecalcAllSpriteInfo
|
||||
lda _Sprites+SPRITE_ID,x
|
||||
; and #$3E00
|
||||
_PrecalcSpriteVBuff
|
||||
lda _Sprites+SPRITE_ID,x ; Compiled sprites use the SPRITE_DISP as a fixed address to compiled code
|
||||
bit #SPRITE_COMPILED
|
||||
bne :compiled
|
||||
|
||||
xba
|
||||
and #$0006
|
||||
|
||||
tay
|
||||
lda _Sprites+VBUFF_ADDR,x
|
||||
clc
|
||||
adc _stamp_step,y
|
||||
sta _Sprites+SPRITE_DISP,x
|
||||
sta _Sprites+SPRITE_DISP,x ; Interpreted as an address in the VBUFF bank
|
||||
rts
|
||||
|
||||
:compiled
|
||||
xba
|
||||
and #$0006 ; Pick the address from the table of 4 values. Can use this value directly
|
||||
clc ; as an index
|
||||
adc _Sprites+VBUFF_ADDR,x
|
||||
tay
|
||||
lda [CompileBank0],y
|
||||
sta _Sprites+SPRITE_DISP,x ; Interpreted as an address in the CompileBank
|
||||
rts
|
||||
|
||||
; Compile the four stamps and keep a reference to the addresses. We take the current CompileBankTop address and allocate 8 bytes
|
||||
; of memory. Then compile each stamp and save the compilation address in the header area. Finally, the DISP_ADDR is set
|
||||
; to that value and the SPRITE_COMPILED bit is set in the SPRITE_ID word.
|
||||
;
|
||||
; A = sprite Id
|
||||
; X = vbuff base address
|
||||
_CompileStampSet
|
||||
:height equ tmp8
|
||||
:width equ tmp9
|
||||
:base equ tmp10
|
||||
:output equ tmp11
|
||||
:addrs equ tmp12 ; 4 words (tmp12, tmp13, tmp14 and tmp15)
|
||||
|
||||
; Save the base address
|
||||
stx :base
|
||||
|
||||
; Initialize the height and width based on the sprite flags
|
||||
|
||||
ldy #8
|
||||
sty :height
|
||||
ldx #4
|
||||
stx :width
|
||||
|
||||
bit #$1000 ; wide flag
|
||||
beq :skinny
|
||||
ldx #8
|
||||
stx :width
|
||||
:skinny
|
||||
|
||||
bit #$0800 ; tall flag
|
||||
beq :short
|
||||
ldy #16
|
||||
sty :height
|
||||
:short
|
||||
|
||||
lda CompileBankTop
|
||||
sta :output ; Save the current address as the return value
|
||||
|
||||
clc
|
||||
adc #8
|
||||
sta CompileBankTop ; Allocate space for the 4 addresses return by _CompileStamp
|
||||
|
||||
; ldy :height ; X and Y are already set for the first call
|
||||
; ldx :width
|
||||
lda :base
|
||||
jsr _CompileStamp ; Compile into the bank
|
||||
sta :addrs ; Save the address temporarily
|
||||
|
||||
ldy :height
|
||||
ldx :width
|
||||
clc
|
||||
lda :base
|
||||
adc _stamp_step+2
|
||||
jsr _CompileStamp
|
||||
sta :addrs+2
|
||||
|
||||
ldy :height
|
||||
ldx :width
|
||||
clc
|
||||
lda :base
|
||||
adc _stamp_step+4
|
||||
jsr _CompileStamp
|
||||
sta :addrs+4
|
||||
|
||||
ldy :height
|
||||
ldx :width
|
||||
clc
|
||||
lda :base
|
||||
adc _stamp_step+6
|
||||
jsr _CompileStamp
|
||||
sta :addrs+6
|
||||
|
||||
; Now the sprite stamps are all compiled. Set the bank to the compilation bank and fill in the header
|
||||
|
||||
phb
|
||||
|
||||
ldy :output
|
||||
pei CompileBank
|
||||
plb
|
||||
|
||||
lda :addrs
|
||||
sta: 0,y
|
||||
lda :addrs+2
|
||||
sta: 2,y
|
||||
lda :addrs+4
|
||||
sta: 4,y
|
||||
lda :addrs+6
|
||||
sta: 6,y
|
||||
|
||||
plb
|
||||
plb
|
||||
|
||||
tya ; Put the output value into the accumulator
|
||||
clc ; No error
|
||||
rts
|
||||
|
||||
_PrecalcSpriteSize
|
||||
; Set the sprite's width and height
|
||||
lda #4
|
||||
sta _Sprites+SPRITE_WIDTH,x
|
||||
|
@ -681,10 +1071,11 @@ _PrecalcAllSpriteInfo
|
|||
lda #16
|
||||
sta _Sprites+SPRITE_HEIGHT,x
|
||||
:height_8
|
||||
rts
|
||||
|
||||
; Clip the sprite's bounding box to the play field size and also set a flag if the sprite
|
||||
; is fully off-screen or not
|
||||
|
||||
_PrecalcSpriteBounds
|
||||
lda _Sprites+SPRITE_X,x
|
||||
bpl :pos_x
|
||||
lda #0
|
||||
|
@ -760,14 +1151,14 @@ _RemoveSprite
|
|||
ora #SPRITE_STATUS_REMOVED
|
||||
sta _Sprites+SPRITE_STATUS,x
|
||||
|
||||
rts
|
||||
rts ; The _DeleteSprite call is made in _DoPhase1 during the next render
|
||||
|
||||
; Update the sprite's flags. We do not allow the size of a sprite to be changed. That requires
|
||||
; the sprite to be removed and re-added.
|
||||
;
|
||||
; A = Sprite slot
|
||||
; X = New Sprite Flags
|
||||
; Y = New Sprite Stamp Address
|
||||
; Y = New Sprite Stamp Address | New Compiled Sprite Token
|
||||
_UpdateSprite
|
||||
cmp #MAX_SPRITES
|
||||
bcc :ok
|
||||
|
@ -813,7 +1204,7 @@ _UpdateSprite
|
|||
ora #SPRITE_STATUS_UPDATED
|
||||
sta _Sprites+SPRITE_STATUS,x
|
||||
|
||||
jmp _PrecalcAllSpriteInfo ; Cache stuff and return
|
||||
jmp _PrecalcSpriteVBuff ; Cache stuff and return
|
||||
|
||||
; Move a sprite to a new location. If the tile ID of the sprite needs to be changed, then
|
||||
; a full remove/add cycle needs to happen
|
||||
|
@ -849,4 +1240,6 @@ _MoveSprite
|
|||
ora #SPRITE_STATUS_MOVED
|
||||
sta _Sprites+SPRITE_STATUS,x
|
||||
|
||||
jmp _PrecalcAllSpriteInfo ; Can be specialized to only update (x,y) values
|
||||
jsr _PrecalcSpriteBounds ; Can be specialized to only update (x,y) values
|
||||
jsr _SortSprite ; Update the sprite's sorted position
|
||||
jmp _Validate
|
||||
|
|
|
@ -1,3 +1,278 @@
|
|||
; Compile a stamp into a compilation cache
|
||||
;
|
||||
; A = vbuff address
|
||||
; X = width (in bytes)
|
||||
; Y = height (in scanlines)
|
||||
|
||||
_CompileStamp
|
||||
:lines equ tmp0
|
||||
:sprwidth equ tmp1
|
||||
:cntwidth equ tmp2
|
||||
:baseAddr equ tmp3
|
||||
:destAddr equ tmp4
|
||||
:vbuffAddr equ tmp5
|
||||
:rtnval equ tmp6
|
||||
|
||||
LDA_IMM_OPCODE equ $A9
|
||||
LDA_ABS_X_OPCODE equ $BD
|
||||
AND_IMM_OPCODE equ $29
|
||||
ORA_IMM_OPCODE equ $09
|
||||
STA_ABS_X_OPCODE equ $9D
|
||||
STZ_ABS_X_OPCODE equ $9E
|
||||
RTL_OPCODE equ $6B
|
||||
|
||||
sta :vbuffAddr
|
||||
sty :lines
|
||||
txa
|
||||
lsr
|
||||
sta :sprwidth
|
||||
|
||||
; Get ready to build the sprite
|
||||
|
||||
ldy CompileBankTop ; First free byte in the compilation bank
|
||||
sty :rtnval ; Save it as the return value
|
||||
|
||||
phb
|
||||
pei CompileBank
|
||||
plb ; Set the bank to the compilation cache
|
||||
|
||||
stz :baseAddr
|
||||
stz :destAddr
|
||||
|
||||
:oloop
|
||||
lda :sprwidth
|
||||
sta :cntwidth
|
||||
ldx :vbuffAddr
|
||||
|
||||
:iloop
|
||||
ldal spritemask,x
|
||||
beq :no_mask ; If Mask == $0000, then it's a solid word
|
||||
cmp #$FFFF
|
||||
beq :next ; If Mask == $FFFF, then it's transparent
|
||||
|
||||
; Mask with the screen data
|
||||
lda #LDA_ABS_X_OPCODE
|
||||
sta: 0,y
|
||||
lda :destAddr
|
||||
sta: 1,y
|
||||
lda #AND_IMM_OPCODE
|
||||
sta: 3,y
|
||||
ldal spritemask,x
|
||||
sta: 4,y
|
||||
lda #ORA_IMM_OPCODE
|
||||
sta: 6,y
|
||||
ldal spritedata,x
|
||||
sta: 7,y
|
||||
lda #STA_ABS_X_OPCODE
|
||||
sta: 9,y
|
||||
lda :destAddr
|
||||
sta: 10,y
|
||||
|
||||
tya
|
||||
clc
|
||||
adc #12
|
||||
tay
|
||||
bra :next
|
||||
|
||||
; Just store the data
|
||||
:no_mask lda #LDA_IMM_OPCODE
|
||||
sta: 0,y
|
||||
ldal spritedata,x
|
||||
beq :zero
|
||||
sta: 1,y
|
||||
|
||||
lda #STA_ABS_X_OPCODE
|
||||
sta: 3,y
|
||||
lda :destAddr
|
||||
sta: 4,y
|
||||
|
||||
tya
|
||||
clc
|
||||
adc #6
|
||||
tay
|
||||
bra :next
|
||||
|
||||
:zero lda #STZ_ABS_X_OPCODE
|
||||
sta: 0,y
|
||||
lda :destAddr
|
||||
sta: 1,y
|
||||
|
||||
iny
|
||||
iny
|
||||
iny
|
||||
|
||||
:next
|
||||
inx
|
||||
inx
|
||||
|
||||
inc :destAddr ; Move to the next word
|
||||
inc :destAddr
|
||||
|
||||
dec :cntwidth
|
||||
bne :iloop
|
||||
|
||||
lda :vbuffAddr
|
||||
clc
|
||||
adc #SPRITE_PLANE_SPAN
|
||||
sta :vbuffAddr
|
||||
|
||||
lda :baseAddr ; Move to the next line
|
||||
clc
|
||||
adc #160
|
||||
sta :baseAddr
|
||||
sta :destAddr
|
||||
|
||||
dec :lines
|
||||
beq :out
|
||||
brl :oloop
|
||||
|
||||
:out
|
||||
lda #RTL_OPCODE ; Finish up the subroutine
|
||||
sta: 0,y
|
||||
iny
|
||||
sty CompileBankTop
|
||||
|
||||
plb
|
||||
plb
|
||||
lda :rtnval ; Address in the compile memory
|
||||
rts
|
||||
|
||||
; Draw a sprite directly to the graphics screen. If sprite is clipped at all, do not draw.
|
||||
;
|
||||
; X = sprite record index
|
||||
_DSTSOut
|
||||
rts
|
||||
|
||||
_DrawStampToScreen
|
||||
lda _Sprites+IS_OFF_SCREEN,x ; If the sprite is off-screen, don't draw it
|
||||
bne _DSTSOut
|
||||
|
||||
lda _Sprites+SPRITE_CLIP_WIDTH,x ; If the sprite is clipped to the playfield, don't draw it
|
||||
cmp _Sprites+SPRITE_WIDTH,x
|
||||
bne _DSTSOut
|
||||
lda _Sprites+SPRITE_CLIP_HEIGHT,x
|
||||
cmp _Sprites+SPRITE_HEIGHT,x
|
||||
bne _DSTSOut
|
||||
|
||||
clc
|
||||
lda _Sprites+SPRITE_Y,x
|
||||
adc ScreenY0
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
sta tmp0
|
||||
asl
|
||||
asl
|
||||
clc
|
||||
adc tmp0
|
||||
clc
|
||||
adc #$2000
|
||||
clc
|
||||
adc ScreenX0
|
||||
adc _Sprites+SPRITE_X,x ; Move to the horizontal address
|
||||
tay ; This is the on-screen address
|
||||
|
||||
lda _Sprites+SPRITE_ID,x ; If this is a compiled sprite, call the routine in the compilation bank
|
||||
bit #SPRITE_COMPILED
|
||||
beq *+5
|
||||
brl :compiled
|
||||
|
||||
lda _Sprites+SPRITE_HEIGHT,x
|
||||
sta tmp0
|
||||
|
||||
; Sprite is either 8 or 16 pixels wide, so select the entry point
|
||||
lda _Sprites+SPRITE_WIDTH,x
|
||||
cmp #4
|
||||
beq :skinny
|
||||
|
||||
lda _Sprites+SPRITE_DISP,x ; This is the VBUFF address with the correct sprite frame
|
||||
tax
|
||||
phb
|
||||
pea $0101
|
||||
plb
|
||||
plb
|
||||
bra :entry16
|
||||
:loop16
|
||||
clc
|
||||
txa
|
||||
adc #SPRITE_PLANE_SPAN
|
||||
tax
|
||||
tya
|
||||
adc #SHR_LINE_WIDTH
|
||||
tay
|
||||
:entry16
|
||||
lda: 6,y
|
||||
andl spritemask+6,x
|
||||
oral spritedata+6,x
|
||||
sta: 6,y
|
||||
lda: 4,y
|
||||
andl spritemask+4,x
|
||||
oral spritedata+4,x
|
||||
sta: 4,y
|
||||
lda: 2,y
|
||||
andl spritemask+2,x
|
||||
oral spritedata+2,x
|
||||
sta: 2,y
|
||||
lda: 0,y
|
||||
andl spritemask+0,x
|
||||
oral spritedata+0,x
|
||||
sta: 0,y
|
||||
|
||||
dec tmp0
|
||||
bne :loop16
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
:skinny
|
||||
lda _Sprites+SPRITE_DISP,x ; This is the VBUFF address with the correct sprite frame
|
||||
tax
|
||||
phb
|
||||
pea $0101
|
||||
plb
|
||||
plb
|
||||
bra :entry8
|
||||
:loop8
|
||||
clc
|
||||
txa
|
||||
adc #SPRITE_PLANE_SPAN
|
||||
tax
|
||||
tya
|
||||
adc #SHR_LINE_WIDTH
|
||||
tay
|
||||
:entry8
|
||||
lda: 2,y
|
||||
andl spritemask+2,x
|
||||
oral spritedata+2,x
|
||||
sta: 2,y
|
||||
lda: 0,y
|
||||
andl spritemask+0,x
|
||||
oral spritedata+0,x
|
||||
sta: 0,y
|
||||
|
||||
dec tmp0
|
||||
bne :loop8
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
:compiled
|
||||
lda CompileBank-1 ; Load the bank into the high byte
|
||||
stal :patch+2 ; Put it into the 3rd address bytes (2nd byte is garbage)
|
||||
lda _Sprites+SPRITE_DISP,x ; Address in the compile bank
|
||||
stal :patch+1 ; Set 1st and 2nd address bytes
|
||||
|
||||
tyx ; Put on-screen address in X-register
|
||||
phb ; Compiled sprites assume bank register is $01
|
||||
pea $0101
|
||||
plb
|
||||
plb
|
||||
:patch jsl $000000 ; Dispatch
|
||||
plb
|
||||
rts
|
||||
|
||||
; Alternate entry point that takes arguments in registers instead of using a _Sprite
|
||||
; record
|
||||
;
|
||||
|
|
226
src/SpriteV1.s
226
src/SpriteV1.s
|
@ -1,226 +0,0 @@
|
|||
; Old code the was in Version 1, but is not needed. May be adapted for Verions 2.
|
||||
|
||||
; Y = _Sprites array offset
|
||||
_EraseSpriteY
|
||||
lda _Sprites+OLD_VBUFF_ADDR,y
|
||||
beq :noerase
|
||||
ldx _Sprites+SPRITE_DISP,y ; get the dispatch index for this sprite (32 values)
|
||||
jmp (:do_erase,x)
|
||||
:noerase rts
|
||||
:do_erase dw _EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8
|
||||
dw _EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16
|
||||
dw _EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8
|
||||
dw _EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16
|
||||
dw _EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8
|
||||
dw _EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16
|
||||
dw _EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8
|
||||
dw _EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16
|
||||
|
||||
; A = bank address
|
||||
_EraseTileSprite8x8
|
||||
tax
|
||||
phb ; Save the bank to switch to the sprite plane
|
||||
|
||||
pei SpriteBanks
|
||||
plb ; pop the data bank (low byte)
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
stz: {]line*SPRITE_PLANE_SPAN}+0,x
|
||||
stz: {]line*SPRITE_PLANE_SPAN}+2,x
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb ; pop the mask bank (high byte)
|
||||
lda #$FFFF
|
||||
]line equ 0
|
||||
lup 8
|
||||
sta: {]line*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {]line*SPRITE_PLANE_SPAN}+2,x
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
_EraseTileSprite8x16
|
||||
tax
|
||||
phb ; Save the bank to switch to the sprite plane
|
||||
|
||||
pei SpriteBanks
|
||||
plb ; pop the data bank (low byte)
|
||||
|
||||
]line equ 0
|
||||
lup 16
|
||||
stz: {]line*SPRITE_PLANE_SPAN}+0,x
|
||||
stz: {]line*SPRITE_PLANE_SPAN}+2,x
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb ; pop the mask bank (high byte)
|
||||
lda #$FFFF
|
||||
]line equ 0
|
||||
lup 16
|
||||
sta: {]line*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {]line*SPRITE_PLANE_SPAN}+2,x
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
_EraseTileSprite16x8
|
||||
tax
|
||||
phb ; Save the bank to switch to the sprite plane
|
||||
|
||||
pei SpriteBanks
|
||||
plb ; pop the data bank (low byte)
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
stz: {]line*SPRITE_PLANE_SPAN}+0,x
|
||||
stz: {]line*SPRITE_PLANE_SPAN}+2,x
|
||||
stz: {]line*SPRITE_PLANE_SPAN}+4,x
|
||||
stz: {]line*SPRITE_PLANE_SPAN}+6,x
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb ; pop the mask bank (high byte)
|
||||
lda #$FFFF
|
||||
]line equ 0
|
||||
lup 8
|
||||
sta: {]line*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: {]line*SPRITE_PLANE_SPAN}+4,x
|
||||
sta: {]line*SPRITE_PLANE_SPAN}+6,x
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
_EraseTileSprite16x16
|
||||
tax
|
||||
phb ; Save the bank to switch to the sprite plane
|
||||
|
||||
pei SpriteBanks
|
||||
plb ; pop the data bank (low byte)
|
||||
|
||||
]line equ 0
|
||||
lup 16
|
||||
stz: {]line*SPRITE_PLANE_SPAN}+0,x
|
||||
stz: {]line*SPRITE_PLANE_SPAN}+2,x
|
||||
stz: {]line*SPRITE_PLANE_SPAN}+4,x
|
||||
stz: {]line*SPRITE_PLANE_SPAN}+6,x
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb ; pop the mask bank (high byte)
|
||||
|
||||
lda #$FFFF
|
||||
]line equ 0
|
||||
lup 16
|
||||
sta: {]line*SPRITE_PLANE_SPAN}+0,x
|
||||
sta: {]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: {]line*SPRITE_PLANE_SPAN}+4,x
|
||||
sta: {]line*SPRITE_PLANE_SPAN}+6,x
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
|
||||
; First, if there is only one sprite, then we can skip any overhead and do a single lda/and/ora/sta to put the
|
||||
; sprite data on the screen.
|
||||
;
|
||||
; Second, if there are 4 or less, then we "stack" the sprite data using an unrolled loop that allows each
|
||||
; sprite to just be a single and/ora pair and the final result is not written to any intermediate memory buffer.
|
||||
;
|
||||
; Third, if there are 5 or more sprites, then we assume that the sprites are "dense" and that there will be a
|
||||
; non-trivial amount of overdraw. In this case we do a series of optimized copies of the sprite data *and*
|
||||
; masks into a direct page buffer in *reverse order*. Once a mask value becomes zero, then nothing else can
|
||||
; show through and that value can be skipped. Once all of the mask values are zero, then the render is terminated
|
||||
; and the data buffer copied to the final destination.
|
||||
;
|
||||
; Note that these rendering algorithms impose a priority ordering on the sprites where lower sprite IDs are drawn
|
||||
; underneath higher sprite IDs.
|
||||
RenderActiveSpriteTiles
|
||||
cmp #0 ; Is there only one active sprite? If so optimise
|
||||
bne :many
|
||||
|
||||
ldx vbuff ; load the address to the (adjusted) sprite tile
|
||||
lda TileStore+TS_SCREEN_ADDR,y
|
||||
tay
|
||||
|
||||
lda tiledata+0,y
|
||||
andl spritemask,x
|
||||
oral spritedata,x
|
||||
sta 00,s
|
||||
|
||||
lda tiledata+2,y
|
||||
andl spritemask+2,x
|
||||
oral spritedata+2,x
|
||||
sta 02,s
|
||||
|
||||
...
|
||||
tsc
|
||||
adc #320
|
||||
tcs
|
||||
...
|
||||
|
||||
lda tiledata+{line*4},y
|
||||
andl spritemask+{line*SPAN},x
|
||||
oral spritedata+{line*SPAN},x
|
||||
sta 160,s
|
||||
|
||||
lda tiledata+{line*4}+2,y
|
||||
andl spritemask+{line*SPAN}+2,x
|
||||
oral spritedata+{line*SPAN}+2,x
|
||||
sta 162,s
|
||||
|
||||
rts
|
||||
|
||||
|
||||
:many
|
||||
lda TileStore+TS_SCREEN_ADDR,y
|
||||
tcs
|
||||
lda TileStore+TS_TILE_ADDR,y
|
||||
tay
|
||||
|
||||
ldx count
|
||||
jmp (:arr,x)
|
||||
lda tiledata+0,y
|
||||
ldx vbuff
|
||||
andl spritemask,x
|
||||
oral spritedata,x
|
||||
ldx vbuff+2
|
||||
andl spritemask,x
|
||||
oral spritedata,x
|
||||
ldx vbuff+4
|
||||
andl spritemask,x
|
||||
oral spritedata,x
|
||||
...
|
||||
sta 00,s
|
||||
|
||||
ldx count
|
||||
jmp (:arr,x)
|
||||
lda tiledata+0,y
|
||||
ldx vbuff
|
||||
andl spritemask,x
|
||||
oral spritedata,x
|
||||
ldx vbuff+2
|
||||
andl spritemask,x
|
||||
oral spritedata,x
|
||||
ldx vbuff+4
|
||||
andl spritemask,x
|
||||
oral spritedata,x
|
||||
...
|
||||
sta 02,s
|
||||
|
||||
sta 160,s
|
||||
|
||||
sta 162,s
|
||||
|
||||
tsc
|
||||
adc #320
|
45
src/Tiles.s
45
src/Tiles.s
|
@ -1,20 +1,29 @@
|
|||
; Basic tile functions
|
||||
|
||||
; Copy tileset data from a pointer in memory to the tiledata back
|
||||
; X = high word
|
||||
; A = low word
|
||||
;
|
||||
; tmp0 = Pointer to tile data
|
||||
; X = first tile
|
||||
; Y = last tile
|
||||
;
|
||||
; To copy in three tiles starting at tile 5, for example, X = 5 and Y = 9
|
||||
_LoadTileSet
|
||||
sta tmp0
|
||||
stx tmp1
|
||||
txa
|
||||
_Mul128 ; Jump to the target location
|
||||
tax
|
||||
tya
|
||||
_Mul128
|
||||
sta tmp2 ; This is the terminating byte
|
||||
|
||||
ldy #0
|
||||
tyx
|
||||
:loop lda [tmp0],y
|
||||
stal tiledata,x
|
||||
dex
|
||||
dex
|
||||
dey
|
||||
dey
|
||||
bne :loop
|
||||
inx
|
||||
inx
|
||||
iny
|
||||
iny
|
||||
cpx tmp2
|
||||
bne :loop ; Use BNE so when Y=512 => $0000, we wait for wrap-around
|
||||
rts
|
||||
|
||||
|
||||
|
@ -259,7 +268,7 @@ _SetNormalTileProcs
|
|||
brl :pickDynProc
|
||||
|
||||
:pickTwoLyrProc ldy #TwoLyrProcs
|
||||
pla ; pull of the proc index
|
||||
pla ; pull off the proc index
|
||||
jmp _SetTileProcs
|
||||
|
||||
; Specialized check for when the engine is in "Fast" mode. If is a simple decision tree based on whether
|
||||
|
@ -436,16 +445,16 @@ _SetTileProcs
|
|||
; TileProcTables
|
||||
;
|
||||
; Tables of tuples used to populate the K_TS_* dispatch arrays for different combinations. This is
|
||||
; easier to maintain than a bunch of conditional code. Each etry hold three addresses.
|
||||
; easier to maintain than a bunch of conditional code. Each entry holds three addresses.
|
||||
;
|
||||
; First address: Draw a tile directly into the code buffer (no sprites)
|
||||
; Second address: Draw a tile merged with sprite data from the direct page
|
||||
; Third address: Specialize routine to draw a tile merged with one sprite
|
||||
;
|
||||
; There are unique tuples of routines for all of the different combinations of tile properties
|
||||
; and engine modes. This is an extesive number of combinations, but it simplified the development
|
||||
; and maintainence of the rendering subroutines. Also, the difference subroutines can be written
|
||||
; in any way and can make use of their on subroutines to reduce code size.
|
||||
; and engine modes. This is an extensive number of combinations, but it simplifies the development
|
||||
; and maintainence of the rendering subroutines. Also, the different subroutines can be written
|
||||
; in any way and can make use of their own subroutines to reduce code size.
|
||||
;
|
||||
; Properties:
|
||||
;
|
||||
|
@ -497,6 +506,12 @@ DynUnder dw CopyDynamicTile,DynamicUnder,OneSpriteDynamicUnder
|
|||
; the TILE_SOLID_BIT hint bit can be set to indicate that a tile
|
||||
; has no transparency. This allows one of the faster routines
|
||||
; to be selected from the other Proc tables
|
||||
;
|
||||
; FUTURE: An optimization that can be done is to have the snippets
|
||||
; code layout fixed based on the EngineFlags and then the Two Layer
|
||||
; routines should only need to update the DATA and MASK operands in
|
||||
; the snippet at a fixed location rather than rebuild the ~20 bytes
|
||||
; of data.
|
||||
TwoLyrProcs
|
||||
TwoLyrOverZA dw Tile0TwoLyr,SpriteOver0TwoLyr,OneSpriteOver0TwoLyr
|
||||
TwoLyrOverZV dw Tile0TwoLyr,SpriteOver0TwoLyr,OneSpriteOver0TwoLyr
|
||||
|
|
202
src/Tool.s
202
src/Tool.s
|
@ -96,6 +96,11 @@ _CallTable
|
|||
|
||||
adrl _TSClearBG1Buffer-1
|
||||
adrl _TSSetBG1Scale-1
|
||||
adrl _TSGetAddress-1
|
||||
|
||||
adrl _TSCompileSpriteStamp-1
|
||||
adrl _TSSetAddress-1
|
||||
|
||||
_CTEnd
|
||||
_GTEAddSprite MAC
|
||||
UserTool $1000+GTEToolNum
|
||||
|
@ -162,7 +167,9 @@ zpToUse = userId+4
|
|||
|
||||
; SetWAP(userOrSystem, tsNum, waptPtr)
|
||||
|
||||
pea #$8000 ; $8000 = user tool set
|
||||
lda EngineMode ; $0000 = system tool, $8000 = user tool set
|
||||
and #$8000
|
||||
pha
|
||||
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
|
||||
|
@ -187,7 +194,9 @@ _TSShutDown
|
|||
jsr _CoreShutDown ; Shut down the library
|
||||
plb
|
||||
|
||||
pea $8000
|
||||
lda EngineMode ; $0000 = system tool, $8000 = user tool set
|
||||
and #$8000
|
||||
pha
|
||||
pei ToolNum
|
||||
pea $0000 ; Set WAP to null
|
||||
pea $0000
|
||||
|
@ -233,14 +242,14 @@ _TSReserved
|
|||
|
||||
; SetScreenMode(width, height)
|
||||
_TSSetScreenMode
|
||||
height equ FirstParam
|
||||
width equ FirstParam+2
|
||||
:height equ FirstParam
|
||||
:width equ FirstParam+2
|
||||
|
||||
_TSEntry
|
||||
|
||||
lda height,s
|
||||
lda :height,s
|
||||
tay
|
||||
lda width,s
|
||||
lda :width,s
|
||||
tax
|
||||
jsr _SetScreenMode
|
||||
|
||||
|
@ -294,7 +303,21 @@ _TSRender
|
|||
|
||||
_TSEntry
|
||||
lda :flags,s
|
||||
bit #RENDER_WITH_SHADOWING
|
||||
beq :no_shadowing
|
||||
jsr _RenderWithShadowing
|
||||
bra :done
|
||||
|
||||
:no_shadowing
|
||||
bit #RENDER_PER_SCANLINE
|
||||
beq :no_scanline
|
||||
jsr _RenderScanlines
|
||||
bra :done
|
||||
|
||||
:no_scanline
|
||||
jsr _Render
|
||||
|
||||
:done
|
||||
_TSExit #0;#2
|
||||
|
||||
|
||||
|
@ -307,18 +330,27 @@ _TSRenderDirty
|
|||
jsr _RenderDirty
|
||||
_TSExit #0;#2
|
||||
|
||||
; LoadTileSet(Pointer)
|
||||
; LoadTileSet(Start, Finish, Pointer)
|
||||
_TSLoadTileSet
|
||||
TSPtr equ FirstParam
|
||||
:TSPtr equ FirstParam
|
||||
:finish equ FirstParam+4
|
||||
:start equ FirstParam+6
|
||||
|
||||
_TSEntry
|
||||
|
||||
lda TSPtr+2,s
|
||||
lda :TSPtr+2,s ; stuff the pointer in the direct page
|
||||
sta tmp1
|
||||
lda :TSPtr,s
|
||||
sta tmp0
|
||||
|
||||
lda :start,s ; put the range in the registers
|
||||
tax
|
||||
lda TSPtr,s
|
||||
lda :finish,s
|
||||
tay
|
||||
|
||||
jsr _LoadTileSet
|
||||
|
||||
_TSExit #0;#4
|
||||
_TSExit #0;#8
|
||||
|
||||
; CreateSpriteStamp(spriteDescriptor: Word, vbuffAddr: Word)
|
||||
_TSCreateSpriteStamp
|
||||
|
@ -334,7 +366,7 @@ _TSCreateSpriteStamp
|
|||
|
||||
_TSExit #0;#4
|
||||
|
||||
; AddSprite(spriteSlot, spriteFlags, vbuff, spriteX, spriteY)
|
||||
; AddSprite(spriteSlot, spriteFlags, vbuff | cbuff, spriteX, spriteY)
|
||||
_TSAddSprite
|
||||
:spriteY equ FirstParam+0
|
||||
:spriteX equ FirstParam+2
|
||||
|
@ -344,13 +376,13 @@ _TSAddSprite
|
|||
|
||||
_TSEntry
|
||||
|
||||
lda :spriteY,s
|
||||
and #$00FF
|
||||
xba
|
||||
sta :spriteY,s
|
||||
lda :spriteX,s
|
||||
and #$00FF
|
||||
ora :spriteY,s
|
||||
xba
|
||||
sta :spriteX,s
|
||||
lda :spriteY,s
|
||||
and #$00FF
|
||||
ora :spriteX,s
|
||||
tay
|
||||
|
||||
lda :spriteSlot,s
|
||||
|
@ -474,6 +506,7 @@ _TSCopyPicToBG1
|
|||
:src_width equ tmp6
|
||||
:src_height equ tmp7
|
||||
:src_stride equ tmp8
|
||||
:src_flags equ tmp9
|
||||
|
||||
lda :width,s
|
||||
sta :src_width
|
||||
|
@ -484,9 +517,10 @@ _TSCopyPicToBG1
|
|||
|
||||
ldy BG1DataBank ; Pick the target data bank
|
||||
lda :flags,s
|
||||
bit #$0001
|
||||
beq *+4
|
||||
ldy BG1AltBank
|
||||
sta :src_flags
|
||||
; bit #$0001
|
||||
; beq *+4
|
||||
; ldy BG1AltBank
|
||||
|
||||
lda :ptr+2,s
|
||||
tax
|
||||
|
@ -679,6 +713,11 @@ _TSStartScript
|
|||
|
||||
_TSExit #0;#6
|
||||
; SetOverlay(top, bottom, proc)
|
||||
;
|
||||
; Overlays are handled as quasi-sprites. They need to be included in the y-sorted list of "stuff", but they are not drawn like
|
||||
; sprites. As such, they set a special flag in the SPRITE_ID field which allows them to be ignored for other purposes. Also,
|
||||
; they are not added into the "normal" sprite range on 0 - 15, but are stored in locations 16 and up to further seggregate them from
|
||||
; the rest of the system. A lot of the SPRITE_* locations are repurposed for Overlay-specific information.
|
||||
_TSSetOverlay
|
||||
:proc equ FirstParam+0
|
||||
:bottom equ FirstParam+4
|
||||
|
@ -686,16 +725,48 @@ _TSSetOverlay
|
|||
|
||||
_TSEntry
|
||||
|
||||
lda #1
|
||||
sta Overlays
|
||||
ldx #0 ; Always just use the first spot
|
||||
lda #SPRITE_OVERLAY
|
||||
sta Overlays+OVERLAY_ID,x
|
||||
stz Overlays+OVERLAY_FLAGS,x
|
||||
|
||||
lda :top,s
|
||||
sta Overlays+2
|
||||
sta Overlays+OVERLAY_TOP,x
|
||||
lda :bottom,s
|
||||
sta Overlays+4
|
||||
dec
|
||||
sta Overlays+OVERLAY_BOTTOM,x
|
||||
sec
|
||||
sbc :top,s
|
||||
inc
|
||||
sta Overlays+OVERLAY_HEIGHT,x
|
||||
|
||||
lda :proc,s
|
||||
sta Overlays+6
|
||||
sta Overlays+OVERLAY_PROC,x
|
||||
lda :proc+2,s
|
||||
sta Overlays+8
|
||||
sta Overlays+OVERLAY_PROC+2,x
|
||||
|
||||
ldx #{MAX_SPRITES+0}*2 ; Adjust to call the generic routings
|
||||
jsr _InsertSprite
|
||||
|
||||
_TSExit #0;#8
|
||||
|
||||
_TSUpdateOverlay
|
||||
:proc equ FirstParam+0
|
||||
:bottom equ FirstParam+4
|
||||
:top equ FirstParam+6
|
||||
|
||||
_TSEntry
|
||||
|
||||
ldx #0
|
||||
stz Overlays+OVERLAY_FLAGS,x
|
||||
lda :top,s
|
||||
sta Overlays+OVERLAY_TOP
|
||||
lda :bottom,s
|
||||
sta Overlays+OVERLAY_BOTTOM
|
||||
lda :proc,s
|
||||
sta Overlays+OVERLAY_PROC
|
||||
lda :proc+2,s
|
||||
sta Overlays+OVERLAY_PROC+2
|
||||
|
||||
_TSExit #0;#8
|
||||
|
||||
|
@ -809,6 +880,83 @@ _TSSetBG1Scale
|
|||
sta BG1Scaling
|
||||
_TSExit #0;#2
|
||||
|
||||
; Pointer GetAddress(tblId)
|
||||
_TSGetAddress
|
||||
:tblId equ FirstParam+0
|
||||
:output equ FirstParam+2
|
||||
|
||||
_TSEntry
|
||||
lda #0
|
||||
sta :output,s
|
||||
sta :output+2,s
|
||||
|
||||
lda :tblId,s
|
||||
cmp #scanlineHorzOffset
|
||||
bne :next_1
|
||||
|
||||
lda StartXMod164Tbl
|
||||
sta :output,s
|
||||
lda StartXMod164Tbl+2
|
||||
sta :output+2,s
|
||||
bra :out
|
||||
|
||||
:next_1 cmp #scanlineHorzOffset2
|
||||
bne :next_2
|
||||
|
||||
lda BG1StartXMod164Tbl
|
||||
sta :output,s
|
||||
lda BG1StartXMod164Tbl+2
|
||||
sta :output+2,s
|
||||
bra :out
|
||||
:next_2
|
||||
:out
|
||||
_TSExit #0;#2
|
||||
|
||||
; SetAddress(tblId, Pointer)
|
||||
_TSSetAddress
|
||||
:ptr equ FirstParam+0
|
||||
:tblId equ FirstParam+4
|
||||
|
||||
_TSEntry
|
||||
lda :tblId,s
|
||||
cmp #scanlineHorzOffset
|
||||
bne :next_1
|
||||
|
||||
lda :ptr,s
|
||||
sta StartXMod164Tbl
|
||||
lda :ptr+2,s
|
||||
sta StartXMod164Tbl+2
|
||||
bra :out
|
||||
|
||||
:next_1
|
||||
cmp #scanlineHorzOffset2
|
||||
bne :next_2
|
||||
|
||||
lda :ptr,s
|
||||
sta BG1StartXMod164Tbl
|
||||
lda :ptr+2,s
|
||||
sta BG1StartXMod164Tbl+2
|
||||
bra :out
|
||||
:next_2
|
||||
:out
|
||||
_TSExit #0;#6
|
||||
|
||||
; CompileSpriteStamp(spriteId, vbuffAddr)
|
||||
_TSCompileSpriteStamp
|
||||
:vbuff equ FirstParam
|
||||
:spriteId equ FirstParam+2
|
||||
:output equ FirstParam+4
|
||||
|
||||
_TSEntry
|
||||
|
||||
lda :vbuff,s
|
||||
tax
|
||||
lda :spriteId,s
|
||||
jsr _CompileStampSet
|
||||
sta :output,s
|
||||
|
||||
_TSExit #0;#4
|
||||
|
||||
; Insert the GTE code
|
||||
|
||||
put Math.s
|
||||
|
@ -823,6 +971,7 @@ _TSSetBG1Scale
|
|||
put Sprite2.s
|
||||
put SpriteRender.s
|
||||
put Render.s
|
||||
; put blitter/Scanline.s
|
||||
put render/Render.s
|
||||
put render/Fast.s
|
||||
put render/Slow.s
|
||||
|
@ -841,3 +990,4 @@ _TSSetBG1Scale
|
|||
put blitter/Template.s
|
||||
put blitter/TemplateUtils.s
|
||||
put blitter/Blitter.s
|
||||
put blitter/PEISlammer.s
|
||||
|
|
|
@ -12,6 +12,7 @@ _InitBG1
|
|||
_CopyBinToBG1
|
||||
:src_width equ tmp6
|
||||
:src_height equ tmp7
|
||||
:src_flags equ tmp9
|
||||
|
||||
clc
|
||||
adc #8 ; Advance over the header
|
||||
|
@ -21,10 +22,47 @@ _CopyBinToBG1
|
|||
sta :src_width
|
||||
lda #208
|
||||
sta :src_height
|
||||
lda #COPY_PIC_NORMAL
|
||||
sta :src_flags
|
||||
|
||||
pla
|
||||
jmp _CopyToBG1
|
||||
|
||||
; Reset the BG1 Y-table depending on the rendering mode
|
||||
;
|
||||
; A = mode
|
||||
; 0 = default (base = $1800, stride = 256)
|
||||
; 1 = scanline (base = $0, stride = 327)
|
||||
_ResetBG1YTable
|
||||
:base equ tmp0
|
||||
:stride equ tmp1
|
||||
cmp #1 ; scanline mode?
|
||||
bne :default
|
||||
lda #0
|
||||
sta :base
|
||||
lda #327
|
||||
sta :stride
|
||||
bra :begin
|
||||
:default
|
||||
lda #$1800
|
||||
sta :base
|
||||
lda #256
|
||||
sta :stride
|
||||
:begin
|
||||
ldx #0
|
||||
lda :base
|
||||
:loop
|
||||
sta BG1YTable,x
|
||||
sta BG1YTable+{208*2},x
|
||||
|
||||
clc
|
||||
adc :stride
|
||||
|
||||
inx
|
||||
inx
|
||||
cpx #{208*2}
|
||||
bcc :loop
|
||||
rts
|
||||
|
||||
; Copy a IIgs $C1 picture into BG1. Assumes the file is the correct size (320 x 200)
|
||||
;
|
||||
|
@ -35,6 +73,7 @@ _CopyPicToBG1
|
|||
:src_width equ tmp6
|
||||
:src_height equ tmp7
|
||||
:src_stride equ tmp8
|
||||
:src_flags equ tmp9
|
||||
|
||||
pha
|
||||
lda #160
|
||||
|
@ -42,6 +81,8 @@ _CopyPicToBG1
|
|||
sta :src_stride
|
||||
lda #200
|
||||
sta :src_height
|
||||
lda #COPY_PIC_NORMAL
|
||||
sta :src_flags
|
||||
pla
|
||||
jmp _CopyToBG1
|
||||
|
||||
|
@ -54,24 +95,64 @@ _CopyToBG1
|
|||
:src_width equ tmp6
|
||||
:src_height equ tmp7
|
||||
:src_stride equ tmp8
|
||||
:src_flags equ tmp9
|
||||
:dstptr2 equ tmp10
|
||||
|
||||
; scanline mode is tricky -- there's not enough space to make two full copies of a 328x200 bitmap buffer, but we can
|
||||
; *barely* fit a (164 + 163) x 200 buffer. And, since the zero offset could use either end, this covers all of the cases.
|
||||
|
||||
sta :srcptr
|
||||
stx :srcptr+2
|
||||
sty :dstptr+2 ; Everything goes into this bank
|
||||
sty :dstptr2+2
|
||||
|
||||
; "Normal" BG1 mode as a stride of 164 bytes and mirrors the BG0 size (328 x 208)
|
||||
; In "Scanline" mode, the BG1 is treated as a 328x200 bitfield with each horizontal line doubled
|
||||
|
||||
lda :src_flags
|
||||
cmp #COPY_PIC_NORMAL
|
||||
bne *+5
|
||||
jmp :_CopyToBG1Normal
|
||||
|
||||
cmp #COPY_PIC_SCANLINE
|
||||
bne *+5
|
||||
jmp :_CopyToBG1SCanline
|
||||
|
||||
rts ; Flag do not match a known copy mode
|
||||
|
||||
:_CopyToBG1SCanline
|
||||
lda #0 ; Start a byte 1 because odd offsets might go back 1 byte and don't want to wrap around
|
||||
sta :dstptr
|
||||
clc
|
||||
adc #164 ; The first part is 1-byte short, the second part is a full 164 bytes
|
||||
sta :dstptr2
|
||||
|
||||
lda :src_width
|
||||
min #164
|
||||
sta :src_width
|
||||
|
||||
lda :src_height
|
||||
min #200
|
||||
sta :src_height
|
||||
|
||||
stz :line_cnt
|
||||
:rloop
|
||||
lda :line_cnt ; get the pointer to the code field line
|
||||
asl
|
||||
tax
|
||||
|
||||
lda BG1YTable,x
|
||||
sta :dstptr
|
||||
|
||||
ldy #0 ; move forward in the image data and image data
|
||||
; Handle first word as a special case
|
||||
|
||||
lda [:srcptr],y
|
||||
sta [:dstptr2],y ; copy directly into the 164-byte buffer
|
||||
iny
|
||||
xba
|
||||
sep #$20
|
||||
sta [:dstptr],y ; only copy the high byte because the previous line occupies the low byte
|
||||
rep #$20
|
||||
iny
|
||||
|
||||
:cloop
|
||||
lda [:srcptr],y
|
||||
sta [:dstptr],y
|
||||
sta [:dstptr2],y
|
||||
|
||||
iny
|
||||
iny
|
||||
|
@ -79,14 +160,12 @@ _CopyToBG1
|
|||
cpy :src_width
|
||||
bcc :cloop
|
||||
|
||||
ldy #164
|
||||
lda [:srcptr] ; Duplicate the last couple of words in the extra space at the end of the line
|
||||
sta [:dstptr],y
|
||||
|
||||
ldy #2
|
||||
lda [:srcptr],y
|
||||
ldy #166
|
||||
sta [:dstptr],y
|
||||
lda :dstptr
|
||||
clc
|
||||
adc #327
|
||||
sta :dstptr
|
||||
adc #164
|
||||
sta :dstptr2
|
||||
|
||||
lda :srcptr
|
||||
clc
|
||||
|
@ -99,6 +178,49 @@ _CopyToBG1
|
|||
bcc :rloop
|
||||
rts
|
||||
|
||||
:_CopyToBG1Normal
|
||||
stz :line_cnt
|
||||
:rloop2
|
||||
lda :line_cnt ; get the pointer to the code field line
|
||||
asl
|
||||
tax
|
||||
|
||||
lda BG1YTable,x
|
||||
sta :dstptr
|
||||
clc
|
||||
adc #164
|
||||
sta :dstptr2
|
||||
|
||||
ldy #0 ; move forward in the image data and image data
|
||||
:cloop2
|
||||
lda [:srcptr],y
|
||||
sta [:dstptr],y
|
||||
|
||||
iny
|
||||
iny
|
||||
|
||||
cpy :src_width
|
||||
bcc :cloop2
|
||||
|
||||
ldy #0
|
||||
lda [:dstptr],y ; Duplicate the last couple of words in the extra space at the end of the line
|
||||
sta [:dstptr2],y
|
||||
|
||||
ldy #2
|
||||
lda [:dstptr],y
|
||||
sta [:dstptr2],y
|
||||
|
||||
lda :srcptr
|
||||
clc
|
||||
adc :src_stride
|
||||
sta :srcptr
|
||||
|
||||
inc :line_cnt
|
||||
lda :line_cnt
|
||||
cmp :src_height
|
||||
bcc :rloop2
|
||||
rts
|
||||
|
||||
_SetBG1XPos
|
||||
cmp BG1StartX
|
||||
beq :out ; Easy, if nothing changed, then nothing changes
|
||||
|
@ -140,6 +262,35 @@ _ApplyBG1XPosPre
|
|||
sta BG1StartXMod164
|
||||
rts
|
||||
|
||||
; Save as _ApplyBG1XPos, but we pretend that StartXMod164 is always zero and deal with the per-line offset adjustment in
|
||||
; _ApplyScanlineBG1YPos. The tweak here is that the buffer is only 160 bytes wide in scanine mode, instead of 164 bytes wide
|
||||
_ApplyScanlineBG1XPos
|
||||
lda BG1StartXMod164 ; How far into the BG1 buffer is the left edge?
|
||||
tay
|
||||
|
||||
phd ; save the direct page because we are going to switch to the
|
||||
lda BlitterDP ; blitter direct page space and fill in the addresses
|
||||
tcd
|
||||
|
||||
ldx #0
|
||||
; tya
|
||||
lda #0
|
||||
:loop
|
||||
sta 00,x ; store the value
|
||||
inc
|
||||
inc
|
||||
cmp #164
|
||||
bcc *+5
|
||||
sbc #164
|
||||
|
||||
inx
|
||||
inx
|
||||
cpx #164
|
||||
bcc :loop
|
||||
|
||||
pld
|
||||
rts
|
||||
|
||||
_ApplyBG1XPos
|
||||
lda #162
|
||||
sec
|
||||
|
@ -196,6 +347,163 @@ _ClearBG1Buffer
|
|||
plb
|
||||
rts
|
||||
|
||||
; Variation to take care of horizontal adjustments within the BG1 buffer to compensate for the
|
||||
; per-scanline BG0 displacement. It is up to the caller to manage the memeory layout to make
|
||||
; this visually work.
|
||||
;
|
||||
; In the scanline mode we have to be able to adjust the base address of each BG1 line up to
|
||||
; a full screen, so scanline mode treats bank as a 640x200 pixel bitmap (64000 byte).
|
||||
;
|
||||
; This is just a limitation of scanline displacement mode that there is no extra vertical space.
|
||||
_ApplyScanlineBG1YPos
|
||||
:stk_save equ tmp0
|
||||
:virt_line_x2 equ tmp1
|
||||
:lines_left_x2 equ tmp2
|
||||
:draw_count_x2 equ tmp3
|
||||
:ytbl_idx_x2 equ tmp4
|
||||
:shift_value equ tmp5
|
||||
|
||||
; Avoid local var collision
|
||||
:ptr2 equ tmp8
|
||||
:ytbl_idx_pos_x2 equ tmp10
|
||||
:virt_line_pos_x2 equ tmp11
|
||||
:total_left_x2 equ tmp12
|
||||
:current_count_x2 equ tmp13
|
||||
:ptr equ tmp14
|
||||
|
||||
lda StartXMod164Tbl
|
||||
sta :ptr
|
||||
lda StartXMod164Tbl+2
|
||||
sta :ptr+2
|
||||
|
||||
lda BG1StartXMod164Tbl
|
||||
sta :ptr2
|
||||
lda BG1StartXMod164Tbl+2
|
||||
sta :ptr2+2
|
||||
ora :ptr2
|
||||
|
||||
lda BG1StartY
|
||||
jsr Mod208
|
||||
sta BG1StartYMod208
|
||||
asl
|
||||
sta :ytbl_idx_pos_x2 ; Start copying from the first entry in the table
|
||||
|
||||
lda StartYMod208 ; This is the base line of the virtual screen
|
||||
asl
|
||||
sta :virt_line_pos_x2
|
||||
tay
|
||||
|
||||
lda ScreenHeight
|
||||
asl
|
||||
sta :total_left_x2
|
||||
|
||||
:loop0
|
||||
lda [:ptr],y
|
||||
tax
|
||||
|
||||
and #$FF00 ; Determine how many sequential lines have this mod value
|
||||
xba
|
||||
inc
|
||||
asl
|
||||
min :total_left_x2 ; Don't draw more than the number of lines that are left to process
|
||||
sta :current_count_x2 ; Save a copy for later
|
||||
|
||||
sta :lines_left_x2 ; Set the parameter
|
||||
lda :ytbl_idx_pos_x2 ; Set the parameter
|
||||
sta :ytbl_idx_x2
|
||||
sty :virt_line_x2 ; Set the parameter
|
||||
txa ; Put the X mod 164 value in the offset value
|
||||
and #$00FF
|
||||
sta :shift_value
|
||||
|
||||
jsr :_ApplyConstBG1YPos ; Shift this range by a constant amount
|
||||
|
||||
clc
|
||||
lda :virt_line_pos_x2
|
||||
adc :current_count_x2
|
||||
cmp #208*2 ; Do the modulo check in this loop
|
||||
bcc *+5
|
||||
sbc #208*2
|
||||
sta :virt_line_pos_x2
|
||||
tay
|
||||
|
||||
clc
|
||||
lda :ytbl_idx_pos_x2
|
||||
adc :current_count_x2
|
||||
sta :ytbl_idx_pos_x2
|
||||
|
||||
lda :total_left_x2
|
||||
sec
|
||||
sbc :current_count_x2
|
||||
sta :total_left_x2
|
||||
bne :loop0
|
||||
|
||||
rts
|
||||
|
||||
:_ApplyConstBG1YPos
|
||||
|
||||
lda #164
|
||||
sec
|
||||
sbc :shift_value
|
||||
clc
|
||||
adc BG1StartXMod164
|
||||
cmp #164+1
|
||||
bcc *+5
|
||||
sbc #164
|
||||
sta :shift_value ; Base shift value
|
||||
|
||||
cmp #165
|
||||
bcc *+4
|
||||
brk $04
|
||||
|
||||
phb ; Save the existing bank
|
||||
tsc
|
||||
sta :stk_save
|
||||
|
||||
:loop
|
||||
ldx :virt_line_x2
|
||||
|
||||
ldal BTableHigh,x ; Get the bank
|
||||
pha
|
||||
plb
|
||||
|
||||
ldal BTableLow,x ; Get the address of the first code field line
|
||||
tay
|
||||
|
||||
txa ; Calculate number of lines to draw on this iteration
|
||||
and #$001E
|
||||
eor #$FFFF
|
||||
sec
|
||||
adc #32
|
||||
min :lines_left_x2
|
||||
sta :draw_count_x2
|
||||
tax
|
||||
|
||||
lda :ytbl_idx_x2 ; Read from this location in the BG1YTable
|
||||
; clc
|
||||
; CopyBG1YTableToBG1Addr3 :shift_value
|
||||
CopyBG1YTableToBG1Addr4 :shift_value;blttmp
|
||||
|
||||
lda :virt_line_x2 ; advance to the virtual line after
|
||||
adc :draw_count_x2 ; filled in
|
||||
sta :virt_line_x2
|
||||
|
||||
lda :ytbl_idx_x2
|
||||
adc :draw_count_x2
|
||||
sta :ytbl_idx_x2
|
||||
|
||||
lda :lines_left_x2 ; subtract the number of lines we just completed
|
||||
sec
|
||||
sbc :draw_count_x2
|
||||
sta :lines_left_x2
|
||||
|
||||
jne :loop
|
||||
|
||||
lda :stk_save
|
||||
tcs
|
||||
plb
|
||||
rts
|
||||
|
||||
; Everytime either BG1 or BG0 Y-position changes, we have to update the Y-register
|
||||
; value in all of the code fields (within the visible screen)
|
||||
_ApplyBG1YPos
|
||||
|
@ -353,8 +661,138 @@ CopyBG1YTableToBG1Addr
|
|||
sta: BG1_ADDR+$0000,y
|
||||
:none rts
|
||||
|
||||
; Unrolled copy routine to move BG1YTable entries into BG1_ADDR position
|
||||
; with a constant shift applied
|
||||
;
|
||||
; A = index into the BG1YTable array (x2)
|
||||
; Y = starting line * $1000
|
||||
; X = number of lines (x2)
|
||||
; ]1 = offset
|
||||
CopyBG1YTableToBG1Addr3 mac
|
||||
jmp (tbl,x)
|
||||
tbl da none
|
||||
da do01,do02,do03,do04
|
||||
da do05,do06,do07,do08
|
||||
da do09,do10,do11,do12
|
||||
da do13,do14,do15,do16
|
||||
do15 tax
|
||||
jmp x15
|
||||
do14 tax
|
||||
jmp x14
|
||||
do13 tax
|
||||
jmp x13
|
||||
do12 tax
|
||||
jmp x12
|
||||
do11 tax
|
||||
jmp x11
|
||||
do10 tax
|
||||
jmp x10
|
||||
do09 tax
|
||||
jmp x09
|
||||
do08 tax
|
||||
jmp x08
|
||||
do07 tax
|
||||
jmp x07
|
||||
do06 tax
|
||||
jmp x06
|
||||
do05 tax
|
||||
jmp x05
|
||||
do04 tax
|
||||
jmp x04
|
||||
do03 tax
|
||||
jmp x03
|
||||
do02 tax
|
||||
jmp x02
|
||||
do01 tax
|
||||
jmp x01
|
||||
do16 tax
|
||||
ldal BG1YTable+30,x
|
||||
adc ]1
|
||||
sta BG1_ADDR+$F000,y
|
||||
x15 ldal BG1YTable+28,x
|
||||
adc ]1
|
||||
sta BG1_ADDR+$E000,y
|
||||
x14 ldal BG1YTable+26,x
|
||||
adc ]1
|
||||
sta BG1_ADDR+$D000,y
|
||||
x13 ldal BG1YTable+24,x
|
||||
adc ]1
|
||||
sta BG1_ADDR+$C000,y
|
||||
x12 ldal BG1YTable+22,x
|
||||
adc ]1
|
||||
sta BG1_ADDR+$B000,y
|
||||
x11 ldal BG1YTable+20,x
|
||||
adc ]1
|
||||
sta BG1_ADDR+$A000,y
|
||||
x10 ldal BG1YTable+18,x
|
||||
adc ]1
|
||||
sta BG1_ADDR+$9000,y
|
||||
x09 ldal BG1YTable+16,x
|
||||
adc ]1
|
||||
sta BG1_ADDR+$8000,y
|
||||
x08 ldal BG1YTable+14,x
|
||||
adc ]1
|
||||
sta BG1_ADDR+$7000,y
|
||||
x07 ldal BG1YTable+12,x
|
||||
adc ]1
|
||||
sta BG1_ADDR+$6000,y
|
||||
x06 ldal BG1YTable+10,x
|
||||
adc ]1
|
||||
sta BG1_ADDR+$5000,y
|
||||
x05 ldal BG1YTable+08,x
|
||||
adc ]1
|
||||
sta: BG1_ADDR+$4000,y
|
||||
x04 ldal BG1YTable+06,x
|
||||
adc ]1
|
||||
sta BG1_ADDR+$3000,y
|
||||
x03 ldal BG1YTable+04,x
|
||||
adc ]1
|
||||
sta BG1_ADDR+$2000,y
|
||||
x02 ldal BG1YTable+02,x
|
||||
adc ]1
|
||||
sta BG1_ADDR+$1000,y
|
||||
x01 ldal BG1YTable+00,x
|
||||
adc ]1
|
||||
sta: BG1_ADDR+$0000,y
|
||||
none <<<
|
||||
|
||||
; Copy routine to move BG1YTable entries into BG1_ADDR position with an additional
|
||||
; shift on every line form the user-provided BG1StartXMod164Tbl.
|
||||
;
|
||||
; A = index into the BG1YTable array (x2)
|
||||
; Y = starting line * $1000
|
||||
; X = number of lines (x2)
|
||||
;
|
||||
; ]1 = constant shift value
|
||||
; ]2 = temp storage space
|
||||
CopyBG1YTableToBG1Addr4 mac
|
||||
phy ; save the registers
|
||||
phx
|
||||
phb
|
||||
pha
|
||||
jsr _SetDataBank ; Set to toolbox data bank
|
||||
|
||||
clc
|
||||
lda 1,s ; virtual_index_x2
|
||||
adc BG1StartXMod164Tbl ; Get the starting address in the array for this chunk
|
||||
tay
|
||||
|
||||
lda BG1StartXMod164Tbl+1 ; Set the bank to the array location
|
||||
pha
|
||||
plb
|
||||
plb
|
||||
|
||||
pla ; POp back the original value
|
||||
ApplyBG1ModXToShift ]1;]2 ; Copy the array into direct page storage and apply the shift
|
||||
|
||||
plb ; Restore the code field bank
|
||||
plx ; x is used directly in this routine
|
||||
ply
|
||||
ApplyBG1ShiftToCode ]2
|
||||
<<<
|
||||
|
||||
; Unrolled copy routine to move BG1YTable entries into BG1_ADDR position with an additional
|
||||
; shift. This has to be split into two
|
||||
; shift on every line. This has to be split into two
|
||||
;
|
||||
; A = index into the BG1YTable array (x2)
|
||||
; Y = starting line * $1000
|
||||
|
@ -504,3 +942,105 @@ ApplyBG1OffsetValues
|
|||
:do01 ldal BG1YCache+00
|
||||
sta: BG1_ADDR+$0000,y
|
||||
:none rts
|
||||
|
||||
; Apply the per-scanline shift from the BG1StartXMod164Tbl pointer. Save the relevant values to the
|
||||
; direct page since the array could be in any bank.
|
||||
;
|
||||
; This does bounds checking to make sure the shift value remains in the valid range
|
||||
;
|
||||
; ]1 = source array offset
|
||||
; ]2 = constant shift value
|
||||
; ]3 = destination address
|
||||
_BG1ShiftTemplate mac
|
||||
lda ]1,y ; Load the value from the array
|
||||
adc ]2 ; Add to the direct page shift_value
|
||||
cmp #165 ; If below this value, we're good
|
||||
bcc *+6
|
||||
sbc #164
|
||||
clc
|
||||
adcl BG1YTable+]1,x
|
||||
sta ]3+]1
|
||||
<<<
|
||||
|
||||
AToX mac
|
||||
tax
|
||||
brl ]1
|
||||
<<<
|
||||
|
||||
ApplyBG1ModXToShift mac
|
||||
jmp (agmxts_tbl,x)
|
||||
agmxts_tbl da none
|
||||
da do01,do02,do03,do04
|
||||
da do05,do06,do07,do08
|
||||
da do09,do10,do11,do12
|
||||
da do13,do14,do15,do16
|
||||
do16 AToX o16
|
||||
do15 AToX o15
|
||||
do14 AToX o14
|
||||
do13 AToX o13
|
||||
do12 AToX o12
|
||||
do11 AToX o11
|
||||
do10 AToX o10
|
||||
do09 AToX o09
|
||||
do08 AToX o08
|
||||
do07 AToX o07
|
||||
do06 AToX o06
|
||||
do05 AToX o05
|
||||
do04 AToX o04
|
||||
do03 AToX o03
|
||||
do02 AToX o02
|
||||
do01 AToX o01
|
||||
|
||||
o16 _BG1ShiftTemplate 30;]1;]2
|
||||
o15 _BG1ShiftTemplate 28;]1;]2
|
||||
o14 _BG1ShiftTemplate 26;]1;]2
|
||||
o13 _BG1ShiftTemplate 24;]1;]2
|
||||
o12 _BG1ShiftTemplate 22;]1;]2
|
||||
o11 _BG1ShiftTemplate 20;]1;]2
|
||||
o10 _BG1ShiftTemplate 18;]1;]2
|
||||
o09 _BG1ShiftTemplate 16;]1;]2
|
||||
o08 _BG1ShiftTemplate 14;]1;]2
|
||||
o07 _BG1ShiftTemplate 12;]1;]2
|
||||
o06 _BG1ShiftTemplate 10;]1;]2
|
||||
o05 _BG1ShiftTemplate 8;]1;]2
|
||||
o04 _BG1ShiftTemplate 6;]1;]2
|
||||
o03 _BG1ShiftTemplate 4;]1;]2
|
||||
o02 _BG1ShiftTemplate 2;]1;]2
|
||||
o01 _BG1ShiftTemplate 0;]1;]2
|
||||
none <<<
|
||||
|
||||
; After the values are saved, the data bank can be repointed at the current code bank and the values copied in
|
||||
; from the direct page
|
||||
;
|
||||
; ]1 = offset in temp buffer
|
||||
; ]2 = address of temp buffer
|
||||
; ]3 = 4k offset in code buffer
|
||||
_BG1ShiftToCodeTemplate mac
|
||||
lda ]2+]1
|
||||
sta: BG1_ADDR+]3,y
|
||||
<<<
|
||||
|
||||
ApplyBG1ShiftToCode mac
|
||||
jmp (abstc_tbl,x)
|
||||
abstc_tbl da none
|
||||
da do01,do02,do03,do04
|
||||
da do05,do06,do07,do08
|
||||
da do09,do10,do11,do12
|
||||
da do13,do14,do15,do16
|
||||
do16 _BG1ShiftToCodeTemplate 30;]1;$F000
|
||||
do15 _BG1ShiftToCodeTemplate 28;]1;$E000
|
||||
do14 _BG1ShiftToCodeTemplate 26;]1;$D000
|
||||
do13 _BG1ShiftToCodeTemplate 24;]1;$C000
|
||||
do12 _BG1ShiftToCodeTemplate 22;]1;$B000
|
||||
do11 _BG1ShiftToCodeTemplate 20;]1;$A000
|
||||
do10 _BG1ShiftToCodeTemplate 18;]1;$9000
|
||||
do09 _BG1ShiftToCodeTemplate 16;]1;$8000
|
||||
do08 _BG1ShiftToCodeTemplate 14;]1;$7000
|
||||
do07 _BG1ShiftToCodeTemplate 12;]1;$6000
|
||||
do06 _BG1ShiftToCodeTemplate 10;]1;$5000
|
||||
do05 _BG1ShiftToCodeTemplate 8;]1;$4000
|
||||
do04 _BG1ShiftToCodeTemplate 6;]1;$3000
|
||||
do03 _BG1ShiftToCodeTemplate 4;]1;$2000
|
||||
do02 _BG1ShiftToCodeTemplate 2;]1;$1000
|
||||
do01 _BG1ShiftToCodeTemplate 0;]1;$0000
|
||||
none <<<
|
|
@ -57,16 +57,19 @@ _BltRange
|
|||
lda EngineMode
|
||||
bit #ENGINE_MODE_TWO_LAYER
|
||||
beq :skip_bank
|
||||
|
||||
lda RenderFlags
|
||||
bit #RENDER_ALT_BG1
|
||||
beq :primary
|
||||
|
||||
lda BG1AltBank
|
||||
bra :alt
|
||||
|
||||
:primary lda BG1DataBank
|
||||
:alt
|
||||
; TODO: Switch to loading the selected BG1 bank. No special "Alt" bank
|
||||
;
|
||||
; lda RenderFlags
|
||||
; bit #RENDER_ALT_BG1
|
||||
; beq :primary
|
||||
;
|
||||
; lda BG1AltBank
|
||||
; bra :alt
|
||||
;
|
||||
;:primary lda BG1DataBank
|
||||
;:alt
|
||||
lda BG1DataBank
|
||||
pha
|
||||
plb
|
||||
|
||||
|
@ -81,7 +84,7 @@ _BltRange
|
|||
_R0W1
|
||||
tsc ; save the stack pointer
|
||||
stal stk_save+1
|
||||
|
||||
|
||||
blt_entry jml $000000 ; Jump into the blitter code $XX/YY00
|
||||
|
||||
blt_return _R0W0
|
||||
|
|
1011
src/blitter/Horz.s
1011
src/blitter/Horz.s
File diff suppressed because it is too large
Load Diff
|
@ -6,13 +6,20 @@
|
|||
; slammer, note that page-aligned addresses repeat every 8 scan lines and some lines would need
|
||||
; to be split into two slams to keep the direct page aligned.
|
||||
;
|
||||
; At best, this saves 1 cycles per word, or 80 cycles for a full screen -- which is only about
|
||||
; At best, this saves 1 cycles per word, or 80 cycles for a full scanline -- which is only about
|
||||
; 12 additional instructions, so this is an optimization that is unlikely to lead to a net
|
||||
; improvement.
|
||||
;
|
||||
; X = first line (inclusive), valid range of 0 to 199
|
||||
; Y = last line (exclusive), valid range >X up to 200
|
||||
_PEISlam
|
||||
cpx #201
|
||||
bcc *+4
|
||||
brk $A9
|
||||
cpy #201
|
||||
bcc *+4
|
||||
brk $A8
|
||||
|
||||
lda ScreenWidth
|
||||
dec
|
||||
stal :screen_width_1 ; save the width-1 outside of the direct page
|
||||
|
|
|
@ -0,0 +1,256 @@
|
|||
; This support an alternate engine mode. When in scanline mode the renderer does not use the
|
||||
; global StartX and StartY parameters to set up the code field. Instead, an array of scanline
|
||||
; parameters must be provided to the blitter.
|
||||
;
|
||||
; This is a low-level mode and it is assumed that the arrays will contain valid values. This
|
||||
; process is quite a bit slower that the normal setup because it must calculate code field
|
||||
; entry points for each line, instead of once for the entire frame.
|
||||
|
||||
_ScanlineBG0XPos
|
||||
|
||||
:stk_save equ tmp0
|
||||
:virt_line_x2 equ tmp1
|
||||
:last_line_x2 equ tmp2
|
||||
:src_bank equ tmp3
|
||||
:exit_offset equ tmp4
|
||||
:entry_offset equ tmp5
|
||||
:exit_bra equ tmp6
|
||||
:exit_address equ tmp7
|
||||
:base_address equ tmp8
|
||||
:opcode equ tmp9
|
||||
:odd_entry_offset equ tmp10
|
||||
|
||||
lda StartYMod208 ; This is the base line of the virtual screen
|
||||
asl
|
||||
sta :virt_line_x2 ; Keep track of it
|
||||
|
||||
lda ScreenHeight
|
||||
asl
|
||||
clc
|
||||
adc :virt_line_x2
|
||||
sta :last_line_x2
|
||||
|
||||
phb
|
||||
phb
|
||||
pla
|
||||
and #$FF00
|
||||
sta :src_bank
|
||||
|
||||
:loop
|
||||
ldx :virt_line_x2
|
||||
|
||||
lda StartXMod164Arr,x ; Get the offset for this line
|
||||
dec ; The exit point is one byte sooner
|
||||
bpl *+5
|
||||
lda #163
|
||||
|
||||
bit #$0001 ; if odd, then original number was even
|
||||
beq :odd_exit ; if even, the original number was odd
|
||||
|
||||
; This is the even code path
|
||||
and #$FFFE
|
||||
tay
|
||||
lda CodeFieldEvenBRA,y
|
||||
sta :exit_bra
|
||||
lda Col2CodeOffset,y
|
||||
sta :exit_offset
|
||||
sta LastPatchOffsetArr,x ; Cache afor later
|
||||
bra :do_entry
|
||||
|
||||
; This is the odd code path
|
||||
:odd_exit tay
|
||||
lda CodeFieldOddBRA,y
|
||||
sta :exit_bra
|
||||
lda Col2CodeOffset,y
|
||||
sta :exit_offset
|
||||
sta LastPatchOffsetArr,x
|
||||
|
||||
; Handle the entry point calculations
|
||||
:do_entry
|
||||
lda StartXMod164Arr,x
|
||||
clc
|
||||
adc ScreenWidth ; move to the right edge and back up a byte
|
||||
dec ; to get the index of the first on-screen byte
|
||||
|
||||
cmp #164 ; Keep the value in range
|
||||
bcc *+5
|
||||
sbc #164
|
||||
|
||||
; Same logic as before
|
||||
|
||||
bit #$0001
|
||||
beq :odd_entry
|
||||
|
||||
and #$FFFE
|
||||
tay
|
||||
lda Col2CodeOffset,y
|
||||
sta :entry_offset
|
||||
lda #$004C ; set the entry_jmp opcode to JMP
|
||||
sta :opcode
|
||||
stz :odd_entry_offset ; mark as an even case
|
||||
bra :prep_complete
|
||||
|
||||
:odd_entry
|
||||
tay
|
||||
lda Col2CodeOffset,y
|
||||
sta :entry_offset ; Will be used to load the data
|
||||
lda Col2CodeOffset-2,y
|
||||
sta :odd_entry_offset ; will the the actual location to jump to
|
||||
lda #$00AF ; set the entry_jmp opcode to LDAL
|
||||
sta :opcode
|
||||
:prep_complete
|
||||
|
||||
; Now patch in the code field line
|
||||
|
||||
ldy BTableLow,x ; Get the address of the first code field line
|
||||
clc
|
||||
adc :exit_offset ; Add some offsets to get the base address in the code field line
|
||||
sta :exit_address
|
||||
sty :base_address
|
||||
|
||||
lda BTableHigh,x
|
||||
ora :src_bank
|
||||
pha
|
||||
plb
|
||||
|
||||
; First step is to set the BRA instruction to exit the code field at the proper location. There
|
||||
; are two sub-steps to do here; we need to save the 16-bit value that exists at the location and
|
||||
; then overwrite it with the branch instruction.
|
||||
|
||||
; SaveOpcode
|
||||
; y is already set to :base_address
|
||||
ldx :exit_address ; Save from this location
|
||||
lda: $0000,x
|
||||
sta: OPCODE_SAVE+$0000,y
|
||||
|
||||
;SetConst
|
||||
; txy ; ldy :exit_address -- starting at this address
|
||||
lda :exit_bra ; Copy this value into all of the lines
|
||||
sta: $0000,x
|
||||
|
||||
; Next, patch in the CODE_ENTRY value, which is the low byte of a JMP instruction. This is an
|
||||
; 8-bit operation and, since the PEA code is bank aligned, we use the entry_offset value directly
|
||||
|
||||
sep #$20
|
||||
|
||||
; SetCodeEntry
|
||||
lda :entry_offset
|
||||
; ldy :base_address
|
||||
sta: CODE_ENTRY+$0000,y
|
||||
|
||||
; SetCodeEntryOpcode
|
||||
|
||||
lda :opcode
|
||||
sta: CODE_ENTRY_OPCODE+$0000,y
|
||||
|
||||
; If this is an odd entry, also set the odd_entry low byte and save the operand high byte
|
||||
|
||||
lda :odd_entry_offset
|
||||
beq :not_odd
|
||||
|
||||
; SetOddCodeEntry
|
||||
sta: ODD_ENTRY+$0000,y
|
||||
; SaveHighOperand
|
||||
; ldx :exit_address
|
||||
lda: $0002,x
|
||||
sta: OPCODE_HIGH_SAVE+$0000,y
|
||||
:not_odd
|
||||
rep #$20 ; clear the carry
|
||||
|
||||
; Do the end of the loop -- update the virtual line counter and reduce the number
|
||||
; of lines left to render
|
||||
|
||||
plb ; restore the bank
|
||||
|
||||
lda :virt_line_x2
|
||||
inc
|
||||
inc
|
||||
sta :virt_line_x2
|
||||
cmp :last_line_x2
|
||||
jne :loop
|
||||
|
||||
rts
|
||||
|
||||
|
||||
_RestoreScanlineBG0Opcodes
|
||||
|
||||
:virt_line_x2 equ tmp1
|
||||
:lines_left_x2 equ tmp2
|
||||
:src_bank equ tmp6
|
||||
|
||||
asl
|
||||
sta :virt_line_x2 ; Keep track of it
|
||||
|
||||
phb
|
||||
phb
|
||||
pla
|
||||
and #$FF00
|
||||
sta :src_bank
|
||||
|
||||
txa
|
||||
asl
|
||||
sta :lines_left_x2
|
||||
|
||||
:loop
|
||||
ldx :virt_line_x2
|
||||
|
||||
lda BTableHigh,x
|
||||
ora :src_bank
|
||||
pha
|
||||
|
||||
lda BTableLow,x ; Get the address of the first code field line
|
||||
clc
|
||||
adc LastPatchOffsetArr,x
|
||||
tax
|
||||
|
||||
plb
|
||||
lda: OPCODE_SAVE+$0000,y
|
||||
sta: $0000,x
|
||||
|
||||
; Do the end of the loop -- update the virtual line counter and reduce the number
|
||||
; of lines left to render
|
||||
|
||||
plb ; restore the bank
|
||||
|
||||
lda :virt_line_x2
|
||||
inc
|
||||
inc
|
||||
sta :virt_line_x2
|
||||
cmp :last_line_x2
|
||||
jne :loop
|
||||
|
||||
stz LastPatchOffset ; Clear the value once completed
|
||||
rts
|
||||
|
||||
; Unrolled copy routine to move BankTable entries into BNK_ADDR position. This is a bit different than the
|
||||
; other routines, because we don't need to put values into the code fields, but just copy one-byte values
|
||||
; into an internal array in bank 00 space. The reason for this is because the code sequence
|
||||
;
|
||||
; lda #ADDR
|
||||
; tcs
|
||||
; plb
|
||||
;
|
||||
; Take only 9 cycles, but the alternative is slower
|
||||
;
|
||||
; pea #$BBBB
|
||||
; plb
|
||||
; plb = 13 cycles
|
||||
;
|
||||
; If for some reason it becomes important to preserve the accumulator, or save the 208 bytes of
|
||||
; bank 00 memory, then we can change it. The advantage right now is that updating the array can
|
||||
; be done 16-bits at a time and without having to chunk up the writes across multiple banks. This
|
||||
; is quite a bit faster than the other routines.
|
||||
CopyTableToBankBytes
|
||||
|
||||
tsx ; save the stack
|
||||
sei
|
||||
jmp $0000
|
||||
|
||||
lda: 2,y
|
||||
pha
|
||||
lda: 0,y
|
||||
pha
|
||||
bottom
|
||||
txs ; restore the stack
|
||||
cli ; turn interrupts back on
|
||||
rts
|
|
@ -5,10 +5,12 @@
|
|||
DP_ADDR equ entry_1-base+1 ; offset to patch in the direct page for dynamic tiles
|
||||
BG1_ADDR equ entry_2-base+1 ; offset to patch in the Y-reg for BG1 (dp),y addressing
|
||||
STK_ADDR equ entry_3-base+1 ; offset to patch in the stack (SHR) right edge address
|
||||
; BNK_ADDR equ entry_0-base+1 ; offset to patch in the address of a Bank 0 memory location to load the bank register
|
||||
|
||||
DP_ENTRY equ entry_1-base
|
||||
TWO_LYR_ENTRY equ entry_2-base
|
||||
ONE_LYR_ENTRY equ entry_3-base
|
||||
; BANK_ENTRY equ entry_0-base
|
||||
|
||||
CODE_ENTRY_OPCODE equ entry_jmp-base
|
||||
CODE_ENTRY equ entry_jmp-base+1 ; low byte of the page-aligned jump address
|
||||
|
@ -16,19 +18,26 @@ ODD_ENTRY equ odd_entry-base+1
|
|||
CODE_TOP equ loop-base
|
||||
CODE_LEN equ top-base
|
||||
CODE_EXIT equ even_exit-base
|
||||
OPCODE_SAVE equ odd_save-base ; spot to save the code field opcode when patching exit BRA
|
||||
OPCODE_HIGH_SAVE equ odd_save-base+2 ; save the third byte
|
||||
OPCODE_SAVE equ odd_low_save-base ; spot to save the code field opcode when patching exit BRA
|
||||
OPCODE_HIGH_SAVE equ odd_high_save-base ; save the second and third byte
|
||||
FULL_RETURN equ full_return-base ; offset that returns from the blitter
|
||||
ENABLE_INT equ enable_int-base ; offset that re-enable interrupts and continues
|
||||
LINES_PER_BANK equ 16
|
||||
SNIPPET_BASE equ snippets-base
|
||||
|
||||
; offsets from each snippet base address for the different entry points
|
||||
|
||||
SNIPPET_ENTRY_1 equ 0 ; two layer + dynamic tile + sprite
|
||||
SNIPPET_ENTRY_2 equ 4 ; (two layer | dynamic tile) + sprite
|
||||
SNIPPET_ENTRY_3 equ 18 ; sprite under dynamic tile
|
||||
SNIPPET_ENTRY_4 equ 19 ; two layer + dynamic tile (no sprite)
|
||||
|
||||
; Locations that need the page offset added
|
||||
PagePatches da {long_0-base+2}
|
||||
da {long_1-base+2}
|
||||
da {long_2-base+2}
|
||||
da {long_3-base+2}
|
||||
da {long_4-base+2}
|
||||
; da {long_4-base+2}
|
||||
da {long_5-base+2}
|
||||
da {long_6-base+2}
|
||||
da {odd_entry-base+2}
|
||||
|
@ -41,9 +50,9 @@ PagePatches da {long_0-base+2}
|
|||
; da {jmp_rtn_2-base+2}
|
||||
|
||||
]index equ 0
|
||||
lup 82 ; All the snippet addresses. The two JMP
|
||||
da {snippets-base+{]index*32}+31} ; instructions are at the end of each of
|
||||
da {snippets-base+{]index*32}+28} ; the 32-byte buffers
|
||||
lup 82 ; Patch anything that needs updating within the snippets
|
||||
da {snippets-base+{]index*32}+17}
|
||||
da {snippets-base+{]index*32}+29}
|
||||
]index equ ]index+1
|
||||
--^
|
||||
PagePatchNum equ *-PagePatches
|
||||
|
@ -53,7 +62,7 @@ BankPatches da {long_0-base+3}
|
|||
da {long_1-base+3}
|
||||
da {long_2-base+3}
|
||||
da {long_3-base+3}
|
||||
da {long_4-base+3}
|
||||
; da {long_4-base+3}
|
||||
da {long_5-base+3}
|
||||
da {long_6-base+3}
|
||||
BankPatchNum equ *-BankPatches
|
||||
|
@ -66,6 +75,9 @@ BankPatchNum equ *-BankPatches
|
|||
; the code is assembled on a page boundary to help with alignment
|
||||
ds \,$00 ; pad to the next page boundary
|
||||
base
|
||||
;entry_0 lda #0000 ; Used to set per-scanline bank register
|
||||
; tcs
|
||||
; plb
|
||||
entry_1 ldx #0000 ; Used for LDA 00,x addressing (Dynamic Tiles)
|
||||
entry_2 ldy #0000 ; Used for LDA (00),y addressing (Second Layer; BG1)
|
||||
entry_3 lda #0000 ; Sets screen address (right edge)
|
||||
|
@ -82,7 +94,7 @@ entry_jmp jmp $0100
|
|||
; update the low-byte of the address, the means it takes only
|
||||
; an amortized 4-cycles per line to set the entry point break
|
||||
|
||||
right_odd bit #$000B ; Check the bottom nibble to quickly identify a PEA instruction
|
||||
bit #$000B ; Check the bottom nibble to quickly identify a PEA instruction
|
||||
bne r_is_not_pea ; This costs 5 cycles in the fast-path
|
||||
|
||||
xba ; fast code for PEA
|
||||
|
@ -166,38 +178,39 @@ loop lup 82 ; +6 Set up 82 PEA instruc
|
|||
loop_back jmp loop-base ; +252 Ensure execution continues to loop around
|
||||
loop_exit_3 jmp even_exit-base ; +255
|
||||
|
||||
long_5
|
||||
odd_exit ldal l_is_jmp+1-base
|
||||
bit #$000B
|
||||
odd_exit sep #$21 ; 8-bit mode and set the carry just in case we get to a snippet JMP
|
||||
long_5 ldal OPCODE_SAVE ; Load the opcode that was saved
|
||||
bit #$0B
|
||||
bne :chk_jmp
|
||||
|
||||
sep #$20
|
||||
long_6 ldal l_is_jmp+3-base ; get the high byte of the PEA operand
|
||||
long_6 ldal OPCODE_HIGH_SAVE+1 ; get the high byte of the PEA operand
|
||||
|
||||
; Fall-through when we have to push a byte on the left edge. Must be 8-bit on entry. Optimized
|
||||
; for the PEA $0000 case -- only 19 cycles to handle the edge, so pretty good
|
||||
:left_byte
|
||||
; for the PEA $0000 case -- only 17 cycles to handle the edge, so pretty good
|
||||
|
||||
pha
|
||||
rep #$20
|
||||
rep #$21
|
||||
|
||||
; JMP opcode = $4C, JML opcode = $5C
|
||||
even_exit jmp $1000 ; Jump to the next line.
|
||||
ds 1 ; space so that the last line in a bank can be patched into a JML
|
||||
|
||||
:chk_jmp
|
||||
bit #$0040
|
||||
:chk_jmp mx %10 ; 8-bit accumulator / 16-bit registers
|
||||
bit #$40
|
||||
bne l_is_jmp
|
||||
|
||||
long_4 stal *+4-base
|
||||
dfb $00,$00
|
||||
rep #$20 ; saved 3 cycles using 8-bit mode, but give it back here.
|
||||
odd_low_save dfb $00,$00 ; save the first and second bytes of the code field. Works for LDA dp,x and LDA (0),y
|
||||
l_jmp_rtn xba
|
||||
sep #$20
|
||||
pha
|
||||
rep #$61 ; Clear everything C, V and M
|
||||
bra even_exit
|
||||
|
||||
l_is_jmp sec ; Set the C flag (V is always cleared at this point) which tells a snippet to push only the high byte
|
||||
odd_save dfb $00,$00,$00 ; The odd exit 3-byte sequence is always stashed here
|
||||
l_is_jmp
|
||||
rep #$20 ; Back to 16-bit mode (carry was set above)
|
||||
; sec ; Set the C flag (V is always cleared at this point) which tells a snippet to push only the high byte
|
||||
dfb $4C ; Expect a JMP instruction
|
||||
odd_high_save dfb $00,$00 ; The high 2 bytes of the 3-byte code field sequence is always stashed here
|
||||
|
||||
; Special epilogue: skip a number of bytes and jump back into the code field. This is useful for
|
||||
; large, floating panels in the attract mode of a game, or to overlay solid
|
||||
|
@ -227,73 +240,95 @@ epilogue_1 tsc
|
|||
; its passed state, because having the carry bit clear prevents evaluation of
|
||||
; the V bit.
|
||||
;
|
||||
; Snippet Samples:
|
||||
; Version 2: In order to improve performance, especially for two-layer tiles + sprites, the
|
||||
; snippet code was revised to have a fixed structure so that the constant DATA and
|
||||
; MASK values always exist in the same location, regarless of the tile type. The
|
||||
; tradeoff is that there is a different entry point into the snippet based on the
|
||||
; tile type, but that is significantly cheaper to lookup and patch into the code
|
||||
; field JMP instruction than it is to rebuild 20+ bytes of code each time.
|
||||
;
|
||||
; Standard Two-level Mix (23 bytes)
|
||||
; There are different snippet templates + offset tables based on the EngineMode
|
||||
;
|
||||
; Optimal = 18 cycles (LDA/AND/ORA/PHA/JMP)
|
||||
; 16-bit write = 20 cycles
|
||||
; 8-bit low = 28 cycles
|
||||
; 8-bit high = 27 cycles
|
||||
; EngineMode
|
||||
;
|
||||
; start lda (00),y ; 6
|
||||
; and #MASK ; 3
|
||||
; ora #DATA ; 3 = 12 cycles to load the data
|
||||
; bcs alt_exit ; 2/3
|
||||
; pha ; 4
|
||||
; out jmp next ; 3 Fast-path completes in 5 additional cycles
|
||||
; alt_exit jmp jmp_rtn ; 3
|
||||
; ENGINE_MODE_TWO_LAYER NO
|
||||
; ENGINE_MODE_DYN_TILES NO
|
||||
;
|
||||
; Snippet Template
|
||||
; None.
|
||||
;
|
||||
; For dynamic masked tiles, we re-write bytes 2 - 8 as this, which mostly
|
||||
; avoids an execution speed pentaly for having to fill in the two extra bytes
|
||||
; with an instruction
|
||||
; ENGINE_MODE_TWO_LAYER YES
|
||||
; ENGINE_MODE_DYN_TILES NO
|
||||
;
|
||||
; start lda (00),y ; 6
|
||||
; and $80,x ; 5
|
||||
; ora $00,x ; 5 = 16 cycles to load the data
|
||||
; bcs alt_exit ; 2/3
|
||||
; pha
|
||||
; ...
|
||||
; Snippet Template
|
||||
;
|
||||
; A theoretical exception handler that performed a full 3-level blend would be
|
||||
; ds 4
|
||||
; lda (00),y <-- Single Entry Point
|
||||
; and #MASK <-- Mask is always at byte 8
|
||||
; ora #DATA <-- Data is always at byte 11
|
||||
; bcs _alt
|
||||
; pha
|
||||
; jmp NEXT
|
||||
; _alt jmp RTN
|
||||
;
|
||||
; start lda 0,s
|
||||
; and [00],y
|
||||
; ora (00),y
|
||||
; and $80,x
|
||||
; ora $00,x
|
||||
; and #MASK
|
||||
; ora #DATA
|
||||
; bcs alt_exit
|
||||
; pha ; 4
|
||||
; out brl next ; 4 Fast-path completes in 5 additional cycles
|
||||
; ENGINE_MODE_TWO_LAYER NO
|
||||
; ENGINE_MODE_DYN_TILES YES
|
||||
;
|
||||
; alt_exit bvs r_edge ; 2/3
|
||||
; clc ; 2
|
||||
; brl l_jmp_rtn ; 3
|
||||
; r_edge rep #$41
|
||||
; brl r_jmp_rtn ; 3
|
||||
; Snippet Template
|
||||
;
|
||||
; ds 4
|
||||
; lda 00,x <-- Single Entry Point
|
||||
; and #MASK
|
||||
; ora #DATA
|
||||
; bcs _alt
|
||||
; pha
|
||||
; jmp NEXT
|
||||
; _alt jmp RTN
|
||||
;
|
||||
; ENGINE_MODE_TWO_LAYER YES
|
||||
; ENGINE_MODE_DYN_TILES YES
|
||||
;
|
||||
; Snippet Template
|
||||
;
|
||||
; lda (00),y <-- Entry Point 1
|
||||
; and $80,x
|
||||
; ora $00,x <-- Entry Point 2 (Change this word to "lda (00),y" or "lda 00,x", or "ora 00,x" depending on combination)
|
||||
; and #MASK
|
||||
; ora #DATA
|
||||
; bcs _alt
|
||||
; _16bit pha
|
||||
; jmp NEXT
|
||||
; db 1 <--- Entry Point 3 (opcode for an LDA #DATA instruction)
|
||||
; lda (00),y <--- Entry Point 4 (sneak this in here to avoid extra branch)
|
||||
; and $80,x
|
||||
; ora $00,x
|
||||
; bcc _16bit
|
||||
; _alt jmp RTN (29 bytes)
|
||||
;
|
||||
; Note that the code that's assembled in these snippets is just a template. Every routine that utilizes
|
||||
; an exception handler *MUST* patch up the routines. There are different routines based on the Engine Mode.
|
||||
;
|
||||
; The LDA (00),y opcodes have a fixed operand, but the dynamic tile instructions are determined by the
|
||||
; dynamic tile id and must be set each time.
|
||||
|
||||
; Each snippet is provided 32 bytes of space. The constant code is filled in from the end and
|
||||
; it is the responsibility of the code that fills in the hander to create valid program in the
|
||||
; first 23 bytes are available to be manipulated.
|
||||
;
|
||||
; Note that the code that's assembled in the first bytes of these snippets is just an example. Every
|
||||
; routine that created an exception handler *MUST* write a full set of instructions since there is
|
||||
; no guarantee of what was written previously.
|
||||
ds \,$00 ; pad to the next page boundary
|
||||
]index equ 0
|
||||
snippets lup 82
|
||||
ds 2 ; space for all exception handlers
|
||||
and #$0000 ; the mask operand will be set when the tile is drawn
|
||||
ora #$0000 ; the data operand will be set when the tile is drawn
|
||||
ds 15 ; extra padding
|
||||
|
||||
bcs :byte ; if C = 0, just push the data and return
|
||||
pha ; 1 byte
|
||||
jmp loop+3+{3*]index}-base ; 3 bytes
|
||||
:byte jmp jmp_rtn-base ; 3 bytes
|
||||
lda ({{81-]index}*2}),y ; 0: Pre-set the LDA (XX),y instructions
|
||||
and $80,x ; 2: The direct page instructions are placeholders and get overwritten
|
||||
ora $00,x ; 4: This gets patched out often
|
||||
and #$0000 ; 6: the mask operand will be set when the tile is drawn
|
||||
ora #$0000 ; 9: the data operand will be set when the tile is drawn
|
||||
bcs :byte ; 12: if C = 0, just push the data and return
|
||||
:word pha ; 14:
|
||||
jmp loop+3+{3*]index}-base ; 15: Return address offset within the code field
|
||||
db $A9 ; 18: LDA #DATA opcode
|
||||
lda ({{81-]index}*2}),y ; 19: Pre-set the LDA (XX),y instructions
|
||||
and $80,x ; 21:
|
||||
ora $00,x ; 23:
|
||||
bcc :word ; 25:
|
||||
:byte jmp jmp_rtn-base ; 27:
|
||||
ds 2 ; 30: Padding to make a full 32 bytes
|
||||
]index equ ]index+1
|
||||
--^
|
||||
top
|
|
@ -72,7 +72,7 @@ Counter equ tmp3
|
|||
rts
|
||||
|
||||
|
||||
; Patch an 8-bit or 16-bit valueS into the bank. These are a set up unrolled loops to
|
||||
; Patch an 8-bit or 16-bit valueS into the bank. These are set up as unrolled loops to
|
||||
; quickly patch in a constant value, or a value from an array into a given set of
|
||||
; templates.
|
||||
;
|
||||
|
@ -87,14 +87,14 @@ Counter equ tmp3
|
|||
; A = value
|
||||
;
|
||||
; Set M to 0 or 1
|
||||
SetConst ; Need a blank line here, otherwise the :tbl local variable resolveds backwards
|
||||
jmp (:tbl,x)
|
||||
:tbl da :bottom-00,:bottom-03,:bottom-06,:bottom-09
|
||||
da :bottom-12,:bottom-15,:bottom-18,:bottom-21
|
||||
da :bottom-24,:bottom-27,:bottom-30,:bottom-33
|
||||
da :bottom-36,:bottom-39,:bottom-42,:bottom-45
|
||||
da :bottom-48
|
||||
:top sta $F000,y
|
||||
SetConst mac
|
||||
jmp (dispTbl,x)
|
||||
dispTbl da bottom-00,bottom-03,bottom-06,bottom-09
|
||||
da bottom-12,bottom-15,bottom-18,bottom-21
|
||||
da bottom-24,bottom-27,bottom-30,bottom-33
|
||||
da bottom-36,bottom-39,bottom-42,bottom-45
|
||||
da bottom-48
|
||||
sta $F000,y
|
||||
sta $E000,y
|
||||
sta $D000,y
|
||||
sta $C000,y
|
||||
|
@ -110,7 +110,8 @@ SetConst ; Need a blank line here, ot
|
|||
sta $2000,y
|
||||
sta $1000,y
|
||||
sta: $0000,y
|
||||
:bottom rts
|
||||
bottom
|
||||
<<<
|
||||
|
||||
; SetDPAddrs
|
||||
;
|
||||
|
@ -244,8 +245,8 @@ BuildBank
|
|||
plb
|
||||
plb
|
||||
|
||||
; Change the patched value to one of DP_ENTRY, TWO_LYR_ENTRY or ONE_LYR_ENTRY based on the capabilities
|
||||
; that the engine needs.
|
||||
; Change the patched value to one of BANK_ENTRY, DP_ENTRY, TWO_LYR_ENTRY or ONE_LYR_ENTRY based
|
||||
; on the capabilities that the engine needs.
|
||||
|
||||
lda #DP_ENTRY
|
||||
sta :entryOffset
|
||||
|
|
|
@ -1,121 +0,0 @@
|
|||
; A simple helper function that fills in all of the opcodes of a tile with the PEA opcode. This is
|
||||
; a separate functino because we can often just update the tile data if we know the opcodes are already
|
||||
; set. When we have to fill the opcodes, this function is used
|
||||
_TBFillPEAOpcode
|
||||
sep #$20
|
||||
lda #$F4
|
||||
]line equ 0
|
||||
lup 8
|
||||
sta: $0000+{]line*$1000},y
|
||||
sta: $0003+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rep #$20
|
||||
rts
|
||||
|
||||
; Copy tile data into the direct page compositing buffer. The main reason to do this in full passes is
|
||||
; because we can avoid needing to use both the X and Y registers during the compositing process and
|
||||
; reserve Y to hold the code field address.
|
||||
;
|
||||
; Also, we can get away with not setting the bank register, this is a wash in terms of speed, but results
|
||||
; in simpler, more composable subroutines
|
||||
_TBCopyTileDataAndMaskToCBuff
|
||||
jsr _TBCopyTileDataToCBuff
|
||||
jmp _TBCopyTileMaskToCBuff
|
||||
|
||||
_TBCopyTileDataAndMaskToCBuffV
|
||||
jsr _TBCopyTileDataToCBuffV
|
||||
jmp _TBCopyTileMaskToCBuffV
|
||||
|
||||
_TBCopyTileDataToCBuff
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4},x
|
||||
sta blttmp+{]line*4}
|
||||
|
||||
ldal tiledata+{]line*4}+2,x
|
||||
sta blttmp+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
_TBCopyTileDataToCBuffV
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]src*4},x
|
||||
sta blttmp+{]dest*4}
|
||||
|
||||
ldal tiledata+{]src*4}+2,x
|
||||
sta blttmp+{]dest*4}+2
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
rts
|
||||
|
||||
; Copy tile mask data into the direct page compositing buffer.
|
||||
_TBCopyTileMaskToCBuff
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4}+32,x
|
||||
sta blttmp+{]line*4}+32
|
||||
|
||||
ldal tiledata+{]line*4}+32+2,x
|
||||
sta blttmp+{]line*4}+32+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
_TBCopyTileMaskToCBuffV
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]src*4}+32,x
|
||||
sta blttmp+{]dest*4}+32
|
||||
|
||||
ldal tiledata+{]src*4}+32+2,x
|
||||
sta blttmp+{]dest*4}+32+2
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
rts
|
||||
|
||||
; Tile 0 specializations
|
||||
; _TBConstTile
|
||||
;
|
||||
; A specialized routine that fills in a tile with a single constant value. It's intended to be used to
|
||||
; fill in solid colors, so there are no specialized horizontal or verical flipped variants
|
||||
_TBConstTileX
|
||||
lda #0
|
||||
sta: $0001,y
|
||||
sta: $0004,y
|
||||
sta $1001,y
|
||||
sta $1004,y
|
||||
sta $2001,y
|
||||
sta $2004,y
|
||||
sta $3001,y
|
||||
sta $3004,y
|
||||
sta $4001,y
|
||||
sta $4004,y
|
||||
sta $5001,y
|
||||
sta $5004,y
|
||||
sta $6001,y
|
||||
sta $6004,y
|
||||
sta $7001,y
|
||||
sta $7004,y
|
||||
plb
|
||||
rts
|
||||
|
||||
_TBConstTileSlow0
|
||||
tax
|
||||
jsr _TBFillPEAOpcode
|
||||
jmp _TBConstTileX
|
||||
|
||||
_TBConstTileDataToDP2
|
||||
]line equ 0
|
||||
lup 8
|
||||
stz tmp_tile_data+{]line*4}
|
||||
stz tmp_tile_data+{]line*4}+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
|
@ -1,52 +0,0 @@
|
|||
; _TBSolidTile
|
||||
;
|
||||
; Define the addresses of the subroutines that draw the normal and flipped variants of the tiles, both
|
||||
; in the optimized (no second background) and normal cases.
|
||||
;
|
||||
; On entry, the following register values need to be set
|
||||
;
|
||||
; X : address of base tile in the tiledata bank (tileId * 128)
|
||||
; Y : address of the top-left corder of the tile location in the code field
|
||||
; B : set to the code field bank
|
||||
|
||||
_TBSolidTile_00
|
||||
jsr _TBCopyData
|
||||
jmp _TBFillPEAOpcode
|
||||
|
||||
_TBSolidTile_0H
|
||||
jsr _TBCopyData
|
||||
jmp _TBFillPEAOpcode
|
||||
|
||||
_TBSolidTile_V0
|
||||
jsr _TBCopyDataV
|
||||
jmp _TBFillPEAOpcode
|
||||
|
||||
_TBSolidTile_VH
|
||||
jsr _TBCopyDataV
|
||||
jmp _TBFillPEAOpcode
|
||||
|
||||
; Old routines
|
||||
_TBCopyData
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]line*4},x
|
||||
sta: $0004+{]line*$1000},y
|
||||
ldal tiledata+{]line*4}+2,x
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
_TBCopyDataV
|
||||
]src equ 7
|
||||
]dest equ 0
|
||||
lup 8
|
||||
ldal tiledata+{]src*4},x
|
||||
sta: $0004+{]dest*$1000},y
|
||||
ldal tiledata+{]src*4}+2,x
|
||||
sta: $0001+{]dest*$1000},y
|
||||
]src equ ]src-1
|
||||
]dest equ ]dest+1
|
||||
--^
|
||||
rts
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
; _TBDynamicTile
|
||||
;
|
||||
; These subroutines fill in the code field with the instructions to render data from the dynamic
|
||||
; code buffer. This is a bit different, because no tile data is manipulated. It is the
|
||||
; responsibiliy of the user of the API to use the CopyTileToDyn subroutine to get data
|
||||
; into the correct location.
|
||||
;
|
||||
; This tile type does not explicitly support horizontal or vertical flipping. An appropriate tile
|
||||
; descriptor should be passed into CopyTileToDyn to put the horizontally or vertically flipped source
|
||||
; data into the dynamic tile buffer
|
||||
_TBDynamicTile_00
|
||||
jsr _TBDynamicData
|
||||
jmp _TBFillLdaDpOpcode
|
||||
|
||||
_TBDynamic
|
||||
ldal TileStore+TS_TILE_ID,x
|
||||
and #$007F
|
||||
ora #$4800
|
||||
|
||||
]line equ 0 ; render the first column
|
||||
lup 8
|
||||
sta: $0004+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
inc ; advance to the next word
|
||||
inc
|
||||
|
||||
]line equ 0 ; render the second column
|
||||
lup 8
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
sep #$20
|
||||
lda #$B5
|
||||
sta: $0000,y
|
||||
sta: $0003,y
|
||||
sta $1000,y
|
||||
sta $1003,y
|
||||
sta $2000,y
|
||||
sta $2003,y
|
||||
sta $3000,y
|
||||
sta $3003,y
|
||||
sta $4000,y
|
||||
sta $4003,y
|
||||
sta $5000,y
|
||||
sta $5003,y
|
||||
sta $6000,y
|
||||
sta $6003,y
|
||||
sta $7000,y
|
||||
sta $7003,y
|
||||
rep #$20
|
||||
|
||||
plb
|
||||
rts
|
||||
; Primitive to render a dynamic tile
|
||||
;
|
||||
; LDA 00,x / PHA where the operand is fixed when the tile is rendered
|
||||
; $B5 $00 $48
|
||||
_TBDynamicData
|
||||
lda _TILE_ID ; Get the original tile descriptor
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
ora #$4800 ; insert the PHA instruction
|
||||
|
||||
]line equ 0 ; render the first column
|
||||
lup 8
|
||||
sta: $0004+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
inc ; advance to the next word
|
||||
inc
|
||||
|
||||
]line equ 0 ; render the second column
|
||||
lup 8
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
rts
|
||||
|
||||
; A simple helper function that fill in all of the opcodes of a tile with the LDA dp,x opcode.
|
||||
_TBFillLdaDpOpcode
|
||||
sep #$20
|
||||
lda #$B5
|
||||
sta: $0000,y
|
||||
sta: $0003,y
|
||||
sta $1000,y
|
||||
sta $1003,y
|
||||
sta $2000,y
|
||||
sta $2003,y
|
||||
sta $3000,y
|
||||
sta $3003,y
|
||||
sta $4000,y
|
||||
sta $4003,y
|
||||
sta $5000,y
|
||||
sta $5003,y
|
||||
sta $6000,y
|
||||
sta $6003,y
|
||||
sta $7000,y
|
||||
sta $7003,y
|
||||
rep #$20
|
||||
rts
|
|
@ -1,131 +0,0 @@
|
|||
; _TBMaskedTile
|
||||
;
|
||||
; These tile renderes are for "normal" tiles that also apply their mask data. If the case of the second
|
||||
; background being disabled, the optimized variants are the same as Tile00000
|
||||
;
|
||||
; Y register = address of code field tile
|
||||
; X register = tile address
|
||||
; Accumulator = logical word offset of the tile (0, 2, 4, ..., 82)
|
||||
;
|
||||
; Need to slightly remap these register inputs to save into the direct page cached values
|
||||
_TBMaskedTile_00
|
||||
_TBMaskedTile_0H
|
||||
sta _X_REG ; Save these values as we will need to reload them
|
||||
sty _Y_REG ; at certain points
|
||||
stx _T_PTR
|
||||
|
||||
; Do the left column first
|
||||
|
||||
CopyMaskedWord tiledata+0;tiledata+32+0;$0003
|
||||
CopyMaskedWord tiledata+4;tiledata+32+4;$1003
|
||||
CopyMaskedWord tiledata+8;tiledata+32+8;$2003
|
||||
CopyMaskedWord tiledata+12;tiledata+32+12;$3003
|
||||
CopyMaskedWord tiledata+16;tiledata+32+16;$4003
|
||||
CopyMaskedWord tiledata+20;tiledata+32+20;$5003
|
||||
CopyMaskedWord tiledata+24;tiledata+32+24;$6003
|
||||
CopyMaskedWord tiledata+28;tiledata+32+28;$7003
|
||||
|
||||
; Move the index for the JTableOffset array. This is the same index used for transparent words,
|
||||
; so, if _X_REG is zero, then we would be patching out the last word in the code field with LDA (0),y
|
||||
; and then increment _X_REG by two to patch the next-to-last word in the code field with LDA (2),y
|
||||
|
||||
inc _X_REG
|
||||
inc _X_REG
|
||||
|
||||
; Do the right column
|
||||
|
||||
CopyMaskedWord tiledata+2;tiledata+32+2;$0000
|
||||
CopyMaskedWord tiledata+6;tiledata+32+6;$1000
|
||||
CopyMaskedWord tiledata+10;tiledata+32+10;$2000
|
||||
CopyMaskedWord tiledata+14;tiledata+32+14;$3000
|
||||
CopyMaskedWord tiledata+18;tiledata+32+18;$4000
|
||||
CopyMaskedWord tiledata+22;tiledata+32+22;$5000
|
||||
CopyMaskedWord tiledata+26;tiledata+32+26;$6000
|
||||
CopyMaskedWord tiledata+30;tiledata+32+30;$7000
|
||||
|
||||
rts
|
||||
|
||||
;_TBMaskedTile_0H
|
||||
; sta _X_REG
|
||||
; sty _Y_REG
|
||||
; stx _T_PTR
|
||||
;
|
||||
; CopyMaskedWord tiledata+64+0;tiledata+64+32+0;$0003
|
||||
; CopyMaskedWord tiledata+64+4;tiledata+64+32+4;$1003
|
||||
; CopyMaskedWord tiledata+64+8;tiledata+64+32+8;$2003
|
||||
; CopyMaskedWord tiledata+64+12;tiledata+64+32+12;$3003
|
||||
; CopyMaskedWord tiledata+64+16;tiledata+64+32+16;$4003
|
||||
; CopyMaskedWord tiledata+64+20;tiledata+64+32+20;$5003
|
||||
; CopyMaskedWord tiledata+64+24;tiledata+64+32+24;$6003
|
||||
; CopyMaskedWord tiledata+64+28;tiledata+64+32+28;$7003
|
||||
;
|
||||
; inc _X_REG
|
||||
; inc _X_REG
|
||||
;
|
||||
; CopyMaskedWord tiledata+64+2;tiledata+64+32+2;$0000
|
||||
; CopyMaskedWord tiledata+64+6;tiledata+64+32+6;$1000
|
||||
; CopyMaskedWord tiledata+64+10;tiledata+64+32+10;$2000
|
||||
; CopyMaskedWord tiledata+64+14;tiledata+64+32+14;$3000
|
||||
; CopyMaskedWord tiledata+64+18;tiledata+64+32+18;$4000
|
||||
; CopyMaskedWord tiledata+64+22;tiledata+64+32+22;$5000
|
||||
; CopyMaskedWord tiledata+64+26;tiledata+64+32+26;$6000
|
||||
; CopyMaskedWord tiledata+64+30;tiledata+64+32+30;$7000
|
||||
;
|
||||
; rts
|
||||
|
||||
_TBMaskedTile_V0
|
||||
_TBMaskedTile_VH
|
||||
sta _X_REG
|
||||
sty _Y_REG
|
||||
stx _T_PTR
|
||||
|
||||
CopyMaskedWord tiledata+0;tiledata+32+0;$7003
|
||||
CopyMaskedWord tiledata+4;tiledata+32+4;$6003
|
||||
CopyMaskedWord tiledata+8;tiledata+32+8;$5003
|
||||
CopyMaskedWord tiledata+12;tiledata+32+12;$4003
|
||||
CopyMaskedWord tiledata+16;tiledata+32+16;$3003
|
||||
CopyMaskedWord tiledata+20;tiledata+32+20;$2003
|
||||
CopyMaskedWord tiledata+24;tiledata+32+24;$1003
|
||||
CopyMaskedWord tiledata+28;tiledata+32+28;$0003
|
||||
|
||||
inc _X_REG
|
||||
inc _X_REG
|
||||
|
||||
CopyMaskedWord tiledata+2;tiledata+32+2;$7000
|
||||
CopyMaskedWord tiledata+6;tiledata+32+6;$6000
|
||||
CopyMaskedWord tiledata+10;tiledata+32+10;$5000
|
||||
CopyMaskedWord tiledata+14;tiledata+32+14;$4000
|
||||
CopyMaskedWord tiledata+18;tiledata+32+18;$3000
|
||||
CopyMaskedWord tiledata+22;tiledata+32+22;$2000
|
||||
CopyMaskedWord tiledata+26;tiledata+32+26;$1000
|
||||
CopyMaskedWord tiledata+30;tiledata+32+30;$0000
|
||||
|
||||
rts
|
||||
|
||||
;_TBMaskedTile_VH
|
||||
; sta _X_REG
|
||||
; sty _Y_REG
|
||||
; stx _T_PTR
|
||||
;
|
||||
; CopyMaskedWord tiledata+64+0;tiledata+64+32+0;$7003
|
||||
; CopyMaskedWord tiledata+64+4;tiledata+64+32+4;$6003
|
||||
; CopyMaskedWord tiledata+64+8;tiledata+64+32+8;$5003
|
||||
; CopyMaskedWord tiledata+64+12;tiledata+64+32+12;$4003
|
||||
; CopyMaskedWord tiledata+64+16;tiledata+64+32+16;$3003
|
||||
; CopyMaskedWord tiledata+64+20;tiledata+64+32+20;$2003
|
||||
; CopyMaskedWord tiledata+64+24;tiledata+64+32+24;$1003
|
||||
; CopyMaskedWord tiledata+64+28;tiledata+64+32+28;$0003
|
||||
;
|
||||
; inc _X_REG
|
||||
; inc _X_REG
|
||||
;
|
||||
; CopyMaskedWord tiledata+64+2;tiledata+64+32+2;$7000
|
||||
; CopyMaskedWord tiledata+64+6;tiledata+64+32+6;$6000
|
||||
; CopyMaskedWord tiledata+64+10;tiledata+64+32+10;$5000
|
||||
; CopyMaskedWord tiledata+64+14;tiledata+64+32+14;$4000
|
||||
; CopyMaskedWord tiledata+64+18;tiledata+64+32+18;$3000
|
||||
; CopyMaskedWord tiledata+64+22;tiledata+64+32+22;$2000
|
||||
; CopyMaskedWord tiledata+64+26;tiledata+64+32+26;$1000
|
||||
; CopyMaskedWord tiledata+64+30;tiledata+64+32+30;$0000
|
||||
;
|
||||
; rts
|
|
@ -1,122 +0,0 @@
|
|||
; _TBDynamicMaskTile
|
||||
;
|
||||
; Insert a code sequence to mask the dynamic tile against the background. This is quite a slow process because
|
||||
; every word needs to be handled with a JMP exception; but it looks good!
|
||||
_TBDynamicMaskTile_00
|
||||
jsr _TBDynamicDataAndMask
|
||||
jmp _TBFillJMPOpcode
|
||||
|
||||
; A = dynamic tile id (must be <32)
|
||||
_TBDynamicDataAndMask
|
||||
sta _X_REG ; Cache some column values derived from _X_REG
|
||||
tax
|
||||
ora #$B100 ; Pre-calc the LDA (dp),y opcode + operand
|
||||
xba
|
||||
sta _OP_CACHE
|
||||
|
||||
clc
|
||||
ldal JTableOffset,x ; Get the address offset and add to the base address
|
||||
adc _BASE_ADDR ; of the current code field line
|
||||
sta _JTBL_CACHE
|
||||
|
||||
; We need to do an AND dp|$80,x / ORA dp,x. The opcode values are $35 and $15, respectively.
|
||||
; We pre-calculate the AND opcode with the high bit of the operand set and then, in the macro
|
||||
; perform and EOR #$2080 to covert the opcode and operand in one instruction
|
||||
|
||||
lda _TILE_ID ; Get the original tile descriptor
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
ora #$3580 ; Pre-calc the AND $80,x opcode + operand
|
||||
xba
|
||||
sta _T_PTR ; This is an op to load the dynamic tile data
|
||||
|
||||
CopyMaskedDWord $0003
|
||||
CopyMaskedDWord $1003
|
||||
CopyMaskedDWord $2003
|
||||
CopyMaskedDWord $3003
|
||||
CopyMaskedDWord $4003
|
||||
CopyMaskedDWord $5003
|
||||
CopyMaskedDWord $6003
|
||||
CopyMaskedDWord $7003
|
||||
|
||||
ldx _X_REG
|
||||
clc
|
||||
ldal JTableOffset+2,x ; Get the address offset and add to the base address
|
||||
adc _BASE_ADDR ; of the current code field line
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda _OP_CACHE
|
||||
adc #$0200
|
||||
sta _OP_CACHE
|
||||
lda _T_PTR
|
||||
adc #$0200
|
||||
sta _T_PTR
|
||||
|
||||
CopyMaskedDWord $0000
|
||||
CopyMaskedDWord $1000
|
||||
CopyMaskedDWord $2000
|
||||
CopyMaskedDWord $3000
|
||||
CopyMaskedDWord $4000
|
||||
CopyMaskedDWord $5000
|
||||
CopyMaskedDWord $6000
|
||||
CopyMaskedDWord $7000
|
||||
|
||||
rts
|
||||
|
||||
; A simple helper function that fill in all of the opcodes of a tile with the JMP opcode.
|
||||
_TBFillJMPOpcode
|
||||
sep #$20
|
||||
lda #$4C
|
||||
sta: $0000,y
|
||||
sta: $0003,y
|
||||
sta $1000,y
|
||||
sta $1003,y
|
||||
sta $2000,y
|
||||
sta $2003,y
|
||||
sta $3000,y
|
||||
sta $3003,y
|
||||
sta $4000,y
|
||||
sta $4003,y
|
||||
sta $5000,y
|
||||
sta $5003,y
|
||||
sta $6000,y
|
||||
sta $6003,y
|
||||
sta $7000,y
|
||||
sta $7003,y
|
||||
rep #$20
|
||||
rts
|
||||
|
||||
|
||||
; Masked renderer for a dynamic tile. What's interesting about this renderer is that the mask
|
||||
; value is not used directly, but simply indicates if we can use a LDA 0,x / PHA sequence,
|
||||
; a LDA (00),y / PHA, or a JMP to a blended render
|
||||
;
|
||||
; If a dynamic tile is animated, there is the possibility to create a special mask that marks
|
||||
; words of the tile that a front / back / mixed across all frames.
|
||||
;
|
||||
; ]1 : code field offset
|
||||
;
|
||||
; This macro does not set the opcode since they will all be JMP instructions, they can be
|
||||
; filled more efficiently in a separate routine.
|
||||
CopyMaskedDWord MAC
|
||||
|
||||
; Need to fill in the first 6 bytes of the JMP handler with the following code sequence
|
||||
;
|
||||
; lda (00),y
|
||||
; and $80,x
|
||||
; ora $00,x
|
||||
; bra *+17
|
||||
|
||||
lda _JTBL_CACHE
|
||||
ora #{]1&$F000} ; adjust for the current row offset
|
||||
sta: ]1+1,y
|
||||
|
||||
tax ; This becomes the new address that we use to patch in
|
||||
lda _OP_CACHE
|
||||
sta: $0000,x ; LDA (00),y
|
||||
lda _T_PTR
|
||||
sta: $0002,x ; AND $80,x
|
||||
eor #$8020 ; Switch the opcode to an ORA and remove the high bit of the operand
|
||||
sta: $0004,x ; ORA $00,x
|
||||
lda #$0F80 ; branch to the prologue (BRA *+17)
|
||||
sta: $0006,x
|
||||
eom
|
|
@ -1,6 +0,0 @@
|
|||
; _TBPriorityTile
|
||||
;
|
||||
; The priority bit allows the tile to be rendered in front of sprites. If there's no sprite
|
||||
; in this tile area, then just fallback to the Tile00000.s implementation
|
||||
_TBPriorityTile dw _TBSolidTile_00,_TBSolidTile_0H,_TBSolidTile_V0,_TBSolidTile_VH
|
||||
dw _TBCopyData,_TBCopyDataH,_TBCopyDataV,_TBCopyDataVH
|
|
@ -1,6 +0,0 @@
|
|||
; _TBPriorityDynamicTile
|
||||
;
|
||||
; The priority bit allows the tile to be rendered in front of sprites. If there's no sprite
|
||||
; in this tile area, then just fallback to the Tile00001.s implementation
|
||||
_TBPriorityDynamicTile dw _TBDynamicTile_00,_TBDynamicTile_00,_TBDynamicTile_00,_TBDynamicTile_00
|
||||
dw _TBDynamicTile_00,_TBDynamicTile_00,_TBDynamicTile_00,_TBDynamicTile_00
|
|
@ -1,19 +0,0 @@
|
|||
; _TBMaskedPriorityTile
|
||||
;
|
||||
; The priority bit allows the tile to be rendered in front of sprites. If there's no sprite
|
||||
; in this tile area, then just fallback to the Tile00000.s implementation
|
||||
_TBMaskedPriorityTile dw _TBMaskedTile_00,_TBMaskedTile_0H,_TBMaskedTile_V0,_TBMaskedTile_VH
|
||||
dw _TBCopyData,_TBCopyDataH,_TBCopyDataV,_TBCopyDataVH
|
||||
|
||||
; NOTE: Eventually, we want a way to support this use-case
|
||||
;
|
||||
; When the high-priority bit is set for a tile, then the BG0 tile will be rendered behind the BG1 data. In
|
||||
; order to support this, the optional BG1 mask buffer needs to be enabled and *every* word in the tile
|
||||
; becomes a JMP handler (similar to masked dynamic tiles)
|
||||
;
|
||||
; The 8 bytes of code that is generated in the JMP handler is
|
||||
;
|
||||
; lda #tiledata
|
||||
; and [dp],y
|
||||
; ora (dp),y
|
||||
; nop
|
|
@ -1,99 +0,0 @@
|
|||
; _TBSolidSpriteTile
|
||||
;
|
||||
; Renders solid tiles with sprites layered on top of the tile data. Because we need to combine
|
||||
; data from the sprite plane, tile data and write to the code field (which are all in different banks),
|
||||
; there is no way to do everything inline, so a composite tile is created on the fly and written to
|
||||
; a direct page buffer. This direct page buffer is then used to render the tile.
|
||||
_TBSolidSpriteTile_00
|
||||
_TBSolidSpriteTile_0H
|
||||
jsr _TBCopyTileDataToCBuff ; Copy the tile into the compositing buffer (using correct x-register)
|
||||
jsr _TBApplySpriteData ; Overlay the data from the sprite plane (and copy into the code field)
|
||||
jmp _TBFillPEAOpcode ; Fill in the code field opcodes
|
||||
|
||||
_TBSolidSpriteTile_V0
|
||||
_TBSolidSpriteTile_VH
|
||||
jsr _TBCopyTileDataToCBuffV
|
||||
jsr _TBApplySpriteData
|
||||
jmp _TBFillPEAOpcode
|
||||
|
||||
; Fast variation that does not need to set the opcode
|
||||
_TBFastSpriteTile_00
|
||||
_TBFastSpriteTile_0H
|
||||
jsr _TBCopyTileDataToCBuff ; Copy the tile into the compositing buffer
|
||||
jmp _TBApplySpriteData ; Overlay the data form the sprite plane (and copy into the code field)
|
||||
|
||||
_TBFastSpriteTile_V0
|
||||
_TBFastSpriteTile_VH
|
||||
jsr _TBCopyTileDataToCBuffV
|
||||
jmp _TBApplySpriteData
|
||||
|
||||
; Need to update the X-register before calling this
|
||||
_TBApplySpriteData
|
||||
ldx _SPR_X_REG ; set to the unaligned tile block address in the sprite plane
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda blttmp+{]line*4}
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta: $0004+{]line*$1000},y
|
||||
|
||||
lda blttmp+{]line*4}+2
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
_TBApplySpriteDataOne
|
||||
ldx spriteIdx
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda blttmp+{]line*4}
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta: $0004+{]line*$1000},y
|
||||
|
||||
lda blttmp+{]line*4}+2
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
_TBApplySpriteDataTwo
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda blttmp+{]line*4}
|
||||
ldx spriteIdx+2
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
ldx spriteIdx
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta: $0004+{]line*$1000},y
|
||||
|
||||
lda blttmp+{]line*4}+2
|
||||
ldx spriteIdx+2
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
ldx spriteIdx
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
; Copy just the data into the code field from the composite buffer
|
||||
_TBSolidComposite
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda blttmp+{]line*4}
|
||||
sta: $0004+{]line*$1000},y
|
||||
lda blttmp+{]line*4}+2
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
|
@ -1,211 +0,0 @@
|
|||
; _TBDynamicSpriteTile
|
||||
;
|
||||
; This tile type does not explicitly support horizontal or vertical flipping. An appropriate tile
|
||||
; descriptor should be passed into CopyTileToDyn to put the horizontally or vertically flipped source
|
||||
; data into the dynamic tile buffer
|
||||
_TBDynamicSpriteTile
|
||||
sta _X_REG
|
||||
ldal TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
sta _JTBL_CACHE
|
||||
|
||||
ldal TileStore+TS_TILE_ID,x ; Get the original tile descriptor
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
ora #$B500
|
||||
xba
|
||||
sta _OP_CACHE ; This is the 2-byte opcode for to load the data
|
||||
|
||||
CopyDynWord 0;$0003
|
||||
CopyDynWord 4;$1003
|
||||
CopyDynWord 8;$2003
|
||||
CopyDynWord 12;$3003
|
||||
CopyDynWord 16;$4003
|
||||
CopyDynWord 20;$5003
|
||||
CopyDynWord 24;$6003
|
||||
CopyDynWord 28;$7003
|
||||
|
||||
clc
|
||||
lda _JTBL_CACHE
|
||||
adc #32 ; All the snippets are 32 bytes wide and, since we're
|
||||
sta _JTBL_CACHE ; within one tile, the second column is consecutive
|
||||
|
||||
lda _OP_CACHE
|
||||
adc #$0200 ; Advance to the next word
|
||||
sta _OP_CACHE
|
||||
|
||||
CopyDynWord 2;$0000
|
||||
CopyDynWord 6;$1000
|
||||
CopyDynWord 10;$2000
|
||||
CopyDynWord 14;$3000
|
||||
CopyDynWord 18;$4000
|
||||
CopyDynWord 22;$5000
|
||||
CopyDynWord 26;$6000
|
||||
CopyDynWord 30;$7000
|
||||
|
||||
plb
|
||||
rts
|
||||
|
||||
|
||||
_TBDynamicSpriteTile_00
|
||||
sty _Y_REG ; This is restored in the macro
|
||||
|
||||
sta _X_REG ; Cache some column values derived from _X_REG
|
||||
tax
|
||||
clc
|
||||
ldal JTableOffset,x ; Get the address offset and add to the base address
|
||||
adc _BASE_ADDR ; of the current code field line
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda _TILE_ID ; Get the original tile descriptor
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
ora #$B500
|
||||
xba
|
||||
sta _OP_CACHE ; This is the 2-byte opcode for to load the data
|
||||
|
||||
ldx _SPR_X_REG
|
||||
|
||||
CopyDynSpriteWord {0*SPRITE_PLANE_SPAN};$0003
|
||||
CopyDynSpriteWord {1*SPRITE_PLANE_SPAN};$1003
|
||||
CopyDynSpriteWord {2*SPRITE_PLANE_SPAN};$2003
|
||||
CopyDynSpriteWord {3*SPRITE_PLANE_SPAN};$3003
|
||||
CopyDynSpriteWord {4*SPRITE_PLANE_SPAN};$4003
|
||||
CopyDynSpriteWord {5*SPRITE_PLANE_SPAN};$5003
|
||||
CopyDynSpriteWord {6*SPRITE_PLANE_SPAN};$6003
|
||||
CopyDynSpriteWord {7*SPRITE_PLANE_SPAN};$7003
|
||||
|
||||
ldx _X_REG
|
||||
clc
|
||||
ldal JTableOffset+2,x ; Get the address offset and add to the base address
|
||||
adc _BASE_ADDR ; of the current code field line
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda _OP_CACHE
|
||||
adc #$0200
|
||||
sta _OP_CACHE
|
||||
|
||||
ldx _SPR_X_REG
|
||||
|
||||
CopyDynSpriteWord {0*SPRITE_PLANE_SPAN}+2;$0000
|
||||
CopyDynSpriteWord {1*SPRITE_PLANE_SPAN}+2;$1000
|
||||
CopyDynSpriteWord {2*SPRITE_PLANE_SPAN}+2;$2000
|
||||
CopyDynSpriteWord {3*SPRITE_PLANE_SPAN}+2;$3000
|
||||
CopyDynSpriteWord {4*SPRITE_PLANE_SPAN}+2;$4000
|
||||
CopyDynSpriteWord {5*SPRITE_PLANE_SPAN}+2;$5000
|
||||
CopyDynSpriteWord {6*SPRITE_PLANE_SPAN}+2;$6000
|
||||
CopyDynSpriteWord {7*SPRITE_PLANE_SPAN}+2;$7000
|
||||
|
||||
rts
|
||||
|
||||
; Create a masked render based on data in the direct page temporary buffer
|
||||
;
|
||||
; ]1 : sprite buffer offset
|
||||
; ]2 : code field offset
|
||||
CopyDynWord mac
|
||||
lda tmp_sprite_mask+{]1} ; load the mask value
|
||||
bne mixed ; a non-zero value may be mixed
|
||||
|
||||
; This is a solid word
|
||||
lda #$00F4 ; PEA instruction
|
||||
sta: ]2,y
|
||||
lda tmp_sprite_data+{]1} ; load the sprite data
|
||||
sta: ]2+1,y ; PEA operand
|
||||
bra next
|
||||
|
||||
mixed cmp #$FFFF ; All 1's in the mask is a fully transparent sprite word
|
||||
beq transparent
|
||||
|
||||
lda #$004C ; JMP to handler
|
||||
sta: {]2},y
|
||||
lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
ora #{]2&$F000} ; adjust for the current row offset
|
||||
sta: {]2}+1,y
|
||||
tax ; This becomes the new address that we use to patch in
|
||||
|
||||
lda _OP_CACHE ; Get the LDA dp,x instruction for this column
|
||||
sta: $0000,x
|
||||
|
||||
lda #$0029 ; AND #SPRITE_MASK
|
||||
sta: $0002,x
|
||||
lda tmp_sprite_mask+{]1}
|
||||
sta: $0003,x
|
||||
|
||||
lda #$0009 ; ORA #SPRITE_DATA
|
||||
sta: $0005,x
|
||||
lda tmp_sprite_data+{]1}
|
||||
sta: $0006,x
|
||||
|
||||
lda #$0D80 ; branch to the prologue (BRA *+15)
|
||||
sta: $0008,x
|
||||
bra next
|
||||
|
||||
; This is a transparent word, so just show the dynamic data
|
||||
transparent
|
||||
lda #$4800 ; Put the PHA in the third byte
|
||||
sta: {]2}+1,y
|
||||
lda _OP_CACHE ; Store the LDA dp,x instruction with operand
|
||||
sta: {]2},y
|
||||
next
|
||||
<<<
|
||||
|
||||
; Masked renderer for a dynamic tile with sprite data overlaid.
|
||||
;
|
||||
; ]1 : sprite plane offset
|
||||
; ]2 : code field offset
|
||||
CopyDynSpriteWord MAC
|
||||
|
||||
; Need to fill in the first 10 bytes of the JMP handler with the following code sequence where
|
||||
; the data and mask from from the sprite plane
|
||||
;
|
||||
; lda $00,x
|
||||
; and #MASK
|
||||
; ora #DATA
|
||||
; bra *+15
|
||||
;
|
||||
; If MASK == 0, then we can do a PEA. If MASK == $FFFF, then fall back to the simple Dynamic Tile
|
||||
; code.
|
||||
ldal spritemask+{]1},x ; load the mask value
|
||||
bne mixed ; a non-zero value may be mixed
|
||||
|
||||
; This is a solid word
|
||||
lda #$00F4 ; PEA instruction
|
||||
sta: ]2,y
|
||||
ldal spritedata+{]1},x ; load the sprite data
|
||||
sta: ]2+1,y ; PEA operand
|
||||
bra next
|
||||
|
||||
mixed cmp #$FFFF ; All 1's in the mask is a fully transparent sprite word
|
||||
beq transparent
|
||||
|
||||
lda #$004C ; JMP to handler
|
||||
sta: ]2,y
|
||||
lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
ora #{]2&$F000} ; adjust for the current row offset
|
||||
sta: ]2+1,y
|
||||
tay ; This becomes the new address that we use to patch in
|
||||
|
||||
lda _OP_CACHE ; Get the LDA dp,x instruction for this column
|
||||
sta: $0000,y
|
||||
|
||||
lda #$0029 ; AND #SPRITE_MASK
|
||||
sta: $0002,y
|
||||
ldal spritemask+{]1},x
|
||||
sta: $0003,y
|
||||
|
||||
lda #$0009 ; ORA #SPRITE_DATA
|
||||
sta: $0005,y
|
||||
ldal spritedata+{]1},x
|
||||
sta: $0006,y
|
||||
|
||||
lda #$0D80 ; branch to the prologue (BRA *+15)
|
||||
sta: $0008,y
|
||||
|
||||
ldy _Y_REG ; restore original y-register value and move on
|
||||
bra next
|
||||
|
||||
; This is a transparent word, so just show the dynamic data
|
||||
transparent
|
||||
lda #$4800 ; Put the PHA in the third byte
|
||||
sta: ]2+1,y
|
||||
lda _OP_CACHE ; Store the LDA dp,x instruction with operand
|
||||
sta: ]2,y
|
||||
next
|
||||
eom
|
|
@ -1,88 +0,0 @@
|
|||
; _TBMaskedSpriteTile
|
||||
;
|
||||
; Renders a composited tile with masking to the code field.
|
||||
_TBMaskedSpriteTile_00
|
||||
_TBMaskedSpriteTile_0H
|
||||
sta _X_REG ; Immedately stash the parameters
|
||||
sty _Y_REG
|
||||
|
||||
jsr _TBCopyTileDataToCBuff ; Copy the tile data into the compositing buffer (using correct x-register)
|
||||
jsr _TBCopyTileMaskToCBuff ; Copy the tile mask into the compositing buffer (using correct x-register)
|
||||
jsr _TBMergeSpriteDataAndMask ; Overlay the data and mask from the sprite plane into the compositing buffer
|
||||
jmp _TBMaskedCBuff ; Render the masked tile from the compositing buffer into the code field
|
||||
|
||||
;_TBMaskedSpriteTile_0H
|
||||
; sta _X_REG
|
||||
; sty _Y_REG
|
||||
; jsr _TBCopyTileDataToCBuffH
|
||||
; jsr _TBCopyTileMaskToCBuffH
|
||||
; jsr _TBMergeSpriteDataAndMask
|
||||
; jmp _TBMaskedCBuff
|
||||
|
||||
_TBMaskedSpriteTile_V0
|
||||
_TBMaskedSpriteTile_VH
|
||||
sta _X_REG
|
||||
sty _Y_REG
|
||||
jsr _TBCopyTileDataToCBuffV
|
||||
jsr _TBCopyTileMaskToCBuffV
|
||||
jsr _TBMergeSpriteDataAndMask
|
||||
jmp _TBMaskedCBuff
|
||||
|
||||
;_TBMaskedSpriteTile_VH
|
||||
; sta _X_REG
|
||||
; sty _Y_REG
|
||||
; jsr _TBCopyTileDataToCBuffVH
|
||||
; jsr _TBCopyTileMaskToCBuffVH
|
||||
; jsr _TBMergeSpriteDataAndMask
|
||||
; jmp _TBMaskedCBuff
|
||||
|
||||
_TBMergeSpriteDataAndMask
|
||||
ldx _SPR_X_REG ; set to the unaligned tile block address in the sprite plane
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
lda blttmp+{]line*4}
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
sta blttmp+{]line*4}
|
||||
|
||||
ldal spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
and blttmp+{]line*4}+32
|
||||
sta blttmp+{]line*4}+32
|
||||
|
||||
lda blttmp+{]line*4}+2
|
||||
andl spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
oral spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
sta blttmp+{]line*4}+2
|
||||
|
||||
ldal spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
and blttmp+{]line*4}+32+2
|
||||
sta blttmp+{]line*4}+32+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
||||
|
||||
; See the Tiles00010.s blitter for additional details
|
||||
_TBMaskedCBuff
|
||||
CopyMaskedWordD blttmp+0;$0003
|
||||
CopyMaskedWordD blttmp+4;$1003
|
||||
CopyMaskedWordD blttmp+8;$2003
|
||||
CopyMaskedWordD blttmp+12;$3003
|
||||
CopyMaskedWordD blttmp+16;$4003
|
||||
CopyMaskedWordD blttmp+20;$5003
|
||||
CopyMaskedWordD blttmp+24;$6003
|
||||
CopyMaskedWordD blttmp+28;$7003
|
||||
|
||||
inc _X_REG
|
||||
inc _X_REG
|
||||
|
||||
CopyMaskedWordD blttmp+2;$0000
|
||||
CopyMaskedWordD blttmp+6;$1000
|
||||
CopyMaskedWordD blttmp+10;$2000
|
||||
CopyMaskedWordD blttmp+14;$3000
|
||||
CopyMaskedWordD blttmp+18;$4000
|
||||
CopyMaskedWordD blttmp+22;$5000
|
||||
CopyMaskedWordD blttmp+26;$6000
|
||||
CopyMaskedWordD blttmp+30;$7000
|
||||
|
||||
rts
|
|
@ -1,134 +0,0 @@
|
|||
; _TBDynamicMaskedSpriteTile
|
||||
;
|
||||
; This tile type does not explicitly support horizontal or vertical flipping. An appropriate tile
|
||||
; descriptor should be passed into CopyTileToDyn to put the horizontally or vertically flipped source
|
||||
; data into the dynamic tile buffer
|
||||
;
|
||||
; When rendering, the background, via lda (dp),y, is shown behind the animate sprite
|
||||
_TBDynamicMaskedSpriteTile_00
|
||||
sty _Y_REG ; This is restored in the macro
|
||||
|
||||
sta _X_REG ; Cache some column values derived from _X_REG
|
||||
tax
|
||||
ora #$B100 ; Pre-calc the LDA (dp),y opcode + operand
|
||||
xba
|
||||
sta _OP_CACHE
|
||||
|
||||
clc
|
||||
ldal JTableOffset,x ; Get the address offset and add to the base address
|
||||
adc _BASE_ADDR ; of the current code field line
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda _TILE_ID ; Get the original tile descriptor
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
ora #$3580 ; Pre-calc the AND $80,x opcode + operand
|
||||
xba
|
||||
sta _T_PTR ; This is an op to load the dynamic tile data
|
||||
|
||||
ldx _SPR_X_REG
|
||||
|
||||
CopyDynMaskedSpriteWord {0*SPRITE_PLANE_SPAN};$0003
|
||||
CopyDynMaskedSpriteWord {1*SPRITE_PLANE_SPAN};$1003
|
||||
CopyDynMaskedSpriteWord {2*SPRITE_PLANE_SPAN};$2003
|
||||
CopyDynMaskedSpriteWord {3*SPRITE_PLANE_SPAN};$3003
|
||||
CopyDynMaskedSpriteWord {4*SPRITE_PLANE_SPAN};$4003
|
||||
CopyDynMaskedSpriteWord {5*SPRITE_PLANE_SPAN};$5003
|
||||
CopyDynMaskedSpriteWord {6*SPRITE_PLANE_SPAN};$6003
|
||||
CopyDynMaskedSpriteWord {7*SPRITE_PLANE_SPAN};$7003
|
||||
|
||||
ldx _X_REG
|
||||
clc
|
||||
ldal JTableOffset+2,x ; Get the address offset and add to the base address
|
||||
adc _BASE_ADDR ; of the current code field line
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda _OP_CACHE
|
||||
adc #$0200
|
||||
sta _OP_CACHE
|
||||
lda _T_PTR
|
||||
adc #$0200
|
||||
sta _T_PTR
|
||||
|
||||
ldx _SPR_X_REG
|
||||
|
||||
CopyDynMaskedSpriteWord {0*SPRITE_PLANE_SPAN}+2;$0000
|
||||
CopyDynMaskedSpriteWord {1*SPRITE_PLANE_SPAN}+2;$1000
|
||||
CopyDynMaskedSpriteWord {2*SPRITE_PLANE_SPAN}+2;$2000
|
||||
CopyDynMaskedSpriteWord {3*SPRITE_PLANE_SPAN}+2;$3000
|
||||
CopyDynMaskedSpriteWord {4*SPRITE_PLANE_SPAN}+2;$4000
|
||||
CopyDynMaskedSpriteWord {5*SPRITE_PLANE_SPAN}+2;$5000
|
||||
CopyDynMaskedSpriteWord {6*SPRITE_PLANE_SPAN}+2;$6000
|
||||
CopyDynMaskedSpriteWord {7*SPRITE_PLANE_SPAN}+2;$7000
|
||||
|
||||
rts
|
||||
|
||||
|
||||
; Masked renderer for a masked dynamic tile with sprite data overlaid.
|
||||
;
|
||||
; ]1 : sprite plane offset
|
||||
; ]2 : code field offset
|
||||
CopyDynMaskedSpriteWord MAC
|
||||
|
||||
; Need to fill in the first 14 bytes of the JMP handler with the following code sequence where
|
||||
; the data and mask from from the sprite plane
|
||||
;
|
||||
; lda ($00),y
|
||||
; and $80,x
|
||||
; ora $00,x
|
||||
; and #MASK
|
||||
; ora #DATA
|
||||
; bra *+15
|
||||
;
|
||||
; If MASK == 0, then we can do a PEA. If MASK == $FFFF, then fall back to the simple Dynamic Tile
|
||||
; code and eliminate the constanct AND/ORA instructions.
|
||||
|
||||
ldal spritemask+{]1},x ; load the mask value
|
||||
bne mixed ; a non-zero value may be mixed
|
||||
|
||||
; This is a solid word
|
||||
lda #$00F4 ; PEA instruction
|
||||
sta: ]2,y
|
||||
ldal spritedata+{]1},x ; load the sprite data
|
||||
sta: ]2+1,y ; PEA operand
|
||||
bra next
|
||||
|
||||
; We will always do a JMP to the eception handler, so set that up, then check for sprite
|
||||
; transparency
|
||||
mixed
|
||||
lda #$004C ; JMP to handler
|
||||
sta: ]2,y
|
||||
lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
ora #{]2&$F000} ; adjust for the current row offset
|
||||
sta: {]2}+1,y
|
||||
tay ; This becomes the new address that we use to patch in
|
||||
|
||||
lda _OP_CACHE
|
||||
sta: $0000,y ; LDA (00),y
|
||||
lda _T_PTR
|
||||
sta: $0002,y ; AND $80,x
|
||||
eor #$8020 ; Switch the opcode to an ORA and remove the high bit of the operand
|
||||
sta: $0004,y ; ORA $00,x
|
||||
|
||||
lda #$0029 ; AND #SPRITE_MASK
|
||||
sta: $0006,y
|
||||
ldal spritemask+{]1},x
|
||||
cmp #$FFFF ; All 1's in the mask is a fully transparent sprite word
|
||||
beq transparent ; so we can use the Tile00011 method
|
||||
sta: $0007,y
|
||||
|
||||
lda #$0009 ; ORA #SPRITE_DATA
|
||||
sta: $0009,y
|
||||
ldal spritedata+{]1},x
|
||||
sta: $000A,y
|
||||
|
||||
lda #$0980 ; branch to the prologue (BRA *+11)
|
||||
sta: $000C,y
|
||||
bra next
|
||||
|
||||
; This is a transparent word, so just show the dynamic data
|
||||
transparent
|
||||
lda #$0F80 ; branch to the epilogue (BRA *+17)
|
||||
sta: $0006,y
|
||||
next
|
||||
ldy _Y_REG ; restore original y-register value and move on
|
||||
eom
|
|
@ -1,50 +0,0 @@
|
|||
; _TBSolidPrioritySpriteTile
|
||||
;
|
||||
; When the sprite is composited with the tile data, the tile mask is used to place the tile data on top of
|
||||
; any sprite data
|
||||
_TBSolidPrioritySpriteTile_00
|
||||
_TBSolidPrioritySpriteTile_0H
|
||||
jsr _TBCopyTileDataToCBuff ; Copy the tile data into the compositing buffer (using correct x-register)
|
||||
jsr _TBCopyTileMaskToCBuff ; Copy the tile mask into the compositing buffer (using correct x-register)
|
||||
jsr _TBApplyPrioritySpriteData ; Underlay the data fromthe sprite plane (and copy into the code field)
|
||||
jmp _TBFillPEAOpcode ; Fill in the code field opcodes
|
||||
|
||||
;_TBSolidPrioritySpriteTile_0H
|
||||
; jsr _TBCopyTileDataToCBuffH
|
||||
; jsr _TBCopyTileMaskToCBuffH
|
||||
; jsr _TBApplyPrioritySpriteData
|
||||
; jmp _TBFillPEAOpcode
|
||||
|
||||
_TBSolidPrioritySpriteTile_V0
|
||||
_TBSolidPrioritySpriteTile_VH
|
||||
jsr _TBCopyTileDataToCBuffV
|
||||
jsr _TBCopyTileMaskToCBuffV
|
||||
jsr _TBApplyPrioritySpriteData
|
||||
jmp _TBFillPEAOpcode
|
||||
|
||||
;_TBSolidPrioritySpriteTile_VH
|
||||
; jsr _TBCopyTileDataToCBuffVH
|
||||
; jsr _TBCopyTileMaskToCBuffVH
|
||||
; jsr _TBApplyPrioritySpriteData
|
||||
; jmp _TBFillPEAOpcode
|
||||
|
||||
; Need to update the X-register before calling this
|
||||
_TBApplyPrioritySpriteData
|
||||
ldx _SPR_X_REG ; set to the unaligned tile block address in the sprite plane
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
and blttmp+{]line*4}+32
|
||||
ora blttmp+{]line*4}
|
||||
sta: $0004+{]line*$1000},y
|
||||
|
||||
ldal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
and blttmp+{]line*4}+32+2
|
||||
ora blttmp+{]line*4}+2
|
||||
sta: $0001+{]line*$1000},y
|
||||
]line equ ]line+1
|
||||
--^
|
||||
|
||||
ldx _X_REG ; restore the original value
|
||||
rts
|
|
@ -1,92 +0,0 @@
|
|||
; _TBDynamicPrioritySpriteTile
|
||||
;
|
||||
; Variant of _TBDynamicSpriteTile (Tile10001), but draw the sprite data behind the dynamic tile
|
||||
_TBDynamicPrioritySpriteTile_00
|
||||
jsr _TBDynamicPriorityDataAndMask
|
||||
jmp _TBFillJMPOpcode
|
||||
|
||||
_TBDynamicPriorityDataAndMask
|
||||
sty _Y_REG ; This is restored in the macro
|
||||
|
||||
sta _X_REG ; Cache some column values derived from _X_REG
|
||||
tax
|
||||
clc
|
||||
ldal JTableOffset,x ; Get the address offset and add to the base address
|
||||
adc _BASE_ADDR ; of the current code field line
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda _TILE_ID ; Get the original tile descriptor
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
ora #$3580 ; Pre-calc the AND $80,x opcode + operand
|
||||
xba
|
||||
sta _OP_CACHE ; This is an op to load the dynamic tile data
|
||||
|
||||
ldx _SPR_X_REG
|
||||
|
||||
CopyDynPriSpriteWord {0*SPRITE_PLANE_SPAN};$0003
|
||||
CopyDynPriSpriteWord {1*SPRITE_PLANE_SPAN};$1003
|
||||
CopyDynPriSpriteWord {2*SPRITE_PLANE_SPAN};$2003
|
||||
CopyDynPriSpriteWord {3*SPRITE_PLANE_SPAN};$3003
|
||||
CopyDynPriSpriteWord {4*SPRITE_PLANE_SPAN};$4003
|
||||
CopyDynPriSpriteWord {5*SPRITE_PLANE_SPAN};$5003
|
||||
CopyDynPriSpriteWord {6*SPRITE_PLANE_SPAN};$6003
|
||||
CopyDynPriSpriteWord {7*SPRITE_PLANE_SPAN};$7003
|
||||
|
||||
ldx _X_REG
|
||||
clc
|
||||
ldal JTableOffset+2,x ; Get the address offset and add to the base address
|
||||
adc _BASE_ADDR ; of the current code field line
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda _OP_CACHE
|
||||
adc #$0200
|
||||
sta _OP_CACHE
|
||||
|
||||
ldx _SPR_X_REG
|
||||
|
||||
CopyDynPriSpriteWord {0*SPRITE_PLANE_SPAN}+2;$0000
|
||||
CopyDynPriSpriteWord {1*SPRITE_PLANE_SPAN}+2;$1000
|
||||
CopyDynPriSpriteWord {2*SPRITE_PLANE_SPAN}+2;$2000
|
||||
CopyDynPriSpriteWord {3*SPRITE_PLANE_SPAN}+2;$3000
|
||||
CopyDynPriSpriteWord {4*SPRITE_PLANE_SPAN}+2;$4000
|
||||
CopyDynPriSpriteWord {5*SPRITE_PLANE_SPAN}+2;$5000
|
||||
CopyDynPriSpriteWord {6*SPRITE_PLANE_SPAN}+2;$6000
|
||||
CopyDynPriSpriteWord {7*SPRITE_PLANE_SPAN}+2;$7000
|
||||
|
||||
rts
|
||||
|
||||
|
||||
; Masked renderer for a dynamic tile with sprite data overlaid.
|
||||
;
|
||||
; ]1 : sprite plane offset
|
||||
; ]2 : code field offset
|
||||
CopyDynPriSpriteWord MAC
|
||||
|
||||
; Need to fill in the first 9 bytes of the JMP handler with the following code sequence where
|
||||
; the data and mask from from the sprite plane
|
||||
;
|
||||
; lda #DATA
|
||||
; and $80,x
|
||||
; ora $00,x
|
||||
; bra *+16
|
||||
|
||||
lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
ora #{]2&$F000} ; adjust for the current row offset
|
||||
sta: ]2+1,y
|
||||
tay ; This becomes the new address that we use to patch in
|
||||
|
||||
lda #$00A9 ; LDA #DATA
|
||||
sta: $0000,y
|
||||
ldal spritedata+{]1},x
|
||||
sta: $0001,y
|
||||
|
||||
lda _OP_CACHE
|
||||
sta: $0003,y ; AND $80,x
|
||||
eor #$8020 ; Switch the opcode to an ORA and remove the high bit of the operand
|
||||
sta: $0005,y ; ORA $00,x
|
||||
|
||||
lda #$0E80 ; branch to the prologue (BRA *+16)
|
||||
sta: $0007,y
|
||||
|
||||
ldy _Y_REG ; restore original y-register value and move on
|
||||
eom
|
|
@ -1,63 +0,0 @@
|
|||
; _TBMaskedPrioritySpriteTile
|
||||
;
|
||||
; Renders a composited tile with masking to the code field. The sprite is underlaid
|
||||
_TBMaskedPrioritySpriteTile_00
|
||||
_TBMaskedPrioritySpriteTile_0H
|
||||
sta _X_REG ; Immedately stash the parameters
|
||||
sty _Y_REG
|
||||
|
||||
jsr _TBCopyTileDataToCBuff ; Copy the tile data into the compositing buffer (using correct x-register)
|
||||
jsr _TBCopyTileMaskToCBuff ; Copy the tile mask into the compositing buffer (using correct x-register)
|
||||
jsr _TBUnderlaySpriteDataAndMask ; Underlay the data and mask from the sprite plane into the compositing buffer
|
||||
jmp _TBMaskedCBuff ; Render the masked tile from the compositing buffer into the code field
|
||||
|
||||
;_TBMaskedPrioritySpriteTile_0H
|
||||
; sta _X_REG
|
||||
; sty _Y_REG
|
||||
; jsr _TBCopyTileDataToCBuffH
|
||||
; jsr _TBCopyTileMaskToCBuffH
|
||||
; jsr _TBUnderlaySpriteDataAndMask
|
||||
; jmp _TBMaskedCBuff
|
||||
|
||||
_TBMaskedPrioritySpriteTile_V0
|
||||
_TBMaskedPrioritySpriteTile_VH
|
||||
sta _X_REG
|
||||
sty _Y_REG
|
||||
jsr _TBCopyTileDataToCBuffV
|
||||
jsr _TBCopyTileMaskToCBuffV
|
||||
jsr _TBUnderlaySpriteDataAndMask
|
||||
jmp _TBMaskedCBuff
|
||||
|
||||
;_TBMaskedPrioritySpriteTile_VH
|
||||
; sta _X_REG
|
||||
; sty _Y_REG
|
||||
; jsr _TBCopyTileDataToCBuffVH
|
||||
; jsr _TBCopyTileMaskToCBuffVH
|
||||
; jsr _TBUnderlaySpriteDataAndMask
|
||||
; jmp _TBMaskedCBuff
|
||||
|
||||
_TBUnderlaySpriteDataAndMask
|
||||
ldx _SPR_X_REG ; set to the unaligned tile block address in the sprite plane
|
||||
|
||||
]line equ 0
|
||||
lup 8
|
||||
ldal spritedata+{]line*SPRITE_PLANE_SPAN},x
|
||||
and blttmp+{]line*4}+32
|
||||
ora blttmp+{]line*4} ; Maybe this can be a TSB???
|
||||
sta blttmp+{]line*4}
|
||||
|
||||
ldal spritemask+{]line*SPRITE_PLANE_SPAN},x
|
||||
and blttmp+{]line*4}+32
|
||||
sta blttmp+{]line*4}+32
|
||||
|
||||
ldal spritedata+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
and blttmp+{]line*4}+32+2
|
||||
ora blttmp+{]line*4}+2
|
||||
sta blttmp+{]line*4}+2
|
||||
|
||||
ldal spritemask+{]line*SPRITE_PLANE_SPAN}+2,x
|
||||
and blttmp+{]line*4}+32+2
|
||||
sta blttmp+{]line*4}+32+2
|
||||
]line equ ]line+1
|
||||
--^
|
||||
rts
|
|
@ -1,123 +0,0 @@
|
|||
; _TBDynamicMaskedPrioritySpriteTile
|
||||
;
|
||||
; This tile type does not explicitly support horizontal or vertical flipping. An appropriate tile
|
||||
; descriptor should be passed into CopyTileToDyn to put the horizontally or vertically flipped source
|
||||
; data into the dynamic tile buffer
|
||||
_TBDynamicMaskedPrioritySpriteTile_00
|
||||
sty _Y_REG ; This is restored in the macro
|
||||
|
||||
sta _X_REG ; Cache some column values derived from _X_REG
|
||||
tax
|
||||
ora #$B100 ; Pre-calc the LDA (dp),y opcode + operand
|
||||
xba
|
||||
sta _OP_CACHE
|
||||
|
||||
clc
|
||||
ldal JTableOffset,x ; Get the address offset and add to the base address
|
||||
adc _BASE_ADDR ; of the current code field line
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda _TILE_ID ; Get the original tile descriptor
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
ora #$3580 ; Pre-calc the AND $80,x opcode + operand
|
||||
xba
|
||||
sta _T_PTR ; This is an op to load the dynamic tile data
|
||||
|
||||
ldx _SPR_X_REG
|
||||
|
||||
CopyDynPrioMaskedSpriteWord {0*SPRITE_PLANE_SPAN};$0003
|
||||
CopyDynPrioMaskedSpriteWord {1*SPRITE_PLANE_SPAN};$1003
|
||||
CopyDynPrioMaskedSpriteWord {2*SPRITE_PLANE_SPAN};$2003
|
||||
CopyDynPrioMaskedSpriteWord {3*SPRITE_PLANE_SPAN};$3003
|
||||
CopyDynPrioMaskedSpriteWord {4*SPRITE_PLANE_SPAN};$4003
|
||||
CopyDynPrioMaskedSpriteWord {5*SPRITE_PLANE_SPAN};$5003
|
||||
CopyDynPrioMaskedSpriteWord {6*SPRITE_PLANE_SPAN};$6003
|
||||
CopyDynPrioMaskedSpriteWord {7*SPRITE_PLANE_SPAN};$7003
|
||||
|
||||
ldx _X_REG
|
||||
clc
|
||||
ldal JTableOffset+2,x ; Get the address offset and add to the base address
|
||||
adc _BASE_ADDR ; of the current code field line
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda _OP_CACHE
|
||||
adc #$0200
|
||||
sta _OP_CACHE
|
||||
lda _T_PTR
|
||||
adc #$0200
|
||||
sta _T_PTR
|
||||
|
||||
ldx _SPR_X_REG
|
||||
|
||||
CopyDynPrioMaskedSpriteWord {0*SPRITE_PLANE_SPAN}+2;$0000
|
||||
CopyDynPrioMaskedSpriteWord {1*SPRITE_PLANE_SPAN}+2;$1000
|
||||
CopyDynPrioMaskedSpriteWord {2*SPRITE_PLANE_SPAN}+2;$2000
|
||||
CopyDynPrioMaskedSpriteWord {3*SPRITE_PLANE_SPAN}+2;$3000
|
||||
CopyDynPrioMaskedSpriteWord {4*SPRITE_PLANE_SPAN}+2;$4000
|
||||
CopyDynPrioMaskedSpriteWord {5*SPRITE_PLANE_SPAN}+2;$5000
|
||||
CopyDynPrioMaskedSpriteWord {6*SPRITE_PLANE_SPAN}+2;$6000
|
||||
CopyDynPrioMaskedSpriteWord {7*SPRITE_PLANE_SPAN}+2;$7000
|
||||
|
||||
rts
|
||||
|
||||
|
||||
; Masked renderer for a masked dynamic tile with sprite data underlaid.
|
||||
;
|
||||
; ]1 : sprite plane offset
|
||||
; ]2 : code field offset
|
||||
CopyDynPrioMaskedSpriteWord MAC
|
||||
|
||||
; Need to fill in the first 14 bytes of the JMP handler with the following code sequence where
|
||||
; the data and mask from from the sprite plane
|
||||
;
|
||||
; lda ($00),y
|
||||
; and #MASK
|
||||
; ora #DATA
|
||||
; and $80,x
|
||||
; ora $00,x
|
||||
; bra *+15
|
||||
|
||||
lda #$004C ; JMP to handler
|
||||
sta: ]2,y
|
||||
lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
ora #{]2&$F000} ; adjust for the current row offset
|
||||
sta: ]2+1,y
|
||||
tay ; This becomes the new address that we use to patch in
|
||||
|
||||
lda _OP_CACHE
|
||||
sta: $0000,y ; LDA (00),y
|
||||
|
||||
lda #$0029 ; AND #SPRITE_MASK
|
||||
sta: $0002,y
|
||||
|
||||
ldal spritemask+{]1},x
|
||||
cmp #$FFFF ; All 1's in the mask is a fully transparent sprite word
|
||||
beq transparent ; so we can use the Tile00011 method
|
||||
sta: $0003,y
|
||||
|
||||
lda #$0009 ; ORA #SPRITE_DATA
|
||||
sta: $0005,y
|
||||
ldal spritedata+{]1},x
|
||||
sta: $0006,y
|
||||
|
||||
lda _T_PTR
|
||||
sta: $0008,y ; AND $80,x
|
||||
eor #$8020 ; Switch the opcode to an ORA and remove the high bit of the operand
|
||||
sta: $000A,y ; ORA $00,x
|
||||
|
||||
lda #$0980 ; branch to the prologue (BRA *+11)
|
||||
sta: $000C,y
|
||||
bra next
|
||||
|
||||
; This is a transparent word, so just show the dynamic data
|
||||
transparent
|
||||
lda _T_PTR
|
||||
sta: $0002,y ; AND $80,x
|
||||
eor #$8020 ; Switch the opcode to an ORA and remove the high bit of the operand
|
||||
sta: $0004,y ; ORA $00,x
|
||||
|
||||
lda #$0F80 ; branch to the epilogue (BRA *+17)
|
||||
sta: $0006,y
|
||||
next
|
||||
ldy _Y_REG ; restore original y-register value and move on
|
||||
eom
|
|
@ -5,31 +5,38 @@
|
|||
; Based on the current value of StartY in the direct page. Set up the dispatch
|
||||
; information so that the BltRange driver will render the correct code field
|
||||
; lines in the correct order
|
||||
_ApplyBG0YPos
|
||||
_ApplyBG0YPosOld
|
||||
|
||||
:rtbl_idx equ tmp0
|
||||
:virt_line equ tmp1
|
||||
:lines_left equ tmp2
|
||||
:draw_count equ tmp3
|
||||
:rtbl_idx_x2 equ tmp0
|
||||
:virt_line_x2 equ tmp1
|
||||
:lines_left_x2 equ tmp2
|
||||
:draw_count_x2 equ tmp3
|
||||
:stk_save equ tmp4
|
||||
|
||||
; First task is to fill in the STK_ADDR values by copying them from the RTable array. We
|
||||
; copy from RTable[i] into BlitField[StartY+i]. As with all of this code, the difficult part
|
||||
; is decomposing the update across banks
|
||||
|
||||
stz :rtbl_idx ; Start copying from the first entry in the table
|
||||
stz :rtbl_idx_x2 ; Start copying from the first entry in the table
|
||||
|
||||
lda StartY ; This is the base line of the virtual screen
|
||||
jsr Mod208
|
||||
sta StartYMod208
|
||||
|
||||
sta :virt_line ; Keep track of it
|
||||
asl
|
||||
sta :virt_line_x2 ; Keep track of it
|
||||
|
||||
phb ; Save the current bank
|
||||
tsc ; we intentionally leak one byte of stack in each loop
|
||||
sta :stk_save ; iteration, so save the stack to repair at the end
|
||||
|
||||
; copy a range of address from the table into the destination bank. If we restrict ourselves to
|
||||
; rectangular playfields, this can be optimized to just subtracting a constant value. See the
|
||||
; Templates::SetScreenAddrs subroutine.
|
||||
|
||||
lda ScreenHeight
|
||||
sta :lines_left
|
||||
asl
|
||||
sta :lines_left_x2
|
||||
|
||||
; This is the verbose part -- figure out how many lines to draw. We don't want to artificially limit
|
||||
; the height of the visible screen (for example, doing an animated wipe while scrolling), so the screen
|
||||
|
@ -38,137 +45,280 @@ _ApplyBG0YPos
|
|||
; For larger values, we want to break things up on 16-line boundaries based on the virt_line value. So,
|
||||
;
|
||||
; draw_count = min(lines_left, (16 - (virt_line % 16))
|
||||
;
|
||||
; Note that almost everything in this loop can be done with 8-bit operations sincc the values are
|
||||
; all under 200. The one exception is the virt_line value which could exceed 256. This will be
|
||||
; a later optimization and might save around 10 cycles per iteration, or up to ~120 cycles per frame
|
||||
; and ~2,500 per secord. This is ~1% of our total CPU budget and is *just* enough cycles to be
|
||||
; interesting.... Another 8 cycles could be removed by doing all calculatinos pre-multiplied by 2
|
||||
; to avoid several 'asl' instructions
|
||||
phb
|
||||
|
||||
:loop
|
||||
lda :virt_line
|
||||
asl
|
||||
tax
|
||||
ldx :virt_line_x2
|
||||
ldal BTableLow,x ; Get the address of the first code field line
|
||||
tay
|
||||
|
||||
sep #$20
|
||||
ldal BTableHigh,x
|
||||
ldal BTableHigh,x ; Target bank in low byte
|
||||
pha
|
||||
plb ; This is the bank that will receive the updates
|
||||
rep #$20
|
||||
|
||||
lda :virt_line
|
||||
and #$000F
|
||||
txa
|
||||
and #$001E
|
||||
eor #$FFFF
|
||||
inc
|
||||
clc
|
||||
adc #16
|
||||
min :lines_left
|
||||
sec
|
||||
adc #32
|
||||
min :lines_left_x2
|
||||
|
||||
sta :draw_count ; Do this many lines
|
||||
asl
|
||||
sta :draw_count_x2 ; Do this many lines
|
||||
tax
|
||||
|
||||
lda :rtbl_idx ; Read from this location in the RTable
|
||||
asl
|
||||
clc ; pre-advance virt_line_2 because we have the value
|
||||
adc :virt_line_x2
|
||||
sta :virt_line_x2
|
||||
|
||||
jsr CopyRTableToStkAddr
|
||||
plb
|
||||
jsr _CopyRTableToStkAddr
|
||||
; CopyRTableToStkAddr :rtbl_idx_x2 ; X = rtbl_idx_x2 on return
|
||||
|
||||
lda :virt_line ; advance to the virtual line after the segment we just
|
||||
clc ; filled in
|
||||
adc :draw_count
|
||||
sta :virt_line
|
||||
txa ; carry flag is unchanged
|
||||
adc :draw_count_x2 ; advance the index into the RTable
|
||||
sta :rtbl_idx_x2
|
||||
|
||||
lda :rtbl_idx ; advance the index into the RTable
|
||||
adc :draw_count
|
||||
sta :rtbl_idx
|
||||
|
||||
lda :lines_left ; subtract the number of lines we just completed
|
||||
lda :lines_left_x2 ; subtract the number of lines we just completed
|
||||
sec
|
||||
sbc :draw_count
|
||||
sta :lines_left
|
||||
sbc :draw_count_x2
|
||||
sta :lines_left_x2
|
||||
|
||||
jne :loop
|
||||
plb
|
||||
|
||||
:out
|
||||
lda :stk_save
|
||||
tcs
|
||||
plb
|
||||
rts
|
||||
|
||||
; This is an optimized version of _ApplyBG0YPos. We pre-compute the breakdown across the bank
|
||||
; boundries in order to eliminate the the minimum calculation and some loop variable updates
|
||||
; from the inner loop.
|
||||
|
||||
_ApplyBG0YPos
|
||||
|
||||
:rtbl_idx_x2 equ tmp0
|
||||
:virt_line_x2 equ tmp1
|
||||
:lines_left_x2 equ tmp2
|
||||
:draw_count_x2 equ tmp3
|
||||
:stk_save equ tmp4
|
||||
:line_count equ tmp5
|
||||
|
||||
; First task is to fill in the STK_ADDR values by copying them from the RTable array. We
|
||||
; copy from RTable[i] into BlitField[StartY+i]. As with all of this code, the difficult part
|
||||
; is decomposing the update across banks
|
||||
|
||||
stz :rtbl_idx_x2 ; Start copying from the first entry in the table
|
||||
|
||||
lda StartY ; This is the base line of the virtual screen
|
||||
jsr Mod208
|
||||
sta StartYMod208
|
||||
|
||||
asl
|
||||
sta :virt_line_x2 ; Keep track of it
|
||||
|
||||
phb ; Save the current bank
|
||||
tsc ; we intentionally leak one byte of stack in each loop
|
||||
sta :stk_save ; iteration, so save the stack to repair at the end
|
||||
|
||||
; copy a range of address from the table into the destination bank. If we restrict ourselves to
|
||||
; rectangular playfields, this can be optimized to just subtracting a constant value. See the
|
||||
; Templates::SetScreenAddrs subroutine.
|
||||
|
||||
lda ScreenHeight
|
||||
asl
|
||||
sta :lines_left_x2
|
||||
|
||||
; This is the verbose part -- figure out how many lines to draw. We don't want to artificially limit
|
||||
; the height of the visible screen (for example, doing an animated wipe while scrolling), so the screen
|
||||
; height could be anything from 1 to 200.
|
||||
;
|
||||
; For larger values, we want to break things up on 16-line boundaries based on the virt_line value. So,
|
||||
;
|
||||
; draw_count = min(lines_left, (16 - (virt_line % 16))
|
||||
|
||||
; Pre-loop: Calculate the number of lines to copy to get the loop into a bank-aligned state
|
||||
;
|
||||
; lines_in_bank = 16 - (virt_line % 16)
|
||||
:pre
|
||||
ldx :virt_line_x2
|
||||
ldal BTableLow,x ; Get the address of the first code field line
|
||||
tay
|
||||
|
||||
ldal BTableHigh,x ; Target bank in low byte
|
||||
pha
|
||||
|
||||
txa
|
||||
and #$001E
|
||||
eor #$FFFF
|
||||
sec
|
||||
adc #32
|
||||
min :lines_left_x2
|
||||
|
||||
sta :draw_count_x2 ; Do this many lines
|
||||
tax
|
||||
|
||||
clc ; pre-advance virt_line_2 because we have the value
|
||||
adc :virt_line_x2
|
||||
sta :virt_line_x2
|
||||
|
||||
plb
|
||||
jsr _CopyRTableToStkAddr
|
||||
|
||||
txa ; carry flag is unchanged
|
||||
adc :draw_count_x2 ; advance the index into the RTable
|
||||
sta :rtbl_idx_x2
|
||||
|
||||
lda :lines_left_x2 ; subtract the number of lines we just completed
|
||||
sec
|
||||
sbc :draw_count_x2
|
||||
sta :lines_left_x2
|
||||
|
||||
jeq :done ; if there are no lines left, we're done!
|
||||
cmp #33
|
||||
jcc :post ; if there are 16 lines or less left, jump to post
|
||||
|
||||
; Now we are in the main loop. We know that the virt_line is a multiple of 16, but the number
|
||||
; of remaining lines could be any number greater than 0. we test to see if the lines_left are
|
||||
; less than 16. If so, we can jump straight to the post-loop update. Otherwise we caculate
|
||||
; the number of 16-line iterations and but that in an auxiliary count variable and simplify
|
||||
; the loop update.
|
||||
|
||||
tax
|
||||
and #$001E ; this is the number of lines in post
|
||||
sta :lines_left_x2
|
||||
txa
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
sta :line_count ; single byte count, saves 9 cycles per loop iteration
|
||||
|
||||
:loop
|
||||
ldx :virt_line_x2
|
||||
ldal BTableLow,x ; Get the address of the first code field line
|
||||
tay
|
||||
|
||||
ldal BTableHigh,x ; Target bank in low byte
|
||||
pha
|
||||
|
||||
lda #32 ; Do this many lines (x2)
|
||||
tax
|
||||
|
||||
clc ; pre-advance virt_line_2 because we have the value
|
||||
adc :virt_line_x2
|
||||
sta :virt_line_x2
|
||||
|
||||
plb
|
||||
CopyRTableToStkAddr :rtbl_idx_x2
|
||||
|
||||
txa ; carry flag is unchanged
|
||||
adc #32 ; advance the index into the RTable
|
||||
sta :rtbl_idx_x2
|
||||
|
||||
dec :line_count
|
||||
jne :loop
|
||||
|
||||
lda :lines_left_x2
|
||||
beq :done
|
||||
|
||||
; Draw some number of lines that are less that 16. No need to update loop variabls because we
|
||||
; know we are in the last iteration
|
||||
|
||||
:post
|
||||
ldx :virt_line_x2
|
||||
ldal BTableLow,x ; Get the address of the first code field line
|
||||
tay
|
||||
|
||||
ldal BTableHigh,x ; Target bank in low byte
|
||||
pha
|
||||
|
||||
ldx :lines_left_x2 ; Do this many lines
|
||||
plb
|
||||
jsr _CopyRTableToStkAddr
|
||||
|
||||
:done
|
||||
lda :stk_save
|
||||
tcs
|
||||
plb
|
||||
rts
|
||||
|
||||
; Unrolled copy routine to move RTable intries into STK_ADDR position.
|
||||
;
|
||||
; A = intect into the RTable array (x2)
|
||||
; A = index into the RTable array (x2)
|
||||
; Y = starting line * $1000
|
||||
; X = number of lines (x2)
|
||||
CopyRTableToStkAddr
|
||||
jmp (:tbl,x)
|
||||
:tbl da :none
|
||||
da :do01,:do02,:do03,:do04
|
||||
da :do05,:do06,:do07,:do08
|
||||
da :do09,:do10,:do11,:do12
|
||||
da :do13,:do14,:do15,:do16
|
||||
:do15 tax
|
||||
bra :x15
|
||||
:do14 tax
|
||||
bra :x14
|
||||
:do13 tax
|
||||
bra :x13
|
||||
:do12 tax
|
||||
bra :x12
|
||||
:do11 tax
|
||||
bra :x11
|
||||
:do10 tax
|
||||
bra :x10
|
||||
:do09 tax
|
||||
bra :x09
|
||||
:do08 tax
|
||||
bra :x08
|
||||
:do07 tax
|
||||
bra :x07
|
||||
:do06 tax
|
||||
bra :x06
|
||||
:do05 tax
|
||||
bra :x05
|
||||
:do04 tax
|
||||
bra :x04
|
||||
:do03 tax
|
||||
bra :x03
|
||||
:do02 tax
|
||||
bra :x02
|
||||
:do01 tax
|
||||
bra :x01
|
||||
:do16 tax
|
||||
CopyRTableToStkAddr mac
|
||||
jmp (dispTbl,x)
|
||||
dispTbl da bottom
|
||||
da do01,do02,do03,do04
|
||||
da do05,do06,do07,do08
|
||||
da do09,do10,do11,do12
|
||||
da do13,do14,do15,do16
|
||||
do15 ldx ]1
|
||||
bra x15
|
||||
do14 ldx ]1
|
||||
bra x14
|
||||
do13 ldx ]1
|
||||
bra x13
|
||||
do12 ldx ]1
|
||||
bra x12
|
||||
do11 ldx ]1
|
||||
bra x11
|
||||
do10 ldx ]1
|
||||
bra x10
|
||||
do09 ldx ]1
|
||||
bra x09
|
||||
do08 ldx ]1
|
||||
bra x08
|
||||
do07 ldx ]1
|
||||
bra x07
|
||||
do06 ldx ]1
|
||||
bra x06
|
||||
do05 ldx ]1
|
||||
bra x05
|
||||
do04 ldx ]1
|
||||
bra x04
|
||||
do03 ldx ]1
|
||||
bra x03
|
||||
do02 ldx ]1
|
||||
bra x02
|
||||
do01 ldx ]1
|
||||
bra x01
|
||||
do16 ldx ]1
|
||||
ldal RTable+30,x
|
||||
sta STK_ADDR+$F000,y
|
||||
:x15 ldal RTable+28,x
|
||||
x15 ldal RTable+28,x
|
||||
sta STK_ADDR+$E000,y
|
||||
:x14 ldal RTable+26,x
|
||||
x14 ldal RTable+26,x
|
||||
sta STK_ADDR+$D000,y
|
||||
:x13 ldal RTable+24,x
|
||||
x13 ldal RTable+24,x
|
||||
sta STK_ADDR+$C000,y
|
||||
:x12 ldal RTable+22,x
|
||||
x12 ldal RTable+22,x
|
||||
sta STK_ADDR+$B000,y
|
||||
:x11 ldal RTable+20,x
|
||||
x11 ldal RTable+20,x
|
||||
sta STK_ADDR+$A000,y
|
||||
:x10 ldal RTable+18,x
|
||||
x10 ldal RTable+18,x
|
||||
sta STK_ADDR+$9000,y
|
||||
:x09 ldal RTable+16,x
|
||||
x09 ldal RTable+16,x
|
||||
sta STK_ADDR+$8000,y
|
||||
:x08 ldal RTable+14,x
|
||||
x08 ldal RTable+14,x
|
||||
sta STK_ADDR+$7000,y
|
||||
:x07 ldal RTable+12,x
|
||||
x07 ldal RTable+12,x
|
||||
sta STK_ADDR+$6000,y
|
||||
:x06 ldal RTable+10,x
|
||||
x06 ldal RTable+10,x
|
||||
sta STK_ADDR+$5000,y
|
||||
:x05 ldal RTable+08,x
|
||||
x05 ldal RTable+08,x
|
||||
sta STK_ADDR+$4000,y
|
||||
:x04 ldal RTable+06,x
|
||||
x04 ldal RTable+06,x
|
||||
sta STK_ADDR+$3000,y
|
||||
:x03 ldal RTable+04,x
|
||||
x03 ldal RTable+04,x
|
||||
sta STK_ADDR+$2000,y
|
||||
:x02 ldal RTable+02,x
|
||||
x02 ldal RTable+02,x
|
||||
sta STK_ADDR+$1000,y
|
||||
:x01 ldal RTable+00,x
|
||||
x01 ldal RTable+00,x
|
||||
sta: STK_ADDR+$0000,y
|
||||
:none rts
|
||||
bottom
|
||||
<<<
|
||||
|
||||
_CopyRTableToStkAddr
|
||||
CopyRTableToStkAddr tmp0
|
||||
rts
|
|
@ -45,13 +45,14 @@ CopyDynamicTile
|
|||
; populating the code field and snippet space
|
||||
DynamicOver
|
||||
lda TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
ora #SNIPPET_ENTRY_2
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda TileStore+TS_TILE_ID,x ; Get the original tile descriptor
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
ora #$B500
|
||||
xba
|
||||
sta _OP_CACHE ; This is the 2-byte opcode for to load the data
|
||||
sta _OP_CACHE ; This is the 2-byte opcode for to load the data
|
||||
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x
|
||||
pha
|
||||
|
@ -91,6 +92,7 @@ DynamicOver
|
|||
|
||||
DynamicUnder
|
||||
lda TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
ora #SNIPPET_ENTRY_3
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda TileStore+TS_TILE_ID,x ; Get the original tile descriptor
|
||||
|
@ -164,6 +166,7 @@ _DynFillJmpOpcode
|
|||
CopyDynamicTileTwoLyr
|
||||
|
||||
ldal TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
ora #SNIPPET_ENTRY_4
|
||||
sta _JTBL_CACHE
|
||||
|
||||
ldal TileStore+TS_WORD_OFFSET,x
|
||||
|
@ -215,9 +218,10 @@ CopyDynamicTileTwoLyr
|
|||
|
||||
jmp _DynFillJmpOpcode
|
||||
|
||||
; Render a sprite on top of a dyamic tile with transparent areas shwing the second background
|
||||
; Render a sprite on top of a dyamic tile with transparent areas showing the second background
|
||||
DynamicOverTwoLyr
|
||||
lda TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
ora #SNIPPET_ENTRY_1
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda TileStore+TS_WORD_OFFSET,x
|
||||
|
@ -275,9 +279,19 @@ DynamicOverTwoLyr
|
|||
plb
|
||||
rts
|
||||
|
||||
; Render a sprite on top of a dyamic tile with transparent areas shwing the second background
|
||||
; Render a sprite under a dyamic tile with transparent areas showing the second background
|
||||
;
|
||||
; This is a special case where we cannot fit the code into the fixed snippet structure. As such,
|
||||
; any tile drawn with this routine will set a DAMAGED flag on the TileStore flags. If another
|
||||
; tile blitter in the TwoLayer function set sees that a tile is marked as DAMAGED, it must
|
||||
; restore the original code structure before proceeding.
|
||||
;
|
||||
; The damages area is not too bad -- just the 10 bytes from [2, 10] are overwritten and must be
|
||||
; restored. This is actually less work than a lot of the snippet macros were doing before
|
||||
; applying the fixed snippet optimization.
|
||||
DynamicUnderTwoLyr
|
||||
lda TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
ora #SNIPPET_ENTRY_1
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda TileStore+TS_WORD_OFFSET,x
|
||||
|
@ -290,6 +304,8 @@ DynamicUnderTwoLyr
|
|||
; perform and EOR #$2080 to covert the opcode and operand in one instruction
|
||||
|
||||
lda TileStore+TS_TILE_ID,x ; Get the original tile descriptor
|
||||
ora #TILE_DAMAGED_BIT ; Set the DAMAGED bit here since we have to load TILE_ID anyway
|
||||
sta TileStore+TS_TILE_ID,x
|
||||
and #$007F ; clamp to < (32 * 4)
|
||||
ora #$3580 ; Pre-calc the AND $80,x opcode + operand
|
||||
xba
|
||||
|
@ -368,18 +384,12 @@ mixed cmp #$FFFF ; All 1's in the mask is a fully transparent sp
|
|||
lda _OP_CACHE ; Get the LDA dp,x instruction for this column
|
||||
sta: $0000,x
|
||||
|
||||
lda #$0029 ; AND #SPRITE_MASK
|
||||
sta: $0002,x
|
||||
lda tmp_sprite_mask+{]1}
|
||||
sta: $0003,x
|
||||
|
||||
lda #$0009 ; ORA #SPRITE_DATA
|
||||
sta: $0005,x
|
||||
lda tmp_sprite_data+{]1}
|
||||
sta: $0006,x
|
||||
|
||||
lda #$0D80 ; branch to the prologue (BRA *+15)
|
||||
sta: $0008,x
|
||||
bra next
|
||||
|
||||
; This is a transparent word, so just show the dynamic data
|
||||
|
@ -410,10 +420,8 @@ CopyDynUnder MAC
|
|||
lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
ora #{]2&$7000} ; adjust for the current row offset
|
||||
sta: {]2}+1,y
|
||||
tax ; This becomes the new address that we use to patch in
|
||||
tax ; This becomes the new address that we use to patch in
|
||||
|
||||
lda #$00A9 ; LDA #DATA
|
||||
sta: $0000,x
|
||||
lda tmp_sprite_data+{]1}
|
||||
sta: $0001,x
|
||||
|
||||
|
@ -421,9 +429,6 @@ CopyDynUnder MAC
|
|||
sta: $0003,x ; AND $80,x
|
||||
eor #$8020 ; Switch the opcode to an ORA and remove the high bit of the operand
|
||||
sta: $0005,x ; ORA $00,x
|
||||
|
||||
lda #$0E80 ; branch to the prologue (BRA *+16)
|
||||
sta: $0007,x
|
||||
eom
|
||||
|
||||
; Masked renderer for a dynamic tile. What's interesting about this renderer is that the mask
|
||||
|
@ -449,37 +454,31 @@ CopyMaskedDWord MAC
|
|||
lda _JTBL_CACHE
|
||||
ora #{{]1}&$7000} ; adjust for the current row offset
|
||||
sta: {]1}+1,y
|
||||
|
||||
tax ; This becomes the new address that we use to patch in
|
||||
|
||||
lda _OP_CACHE
|
||||
sta: $0000,x ; LDA (00),y
|
||||
lda _OP_CACHE2
|
||||
sta: $0002,x ; AND $80,x
|
||||
eor #$8020 ; Switch the opcode to an ORA and remove the high bit of the operand
|
||||
sta: $0004,x ; ORA $00,x
|
||||
lda #$0F80 ; branch to the prologue (BRA *+17)
|
||||
sta: $0006,x
|
||||
eom
|
||||
|
||||
|
||||
; Masked renderer for a masked dynamic tile with sprite data overlaid.
|
||||
; Version 2 will set the JMP to Entry Point 1 and set the Opcode at Entry Point 2 to a ora $00,x. Also
|
||||
; the mask transparency check can be performed earlier.
|
||||
;
|
||||
; ]1 : sprite plane offset
|
||||
; ]2 : code field offset
|
||||
; lda #$004C ; JMP to handler
|
||||
; sta: {]2},y
|
||||
; lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
; ora #{]2&$7000} ; adjust for the current row offset
|
||||
; sta: {]2}+1,y
|
||||
; tax ; This becomes the new address that we use to patch in
|
||||
; lda OP_CACHE_2 ; switch from AND to ORA instruction cached in setup
|
||||
; sta: $0004,x ; ORA $00,x
|
||||
|
||||
CopyDynMaskedSpriteWord MAC
|
||||
|
||||
; Need to fill in the first 14 bytes of the JMP handler with the following code sequence where
|
||||
; the data and mask from from the sprite plane
|
||||
;
|
||||
; lda ($00),y
|
||||
; and $80,x
|
||||
; ora $00,x
|
||||
; and #MASK
|
||||
; ora #DATA
|
||||
; bra *+15
|
||||
;
|
||||
; If MASK == 0, then we can do a PEA. If MASK == $FFFF, then fall back to the simple Dynamic Tile
|
||||
; code and eliminate the constanct AND/ORA instructions.
|
||||
; code and eliminate the constant AND/ORA instructions.
|
||||
|
||||
lda tmp_sprite_mask+{]1} ; load the mask value
|
||||
bne mixed ; a non-zero value may be mixed
|
||||
|
@ -491,9 +490,12 @@ CopyDynMaskedSpriteWord MAC
|
|||
sta: {]2}+1,y ; PEA operand
|
||||
bra next
|
||||
|
||||
; We will always do a JMP to the exception handler, so set that up, then check for sprite
|
||||
; transparency
|
||||
; We will always do a JMP to the exception handler, but the entry point changes depending on
|
||||
; whether the mask is transparent or not
|
||||
mixed
|
||||
cmp #$FFFF
|
||||
beq transparent
|
||||
|
||||
lda #$004C ; JMP to handler
|
||||
sta: {]2},y
|
||||
lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
|
@ -501,37 +503,37 @@ mixed
|
|||
sta: {]2}+1,y
|
||||
tax ; This becomes the new address that we use to patch in
|
||||
|
||||
lda _OP_CACHE2
|
||||
sta: $0002,x ; AND $80,x
|
||||
eor #$8020 ; Switch the opcode to an ORA and remove the high bit of the operand
|
||||
sta: $0004,x ; ORA $00,x
|
||||
|
||||
lda tmp_sprite_mask+{]1}
|
||||
sta: $0007,x
|
||||
|
||||
lda tmp_sprite_data+{]1}
|
||||
sta: $000A,x
|
||||
|
||||
bra next
|
||||
|
||||
; This is a transparent word, so just show the dynamic data overlaid on layer 2
|
||||
transparent
|
||||
lda #$004C ; JMP to handler
|
||||
sta: {]2},y
|
||||
lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
ora #{]2&$7000}.SNIPPET_ENTRY_4 ; adjust for the current row offset and OR in the offset since snippets are 32-byte aligned
|
||||
sta: {]2}+1,y
|
||||
tax
|
||||
|
||||
lda _OP_CACHE
|
||||
sta: $0000,x ; LDA (00),y
|
||||
lda _OP_CACHE2
|
||||
sta: $0002,x ; AND $80,x
|
||||
eor #$8020 ; Switch the opcode to an ORA and remove the high bit of the operand
|
||||
sta: $0004,x ; ORA $00,x
|
||||
|
||||
lda #$0029 ; AND #SPRITE_MASK
|
||||
sta: $0006,x
|
||||
lda tmp_sprite_mask+{]1}
|
||||
cmp #$FFFF ; All 1's in the mask is a fully transparent sprite word
|
||||
beq transparent
|
||||
sta: $0007,x
|
||||
|
||||
lda #$0009 ; ORA #SPRITE_DATA
|
||||
sta: $0009,x
|
||||
lda tmp_sprite_data+{]1}
|
||||
sta: $000A,x
|
||||
|
||||
lda #$0980 ; branch to the prologue (BRA *+11)
|
||||
sta: $000C,x
|
||||
bra next
|
||||
|
||||
; This is a transparent word, so just show the dynamic data
|
||||
transparent
|
||||
lda #$0F80 ; branch to the epilogue (BRA *+17)
|
||||
sta: $0006,x
|
||||
next
|
||||
eom
|
||||
|
||||
|
||||
; Masked renderer for a masked dynamic tile with sprite data underlaid.
|
||||
;
|
||||
; ]1 : sprite plane offset
|
||||
|
@ -546,7 +548,12 @@ CopyDynPrioMaskedSpriteWord MAC
|
|||
; ora #DATA
|
||||
; and $80,x
|
||||
; ora $00,x
|
||||
; bra *+15
|
||||
|
||||
; This macro has different targets based on the transparency
|
||||
|
||||
lda tmp_sprite_mask+{]1}
|
||||
cmp #$FFFF ; All 1's in the mask is a fully transparent sprite word
|
||||
beq transparent
|
||||
|
||||
lda #$004C ; JMP to handler
|
||||
sta: {]2},y
|
||||
|
@ -555,15 +562,10 @@ CopyDynPrioMaskedSpriteWord MAC
|
|||
sta: {]2}+1,y
|
||||
tax ; This becomes the new address that we use to patch in
|
||||
|
||||
lda _OP_CACHE
|
||||
sta: $0000,x ; LDA (00),y
|
||||
|
||||
lda #$0029 ; AND #SPRITE_MASK
|
||||
sta: $0002,x
|
||||
|
||||
lda tmp_sprite_mask+{]1}
|
||||
cmp #$FFFF ; All 1's in the mask is a fully transparent sprite word
|
||||
beq transparent ; so we can use the Tile00011 method
|
||||
sta: $0003,x
|
||||
|
||||
lda #$0009 ; ORA #SPRITE_DATA
|
||||
|
@ -576,19 +578,22 @@ CopyDynPrioMaskedSpriteWord MAC
|
|||
eor #$8020 ; Switch the opcode to an ORA and remove the high bit of the operand
|
||||
sta: $000A,x ; ORA $00,x
|
||||
|
||||
lda #$0980 ; branch to the prologue (BRA *+11)
|
||||
sta: $000C,x
|
||||
bra next
|
||||
|
||||
; This is a transparent word, so just show the dynamic data
|
||||
transparent
|
||||
lda _OP_CACHE2
|
||||
sta: $0002,x ; AND $80,x
|
||||
eor #$8020 ; Switch the opcode to an ORA and remove the high bit of the operand
|
||||
sta: $0004,x ; ORA $00,x
|
||||
; This is a transparent word, so just show the dynamic data
|
||||
lda #$004C ; JMP to handler
|
||||
sta: {]2},y
|
||||
lda _JTBL_CACHE ; Get the offset to the exception handler for this column
|
||||
ora #{]2&$7000}.SNIPPET_ENTRY_4 ; adjust for the current row offset and OR in the offset since snippets are 32-byte aligned
|
||||
sta: {]2}+1,y
|
||||
tax
|
||||
|
||||
lda #$0F80 ; branch to the epilogue (BRA *+17)
|
||||
sta: $0006,x
|
||||
lda _OP_CACHE
|
||||
sta: $0000,x ; LDA (00),y
|
||||
lda _OP_CACHE2
|
||||
sta: $0002,x ; AND $80,x
|
||||
eor #$8020 ; Switch the opcode to an ORA and remove the high bit of the operand
|
||||
sta: $0004,x ; ORA $00,x
|
||||
next
|
||||
eom
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
; GenericUnderSlow : Places the TileStore's tile on top of tmp_sprite_data
|
||||
|
||||
ConstTile0Slow
|
||||
jsr FillPEAOpcode
|
||||
jmp ConstTile0Fast
|
||||
jsr FillPEAOpcode ; Could these be slightly faster to do PEA ConstTile0Fast-1 ; JMP FillPEAOpcode?
|
||||
jmp ConstTile0Fast ; Currently it's 6 + 6 + 3 + 6, improved would be 5 + 3 + 6 + 6 = 1 cycle saved. :(
|
||||
|
||||
SpriteOverASlow
|
||||
lda TileStore+TS_CODE_ADDR_HIGH,x ; load the bank of the target code field line
|
||||
|
@ -79,12 +79,6 @@ FillPEAOpcode
|
|||
rep #$20
|
||||
rts
|
||||
|
||||
; This is a stub; will be removed eventually
|
||||
_FillPEAOpcode
|
||||
jsr FillPEAOpcode
|
||||
plb ; Restore the TileStore bank
|
||||
rts
|
||||
|
||||
CopyTileASlow
|
||||
tax
|
||||
jsr FillPEAOpcode
|
||||
|
|
|
@ -50,6 +50,7 @@ Tile0TwoLyr
|
|||
SpriteOver0TwoLyr
|
||||
|
||||
lda TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
ora #SNIPPET_ENTRY_2 ; Offset into the second entry point
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda TileStore+TS_WORD_OFFSET,x ; Load the word offset of this tile (0 to 82 in steps of 2)
|
||||
|
@ -95,6 +96,7 @@ SpriteOver0TwoLyr
|
|||
|
||||
TmpTileDataToCodeField
|
||||
lda TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
ora #SNIPPET_ENTRY_2
|
||||
sta _JTBL_CACHE
|
||||
|
||||
lda TileStore+TS_WORD_OFFSET,x ; Load the word offset of this tile (0 to 82 in steps of 2)
|
||||
|
@ -143,6 +145,7 @@ _TmpTileDataToCodeField
|
|||
; Copy a tile into the tile data buffer and then render to the code field
|
||||
CopyTileATwoLyr
|
||||
ldal TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
ora #SNIPPET_ENTRY_2
|
||||
sta _JTBL_CACHE
|
||||
|
||||
ldal TileStore+TS_WORD_OFFSET,x ; Load the word offset of this tile (0 to 82 in steps of 2)
|
||||
|
@ -170,6 +173,7 @@ CopyTileATwoLyr
|
|||
|
||||
CopyTileVTwoLyr
|
||||
ldal TileStore+TS_JMP_ADDR,x ; Get the address of the exception handler
|
||||
ora #SNIPPET_ENTRY_2
|
||||
sta _JTBL_CACHE
|
||||
|
||||
ldal TileStore+TS_WORD_OFFSET,x ; Load the word offset of this tile (0 to 82 in steps of 2)
|
||||
|
@ -348,22 +352,14 @@ mixed cmp #$FFFF ; All 1's in the mask is fully transparent
|
|||
sta: {]2}+1,y
|
||||
tax ; This becomes the new address that we use to patch in
|
||||
|
||||
lda #$29
|
||||
sta: $0002,x ; AND #$0000 opcode
|
||||
lda #$09
|
||||
sta: $0005,x ; ORA #$0000 opcode
|
||||
|
||||
lda _OP_CACHE ; Get the LDA (dp),y instruction for this column
|
||||
sta: $0000,x
|
||||
|
||||
lda {]1}+32 ; insert the tile mask and data into the exception
|
||||
sta: $0003,x ; handler.
|
||||
lda {]1}+32 ; insert the tile mask and data into the exception
|
||||
sta: $0003,x ; handler.
|
||||
lda {]1}
|
||||
sta: $0006,x
|
||||
|
||||
lda #$0D80 ; branch to the prologue (BRA *+15)
|
||||
sta: $0008,x
|
||||
|
||||
bra next
|
||||
|
||||
; This is a transparent word, so just show the second background layer
|
||||
|
|
|
@ -27,7 +27,7 @@ DirtyTiles ENT
|
|||
|
||||
ds \,$00 ; pad to the next page boundary
|
||||
_Sprites ENT
|
||||
ds SPRITE_REC_SIZE*MAX_SPRITES
|
||||
ds SPRITE_REC_SIZE*MAX_ELEMENTS
|
||||
|
||||
;-------------------------------------------------------------------------------------
|
||||
;
|
||||
|
@ -108,6 +108,10 @@ TileStoreLookup ENT
|
|||
Col2CodeOffset ENT
|
||||
lup 82
|
||||
dw CODE_TOP+{{81-]step}*PER_TILE_SIZE}
|
||||
]step equ ]step+1
|
||||
--^
|
||||
lup 82 ; Make is a double-length table so we can add the ScreenWidth without testing for wrap-around
|
||||
dw CODE_TOP+{{81-]step}*PER_TILE_SIZE}
|
||||
]step equ ]step+1
|
||||
--^
|
||||
dw CODE_TOP+{81*PER_TILE_SIZE}
|
||||
|
@ -129,6 +133,7 @@ JTableOffset ENT
|
|||
;
|
||||
; These tables are reversed to be parallel with the JTableOffset and Col2CodeOffset tables above. The
|
||||
; physical word index that each instruction is intended to be placed at is in the comment.
|
||||
bra *-3 ; wrap around
|
||||
CodeFieldEvenBRA ENT
|
||||
bra *+6 ; 81 -- need to skip over the JMP loop that passed control back
|
||||
bra *+9 ; 80
|
||||
|
@ -213,6 +218,7 @@ CodeFieldEvenBRA ENT
|
|||
bra *-6 ; 1
|
||||
bra *-3 ; 0
|
||||
|
||||
bra *-6 ; wrap around
|
||||
CodeFieldOddBRA ENT
|
||||
bra *+9 ; 81 -- need to skip over two JMP instructions
|
||||
bra *+12 ; 80
|
||||
|
@ -382,6 +388,17 @@ BG1YOffsetTable ENT
|
|||
; dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
--^
|
||||
|
||||
; Pointer to per-scanline offsets for BG0
|
||||
StartXMod164Tbl ENT
|
||||
dw 0,0
|
||||
|
||||
LastOffsetTbl ENT
|
||||
ds 416
|
||||
|
||||
; Pointer to per-scanline offsets for BG1
|
||||
BG1StartXMod164Tbl ENT
|
||||
dw 0,0
|
||||
|
||||
; Other Toolset variables
|
||||
OneSecondCounter ENT
|
||||
dw 0
|
||||
|
@ -389,9 +406,10 @@ OldOneSecVec ENT
|
|||
ds 4
|
||||
Timers ENT
|
||||
ds TIMER_REC_SIZE*MAX_TIMERS
|
||||
Overlays ENT
|
||||
dw 0 ; count
|
||||
ds 8 ; only support one or now (start_line, end_line, function call)
|
||||
|
||||
;Overlays ENT
|
||||
; dw 0 ; count
|
||||
; ds 10 ; only support one for now (flags, start_line, end_line, function call)
|
||||
|
||||
; From the IIgs ref
|
||||
DefaultPalette ENT
|
||||
|
@ -503,6 +521,29 @@ _SpriteBits ENT
|
|||
_SpriteBitsNot ENT
|
||||
dw $FFFE,$FFFD,$FFFB,$FFF7,$FFEF,$FFDF,$FFBF,$FF7F,$FEFF,$FDFF,$FBFF,$F7FF,$EFFF,$DFFF,$BFFF,$7FFF
|
||||
|
||||
; Doubly linked list that allows the sprites to be traversed in SPRITE_CLIP_TOP order. The prev/next
|
||||
; index links are stored in the parallel _Sprites structure; just the extra head and tail index values
|
||||
; are stored here. A negative value is used as a setinel
|
||||
_SortedHead ENT
|
||||
dw $FFFF
|
||||
|
||||
; Array of screen ranges covered by the sprites. Adjacent sprites are merged. Used in the shadowing renderer
|
||||
_ShadowListCount ENT
|
||||
ds 2
|
||||
_ShadowListTop ENT
|
||||
ds {2*{MAX_ELEMENTS}} ; space for all of the sprites + overlay range
|
||||
_ShadowListBottom ENT
|
||||
ds {2*{MAX_ELEMENTS}}
|
||||
|
||||
; Complement of the Shadow List. Can have one more segment than that list
|
||||
_DirectListCount ENT
|
||||
ds 2
|
||||
_DirectListTop ENT
|
||||
ds {2*{MAX_ELEMENTS+1}}
|
||||
_DirectListBottom ENT
|
||||
ds {2*{MAX_ELEMENTS+1}}
|
||||
|
||||
|
||||
; Steps to the different sprite stamps
|
||||
_stamp_step ENT
|
||||
dw 0,12,24,36
|
||||
|
@ -541,4 +582,9 @@ Handles ENT
|
|||
ds 4*32
|
||||
|
||||
blt_return
|
||||
stk_save
|
||||
stk_save
|
||||
|
||||
;StartXMod164Arr ENT
|
||||
; ds 416*2
|
||||
;LastPatchOffsetArr ENT
|
||||
; ds 416*2
|
||||
|
|
|
@ -12,7 +12,6 @@ TS_TILE_ADDR equ {TILE_STORE_SIZE*3} ; cached value, the address
|
|||
TS_CODE_ADDR_LOW equ {TILE_STORE_SIZE*4} ; const value, address of this tile in the code fields
|
||||
TS_CODE_ADDR_HIGH equ {TILE_STORE_SIZE*5}
|
||||
TS_WORD_OFFSET equ {TILE_STORE_SIZE*6} ; const value, word offset value for this tile if LDA (dp),y instructions re used
|
||||
;TS_BASE_ADDR equ {TILE_STORE_SIZE*7} ; const value, because there are two rows of tiles per bank, this is set to $0000 or $8000.
|
||||
TS_JMP_ADDR equ {TILE_STORE_SIZE*7} ; const value, address of the 32-byte snippet space for this tile
|
||||
TS_SCREEN_ADDR equ {TILE_STORE_SIZE*8} ; cached value of on-screen location of tile. Used for DirtyRender.
|
||||
|
||||
|
@ -29,6 +28,9 @@ TILE_STORE_NUM equ 12 ; Need this many parallel arra
|
|||
MAX_SPRITES equ 16
|
||||
SPRITE_REC_SIZE equ 42
|
||||
|
||||
MAX_OVERLAYS equ 2
|
||||
MAX_ELEMENTS equ {MAX_SPRITES+MAX_OVERLAYS}
|
||||
|
||||
; Mark each sprite as ADDED, UPDATED, MOVED, REMOVED depending on the actions applied to it
|
||||
; on this frame. Quick note, the same Sprite ID cannot be removed and added in the same frame.
|
||||
; A REMOVED sprite if removed from the sprite list during the Render call, so it's ID is not
|
||||
|
@ -42,27 +44,39 @@ SPRITE_STATUS_REMOVED equ $0008 ; Sprite has been removed.
|
|||
SPRITE_STATUS_HIDDEN equ $0010 ; Sprite is in a hidden state
|
||||
|
||||
; These values are set by the user
|
||||
SPRITE_STATUS equ {MAX_SPRITES*0}
|
||||
SPRITE_ID equ {MAX_SPRITES*2}
|
||||
SPRITE_X equ {MAX_SPRITES*4}
|
||||
SPRITE_Y equ {MAX_SPRITES*6}
|
||||
VBUFF_ADDR equ {MAX_SPRITES*8} ; Base address of the sprite's stamp in the data/mask banks
|
||||
SPRITE_STATUS equ {MAX_ELEMENTS*0}
|
||||
SPRITE_ID equ {MAX_ELEMENTS*2}
|
||||
SPRITE_X equ {MAX_ELEMENTS*4}
|
||||
SPRITE_Y equ {MAX_ELEMENTS*6}
|
||||
VBUFF_ADDR equ {MAX_ELEMENTS*8} ; Base address of the sprite's stamp in the data/mask banks
|
||||
|
||||
; These values are cached / calculated during the rendering process
|
||||
TS_LOOKUP_INDEX equ {MAX_SPRITES*10} ; The index from the TileStoreLookup table that corresponds to the top-left corner of the sprite
|
||||
TS_COVERAGE_SIZE equ {MAX_SPRITES*12} ; Representation of how many TileStore tiles (NxM) are covered by this sprite
|
||||
SPRITE_DISP equ {MAX_SPRITES*14} ; Cached address of the specific stamp based on sprite flags
|
||||
SPRITE_CLIP_LEFT equ {MAX_SPRITES*16}
|
||||
SPRITE_CLIP_RIGHT equ {MAX_SPRITES*18}
|
||||
SPRITE_CLIP_TOP equ {MAX_SPRITES*20}
|
||||
SPRITE_CLIP_BOTTOM equ {MAX_SPRITES*22}
|
||||
IS_OFF_SCREEN equ {MAX_SPRITES*24}
|
||||
SPRITE_WIDTH equ {MAX_SPRITES*26}
|
||||
SPRITE_HEIGHT equ {MAX_SPRITES*28}
|
||||
SPRITE_CLIP_WIDTH equ {MAX_SPRITES*30}
|
||||
SPRITE_CLIP_HEIGHT equ {MAX_SPRITES*32}
|
||||
TS_VBUFF_BASE equ {MAX_SPRITES*34} ; Finalized VBUFF address based on the sprite position and tile offsets
|
||||
VBUFF_ARRAY_ADDR equ {MAX_SPRITES*36} ; Fixed address where this sprite's VBUFF addresses are stores. The array is the same shape as TileStore, but much smaller
|
||||
TS_LOOKUP_INDEX equ {MAX_ELEMENTS*10} ; The index from the TileStoreLookup table that corresponds to the top-left corner of the sprite
|
||||
TS_COVERAGE_SIZE equ {MAX_ELEMENTS*12} ; Representation of how many TileStore tiles (NxM) are covered by this sprite
|
||||
SPRITE_DISP equ {MAX_ELEMENTS*14} ; Cached address of the specific stamp based on sprite flags
|
||||
SPRITE_CLIP_LEFT equ {MAX_ELEMENTS*16}
|
||||
SPRITE_CLIP_RIGHT equ {MAX_ELEMENTS*18}
|
||||
SPRITE_CLIP_TOP equ {MAX_ELEMENTS*20}
|
||||
SPRITE_CLIP_BOTTOM equ {MAX_ELEMENTS*22}
|
||||
IS_OFF_SCREEN equ {MAX_ELEMENTS*24}
|
||||
SPRITE_WIDTH equ {MAX_ELEMENTS*26}
|
||||
SPRITE_HEIGHT equ {MAX_ELEMENTS*28}
|
||||
SPRITE_CLIP_WIDTH equ {MAX_ELEMENTS*30}
|
||||
SPRITE_CLIP_HEIGHT equ {MAX_ELEMENTS*32}
|
||||
TS_VBUFF_BASE equ {MAX_ELEMENTS*34} ; Finalized VBUFF address based on the sprite position and tile offsets
|
||||
SORTED_PREV equ {MAX_ELEMENTS*36} ; Doubly-Linked List that maintains the sprites in sorted order based on SPRITE_Y
|
||||
SORTED_NEXT equ {MAX_ELEMENTS*38}
|
||||
|
||||
; The Overlays are part of the _Sprites memory space and come after the maximum number of sprites
|
||||
Overlays equ {_Sprites+{MAX_SPRITES*2}}
|
||||
|
||||
; Aliases of SPRITE_* memory locations that are used for Overlay info when the SPRITE_OVERLAY bit is set on SPRITE_ID
|
||||
OVERLAY_ID equ SPRITE_ID
|
||||
OVERLAY_FLAGS equ SPRITE_STATUS
|
||||
OVERLAY_TOP equ SPRITE_CLIP_TOP ; This is important because SPRITE_CLIP_TOP is used for sorting
|
||||
OVERLAY_BOTTOM equ SPRITE_CLIP_BOTTOM
|
||||
OVERLAY_HEIGHT equ SPRITE_HEIGHT
|
||||
OVERLAY_PROC equ VBUFF_ADDR
|
||||
|
||||
; 52 rows by 82 columns + 2 extra rows and columns for sprite sizes
|
||||
;
|
||||
|
|
|
@ -146,6 +146,8 @@ function getOptions(argv) {
|
|||
options.targetPalette = getArg(argv, '--palette', x => x.split(',').map(c => hexStringToPalette(c)), null);
|
||||
options.forceMatch = getArg(argv, '--force-color-match', x => true, false);
|
||||
options.forceWordAlignment = getArg(argv, '--force-word-alignment', x => true, false);
|
||||
options.format = getArg(argv, '--format', x => x, 'asm65816'); // asm65816 or orcac or rez
|
||||
options.varName = getArg(argv, '--var-name', x => x, 'tiles'); // language-specific label to reference tile data
|
||||
|
||||
return options;
|
||||
}
|
||||
|
@ -222,25 +224,60 @@ function getPaletteMap(options, png) {
|
|||
};
|
||||
}
|
||||
|
||||
function writeComment(options, message, logger=console.log) {
|
||||
switch (options.format) {
|
||||
case 'orcac':
|
||||
logger(`/* ${message} */`);
|
||||
break;
|
||||
default:
|
||||
logger(`; ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
function writePaletteArray(options, palette, logger=console.log) {
|
||||
switch (options.format) {
|
||||
case 'orcac': {
|
||||
const hexCodes = palette.map(c => '0x' + paletteToIIgs(c));
|
||||
if (options.backgroundColor !== null) {
|
||||
hexCodes[0] = '0x' + paletteToIIgs(hexStringToPalette(options.backgroundColor));
|
||||
}
|
||||
logger('#include <types.h>');
|
||||
logger('');
|
||||
logger(`Word ${options.varName}Palette[16] = {`);
|
||||
logger(` ${hexCodes.join(',')}`);
|
||||
logger(`};`);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
const hexCodes = palette.map(c => '$' + paletteToIIgs(c));
|
||||
// The transparent color is always mapped into color 0, so if a background color is set it goes into index 0
|
||||
if (options.backgroundColor !== null) {
|
||||
hexCodes[0] = '$' + paletteToIIgs(hexStringToPalette(options.backgroundColor));
|
||||
}
|
||||
logger('TileSetPalette ENT');
|
||||
logger(' dw ', hexCodes.join(','));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function main(argv) {
|
||||
// try {
|
||||
const png = await readPNG(argv[0]);
|
||||
const options = getOptions(argv);
|
||||
|
||||
console.info(`; startIndex = ${options.startIndex}`);
|
||||
|
||||
writeComment(options, `startIndex = ${options.startIndex}`);
|
||||
if (png.colorType !== 3) {
|
||||
console.warn('; PNG must be in palette color type');
|
||||
writeComment(options, `PNG must be in palette color type`, logger.warn);
|
||||
return;
|
||||
}
|
||||
|
||||
if (png.palette.length > 16) {
|
||||
console.warn('; Too many colors. Must be 16 or less');
|
||||
writeComment(options, `Too many colors. Must be 16 or less`, logger.warn);
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.palette && options.palette.length > 16) {
|
||||
console.warn('; Too many colors on command line. Must be 16 or less');
|
||||
writeComment(options, `Too many colors on command line. Must be 16 or less`, logger.warn);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -249,22 +286,16 @@ async function main(argv) {
|
|||
options.paletteMap = paletteMap;
|
||||
|
||||
// Dump the palette in IIgs hex format
|
||||
console.log('; Palette');
|
||||
const hexCodes = targetPalette.map(c => '$' + paletteToIIgs(c));
|
||||
|
||||
// The transparent color is always mapped into color 0, so if a background color is set it goes into index 0
|
||||
if (options.backgroundColor !== null) {
|
||||
hexCodes[0] = '$' + paletteToIIgs(hexStringToPalette(options.backgroundColor));
|
||||
}
|
||||
console.log('TileSetPalette ENT');
|
||||
console.log(' dw ', hexCodes.join(','));
|
||||
writeComment(options, `Palette`);
|
||||
writePaletteArray(options, targetPalette);
|
||||
|
||||
// Just convert a paletted PNG to IIgs memory format. We make sure that only a few widths
|
||||
// are supported
|
||||
let buff = null;
|
||||
let mask = null;
|
||||
|
||||
console.log('; Converting to BG0 format...');
|
||||
console.log('');
|
||||
writeComment(options, `Converting to BG0 format...`);
|
||||
[buff, mask] = pngToIIgsBuff(options, png);
|
||||
|
||||
if (buff && argv[1]) {
|
||||
|
@ -272,7 +303,7 @@ async function main(argv) {
|
|||
writeToTileDataSource(options, buff, mask, png.width / 2);
|
||||
}
|
||||
else {
|
||||
console.log(`; Writing to output file ${argv[1]}`);
|
||||
writeComment(options, `Writing to output file ${argv[1]}`);
|
||||
await writeBinayOutput(options, argv[1], buff);
|
||||
}
|
||||
}
|
||||
|
@ -288,7 +319,7 @@ function reverse(str) {
|
|||
}
|
||||
|
||||
function toHex(h) {
|
||||
return h.toString(16).padStart(2, '0');
|
||||
return h.toString(16).padStart(2, '0').toUpperCase();
|
||||
}
|
||||
|
||||
function swap(hex) {
|
||||
|
@ -429,21 +460,69 @@ function writeTileToStream(stream, data) {
|
|||
}
|
||||
}
|
||||
|
||||
function writeTileToStreamORCAC(stream, data) {
|
||||
// Output the tile data
|
||||
for (const row of data) {
|
||||
const hex = row.map(d => '0x' + toHex(d)).join(', ');
|
||||
stream.write(' ' + hex + ',\n');
|
||||
}
|
||||
stream.write('\n');
|
||||
}
|
||||
|
||||
function writeTilesToStream(options, stream, tiles, label='tiledata') {
|
||||
stream.write(`${label} ENT\n`);
|
||||
switch (options.format) {
|
||||
case 'orcac':
|
||||
writeTilesToStreamORCAC(options, stream, tiles, label);
|
||||
break;
|
||||
|
||||
case 'asm65816':
|
||||
writeTilesToStreamASM65816(options, stream, tiles, label);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw `Unknown output format: ${options.format}`;
|
||||
}
|
||||
}
|
||||
|
||||
function writeTilesToStreamORCAC(options, stream, tiles, label='tiledata') {
|
||||
stream.write(`Byte ${options.varName}[] = {\n`);
|
||||
stream.write('/* Reserved space (tile 0 is special...) */\n');
|
||||
for (let j = 0; j < 4; j += 1) {
|
||||
for (let i = 0; i < 8; i += 1) {
|
||||
stream.write(' 0x00, 0x00, 0x00, 0x00,\n');
|
||||
}
|
||||
stream.write('\n');
|
||||
}
|
||||
|
||||
let count = 0;
|
||||
for (const tile of tiles.slice(0, options.maxTiles)) {
|
||||
stream.write(`/* Tile ID ${count + 1}, isSolid: ${tile.isSolid} */\n`);
|
||||
writeTileToStreamORCAC(stream, tile.normal.data);
|
||||
writeTileToStreamORCAC(stream, tile.normal.mask);
|
||||
writeTileToStreamORCAC(stream, tile.flipped.data);
|
||||
writeTileToStreamORCAC(stream, tile.flipped.mask);
|
||||
stream.write('\n');
|
||||
|
||||
count += 1;
|
||||
}
|
||||
stream.write('};\n');
|
||||
stream.write('\n');
|
||||
}
|
||||
|
||||
function writeTilesToStreamASM65816(options, stream, tiles, label='tiledata') {
|
||||
stream.write(`${options.varName} ENT\n`);
|
||||
stream.write('');
|
||||
stream.write('; Reserved space (tile 0 is special...)\n');
|
||||
stream.write(' ds 128\n');
|
||||
|
||||
let count = 0;
|
||||
for (const tile of tiles.slice(0, options.maxTiles)) {
|
||||
console.log(`Writing tile ${count + 1}`);
|
||||
stream.write(`; Tile ID ${count + 1}, isSolid: ${tile.isSolid}\n`);
|
||||
writeTileToStream(stream, tile.normal.data);
|
||||
writeTileToStream(stream, tile.normal.mask);
|
||||
writeTileToStream(stream, tile.flipped.data);
|
||||
writeTileToStream(stream, tile.flipped.mask);
|
||||
stream.write('');
|
||||
stream.write('\n');
|
||||
|
||||
count += 1;
|
||||
}
|
||||
|
@ -485,51 +564,13 @@ function buildMerlinCodeForTiles(options, tiles, label='tiledata') {
|
|||
}
|
||||
|
||||
function writeToTileDataSource(options, buff, mask, width) {
|
||||
console.log('tiledata ENT');
|
||||
console.log();
|
||||
console.log('; Reserved space (tile 0 is special...');
|
||||
console.log(' ds 128');
|
||||
const stream = process.stdout;
|
||||
|
||||
let count = 0;
|
||||
for (let y = 0; ; y += 8) {
|
||||
for (let x = 0; x < width; x += 4, count += 1) {
|
||||
if (count >= options.maxTiles) {
|
||||
return;
|
||||
}
|
||||
console.log('; Tile ID ' + (count + 1));
|
||||
console.log('; From image coordinates ' + (x * 2) + ', ' + y);
|
||||
// Build the tiles
|
||||
const tiles = buildTiles(options, buff, mask, width);
|
||||
|
||||
const tile = buildTile(options, buff, mask, width, x, y);
|
||||
|
||||
// Output the tile data
|
||||
for (const row of tile.normal.data) {
|
||||
const hex = row.map(d => toHex(d)).join('');
|
||||
console.log(' hex ' + hex);
|
||||
}
|
||||
console.log();
|
||||
|
||||
// Output the tile mask
|
||||
for (const row of tile.normal.mask) {
|
||||
const hex = row.map(d => toHex(d)).join('');
|
||||
console.log(' hex ' + hex);
|
||||
}
|
||||
console.log();
|
||||
|
||||
// Output the flipped tile data
|
||||
for (const row of tile.flipped.data) {
|
||||
const hex = row.map(d => toHex(d)).join('');
|
||||
console.log(' hex ' + hex);
|
||||
}
|
||||
console.log();
|
||||
|
||||
// Output the flipped tile data
|
||||
for (const row of tile.flipped.mask) {
|
||||
const hex = row.map(d => toHex(d)).join('');
|
||||
console.log(' hex ' + hex);
|
||||
}
|
||||
console.log();
|
||||
}
|
||||
}
|
||||
// Write them to the default output stream
|
||||
writeTilesToStream(options, stream, tiles, options.varName);
|
||||
}
|
||||
|
||||
async function writeBinayOutput(options, filename, buff) {
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
# Playground for working through scanline decomposition algorithm
|
||||
|
||||
# 1. Shadow Off
|
||||
# 2. Draw Playfield (sprite OR overlay) AND NOT solid_overlay
|
||||
# 3. Draw sprites
|
||||
|
||||
sprites = [
|
||||
{ 'top': 10, 'bottom': 17 },
|
||||
{ 'top': 14, 'bottom': 29 }
|
||||
]
|
||||
|
||||
overlays = [
|
||||
{ 'top': 0, 'bottom': 7 }
|
||||
]
|
||||
|
||||
MAX_HEIGHT = 199
|
||||
|
||||
# Combine a list on ranges into a minimal list by merging overlapping ranges
|
||||
def simplify(a):
|
||||
b = []
|
||||
if len(a) > 0:
|
||||
last = a[0]
|
||||
start = last['top']
|
||||
for r in a[1:]:
|
||||
if r['top'] <= last['bottom']:
|
||||
last = r
|
||||
continue
|
||||
|
||||
b.append([start, last['bottom']])
|
||||
last = r
|
||||
start = r['top']
|
||||
|
||||
b.append([start, last['bottom']])
|
||||
|
||||
return b
|
||||
|
||||
# Given two sorted lists, merge them together into a minimal set of ranges. This could
|
||||
# be done as a list merge and then a combine step, but we want to be more efficient and
|
||||
# do the merge-and-combine at the same time
|
||||
def merge(a, b):
|
||||
if len(a) == 0:
|
||||
return simplify(b)
|
||||
|
||||
if len(b) == 0:
|
||||
return simplify(a)
|
||||
|
||||
c = []
|
||||
i = j = 0
|
||||
|
||||
while i < len(a) and j < len(b):
|
||||
if a[i]['top'] <= b[j]['top']:
|
||||
c.append(a[i])
|
||||
i += 1
|
||||
else:
|
||||
c.append(b[j])
|
||||
j += 1
|
||||
|
||||
if i < len(a):
|
||||
c.extend(a[i:])
|
||||
|
||||
if j < len(b):
|
||||
c.extend(b[j:])
|
||||
|
||||
return simplify(c)
|
||||
|
||||
# Find the lines that need to be drawn with shadowing off
|
||||
def get_shadow_off_bg(sprites):
|
||||
ranges = []
|
||||
|
||||
if len(sprites) > 0:
|
||||
last = sprites[0]
|
||||
start = last['top']
|
||||
|
||||
for sprite in sprites[1:]:
|
||||
if sprite['top'] <= last['bottom']:
|
||||
last = sprite
|
||||
continue
|
||||
|
||||
ranges.push([start, last['bottom']])
|
||||
start = sprite['top']
|
||||
last = sprite
|
||||
|
||||
ranges.append([start, last['bottom']])
|
||||
|
||||
return ranges
|
||||
|
||||
def complement(ranges):
|
||||
comp = []
|
||||
if len(ranges) > 0:
|
||||
if ranges[0][0] > 0:
|
||||
comp.append([0, ranges[0][0]])
|
||||
for i in range(1, len(ranges)):
|
||||
comp.append([ranges[i-1][1]+1, ranges[i][0]])
|
||||
last = ranges[len(ranges)-1]
|
||||
if last[1] < MAX_HEIGHT:
|
||||
comp.append([last[1]+1, MAX_HEIGHT])
|
||||
return comp
|
||||
else:
|
||||
return [0, MAX_HEIGHT]
|
||||
|
||||
r = get_shadow_off_bg(sprites)
|
||||
print(r)
|
||||
print(complement(r))
|
||||
|
||||
print(merge(sprites, overlays))
|
Loading…
Reference in New Issue