Files
muuhd/frontend/ascii_textureloader.js
Kim Ravn Hansen 95068939af truthstorian
2025-09-26 09:01:29 +02:00

116 lines
3.0 KiB
JavaScript
Executable File

/**
* @typedef {object} NormalizedPixel
* @property {number} r value [0...1]
* @property {number} g value [0...1]
* @property {number} b value [0...1]
* @property {number} a value [0...1]
*
* @typedef {object} Pixel
* @property {number} r value [0...255]
* @property {number} g value [0...255]
* @property {number} b value [0...255]
* @property {number} a value [0...255]
*/
export class NRGBA {
//
constructor(r = 0, g = 0, b = 0, a = 0) {
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}
mulRGB(factor) {
this.r *= factor;
this.g *= factor;
this.b *= factor;
}
get dR() {
return ((this.r * 255) | 0) % 256;
}
get dG() {
return ((this.g * 255) | 0) % 256;
}
get dB() {
return ((this.b * 255) | 0) % 256;
}
get dA() {
return ((this.a * 255) | 0) % 256;
}
toCSS() {
return (
"#" + // prefix
this.dR.toString(16).padStart(2, "0") +
this.dG.toString(16).padStart(2, "0") +
this.dB.toString(16).padStart(2, "0") +
this.dA.toString(16).padStart(2, "0")
);
}
}
/**
* Texture class,
* represents a single texture
*/
export class Texture {
static async fromSource(src) {
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = "anonymous";
img.onload = () => {
try {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
const imageData = ctx.getImageData(0, 0, img.width, img.height);
const result = new Texture(img.width, img.height, imageData.data);
resolve(result);
} catch (error) {
reject(error);
}
};
img.onerror = () => reject(new Error(`Failed to load texture: ${src}`));
img.src = src;
});
}
constructor(width, height, data) {
/** @type {number} */
this.width = width;
/** @type {number} */
this.height = height;
/** @type {Uint8ClampedArray} */
this.data = data;
}
/**
* Bilinear sampling for smooth texture filtering
*
* @param {number} u the "x" coordinate of the texture sample pixel. Normalized to [0...1]
* @param {number} w the "y" coordinate of the texture sample pixel. Normalized to [0...1]
*
* @returns {NRGBA}
*/
sample(u, v) {
const x = Math.round(u * this.width);
const y = Math.round(v * this.height);
const index = (y * this.width + x) * 4;
return new NRGBA(
this.data[index + 0] / 255,
this.data[index + 1] / 255,
this.data[index + 2] / 255,
1, // this.data[index + 3] / 255,
);
}
}