|
<!doctype html>
<html>
<head>
<title>.trixl</title>
<meta charset="utf-8" />
<style>
#stage {
position: absolute;
top: 0;
left: 0;
}
#debug {
position: absolute;
bottom: 0;
right: 0;
}
</style>
</head>
<body>
<canvas id="stage">
sorry. your browser is from the dark ages. please initiate
temporal leap to a minimally brighter future where browsers can
investigate the third dimension.
</canvas>
<span id="debug"></span>
<script type="gl/vertex-shader">
attribute vec3 pos;
varying vec3 world_pos;
uniform mat4 transform;
void main() {
world_pos = pos;
gl_Position = vec4(transform * vec4(pos, 1));
}
</script>
<script type="gl/fragment-shader">
precision mediump float;
uniform vec4 color;
varying vec3 world_pos;
void main() {
if (color.x >= 0.0 && color.x <= 1.0) {
gl_FragColor = color;
} else {
gl_FragColor = vec4(world_pos.x, world_pos.y, world_pos.z, 1);
}
}
</script>
<script src="gl.js"></script>
<script src="geometry.js"></script>
<script src="matrix.js"></script>
<script src="glmatrix.js"></script>
<script>
mat4.multiplyMany = function() {
var m = arguments[0];
for(var i = 1; i < arguments.length; i++) {
m = mat4.multiply([], arguments[i], m);
}
return m;
}
</script>
<script>
window.trixl = {};
trixl.stage = document.querySelector("#stage");
trixl.window = {w: window.innerWidth, h: window.innerHeight};
trixl.stage.width = trixl.window.w;
trixl.stage.height = trixl.window.h;
trixl.debug = document.querySelector("#debug");
trixl.debug_pos = function(pos) {
var coord_html = function(coord) {
var s = (coord.toString() + " ").slice(0, 6);
if (coord < -1.0 || coord > 1.0) {
return '<span style="color: red">' + s + '</span>';
} else {
return '<span>' + s + '</span>';
}
return s;
}
return coord_html(pos[0]) + ", " + coord_html(pos[1]) + ", " + coord_html(pos[2]);
}
var gl = trixl.gl = trixl.stage.getContext("webgl");
//gl.enable(gl.CULL_FACE);
gl.enable(gl.DEPTH_TEST);
trixl.camera = { pos: [0, 0, 5], focus: [0, 0, 10], up: [0, 1, 0] };
trixl.camera.front = function() {
var front = vec3.subtract([], trixl.camera.focus, trixl.camera.pos);
return vec3.normalize(front, front);
}
trixl.camera.strafe = function(front) {
var strafe = vec3.cross([], front || trixl.camera.front(), trixl.camera.up);
return vec3.normalize(strafe, strafe);
}
trixl.camera.forward = function(scale) {
var front = trixl.camera.front();
vec3.scale(front, front, scale);
vec3.add(trixl.camera.pos, trixl.camera.pos, front);
vec3.add(trixl.camera.focus, trixl.camera.focus, front);
}
trixl.camera.sideways = function(scale) {
var front = trixl.camera.front();
var strafe = trixl.camera.strafe(front);
vec3.scale(strafe, strafe, scale);
vec3.add(trixl.camera.pos, trixl.camera.pos, strafe);
vec3.add(trixl.camera.focus, trixl.camera.focus, strafe);
}
trixl.camera.rotate = function(dx, dy) {
var front = trixl.camera.front();
var strafe = trixl.camera.strafe(front);
trixl.camera.rotateAround(dx, trixl.camera.up);
trixl.camera.rotateAround(dy, strafe);
}
trixl.camera.rotateAround = function(angle, axis) {
var front = trixl.camera.front();
var q = quat.setAxisAngle([], axis, angle);
vec3.transformQuat(front, front, q);
vec3.add(trixl.camera.focus, trixl.camera.pos, front);
}
var vertexPosBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(geometry.cube()), gl.STATIC_DRAW);
var vs = document.querySelector("script[type='gl/vertex-shader']").textContent;
var fs = document.querySelector("script[type='gl/fragment-shader']").textContent;
var program = createProgram(vs, fs);
gl.useProgram(program);
program.vertexPosAttrib = gl.getAttribLocation(program, 'pos');
gl.enableVertexAttribArray(program.vertexPosAttrib);
gl.vertexAttribPointer(program.vertexPosBuffer, 3, gl.FLOAT, false, 0, 0);
program.color = gl.getUniformLocation(program, 'color');
gl.uniform4f(program.color, -1, -1, -1, -1);
var angle = {x: 0, y: 0, z: 0};
var offset = {x: 0, y: 0, z: 0};
program.transform = gl.getUniformLocation(program, 'transform');
trixl.redraw = function() {
var camera = mat4.lookAt([], trixl.camera.pos, trixl.camera.focus, trixl.camera.up);
var view = mat4.invert([], camera);
var aspect = trixl.window.w / trixl.window.h;
var transform = function(pos) {
return mat4.multiplyMany(
matrix.translate(-0.5, -0.5, -0.5),
matrix.rotateZ(angle.z / 10),
//matrix.rotateY(angle.y / 10),
matrix.rotateX(angle.x / 10),
matrix.translate(pos[0] + offset.x, pos[1] + offset.y, pos[2] + offset.z),
view,
matrix.persective(Math.PI / 3, aspect)
);
}
var t = transform([0.0, 0.0, 2]);
trixl.debug.innerHTML = "";
[[0, 0, 0], [0, 1, 0], [1, 0, 0], [1, 1, 0],
[0, 0, 1], [0, 1, 1], [1, 0, 1], [1, 1, 1]].forEach(function(el) {
trixl.debug.innerHTML +=
trixl.debug_pos(matrix.multiply([el[0], el[1], el[2], 1], [1, 4], t, [4, 4]));
trixl.debug.innerHTML += "<br />";
});
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.uniform4f(program.color, (Math.sin(angle.x) + 1.0) * 0.5, 0, 0, 1.0);
gl.uniformMatrix4fv(program.transform, false, t);
gl.drawArrays(gl.TRIANGLES, 0, 6 * 6);
var c = (Math.sin(angle.x) + 1.0) * 0.5;
gl.uniform4f(program.color, c, c, c, 1.0);
gl.uniformMatrix4fv(program.transform, false, transform([-3.0, 0.0, 2]));
gl.drawArrays(gl.TRIANGLES, 0, 6 * 6);
gl.uniformMatrix4fv(program.transform, false, transform([+3.0, 0.0, 2]));
gl.drawArrays(gl.TRIANGLES, 0, 6 * 6);
gl.uniformMatrix4fv(program.transform, false, transform([+0.0, +3.0, 2]));
gl.drawArrays(gl.TRIANGLES, 0, 6 * 6);
gl.uniformMatrix4fv(program.transform, false, transform([+0.0, -3.0, 2]));
gl.drawArrays(gl.TRIANGLES, 0, 6 * 6);
gl.uniform4f(program.color, -1, -1, -1, 0);
angle.x += Math.PI / 10;
angle.y += Math.PI / 10;
angle.z += Math.PI / 10;
offset.x = Math.sin(angle.x * 0.1);
offset.y = Math.sin(angle.y * 0.1);
offset.z = Math.cos(angle.z * 0.1) * 2;
}
trixl.step = function() {
trixl.redraw();
trixl.step.reqId = requestAnimationFrame(trixl.step);
}
trixl.start = function() {
trixl.step.reqId = requestAnimationFrame(trixl.step);
}
trixl.stop = function() {
cancelAnimationFrame(trixl.step.reqId);
trixl.step.reqId = null;
}
trixl.start();
trixl.input = {};
trixl.input.keys = new Set();
document.addEventListener("keydown", function(ev) {
trixl.input.keys.add(ev.keyCode);
var isPressed = function(keyCode) {
return trixl.input.keys.has(keyCode);
}
if (isPressed(32)) { // space
if (trixl.step.reqId == null) {
trixl.start();
} else {
trixl.stop();
}
}
if (isPressed(37) || isPressed(65)) { // left || a
trixl.camera.sideways(-0.05);
}
if (isPressed(38) || isPressed(87)) { // up || w
trixl.camera.forward(-0.05);
}
if (isPressed(39) || isPressed(68)) { // right || d
trixl.camera.sideways(0.05);
}
if (isPressed(40) || isPressed(83)) { // down || s
trixl.camera.forward(0.05);
}
});
document.addEventListener("keyup", function(ev) {
trixl.input.keys.delete(ev.keyCode);
});
trixl.input.mouse = {last: null};
trixl.stage.addEventListener("mousemove", function(ev) {
var mouse = trixl.input.mouse;
if (mouse.last === null) {
mouse.last = {x: ev.clientX, y: ev.clientY};
}
var diff = { x: mouse.last.x - ev.clientX, y: mouse.last.y - ev.clientY };
trixl.camera.rotate(diff.x * 0.01, diff.y * 0.01);
mouse.last = {x: ev.clientX, y: ev.clientY};
});
window.onresize = function() {
trixl.window.w = window.innerWidth;
trixl.window.h = window.innerHeight;
trixl.stage.width = trixl.window.w;
trixl.stage.height = trixl.window.h;
gl.viewport(0, 0, trixl.window.w, trixl.window.h);
trixl.redraw();
}
</script>
</body>
</html>
|