"use strict";
const vs = `
attribute vec4 position;
uniform mat4 matrix;
void main() {
gl_Position = matrix * position;
}
`;
const fs = `
precision mediump float;
uniform vec4 color;
void main() {
gl_FragColor = color;
}
`;
const m4 = twgl.m4;
const gl = document.querySelector("canvas").getContext("webgl");
// compiles shaders, link program, looks up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const arrays = {
position: {
numComponents: 2,
data: [
-1, -1,
1, -1,
-1, 1,
1, 1,
],
},
indices: {
numComponents: 2,
data: [
0, 1,
1, 3,
3, 2,
2, 0,
],
},
};
// calls gl.createBuffer, gl.bindBuffer, gl.bufferData for each array
const bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
// note: a good app would try to only draw what's visible in each
// view
function drawScene(viewProjection) {
gl.useProgram(programInfo.program);
// calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
for (let y = -5; y <= 5; ++y) {
for (let x = -5; x <= 5; ++x) {
const world = m4.translation([x * 2.4, y * 2.4, 0]);
const mat = m4.multiply(viewProjection, world);
// calls gl.uniformXXX
twgl.setUniforms(programInfo, {
color: [(x + 5) / 10, (y + 5) / 10, x / 5 * y / 5 * .5 + 5, 1],
matrix: mat,
});
// calls gl.drawArrays or gl.drawElements
twgl.drawBufferInfo(gl, bufferInfo, gl.LINES);
}
}
}
function render(time) {
time *= 0.001;
twgl.resizeCanvasToDisplaySize(gl.canvas);
// draw main scene
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.disable(gl.SCISSOR_TEST);
gl.clearColor(0,0,0,1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
{
const unitsVertical = 3;
const half = unitsVertical * .5
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const left = -half * aspect;
const right = half * aspect;
const bottom = -half;
const top = half;
const zNear = -1;
const zFar = 1;
const projection = m4.ortho(left, right, bottom, top, zNear, zFar);
const camera = m4.rotationZ(time * .1);
const view = m4.inverse(camera);
const viewProjection = m4.multiply(projection, view);
drawScene(viewProjection);
}
// draw mini map
const miniMapWidth = gl.canvas.width / 3 | 0;
const miniMapHeight = gl.canvas.height / 3 | 0;
const miniMapX = gl.canvas.width - miniMapWidth;
const miniMapY = gl.canvas.height - miniMapHeight;
gl.viewport(miniMapX, miniMapY, miniMapWidth, miniMapHeight);
gl.scissor(miniMapX, miniMapY, miniMapWidth, miniMapHeight);
gl.enable(gl.SCISSOR_TEST);
gl.clearColor(0.2,0.2,0.2,1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
{
const unitsVertical = 20;
const half = unitsVertical * .5
const aspect = miniMapWidth / miniMapHeight;
const left = -half * aspect;
const right = half * aspect;
const bottom = -half;
const top = half;
const zNear = -1;
const zFar = 1;
const projection = m4.ortho(left, right, bottom, top, zNear, zFar);
const camera = m4.rotationZ(time * .1);
const view = m4.inverse(camera);
const viewProjection = m4.multiply(projection, view);
drawScene(viewProjection);
}
requestAnimationFrame(render);
}
requestAnimationFrame(render);
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<canvas></canvas>
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>