UNPKG

@tolokoban/tgd

Version:

ToloGameDev library for WebGL2

120 lines 10.5 kB
import { TgdColor } from "./../color/index.js"; import { TgdVec4 } from "./../math/index.js"; /** * Helper to get a canvas with the given size. */ export function tgdCanvasCreate(width, height) { const canvas = globalThis.document.createElement("canvas"); canvas.width = width; canvas.height = height; // Force backing store allocation // Needed for Safari to prevent INVALID_OPERATION errors with textures. canvas.getContext("2d"); return canvas; } /** * Helper to get a canvas of the given size and a 2D context on it. * If this is not possible, the method will throw an exception. */ export function tgdCanvasCreateWithContext2D(width, height, settings) { const canvas = globalThis.document.createElement("canvas"); canvas.width = width; canvas.height = height; const context = canvas.getContext("2d", settings); if (!context) throw new Error("Unable to create 2D context!"); return { canvas, ctx: context }; } export function tgdCanvasFromImage(img) { const { canvas, ctx } = tgdCanvasCreateWithContext2D(img.width, img.height); ctx.drawImage(img, 0, 0); return canvas; } export async function tgdCanvasToArrayBuffer(canvas, type = "image/png", quality = 1) { const blob = await new Promise((resolve) => canvas.toBlob(resolve, type, quality)); if (!blob) { throw new Error(`[tgdCanvasToArrayBuffer] Failed to get canvas blob for "${type}" with quality ${quality}!`); } return await blob.arrayBuffer(); } /** * A palette is an image with a different (or not) color for each pixel. * It can be used in a texture with NEAREST filter, for instance. * @param colors CSS colors of each pixel * @param colums If not defined, the canvas will have a size of (colors.length, 1). * But if `colums` is defined, it will be the width of the vanva and the height will * be computed to hold all the colors. * If there are more pixels in the canvas that colors, we just wrap around the colors * array. * @param rows If defined, it will be the height of the canvas. * @example * ``` * // Create a 5x5 checkboard. * const canvas = tgdCanvasCreatePalette(["#000", "#fff"], 5, 5) * ``` */ export function tgdCanvasCreatePalette(colors, colums = 0, rows = 0) { const width = colums > 0 ? colums : colors.length; const height = rows > 0 ? rows : Math.ceil(colors.length / width); const { canvas, ctx } = tgdCanvasCreateWithContext2D(width, height); let colorIndex = 0; for (let y = 0; y < height; y++) { for (let x = 0; x < width; x++) { ctx.fillStyle = colorToString(colors[colorIndex % colors.length]); ctx.fillRect(x, y, 1, 1); colorIndex++; } } return canvas; } export function tgdCanvasCreateFill(width, height, fillColor = "#000") { const { canvas, ctx } = tgdCanvasCreateWithContext2D(width, height); ctx.fillStyle = colorToString(fillColor); ctx.fillRect(0, 0, width, height); return canvas; } export function tgdCanvasCreateGradientHorizontal(size, colors) { return tgdCanvasCreateGradient(size, 1, 1, 0, colors); } export function tgdCanvasCreateCreateGradientvertical(size, colors) { return tgdCanvasCreateGradient(1, size, 0, 1, colors); } /** * Create a canvas with a linear gradient. * @param width Width of the resulting canvas. * @param height Height of the resulting canvas. * @param directionX X coord of the direction vector. * @param directionY Y coord of the direction vector. * @param colors CSS colors of each step */ export function tgdCanvasCreateGradient(width, height, directionX, directionY, colors) { const { canvas, ctx } = tgdCanvasCreateWithContext2D(width, height); const gradient = ctx.createLinearGradient(0, 0, width * directionX, height * directionY); for (let colorIndex = 0; colorIndex < colors.length; colorIndex++) { const color = colors[colorIndex]; const cssColor = colorToString(color); gradient.addColorStop(colorIndex / (colors.length - 1), cssColor); } ctx.fillStyle = gradient; ctx.fillRect(0, 0, width, height); return canvas; } function colorToString(color) { try { if (typeof color === "string") return color; if (color instanceof TgdColor) return color.toString(); if (Array.isArray(color)) { const [r, g, b, a] = color; return new TgdColor(r, g, b, a ?? 1).toString(); } return new TgdColor(color.x, color.y, color.z, color instanceof TgdVec4 ? color.w : 1).toString(); } catch { console.error("[Tgd::colorToString] Invalid color argument:", color); console.info("[Tgd::colorToString] We will use purple (#F0F)."); return "#f0f"; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FudmFzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL2NhbnZhcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sWUFBWSxDQUFBO0FBQ3JDLE9BQU8sRUFBVyxPQUFPLEVBQUUsTUFBTSxXQUFXLENBQUE7QUFHNUM7O0dBRUc7QUFDSCxNQUFNLFVBQVUsZUFBZSxDQUFDLEtBQWEsRUFBRSxNQUFjO0lBQ3pELE1BQU0sTUFBTSxHQUFHLFVBQVUsQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxDQUFBO0lBQzFELE1BQU0sQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFBO0lBQ3BCLE1BQU0sQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFBO0lBQ3RCLGlDQUFpQztJQUNqQyx1RUFBdUU7SUFDdkUsTUFBTSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUN2QixPQUFPLE1BQU0sQ0FBQTtBQUNqQixDQUFDO0FBRUQ7OztHQUdHO0FBQ0gsTUFBTSxVQUFVLDRCQUE0QixDQUN4QyxLQUFhLEVBQ2IsTUFBYyxFQUNkLFFBQTJDO0lBRTNDLE1BQU0sTUFBTSxHQUFHLFVBQVUsQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxDQUFBO0lBQzFELE1BQU0sQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFBO0lBQ3BCLE1BQU0sQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFBO0lBQ3RCLE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFBO0lBQ2pELElBQUksQ0FBQyxPQUFPO1FBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyw4QkFBOEIsQ0FBQyxDQUFBO0lBRTdELE9BQU8sRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLE9BQU8sRUFBRSxDQUFBO0FBQ25DLENBQUM7QUFFRCxNQUFNLFVBQVUsa0JBQWtCLENB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