diff --git a/bin/flutter-ST06T.BIN b/bin/flutter-ST06T.BIN new file mode 100644 index 0000000..a9e276e Binary files /dev/null and b/bin/flutter-ST06T.BIN differ diff --git a/index.ts b/index.ts index 8358118..73efe90 100644 --- a/index.ts +++ b/index.ts @@ -24,6 +24,7 @@ import { } from "./src/EncodeWeapon"; import { updateDemoLogo } from "./src/GAME"; import { updateFlutterPaintings } from "./src/ST05T"; +import { updateFlutterPaintings2 } from "./src/ST06T"; import { updateYosyonkePaintings } from "./src/ST47T"; import { updateYosyonkePaintings2 } from "./src/ST0AT"; import { updateYosyonkePaintings3 } from "./src/ST0CT"; @@ -217,7 +218,11 @@ replaceDrillArm("miku/weapons/PL00R10_001.obj"); **/ encodeApronMegaman(); -updateST03T("miku/apron/body-01.png", "miku/faces/ST03T.png"); +updateST03T( + "miku/apron/body-01.png", + "miku/faces/ST03T.png", + "miku/paintings/dashie2.png", +); updateSceneModel(); updateDemoLogo("miku/title-smol.png"); @@ -226,6 +231,9 @@ updateFlutterPaintings( "miku/paintings/roll-room.png", "miku/paintings/roll-lofi.png", ); + +updateFlutterPaintings2("miku/paintings/dashie2.png"); + updateYosyonkePaintings( "miku/paintings/room-203.png", "miku/paintings/room-203-poster.png", diff --git a/miku/paintings/dashie.png b/miku/paintings/dashie.png new file mode 100644 index 0000000..dcf679e Binary files /dev/null and b/miku/paintings/dashie.png differ diff --git a/miku/paintings/dashie2.png b/miku/paintings/dashie2.png new file mode 100644 index 0000000..d08e056 Binary files /dev/null and b/miku/paintings/dashie2.png differ diff --git a/src/EncodeRom.ts b/src/EncodeRom.ts index 5c9fa1c..5ae4640 100644 --- a/src/EncodeRom.ts +++ b/src/EncodeRom.ts @@ -574,6 +574,7 @@ const encodeRom = () => { "cut-ST2501.BIN", "GAME.BIN", "flutter-ST05T.BIN", + "flutter-ST06T.BIN", "yosyonke-ST47T.BIN", "yosyonke-ST0AT.BIN", "yosyonke-ST0CT.BIN", diff --git a/src/ST0305.ts b/src/ST0305.ts index 0f90667..76850c5 100644 --- a/src/ST0305.ts +++ b/src/ST0305.ts @@ -65,6 +65,44 @@ const CUT_SCENES = [ }, ]; +const updateDashie = (bin: Buffer, pngPath: string) => { + const pngData = readFileSync(pngPath); + + const imgOfs = 0x1a000; + const pal: number[] = []; + + const encodedLogo = encodeCutSceneTexture(pal, pngData); + const encodedTexture = Buffer.from(bin.subarray(0x1a800, 0x22800)); + + // Update Palette + const palOfs = 0x23800; + const red = encodeTexel(255, 0, 0, 255); + for (let i = 0; i < pal.length; i++) { + bin.writeUInt16LE(pal[i], palOfs + 0x30 + i * 2); + // bin.writeUInt16LE(red, palOfs + 0x30 + i * 2); + } + + const ROW_LEN = 0x80; + const X_START = 0; + const Y_START = 88; + let texOfs = ROW_LEN * Y_START; // + PAL_OFS; + let logoOfs = 0; + const HEIGHT = 40; + const WIDTH = 64; + for (let y = 0; y < HEIGHT; y++) { + texOfs += X_START / 2; + for (let x = 0; x < WIDTH / 2; x++) { + encodedTexture[texOfs++] = encodedLogo[logoOfs++]; + } + texOfs += (256 - X_START - WIDTH) / 2; + } + + let ofs = 0x1a800; + for (let i = 0; i < encodedTexture.length; i++) { + bin[ofs + i] = encodedTexture[i]; + } +}; + const encodeCutScenes = () => { const palette: number[] = []; @@ -535,6 +573,7 @@ const fixEggs = (buffer: Buffer) => { const encodeApronMegaman = () => { encodeCutScenes(); const file = readFileSync("out/cut-ST0305.BIN"); + updateDashie(file, "miku/paintings/dashie2.png"); const contentEnd = file.readUInt32LE(0x04); const buffer = file.subarray(0x30, 0xe000); diff --git a/src/ST03T.ts b/src/ST03T.ts index a9a4a59..320dec5 100644 --- a/src/ST03T.ts +++ b/src/ST03T.ts @@ -29,6 +29,97 @@ import { readPixel, } from "./EncodeTexture"; +const decompress = (src: Buffer) => { + const tim = { + type: src.readUInt32LE(0x00), + fullSize: src.readUInt32LE(0x04), + paletteX: src.readUInt16LE(0x0c), + paletteY: src.readUInt16LE(0x0e), + colorCount: src.readUInt16LE(0x10), + paletteCount: src.readUInt16LE(0x12), + imageX: src.readUInt16LE(0x14), + imageY: src.readUInt16LE(0x16), + width: src.readUInt16LE(0x18), + height: src.readUInt16LE(0x1a), + bitfieldSize: src.readUInt16LE(0x24), + payloadSize: src.readUInt16LE(0x26), + }; + + switch (tim.colorCount) { + case 16: + tim.width *= 4; + break; + case 256: + tim.width *= 2; + break; + default: + tim.paletteCount *= tim.colorCount / 16; + tim.colorCount = 16; + tim.width *= 4; + break; + } + + const { fullSize, bitfieldSize } = tim; + const bitfield: number[] = new Array(); + const target = Buffer.alloc(fullSize); + + // Read Bitfield + + const bitfieldBuffer = src.subarray(0x30, 0x30 + bitfieldSize); + let ofs = 0x30; + for (let i = 0; i < bitfieldSize; i += 4) { + const dword = src.readUInt32LE(ofs + i); + for (let k = 31; k > -1; k--) { + bitfield.push(dword & (1 << k) ? 1 : 0); + } + } + + ofs += bitfieldSize; + const payloadStart = 0; + + // Decompress + + let outOfs = 0; + let windowOfs = 0; + let cmdCount = 0; + let bytes = 0; + + for (let i = 0; i < bitfield.length; i++) { + const bit = bitfield[i]; + if (outOfs === fullSize) { + const payload = src.subarray(0x30 + bitfieldSize, ofs); + break; + } + + const word = src.readUInt16LE(ofs); + ofs += 2; + + switch (bit) { + case 0: + target.writeUInt16LE(word, outOfs); + outOfs += 2; + break; + case 1: + if (word === 0xffff) { + windowOfs += 0x2000; + cmdCount = 0; + bytes = 0; + } else { + cmdCount++; + const copyFrom = windowOfs + ((word >> 3) & 0x1fff); + const copyLen = ((word & 0x07) + 2) * 2; + bytes += copyLen; + for (let i = 0; i < copyLen; i++) { + target[outOfs++] = target[copyFrom + i]; + } + } + break; + } + } + + return target; +}; + /** * Updates the face texture in the prodived archive * @param src Buffer of the bin file to be updated @@ -393,12 +484,96 @@ const updateEggs = (src: Buffer) => { // } }; +const updateDashie = (bin: Buffer, pngPath: string) => { + const pngData = readFileSync(pngPath); + + const imgOfs = 0x2e000; + const pal: number[] = []; + + const encodedLogo = encodeCutSceneTexture(pal, pngData); + const mpTexture = decompress(Buffer.from(bin.subarray(imgOfs))); + + const includedPal = Buffer.from(mpTexture.subarray(0, 0x20)); + const encodedTexture = Buffer.from(mpTexture.subarray(0x20)); + + // Update Palette + const palOfs = 0x33800; + const red = encodeTexel(255, 0, 0, 255); + for (let i = 0; i < pal.length; i++) { + bin.writeUInt16LE(pal[i], palOfs + 0x30 + i * 2); + // bin.writeUInt16LE(red, palOfs + 0x30 + i * 2); + } + + const ROW_LEN = 0x80; + const X_START = 0; + const Y_START = 88; + let texOfs = ROW_LEN * Y_START; // + PAL_OFS; + let logoOfs = 0; + const HEIGHT = 40; + const WIDTH = 64; + for (let y = 0; y < HEIGHT; y++) { + texOfs += X_START / 2; + for (let x = 0; x < WIDTH / 2; x++) { + encodedTexture[texOfs++] = encodedLogo[logoOfs++]; + } + texOfs += (256 - X_START - WIDTH) / 2; + } + + // console.log("Logo Pos: 0x%s", logoOfs.toString(16)); + + const imageData: number[] = new Array(); + for (let ofs = 0; ofs < encodedTexture.length; ofs++) { + const byte = encodedTexture.readUInt8(ofs); + + imageData.push(byte & 0xf); + imageData.push(byte >> 4); + } + + const [bodyBitField, compressedBody] = compressNewTexture( + includedPal, + encodedTexture, + 1, + ); + const len = bodyBitField.length + compressedBody.length; + + for (let i = 0x2e030; i < 0x321b0; i++) { + bin[i] = 0; + } + + let ofs = 0x2e030; + for (let i = 0; i < bodyBitField.length; i++) { + bin[ofs++] = bodyBitField[i]; + } + + for (let i = 0; i < compressedBody.length; i++) { + bin[ofs++] = compressedBody[i]; + } + + if (ofs <= 0x32000) { + console.log("too short!!!"); + throw new Error("dashie painting too short"); + } else if (len > 0x32800) { + console.log("too long"); + throw new Error("dashie painting too long"); + } else { + console.log("yaya!!!"); + } + + console.log("End: 0x%s", ofs.toString(16)); + bin.writeInt16LE(bodyBitField.length, 0x2e024); +}; + /** * Takes a face texture and a body texture to replace in the opening cut scene * @param bodyTexture relative path to png file for body texture * @param faceTexture relative path to png file for face texture + * @param dashie relative path to png file for painting in flutter living room */ -const updateST03T = (bodyTexture: string, faceTexture: string) => { +const updateST03T = ( + bodyTexture: string, + faceTexture: string, + dashie: string, +) => { // Read the input files const src = readFileSync("bin/cut-ST03T.BIN"); const body = readFileSync(bodyTexture); @@ -409,6 +584,7 @@ const updateST03T = (bodyTexture: string, faceTexture: string) => { updateFace(src, face); // updateEggs(src); + updateDashie(src, dashie); // Write the resulting Archive writeFileSync("out/cut-ST03T.BIN", src); }; diff --git a/src/ST06T.ts b/src/ST06T.ts new file mode 100644 index 0000000..f3d06f1 --- /dev/null +++ b/src/ST06T.ts @@ -0,0 +1,222 @@ +/** + + Miku-Legends-2 + Copyright (C) 2024, DashGL Project + By Kion (kion@dashgl.com) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +**/ + +import { readFileSync, writeFileSync } from "fs"; +import { + encodeCutSceneTexture, + compressNewTexture, + encodeTexel, +} from "./EncodeTexture"; +import { PNG } from "pngjs"; + +type Pixel = { + r: number; + g: number; + b: number; + a: number; +}; + +const wordToColor = (word: number): Pixel => { + const r = ((word >> 0x00) & 0x1f) << 3; + const g = ((word >> 0x05) & 0x1f) << 3; + const b = ((word >> 0x0a) & 0x1f) << 3; + const a = word > 0 ? 255 : 0; + return { r, g, b, a }; +}; + +const decompress = (src: Buffer) => { + const tim = { + type: src.readUInt32LE(0x00), + fullSize: src.readUInt32LE(0x04), + paletteX: src.readUInt16LE(0x0c), + paletteY: src.readUInt16LE(0x0e), + colorCount: src.readUInt16LE(0x10), + paletteCount: src.readUInt16LE(0x12), + imageX: src.readUInt16LE(0x14), + imageY: src.readUInt16LE(0x16), + width: src.readUInt16LE(0x18), + height: src.readUInt16LE(0x1a), + bitfieldSize: src.readUInt16LE(0x24), + payloadSize: src.readUInt16LE(0x26), + }; + + switch (tim.colorCount) { + case 16: + tim.width *= 4; + break; + case 256: + tim.width *= 2; + break; + default: + tim.paletteCount *= tim.colorCount / 16; + tim.colorCount = 16; + tim.width *= 4; + break; + } + + const { fullSize, bitfieldSize } = tim; + const bitfield: number[] = new Array(); + const target = Buffer.alloc(fullSize); + + // Read Bitfield + + const bitfieldBuffer = src.subarray(0x30, 0x30 + bitfieldSize); + let ofs = 0x30; + for (let i = 0; i < bitfieldSize; i += 4) { + const dword = src.readUInt32LE(ofs + i); + for (let k = 31; k > -1; k--) { + bitfield.push(dword & (1 << k) ? 1 : 0); + } + } + + ofs += bitfieldSize; + const payloadStart = 0; + + // Decompress + + let outOfs = 0; + let windowOfs = 0; + let cmdCount = 0; + let bytes = 0; + + for (let i = 0; i < bitfield.length; i++) { + const bit = bitfield[i]; + if (outOfs === fullSize) { + const payload = src.subarray(0x30 + bitfieldSize, ofs); + break; + } + + const word = src.readUInt16LE(ofs); + ofs += 2; + + switch (bit) { + case 0: + target.writeUInt16LE(word, outOfs); + outOfs += 2; + break; + case 1: + if (word === 0xffff) { + windowOfs += 0x2000; + cmdCount = 0; + bytes = 0; + } else { + cmdCount++; + const copyFrom = windowOfs + ((word >> 3) & 0x1fff); + const copyLen = ((word & 0x07) + 2) * 2; + bytes += copyLen; + for (let i = 0; i < copyLen; i++) { + target[outOfs++] = target[copyFrom + i]; + } + } + break; + } + } + + return target; +}; + +const updateDashie = (bin: Buffer, pngPath: string) => { + const pngData = readFileSync(pngPath); + + const imgOfs = 0x20800; + const pal: number[] = []; + + const encodedLogo = encodeCutSceneTexture(pal, pngData); + const mpTexture = decompress(Buffer.from(bin.subarray(imgOfs))); + + const includedPal = Buffer.from(mpTexture.subarray(0, 0x20)); + const encodedTexture = Buffer.from(mpTexture.subarray(0x20)); + + // Update Palette + const palOfs = 0x26000; + const red = encodeTexel(255, 0, 0, 255); + for (let i = 0; i < pal.length; i++) { + bin.writeUInt16LE(pal[i], palOfs + 0x30 + i * 2); + // bin.writeUInt16LE(red, palOfs + 0x30 + i * 2); + } + + const ROW_LEN = 0x80; + const X_START = 0; + const Y_START = 88; + let texOfs = ROW_LEN * Y_START; // + PAL_OFS; + let logoOfs = 0; + const HEIGHT = 40; + const WIDTH = 64; + for (let y = 0; y < HEIGHT; y++) { + texOfs += X_START / 2; + for (let x = 0; x < WIDTH / 2; x++) { + encodedTexture[texOfs++] = encodedLogo[logoOfs++]; + } + texOfs += (256 - X_START - WIDTH) / 2; + } + + // console.log("Logo Pos: 0x%s", logoOfs.toString(16)); + + const imageData: number[] = new Array(); + for (let ofs = 0; ofs < encodedTexture.length; ofs++) { + const byte = encodedTexture.readUInt8(ofs); + + imageData.push(byte & 0xf); + imageData.push(byte >> 4); + } + + const [bodyBitField, compressedBody] = compressNewTexture( + includedPal, + encodedTexture, + 1, + ); + const len = bodyBitField.length + compressedBody.length; + + for (let i = 0x20830; i < 0x24a00; i++) { + bin[i] = 0; + } + + let ofs = 0x20830; + for (let i = 0; i < bodyBitField.length; i++) { + bin[ofs++] = bodyBitField[i]; + } + + for (let i = 0; i < compressedBody.length; i++) { + bin[ofs++] = compressedBody[i]; + } + + if (ofs <= 0x24800) { + console.log("too short!!!"); + throw new Error("dashie painting too short"); + } else if (len > 0x25000) { + console.log("too long"); + throw new Error("dashie painting too long"); + } else { + console.log("yaya!!!"); + } + + console.log("End: 0x%s", ofs.toString(16)); + bin.writeInt16LE(bodyBitField.length, 0x20824); +}; + +const updateFlutterPaintings2 = (dashie: string) => { + const bin = readFileSync("bin/flutter-ST06T.BIN"); + updateDashie(bin, dashie); + writeFileSync("out/flutter-ST06T.BIN", bin); +}; + +export default updateFlutterPaintings2; +export { updateFlutterPaintings2 }; diff --git a/test/yosyonke.skip b/test/yosyonke.skip index daa3241..8701ed2 100644 --- a/test/yosyonke.skip +++ b/test/yosyonke.skip @@ -163,7 +163,97 @@ const renderImage = ( for (let y = 0; y < height; y++) { for (var x = 0; x < width; x++) { const colorIndex = imageData[index++]; - const { r, g, b, a } = wordToColor(polly[colorIndex!]); + + // const { r, g, b, a } = wordToColor(polly[colorIndex!]); + const { r, g, b, a } = palette[colorIndex!]; + + png.data[dst++] = r; + png.data[dst++] = g; + png.data[dst++] = b; + png.data[dst++] = a; + } + } + + // Export file + const buffer = PNG.sync.write(png); + writeFileSync(`out/${base}_${pos.toString(16)}.png`, buffer); +}; + +const renderImg = ( + src: Buffer, + base: string, + pos: number, + palette: Pixel[], +) => { + const tim = { + type: src.readUInt32LE(0x00), + fullSize: src.readUInt32LE(0x04), + paletteX: src.readUInt16LE(0x0c), + paletteY: src.readUInt16LE(0x0e), + colorCount: src.readUInt16LE(0x10), + paletteCount: src.readUInt16LE(0x12), + imageX: src.readUInt16LE(0x14), + imageY: src.readUInt16LE(0x16), + width: src.readUInt16LE(0x18), + height: src.readUInt16LE(0x1a), + bitfieldSize: src.readUInt16LE(0x24), + payloadSize: src.readUInt16LE(0x26), + }; + + switch (tim.colorCount) { + case 16: + tim.width *= 4; + break; + case 256: + tim.width *= 2; + break; + default: + tim.paletteCount *= tim.colorCount / 16; + tim.colorCount = 16; + tim.width *= 4; + break; + } + + const { fullSize } = tim; + + // Read Bitfield + + let ofs = 0x30; + const { colorCount, paletteCount } = tim; + const polly: Pixel[][] = new Array(); + for (let i = 0; i < paletteCount; i++) { + polly[i] = new Array(); + for (let k = 0; k < colorCount; k++) { + const word = src.readUInt16LE(ofs); + ofs += 2; + polly[i].push(wordToColor(word)); + } + } + const diff = ofs - 0x30; + ofs = 0x800; + + // Read the image data + const imageData: number[] = new Array(); + for (let i = 0; i < fullSize - diff; i++) { + const byte = src.readUInt8(ofs); + ofs++; + if (colorCount === 256) { + imageData.push(byte); + } else { + imageData.push(byte & 0xf); + imageData.push(byte >> 4); + } + } + + const { width, height } = tim; + const png = new PNG({ width, height }); + + let index = 0; + let dst = 0; + for (let y = 0; y < height; y++) { + for (var x = 0; x < width; x++) { + const colorIndex = imageData[index++]; + const { r, g, b, a } = palette[colorIndex!]; png.data[dst++] = r; png.data[dst++] = g; png.data[dst++] = b; @@ -176,63 +266,63 @@ const renderImage = ( writeFileSync(`out/${base}_${pos.toString(16)}.png`, buffer); }; -// test("it should search for textures in the yosyonke", () => { -// const src = readFileSync("bin/carlbania-ST20T.BIN"); -// const pals: Pixel[][] = [ -// [ -// { r: 0, g: 0, b: 0, a: 0 }, -// { r: 0, g: 0, b: 0, a: 255 }, -// { r: 16, g: 16, b: 16, a: 255 }, -// { r: 32, g: 32, b: 32, a: 255 }, -// { r: 48, g: 48, b: 48, a: 255 }, -// { r: 64, g: 64, b: 64, a: 255 }, -// { r: 72, g: 72, b: 72, a: 255 }, -// { r: 90, g: 90, b: 90, a: 255 }, -// { r: 110, g: 110, b: 110, a: 255 }, -// { r: 120, g: 120, b: 120, a: 255 }, -// { r: 130, g: 130, b: 130, a: 255 }, -// { r: 140, g: 140, b: 140, a: 255 }, -// { r: 150, g: 150, b: 150, a: 255 }, -// { r: 160, g: 160, b: 160, a: 255 }, -// { r: 190, g: 190, b: 190, a: 255 }, -// { r: 210, g: 210, b: 210, a: 255 }, -// { r: 220, g: 220, b: 220, a: 255 }, -// { r: 255, g: 255, b: 255, a: 255 }, -// ], -// ]; - -// for (let i = 0; i < src.length; i += 0x800) { -// const tim = { -// type: src.readUInt32LE(i + 0x00), -// fullSize: src.readUInt32LE(i + 0x04), -// paletteX: src.readUInt16LE(i + 0x0c), -// paletteY: src.readUInt16LE(i + 0x0e), -// colorCount: src.readUInt16LE(i + 0x10), -// paletteCount: src.readUInt16LE(i + 0x12), -// imageX: src.readUInt16LE(i + 0x14), -// imageY: src.readUInt16LE(i + 0x16), -// width: src.readUInt16LE(i + 0x18), -// height: src.readUInt16LE(i + 0x1a), -// bitfieldSize: src.readUInt16LE(i + 0x24), -// payloadSize: src.readUInt16LE(i + 0x26), -// }; - -// if (tim.type !== 2 && tim.type !== 3) { -// continue; -// } - -// if (tim.width == 0 || tim.height == 0) { -// continue; -// } - -// const img = src.subarray(i); -// renderImage(img, "nino", i, pals[0]); -// } -// }); +test("it should search for textures in the flutter", () => { + const src = readFileSync("bin/cut-ST0305.BIN"); + const pals: Pixel[][] = [ + [ + { r: 0, g: 0, b: 0, a: 0 }, + { r: 0, g: 0, b: 0, a: 255 }, + { r: 16, g: 16, b: 16, a: 255 }, + { r: 32, g: 32, b: 32, a: 255 }, + { r: 48, g: 48, b: 48, a: 255 }, + { r: 64, g: 64, b: 64, a: 255 }, + { r: 72, g: 72, b: 72, a: 255 }, + { r: 90, g: 90, b: 90, a: 255 }, + { r: 110, g: 110, b: 110, a: 255 }, + { r: 120, g: 120, b: 120, a: 255 }, + { r: 130, g: 130, b: 130, a: 255 }, + { r: 140, g: 140, b: 140, a: 255 }, + { r: 150, g: 150, b: 150, a: 255 }, + { r: 160, g: 160, b: 160, a: 255 }, + { r: 190, g: 190, b: 190, a: 255 }, + { r: 210, g: 210, b: 210, a: 255 }, + { r: 220, g: 220, b: 220, a: 255 }, + { r: 255, g: 255, b: 255, a: 255 }, + ], + ]; + + for (let i = 0; i < src.length; i += 0x800) { + const tim = { + type: src.readUInt32LE(i + 0x00), + fullSize: src.readUInt32LE(i + 0x04), + paletteX: src.readUInt16LE(i + 0x0c), + paletteY: src.readUInt16LE(i + 0x0e), + colorCount: src.readUInt16LE(i + 0x10), + paletteCount: src.readUInt16LE(i + 0x12), + imageX: src.readUInt16LE(i + 0x14), + imageY: src.readUInt16LE(i + 0x16), + width: src.readUInt16LE(i + 0x18), + height: src.readUInt16LE(i + 0x1a), + bitfieldSize: src.readUInt16LE(i + 0x24), + payloadSize: src.readUInt16LE(i + 0x26), + }; + + if (tim.type !== 2) { + continue; + } + + if (tim.width == 0 || tim.height == 0) { + continue; + } + + const img = src.subarray(i); + renderImg(img, "scene", i, pals[0]); + } +}); test("it should search for room203 palette", () => { - const src = readFileSync("bin/carlbania-ST20T.BIN"); - const img = src.subarray(0x3c000); + const src = readFileSync("bin/cut-ST0305.BIN"); + const img = src.subarray(0x1a000); for (let i = 0; i < src.length; i += 0x800) { const tim = { @@ -264,46 +354,6 @@ test("it should search for room203 palette", () => { pal.push(wordToColor(word)); } - renderImage(img, "poster", i, pal); - break; + renderImg(img, "poster", i, pal); } }); - -// test("it should search for roll palette", () => { -// const src = readFileSync("out/flutter-ST05T.BIN"); - -// const img = src.subarray(0x10000); - -// for (let i = 0; i < src.length; i += 0x800) { -// const tim = { -// type: src.readUInt32LE(i + 0x00), -// fullSize: src.readUInt32LE(i + 0x04), -// paletteX: src.readUInt16LE(i + 0x0c), -// paletteY: src.readUInt16LE(i + 0x0e), -// colorCount: src.readUInt16LE(i + 0x10), -// paletteCount: src.readUInt16LE(i + 0x12), -// imageX: src.readUInt16LE(i + 0x14), -// imageY: src.readUInt16LE(i + 0x16), -// width: src.readUInt16LE(i + 0x18), -// height: src.readUInt16LE(i + 0x1a), -// bitfieldSize: src.readUInt16LE(i + 0x24), -// payloadSize: src.readUInt16LE(i + 0x26), -// }; - -// if (tim.type !== 2) { -// continue; -// } - -// if (tim.paletteX === 0 && tim.paletteY === 0) { -// continue; -// } - -// const pal: Pixel[] = []; -// for (let k = 0; k < 16; k++) { -// const word = src.readUInt16LE(i + 0x30 + k * 2); -// pal.push(wordToColor(word)); -// } - -// renderImage(img, "roll", i, pal); -// } -// });