diff --git a/build-image.bat b/build-image.bat index f8b47f3..f526bd4 100644 --- a/build-image.bat +++ b/build-image.bat @@ -15,3 +15,4 @@ REM Cadius does not overwrite files, so clear the root folder first REM Now copy files and folders as needed %CADIUS% ADDFILE %IMAGE% %FOLDER% src\\GTETestApp %CADIUS% ADDFILE %IMAGE% %FOLDER% emu\\test.pic +%CADIUS% ADDFILE %IMAGE% %FOLDER% emu\\bg1.bin diff --git a/package-lock.json b/package-lock.json index 07f2ab0..88655ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,12 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, + "pngjs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", + "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", + "dev": true + }, "watch": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/watch/-/watch-1.0.2.tgz", diff --git a/package.json b/package.json index 291d9a3..925551d 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "test": "npm run build && build-image.bat %npm_package_config_cadius% && %npm_package_config_gsport%", "debug": "%npm_package_config_crossrunner% src\\GTETestApp -Source src\\GTETestApp_S02_MAINSEG_Output.txt -Debug -CompatibilityLayer", "build": "%npm_package_config_merlin32% -V %npm_package_config_macros% src\\App.s", - "build:watch": "watch \"npm run build\" src" + "build:watch": "watch \"npm run build\" src", + "build:assets": "node ./tools/pngtoiigs.js ./assets/gba-cloud-bgnd-8-color.png ./emu/bg1.bin" }, "repository": { "type": "git", @@ -27,6 +28,7 @@ }, "homepage": "https://github.com/lscharen/iigs-game-engine#readme", "devDependencies": { + "pngjs": "^6.0.0", "watch": "latest" } } diff --git a/src/App.Main.s b/src/App.Main.s index 3424370..64caf5b 100644 --- a/src/App.Main.s +++ b/src/App.Main.s @@ -114,10 +114,15 @@ EvtLoop brl Exit :1 cmp #'l' - bne :2 + bne :1_1 jsr DoLoadPic bra EvtLoop +:1_1 cmp #'b' + bne :2 + jsr DoLoadBG1 + bra EvtLoop + :2 cmp #'m' bne :3 jsr DumpBanks @@ -337,6 +342,16 @@ DoFrame jsr Render ; Render the play field rts +; Load a binary file in the BG1 buffer +DoLoadBG1 + lda BG1DataBank + xba + and #$FF00 + ora #$0001 ; Load directly into the BG1 buffer bank on Page 1 + ldx #BG1DataFile + jsr LoadFile + rts + ; Load a simple picture format onto the SHR screen DoLoadPic lda BankLoad @@ -516,8 +531,12 @@ GrafInit jsr SetPalette rts -DefaultPalette dw $0000,$007F,$0090,$0FF0 - dw $000F,$0080,$0f70,$0FFF +;DefaultPalette dw $0000,$007F,$0090,$0FF0 +; dw $000F,$0080,$0f70,$0FFF + dw $0fa9,$0ff0,$00e0,$04DF + dw $0d00,$078f,$0ccc,$0FFF + +DefaultPalette dw $0ADF,$0FF8,$0CD6,$09CF,$0AC6,$08A5,$0FFF,$0694 dw $0fa9,$0ff0,$00e0,$04DF dw $0d00,$078f,$0ccc,$0FFF @@ -716,6 +735,7 @@ msgLine3 str ' -> Return to Try Again' msgLine4 str ' -> Esc to Quit' ; Data storage +BG1DataFile strl '1/bg1.bin' ImageName strl '1/test.pic' MasterId ds 2 UserId ds 2 @@ -762,3 +782,7 @@ qtRec adrl $0000 + + + + diff --git a/src/blitter/Template.s b/src/blitter/Template.s index d83152f..de6d693 100644 --- a/src/blitter/Template.s +++ b/src/blitter/Template.s @@ -454,7 +454,7 @@ right_odd bit #$000B ; Check the bottom nibble bit #$0040 ; Check bit 6 to distinguish between JMP and all of the LDA variants bne r_is_jmp -long_1 stal *+4-base +long_1 stal *+4-base ; Everything else is a two-byte LDA opcode + PHA dfb $00,$00 bra r_is_pea+1 @@ -546,7 +546,9 @@ long_4 stal *+4-base dfb $00,$00 xba sep #$20 - bra :left_byte + pha + rep #$20 + 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 long_5 ldal entry_jmp+1-base @@ -615,3 +617,5 @@ top + + diff --git a/tools/pngtoiigs.js b/tools/pngtoiigs.js new file mode 100644 index 0000000..6913c62 --- /dev/null +++ b/tools/pngtoiigs.js @@ -0,0 +1,123 @@ +const fs = require('fs').promises; +const PNG = require("pngjs").PNG; +const process = require('process'); +const { Buffer } = require('buffer'); + +main(process.argv.slice(2)).then( + () => process.exit(0), + (e) => { + console.error(e); + process.exit(1); + } +); + +function findColorIndex(png, pixel) { + for (let i = 0; i < png.palette.length; i += 1) { + const color = png.palette[i]; + if (color.every((c, idx) => c === pixel[idx])) { + return i; + } + } + + return null; +} + +function pngToIIgsBuff(png) { + let i = 0; + const buff = Buffer.alloc(png.height * (png.width / 2), 0); + for (let y = 0; y < png.height; y += 1) { + for (let x = 0; x < png.width; x += 1, i += 4) { + const pixel = png.data.slice(i, i + 4); + const index = findColorIndex(png, pixel); + const j = i / 8; + + if (x % 2 === 0) { + buff[j] = buff[j] + (16 * index); + } + else { + buff[j] = buff[j] + index + } + } + } + + return buff; +} + +function pngToIIgsBuffRepeat(png) { + let i = 0; + const buff = Buffer.alloc(png.height * png.width, 0); + for (let y = 0; y < png.height; y += 1) { + for (let x = 0; x < png.width; x += 1, i += 4) { + const pixel = png.data.slice(i, i + 4); + const index = findColorIndex(png, pixel); + const j = y * png.width + Math.floor(x / 2); + + if (index > 15) { + console.warn('Pixel index greater than 15. Skipping...'); + continue; + } + + if (x % 2 === 0) { + buff[j] = 16 * index; + } + else { + buff[j] = buff[j] | index; + } + + buff[j + (png.width / 2)] = buff[j]; + } + } + + return buff; +} + +function paletteToIIgs(palette) { + const r = Math.round(palette[0] / 17); + const g = Math.round(palette[1] / 17); + const b = Math.round(palette[2] / 17); + + return '0' + r.toString(16).toUpperCase() + g.toString(16).toUpperCase() + b.toString(16).toUpperCase(); +} + +async function main(argv) { + const data = await fs.readFile(argv[0]); + const png = PNG.sync.read(data); + + if (png.colorType !== 3) { + console.warn('PNG must be in palette color type'); + return; + } + + if (png.palette.length > 16) { + console.warn('Too many colors. Must be 16 or less'); + return; + } + + // Dump the palette in IIgs hex format + console.log('Palette:'); + const hexCodes = png.palette.map(c => '$' + paletteToIIgs(c)); + console.log(hexCodes.join(',')); + + // Just convert a paletted PNG to IIgs memory format + let buff = null; + if (png.width === 512) { + console.log('Converting to BG1 format...'); + buff = pngToIIgsBuff(png); + } + + if (png.width === 256) { + console.log('Converting to BG1 format w/repeat...'); + buff = pngToIIgsBuffRepeat(png); + } + + if (png.width === 328) { + console.log('Converting to BG0 format...'); + buff = pngToIIgsBuff(png); + } + + if (buff && argv[1]) { + console.log(`Writing to output file ${argv[1]}`); + await fs.writeFile(argv[1], buff); + } +} +