@tolokoban/tgd
Version:
ToloGameDev library for WebGL2
120 lines • 10.5 kB
JavaScript
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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