<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta name="robots" content="noindex">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Generated Texture</title>
<style>
html,
body,
canvas {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<!--
© Adam Murray 2024
https://adammurray.link/
Creative Commons License
Attribution-NonCommercial-ShareAlike 4.0 International
https://creativecommons.org/licenses/by-nc-sa/4.0/
-->
<script id="vertexShader" type="x-shader/x-vertex">
#version 300 es
in vec4 vertexPosition;
void main() { // no-op vertex shader
gl_Position = vertexPosition;
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
#version 300 es
precision highp float;
uniform sampler2D tex;
uniform vec2 canvasSize;
out vec4 fragColor;
void main() {
vec2 coord = gl_FragCoord.xy/canvasSize; // stretch texture to canvas (don't maintain aspect ratio)
fragColor = texture(tex, coord);
}
</script>
<script>
const canvas = document.querySelector('canvas');
const vertexShader = document.querySelector('script[type="x-shader/x-vertex"]');
const fragmentShader = document.querySelector('script[type="x-shader/x-fragment"]');
const gl = canvas.getContext("webgl2", { preserveDrawingBuffer: true });
if (!gl) {
main.innerHTML = '<p>Error: WebGL2 is <a href="https://get.webgl.org/webgl2/">not supported by your browser</a></p>';
throw "WebGL2 not supported";
}
function createShader(shaderType, sourceCode) {
const shader = gl.createShader(shaderType);
gl.shaderSource(shader, sourceCode);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) throw gl.getShaderInfoLog(shader);
return shader;
}
const program = gl.createProgram();
gl.attachShader(program, createShader(gl.VERTEX_SHADER, vertexShader.textContent.trim()));
gl.attachShader(program, createShader(gl.FRAGMENT_SHADER, fragmentShader.textContent.trim()));
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) throw gl.getProgramInfoLog(program);
gl.useProgram(program);
const textureWidth = 20;
const textureHeight = 20;
const textureData = []; /* Format: [R, G, B, R, G, B, ...] */
for (let x = 0; x < textureWidth; x++) {
for (let y = 0; y < textureHeight; y++) {
// add a texture pixel via 3 values for R,G,B:
textureData.push(x * 255 / textureWidth); // R
textureData.push(y * 255 / textureHeight); // G
textureData.push(127 * (Math.cos(x + y) + 1)); // B
}
}
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(
gl.TEXTURE_2D, 0, gl.RGB,
textureWidth, textureHeight, 0,
gl.RGB, gl.UNSIGNED_BYTE, new Uint8Array(textureData)
);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); // or gl.LINEAR for interpolation
/*
// Prevent interpolating with wrap-around at the edges when using gl.LINEAR:
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); // or try gl.MIRRORED_REPEAT
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
*/
const vertices = [[-1, -1], [1, -1], [-1, 1], [1, 1]];
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices.flat()), gl.STATIC_DRAW);
const vertexPosition = gl.getAttribLocation(program, "vertexPosition");
gl.enableVertexAttribArray(vertexPosition);
gl.vertexAttribPointer(vertexPosition, 2, gl.FLOAT, false, 0, 0);
const canvasSizeUniform = gl.getUniformLocation(program, 'canvasSize');
function draw() {
const width = canvas.clientWidth;
const height = canvas.clientHeight;
canvas.width = width;
canvas.height = height;
gl.viewport(0, 0, width, height);
gl.uniform2f(canvasSizeUniform, width, height);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, vertices.length);
}
window.addEventListener('resize', () => draw());
draw();
</script>
</body>
</html>