diff --git a/tools/mksprite.js b/tools/mksprite.js index fbf25d9..cb099f3 100644 --- a/tools/mksprite.js +++ b/tools/mksprite.js @@ -2,7 +2,7 @@ * 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 difference code + * 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 @@ -41,4 +41,81 @@ * 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(); +} \ No newline at end of file diff --git a/tools/png2iigs.js b/tools/png2iigs.js index 07d0c44..92ca5a6 100644 --- a/tools/png2iigs.js +++ b/tools/png2iigs.js @@ -8,6 +8,7 @@ const StringBuilder = require('string-builder'); let startIndex = 0; let transparentColor = 0; let transparentIndex = -1; +let maxTiles = 511; main(process.argv.slice(2)).then( () => process.exit(0), @@ -92,6 +93,18 @@ function pngToIIgsBuffRepeat(png) { return buff; } +function paletteToHexString(palette) { + const r = Math.round(palette[0]); + const g = Math.round(palette[1]); + const b = Math.round(palette[2]); + + return ( + r.toString(16).toUpperCase().padStart(2, '0') + + g.toString(16).toUpperCase().padStart(2, '0') + + b.toString(16).toUpperCase().padStart(2, '0') + ); +} + function paletteToIIgs(palette) { const r = Math.round(palette[0] / 17); const g = Math.round(palette[1] / 17); @@ -133,10 +146,12 @@ async function main(argv) { 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); + maxTiles = getArg(argv, '--max-tiles', x => parseInt(x, 10), 511); transparentColor = getArg(argv, '--transparent-color-index', x => parseInt(x, 10), -1); - transparentIndex = transparentColor; + if (transparentColor !== -1) { + transparentIndex = transparentColor; + } console.info(`; startIndex = ${startIndex}`); @@ -150,6 +165,17 @@ async function main(argv) { return; } + // Get the RGB triplets from the palette + const palette = png.palette.map(c => paletteToHexString(c)); + transparentColorTriple = getArg(argv, '--transparent-color', x => x, null); + if (transparentColorTriple) { + console.log('; Looking for transparent color', transparentColorTriple); + transparentIndex = palette.findIndex(p => p === transparentColorTriple); + if (transparentIndex !== -1) { + console.log('; found color at palette index', transparentIndex); + } + } + // Dump the palette in IIgs hex format console.log('; Palette:'); const hexCodes = png.palette.map(c => '$' + paletteToIIgs(c)); @@ -277,12 +303,10 @@ function buildTile(buff, width, x, y, transparentIndex = -1) { function buildTiles(buff, width, transparentIndex = -1) { const tiles = []; - const MAX_TILES = 240; - let count = 0; for (let y = 0; ; y += 8) { for (let x = 0; x < width; x += 4, count += 1) { - if (count >= MAX_TILES) { + if (count >= maxTiles) { return tiles; } const tile = buildTile(buff, width, x, y, transparentIndex); diff --git a/tools/tiled2iigs.js b/tools/tiled2iigs.js index 23b8650..0fa3f7a 100644 --- a/tools/tiled2iigs.js +++ b/tools/tiled2iigs.js @@ -406,8 +406,16 @@ function convertTileID(tileId, tileset) { throw new Error('A maximum of 511 tiles are supported'); } + if (tileIndex === 0) { + // This should be a warning + return 0; + } + // The tileId starts at one, but the tile set starts at zero. It's ok when we export, // because a special zero tile is inserted, but we have to manually adjust here + if (!tileset[tileIndex - 1]) { + throw new Error(`Tileset for tileId ${tileIndex} is underinfed`); + } const mask_bit = (!tileset[tileIndex - 1].isSolid) && (GLOBALS.tileLayers.length !== 1); // Build up a partial set of control bits