Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | 5x 5x 5x 5x 149760x 149760x 149760x 149760x 5x 9360x 5x 4680x 4680x 37440x 37440x 4680x 5x 10x 10x 10x 6x 6x 10x 4680x 4680x 4680x 4680x 4680x 4680x 5417x 4680x 4457x 4457x 223x 223x 223x 10x 5x 5x 5x 5x 5x 90x 2880x 5x | import {
TILE_COLOR_PROP_FLIP_VERTICAL,
TILE_COLOR_PROP_FLIP_HORIZONTAL,
TILE_SIZE,
} from "consts";
import {
IndexedImage,
indexedImageTo2bppTileData,
sliceIndexedImage,
} from "shared/lib/tiles/indexedImage";
import { TileLookup, hashTileData } from "shared/lib/tiles/tileData";
interface AutoFlipResult {
tileData: Uint8Array[];
tileAttrs: number[];
tilesetData: Uint8Array[];
}
const reverseByte = (value: number): number => {
let output = value;
output = ((output & 0xf0) >> 4) | ((output & 0x0f) << 4);
output = ((output & 0xcc) >> 2) | ((output & 0x33) << 2);
return ((output & 0xaa) >> 1) | ((output & 0x55) << 1);
};
const flipTileDataX = (tile: Uint8Array): Uint8Array =>
Uint8Array.from(tile, reverseByte);
const flipTileDataY = (tile: Uint8Array): Uint8Array => {
const output = new Uint8Array(tile.length);
for (let row = 0; row < 8; row++) {
output[row * 2] = tile[(7 - row) * 2] ?? 0;
output[row * 2 + 1] = tile[(7 - row) * 2 + 1] ?? 0;
}
return output;
};
export const autoFlipTileData = ({
tileData,
tileColors,
commonTileData,
}: {
tileData: Uint8Array[];
tileColors: readonly number[];
commonTileData: Uint8Array[];
}): AutoFlipResult => {
const newTileData: Uint8Array[] = [];
const newTileColors = [...tileColors];
const tileLookup: TileLookup = commonTileData.reduce((memo, data) => {
memo[hashTileData(data)] = data;
return memo;
}, {} as TileLookup);
tileData.forEach((origData, index) => {
const attr = tileColors[index] ?? 0;
const clearedAttr =
attr & ~(TILE_COLOR_PROP_FLIP_VERTICAL | TILE_COLOR_PROP_FLIP_HORIZONTAL);
const flipX = flipTileDataX(origData);
const flipY = flipTileDataY(origData);
const flipXY = flipTileDataX(flipY);
const variants = [
{ data: origData, hash: hashTileData(origData), mask: 0 },
{
data: flipX,
hash: hashTileData(flipX),
mask: TILE_COLOR_PROP_FLIP_HORIZONTAL,
},
{
data: flipY,
hash: hashTileData(flipY),
mask: TILE_COLOR_PROP_FLIP_VERTICAL,
},
{
data: flipXY,
hash: hashTileData(flipXY),
mask: TILE_COLOR_PROP_FLIP_HORIZONTAL | TILE_COLOR_PROP_FLIP_VERTICAL,
},
];
const matched = variants.find((variant) => tileLookup[variant.hash]);
if (matched) {
newTileData.push(matched.data);
newTileColors[index] = clearedAttr | matched.mask;
} else {
tileLookup[variants[0].hash] = origData;
newTileColors[index] = clearedAttr;
newTileData.push(origData);
}
});
return {
tileData: newTileData,
tileAttrs: newTileColors,
tilesetData: [...commonTileData, ...newTileData],
};
};
export const autoFlipTiles = ({
indexedImage,
tileColors,
commonTileData,
}: {
indexedImage: IndexedImage;
tileColors: readonly number[];
commonTileData: Uint8Array[];
}): AutoFlipResult => {
const tileData: Uint8Array[] = [];
const width = Math.floor(indexedImage.width / TILE_SIZE);
const height = Math.floor(indexedImage.height / TILE_SIZE);
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
tileData.push(
indexedImageTo2bppTileData(
sliceIndexedImage(
indexedImage,
x * TILE_SIZE,
y * TILE_SIZE,
TILE_SIZE,
TILE_SIZE,
),
),
);
}
}
return autoFlipTileData({
tileData,
tileColors,
commonTileData,
});
};
|