game_list/frontend/src/randomTextureForShader.ts
code002lover 4e91349a59 WIP
Try adding black hole background
2025-12-06 13:49:52 +01:00

94 lines
2.8 KiB
TypeScript

export function generateRandomRGBABytes(
width: number,
height: number
): Uint8Array {
if (width <= 0 || height <= 0) {
throw new Error("width and height must be positive");
}
const len = width * height * 4;
const out = new Uint8Array(len);
// Maximum bytes per getRandomValues call (per spec / browsers)
const MAX_GETRANDOM_BYTES = 65536;
if (typeof crypto !== "undefined" && "getRandomValues" in crypto) {
// Fill in chunks of up to MAX_GETRANDOM_BYTES
let offset = 0;
while (offset < len) {
const chunkSize = Math.min(MAX_GETRANDOM_BYTES, len - offset);
// Subarray view for the current chunk
const chunkView = out.subarray(offset, offset + chunkSize);
crypto.getRandomValues(chunkView);
offset += chunkSize;
}
// Ensure alpha channel is fully opaque (255)
for (let i = 3; i < len; i += 4) out[i] = 255;
} else {
// Fallback to Math.random for all bytes
for (let i = 0; i < len; i++) {
if ((i + 1) % 4 === 0) out[i] = 255;
else out[i] = Math.floor(Math.random() * 256);
}
}
return out;
}
/**
* Create a WebGL texture from random data and bind it to texture unit 0,
* then set the sampler2D uniform named `iChannel0` to use unit 0.
*
* gl: WebGLRenderingContext or WebGL2RenderingContext
* program: compiled & linked shader program (must be in use or will be used)
*/
export function createAndBindRandomTextureToIChannel0(
gl: WebGLRenderingContext | WebGL2RenderingContext,
program: WebGLProgram,
width: number,
height: number
): WebGLTexture {
const bytes = generateRandomRGBABytes(width, height);
const tex = gl.createTexture();
if (!tex) throw new Error("Failed to create texture");
// Activate texture unit 0 and bind the texture
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, tex);
// Texture parameters suitable for data textures
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
// Upload pixel data as RGBA UNSIGNED_BYTE
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA,
width,
height,
0,
gl.RGBA,
gl.UNSIGNED_BYTE,
bytes
);
const location = gl.getUniformLocation(program, "iChannel0");
if (location === null) {
// Clean up binding and return but signal with thrown error if desired
gl.bindTexture(gl.TEXTURE_2D, null);
throw new Error("Uniform 'iChannel0' not found in program");
}
// Set sampler uniform to texture unit 0
gl.uniform1i(location, 0);
// Unbind the texture if you prefer (not strictly necessary)
gl.bindTexture(gl.TEXTURE_2D, null);
return tex;
}