import type { VideoFrame } from "./frame-buffer.ts"; const RESET = "\x1b[0m"; const UPPER_HALF_BLOCK = "▀"; export function renderHalfBlock(frame: VideoFrame, targetCols: number, targetRows: number): string[] { if (!Number.isInteger(targetCols) || !Number.isInteger(targetRows) || targetCols < 1 || targetRows < 1) { throw new RangeError("Half-block target dimensions must be positive integers"); } const targetPixelHeight = targetRows * 2; const lines = new Array(targetRows); for (let row = 0; row < targetRows; row++) { const topY = sampleCoordinate(row * 2, targetPixelHeight, frame.height); const bottomY = sampleCoordinate(row * 2 + 1, targetPixelHeight, frame.height); const cells = new Array(targetCols + 1); for (let col = 0; col < targetCols; col++) { const sourceX = sampleCoordinate(col, targetCols, frame.width); const topOffset = topY * frame.stride + sourceX * 4; const bottomOffset = bottomY * frame.stride + sourceX * 4; cells[col] = `\x1b[38;2;${frame.pixels[topOffset]};${frame.pixels[topOffset + 1]};${frame.pixels[topOffset + 2]}m` + `\x1b[48;2;${frame.pixels[bottomOffset]};${frame.pixels[bottomOffset + 1]};${frame.pixels[bottomOffset + 2]}m` + UPPER_HALF_BLOCK; } cells[targetCols] = RESET; lines[row] = cells.join(""); } return lines; } function sampleCoordinate(target: number, targetSize: number, sourceSize: number): number { return Math.min(sourceSize - 1, Math.floor((target * sourceSize) / targetSize)); }