Small update to add ability to specify a transparent color directly
This commit is contained in:
parent
631f40da23
commit
532af93538
|
@ -2,7 +2,7 @@
|
||||||
* Basic sprite compiler
|
* Basic sprite compiler
|
||||||
*
|
*
|
||||||
* GTE has some specific needs that makes existing tools (like MrSprite) inappropriate. GTE
|
* 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.
|
* 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 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
|
* 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.
|
* 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();
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ const StringBuilder = require('string-builder');
|
||||||
let startIndex = 0;
|
let startIndex = 0;
|
||||||
let transparentColor = 0;
|
let transparentColor = 0;
|
||||||
let transparentIndex = -1;
|
let transparentIndex = -1;
|
||||||
|
let maxTiles = 511;
|
||||||
|
|
||||||
main(process.argv.slice(2)).then(
|
main(process.argv.slice(2)).then(
|
||||||
() => process.exit(0),
|
() => process.exit(0),
|
||||||
|
@ -92,6 +93,18 @@ function pngToIIgsBuffRepeat(png) {
|
||||||
return buff;
|
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) {
|
function paletteToIIgs(palette) {
|
||||||
const r = Math.round(palette[0] / 17);
|
const r = Math.round(palette[0] / 17);
|
||||||
const g = Math.round(palette[1] / 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);
|
startIndex = getArg(argv, '--start-index', x => parseInt(x, 10), 0);
|
||||||
asTileData = getArg(argv, '--as-tile-data', null, 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);
|
transparentColor = getArg(argv, '--transparent-color-index', x => parseInt(x, 10), -1);
|
||||||
transparentIndex = transparentColor;
|
if (transparentColor !== -1) {
|
||||||
|
transparentIndex = transparentColor;
|
||||||
|
}
|
||||||
|
|
||||||
console.info(`; startIndex = ${startIndex}`);
|
console.info(`; startIndex = ${startIndex}`);
|
||||||
|
|
||||||
|
@ -150,6 +165,17 @@ async function main(argv) {
|
||||||
return;
|
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
|
// Dump the palette in IIgs hex format
|
||||||
console.log('; Palette:');
|
console.log('; Palette:');
|
||||||
const hexCodes = png.palette.map(c => '$' + paletteToIIgs(c));
|
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) {
|
function buildTiles(buff, width, transparentIndex = -1) {
|
||||||
const tiles = [];
|
const tiles = [];
|
||||||
|
|
||||||
const MAX_TILES = 240;
|
|
||||||
|
|
||||||
let count = 0;
|
let count = 0;
|
||||||
for (let y = 0; ; y += 8) {
|
for (let y = 0; ; y += 8) {
|
||||||
for (let x = 0; x < width; x += 4, count += 1) {
|
for (let x = 0; x < width; x += 4, count += 1) {
|
||||||
if (count >= MAX_TILES) {
|
if (count >= maxTiles) {
|
||||||
return tiles;
|
return tiles;
|
||||||
}
|
}
|
||||||
const tile = buildTile(buff, width, x, y, transparentIndex);
|
const tile = buildTile(buff, width, x, y, transparentIndex);
|
||||||
|
|
|
@ -406,8 +406,16 @@ function convertTileID(tileId, tileset) {
|
||||||
throw new Error('A maximum of 511 tiles are supported');
|
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,
|
// 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
|
// 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);
|
const mask_bit = (!tileset[tileIndex - 1].isSolid) && (GLOBALS.tileLayers.length !== 1);
|
||||||
|
|
||||||
// Build up a partial set of control bits
|
// Build up a partial set of control bits
|
||||||
|
|
Loading…
Reference in New Issue