<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<!------ Include the above in your HEAD tag ---------->
<div class="container">
<div class="row">
<h2>Create your snippet's HTML, CSS and Javascript in the editor tabs</h2>
</div>
</div>
body, html {
touch-action: none;
content-zooming: none;
position: absolute;
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
canvas {
position: absolute;
display: block;
width: 100%;
height: 100%;
background:#000;
cursor: pointer;
}
"use strict";
{
const webgl = {
init() {
// create webGL canvas context
this.elem = document.createElement("canvas");
document.body.appendChild(this.elem);
const options = { alpha: false };
const gl = this.gl = this.elem.getContext('webgl', options) || this.elem.getContext('experimental-webgl', options);
// set shaders
this.vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(
this.vertexShader,
`
uniform mat4 camProj, camView, modelMatrix;
attribute vec3 aPosition, aNormal, aColor;
varying vec3 vWPosition, vPosition, vNormal, vColor;
void main(void) {
vec4 mpos = modelMatrix * vec4(aPosition, 1.0);
vec4 wpos = camView * mpos;
vPosition = wpos.xyz;
vWPosition = mpos.xyz;
vNormal = aNormal;
vColor = aColor;
gl_Position = camProj * wpos;
}
`
);
this.fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(
this.fragmentShader,
`
precision highp float;
varying vec3 vWPosition, vPosition, vNormal, vColor;
const vec3 lightPos = vec3(0.0, 0.0, -2.5);
const vec3 lightColor = vec3(1.3, 1.3, 0.9);
const vec3 ambientFar = vec3(0.05, 0.1, 0.6);
const vec3 ambientNear = vec3(0.12, 0.09, 0.02);
const float radius = 2.5;
uniform float uTime;
uniform vec2 uResolution;
void main(void) {
float dist = distance(vPosition, lightPos);
float att = max(1.0 - (dist * dist) / (radius * radius), 0.0);
vec3 lightDirection = normalize(lightPos - vWPosition);
float angle = max(dot(lightDirection, vNormal), 0.0);
vec3 diffuse = att * att * lightColor * vColor * angle;
vec3 col = ambientFar * angle * att + ambientNear * 1.0 / dist + diffuse;
if (vColor.r > 9.0) col = vColor;
vec2 uv = gl_FragCoord.xy / uResolution.xy;
col -= abs(sin(uv.y * 200.0 - uTime * 3.0)) * 0.02;
gl_FragColor = vec4(col, 1.0);
}
`
);
// compile shaders
gl.compileShader(this.vertexShader);
gl.compileShader(this.fragmentShader);
this.program = gl.createProgram();
gl.attachShader(this.program, this.vertexShader);
gl.attachShader(this.program, this.fragmentShader);
gl.linkProgram(this.program);
gl.useProgram(this.program);
// camera
this.camera = {
proj: this.mat4().uniform("camProj").load(),
view: this.mat4().uniform("camView").load()
};
// resize event
this.resize();
window.addEventListener("resize", () => this.resize(), false);
return gl;
},
Attribute: class {
constructor(name) {
this.gl = webgl.gl;
this.index = gl.getAttribLocation(webgl.program, name);
gl.enableVertexAttribArray(this.index);
this.buffer = gl.createBuffer();
this.numElements = 0;
}
load(data, size) {
this.itemSize = size;
this.bind();
this.gl.bufferData(
this.gl.ARRAY_BUFFER,
data instanceof Array ? new Float32Array(data) : data,
this.gl.STATIC_DRAW
);
this.numElements = data.length / size;
return this;
}
loadIndices(indices) {
if (!this.indices) this.indices = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.indices);
this.gl.bufferData(
this.gl.ELEMENT_ARRAY_BUFFER,
indices instanceof Array ? new Uint16Array(indices) : indices,
this.gl.STATIC_DRAW
);
this.numIndices = indices.length;
return this;
}
bind() {
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffer);
if (this.indices) this.gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indices);
this.gl.vertexAttribPointer(
this.index,
this.itemSize,
gl.FLOAT,
false,
0,
0
);
}
},
resize() {
this.width = this.elem.width = this.elem.offsetWidth;
this.height = this.elem.height = this.elem.offsetHeight;
this.aspect = this.width / this.height;
if (this.uResolution) this.uResolution.set(this.width, this.height).load();
// perspective projection
this.camera.proj.perspective(45).load();
this.gl.viewport(
0,
0,
this.gl.drawingBufferWidth,
this.gl.drawingBufferHeight
);
// clear screen
this.gl.clearColor(0, 0, 0, 0);
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
},
mat4() {
return new this.Mat4();
},
float(v) {
return new this.Float(v);
},
vec2(x, y) {
return new this.Vec2(x, y);
},
vec3(x, y, z) {
return new this.Vec3(x, y, z);
},
vec4(x, y, z, w) {
return new this.Vec4(x, y, z, w);
},
Mat4: class {
constructor() {
this.matrix = new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
]);
this.gl = webgl.gl;
this.u = null;
}
identity() {
const d = this.matrix;
d[0] = 1;
d[1] = 0;
d[2] = 0;
d[3] = 0;
d[4] = 0;
d[5] = 1;
d[6] = 0;
d[7] = 0;
d[8] = 0;
d[9] = 0;
d[10] = 1;
d[11] = 0;
d[12] = 0;
d[13] = 0;
d[14] = 0;
d[15] = 1;
return this;
}
translate(x, y, z) {
const d = this.matrix;
d[12] = d[0] * x + d[4] * y + d[8] * z + d[12];
d[13] = d[1] * x + d[5] * y + d[9] * z + d[13];
d[14] = d[2] * x + d[6] * y + d[10] * z + d[14];
d[15] = d[3] * x + d[7] * y + d[11] * z + d[15];
return this;
}
fromTranslation(x, y, z) {
const a = this.matrix;
a[0] = 1;
a[1] = 0;
a[2] = 0;
a[3] = 0;
a[4] = 0;
a[5] = 1;
a[6] = 0;
a[7] = 0;
a[8] = 0;
a[9] = 0;
a[10] = 1;
a[11] = 0;
a[12] = x;
a[13] = y;
a[14] = z;
a[15] = 1;
return this;
}
rotateX(angle) {
const d = this.matrix;
const s = Math.sin(angle);
const c = Math.cos(angle);
const a10 = d[4];
const a11 = d[5];
const a12 = d[6];
const a13 = d[7];
const a20 = d[8];
const a21 = d[9];
const a22 = d[10];
const a23 = d[11];
d[4] = a10 * c + a20 * s;
d[5] = a11 * c + a21 * s;
d[6] = a12 * c + a22 * s;
d[7] = a13 * c + a23 * s;
d[8] = a10 * -s + a20 * c;
d[9] = a11 * -s + a21 * c;
d[10] = a12 * -s + a22 * c;
d[11] = a13 * -s + a23 * c;
return this;
}
rotateY(angle) {
const d = this.matrix;
const s = Math.sin(angle);
const c = Math.cos(angle);
const a00 = d[0];
const a01 = d[1];
const a02 = d[2];
const a03 = d[3];
const a20 = d[8];
const a21 = d[9];
const a22 = d[10];
const a23 = d[11];
d[0] = a00 * c + a20 * -s;
d[1] = a01 * c + a21 * -s;
d[2] = a02 * c + a22 * -s;
d[3] = a03 * c + a23 * -s;
d[8] = a00 * s + a20 * c;
d[9] = a01 * s + a21 * c;
d[10] = a02 * s + a22 * c;
d[11] = a03 * s + a23 * c;
return this;
}
rotateZ(angle) {
const d = this.matrix;
const s = Math.sin(angle);
const c = Math.cos(angle);
const a00 = d[0];
const a01 = d[1];
const a02 = d[2];
const a03 = d[3];
const a10 = d[4];
const a11 = d[5];
const a12 = d[6];
const a13 = d[7];
d[0] = a00 * c + a10 * s;
d[1] = a01 * c + a11 * s;
d[2] = a02 * c + a12 * s;
d[3] = a03 * c + a13 * s;
d[4] = a00 * -s + a10 * c;
d[5] = a01 * -s + a11 * c;
d[6] = a02 * -s + a12 * c;
d[7] = a03 * -s + a13 * c;
return this;
}
scale(x, y, z) {
const d = this.matrix;
d[0] *= x;
d[1] *= x;
d[2] *= x;
d[3] *= x;
d[4] *= y;
d[5] *= y;
d[6] *= y;
d[7] *= y;
d[8] *= z;
d[9] *= z;
d[10] *= z;
d[11] *= z;
return this;
}
perspective(fov) {
const d = this.matrix;
const near = 0.01;
const far = 100;
const top = near * Math.tan(fov * Math.PI / 360);
const right = top * webgl.aspect;
const left = -right;
const bottom = -top;
d[0] = 2 * near / (right - left);
d[1] = 0;
d[2] = 0;
d[3] = 0;
d[4] = 0;
d[5] = 2 * near / (top - bottom);
d[6] = 0;
d[7] = 0;
d[8] = (right + left) / (right - left);
d[9] = (top + bottom) / (top - bottom);
d[10] = -(far + near) / (far - near);
d[11] = -1;
d[12] = 0;
d[13] = 0;
d[14] = -(2 * far * near) / (far - near);
d[15] = 0;
return this;
}
multiply(m1, m2) {
let b0, b1, b2, b3;
const d = this.matrix;
const d1 = m1.matrix;
const d2 = m2.matrix;
const a00 = d1[0],
a01 = d1[1],
a02 = d1[2],
a03 = d1[3],
a10 = d1[4],
a11 = d1[5],
a12 = d1[6],
a13 = d1[7],
a20 = d1[8],
a21 = d1[9],
a22 = d1[10],
a23 = d1[11],
a30 = d1[12],
a31 = d1[13],
a32 = d1[14],
a33 = d1[15];
b0 = d2[0];
b1 = d2[1];
b2 = d2[2];
b3 = d2[3];
d[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
d[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
d[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
d[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
b0 = d2[4];
b1 = d2[5];
b2 = d2[6];
b3 = d2[7];
d[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
d[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
d[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
d[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
b0 = d2[8];
b1 = d2[9];
b2 = d2[10];
b3 = d2[11];
d[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
d[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
d[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
d[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
b0 = d2[12];
b1 = d2[13];
b2 = d2[14];
b3 = d2[15];
d[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
d[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
d[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
d[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
return this;
}
uniform(uName) {
this.u = this.gl.getUniformLocation(webgl.program, uName);
return this;
}
load() {
this.gl.uniformMatrix4fv(this.u, this.gl.FALSE, this.matrix);
return this;
}
},
Float: class {
constructor(v = 0.0) {
this.value = v;
this.u = null;
this.gl = webgl.gl;
}
set(v) {
this.value = v;
return this;
}
uniform(uName) {
this.u = this.gl.getUniformLocation(webgl.program, uName);
return this;
}
load() {
this.gl.uniform1f(this.u, this.value);
return this;
}
},
Vec2: class {
constructor(x = 0.0, y = 0.0) {
this.x = x;
this.y = y;
this.u = null;
this.gl = webgl.gl;
}
set(x, y) {
this.x = x;
this.y = y;
return this;
}
uniform(uName) {
this.u = this.gl.getUniformLocation(webgl.program, uName);
return this;
}
load() {
this.gl.uniform2f(this.u, this.x, this.y);
return this;
}
},
Vec3: class {
constructor(x = 0.0, y = 0.0, z = 0.0) {
this.x = x;
this.y = y;
this.z = z;
this.u = null;
this.gl = webgl.gl;
}
set(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
return this;
}
copy(v) {
this.x = v.x;
this.y = v.y;
this.z = v.z;
return this;
}
lerp(v, s) {
this.x += (v.x - this.x) * s;
this.y += (v.y - this.y) * s;
this.z += (v.z - this.z) * s;
return this;
}
distance(b) {
const dx = b.x - this.x;
const dy = b.y - this.y;
const dz = b.z - this.z;
return Math.sqrt(dx * dx + dy * dy + dz * dz);
}
transformMat4(v, m) {
const d = m.matrix;
const x = v.x;
const y = v.y;
const z = v.z;
const w = d[3] * x + d[7] * y + d[11] * z + d[15] || 1.0;
this.x = (d[0] * x + d[4] * y + d[8] * z + d[12]) / w;
this.y = (d[1] * x + d[5] * y + d[9] * z + d[13]) / w;
this.z = (d[2] * x + d[6] * y + d[10] * z + d[14]) / w;
return this;
}
uniform(uName) {
this.u = this.gl.getUniformLocation(webgl.program, uName);
return this;
}
load() {
this.gl.uniform3f(this.u, this.x, this.y, this.z);
return this;
}
},
Vec4: class {
constructor(x = 0.0, y = 0.0, z = 0.0, w = 0.0) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
this.u = null;
this.gl = webgl.gl;
}
set(x, y, z, w) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
return this;
}
lerp(v, s) {
this.x += (v.x - this.x) * s;
this.y += (v.y - this.y) * s;
this.z += (v.z - this.z) * s;
this.w += (v.w - this.w) * s;
return this;
}
uniform(uName) {
this.u = this.gl.getUniformLocation(webgl.program, uName);
return this;
}
load() {
this.gl.uniform4f(this.u, this.x, this.y, this.z, this.w);
return this;
}
},
cube: {
indices(s) {
return [
s+0, s+1, s+2, s+0, s+2, s+3, // Front face
s+4, s+5, s+6, s+4, s+6, s+7, // Back face
s+8, s+9, s+10, s+8, s+10, s+11, // Top face
s+12, s+13, s+14, s+12, s+14, s+15, // Bottom face
s+16, s+17, s+18, s+16, s+18, s+19, // Right face
s+20, s+21, s+22, s+20, s+22, s+23 // Left face
]
},
normals() {
return [
// Front face
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
// Back face
0.0, 0.0, -1.0,
0.0, 0.0, -1.0,
0.0, 0.0, -1.0,
0.0, 0.0, -1.0,
// Top face
0.0, 1.0, 0.0,
0.0, 1.0, 0.0,
0.0, 1.0, 0.0,
0.0, 1.0, 0.0,
// Bottom face
0.0, -1.0, 0.0,
0.0, -1.0, 0.0,
0.0, -1.0, 0.0,
0.0, -1.0, 0.0,
// Right face
1.0, 0.0, 0.0,
1.0, 0.0, 0.0,
1.0, 0.0, 0.0,
1.0, 0.0, 0.0,
// Left face
-1.0, 0.0, 0.0,
-1.0, 0.0, 0.0,
-1.0, 0.0, 0.0,
-1.0, 0.0, 0.0
];
},
vertices(x, y, z, l, h, w) {
return [
// Front face
x-l, y-h, z+w,
x+l, y-h, z+w,
x+l, y+h, z+w,
x-l, y+h, z+w,
// Back face
x-l, y-h, z-w,
x-l, y+h, z-w,
x+l, y+h, z-w,
x+l, y-h, z-w,
// Top face
x-l, y+h, z-w,
x-l, y+h, z+w,
x+l, y+h, z+w,
x+l, y+h, z-w,
// Bottom face
x-l, y-h, z-w,
x+l, y-h, z-w,
x+l, y-h, z+w,
x-l, y-h, z+w,
// Right face
x+l, y-h, z-w,
x+l, y+h, z-w,
x+l, y+h, z+w,
x+l, y-h, z+w,
// Left face
x-l, y-h, z-w,
x-l, y-h, z+w,
x-l, y+h, z+w,
x-l, y+h, z-w
]
},
colors(r, g, b) {
return [
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b,
r,g,b
]
}
}
};
// set pointer
const pointer = {
init(canvas) {
this.x = canvas.width * 0.5;
this.y = canvas.height * 0.5;
this.cx = this.xb = this.ex = 0;
this.cy = this.yb = this.ey = 0;
this.cz = this.ez = 0;
this.temp = 0;
this.speed = 0.001;
this.isDown = false;
this.add(window, "mousemove,touchmove", e => this.move(e));
this.add(canvas.elem, "mousedown,touchstart", e => {
this.move(e);
this.isDown = true;
this.xb = this.x;
this.yb = this.y;
webgl.elem.style.cursor = "move";
});
this.add(window, "mouseup,touchend,touchcancel", e => {
this.isDown = false;
webgl.elem.style.cursor = "pointer";
});
},
move(e) {
let touchMode = e.targetTouches,
pointer;
if (touchMode) {
e.preventDefault();
pointer = touchMode[0];
} else pointer = e;
this.x = pointer.clientX;
this.y = pointer.clientY;
},
add(elem, events, fn) {
for (let i = 0, e = events.split(","); i < e.length; i++) {
elem.addEventListener(e[i], fn, false);
}
},
rotate() {
if (this.isDown) {
this.cx += (this.x - this.xb) / 200;
this.cy += (this.y - this.yb) / 200;
if (this.cx > Math.PI / 2) this.cx = Math.PI / 2;
if (this.cx < -Math.PI / 2) this.cx = -Math.PI / 2;
if (this.cy > Math.PI / 2) this.cy = Math.PI / 2;
if (this.cy < -Math.PI / 2) this.cy = -Math.PI / 2;
this.tempo = 0;
if (
this.ex > -0.2 &&
this.ex < 0.2 &&
this.ey > -0.2 &&
this.ey < 0.2 &&
this.speed < 0.15
) {
this.speed *= 1.005;
}
if (this.speed > 0.1) {
this.ez += 0.01;
this.ez = this.ez % (2 * Math.PI);
}
} else {
if (this.tempo > 100) {
this.cx *= 0.995;
this.cy *= 0.995;
this.ez *= 0.99;
}
if (this.speed > 0.004) this.speed *= 0.99;
if (this.speed < 0.004) this.speed *= 1.02;
}
this.xb = this.x;
this.yb = this.y;
this.ex += (this.cx - this.ex) * 0.1;
this.ey += (this.cy - this.ey) * 0.1;
this.tempo++;
}
};
const Block = class {
constructor(x, y, z) {
this.indices = [];
this.vertices = [];
this.normals = [];
this.colors = [];
this.matrix = webgl.mat4().translate(x, y, z).uniform("modelMatrix");
const ax = Math.abs(x);
const ay = Math.abs(y);
const md = (ax < 2 && ay < 2) ? 3 : (ax < 3 && ay <3 ? 1 : 0);
this.fractalCube(0, 0, 0, 1, md, 0);
this.aPosition = new webgl.Attribute("aPosition").load(this.vertices, 3).loadIndices(this.indices);
this.aNormal = new webgl.Attribute("aNormal").load(this.normals, 3);
this.aColor = new webgl.Attribute("aColor").load(this.colors, 3);
}
blockType() {
const blockTypes = [
[
[-0.4, 0, -0.4, 0.2, 1, 0.2],
[-0.4, 0, 0.4, 0.2, 1, 0.2],
[0.4, 0, -0.4, 0.2, 1, 0.2],
[0.4, 0, 0.4, 0.2, 1, 0.2],
[-0.4, -0.4, 0, 0.2, 0.2, 1],
[-0.4, 0.4, 0, 0.2, 0.2, 1],
[0.4, -0.4, 0, 0.2, 0.2, 1],
[0.4, 0.4, 0, 0.2, 0.2, 1],
[0, -0.4, -0.4, 1, 0.2, 0.2],
[0, 0.4, -0.4, 1, 0.2, 0.2],
[0, -0.4, 0.4, 1, 0.2, 0.2],
[0, 0.4, 0.4, 1, 0.2, 0.2]
],
[
[-0.475, 0, -0.475, 0.051, 1, 0.051, 0.5, 0.4, 0],
[-0.475, 0, 0.475, 0.051, 1, 0.051, 0.5, 0.4, 0],
[0.475, 0, -0.475, 0.051, 1, 0.051, 0.5, 0.4, 0],
[0.475, 0, 0.475, 0.051, 1, 0.051, 0.5, 0.4, 0],
[-0.475, -0.475, 0, 0.051, 0.051, 1, 0.5, 0.4, 0],
[-0.475, 0.475, 0, 0.051, 0.051, 1, 0.5, 0.4, 0],
[0.475, -0.475, 0, 0.051, 0.051, 1, 0.5, 0.4, 0],
[0.475, 0.475, 0, 0.051, 0.051, 1, 0.5, 0.4, 0],
[0, -0.475, -0.475, 1, 0.051, 0.051, 0.5, 0.4, 0],
[0, 0.475, -0.475, 1, 0.051, 0.051, 0.5, 0.4, 0],
[0, -0.475, 0.475, 1, 0.051, 0.051, 0.5, 0.4, 0],
[0, 0.475, 0.475, 1, 0.051, 0.051, 0.5, 0.4, 0]
],
[[0, 0, 0, 1, 1, 1]],
[
[0, 0, 0, 1.01, 1.01, 1.01, 0.5, 0.4, 0],
[0, 0, -0.25, 1.02, 0.1, 0.15, 10, 9, 8],
[0, 0, 0, 1.02, 0.1, 0.15, 10, 9, 8],
[0, 0, 0.25, 1.02, 0.1, 0.15, 10, 9, 8]
],
[[0, -0.4, 0, 1, 0.1, 1]],
[[0, 0, 0, 0.5, 0.5, 0.5, 1.5, 1.0, 0.0]]
];
return blockTypes[Math.floor(Math.random() * blockTypes.length)];
}
concat(a1, a2) {
for (let i = 0, l = a2.length; i < l; i++) a1.push(a2[i]);
}
fractalCube(cx, cy, cz, scale, md, level) {
if (Math.random() > 0.85) return;
if (level < md && Math.random() > 0.75) {
const s = 0.25 * scale;
const r = scale / (1.75 - 0.25 * Math.random());
const l = level + 1;
this.fractalCube(cx - s, cy - s, cz + Math.random() > 0.5 ? s : -s, r, md, l);
this.fractalCube(cx + s, cy - s, cz + Math.random() > 0.5 ? s : -s, r, md, l);
this.fractalCube(cx - s, cy + s, cz + Math.random() > 0.5 ? s : -s, r, md, l);
this.fractalCube(cx + s, cy + s, cz + Math.random() > 0.5 ? s : -s, r, md, l);
} else {
const structure = this.blockType();
for (const cube of structure) {
this.concat(this.indices, webgl.cube.indices(this.vertices.length / 3));
this.concat(this.vertices, webgl.cube.vertices(
cx + cube[0] * scale,
cy + cube[1] * scale,
cz + cube[2] * scale,
cube[3] * scale / 2,
cube[4] * scale / 2,
cube[5] * scale / 2
));
this.concat(this.normals, webgl.cube.normals());
this.concat(this.colors, webgl.cube.colors(
cube[6] === undefined ? 1 : cube[6],
cube[7] === undefined ? 1 : cube[7],
cube[8] === undefined ? 1 : cube[8]
));
}
}
}
draw() {
this.matrix.load();
this.aNormal.bind();
this.aColor.bind();
this.aPosition.bind();
gl.drawElements(gl.TRIANGLES, this.aPosition.numIndices, gl.UNSIGNED_SHORT, 0);
}
};
const layer = z => {
for (let x = -4; x <= 4; x++) {
for (let y = -3; y <= 3; y++) {
if (x !== 0 || y !== 0) {
const b = new Block(x * 0.999, y * 0.999, z);
if (b.aPosition.numElements > 0) cubes.push(b);
}
}
}
return z - 1;
};
// ---- init ----
const gl = webgl.init();
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
pointer.init(webgl);
const camera = webgl.camera;
const cubes = [];
let z = layer(0);
let frame = 0;
let uTime = webgl.float().uniform("uTime");
webgl.uResolution = webgl
.vec2()
.set(webgl.width, webgl.height)
.uniform("uResolution")
.load();
// main loop
const run = () => {
requestAnimationFrame(run);
uTime.set(++frame / 20).load();
if (z > -12) {
// create structure
z = layer(z - 0.05);
} else {
// rotate world matrix
pointer.rotate();
camera.view
.identity()
.rotateZ(pointer.ez)
.rotateX(pointer.ey)
.rotateY(pointer.ex)
.load();
}
// draw blocs
for (const cube of cubes) {
cube.matrix.translate(0, 0, pointer.speed);
if (cube.matrix.matrix[14] > 3) cube.matrix.matrix[14] -= 13.0;
cube.draw();
}
};
requestAnimationFrame(run);
}