180 lines
4.8 KiB
JavaScript
180 lines
4.8 KiB
JavaScript
|
let gl = null;
|
||
|
let glCanvas = null;
|
||
|
|
||
|
// Aspect ratio and coordinate system
|
||
|
// details
|
||
|
|
||
|
let aspectRatio;
|
||
|
let currentRotation = [0, 1];
|
||
|
let currentScale = 1.0;
|
||
|
|
||
|
// Vertex information
|
||
|
|
||
|
let vertexArray;
|
||
|
let vertexBuffer;
|
||
|
let vertexNumComponents;
|
||
|
let vertexCount;
|
||
|
|
||
|
// Rendering data shared with the
|
||
|
// scalers.
|
||
|
|
||
|
let uScalingFactor;
|
||
|
let uGlobalColor;
|
||
|
let uRotationVector;
|
||
|
let aVertexPosition;
|
||
|
|
||
|
// Animation timing
|
||
|
|
||
|
let previousTime = 0.0;
|
||
|
let degreesPerSecond = 45;
|
||
|
let scalePerSecond = 0.001;
|
||
|
|
||
|
const img = new Image();
|
||
|
|
||
|
window.addEventListener("load", startup, false);
|
||
|
|
||
|
function startup() {
|
||
|
glCanvas = document.getElementById("glcanvas");
|
||
|
gl = glCanvas.getContext("webgl");
|
||
|
|
||
|
const shaderSet = [
|
||
|
{
|
||
|
type: gl.VERTEX_SHADER,
|
||
|
id: "vertex-shader"
|
||
|
},
|
||
|
{
|
||
|
type: gl.FRAGMENT_SHADER,
|
||
|
id: "fragment-shader"
|
||
|
}
|
||
|
];
|
||
|
|
||
|
shaderProgram = buildShaderProgram(shaderSet);
|
||
|
|
||
|
aspectRatio = 1;
|
||
|
currentRotation = [0, 1];
|
||
|
currentScale = 1;
|
||
|
|
||
|
|
||
|
vertexBuffer = gl.createBuffer();
|
||
|
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
||
|
|
||
|
vertexArray = new Float32Array([ -1,1, -1,-1, 1,-1, 1,1 ]);
|
||
|
gl.bufferData(gl.ARRAY_BUFFER, vertexArray, gl.STATIC_DRAW);
|
||
|
|
||
|
vertexNumComponents = 2;
|
||
|
vertexCount = vertexArray.length / vertexNumComponents;
|
||
|
|
||
|
currentAngle = 0.0;
|
||
|
|
||
|
img.onload = function() {
|
||
|
|
||
|
// load texture
|
||
|
gl.activeTexture(gl.TEXTURE0);
|
||
|
const tex = gl.createTexture();
|
||
|
gl.bindTexture(gl.TEXTURE_2D, tex);
|
||
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, img);
|
||
|
|
||
|
// function isPowerOf2(value) {
|
||
|
// return (value & (value - 1)) == 0;
|
||
|
// }
|
||
|
// if (isPowerOf2(img.width) && isPowerOf2(img.height)) {
|
||
|
// // Yes, it's a power of 2. Generate mips.
|
||
|
// gl.generateMipmap(gl.TEXTURE_2D);
|
||
|
// } else {
|
||
|
// // No, it's not a power of 2. Turn off mips and set
|
||
|
// // wrapping to clamp to edge
|
||
|
// }
|
||
|
|
||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
||
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
||
|
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);
|
||
|
|
||
|
animateScene();
|
||
|
};
|
||
|
img.src = 'images/js-sm.png';
|
||
|
}
|
||
|
|
||
|
function buildShaderProgram(shaderInfo) {
|
||
|
let program = gl.createProgram();
|
||
|
|
||
|
shaderInfo.forEach(function(desc) {
|
||
|
let shader = compileShader(desc.id, desc.type);
|
||
|
|
||
|
if (shader) {
|
||
|
gl.attachShader(program, shader);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
gl.linkProgram(program)
|
||
|
|
||
|
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
||
|
console.error("Error linking shader program:", gl.getProgramInfoLog(program));
|
||
|
}
|
||
|
|
||
|
return program;
|
||
|
}
|
||
|
|
||
|
function compileShader(id, type) {
|
||
|
let code = document.getElementById(id).firstChild.nodeValue;
|
||
|
let shader = gl.createShader(type);
|
||
|
|
||
|
gl.shaderSource(shader, code);
|
||
|
gl.compileShader(shader);
|
||
|
|
||
|
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
||
|
console.error(
|
||
|
`Error compiling ${type === gl.VERTEX_SHADER ? "vertex" : "fragment"} shader:`,
|
||
|
gl.getShaderInfoLog(shader)
|
||
|
);
|
||
|
}
|
||
|
return shader;
|
||
|
}
|
||
|
function animateScene() {
|
||
|
gl.viewport(0, 0, glCanvas.width, glCanvas.height);
|
||
|
gl.clearColor(0.8, 0.9, 1.0, 1.0);
|
||
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||
|
|
||
|
let radians = currentAngle * Math.PI / 180.0;
|
||
|
currentRotation[0] = Math.sin(radians);
|
||
|
currentRotation[1] = Math.cos(radians);
|
||
|
|
||
|
gl.useProgram(shaderProgram);
|
||
|
|
||
|
uScalingFactor =
|
||
|
gl.getUniformLocation(shaderProgram, "uScalingFactor");
|
||
|
uGlobalColor =
|
||
|
gl.getUniformLocation(shaderProgram, "uGlobalColor");
|
||
|
uRotationVector =
|
||
|
gl.getUniformLocation(shaderProgram, "uRotationVector");
|
||
|
|
||
|
gl.uniform1f(uScalingFactor, currentScale);
|
||
|
gl.uniform2fv(uRotationVector, currentRotation);
|
||
|
gl.uniform4fv(uGlobalColor, [0.1, 0.7, 0.2, 1.0]);
|
||
|
|
||
|
const texLoc = gl.getUniformLocation(shaderProgram, "tex");
|
||
|
gl.uniform1i(texLoc, 0);
|
||
|
|
||
|
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
||
|
|
||
|
aVertexPosition = gl.getAttribLocation(shaderProgram, "aVertexPosition");
|
||
|
|
||
|
gl.vertexAttribPointer(aVertexPosition, vertexNumComponents, gl.FLOAT, false, 0, 0);
|
||
|
gl.enableVertexAttribArray(aVertexPosition);
|
||
|
|
||
|
gl.drawArrays(gl.TRIANGLE_FAN, 0, vertexCount);
|
||
|
|
||
|
window.requestAnimationFrame(function (currentTime) {
|
||
|
let secondsElapsed = ((currentTime - previousTime) / 1000.0)
|
||
|
let deltaAngle = secondsElapsed * degreesPerSecond;
|
||
|
|
||
|
currentAngle = (currentAngle + deltaAngle) % 360;
|
||
|
currentScale = 0.5+0.5*(Math.cos(0.0004*currentTime))**2
|
||
|
|
||
|
previousTime = currentTime;
|
||
|
animateScene();
|
||
|
});
|
||
|
}
|
||
|
|
||
|
startup()
|