mirror of
https://github.com/lscharen/iigs-game-engine.git
synced 2024-12-26 05:31:42 +00:00
121 lines
4.3 KiB
JavaScript
121 lines
4.3 KiB
JavaScript
/**
|
|
* Basic sprite compiler
|
|
*
|
|
* GTE has some specific needs that makes existing tools (like MrSprite) inappropriate. GTE
|
|
* sprites need to reference some internal data structures and have slightly different code
|
|
* in order to handle clipping to the playfield bounds.
|
|
*
|
|
* The core sprite drawing approach is the same (set up Bank 1 direct page and stack), but
|
|
* the setup and dispatch are a bit different.
|
|
*
|
|
* A Note on Clipping
|
|
*
|
|
* GTE supports two clipping buffers for sprites to use. The first one is a static buffer
|
|
* that is aligned with the playfield and is used to clip the sprite when crossing the
|
|
* left and right boundaries, but since it's a static image, mask data can be put anywhere
|
|
* that the sprites should not show through, so irregular borders and sprite punch-outs
|
|
* on the playfield are possible.
|
|
*
|
|
* The second buffer matches the current tiles in the playfield and can be used as a
|
|
* dynamic mask of the playfield. Since the sprite code itself must use this data,
|
|
* different variations of the same sprite can be created to stand in "front" and "behind"
|
|
* different screen elements.
|
|
*
|
|
* The sprite requires the X and Y registers for this. The most general code that
|
|
* should be used for each sprite word is this:
|
|
*
|
|
* Example: DATA = $5670, MASK = $000F, screen_mask = $FF00, field_mask = $F0FF
|
|
* lda DP ; A = $1234
|
|
* eor #DATA ; A = $4444
|
|
* and #~MASK ; A = $4440
|
|
* and screen_mask,y ; A = $4400
|
|
* and >field_mask,x ; A = $4000
|
|
* eor DP ; A = $5234 <-- Only the high nibble is set to the sprite data
|
|
* sta DP
|
|
*
|
|
* It is not *required* that sprites use this approach, any compiled sprites code can be used,
|
|
* so if a sprite does not need to be masked, than any of the fast sprite approaches can be
|
|
* used.
|
|
*
|
|
* For clipping vertically, we pass in the starting and finishing lines in a register and
|
|
* a sprite record is set up to allow the sprite to be entered in the middle and exited
|
|
* before the last line of the sprite.
|
|
*/
|
|
const { readPNG, pngToIIgsBuff } = require('./png2iigs');
|
|
const process = require('process');
|
|
|
|
main(process.argv.slice(2)).then(
|
|
() => process.exit(0),
|
|
(e) => {
|
|
console.error(e);
|
|
process.exit(1);
|
|
}
|
|
);
|
|
|
|
async function main(argv) {
|
|
const png = await readPNG(argv[0]);
|
|
const buff = pngToIIgsBuff(png);
|
|
|
|
const options = {
|
|
staticClip: true,
|
|
label: 'Sprite001'
|
|
};
|
|
|
|
startIndex = getArg(argv, '--start-index', x => parseInt(x, 10), 0);
|
|
asTileData = getArg(argv, '--as-tile-data', null, 0);
|
|
maxTiles = getArg(argv, '--max-tiles', x => parseInt(x, 10), 64);
|
|
}
|
|
|
|
function getArg(argv, arg, fn, defaultValue) {
|
|
for (let i = 0; i < argv.length; i += 1) {
|
|
if (argv[i] === arg) {
|
|
if (fn) {
|
|
return fn(argv[i+1]);
|
|
}
|
|
return true; // Return true if the argument was found
|
|
}
|
|
}
|
|
return defaultValue;
|
|
}
|
|
|
|
|
|
function buildMerlinCodeForSprite(sprite, options) {
|
|
const { label, staticClip } = options;
|
|
const rtnOpCode = options.longReturn ? 'rtl' : 'rts';
|
|
|
|
const sb = new StringBuilder();
|
|
sb.appendLine(`${label} ENT`);
|
|
sb.appendLine(` cpx #${sprite.height * 2}`);
|
|
sb.appendLine(` bcc *+3`);
|
|
sb.appendLine(` ${rtnOpCode}`);
|
|
sb.appendLine(` sei`);
|
|
sb.appendLine(` tcs`);
|
|
sb.appendLine(` jmp (${label}_jtbl,x)`);
|
|
sb.appendLine(`${label}_jtbl`);
|
|
for (let line = 0; line < sprite.rows.length; line += 1) {
|
|
lda DP ; A = $1234
|
|
* eor #DATA ; A = $4444
|
|
* and #~MASK ; A = $4440
|
|
* and screen_mask,y ; A = $4400
|
|
* and >field_mask,x ; A = $4000
|
|
* eor DP ; A = $5234 <-- Only the high nibble is set to the sprite data
|
|
* sta DP
|
|
sb.appendLine(` dw ${label}_${line}`);
|
|
}
|
|
|
|
// Implement each line to draw the sprite data
|
|
//
|
|
// label_XX tdc
|
|
// clc
|
|
// adc #160*line
|
|
// tcd
|
|
// main_XX lda 00
|
|
// and #
|
|
// ora #
|
|
//
|
|
for (let line = 0; line < sprite.rows.length; line += 1) {
|
|
|
|
}
|
|
|
|
return sb.toString();
|
|
} |