css3-anime/canvas/3DBackground/js/FSS.js

968 lines
28 KiB
JavaScript

function FSS(container, output){
FSS = {
FRONT: 0,
BACK: 1,
DOUBLE: 2,
SVGNS: "http://www.w3.org/2000/svg"
};
FSS.Array = "function" === typeof Float32Array ? Float32Array: Array;
FSS.Utils = {
isNumber: function(b) {
return ! isNaN(parseFloat(b)) && isFinite(b)
}
};
(function() {
for (var b = 0, d = ["ms", "moz", "webkit", "o"], h = 0; h < d.length && !window.requestAnimationFrame; ++h) window.requestAnimationFrame = window[d[h] + "RequestAnimationFrame"],
window.cancelAnimationFrame = window[d[h] + "CancelAnimationFrame"] || window[d[h] + "CancelRequestAnimationFrame"];
window.requestAnimationFrame || (window.requestAnimationFrame = function(d, h) {
var n = (new Date).getTime(),
s = Math.max(0, 16 - (n - b)),
k = window.setTimeout(function() {
d(n + s)
},
s);
b = n + s;
return k
});
window.cancelAnimationFrame || (window.cancelAnimationFrame = function(b) {
clearTimeout(b)
})
})();
Math.PIM2 = 2 * Math.PI;
Math.PID2 = Math.PI / 2;
Math.randomInRange = function(b, d) {
return b + (d - b) * Math.random()
};
Math.clamp = function(b, d, h) {
b = Math.max(b, d);
return b = Math.min(b, h)
};
FSS.Vector3 = {
create: function(b, d, h) {
var g = new FSS.Array(3);
this.set(g, b, d, h);
return g
},
clone: function(b) {
var d = this.create();
this.copy(d, b);
return d
},
set: function(b, d, h, g) {
b[0] = d || 0;
b[1] = h || 0;
b[2] = g || 0;
return this
},
setX: function(b, d) {
b[0] = d || 0;
return this
},
setY: function(b, d) {
b[1] = d || 0;
return this
},
setZ: function(b, d) {
b[2] = d || 0;
return this
},
copy: function(b, d) {
b[0] = d[0];
b[1] = d[1];
b[2] = d[2];
return this
},
add: function(b, d) {
b[0] += d[0];
b[1] += d[1];
b[2] += d[2];
return this
},
addVectors: function(b, d, h) {
b[0] = d[0] +
h[0];
b[1] = d[1] + h[1];
b[2] = d[2] + h[2];
return this
},
addScalar: function(b, d) {
b[0] += d;
b[1] += d;
b[2] += d;
return this
},
subtract: function(b, d) {
b[0] -= d[0];
b[1] -= d[1];
b[2] -= d[2];
return this
},
subtractVectors: function(b, d, h) {
b[0] = d[0] - h[0];
b[1] = d[1] - h[1];
b[2] = d[2] - h[2];
return this
},
subtractScalar: function(b, d) {
b[0] -= d;
b[1] -= d;
b[2] -= d;
return this
},
multiply: function(b, d) {
b[0] *= d[0];
b[1] *= d[1];
b[2] *= d[2];
return this
},
multiplyVectors: function(b, d, h) {
b[0] = d[0] * h[0];
b[1] = d[1] * h[1];
b[2] = d[2] * h[2];
return this
},
multiplyScalar: function(b, d) {
b[0] *= d;
b[1] *= d;
b[2] *= d;
return this
},
divide: function(b, d) {
b[0] /= d[0];
b[1] /= d[1];
b[2] /= d[2];
return this
},
divideVectors: function(b, d, h) {
b[0] = d[0] / h[0];
b[1] = d[1] / h[1];
b[2] = d[2] / h[2];
return this
},
divideScalar: function(b, d) {
0 !== d ? (b[0] /= d, b[1] /= d, b[2] /= d) : (b[0] = 0, b[1] = 0, b[2] = 0);
return this
},
cross: function(b, d) {
var h = b[0],
g = b[1],
l = b[2];
b[0] = g * d[2] - l * d[1];
b[1] = l * d[0] - h * d[2];
b[2] = h * d[1] - g * d[0];
return this
},
crossVectors: function(b, d, h) {
b[0] = d[1] * h[2] - d[2] * h[1];
b[1] = d[2] * h[0] - d[0] * h[2];
b[2] = d[0] * h[1] - d[1] * h[0];
return this
},
min: function(b, d) {
b[0] < d && (b[0] = d);
b[1] < d && (b[1] = d);
b[2] < d && (b[2] = d);
return this
},
max: function(b, d) {
b[0] > d && (b[0] = d);
b[1] > d && (b[1] = d);
b[2] > d && (b[2] = d);
return this
},
clamp: function(b, d, h) {
this.min(b, d);
this.max(b, h);
return this
},
limit: function(b, d, h) {
var g = this.length(b);
null !== d && g < d ? this.setLength(b, d) : null !== h && g > h && this.setLength(b, h);
return this
},
dot: function(b, d) {
return b[0] * d[0] + b[1] * d[1] + b[2] * d[2]
},
normalise: function(b) {
return this.divideScalar(b, this.length(b))
},
negate: function(b) {
return this.multiplyScalar(b, -1)
},
distanceSquared: function(b, d) {
var h = b[0] - d[0],
g = b[1] - d[1],
l = b[2] - d[2];
return h * h + g * g + l * l
},
distance: function(b, d) {
return Math.sqrt(this.distanceSquared(b, d))
},
lengthSquared: function(b) {
return b[0] * b[0] + b[1] * b[1] + b[2] * b[2]
},
length: function(b) {
return Math.sqrt(this.lengthSquared(b))
},
setLength: function(b, d) {
var h = this.length(b);
0 !== h && d !== h && this.multiplyScalar(b, d / h);
return this
}
};
FSS.Vector4 = {
create: function(b, d, h, g) {
g = new FSS.Array(4);
this.set(g, b, d, h);
return g
},
set: function(b, d, h, g, l) {
b[0] = d || 0;
b[1] = h || 0;
b[2] = g || 0;
b[3] = l || 0;
return this
},
setX: function(b, d) {
b[0] = d || 0;
return this
},
setY: function(b, d) {
b[1] = d || 0;
return this
},
setZ: function(b, d) {
b[2] = d || 0;
return this
},
setW: function(b, d) {
b[3] = d || 0;
return this
},
add: function(b, d) {
b[0] += d[0];
b[1] += d[1];
b[2] += d[2];
b[3] += d[3];
return this
},
multiplyVectors: function(b, d, h) {
b[0] = d[0] * h[0];
b[1] = d[1] * h[1];
b[2] = d[2] * h[2];
b[3] = d[3] * h[3];
return this
},
multiplyScalar: function(b, d) {
b[0] *= d;
b[1] *= d;
b[2] *= d;
b[3] *= d;
return this
},
min: function(b, d) {
b[0] < d && (b[0] = d);
b[1] < d && (b[1] = d);
b[2] < d && (b[2] = d);
b[3] < d && (b[3] = d);
return this
},
max: function(b, d) {
b[0] > d && (b[0] = d);
b[1] > d && (b[1] = d);
b[2] > d && (b[2] = d);
b[3] > d && (b[3] = d);
return this
},
clamp: function(b, d, h) {
this.min(b, d);
this.max(b, h);
return this
}
};
FSS.Color = function(b, d) {
this.rgba = FSS.Vector4.create();
this.hex = b || "#000000";
this.opacity = FSS.Utils.isNumber(d) ? d: 1;
this.set(this.hex, this.opacity)
};
FSS.Color.prototype = {
set: function(b, d) {
b = b.replace("#", "");
var h = b.length / 3;
this.rgba[0] = parseInt(b.substring(0 * h, 1 * h), 16) / 255;
this.rgba[1] = parseInt(b.substring(1 * h, 2 * h), 16) / 255;
this.rgba[2] = parseInt(b.substring(2 * h, 3 * h), 16) / 255;
this.rgba[3] = FSS.Utils.isNumber(d) ? d: this.rgba[3];
return this
},
hexify: function(b) {
b = Math.ceil(255 * b).toString(16);
1 === b.length && (b = "0" + b);
return b
},
format: function() {
var b = this.hexify(this.rgba[0]),
d = this.hexify(this.rgba[1]),
h = this.hexify(this.rgba[2]);
return this.hex = "#" +
b + d + h
}
};
FSS.Object = function() {
this.position = FSS.Vector3.create()
};
FSS.Object.prototype = {
setPosition: function(b, d, h) {
FSS.Vector3.set(this.position, b, d, h);
return this
}
};
FSS.Light = function(b, d) {
FSS.Object.call(this);
this.ambient = new FSS.Color(b || "#FFFFFF");
this.diffuse = new FSS.Color(d || "#FFFFFF");
this.ray = FSS.Vector3.create()
};
FSS.Light.prototype = Object.create(FSS.Object.prototype);
FSS.Vertex = function(b, d, h) {
this.position = FSS.Vector3.create(b, d, h)
};
FSS.Vertex.prototype = {
setPosition: function(b, d, h) {
FSS.Vector3.set(this.position, b, d, h);
return this
}
};
FSS.Triangle = function(b, d, h) {
this.a = b || new FSS.Vertex;
this.b = d || new FSS.Vertex;
this.c = h || new FSS.Vertex;
this.vertices = [this.a, this.b, this.c];
this.u = FSS.Vector3.create();
this.v = FSS.Vector3.create();
this.centroid = FSS.Vector3.create();
this.normal = FSS.Vector3.create();
this.color = new FSS.Color;
this.polygon = document.createElementNS(FSS.SVGNS, "polygon");
this.polygon.setAttributeNS(null, "stroke-linejoin", "round");
this.polygon.setAttributeNS(null, "stroke-miterlimit", "1");
this.polygon.setAttributeNS(null, "stroke-width", "1");
this.computeCentroid();
this.computeNormal()
};
FSS.Triangle.prototype = {
computeCentroid: function() {
this.centroid[0] = this.a.position[0] + this.b.position[0] + this.c.position[0];
this.centroid[1] = this.a.position[1] + this.b.position[1] + this.c.position[1];
this.centroid[2] = this.a.position[2] + this.b.position[2] + this.c.position[2];
FSS.Vector3.divideScalar(this.centroid, 3);
return this
},
computeNormal: function() {
FSS.Vector3.subtractVectors(this.u, this.b.position, this.a.position);
FSS.Vector3.subtractVectors(this.v, this.c.position, this.a.position);
FSS.Vector3.crossVectors(this.normal, this.u, this.v);
FSS.Vector3.normalise(this.normal);
return this
}
};
FSS.Geometry = function() {
this.vertices = [];
this.triangles = [];
this.dirty = !1
};
FSS.Geometry.prototype = {
update: function() {
if (this.dirty) {
var b,
d;
for (b = this.triangles.length - 1; 0 <= b; b--) d = this.triangles[b],
d.computeCentroid(),
d.computeNormal();
this.dirty = !1
}
return this
}
};
FSS.Plane = function(b, d, h, g) {
FSS.Geometry.call(this);
this.width = b || 100;
this.height = d || 100;
this.segments = h || 4;
this.slices = g || 4;
this.segmentWidth = this.width / this.segments;
this.sliceHeight = this.height / this.slices;
var l,
n,
s;
h = [];
l = -0.5 * this.width;
n = 0.5 * this.height;
for (b = 0; b <= this.segments; b++) for (h.push([]), d = 0; d <= this.slices; d++) g = new FSS.Vertex(l + b * this.segmentWidth, n - d * this.sliceHeight),
h[b].push(g),
this.vertices.push(g);
for (b = 0; b < this.segments; b++) for (d = 0; d < this.slices; d++) g = h[b + 0][d + 0],
l = h[b + 0][d +
1],
n = h[b + 1][d + 0],
s = h[b + 1][d + 1],
t0 = new FSS.Triangle(g, l, n),
t1 = new FSS.Triangle(n, l, s),
this.triangles.push(t0, t1)
};
FSS.Plane.prototype = Object.create(FSS.Geometry.prototype);
FSS.Material = function(b, d) {
this.ambient = new FSS.Color(b || "#444444");
this.diffuse = new FSS.Color(d || "#FFFFFF");
this.slave = new FSS.Color
};
FSS.Mesh = function(b, d) {
FSS.Object.call(this);
this.geometry = b || new FSS.Geometry;
this.material = d || new FSS.Material;
this.side = FSS.FRONT;
this.visible = !0
};
FSS.Mesh.prototype = Object.create(FSS.Object.prototype);
FSS.Mesh.prototype.update = function(b, d) {
var h,
g,
l,
n,
s;
this.geometry.update();
if (d) for (h = this.geometry.triangles.length - 1; 0 <= h; h--) {
g = this.geometry.triangles[h];
FSS.Vector4.set(g.color.rgba);
for (l = b.length - 1; 0 <= l; l--) n = b[l],
FSS.Vector3.subtractVectors(n.ray, n.position, g.centroid),
FSS.Vector3.normalise(n.ray),
s = FSS.Vector3.dot(g.normal, n.ray),
this.side === FSS.FRONT ? s = Math.max(s, 0) : this.side === FSS.BACK ? s = Math.abs(Math.min(s, 0)) : this.side === FSS.DOUBLE && (s = Math.max(Math.abs(s), 0)),
FSS.Vector4.multiplyVectors(this.material.slave.rgba, this.material.ambient.rgba, n.ambient.rgba),
FSS.Vector4.add(g.color.rgba, this.material.slave.rgba),
FSS.Vector4.multiplyVectors(this.material.slave.rgba, this.material.diffuse.rgba, n.diffuse.rgba),
FSS.Vector4.multiplyScalar(this.material.slave.rgba, s),
FSS.Vector4.add(g.color.rgba, this.material.slave.rgba);
FSS.Vector4.clamp(g.color.rgba, 0, 1)
}
return this
};
FSS.Scene = function() {
this.meshes = [];
this.lights = []
};
FSS.Scene.prototype = {
add: function(b) {
b instanceof FSS.Mesh && !~this.meshes.indexOf(b) ? this.meshes.push(b) : b instanceof FSS.Light && !~this.lights.indexOf(b) && this.lights.push(b);
return this
},
remove: function(b) {
b instanceof FSS.Mesh && ~this.meshes.indexOf(b) ? this.meshes.splice(this.meshes.indexOf(b), 1) : b instanceof FSS.Light && ~this.lights.indexOf(b) && this.lights.splice(this.lights.indexOf(b), 1);
return this
}
};
FSS.Renderer = function() {
this.halfHeight = this.halfWidth = this.height = this.width = 0
};
FSS.Renderer.prototype = {
setSize: function(b, d) {
if (this.width !== b || this.height !== d) return this.width = b,
this.height = d,
this.halfWidth = 0.5 * this.width,
this.halfHeight = 0.5 * this.height,
this
},
clear: function() {
return this
},
render: function(b) {
return this
}
};
FSS.CanvasRenderer = function() {
FSS.Renderer.call(this);
this.element = document.createElement("canvas");
this.element.style.display = "block";
this.context = this.element.getContext("2d");
this.setSize(this.element.width, this.element.height)
};
FSS.CanvasRenderer.prototype = Object.create(FSS.Renderer.prototype);
FSS.CanvasRenderer.prototype.setSize = function(b, d) {
FSS.Renderer.prototype.setSize.call(this, b, d);
this.element.width = b;
this.element.height = d;
this.context.setTransform(1, 0, 0, -1, this.halfWidth, this.halfHeight);
return this
};
FSS.CanvasRenderer.prototype.clear = function() {
FSS.Renderer.prototype.clear.call(this);
this.context.clearRect( - this.halfWidth, -this.halfHeight, this.width, this.height);
return this
};
FSS.CanvasRenderer.prototype.render = function(b) {
FSS.Renderer.prototype.render.call(this, b);
var d,
h,
g,
l,
n;
this.clear();
this.context.lineJoin = "round";
this.context.lineWidth = 1;
for (d = b.meshes.length - 1; 0 <= d; d--) if (h = b.meshes[d], h.visible) for (h.update(b.lights, !0), g = h.geometry.triangles.length - 1; 0 <= g; g--) l = h.geometry.triangles[g],
n = l.color.format(),
this.context.beginPath(),
this.context.moveTo(l.a.position[0], l.a.position[1]),
this.context.lineTo(l.b.position[0], l.b.position[1]),
this.context.lineTo(l.c.position[0], l.c.position[1]),
this.context.closePath(),
this.context.strokeStyle = n,
this.context.fillStyle = n,
this.context.stroke(),
this.context.fill();
return this
};
FSS.WebGLRenderer = function() {
FSS.Renderer.call(this);
this.element = document.createElement("canvas");
this.element.style.display = "block";
this.lights = this.vertices = null;
this.gl = this.getContext(this.element, {
preserveDrawingBuffer: !1,
premultipliedAlpha: !0,
antialias: !0,
stencil: !0,
alpha: !0
});
if (this.unsupported = !this.gl) return "WebGL is not supported by your browser.";
this.gl.clearColor(0, 0, 0, 0);
this.gl.enable(this.gl.DEPTH_TEST);
this.setSize(this.element.width, this.element.height)
};
FSS.WebGLRenderer.prototype = Object.create(FSS.Renderer.prototype);
FSS.WebGLRenderer.prototype.getContext = function(b, d) {
var h = !1;
try {
if (! (h = b.getContext("experimental-webgl", d))) throw "Error creating WebGL context.";
} catch(g) {
// console.error(g);
}
return h
};
FSS.WebGLRenderer.prototype.setSize = function(b, d) {
FSS.Renderer.prototype.setSize.call(this, b, d);
if (!this.unsupported) return this.element.width = b,
this.element.height = d,
this.gl.viewport(0, 0, b, d),
this
};
FSS.WebGLRenderer.prototype.clear = function() {
FSS.Renderer.prototype.clear.call(this);
if (!this.unsupported) return this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT),
this
};
FSS.WebGLRenderer.prototype.render = function(b) {
FSS.Renderer.prototype.render.call(this, b);
if (!this.unsupported) {
var d,
h,
g,
l,
n,
s,
k,
m;
s = !1;
var r = b.lights.length,
u,
E,
y,
z = 0;
this.clear();
if (this.lights !== r) if (this.lights = r, 0 < this.lights) this.buildProgram(r);
else return;
if (this.program) {
for (d = b.meshes.length - 1; 0 <= d; d--) h = b.meshes[d],
h.geometry.dirty && (s = !0),
h.update(b.lights, !1),
z += 3 * h.geometry.triangles.length;
if (s || this.vertices !== z) for (k in this.vertices = z, this.program.attributes) {
s = this.program.attributes[k];
s.data = new FSS.Array(z * s.size);
u = 0;
for (d = b.meshes.length - 1; 0 <= d; d--) for (h = b.meshes[d], g = 0, l = h.geometry.triangles.length; g < l; g++) for (n = h.geometry.triangles[g], E = 0, y = n.vertices.length; E < y; E++) {
vertex = n.vertices[E];
switch (k) {
case "side":
this.setBufferData(u, s, h.side);
break;
case "position":
this.setBufferData(u, s, vertex.position);
break;
case "centroid":
this.setBufferData(u, s, n.centroid);
break;
case "normal":
this.setBufferData(u, s, n.normal);
break;
case "ambient":
this.setBufferData(u, s, h.material.ambient.rgba);
break;
case "diffuse":
this.setBufferData(u, s, h.material.diffuse.rgba)
}
u++
}
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, s.buffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, s.data, this.gl.DYNAMIC_DRAW);
this.gl.enableVertexAttribArray(s.location);
this.gl.vertexAttribPointer(s.location, s.size, this.gl.FLOAT, !1, 0, 0)
}
this.setBufferData(0, this.program.uniforms.resolution, [this.width, this.height, this.width]);
for (s = r - 1; 0 <= s; s--) d = b.lights[s],
this.setBufferData(s, this.program.uniforms.lightPosition, d.position),
this.setBufferData(s, this.program.uniforms.lightAmbient, d.ambient.rgba),
this.setBufferData(s, this.program.uniforms.lightDiffuse, d.diffuse.rgba);
for (m in this.program.uniforms) switch (s = this.program.uniforms[m], d = s.location, b = s.data, s.structure) {
case "3f":
this.gl.uniform3f(d, b[0], b[1], b[2]);
break;
case "3fv":
this.gl.uniform3fv(d, b);
break;
case "4fv":
this.gl.uniform4fv(d, b)
}
}
this.gl.drawArrays(this.gl.TRIANGLES, 0, this.vertices);
return this
}
};
FSS.WebGLRenderer.prototype.setBufferData = function(b, d, h) {
if (FSS.Utils.isNumber(h)) d.data[b * d.size] = h;
else for (var g = h.length - 1; 0 <= g; g--) d.data[b * d.size + g] = h[g]
};
FSS.WebGLRenderer.prototype.buildProgram = function(b) {
if (!this.unsupported) {
var d = FSS.WebGLRenderer.VS(b),
h = FSS.WebGLRenderer.FS(b),
g = d + h;
if (!this.program || this.program.code !== g) {
var l = this.gl.createProgram(),
d = this.buildShader(this.gl.VERTEX_SHADER, d),
h = this.buildShader(this.gl.FRAGMENT_SHADER, h);
this.gl.attachShader(l, d);
this.gl.attachShader(l, h);
this.gl.linkProgram(l);
if (!this.gl.getProgramParameter(l, this.gl.LINK_STATUS)) return b = this.gl.getError(),
l = this.gl.getProgramParameter(l, this.gl.VALIDATE_STATUS),
console.error("Could not initialise shader.\nVALIDATE_STATUS: " + l + "\nERROR: " + b),
null;
this.gl.deleteShader(h);
this.gl.deleteShader(d);
l.code = g;
l.attributes = {
side: this.buildBuffer(l, "attribute", "aSide", 1, "f"),
position: this.buildBuffer(l, "attribute", "aPosition", 3, "v3"),
centroid: this.buildBuffer(l, "attribute", "aCentroid", 3, "v3"),
normal: this.buildBuffer(l, "attribute", "aNormal", 3, "v3"),
ambient: this.buildBuffer(l, "attribute", "aAmbient", 4, "v4"),
diffuse: this.buildBuffer(l, "attribute", "aDiffuse", 4, "v4")
};
l.uniforms = {
resolution: this.buildBuffer(l, "uniform", "uResolution", 3, "3f", 1),
lightPosition: this.buildBuffer(l, "uniform", "uLightPosition", 3, "3fv", b),
lightAmbient: this.buildBuffer(l, "uniform", "uLightAmbient", 4, "4fv", b),
lightDiffuse: this.buildBuffer(l, "uniform", "uLightDiffuse", 4, "4fv", b)
};
this.program = l;
this.gl.useProgram(this.program);
return l
}
}
};
FSS.WebGLRenderer.prototype.buildShader = function(b, d) {
if (!this.unsupported) {
var h = this.gl.createShader(b);
this.gl.shaderSource(h, d);
this.gl.compileShader(h);
return this.gl.getShaderParameter(h, this.gl.COMPILE_STATUS) ? h: (console.error(this.gl.getShaderInfoLog(h)), null)
}
};
FSS.WebGLRenderer.prototype.buildBuffer = function(b, d, h, g, l, n) {
l = {
buffer: this.gl.createBuffer(),
size: g,
structure: l,
data: null
};
switch (d) {
case "attribute":
l.location = this.gl.getAttribLocation(b, h);
break;
case "uniform":
l.location = this.gl.getUniformLocation(b, h)
}
n && (l.data = new FSS.Array(n * g));
return l
};
FSS.WebGLRenderer.VS = function(b) {
return ["precision mediump float;", "#define LIGHTS " + b, "attribute float aSide;\nattribute vec3 aPosition;\nattribute vec3 aCentroid;\nattribute vec3 aNormal;\nattribute vec4 aAmbient;\nattribute vec4 aDiffuse;\nuniform vec3 uResolution;\nuniform vec3 uLightPosition[LIGHTS];\nuniform vec4 uLightAmbient[LIGHTS];\nuniform vec4 uLightDiffuse[LIGHTS];\nvarying vec4 vColor;\nvoid main() {\nvColor = vec4(0.0);\nvec3 position = aPosition / uResolution * 2.0;\nfor (int i = 0; i < LIGHTS; i++) {\nvec3 lightPosition = uLightPosition[i];\nvec4 lightAmbient = uLightAmbient[i];\nvec4 lightDiffuse = uLightDiffuse[i];\nvec3 ray = normalize(lightPosition - aCentroid);\nfloat illuminance = dot(aNormal, ray);\nif (aSide == 0.0) {\nilluminance = max(illuminance, 0.0);\n} else if (aSide == 1.0) {\nilluminance = abs(min(illuminance, 0.0));\n} else if (aSide == 2.0) {\nilluminance = max(abs(illuminance), 0.0);\n}\nvColor += aAmbient * lightAmbient;\nvColor += aDiffuse * lightDiffuse * illuminance;\n}\nvColor = clamp(vColor, 0.0, 1.0);\ngl_Position = vec4(position, 1.0);\n}"].join("\n")
};
FSS.WebGLRenderer.FS = function(b) {
return "precision mediump float;\nvarying vec4 vColor;\nvoid main() {\ngl_FragColor = vColor;\n}"
};
FSS.SVGRenderer = function() {
FSS.Renderer.call(this);
this.element = document.createElementNS(FSS.SVGNS, "svg");
this.element.setAttribute("xmlns", FSS.SVGNS);
this.element.setAttribute("version", "1.1");
this.element.style.display = "block";
this.setSize(300, 150)
};
FSS.SVGRenderer.prototype = Object.create(FSS.Renderer.prototype);
FSS.SVGRenderer.prototype.setSize = function(b, d) {
FSS.Renderer.prototype.setSize.call(this, b, d);
this.element.setAttribute("width", b);
this.element.setAttribute("height", d);
return this
};
FSS.SVGRenderer.prototype.clear = function() {
FSS.Renderer.prototype.clear.call(this);
for (var b = this.element.childNodes.length - 1; 0 <= b; b--) this.element.removeChild(this.element.childNodes[b]);
return this
};
FSS.SVGRenderer.prototype.render = function(b) {
FSS.Renderer.prototype.render.call(this, b);
var d,
h,
g,
l,
n,
s;
for (d = b.meshes.length - 1; 0 <= d; d--) if (h = b.meshes[d], h.visible) for (h.update(b.lights, !0), g = h.geometry.triangles.length - 1; 0 <= g; g--) l = h.geometry.triangles[g],
l.polygon.parentNode !== this.element && this.element.appendChild(l.polygon),
n = this.formatPoint(l.a) + " ",
n += this.formatPoint(l.b) + " ",
n += this.formatPoint(l.c),
s = this.formatStyle(l.color.format()),
l.polygon.setAttributeNS(null, "points", n),
l.polygon.setAttributeNS(null, "style", s);
return this
};
FSS.SVGRenderer.prototype.formatPoint = function(b) {
return this.halfWidth + b.position[0] + "," + (this.halfHeight - b.position[1])
};
FSS.SVGRenderer.prototype.formatStyle = function(b) {
return b = "fill:" + b + ";" + ("stroke:" + b + ";")
};
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ||
function() {
function b() {
B.remove(G);
D.clear();
H = new FSS.Plane(l.width * D.width, l.height * D.height, l.segments, l.slices);
J = new FSS.Material(l.ambient, l.diffuse);
G = new FSS.Mesh(H, J);
B.add(G);
var b,
d;
for (b = H.vertices.length - 1; 0 <= b; b--) d = H.vertices[b],
d.anchor = FSS.Vector3.clone(d.position),
d.step = FSS.Vector3.create(Math.randomInRange(0.2, 1), Math.randomInRange(0.2, 1), Math.randomInRange(0.2, 1)),
d.time = Math.randomInRange(0, Math.PIM2)
}
function d(d, g) {
D.setSize(d, g);
FSS.Vector3.set(E, D.halfWidth, D.halfHeight);
b()
}
function h() {
r = Date.now() - u;
var b,
d,
k,
m,
s,
z = l.depth / 2;
FSS.Vector3.copy(n.bounds, E);
FSS.Vector3.multiplyScalar(n.bounds, n.xyScalar);
FSS.Vector3.setZ(y, n.zOffset);
n.autopilot && (b = Math.sin(n.step[0] * r * n.speed), d = Math.cos(n.step[1] * r * n.speed), FSS.Vector3.set(y, n.bounds[0] * b, n.bounds[1] * d, n.zOffset));
for (b = B.lights.length - 1; 0 <= b; b--) d = B.lights[b],
FSS.Vector3.setZ(d.position, n.zOffset),
k = Math.clamp(FSS.Vector3.distanceSquared(d.position, y), n.minDistance, n.maxDistance),
k = n.gravity * d.mass / k,
FSS.Vector3.subtractVectors(d.force, y, d.position),
FSS.Vector3.normalise(d.force),
FSS.Vector3.multiplyScalar(d.force, k),
FSS.Vector3.set(d.acceleration),
FSS.Vector3.add(d.acceleration, d.force),
FSS.Vector3.add(d.velocity, d.acceleration),
FSS.Vector3.multiplyScalar(d.velocity, n.dampening),
FSS.Vector3.limit(d.velocity, n.minLimit, n.maxLimit),
FSS.Vector3.add(d.position, d.velocity);
for (m = H.vertices.length - 1; 0 <= m; m--) s = H.vertices[m],
b = Math.sin(s.time + s.step[0] * r * l.speed),
d = Math.cos(s.time + s.step[1] * r * l.speed),
k = Math.sin(s.time + s.step[2] * r * l.speed),
FSS.Vector3.set(s.position, l.xRange * H.segmentWidth * b, l.yRange * H.sliceHeight * d, l.zRange * z * k - z),
FSS.Vector3.add(s.position, s.anchor);
H.dirty = !0;
g();
requestAnimationFrame(h)
}
function g() {
D.render(B);
if (n.draw) {
var b,
d,
g,
h;
for (b = B.lights.length - 1; 0 <= b; b--) switch (h = B.lights[b], d = h.position[0], g = h.position[1], m.renderer) {
case s:
D.context.lineWidth = 0.5;
D.context.beginPath();
D.context.arc(d, g, 10, 0, Math.PIM2);
D.context.strokeStyle = h.ambientHex;
D.context.stroke();
D.context.beginPath();
D.context.arc(d, g, 4, 0, Math.PIM2);
D.context.fillStyle = h.diffuseHex;
D.context.fill();
break;
case k:
d += D.halfWidth,
g = D.halfHeight - g,
h.core.setAttributeNS(null, "fill", h.diffuseHex),
h.core.setAttributeNS(null, "cx", d),
h.core.setAttributeNS(null, "cy", g),
D.element.appendChild(h.core),
h.ring.setAttributeNS(null, "stroke", h.ambientHex),
h.ring.setAttributeNS(null, "cx", d),
h.ring.setAttributeNS(null, "cy", g),
D.element.appendChild(h.ring)
}
}
}
var l = {
width: 1.8,
height: 1.8,
depth: 10,
segments: 16,
slices: 8,
xRange: 0.8,
yRange: 0.1,
zRange: 1,
ambient: "#010101",
diffuse: "#ffffff",
speed: 6E-4,
opacity: 0.5
},
n = {
count: 2,
xyScalar: 1,
zOffset: 100,
ambient: "#ffffff",
diffuse: "#2d2d2d",
speed: 0.001,
gravity: 800,
dampening: 0.95,
minLimit: 10,
maxLimit: null,
minDistance: 20,
maxDistance: 400,
autopilot: !1,
draw: !1,
bounds: FSS.Vector3.create(),
step: FSS.Vector3.create(Math.randomInRange(0.2, 1), Math.randomInRange(0.2, 1), Math.randomInRange(0.2, 1))
},
s = "canvas",
k = "svg",
m = {
renderer: s
},
r,
u = Date.now(),
E = FSS.Vector3.create(),
y = FSS.Vector3.create(),
z = document.getElementById(container || "container");
document.getElementById("controls");
var X = document.getElementById(output || "output");
document.getElementById("ui");
var D,
B,
G,
H,
J,
R,
C,
S;
R = new FSS.WebGLRenderer;
C = new FSS.CanvasRenderer;
S = new FSS.SVGRenderer; (function(b) {
D && X.removeChild(D.element);
switch (b) {
case "webgl":
D = R;
break;
case s:
D = C;
break;
case k:
D = S
}
D.setSize(z.offsetWidth, z.offsetHeight);
X.appendChild(D.element)
})(m.renderer);
B = new FSS.Scene;
b(); (function() {
var b,
d;
for (b = B.lights.length -
1; 0 <= b; b--) d = B.lights[b],
B.remove(d);
D.clear();
for (b = 0; b < n.count; b++) d = new FSS.Light(n.ambient, n.diffuse),
d.ambientHex = d.ambient.format(),
d.diffuseHex = d.diffuse.format(),
B.add(d),
d.mass = Math.randomInRange(0.5, 1),
d.velocity = FSS.Vector3.create(),
d.acceleration = FSS.Vector3.create(),
d.force = FSS.Vector3.create(),
d.ring = document.createElementNS(FSS.SVGNS, "circle"),
d.ring.setAttributeNS(null, "stroke", d.ambientHex),
d.ring.setAttributeNS(null, "stroke-width", "0.5"),
d.ring.setAttributeNS(null, "fill", "none"),
d.ring.setAttributeNS(null, "r", "10"),
d.core = document.createElementNS(FSS.SVGNS, "circle"),
d.core.setAttributeNS(null, "fill", d.diffuseHex),
d.core.setAttributeNS(null, "r", "4")
})();
window.addEventListener("resize",
function(b) {
d(z.offsetWidth, z.offsetHeight);
g()
});
z.addEventListener("click",
function(b) {
FSS.Vector3.set(y, b.x, D.height - b.y);
FSS.Vector3.subtract(y, E);
n.autopilot = !n.autopilot; (void 0).updateDisplay()
});
z.addEventListener("mousemove",
function(b) {
FSS.Vector3.set(y, b.x, D.height - b.y);
FSS.Vector3.subtract(y, E)
});
d(z.offsetWidth, z.offsetHeight);
h()
} ();
}