import type { Palette } from "../world/types"; /** Decode Game Boy planar pixels directly to RGBA; no display hardware emulation. */ export function drawTile( target: Uint8ClampedArray, width: number, height: number, graphics: Uint8Array, tile: number, x: number, y: number, palette: Palette, options: { transparent?: boolean; flipX?: boolean; flipY?: boolean; /** Background color indices per pixel: a background tile records them; * an OAM_PRIO sprite (`behind`) only draws over color 0. */ indices?: Uint8Array; behind?: boolean; } = {}, ) { const offset = tile * 16; if (offset < 0 || offset + 16 > graphics.length) return; for (let row = 0; row < 8; row++) { const sourceRow = options.flipY ? 7 - row : row; const lo = graphics[offset + sourceRow * 2], hi = graphics[offset + sourceRow * 2 + 1]; for (let col = 0; col < 8; col++) { const bit = options.flipX ? col : 7 - col; const index = ((lo >> bit) & 1) | (((hi >> bit) & 1) << 1); if (options.transparent && index === 0) continue; const px = x + col, py = y + row; if (px < 0 || py < 0 || px >= width || py >= height) continue; if (options.indices) { if (options.behind) { if (options.indices[py * width + px]) continue; } else if (!options.transparent) options.indices[py * width + px] = index; } const destination = (py * width + px) * 4, color = palette[index]; target[destination] = color[0]; target[destination + 1] = color[1]; target[destination + 2] = color[2]; target[destination + 3] = 255; } } }