Added gbc script I'm never using again
This commit is contained in:
247
scripts/gbc_old.js
Normal file
247
scripts/gbc_old.js
Normal file
@@ -0,0 +1,247 @@
|
||||
const fs = require('fs');
|
||||
const { PNG } = require('pngjs');
|
||||
const path = require('path');
|
||||
|
||||
const TRANSPARENT = { r: 0, g: 0, b: 0, a: 0 };
|
||||
const WHITE = { r: 255, g: 255, b : 255, a: 255 };
|
||||
const RED = { r: 255, g: 0, b: 0, a: 255 };
|
||||
|
||||
const TILE_WIDTH = 8;
|
||||
const TILE_HEIGHT = 8;
|
||||
|
||||
// Helpers
|
||||
const pixelIsSame = (left, right, alpha) => {
|
||||
if(left.r !== right.r) return false;
|
||||
if(left.g !== right.g) return false;
|
||||
if(left.b !== right.b) return false;
|
||||
if(!alpha) return true;
|
||||
return left.a === right.a;
|
||||
}
|
||||
|
||||
const imageOut = (pixels, width, fileName) => {
|
||||
const png = new PNG({
|
||||
width,
|
||||
height: pixels.length / width
|
||||
});
|
||||
|
||||
pixels.forEach((pixel, i) => {
|
||||
const x = i % width;
|
||||
const y = (i - x) / width;
|
||||
const idx = (width * y + x) << 2;
|
||||
png.data[idx] = pixel.r;
|
||||
png.data[idx+1] = pixel.g;
|
||||
png.data[idx+2] = pixel.b;
|
||||
png.data[idx+3] = pixel.a;
|
||||
});
|
||||
|
||||
if(!fs.existsSync('out')) fs.mkdirSync('out');
|
||||
|
||||
const out = PNG.sync.write(png);
|
||||
fs.writeFileSync(path.join('out', fileName), out);
|
||||
}
|
||||
|
||||
const imageIn = fileName => {
|
||||
const data = fs.readFileSync(fileName);
|
||||
const png = PNG.sync.read(data);
|
||||
const pixels = [];
|
||||
|
||||
for(let y = 0; y < png.height; y++) {
|
||||
for (let x = 0; x < png.width; x++) {
|
||||
let idx = (png.width * y + x) << 2;
|
||||
const r = png.data[idx];
|
||||
const g = png.data[idx+1];
|
||||
const b = png.data[idx+2];
|
||||
const a = png.data[idx+3];
|
||||
|
||||
let pixel = { r, g, b, a };
|
||||
if(a === 0) {
|
||||
pixel = { ...WHITE };
|
||||
} else {
|
||||
pixel.a = 255;
|
||||
}
|
||||
|
||||
pixels.push(pixel);
|
||||
}
|
||||
}
|
||||
|
||||
return { pixels, width: png.width, height: png.height };
|
||||
}
|
||||
|
||||
const tileFromPixel = (x, y, original) => {
|
||||
const byEightX = Math.floor(x / 8);
|
||||
const byEightY = Math.floor(y / 8);
|
||||
const byEightWidth = Math.floor(original.width / 8);
|
||||
const byEightId = byEightX + (byEightY * byEightWidth);
|
||||
|
||||
return { x: byEightX, y: byEightY, columns: byEightWidth, id: byEightId };
|
||||
}
|
||||
|
||||
// Read Input File
|
||||
const original = imageIn('bruh.png');
|
||||
|
||||
const columns = (original.width / TILE_WIDTH);
|
||||
const rows = (original.height / TILE_HEIGHT);
|
||||
|
||||
// Foreach pixel
|
||||
const palette = [];
|
||||
const paletteByEight = [];
|
||||
const withPaletteOverflows = [];
|
||||
|
||||
for(let y = 0; y < original.height; y++) {
|
||||
for(let x = 0; x < original.width; x++) {
|
||||
const id = x + (y * original.width);
|
||||
const pixel = original.pixels[id];
|
||||
let errorPixel = { ...pixel };
|
||||
const tile = tileFromPixel(x, y, original);
|
||||
|
||||
// Handle palettes
|
||||
if(pixel.a != 0) {
|
||||
const pb8 = (paletteByEight[tile.id] = paletteByEight[tile.id] || []);
|
||||
|
||||
if(!pb8.some(p => pixelIsSame(pixel, p))) {
|
||||
pb8.push(pixel);
|
||||
}
|
||||
// Handle palette overflow
|
||||
if(pb8.length > 4) errorPixel = { ...RED };
|
||||
|
||||
// Append to palette
|
||||
if(!palette.some(p => pixelIsSame(pixel, p))) palette.push(pixel);
|
||||
}
|
||||
|
||||
withPaletteOverflows.push(errorPixel);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the palette set image
|
||||
const outPaletteByEight = [];
|
||||
let outByEightWidth = 1;
|
||||
paletteByEight.forEach((pal,y) => {
|
||||
pal.forEach((p,x) => {
|
||||
outByEightWidth = Math.max(outByEightWidth, x+1);
|
||||
})
|
||||
});
|
||||
paletteByEight.forEach((pal,y) => {
|
||||
for(let x = 0; x < outByEightWidth; x++) {
|
||||
outPaletteByEight.push(x >= pal.length ? TRANSPARENT : pal[x]);
|
||||
}
|
||||
});
|
||||
|
||||
// Now determine for each TILE what palette to use.
|
||||
const paletteGroups = [];
|
||||
const gbVersion = [];
|
||||
const paletteImage = [];
|
||||
|
||||
for(let y = 0; y < original.height; y++) {
|
||||
for(let x = 0; x < original.width; x++) {
|
||||
const id = x + (y * original.width);
|
||||
const pixel = original.pixels[id];
|
||||
const tile = tileFromPixel(x, y, original);
|
||||
|
||||
// Get the palette
|
||||
const paletteSet = paletteByEight[tile.id];
|
||||
|
||||
// Check for matching
|
||||
let palId = paletteGroups.findIndex(pg => {
|
||||
// Check for cases where one of the pallet group palettes may have
|
||||
// less pixels than the current set we're checking, e.g. we do a tile that
|
||||
// has only two colors, then we iterate over a tile with 4 colors that has
|
||||
// two colors shared with that other tile. In that case we just add our
|
||||
// two extra colors.
|
||||
if(paletteSet.length > pg.length) {
|
||||
return pg.every(p => paletteSet.some(pss => pixelIsSame(pss, p)));
|
||||
} else {
|
||||
return paletteSet.every(p => pg.some(pgs => pixelIsSame(pgs, p)));
|
||||
}
|
||||
});
|
||||
|
||||
if(palId === -1) {
|
||||
palId = paletteGroups.length;
|
||||
paletteGroups.push(paletteSet);
|
||||
}
|
||||
|
||||
const paletteGroupSet = paletteGroups[palId];
|
||||
|
||||
// This is where we correct the missing pixels if we share that tileset from
|
||||
// earlier
|
||||
paletteSet.forEach(ps => {
|
||||
const existing = paletteGroupSet.some(pgs => pixelIsSame(pgs, ps));
|
||||
if(existing) return;
|
||||
paletteGroupSet.push(ps);
|
||||
});
|
||||
|
||||
// Sort the paletteGroupSet...
|
||||
const pgsGetWeight = thing => {
|
||||
return thing.r + thing.g + thing.b;
|
||||
}
|
||||
paletteGroupSet.sort((l,r) => {
|
||||
return pgsGetWeight(l) - pgsGetWeight(r);
|
||||
});
|
||||
|
||||
const examples = [
|
||||
/* 0 */{ r: 0, g: 0, b: 0, a: 255 },
|
||||
/* 1 */{ r: 255, g: 0, b: 0, a: 255 },
|
||||
/* 2 */{ r: 0, g: 255, b: 0, a: 255 },
|
||||
/* 3 */{ r: 0, g: 0, b: 255, a: 255 },
|
||||
/* 4 */{ r: 255, g: 255, b: 0, a: 255 },
|
||||
/* 5 */{ r: 255, g: 0, b: 255, a: 255 },
|
||||
/* 6 */{ r: 0, g: 255, b: 255, a: 255 },
|
||||
/* 7 */{ r: 255, g: 255, b: 255, a: 255 },
|
||||
|
||||
/* S */{ r: 100, g: 0, b: 0, a: 255 },
|
||||
/* S */{ r: 0, g: 100, b: 0, a: 255 },
|
||||
/* S */{ r: 0, g: 0, b: 100, a: 255 },
|
||||
/* S */{ r: 100, g: 100, b: 0, a: 255 },
|
||||
/* S */{ r: 0, g: 100, b: 100, a: 255 },
|
||||
/* S */{ r: 100, g: 0, b: 100, a: 255 },
|
||||
/* S */{ r: 100, g: 100, b: 100, a: 255 },
|
||||
];
|
||||
paletteImage.push(examples[palId]);
|
||||
|
||||
const pixelIndex = paletteGroupSet.findIndex(ps => pixelIsSame(ps, pixel));
|
||||
const nonColor = [
|
||||
{ r: 8, g: 24, b: 32, a: 255 },
|
||||
{ r: 52, g: 104, b: 86, a: 255 },
|
||||
{ r: 136, g: 192, b: 112, a: 255 },
|
||||
{ r: 224, g: 248, b: 208, a: 255 }
|
||||
];
|
||||
gbVersion.push(nonColor[pixelIndex % nonColor.length]);
|
||||
}
|
||||
}
|
||||
console.log('Found', paletteGroups.length, 'palettes');
|
||||
|
||||
imageOut(original.pixels, original.width, 'original.png');
|
||||
imageOut(withPaletteOverflows, original.width, 'errors.png');
|
||||
imageOut(palette, palette.length, 'palette.png');
|
||||
imageOut(outPaletteByEight, outByEightWidth, 'paletteByEight.png');
|
||||
imageOut(paletteImage, original.width, 'palettes.png');
|
||||
imageOut(gbVersion, original.width, 'gameboy.png');
|
||||
|
||||
// Now generate the GB files
|
||||
// let rearranged = [];
|
||||
// let n = 0;
|
||||
// for(let i = 0; i < columns * rows; i++) {
|
||||
// const tileX = i % columns;
|
||||
// const tileY = Math.floor(i / columns) % rows;
|
||||
|
||||
// for(let y = 0; y < TILE_HEIGHT; y++) {
|
||||
// for(let x = 0; x < TILE_WIDTH; x++) {
|
||||
// const px = (tileX * TILE_WIDTH) + x;
|
||||
// const py = (tileY * TILE_HEIGHT) + y;
|
||||
// const pi = (py * png.width) + px;
|
||||
// rearranged[n++] = original.pixels[pi];
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Now turn into a tileset
|
||||
// const bits = [];
|
||||
// for(let i = 0; i < rearranged.length; i += TILE_WIDTH) {
|
||||
// let lowBits = 0x00;
|
||||
// let highBits = 0x00;
|
||||
// for(let j = 0; j < TILE_WIDTH; j++) {
|
||||
// const pixel = rearranged[i + j];
|
||||
// lowBits = lowBits | ((pixel & 0x01) << (7-j));
|
||||
// highBits = highBits | ((pixel & 0x02) >> 1 << (7-j));
|
||||
// }
|
||||
// bits.push(lowBits, highBits);
|
||||
// }
|
Reference in New Issue
Block a user