Canvas三角图形背景生成器代码

版权:原创 更新时间:1年以上
[该文章底部包含文件资源,可根据自己情况,决定是否下载资源使用,时间>金钱,如有需要,立即查看资源]

以下是 Canvas三角图形背景生成器代码 的示例演示效果:

当前平台(PC电脑)
  • 平台:

部分效果截图1:

Canvas三角图形背景生成器代码

部分效果截图2:

Canvas三角图形背景生成器代码

HTML代码(index.html):

<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<title>Canvas三角图形背景生成器代码 </title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>

<div id="container" class="container">
	<div id="output" class="container"></div>
</div>

<div id="controls" class="controls"></div>

<script src="js/index.js"></script>

</body>
</html>

JS代码(index.js):

var Delaunay;
	(function(){
	"use strict";
	var EPSILON = 1.0 / 1048576.0;
	function supertriangle(vertices){
	var xmin = Number.POSITIVE_INFINITY,ymin = Number.POSITIVE_INFINITY,xmax = Number.NEGATIVE_INFINITY,ymax = Number.NEGATIVE_INFINITY,i,dx,dy,dmax,xmid,ymid;
	for(i = vertices.length;
	i--;
	){
	if(vertices[i][0] < xmin) xmin = vertices[i][0];
	if(vertices[i][0] > xmax) xmax = vertices[i][0];
	if(vertices[i][1] < ymin) ymin = vertices[i][1];
	if(vertices[i][1] > ymax) ymax = vertices[i][1];
}
dx = xmax - xmin;
	dy = ymax - ymin;
	dmax = Math.max(dx,dy);
	xmid = xmin + dx * 0.5;
	ymid = ymin + dy * 0.5;
	return [ [xmid - 20 * dmax,ymid - dmax],[xmid,ymid + 20 * dmax],[xmid + 20 * dmax,ymid - dmax] ];
}
function circumcircle(vertices,i,j,k){
	var x1 = vertices[i][0],y1 = vertices[i][1],x2 = vertices[j][0],y2 = vertices[j][1],x3 = vertices[k][0],y3 = vertices[k][1],fabsy1y2 = Math.abs(y1 - y2),fabsy2y3 = Math.abs(y2 - y3),xc,yc,m1,m2,mx1,mx2,my1,my2,dx,dy;
	/* Check for coincident points */
 if(fabsy1y2 < EPSILON && fabsy2y3 < EPSILON) throw new Error("Eek! Coincident points!");
	if(fabsy1y2 < EPSILON){
	m2 = -((x3 - x2) / (y3 - y2));
	mx2 = (x2 + x3) / 2.0;
	my2 = (y2 + y3) / 2.0;
	xc = (x2 + x1) / 2.0;
	yc = m2 * (xc - mx2) + my2;
}
else if(fabsy2y3 < EPSILON){
	m1 = -((x2 - x1) / (y2 - y1));
	mx1 = (x1 + x2) / 2.0;
	my1 = (y1 + y2) / 2.0;
	xc = (x3 + x2) / 2.0;
	yc = m1 * (xc - mx1) + my1;
}
else{
	m1 = -((x2 - x1) / (y2 - y1));
	m2 = -((x3 - x2) / (y3 - y2));
	mx1 = (x1 + x2) / 2.0;
	mx2 = (x2 + x3) / 2.0;
	my1 = (y1 + y2) / 2.0;
	my2 = (y2 + y3) / 2.0;
	xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
	yc = (fabsy1y2 > fabsy2y3) ? m1 * (xc - mx1) + my1:m2 * (xc - mx2) + my2;
}
dx = x2 - xc;
	dy = y2 - yc;
	return{
	i:i,j:j,k:k,x:xc,y:yc,r:dx * dx + dy * dy}
;
}
function dedup(edges){
	var i,j,a,b,m,n;
	for(j = edges.length;
	j;
	){
	b = edges[--j];
	a = edges[--j];
	for(i = j;
	i;
	){
	n = edges[--i];
	m = edges[--i];
	if((a === m && b === n) || (a === n && b === m)){
	edges.splice(j,2);
	edges.splice(i,2);
	break;
}
}
}
}
Delaunay ={
	triangulate:function(vertices,key){
	var n = vertices.length,i,j,indices,st,open,closed,edges,dx,dy,a,b,c;
	/* Bail if there aren't enough vertices to form any triangles. */
 if(n < 3) return [];
	/* Slice out the actual vertices from the passed objects. (Duplicate the * array even if we don't,though,since we need to make a supertriangle * later on!) */
 vertices = vertices.slice(0);
	if(key) for(i = n;
	i--;
	) vertices[i] = vertices[i][key];
	/* Make an array of indices into the vertex array,sorted by the * vertices' x-position. */
 indices = new Array(n);
	for(i = n;
	i--;
	) indices[i] = i;
	indices.sort(function(i,j){
	return vertices[j][0] - vertices[i][0];
}
);
	/* Next,find the vertices of the supertriangle (which contains all other * triangles),and append them onto the end of a (copy of) the vertex * array. */
 st = supertriangle(vertices);
	vertices.push(st[0],st[1],st[2]);
	/* Initialize the open list (containing the supertriangle and nothing * else) and the closed list (which is empty since we havn't processed * any triangles yet). */
 open = [circumcircle(vertices,n + 0,n + 1,n + 2)];
	closed = [];
	edges = [];
	/* Incrementally add each vertex to the mesh. */
 for(i = indices.length;
	i--;
	edges.length = 0){
	c = indices[i];
	/* For each open triangle,check to see if the current point is * inside it's circumcircle. If it is,remove the triangle and add * it's edges to an edge list. */
 for(j = open.length;
	j--;
	){
	/* If this point is to the right of this triangle's circumcircle,* then this triangle should never get checked again. Remove it * from the open list,add it to the closed list,and skip. */
 dx = vertices[c][0] - open[j].x;
	if(dx > 0.0 && dx * dx > open[j].r){
	closed.push(open[j]);
	open.splice(j,1);
	continue;
}
/* If we're outside the circumcircle,skip this triangle. */
 dy = vertices[c][1] - open[j].y;
	if(dx * dx + dy * dy - open[j].r > EPSILON) continue;
	/* Remove the triangle and add it's edges to the edge list. */
 edges.push( open[j].i,open[j].j,open[j].j,open[j].k,open[j].k,open[j].i );
	open.splice(j,1);
}
/* Remove any doubled edges. */
 dedup(edges);
	/* Add a new triangle for each edge. */
 for(j = edges.length;
	j;
	){
	b = edges[--j];
	a = edges[--j];
	open.push(circumcircle(vertices,a,b,c));
}
}
/* Copy any remaining open triangles to the closed list,and then * remove any triangles that share a vertex with the supertriangle,* building a list of triplets that represent triangles. */
 for(i = open.length;
	i--;
	) closed.push(open[i]);
	open.length = 0;
	for(i = closed.length;
	i--;
	) if(closed[i].i < n && closed[i].j < n && closed[i].k < n) open.push(closed[i].i,closed[i].j,closed[i].k);
	/* Yay,we're done! */
 return open;
}
,contains:function(tri,p){
	/* Bounding box test first,for quick rejections. */
 if((p[0] < tri[0][0] && p[0] < tri[1][0] && p[0] < tri[2][0]) || (p[0] > tri[0][0] && p[0] > tri[1][0] && p[0] > tri[2][0]) || (p[1] < tri[0][1] && p[1] < tri[1][1] && p[1] < tri[2][1]) || (p[1] > tri[0][1] && p[1] > tri[1][1] && p[1] > tri[2][1])) return null;
	var a = tri[1][0] - tri[0][0],b = tri[2][0] - tri[0][0],c = tri[1][1] - tri[0][1],d = tri[2][1] - tri[0][1],i = a * d - b * c;
	/* Degenerate tri. */
 if(i === 0.0) return null;
	var u = (d * (p[0] - tri[0][0]) - b * (p[1] - tri[0][1])) / i,v = (a * (p[1] - tri[0][1]) - c * (p[0] - tri[0][0])) / i;
	/* If we're outside the tri,fail. */
 if(u < 0.0 || v < 0.0 || (u + v) > 1.0) return null;
	return [u,v];
}
}
;
	if(typeof module !== "undefined") module.exports = Delaunay;
}
)();
	/* mousetrap v1.4.6 craig.is/killing/mice */
(function(J,r,f){
	function s(a,b,d){
	a.addEventListener?a.addEventListener(b,d,!1):a.attachEvent("on"+b,d)}
function A(a){
	if("keypress"==a.type){
	var b=String.fromCharCode(a.which);
	a.shiftKey||(b=b.toLowerCase());
	return b}
return h[a.which]?h[a.which]:B[a.which]?B[a.which]:String.fromCharCode(a.which).toLowerCase()}
function t(a){
	a=a||{
}
;
	var b=!1,d;
	for(d in n)a[d]?b=!0:n[d]=0;
	b||(u=!1)}
function C(a,b,d,c,e,v){
	var g,k,f=[],h=d.type;
	if(!l[a])return[];
	"keyup"==h&&w(a)&&(b=[a]);
	for(g=0;
	g<l[a].length;
	++g)if(k=l[a][g],!(!c&&k.seq&&n[k.seq]!=k.level||h!=k.action||("keypress"!=h||d.metaKey||d.ctrlKey)&&b.sort().join(",")!==k.modifiers.sort().join(","))){
	var m=c&&k.seq==c&&k.level==v;
	(!c&&k.combo==e||m)&&l[a].splice(g,1);
	f.push(k)}
return f}
function K(a){
	var b=[];
	a.shiftKey&&b.push("shift");
	a.altKey&&b.push("alt");
	a.ctrlKey&&b.push("ctrl");
	a.metaKey&&b.push("meta");
	return b}
function x(a,b,d,c){
	m.stopCallback(b,b.target||b.srcElement,d,c)||!1!==a(b,d)||(b.preventDefault?b.preventDefault():b.returnValue=!1,b.stopPropagation?b.stopPropagation():b.cancelBubble=!0)}
function y(a){
	"number"!==typeof a.which&&(a.which=a.keyCode);
	var b=A(a);
	b&&("keyup"==a.type&&z===b?z=!1:m.handleKey(b,K(a),a))}
function w(a){
	return"shift"==a||"ctrl"==a||"alt"==a||"meta"==a}
function L(a,b,d,c){
	function e(b){
	return function(){
	u=b;
	++n[a];
	clearTimeout(D);
	D=setTimeout(t,1E3)}
}
function v(b){
	x(d,b,a);
	"keyup"!==c&&(z=A(b));
	setTimeout(t,10)}
for(var g=n[a]=0;
	g<b.length;
	++g){
	var f=g+1===b.length?v:e(c||E(b[g+1]).action);
	F(b[g],f,c,a,g)}
}
function E(a,b){
	var d,c,e,f=[];
	d="+"===a?["+"]:a.split("+");
	for(e=0;
	e<d.length;
	++e)c=d[e],G[c]&&(c=G[c]),b&&"keypress"!=b&&H[c]&&(c=H[c],f.push("shift")),w(c)&&f.push(c);
	d=c;
	e=b;
	if(!e){
	if(!p){
	p={
}
;
	for(var g in h)95<g&&112>g||h.hasOwnProperty(g)&&(p[h[g]]=g)}
e=p[d]?"keydown":"keypress"}
"keypress"==e&&f.length&&(e="keydown");
	return{
	key:c,modifiers:f,action:e}
}
function F(a,b,d,c,e){
	q[a+":"+d]=b;
	a=a.replace(/\s+/g," ");
	var f=a.split(" ");
	1<f.length?L(a,f,b,d):(d=E(a,d),l[d.key]=l[d.key]||[],C(d.key,d.modifiers,{
	type:d.action}
,c,a,e),l[d.key][c?"unshift":"push"]({
	callback:b,modifiers:d.modifiers,action:d.action,seq:c,level:e,combo:a}
))}
var h={
	8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"}
,B={
	106:"*",107:"+",109:"-",110:".",111:"/",186:";
	",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"}
,H={
	"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";
	",'"':"'","<":",",">":".","?":"/","|":"\\"}
,G={
	option:"alt",command:"meta","return":"enter",escape:"esc",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"}
,p,l={
}
,q={
}
,n={
}
,D,z=!1,I=!1,u=!1;
	for(f=1;
	20>f;
	++f)h[111+f]="f"+f;
	for(f=0;
	9>=f;
	++f)h[f+96]=f;
	s(r,"keypress",y);
	s(r,"keydown",y);
	s(r,"keyup",y);
	var m={
	bind:function(a,b,d){
	a=a instanceof Array?a:[a];
	for(var c=0;
	c<a.length;
	++c)F(a[c],b,d);
	return this}
,unbind:function(a,b){
	return m.bind(a,function(){
}
,b)}
,trigger:function(a,b){
	if(q[a+":"+b])q[a+":"+b]({
}
,a);
	return this}
,reset:function(){
	l={
}
;
	q={
}
;
	return this}
,stopCallback:function(a,b){
	return-1<(" "+b.className+" ").indexOf(" mousetrap ")?!1:"INPUT"==b.tagName||"SELECT"==b.tagName||"TEXTAREA"==b.tagName||b.isContentEditable}
,handleKey:function(a,b,d){
	var c=C(a,b,d),e;
	b={
}
;
	var f=0,g=!1;
	for(e=0;
	e<c.length;
	++e)c[e].seq&&(f=Math.max(f,c[e].level));
	for(e=0;
	e<c.length;
	++e)c[e].seq?c[e].level==f&&(g=!0,b[c[e].seq]=1,x(c[e].callback,d,c[e].combo,c[e].seq)):g||x(c[e].callback,d,c[e].combo);
	c="keypress"==d.type&&I;
	d.type!=u||w(a)||c||t(b);
	I=g&&"keydown"==d.type}
}
;
	J.Mousetrap=m;
	"function"===typeof define&&define.amd&&define(m)}
)(window,document);
	/** * StyleFix 1.0.3 & PrefixFree 1.0.7 * @author Lea Verou * MIT license */
(function(){
	function t(e,t){
	return[].slice.call((t||document).querySelectorAll(e))}
if(!window.addEventListener)return;
	var e=window.StyleFix={
	link:function(t){
	try{
	if(t.rel!=="stylesheet"||t.hasAttribute("data-noprefix"))return}
catch(n){
	return}
var r=t.href||t.getAttribute("data-href"),i=r.replace(/[^\/]+$/,""),s=(/^[a-z]{
	3,10}
:/.exec(i)||[""])[0],o=(/^[a-z]{
	3,10}
:\/\/[^\/]+/.exec(i)||[""])[0],u=/^([^?]*)\??/.exec(r)[1],a=t.parentNode,f=new XMLHttpRequest,l;
	f.onreadystatechange=function(){
	f.readyState===4&&l()}
;
	l=function(){
	var n=f.responseText;
	if(n&&t.parentNode&&(!f.status||f.status<400||f.status>600)){
	n=e.fix(n,!0,t);
	if(i){
	n=n.replace(/url\(\s*?((?:"|')?)(.+?)\1\s*?\)/gi,function(e,t,n){
	return/^([a-z]{
	3,10}
:|#)/i.test(n)?e:/^\/\//.test(n)?'url("'+s+n+'")':/^\//.test(n)?'url("'+o+n+'")':/^\?/.test(n)?'url("'+u+n+'")':'url("'+i+n+'")'}
);
	var r=i.replace(/([\\\^\$*+[\]?{
}
.=!:(|)])/g,"\\$1");
	n=n.replace(RegExp("\\b(behavior:\\s*?url\\('?\"?)"+r,"gi"),"$1")}
var l=document.createElement("style");
	l.textContent=n;
	l.media=t.media;
	l.disabled=t.disabled;
	l.setAttribute("data-href",t.getAttribute("href"));
	a.insertBefore(l,t);
	a.removeChild(t);
	l.media=t.media}
}
;
	try{
	f.open("GET",r);
	f.send(null)}
catch(n){
	if(typeof XDomainRequest!="undefined"){
	f=new XDomainRequest;
	f.onerror=f.onprogress=function(){
}
;
	f.onload=l;
	f.open("GET",r);
	f.send(null)}
}
t.setAttribute("data-inprogress","")}
,styleElement:function(t){
	if(t.hasAttribute("data-noprefix"))return;
	var n=t.disabled;
	t.textContent=e.fix(t.textContent,!0,t);
	t.disabled=n}
,styleAttribute:function(t){
	var n=t.getAttribute("style");
	n=e.fix(n,!1,t);
	t.setAttribute("style",n)}
,process:function(){
	t('link[rel="stylesheet"]:not([data-inprogress])').forEach(StyleFix.link);
	t("style").forEach(StyleFix.styleElement);
	t("[style]").forEach(StyleFix.styleAttribute)}
,register:function(t,n){
	(e.fixers=e.fixers||[]).splice(n===undefined?e.fixers.length:n,0,t)}
,fix:function(t,n,r){
	for(var i=0;
	i<e.fixers.length;
	i++)t=e.fixers[i](t,n,r)||t;
	return t}
,camelCase:function(e){
	return e.replace(/-([a-z])/g,function(e,t){
	return t.toUpperCase()}
).replace("-","")}
,deCamelCase:function(e){
	return e.replace(/[A-Z]/g,function(e){
	return"-"+e.toLowerCase()}
)}
}
;
	(function(){
	setTimeout(function(){
	t('link[rel="stylesheet"]').forEach(StyleFix.link)}
,10);
	document.addEventListener("DOMContentLoaded",StyleFix.process,!1)}
)()}
)();
	(function(e){
	function t(e,t,r,i,s){
	e=n[e];
	if(e.length){
	var o=RegExp(t+"("+e.join("|")+")"+r,"gi");
	s=s.replace(o,i)}
return s}
if(!window.StyleFix||!window.getComputedStyle)return;
	var n=window.PrefixFree={
	prefixCSS:function(e,r,i){
	var s=n.prefix;
	n.functions.indexOf("linear-gradient")>-1&&(e=e.replace(/(\s|:|,)(repeating-)?linear-gradient\(\s*(-?\d*\.?\d*)deg/ig,function(e,t,n,r){
	return t+(n||"")+"linear-gradient("+(90-r)+"deg"}
));
	e=t("functions","(\\s|:|,)","\\s*\\(","$1"+s+"$2(",e);
	e=t("keywords","(\\s|:)","(\\s|;
	|\\}
|$)","$1"+s+"$2$3",e);
	e=t("properties","(^|\\{
	|\\s|;
	)","\\s*:","$1"+s+"$2:",e);
	if(n.properties.length){
	var o=RegExp("\\b("+n.properties.join("|")+")(?!:)","gi");
	e=t("valueProperties","\\b",":(.+?);
	",function(e){
	return e.replace(o,s+"$1")}
,e)}
if(r){
	e=t("selectors","","\\b",n.prefixSelector,e);
	e=t("atrules","@","\\b","@"+s+"$1",e)}
e=e.replace(RegExp("-"+s,"g"),"-");
	e=e.replace(/-\*-(?=[a-z]+)/gi,n.prefix);
	return e}
,property:function(e){
	return(n.properties.indexOf(e)?n.prefix:"")+e}
,value:function(e,r){
	e=t("functions","(^|\\s|,)","\\s*\\(","$1"+n.prefix+"$2(",e);
	e=t("keywords","(^|\\s)","(\\s|$)","$1"+n.prefix+"$2$3",e);
	return e}
,prefixSelector:function(e){
	return e.replace(/^:{
	1,2}
/,function(e){
	return e+n.prefix}
)}
,prefixProperty:function(e,t){
	var r=n.prefix+e;
	return t?StyleFix.camelCase(r):r}
}
;
	(function(){
	var e={
}
,t=[],r={
}
,i=getComputedStyle(document.documentElement,null),s=document.createElement("div").style,o=function(n){
	if(n.charAt(0)==="-"){
	t.push(n);
	var r=n.split("-"),i=r[1];
	e[i]=++e[i]||1;
	while(r.length>3){
	r.pop();
	var s=r.join("-");
	u(s)&&t.indexOf(s)===-1&&t.push(s)}
}
}
,u=function(e){
	return StyleFix.camelCase(e)in s}
;
	if(i.length>0)for(var a=0;
	a<i.length;
	a++)o(i[a]);
	else for(var f in i)o(StyleFix.deCamelCase(f));
	var l={
	uses:0}
;
	for(var c in e){
	var h=e[c];
	l.uses<h&&(l={
	prefix:c,uses:h}
)}
n.prefix="-"+l.prefix+"-";
	n.Prefix=StyleFix.camelCase(n.prefix);
	n.properties=[];
	for(var a=0;
	a<t.length;
	a++){
	var f=t[a];
	if(f.indexOf(n.prefix)===0){
	var p=f.slice(n.prefix.length);
	u(p)||n.properties.push(p)}
}
n.Prefix=="Ms"&&!("transform"in s)&&!("MsTransform"in s)&&"msTransform"in s&&n.properties.push("transform","transform-origin");
	n.properties.sort()}
)();
	(function(){
	function i(e,t){
	r[t]="";
	r[t]=e;
	return!!r[t]}
var e={
	"linear-gradient":{
	property:"backgroundImage",params:"red,teal"}
,calc:{
	property:"width",params:"1px + 5%"}
,element:{
	property:"backgroundImage",params:"#foo"}
,"cross-fade":{
	property:"backgroundImage",params:"url(a.png),url(b.png),50%"}
}
;
	e["repeating-linear-gradient"]=e["repeating-radial-gradient"]=e["radial-gradient"]=e["linear-gradient"];
	var t={
	initial:"color","zoom-in":"cursor","zoom-out":"cursor",box:"display",flexbox:"display","inline-flexbox":"display",flex:"display","inline-flex":"display",grid:"display","inline-grid":"display","min-content":"width"}
;
	n.functions=[];
	n.keywords=[];
	var r=document.createElement("div").style;
	for(var s in e){
	var o=e[s],u=o.property,a=s+"("+o.params+")";
	!i(a,u)&&i(n.prefix+a,u)&&n.functions.push(s)}
for(var f in t){
	var u=t[f];
	!i(f,u)&&i(n.prefix+f,u)&&n.keywords.push(f)}
}
)();
	(function(){
	function s(e){
	i.textContent=e+"{
}
";
	return!!i.sheet.cssRules.length}
var t={
	":read-only":null,":read-write":null,":any-link":null,"::selection":null}
,r={
	keyframes:"name",viewport:null,document:'regexp(".")'}
;
	n.selectors=[];
	n.atrules=[];
	var i=e.appendChild(document.createElement("style"));
	for(var o in t){
	var u=o+(t[o]?"("+t[o]+")":"");
	!s(u)&&s(n.prefixSelector(u))&&n.selectors.push(o)}
for(var a in r){
	var u=a+" "+(r[a]||"");
	!s("@"+u)&&s("@"+n.prefix+u)&&n.atrules.push(a)}
e.removeChild(i)}
)();
	n.valueProperties=["transition","transition-property"];
	e.className+=" "+n.prefix;
	StyleFix.register(n.prefixCSS)}
)(document.documentElement);
	/** * Defines the Flat Surface Shader namespace for all the awesomeness to exist upon. * @author Matthew Wagerfield */
FSS ={
	FRONT:0,BACK:1,DOUBLE:2,SVGNS:'http://www.w3.org/2000/svg'}
;
	/** * @class Array * @author Matthew Wagerfield */
FSS.Array = typeof Float32Array === 'function' ? Float32Array:Array;
	/** * @class Utils * @author Matthew Wagerfield */
FSS.Utils ={
	isNumber:function(value){
	return !isNaN(parseFloat(value)) && isFinite(value);
}
}
;
	/** * Request Animation Frame Polyfill. * @author Paul Irish * @see https://gist.github.com/paulirish/1579671 */
(function(){
	var lastTime = 0;
	var vendors = ['ms','moz','webkit','o'];
	for(var x = 0;
	x < vendors.length && !window.requestAnimationFrame;
	++x){
	window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
	window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame){
	window.requestAnimationFrame = function(callback,element){
	var currentTime = new Date().getTime();
	var timeToCall = Math.max(0,16 - (currentTime - lastTime));
	var id = window.setTimeout(function(){
	callback(currentTime + timeToCall);
}
,timeToCall);
	lastTime = currentTime + timeToCall;
	return id;
}
;
}
if (!window.cancelAnimationFrame){
	window.cancelAnimationFrame = function(id){
	clearTimeout(id);
}
;
}
}
());
	/** * @object Math Augmentation * @author Matthew Wagerfield */
Math.PIM2 = Math.PI*2;
	Math.PID2 = Math.PI/2;
	Math.randomInRange = function(min,max){
	return min + (max - min) * Math.random();
}
;
	Math.clamp = function(value,min,max){
	value = Math.max(value,min);
	value = Math.min(value,max);
	return value;
}
;
	/** * @object Vector3 * @author Matthew Wagerfield */
FSS.Vector3 ={
	create:function(x,y,z){
	var vector = new FSS.Array(3);
	this.set(vector,x,y,z);
	return vector;
}
,clone:function(a){
	var vector = this.create();
	this.copy(vector,a);
	return vector;
}
,set:function(target,x,y,z){
	target[0] = x || 0;
	target[1] = y || 0;
	target[2] = z || 0;
	return this;
}
,setX:function(target,x){
	target[0] = x || 0;
	return this;
}
,setY:function(target,y){
	target[1] = y || 0;
	return this;
}
,setZ:function(target,z){
	target[2] = z || 0;
	return this;
}
,copy:function(target,a){
	target[0] = a[0];
	target[1] = a[1];
	target[2] = a[2];
	return this;
}
,add:function(target,a){
	target[0] += a[0];
	target[1] += a[1];
	target[2] += a[2];
	return this;
}
,addVectors:function(target,a,b){
	target[0] = a[0] + b[0];
	target[1] = a[1] + b[1];
	target[2] = a[2] + b[2];
	return this;
}
,addScalar:function(target,s){
	target[0] += s;
	target[1] += s;
	target[2] += s;
	return this;
}
,subtract:function(target,a){
	target[0] -= a[0];
	target[1] -= a[1];
	target[2] -= a[2];
	return this;
}
,subtractVectors:function(target,a,b){
	target[0] = a[0] - b[0];
	target[1] = a[1] - b[1];
	target[2] = a[2] - b[2];
	return this;
}
,subtractScalar:function(target,s){
	target[0] -= s;
	target[1] -= s;
	target[2] -= s;
	return this;
}
,multiply:function(target,a){
	target[0] *= a[0];
	target[1] *= a[1];
	target[2] *= a[2];
	return this;
}
,multiplyVectors:function(target,a,b){
	target[0] = a[0] * b[0];
	target[1] = a[1] * b[1];
	target[2] = a[2] * b[2];
	return this;
}
,multiplyScalar:function(target,s){
	target[0] *= s;
	target[1] *= s;
	target[2] *= s;
	return this;
}
,divide:function(target,a){
	target[0] /= a[0];
	target[1] /= a[1];
	target[2] /= a[2];
	return this;
}
,divideVectors:function(target,a,b){
	target[0] = a[0] / b[0];
	target[1] = a[1] / b[1];
	target[2] = a[2] / b[2];
	return this;
}
,divideScalar:function(target,s){
	if (s !== 0){
	target[0] /= s;
	target[1] /= s;
	target[2] /= s;
}
else{
	target[0] = 0;
	target[1] = 0;
	target[2] = 0;
}
return this;
}
,cross:function(target,a){
	var x = target[0];
	var y = target[1];
	var z = target[2];
	target[0] = y*a[2] - z*a[1];
	target[1] = z*a[0] - x*a[2];
	target[2] = x*a[1] - y*a[0];
	return this;
}
,crossVectors:function(target,a,b){
	target[0] = a[1]*b[2] - a[2]*b[1];
	target[1] = a[2]*b[0] - a[0]*b[2];
	target[2] = a[0]*b[1] - a[1]*b[0];
	return this;
}
,min:function(target,value){
	if (target[0] < value){
	target[0] = value;
}
if (target[1] < value){
	target[1] = value;
}
if (target[2] < value){
	target[2] = value;
}
return this;
}
,max:function(target,value){
	if (target[0] > value){
	target[0] = value;
}
if (target[1] > value){
	target[1] = value;
}
if (target[2] > value){
	target[2] = value;
}
return this;
}
,clamp:function(target,min,max){
	this.min(target,min);
	this.max(target,max);
	return this;
}
,limit:function(target,min,max){
	var length = this.length(target);
	if (min !== null && length < min){
	this.setLength(target,min);
}
else if (max !== null && length > max){
	this.setLength(target,max);
}
return this;
}
,dot:function(a,b){
	return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
}
,normalise:function(target){
	return this.divideScalar(target,this.length(target));
}
,negate:function(target){
	return this.multiplyScalar(target,-1);
}
,distanceSquared:function(a,b){
	var dx = a[0] - b[0];
	var dy = a[1] - b[1];
	var dz = a[2] - b[2];
	return dx*dx + dy*dy + dz*dz;
}
,distance:function(a,b){
	return Math.sqrt(this.distanceSquared(a,b));
}
,lengthSquared:function(a){
	return a[0]*a[0] + a[1]*a[1] + a[2]*a[2];
}
,length:function(a){
	return Math.sqrt(this.lengthSquared(a));
}
,setLength:function(target,l){
	var length = this.length(target);
	if (length !== 0 && l !== length){
	this.multiplyScalar(target,l / length);
}
return this;
}
}
;
	/** * @object Vector4 * @author Matthew Wagerfield */
FSS.Vector4 ={
	create:function(x,y,z,w){
	var vector = new FSS.Array(4);
	this.set(vector,x,y,z);
	return vector;
}
,set:function(target,x,y,z,w){
	target[0] = x || 0;
	target[1] = y || 0;
	target[2] = z || 0;
	target[3] = w || 0;
	return this;
}
,setX:function(target,x){
	target[0] = x || 0;
	return this;
}
,setY:function(target,y){
	target[1] = y || 0;
	return this;
}
,setZ:function(target,z){
	target[2] = z || 0;
	return this;
}
,setW:function(target,w){
	target[3] = w || 0;
	return this;
}
,add:function(target,a){
	target[0] += a[0];
	target[1] += a[1];
	target[2] += a[2];
	target[3] += a[3];
	return this;
}
,multiplyVectors:function(target,a,b){
	target[0] = a[0] * b[0];
	target[1] = a[1] * b[1];
	target[2] = a[2] * b[2];
	target[3] = a[3] * b[3];
	return this;
}
,multiplyScalar:function(target,s){
	target[0] *= s;
	target[1] *= s;
	target[2] *= s;
	target[3] *= s;
	return this;
}
,min:function(target,value){
	if (target[0] < value){
	target[0] = value;
}
if (target[1] < value){
	target[1] = value;
}
if (target[2] < value){
	target[2] = value;
}
if (target[3] < value){
	target[3] = value;
}
return this;
}
,max:function(target,value){
	if (target[0] > value){
	target[0] = value;
}
if (target[1] > value){
	target[1] = value;
}
if (target[2] > value){
	target[2] = value;
}
if (target[3] > value){
	target[3] = value;
}
return this;
}
,clamp:function(target,min,max){
	this.min(target,min);
	this.max(target,max);
	return this;
}
}
;
	/** * @class Color * @author Matthew Wagerfield */
FSS.Color = function(hex,opacity){
	this.rgba = FSS.Vector4.create();
	this.hex = hex || '#000000';
	this.opacity = FSS.Utils.isNumber(opacity) ? opacity:1;
	this.set(this.hex,this.opacity);
}
;
	FSS.Color.prototype ={
	set:function(hex,opacity){
	hex = hex.replace('#','');
	var size = hex.length / 3;
	this.rgba[0] = parseInt(hex.substring(size*0,size*1),16) / 255;
	this.rgba[1] = parseInt(hex.substring(size*1,size*2),16) / 255;
	this.rgba[2] = parseInt(hex.substring(size*2,size*3),16) / 255;
	this.rgba[3] = FSS.Utils.isNumber(opacity) ? opacity:this.rgba[3];
	return this;
}
,hexify:function(channel){
	var hex = Math.ceil(channel*255).toString(16);
	if (hex.length === 1){
	hex = '0' + hex;
}
return hex;
}
,format:function(){
	var r = this.hexify(this.rgba[0]);
	var g = this.hexify(this.rgba[1]);
	var b = this.hexify(this.rgba[2]);
	this.hex = '#' + r + g + b;
	return this.hex;
}
}
;
	/** * @class Object * @author Matthew Wagerfield */
FSS.Object = function(){
	this.position = FSS.Vector3.create();
}
;
	FSS.Object.prototype ={
	setPosition:function(x,y,z){
	FSS.Vector3.set(this.position,x,y,z);
	return this;
}
}
;
	/** * @class Light * @author Matthew Wagerfield */
FSS.Light = function(ambient,diffuse){
	FSS.Object.call(this);
	this.ambient = new FSS.Color(ambient || '#FFFFFF');
	this.diffuse = new FSS.Color(diffuse || '#FFFFFF');
	this.ray = FSS.Vector3.create();
}
;
	FSS.Light.prototype = Object.create(FSS.Object.prototype);
	/** * @class Vertex * @author Matthew Wagerfield */
FSS.Vertex = function(x,y,z){
	this.position = FSS.Vector3.create(x,y,z);
}
;
	FSS.Vertex.prototype ={
	setPosition:function(x,y,z){
	FSS.Vector3.set(this.position,x,y,z);
	return this;
}
}
;
	/** * @class Triangle * @author Matthew Wagerfield */
FSS.Triangle = function(a,b,c){
	this.a = a || new FSS.Vertex();
	this.b = b || new FSS.Vertex();
	this.c = c || 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;
}
}
;
	/** * @class Geometry * @author Matthew Wagerfield */
FSS.Geometry = function(){
	this.vertices = [];
	this.triangles = [];
	this.dirty = false;
}
;
	FSS.Geometry.prototype ={
	update:function(){
	if (this.dirty){
	var t,triangle;
	for (t = this.triangles.length - 1;
	t >= 0;
	t--){
	triangle = this.triangles[t];
	triangle.computeCentroid();
	triangle.computeNormal();
}
this.dirty = false;
}
return this;
}
}
;
	/** * @class Plane * @author Matthew Wagerfield,modified by Maksim Surguy to implement Delaunay triangulation */
FSS.Plane = function(width,height,howmany){
	FSS.Geometry.call(this);
	this.width = width || 100;
	this.height = height || 100;
	// Cache Variables var x,y,vertices = new Array(howmany);
	offsetX = this.width * -0.5,offsetY = this.height * 0.5;
	for(i = vertices.length;
	i--;
	){
	x = offsetX + Math.random()*width;
	y = offsetY - Math.random()*height;
	vertices[i] = [x,y];
}
// Generate additional points on the perimeter so that there are no holes in the pattern vertices.push([offsetX,offsetY]);
	vertices.push([offsetX + width/2,offsetY]);
	vertices.push([offsetX + width,offsetY]);
	vertices.push([offsetX + width,offsetY - height/2]);
	vertices.push([offsetX + width,offsetY - height]);
	vertices.push([offsetX + width/2,offsetY - height]);
	vertices.push([offsetX,offsetY - height]);
	vertices.push([offsetX,offsetY - height/2]);
	// Generate additional randomly placed points on the perimeter for (var i = 6;
	i >= 0;
	i--){
	vertices.push([ offsetX + Math.random()*width,offsetY]);
	vertices.push([ offsetX,offsetY - Math.random()*height]);
	vertices.push([ offsetX + width,offsetY - Math.random()*height]);
	vertices.push([ offsetX + Math.random()*width,offsetY-height]);
}
// Create an array of triangulated coordinates from our vertices var triangles = Delaunay.triangulate(vertices);
	for(i = triangles.length;
	i;
	){
	--i;
	var p1 = [Math.ceil(vertices[triangles[i]][0]),Math.ceil(vertices[triangles[i]][1])];
	--i;
	var p2 = [Math.ceil(vertices[triangles[i]][0]),Math.ceil(vertices[triangles[i]][1])];
	--i;
	var p3 = [Math.ceil(vertices[triangles[i]][0]),Math.ceil(vertices[triangles[i]][1])];
	t1 = new FSS.Triangle(new FSS.Vertex(p1[0],p1[1]),new FSS.Vertex(p2[0],p2[1]),new FSS.Vertex(p3[0],p3[1]));
	this.triangles.push(t1);
}
}
;
	FSS.Plane.prototype = Object.create(FSS.Geometry.prototype);
	/** * @class Material * @author Matthew Wagerfield */
FSS.Material = function(ambient,diffuse){
	this.ambient = new FSS.Color(ambient || '#444444');
	this.diffuse = new FSS.Color(diffuse || '#FFFFFF');
	this.slave = new FSS.Color();
}
;
	/** * @class Mesh * @author Matthew Wagerfield */
FSS.Mesh = function(geometry,material){
	FSS.Object.call(this);
	this.geometry = geometry || new FSS.Geometry();
	this.material = material || new FSS.Material();
	this.side = FSS.FRONT;
	this.visible = true;
}
;
	FSS.Mesh.prototype = Object.create(FSS.Object.prototype);
	FSS.Mesh.prototype.update = function(lights,calculate){
	var t,triangle,l,light,illuminance;
	// Update Geometry this.geometry.update();
	// Calculate the triangle colors if (calculate){
	// Iterate through Triangles for (t = this.geometry.triangles.length - 1;
	t >= 0;
	t--){
	triangle = this.geometry.triangles[t];
	// Reset Triangle Color FSS.Vector4.set(triangle.color.rgba);
	// Iterate through Lights for (l = lights.length - 1;
	l >= 0;
	l--){
	light = lights[l];
	// Calculate Illuminance FSS.Vector3.subtractVectors(light.ray,light.position,triangle.centroid);
	FSS.Vector3.normalise(light.ray);
	illuminance = FSS.Vector3.dot(triangle.normal,light.ray);
	if (this.side === FSS.FRONT){
	illuminance = Math.max(illuminance,0);
}
else if (this.side === FSS.BACK){
	illuminance = Math.abs(Math.min(illuminance,0));
}
else if (this.side === FSS.DOUBLE){
	illuminance = Math.max(Math.abs(illuminance),0);
}
// Calculate Ambient Light FSS.Vector4.multiplyVectors(this.material.slave.rgba,this.material.ambient.rgba,light.ambient.rgba);
	FSS.Vector4.add(triangle.color.rgba,this.material.slave.rgba);
	// Calculate Diffuse Light FSS.Vector4.multiplyVectors(this.material.slave.rgba,this.material.diffuse.rgba,light.diffuse.rgba);
	FSS.Vector4.multiplyScalar(this.material.slave.rgba,illuminance);
	FSS.Vector4.add(triangle.color.rgba,this.material.slave.rgba);
}
// Clamp & Format Color FSS.Vector4.clamp(triangle.color.rgba,0,1);
}
}
return this;
}
;
	/** * @class Scene * @author Matthew Wagerfield */
FSS.Scene = function(){
	this.meshes = [];
	this.lights = [];
}
;
	FSS.Scene.prototype ={
	add:function(object){
	if (object instanceof FSS.Mesh && !~this.meshes.indexOf(object)){
	this.meshes.push(object);
}
else if (object instanceof FSS.Light && !~this.lights.indexOf(object)){
	this.lights.push(object);
}
return this;
}
,remove:function(object){
	if (object instanceof FSS.Mesh && ~this.meshes.indexOf(object)){
	this.meshes.splice(this.meshes.indexOf(object),1);
}
else if (object instanceof FSS.Light && ~this.lights.indexOf(object)){
	this.lights.splice(this.lights.indexOf(object),1);
}
return this;
}
}
;
	/** * @class Renderer * @author Matthew Wagerfield */
FSS.Renderer = function(){
	this.width = 0;
	this.height = 0;
	this.halfWidth = 0;
	this.halfHeight = 0;
}
;
	FSS.Renderer.prototype ={
	setSize:function(width,height){
	if (this.width === width && this.height === height) return;
	this.width = width;
	this.height = height;
	this.halfWidth = this.width * 0.5;
	this.halfHeight = this.height * 0.5;
	return this;
}
,clear:function(){
	return this;
}
,render:function(scene){
	return this;
}
}
;
	/** * @class Canvas Renderer * @author Matthew Wagerfield */
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(width,height){
	FSS.Renderer.prototype.setSize.call(this,width,height);
	this.element.width = width;
	this.element.height = height;
	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(scene){
	FSS.Renderer.prototype.render.call(this,scene);
	var m,mesh,t,triangle,color;
	// Clear Context this.clear();
	// Configure Context this.context.lineJoin = 'round';
	this.context.lineWidth = 1;
	// Update Meshes for (m = scene.meshes.length - 1;
	m >= 0;
	m--){
	mesh = scene.meshes[m];
	if (mesh.visible){
	mesh.update(scene.lights,true);
	// Render Triangles for (t = mesh.geometry.triangles.length - 1;
	t >= 0;
	t--){
	triangle = mesh.geometry.triangles[t];
	color = triangle.color.format();
	this.context.beginPath();
	this.context.moveTo(triangle.a.position[0],triangle.a.position[1]);
	this.context.lineTo(triangle.b.position[0],triangle.b.position[1]);
	this.context.lineTo(triangle.c.position[0],triangle.c.position[1]);
	this.context.closePath();
	this.context.strokeStyle = color;
	this.context.fillStyle = color;
	this.context.stroke();
	this.context.fill();
}
}
}
return this;
}
;
	/** * @class WebGL Renderer * @author Matthew Wagerfield */
FSS.WebGLRenderer = function(){
	FSS.Renderer.call(this);
	this.element = document.createElement('canvas');
	this.element.style.display = 'block';
	// Set initial vertex and light count this.vertices = null;
	this.lights = null;
	// Create parameters object var parameters ={
	preserveDrawingBuffer:false,premultipliedAlpha:true,antialias:true,stencil:true,alpha:true}
;
	// Create and configure the gl context this.gl = this.getContext(this.element,parameters);
	// Set the internal support flag this.unsupported = !this.gl;
	// Setup renderer if (this.unsupported){
	return 'WebGL is not supported by your browser.';
}
else{
	this.gl.clearColor(0.0,0.0,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(canvas,parameters){
	var context = false;
	try{
	if (!(context = canvas.getContext('experimental-webgl',parameters))){
	throw 'Error creating WebGL context.';
}
}
catch (error){
	console.error(error);
}
return context;
}
;
	FSS.WebGLRenderer.prototype.setSize = function(width,height){
	FSS.Renderer.prototype.setSize.call(this,width,height);
	if (this.unsupported) return;
	// Set the size of the canvas element this.element.width = width;
	this.element.height = height;
	// Set the size of the gl viewport this.gl.viewport(0,0,width,height);
	return 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);
	return this;
}
;
	FSS.WebGLRenderer.prototype.render = function(scene){
	FSS.Renderer.prototype.render.call(this,scene);
	if (this.unsupported) return;
	var m,mesh,t,tl,triangle,l,light,attribute,uniform,buffer,data,location,update = false,lights = scene.lights.length,index,v,vl,vetex,vertices = 0;
	// Clear context this.clear();
	// Build the shader program if (this.lights !== lights){
	this.lights = lights;
	if (this.lights > 0){
	this.buildProgram(lights);
}
else{
	return;
}
}
// Update program if (!!this.program){
	// Increment vertex counter for (m = scene.meshes.length - 1;
	m >= 0;
	m--){
	mesh = scene.meshes[m];
	if (mesh.geometry.dirty) update = true;
	mesh.update(scene.lights,false);
	vertices += mesh.geometry.triangles.length*3;
}
// Compare vertex counter if (update || this.vertices !== vertices){
	this.vertices = vertices;
	// Build buffers for (attribute in this.program.attributes){
	buffer = this.program.attributes[attribute];
	buffer.data = new FSS.Array(vertices*buffer.size);
	// Reset vertex index index = 0;
	// Update attribute buffer data for (m = scene.meshes.length - 1;
	m >= 0;
	m--){
	mesh = scene.meshes[m];
	for (t = 0,tl = mesh.geometry.triangles.length;
	t < tl;
	t++){
	triangle = mesh.geometry.triangles[t];
	for (v = 0,vl = triangle.vertices.length;
	v < vl;
	v++){
	vertex = triangle.vertices[v];
	switch (attribute){
	case 'side':this.setBufferData(index,buffer,mesh.side);
	break;
	case 'position':this.setBufferData(index,buffer,vertex.position);
	break;
	case 'centroid':this.setBufferData(index,buffer,triangle.centroid);
	break;
	case 'normal':this.setBufferData(index,buffer,triangle.normal);
	break;
	case 'ambient':this.setBufferData(index,buffer,mesh.material.ambient.rgba);
	break;
	case 'diffuse':this.setBufferData(index,buffer,mesh.material.diffuse.rgba);
	break;
}
index++;
}
}
}
// Upload attribute buffer data this.gl.bindBuffer(this.gl.ARRAY_BUFFER,buffer.buffer);
	this.gl.bufferData(this.gl.ARRAY_BUFFER,buffer.data,this.gl.DYNAMIC_DRAW);
	this.gl.enableVertexAttribArray(buffer.location);
	this.gl.vertexAttribPointer(buffer.location,buffer.size,this.gl.FLOAT,false,0,0);
}
}
// Build uniform buffers this.setBufferData(0,this.program.uniforms.resolution,[this.width,this.height,this.width]);
	for (l = lights-1;
	l >= 0;
	l--){
	light = scene.lights[l];
	this.setBufferData(l,this.program.uniforms.lightPosition,light.position);
	this.setBufferData(l,this.program.uniforms.lightAmbient,light.ambient.rgba);
	this.setBufferData(l,this.program.uniforms.lightDiffuse,light.diffuse.rgba);
}
// Update uniforms for (uniform in this.program.uniforms){
	buffer = this.program.uniforms[uniform];
	location = buffer.location;
	data = buffer.data;
	switch (buffer.structure){
	case '3f':this.gl.uniform3f(location,data[0],data[1],data[2]);
	break;
	case '3fv':this.gl.uniform3fv(location,data);
	break;
	case '4fv':this.gl.uniform4fv(location,data);
	break;
}
}
}
// Draw those lovely triangles this.gl.drawArrays(this.gl.TRIANGLES,0,this.vertices);
	return this;
}
;
	FSS.WebGLRenderer.prototype.setBufferData = function(index,buffer,value){
	if (FSS.Utils.isNumber(value)){
	buffer.data[index*buffer.size] = value;
}
else{
	for (var i = value.length - 1;
	i >= 0;
	i--){
	buffer.data[index*buffer.size+i] = value[i];
}
}
}
;
	/** * Concepts taken from three.js WebGLRenderer * @see https://github.com/mrdoob/three.js/blob/master/src/renderers/WebGLRenderer.js */
FSS.WebGLRenderer.prototype.buildProgram = function(lights){
	if (this.unsupported) return;
	// Create shader source var vs = FSS.WebGLRenderer.VS(lights);
	var fs = FSS.WebGLRenderer.FS(lights);
	// Derive the shader fingerprint var code = vs + fs;
	// Check if the program has already been compiled if (!!this.program && this.program.code === code) return;
	// Create the program and shaders var program = this.gl.createProgram();
	var vertexShader = this.buildShader(this.gl.VERTEX_SHADER,vs);
	var fragmentShader = this.buildShader(this.gl.FRAGMENT_SHADER,fs);
	// Attach an link the shader this.gl.attachShader(program,vertexShader);
	this.gl.attachShader(program,fragmentShader);
	this.gl.linkProgram(program);
	// Add error handling if (!this.gl.getProgramParameter(program,this.gl.LINK_STATUS)){
	var error = this.gl.getError();
	var status = this.gl.getProgramParameter(program,this.gl.VALIDATE_STATUS);
	console.error('Could not initialise shader.\nVALIDATE_STATUS:'+status+'\nERROR:'+error);
	return null;
}
// Delete the shader this.gl.deleteShader(fragmentShader);
	this.gl.deleteShader(vertexShader);
	// Set the program code program.code = code;
	// Add the program attributes program.attributes ={
	side:this.buildBuffer(program,'attribute','aSide',1,'f' ),position:this.buildBuffer(program,'attribute','aPosition',3,'v3'),centroid:this.buildBuffer(program,'attribute','aCentroid',3,'v3'),normal:this.buildBuffer(program,'attribute','aNormal',3,'v3'),ambient:this.buildBuffer(program,'attribute','aAmbient',4,'v4'),diffuse:this.buildBuffer(program,'attribute','aDiffuse',4,'v4')}
;
	// Add the program uniforms program.uniforms ={
	resolution:this.buildBuffer(program,'uniform','uResolution',3,'3f',1 ),lightPosition:this.buildBuffer(program,'uniform','uLightPosition',3,'3fv',lights),lightAmbient:this.buildBuffer(program,'uniform','uLightAmbient',4,'4fv',lights),lightDiffuse:this.buildBuffer(program,'uniform','uLightDiffuse',4,'4fv',lights)}
;
	// Set the renderer program this.program = program;
	// Enable program this.gl.useProgram(this.program);
	// Return the program return program;
}
;
	FSS.WebGLRenderer.prototype.buildShader = function(type,source){
	if (this.unsupported) return;
	// Create and compile shader var shader = this.gl.createShader(type);
	this.gl.shaderSource(shader,source);
	this.gl.compileShader(shader);
	// Add error handling if (!this.gl.getShaderParameter(shader,this.gl.COMPILE_STATUS)){
	console.error(this.gl.getShaderInfoLog(shader));
	return null;
}
// Return the shader return shader;
}
;
	FSS.WebGLRenderer.prototype.buildBuffer = function(program,type,identifier,size,structure,count){
	var buffer ={
	buffer:this.gl.createBuffer(),size:size,structure:structure,data:null}
;
	// Set the location switch (type){
	case 'attribute':buffer.location = this.gl.getAttribLocation(program,identifier);
	break;
	case 'uniform':buffer.location = this.gl.getUniformLocation(program,identifier);
	break;
}
// Create the buffer if count is provided if (!!count){
	buffer.data = new FSS.Array(count*size);
}
// Return the buffer return buffer;
}
;
	FSS.WebGLRenderer.VS = function(lights){
	var shader = [ // Precision 'precision mediump float;
	',// Lights '#define LIGHTS ' + lights,// Attributes 'attribute float aSide;
	','attribute vec3 aPosition;
	','attribute vec3 aCentroid;
	','attribute vec3 aNormal;
	','attribute vec4 aAmbient;
	','attribute vec4 aDiffuse;
	',// Uniforms 'uniform vec3 uResolution;
	','uniform vec3 uLightPosition[LIGHTS];
	','uniform vec4 uLightAmbient[LIGHTS];
	','uniform vec4 uLightDiffuse[LIGHTS];
	',// Varyings 'varying vec4 vColor;
	',// Main 'void main(){
	',// Create color 'vColor = vec4(0.0);
	',// Calculate the vertex position 'vec3 position = aPosition / uResolution * 2.0;
	',// Iterate through lights 'for (int i = 0;
	i < LIGHTS;
	i++){
	','vec3 lightPosition = uLightPosition[i];
	','vec4 lightAmbient = uLightAmbient[i];
	','vec4 lightDiffuse = uLightDiffuse[i];
	',// Calculate illuminance 'vec3 ray = normalize(lightPosition - aCentroid);
	','float illuminance = dot(aNormal,ray);
	','if (aSide == 0.0){
	','illuminance = max(illuminance,0.0);
	','}
else if (aSide == 1.0){
	','illuminance = abs(min(illuminance,0.0));
	','}
else if (aSide == 2.0){
	','illuminance = max(abs(illuminance),0.0);
	','}
',// Calculate ambient light 'vColor += aAmbient * lightAmbient;
	',// Calculate diffuse light 'vColor += aDiffuse * lightDiffuse * illuminance;
	','}
',// Clamp color 'vColor = clamp(vColor,0.0,1.0);
	',// Set gl_Position 'gl_Position = vec4(position,1.0);
	','}
' // Return the shader ].join('\n');
	return shader;
}
;
	FSS.WebGLRenderer.FS = function(lights){
	var shader = [ // Precision 'precision mediump float;
	',// Varyings 'varying vec4 vColor;
	',// Main 'void main(){
	',// Set gl_FragColor 'gl_FragColor = vColor;
	','}
' // Return the shader ].join('\n');
	return shader;
}
;
	/** * @class SVG Renderer * @author Matthew Wagerfield */
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(width,height){
	FSS.Renderer.prototype.setSize.call(this,width,height);
	this.element.setAttribute('width',width);
	this.element.setAttribute('height',height);
	return this;
}
;
	FSS.SVGRenderer.prototype.clear = function(){
	FSS.Renderer.prototype.clear.call(this);
	for (var i = this.element.childNodes.length - 1;
	i >= 0;
	i--){
	this.element.removeChild(this.element.childNodes[i]);
}
return this;
}
;
	FSS.SVGRenderer.prototype.render = function(scene){
	FSS.Renderer.prototype.render.call(this,scene);
	var m,mesh,t,triangle,points,style;
	// Update Meshes for (m = scene.meshes.length - 1;
	m >= 0;
	m--){
	mesh = scene.meshes[m];
	if (mesh.visible){
	mesh.update(scene.lights,true);
	// Render Triangles for (t = mesh.geometry.triangles.length - 1;
	t >= 0;
	t--){
	triangle = mesh.geometry.triangles[t];
	if (triangle.polygon.parentNode !== this.element){
	this.element.appendChild(triangle.polygon);
}
points = this.formatPoint(triangle.a)+' ';
	points += this.formatPoint(triangle.b)+' ';
	points += this.formatPoint(triangle.c);
	style = this.formatStyle(triangle.color.format());
	triangle.polygon.setAttributeNS(null,'points',points);
	triangle.polygon.setAttributeNS(null,'style',style);
}
}
}
return this;
}
;
	FSS.SVGRenderer.prototype.formatPoint = function(vertex){
	return (this.halfWidth+vertex.position[0])+','+(this.halfHeight-vertex.position[1]);
}
;
	FSS.SVGRenderer.prototype.formatStyle = function(color){
	var style = 'fill:'+color+';
	';
	style += 'stroke:'+color+';
	';
	return style;
}
;
	/** * dat-gui JavaScript Controller Library * http://code.google.com/p/dat-gui * * Copyright 2011 Data Arts Team,Google Creative Lab * * Licensed under the Apache License,Version 2.0 (the "License");
	* you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */
var dat=dat||{
}
;
	dat.gui=dat.gui||{
}
;
	dat.utils=dat.utils||{
}
;
	dat.controllers=dat.controllers||{
}
;
	dat.dom=dat.dom||{
}
;
	dat.color=dat.color||{
}
;
	dat.utils.css=function(){
	return{
	load:function(e,a){
	var a=a||document,c=a.createElement("link");
	c.type="text/css";
	c.rel="stylesheet";
	c.href=e;
	a.getElementsByTagName("head")[0].appendChild(c)}
,inject:function(e,a){
	var a=a||document,c=document.createElement("style");
	c.type="text/css";
	c.innerHTML=e;
	a.getElementsByTagName("head")[0].appendChild(c)}
}
}
();
	dat.utils.common=function(){
	var e=Array.prototype.forEach,a=Array.prototype.slice;
	return{
	BREAK:{
}
,extend:function(c){
	this.each(a.call(arguments,1),function(a){
	for(var f in a)this.isUndefined(a[f])||(c[f]=a[f])}
,this);
	return c}
,defaults:function(c){
	this.each(a.call(arguments,1),function(a){
	for(var f in a)this.isUndefined(c[f])&&(c[f]=a[f])}
,this);
	return c}
,compose:function(){
	var c=a.call(arguments);
	return function(){
	for(var d=a.call(arguments),f=c.length-1;
	f>=0;
	f--)d=[c[f].apply(this,d)];
	return d[0]}
}
,each:function(a,d,f){
	if(e&&a.forEach===e)a.forEach(d,f);
	else if(a.length===a.length+0)for(var b=0,n=a.length;
	b<n;
	b++){
	if(b in a&&d.call(f,a[b],b)===this.BREAK)break}
else for(b in a)if(d.call(f,a[b],b)===this.BREAK)break}
,defer:function(a){
	setTimeout(a,0)}
,toArray:function(c){
	return c.toArray?c.toArray():a.call(c)}
,isUndefined:function(a){
	return a===void 0}
,isNull:function(a){
	return a===null}
,isNaN:function(a){
	return a!==a}
,isArray:Array.isArray||function(a){
	return a.constructor===Array}
,isObject:function(a){
	return a===Object(a)}
,isNumber:function(a){
	return a===a+0}
,isString:function(a){
	return a===a+""}
,isBoolean:function(a){
	return a===false||a===true}
,isFunction:function(a){
	return Object.prototype.toString.call(a)==="[object Function]"}
}
}
();
	dat.controllers.Controller=function(e){
	var a=function(a,d){
	this.initialValue=a[d];
	this.domElement=document.createElement("div");
	this.object=a;
	this.property=d;
	this.__onFinishChange=this.__onChange=void 0}
;
	e.extend(a.prototype,{
	onChange:function(a){
	this.__onChange=a;
	return this}
,onFinishChange:function(a){
	this.__onFinishChange=a;
	return this}
,setValue:function(a){
	this.object[this.property]=a;
	this.__onChange&&this.__onChange.call(this,a);
	this.updateDisplay();
	return this}
,getValue:function(){
	return this.object[this.property]}
,updateDisplay:function(){
	return this}
,isModified:function(){
	return this.initialValue!==this.getValue()}
}
);
	return a}
(dat.utils.common);
	dat.dom.dom=function(e){
	function a(b){
	if(b==="0"||e.isUndefined(b))return 0;
	b=b.match(d);
	return!e.isNull(b)?parseFloat(b[1]):0}
var c={
}
;
	e.each({
	HTMLEvents:["change"],MouseEvents:["click","mousemove","mousedown","mouseup","mouseover"],KeyboardEvents:["keydown"]}
,function(b,a){
	e.each(b,function(b){
	c[b]=a}
)}
);
	var d=/(\d+(\.\d+)?)px/,f={
	makeSelectable:function(b,a){
	if(!(b===void 0||b.style===void 0))b.onselectstart=a?function(){
	return false}
:function(){
}
,b.style.MozUserSelect=a?"auto":"none",b.style.KhtmlUserSelect=a?"auto":"none",b.unselectable=a?"on":"off"}
,makeFullscreen:function(b,a,d){
	e.isUndefined(a)&&(a=true);
	e.isUndefined(d)&&(d=true);
	b.style.position="absolute";
	if(a)b.style.left=0,b.style.right=0;
	if(d)b.style.top=0,b.style.bottom=0}
,fakeEvent:function(b,a,d,f){
	var d=d||{
}
,m=c[a];
	if(!m)throw Error("Event type "+a+" not supported.");
	var l=document.createEvent(m);
	switch(m){
	case "MouseEvents":l.initMouseEvent(a,d.bubbles||false,d.cancelable||true,window,d.clickCount||1,0,0,d.x||d.clientX||0,d.y||d.clientY||0,false,false,false,false,0,null);
	break;
	case "KeyboardEvents":m=l.initKeyboardEvent||l.initKeyEvent;
	e.defaults(d,{
	cancelable:true,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false,keyCode:void 0,charCode:void 0}
);
	m(a,d.bubbles||false,d.cancelable,window,d.ctrlKey,d.altKey,d.shiftKey,d.metaKey,d.keyCode,d.charCode);
	break;
	default:l.initEvent(a,d.bubbles||false,d.cancelable||true)}
e.defaults(l,f);
	b.dispatchEvent(l)}
,bind:function(b,a,d,c){
	b.addEventListener?b.addEventListener(a,d,c||false):b.attachEvent&&b.attachEvent("on"+a,d);
	return f}
,unbind:function(b,a,d,c){
	b.removeEventListener?b.removeEventListener(a,d,c||false):b.detachEvent&&b.detachEvent("on"+a,d);
	return f}
,addClass:function(b,a){
	if(b.className===void 0)b.className=a;
	else if(b.className!==a){
	var d=b.className.split(/ +/);
	if(d.indexOf(a)==-1)d.push(a),b.className=d.join(" ").replace(/^\s+/,"").replace(/\s+$/,"")}
return f}
,removeClass:function(b,a){
	if(a){
	if(b.className!==void 0)if(b.className===a)b.removeAttribute("class");
	else{
	var d=b.className.split(/ +/),c=d.indexOf(a);
	if(c!=-1)d.splice(c,1),b.className=d.join(" ")}
}
else b.className=void 0;
	return f}
,hasClass:function(a,d){
	return RegExp("(?:^|\\s+)"+d+"(?:\\s+|$)").test(a.className)||false}
,getWidth:function(b){
	b=getComputedStyle(b);
	return a(b["border-left-width"])+a(b["border-right-width"])+a(b["padding-left"])+a(b["padding-right"])+a(b.width)}
,getHeight:function(b){
	b=getComputedStyle(b);
	return a(b["border-top-width"])+a(b["border-bottom-width"])+a(b["padding-top"])+a(b["padding-bottom"])+a(b.height)}
,getOffset:function(a){
	var d={
	left:0,top:0}
;
	if(a.offsetParent){
	do d.left+=a.offsetLeft,d.top+=a.offsetTop;
	while(a=a.offsetParent)}
return d}
,isActive:function(a){
	return a===document.activeElement&&(a.type||a.href)}
}
;
	return f}
(dat.utils.common);
	dat.controllers.OptionController=function(e,a,c){
	var d=function(f,b,e){
	d.superclass.call(this,f,b);
	var h=this;
	this.__select=document.createElement("select");
	if(c.isArray(e)){
	var j={
}
;
	c.each(e,function(a){
	j[a]=a}
);
	e=j}
c.each(e,function(a,b){
	var d=document.createElement("option");
	d.innerHTML=b;
	d.setAttribute("value",a);
	h.__select.appendChild(d)}
);
	this.updateDisplay();
	a.bind(this.__select,"change",function(){
	h.setValue(this.options[this.selectedIndex].value)}
);
	this.domElement.appendChild(this.__select)}
;
	d.superclass=e;
	c.extend(d.prototype,e.prototype,{
	setValue:function(a){
	a=d.superclass.prototype.setValue.call(this,a);
	this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue());
	return a}
,updateDisplay:function(){
	this.__select.value=this.getValue();
	return d.superclass.prototype.updateDisplay.call(this)}
}
);
	return d}
(dat.controllers.Controller,dat.dom.dom,dat.utils.common);
	dat.controllers.NumberController=function(e,a){
	var c=function(d,f,b){
	c.superclass.call(this,d,f);
	b=b||{
}
;
	this.__min=b.min;
	this.__max=b.max;
	this.__step=b.step;
	d=this.__impliedStep=a.isUndefined(this.__step)?this.initialValue==0?1:Math.pow(10,Math.floor(Math.log(this.initialValue)/Math.LN10))/10:this.__step;
	d=d.toString();
	this.__precision=d.indexOf(".")>-1?d.length-d.indexOf(".")-1:0}
;
	c.superclass=e;
	a.extend(c.prototype,e.prototype,{
	setValue:function(a){
	if(this.__min!==void 0&&a<this.__min)a=this.__min;
	else if(this.__max!==void 0&&a>this.__max)a=this.__max;
	this.__step!==void 0&&a%this.__step!=0&&(a=Math.round(a/this.__step)*this.__step);
	return c.superclass.prototype.setValue.call(this,a)}
,min:function(a){
	this.__min=a;
	return this}
,max:function(a){
	this.__max=a;
	return this}
,step:function(a){
	this.__step=a;
	return this}
}
);
	return c}
(dat.controllers.Controller,dat.utils.common);
	dat.controllers.NumberControllerBox=function(e,a,c){
	var d=function(f,b,e){
	function h(){
	var a=parseFloat(l.__input.value);
	c.isNaN(a)||l.setValue(a)}
function j(a){
	var b=o-a.clientY;
	l.setValue(l.getValue()+b*l.__impliedStep);
	o=a.clientY}
function m(){
	a.unbind(window,"mousemove",j);
	a.unbind(window,"mouseup",m)}
this.__truncationSuspended=false;
	d.superclass.call(this,f,b,e);
	var l=this,o;
	this.__input=document.createElement("input");
	this.__input.setAttribute("type","text");
	a.bind(this.__input,"change",h);
	a.bind(this.__input,"blur",function(){
	h();
	l.__onFinishChange&&l.__onFinishChange.call(l,l.getValue())}
);
	a.bind(this.__input,"mousedown",function(b){
	a.bind(window,"mousemove",j);
	a.bind(window,"mouseup",m);
	o=b.clientY}
);
	a.bind(this.__input,"keydown",function(a){
	if(a.keyCode===13)l.__truncationSuspended=true,this.blur(),l.__truncationSuspended=false}
);
	this.updateDisplay();
	this.domElement.appendChild(this.__input)}
;
	d.superclass=e;
	c.extend(d.prototype,e.prototype,{
	updateDisplay:function(){
	var a=this.__input,b;
	if(this.__truncationSuspended)b=this.getValue();
	else{
	b=this.getValue();
	var c=Math.pow(10,this.__precision);
	b=Math.round(b*c)/c}
a.value=b;
	return d.superclass.prototype.updateDisplay.call(this)}
}
);
	return d}
(dat.controllers.NumberController,dat.dom.dom,dat.utils.common);
	dat.controllers.NumberControllerSlider=function(e,a,c,d,f){
	var b=function(d,c,f,e,l){
	function o(b){
	b.preventDefault();
	var d=a.getOffset(g.__background),c=a.getWidth(g.__background);
	g.setValue(g.__min+(g.__max-g.__min)*((b.clientX-d.left)/(d.left+c-d.left)));
	return false}
function y(){
	a.unbind(window,"mousemove",o);
	a.unbind(window,"mouseup",y);
	g.__onFinishChange&&g.__onFinishChange.call(g,g.getValue())}
b.superclass.call(this,d,c,{
	min:f,max:e,step:l}
);
	var g=this;
	this.__background=document.createElement("div");
	this.__foreground=document.createElement("div");
	a.bind(this.__background,"mousedown",function(b){
	a.bind(window,"mousemove",o);
	a.bind(window,"mouseup",y);
	o(b)}
);
	a.addClass(this.__background,"slider");
	a.addClass(this.__foreground,"slider-fg");
	this.updateDisplay();
	this.__background.appendChild(this.__foreground);
	this.domElement.appendChild(this.__background)}
;
	b.superclass=e;
	b.useDefaultStyles=function(){
	c.inject(f)}
;
	d.extend(b.prototype,e.prototype,{
	updateDisplay:function(){
	this.__foreground.style.width=(this.getValue()-this.__min)/(this.__max-this.__min)*100+"%";
	return b.superclass.prototype.updateDisplay.call(this)}
}
);
	return b}
(dat.controllers.NumberController,dat.dom.dom,dat.utils.css,dat.utils.common,".slider{
	\n box-shadow:inset 0 2px 4px rgba(0,0,0,0.15);
	\n height:1em;
	\n border-radius:1em;
	\n background-color:#eee;
	\n padding:0 0.5em;
	\n overflow:hidden;
	\n}
\n\n.slider-fg{
	\n padding:1px 0 2px 0;
	\n background-color:#aaa;
	\n height:1em;
	\n margin-left:-0.5em;
	\n padding-right:0.5em;
	\n border-radius:1em 0 0 1em;
	\n}
\n\n.slider-fg:after{
	\n display:inline-block;
	\n border-radius:1em;
	\n background-color:#fff;
	\n border:1px solid #aaa;
	\n content:'';
	\n float:right;
	\n margin-right:-1em;
	\n margin-top:-1px;
	\n height:0.9em;
	\n width:0.9em;
	\n}
");
	dat.controllers.FunctionController=function(e,a,c){
	var d=function(c,b,e){
	d.superclass.call(this,c,b);
	var h=this;
	this.__button=document.createElement("div");
	this.__button.innerHTML=e===void 0?"Fire":e;
	a.bind(this.__button,"click",function(a){
	a.preventDefault();
	h.fire();
	return false}
);
	a.addClass(this.__button,"button");
	this.domElement.appendChild(this.__button)}
;
	d.superclass=e;
	c.extend(d.prototype,e.prototype,{
	fire:function(){
	this.__onChange&&this.__onChange.call(this);
	this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue());
	this.getValue().call(this.object)}
}
);
	return d}
(dat.controllers.Controller,dat.dom.dom,dat.utils.common);
	dat.controllers.BooleanController=function(e,a,c){
	var d=function(c,b){
	d.superclass.call(this,c,b);
	var e=this;
	this.__prev=this.getValue();
	this.__checkbox=document.createElement("input");
	this.__checkbox.setAttribute("type","checkbox");
	a.bind(this.__checkbox,"change",function(){
	e.setValue(!e.__prev)}
,false);
	this.domElement.appendChild(this.__checkbox);
	this.updateDisplay()}
;
	d.superclass=e;
	c.extend(d.prototype,e.prototype,{
	setValue:function(a){
	a=d.superclass.prototype.setValue.call(this,a);
	this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue());
	this.__prev=this.getValue();
	return a}
,updateDisplay:function(){
	this.getValue()===true?(this.__checkbox.setAttribute("checked","checked"),this.__checkbox.checked=true):this.__checkbox.checked=false;
	return d.superclass.prototype.updateDisplay.call(this)}
}
);
	return d}
(dat.controllers.Controller,dat.dom.dom,dat.utils.common);
	dat.color.toString=function(e){
	return function(a){
	if(a.a==1||e.isUndefined(a.a)){
	for(a=a.hex.toString(16);
	a.length<6;
	)a="0"+a;
	return"#"+a}
else return"rgba("+Math.round(a.r)+","+Math.round(a.g)+","+Math.round(a.b)+","+a.a+")"}
}
(dat.utils.common);
	dat.color.interpret=function(e,a){
	var c,d,f=[{
	litmus:a.isString,conversions:{
	THREE_CHAR_HEX:{
	read:function(a){
	a=a.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);
	return a===null?false:{
	space:"HEX",hex:parseInt("0x"+a[1].toString()+a[1].toString()+a[2].toString()+a[2].toString()+a[3].toString()+a[3].toString())}
}
,write:e}
,SIX_CHAR_HEX:{
	read:function(a){
	a=a.match(/^#([A-F0-9]{
	6}
)$/i);
	return a===null?false:{
	space:"HEX",hex:parseInt("0x"+a[1].toString())}
}
,write:e}
,CSS_RGB:{
	read:function(a){
	a=a.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);
	return a===null?false:{
	space:"RGB",r:parseFloat(a[1]),g:parseFloat(a[2]),b:parseFloat(a[3])}
}
,write:e}
,CSS_RGBA:{
	read:function(a){
	a=a.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\,\s*(.+)\s*\)/);
	return a===null?false:{
	space:"RGB",r:parseFloat(a[1]),g:parseFloat(a[2]),b:parseFloat(a[3]),a:parseFloat(a[4])}
}
,write:e}
}
}
,{
	litmus:a.isNumber,conversions:{
	HEX:{
	read:function(a){
	return{
	space:"HEX",hex:a,conversionName:"HEX"}
}
,write:function(a){
	return a.hex}
}
}
}
,{
	litmus:a.isArray,conversions:{
	RGB_ARRAY:{
	read:function(a){
	return a.length!=3?false:{
	space:"RGB",r:a[0],g:a[1],b:a[2]}
}
,write:function(a){
	return[a.r,a.g,a.b]}
}
,RGBA_ARRAY:{
	read:function(a){
	return a.length!=4?false:{
	space:"RGB",r:a[0],g:a[1],b:a[2],a:a[3]}
}
,write:function(a){
	return[a.r,a.g,a.b,a.a]}
}
}
}
,{
	litmus:a.isObject,conversions:{
	RGBA_OBJ:{
	read:function(b){
	return a.isNumber(b.r)&&a.isNumber(b.g)&&a.isNumber(b.b)&&a.isNumber(b.a)?{
	space:"RGB",r:b.r,g:b.g,b:b.b,a:b.a}
:false}
,write:function(a){
	return{
	r:a.r,g:a.g,b:a.b,a:a.a}
}
}
,RGB_OBJ:{
	read:function(b){
	return a.isNumber(b.r)&&a.isNumber(b.g)&&a.isNumber(b.b)?{
	space:"RGB",r:b.r,g:b.g,b:b.b}
:false}
,write:function(a){
	return{
	r:a.r,g:a.g,b:a.b}
}
}
,HSVA_OBJ:{
	read:function(b){
	return a.isNumber(b.h)&&a.isNumber(b.s)&&a.isNumber(b.v)&&a.isNumber(b.a)?{
	space:"HSV",h:b.h,s:b.s,v:b.v,a:b.a}
:false}
,write:function(a){
	return{
	h:a.h,s:a.s,v:a.v,a:a.a}
}
}
,HSV_OBJ:{
	read:function(b){
	return a.isNumber(b.h)&&a.isNumber(b.s)&&a.isNumber(b.v)?{
	space:"HSV",h:b.h,s:b.s,v:b.v}
:false}
,write:function(a){
	return{
	h:a.h,s:a.s,v:a.v}
}
}
}
}
];
	return function(){
	d=false;
	var b=arguments.length>1?a.toArray(arguments):arguments[0];
	a.each(f,function(e){
	if(e.litmus(b))return a.each(e.conversions,function(e,f){
	c=e.read(b);
	if(d===false&&c!==false)return d=c,c.conversionName=f,c.conversion=e,a.BREAK}
),a.BREAK}
);
	return d}
}
(dat.color.toString,dat.utils.common);
	dat.GUI=dat.gui.GUI=function(e,a,c,d,f,b,n,h,j,m,l,o,y,g,i){
	function q(a,b,r,c){
	if(b[r]===void 0)throw Error("Object "+b+' has no property "'+r+'"');
	c.color?b=new l(b,r):(b=[b,r].concat(c.factoryArgs),b=d.apply(a,b));
	if(c.before instanceof f)c.before=c.before.__li;
	t(a,b);
	g.addClass(b.domElement,"c");
	r=document.createElement("span");
	g.addClass(r,"property-name");
	r.innerHTML=b.property;
	var e=document.createElement("div");
	e.appendChild(r);
	e.appendChild(b.domElement);
	c=s(a,e,c.before);
	g.addClass(c,k.CLASS_CONTROLLER_ROW);
	g.addClass(c,typeof b.getValue());
	p(a,c,b);
	a.__controllers.push(b);
	return b}
function s(a,b,d){
	var c=document.createElement("li");
	b&&c.appendChild(b);
	d?a.__ul.insertBefore(c,params.before):a.__ul.appendChild(c);
	a.onResize();
	return c}
function p(a,d,c){
	c.__li=d;
	c.__gui=a;
	i.extend(c,{
	options:function(b){
	if(arguments.length>1)return c.remove(),q(a,c.object,c.property,{
	before:c.__li.nextElementSibling,factoryArgs:[i.toArray(arguments)]}
);
	if(i.isArray(b)||i.isObject(b))return c.remove(),q(a,c.object,c.property,{
	before:c.__li.nextElementSibling,factoryArgs:[b]}
)}
,name:function(a){
	c.__li.firstElementChild.firstElementChild.innerHTML=a;
	return c}
,listen:function(){
	c.__gui.listen(c);
	return c}
,remove:function(){
	c.__gui.remove(c);
	return c}
}
);
	if(c instanceof j){
	var e=new h(c.object,c.property,{
	min:c.__min,max:c.__max,step:c.__step}
);
	i.each(["updateDisplay","onChange","onFinishChange"],function(a){
	var b=c[a],H=e[a];
	c[a]=e[a]=function(){
	var a=Array.prototype.slice.call(arguments);
	b.apply(c,a);
	return H.apply(e,a)}
}
);
	g.addClass(d,"has-slider");
	c.domElement.insertBefore(e.domElement,c.domElement.firstElementChild)}
else if(c instanceof h){
	var f=function(b){
	return i.isNumber(c.__min)&&i.isNumber(c.__max)?(c.remove(),q(a,c.object,c.property,{
	before:c.__li.nextElementSibling,factoryArgs:[c.__min,c.__max,c.__step]}
)):b}
;
	c.min=i.compose(f,c.min);
	c.max=i.compose(f,c.max)}
else if(c instanceof b)g.bind(d,"click",function(){
	g.fakeEvent(c.__checkbox,"click")}
),g.bind(c.__checkbox,"click",function(a){
	a.stopPropagation()}
);
	else if(c instanceof n)g.bind(d,"click",function(){
	g.fakeEvent(c.__button,"click")}
),g.bind(d,"mouseover",function(){
	g.addClass(c.__button,"hover")}
),g.bind(d,"mouseout",function(){
	g.removeClass(c.__button,"hover")}
);
	else if(c instanceof l)g.addClass(d,"color"),c.updateDisplay=i.compose(function(a){
	d.style.borderLeftColor=c.__color.toString();
	return a}
,c.updateDisplay),c.updateDisplay();
	c.setValue=i.compose(function(b){
	a.getRoot().__preset_select&&c.isModified()&&B(a.getRoot(),true);
	return b}
,c.setValue)}
function t(a,b){
	var c=a.getRoot(),d=c.__rememberedObjects.indexOf(b.object);
	if(d!=-1){
	var e=c.__rememberedObjectIndecesToControllers[d];
	e===void 0&&(e={
}
,c.__rememberedObjectIndecesToControllers[d]=e);
	e[b.property]=b;
	if(c.load&&c.load.remembered){
	c=c.load.remembered;
	if(c[a.preset])c=c[a.preset];
	else if(c[w])c=c[w];
	else return;
	if(c[d]&&c[d][b.property]!==void 0)d=c[d][b.property],b.initialValue=d,b.setValue(d)}
}
}
function I(a){
	var b=a.__save_row=document.createElement("li");
	g.addClass(a.domElement,"has-save");
	a.__ul.insertBefore(b,a.__ul.firstChild);
	g.addClass(b,"save-row");
	var c=document.createElement("span");
	c.innerHTML="&nbsp;
	";
	g.addClass(c,"button gears");
	var d=document.createElement("span");
	d.innerHTML="Save";
	g.addClass(d,"button");
	g.addClass(d,"save");
	var e=document.createElement("span");
	e.innerHTML="New";
	g.addClass(e,"button");
	g.addClass(e,"save-as");
	var f=document.createElement("span");
	f.innerHTML="Revert";
	g.addClass(f,"button");
	g.addClass(f,"revert");
	var m=a.__preset_select=document.createElement("select");
	a.load&&a.load.remembered?i.each(a.load.remembered,function(b,c){
	C(a,c,c==a.preset)}
):C(a,w,false);
	g.bind(m,"change",function(){
	for(var b=0;
	b<a.__preset_select.length;
	b++)a.__preset_select[b].innerHTML=a.__preset_select[b].value;
	a.preset=this.value}
);
	b.appendChild(m);
	b.appendChild(c);
	b.appendChild(d);
	b.appendChild(e);
	b.appendChild(f);
	if(u){
	var b=document.getElementById("dg-save-locally"),l=document.getElementById("dg-local-explain");
	b.style.display="block";
	b=document.getElementById("dg-local-storage");
	localStorage.getItem(document.location.href+".isLocal")==="true"&&b.setAttribute("checked","checked");
	var o=function(){
	l.style.display=a.useLocalStorage?"block":"none"}
;
	o();
	g.bind(b,"change",function(){
	a.useLocalStorage=!a.useLocalStorage;
	o()}
)}
var h=document.getElementById("dg-new-constructor");
	g.bind(h,"keydown",function(a){
	a.metaKey&&(a.which===67||a.keyCode==67)&&x.hide()}
);
	g.bind(c,"click",function(){
	h.innerHTML=JSON.stringify(a.getSaveObject(),void 0,2);
	x.show();
	h.focus();
	h.select()}
);
	g.bind(d,"click",function(){
	a.save()}
);
	g.bind(e,"click",function(){
	var b=prompt("Enter a new preset name.");
	b&&a.saveAs(b)}
);
	g.bind(f,"click",function(){
	a.revert()}
)}
function J(a){
	function b(f){
	f.preventDefault();
	e=f.clientX;
	g.addClass(a.__closeButton,k.CLASS_DRAG);
	g.bind(window,"mousemove",c);
	g.bind(window,"mouseup",d);
	return false}
function c(b){
	b.preventDefault();
	a.width+=e-b.clientX;
	a.onResize();
	e=b.clientX;
	return false}
function d(){
	g.removeClass(a.__closeButton,k.CLASS_DRAG);
	g.unbind(window,"mousemove",c);
	g.unbind(window,"mouseup",d)}
a.__resize_handle=document.createElement("div");
	i.extend(a.__resize_handle.style,{
	width:"6px",marginLeft:"-3px",height:"200px",cursor:"ew-resize",position:"absolute"}
);
	var e;
	g.bind(a.__resize_handle,"mousedown",b);
	g.bind(a.__closeButton,"mousedown",b);
	a.domElement.insertBefore(a.__resize_handle,a.domElement.firstElementChild)}
function D(a,b){
	a.domElement.style.width=b+"px";
	if(a.__save_row&&a.autoPlace)a.__save_row.style.width=b+"px";
	if(a.__closeButton)a.__closeButton.style.width=b+"px"}
function z(a,b){
	var c={
}
;
	i.each(a.__rememberedObjects,function(d,e){
	var f={
}
;
	i.each(a.__rememberedObjectIndecesToControllers[e],function(a,c){
	f[c]=b?a.initialValue:a.getValue()}
);
	c[e]=f}
);
	return c}
function C(a,b,c){
	var d=document.createElement("option");
	d.innerHTML=b;
	d.value=b;
	a.__preset_select.appendChild(d);
	if(c)a.__preset_select.selectedIndex=a.__preset_select.length-1}
function B(a,b){
	var c=a.__preset_select[a.__preset_select.selectedIndex];
	c.innerHTML=b?c.value+"*":c.value}
function E(a){
	a.length!=0&&o(function(){
	E(a)}
);
	i.each(a,function(a){
	a.updateDisplay()}
)}
e.inject(c);
	var w="Default",u;
	try{
	u="localStorage"in window&&window.localStorage!==null}
catch(K){
	u=false}
var x,F=true,v,A=false,G=[],k=function(a){
	function b(){
	localStorage.setItem(document.location.href+".gui",JSON.stringify(d.getSaveObject()))}
function c(){
	var a=d.getRoot();
	a.width+=1;
	i.defer(function(){
	a.width-=1}
)}
var d=this;
	this.domElement=document.createElement("div");
	this.__ul=document.createElement("ul");
	this.domElement.appendChild(this.__ul);
	g.addClass(this.domElement,"dg");
	this.__folders={
}
;
	this.__controllers=[];
	this.__rememberedObjects=[];
	this.__rememberedObjectIndecesToControllers=[];
	this.__listening=[];
	a=a||{
}
;
	a=i.defaults(a,{
	autoPlace:true,width:k.DEFAULT_WIDTH}
);
	a=i.defaults(a,{
	resizable:a.autoPlace,hideable:a.autoPlace}
);
	if(i.isUndefined(a.load))a.load={
	preset:w}
;
	else if(a.preset)a.load.preset=a.preset;
	i.isUndefined(a.parent)&&a.hideable&&G.push(this);
	a.resizable=i.isUndefined(a.parent)&&a.resizable;
	if(a.autoPlace&&i.isUndefined(a.scrollable))a.scrollable=true;
	var e=u&&localStorage.getItem(document.location.href+".isLocal")==="true";
	Object.defineProperties(this,{
	parent:{
	get:function(){
	return a.parent}
}
,scrollable:{
	get:function(){
	return a.scrollable}
}
,autoPlace:{
	get:function(){
	return a.autoPlace}
}
,preset:{
	get:function(){
	return d.parent?d.getRoot().preset:a.load.preset}
,set:function(b){
	d.parent?d.getRoot().preset=b:a.load.preset=b;
	for(b=0;
	b<this.__preset_select.length;
	b++)if(this.__preset_select[b].value==this.preset)this.__preset_select.selectedIndex=b;
	d.revert()}
}
,width:{
	get:function(){
	return a.width}
,set:function(b){
	a.width=b;
	D(d,b)}
}
,name:{
	get:function(){
	return a.name}
,set:function(b){
	a.name=b;
	if(m)m.innerHTML=a.name}
}
,closed:{
	get:function(){
	return a.closed}
,set:function(b){
	a.closed=b;
	a.closed?g.addClass(d.__ul,k.CLASS_CLOSED):g.removeClass(d.__ul,k.CLASS_CLOSED);
	this.onResize();
	if(d.__closeButton)d.__closeButton.innerHTML=b?k.TEXT_OPEN:k.TEXT_CLOSED}
}
,load:{
	get:function(){
	return a.load}
}
,useLocalStorage:{
	get:function(){
	return e}
,set:function(a){
	u&&((e=a)?g.bind(window,"unload",b):g.unbind(window,"unload",b),localStorage.setItem(document.location.href+".isLocal",a))}
}
}
);
	if(i.isUndefined(a.parent)){
	a.closed=false;
	g.addClass(this.domElement,k.CLASS_MAIN);
	g.makeSelectable(this.domElement,false);
	if(u&&e){
	d.useLocalStorage=true;
	var f=localStorage.getItem(document.location.href+".gui");
	if(f)a.load=JSON.parse(f)}
this.__closeButton=document.createElement("div");
	this.__closeButton.innerHTML=k.TEXT_CLOSED;
	g.addClass(this.__closeButton,k.CLASS_CLOSE_BUTTON);
	this.domElement.appendChild(this.__closeButton);
	g.bind(this.__closeButton,"click",function(){
	d.closed=!d.closed}
)}
else{
	if(a.closed===void 0)a.closed=true;
	var m=document.createTextNode(a.name);
	g.addClass(m,"controller-name");
	f=s(d,m);
	g.addClass(this.__ul,k.CLASS_CLOSED);
	g.addClass(f,"title");
	g.bind(f,"click",function(a){
	a.preventDefault();
	d.closed=!d.closed;
	return false}
);
	if(!a.closed)this.closed=false}
a.autoPlace&&(i.isUndefined(a.parent)&&(F&&(v=document.createElement("div"),g.addClass(v,"dg"),g.addClass(v,k.CLASS_AUTO_PLACE_CONTAINER),document.body.appendChild(v),F=false),v.appendChild(this.domElement),g.addClass(this.domElement,k.CLASS_AUTO_PLACE)),this.parent||D(d,a.width));
	g.bind(window,"resize",function(){
	d.onResize()}
);
	g.bind(this.__ul,"webkitTransitionEnd",function(){
	d.onResize()}
);
	g.bind(this.__ul,"transitionend",function(){
	d.onResize()}
);
	g.bind(this.__ul,"oTransitionEnd",function(){
	d.onResize()}
);
	this.onResize();
	a.resizable&&J(this);
	d.getRoot();
	a.parent||c()}
;
	k.toggleHide=function(){
	A=!A;
	i.each(G,function(a){
	a.domElement.style.zIndex=A?-999:999;
	a.domElement.style.opacity=A?0:1}
)}
;
	k.CLASS_AUTO_PLACE="a";
	k.CLASS_AUTO_PLACE_CONTAINER="ac";
	k.CLASS_MAIN="main";
	k.CLASS_CONTROLLER_ROW="cr";
	k.CLASS_TOO_TALL="taller-than-window";
	k.CLASS_CLOSED="closed";
	k.CLASS_CLOSE_BUTTON="close-button";
	k.CLASS_DRAG="drag";
	k.DEFAULT_WIDTH=245;
	k.TEXT_CLOSED="Close Controls";
	k.TEXT_OPEN="Open Controls";
	g.bind(window,"keydown",function(a){
	document.activeElement.type!=="text"&&(a.which===72||a.keyCode==72)&&k.toggleHide()}
,false);
	i.extend(k.prototype,{
	add:function(a,b){
	return q(this,a,b,{
	factoryArgs:Array.prototype.slice.call(arguments,2)}
)}
,addColor:function(a,b){
	return q(this,a,b,{
	color:true}
)}
,remove:function(a){
	this.__ul.removeChild(a.__li);
	this.__controllers.slice(this.__controllers.indexOf(a),1);
	var b=this;
	i.defer(function(){
	b.onResize()}
)}
,destroy:function(){
	this.autoPlace&&v.removeChild(this.domElement)}
,addFolder:function(a){
	if(this.__folders[a]!==void 0)throw Error('You already have a folder in this GUI by the name "'+a+'"');
	var b={
	name:a,parent:this}
;
	b.autoPlace=this.autoPlace;
	if(this.load&&this.load.folders&&this.load.folders[a])b.closed=this.load.folders[a].closed,b.load=this.load.folders[a];
	b=new k(b);
	this.__folders[a]=b;
	a=s(this,b.domElement);
	g.addClass(a,"folder");
	return b}
,open:function(){
	this.closed=false}
,close:function(){
	this.closed=true}
,onResize:function(){
	var a=this.getRoot();
	if(a.scrollable){
	var b=g.getOffset(a.__ul).top,c=0;
	i.each(a.__ul.childNodes,function(b){
	a.autoPlace&&b===a.__save_row||(c+=g.getHeight(b))}
);
	window.innerHeight-b-20<c?(g.addClass(a.domElement,k.CLASS_TOO_TALL),a.__ul.style.height=window.innerHeight-b-20+"px"):(g.removeClass(a.domElement,k.CLASS_TOO_TALL),a.__ul.style.height="auto")}
a.__resize_handle&&i.defer(function(){
	a.__resize_handle.style.height=a.__ul.offsetHeight+"px"}
);
	if(a.__closeButton)a.__closeButton.style.width=a.width+"px"}
,remember:function(){
	if(i.isUndefined(x))x=new y,x.domElement.innerHTML=a;
	if(this.parent)throw Error("You can only call remember on a top level GUI.");
	var b=this;
	i.each(Array.prototype.slice.call(arguments),function(a){
	b.__rememberedObjects.length==0&&I(b);
	b.__rememberedObjects.indexOf(a)==-1&&b.__rememberedObjects.push(a)}
);
	this.autoPlace&&D(this,this.width)}
,getRoot:function(){
	for(var a=this;
	a.parent;
	)a=a.parent;
	return a}
,getSaveObject:function(){
	var a=this.load;
	a.closed=this.closed;
	if(this.__rememberedObjects.length>0){
	a.preset=this.preset;
	if(!a.remembered)a.remembered={
}
;
	a.remembered[this.preset]=z(this)}
a.folders={
}
;
	i.each(this.__folders,function(b,c){
	a.folders[c]=b.getSaveObject()}
);
	return a}
,save:function(){
	if(!this.load.remembered)this.load.remembered={
}
;
	this.load.remembered[this.preset]=z(this);
	B(this,false)}
,saveAs:function(a){
	if(!this.load.remembered)this.load.remembered={
}
,this.load.remembered[w]=z(this,true);
	this.load.remembered[a]=z(this);
	this.preset=a;
	C(this,a,true)}
,revert:function(a){
	i.each(this.__controllers,function(b){
	this.getRoot().load.remembered?t(a||this.getRoot(),b):b.setValue(b.initialValue)}
,this);
	i.each(this.__folders,function(a){
	a.revert(a)}
);
	a||B(this.getRoot(),false)}
,listen:function(a){
	var b=this.__listening.length==0;
	this.__listening.push(a);
	b&&E(this.__listening)}
}
);
	return k}
(dat.utils.css,'<div id="dg-save" class="dg dialogue">\n\n Here\'s the new load parameter for your <code>GUI</code>\'s constructor:\n\n <textarea id="dg-new-constructor"></textarea>\n\n <div id="dg-save-locally">\n\n <input id="dg-local-storage" type="checkbox"/> Automatically save\n values to <code>localStorage</code> on exit.\n\n <div id="dg-local-explain">The values saved to <code>localStorage</code> will\n override those passed to <code>dat.GUI</code>\'s constructor. This makes it\n easier to work incrementally,but <code>localStorage</code> is fragile,\n and your friends may not see the same values you do.\n \n </div>\n \n </div>\n\n</div>',".dg ul{
	list-style:none;
	margin:0;
	padding:0;
	width:100%;
	clear:both}
.dg.ac{
	position:fixed;
	top:0;
	left:0;
	right:0;
	height:0;
	z-index:0}
.dg:not(.ac) .main{
	overflow:hidden}
.dg.main{
	-webkit-transition:opacity 0.1s linear;
	-o-transition:opacity 0.1s linear;
	-moz-transition:opacity 0.1s linear;
	transition:opacity 0.1s linear}
.dg.main.taller-than-window{
	overflow-y:auto}
.dg.main.taller-than-window .close-button{
	opacity:1;
	margin-top:-1px;
	border-top:1px solid #2c2c2c}
.dg.main ul.closed .close-button{
	opacity:1 !important}
.dg.main:hover .close-button,.dg.main .close-button.drag{
	opacity:1}
.dg.main .close-button{
	-webkit-transition:opacity 0.1s linear;
	-o-transition:opacity 0.1s linear;
	-moz-transition:opacity 0.1s linear;
	transition:opacity 0.1s linear;
	border:0;
	position:absolute;
	line-height:19px;
	height:20px;
	cursor:pointer;
	text-align:center;
	background-color:#000}
.dg.main .close-button:hover{
	background-color:#111}
.dg.a{
	float:right;
	margin-right:15px;
	overflow-x:hidden}
.dg.a.has-save ul{
	margin-top:27px}
.dg.a.has-save ul.closed{
	margin-top:0}
.dg.a .save-row{
	position:fixed;
	top:0;
	z-index:1002}
.dg li{
	-webkit-transition:height 0.1s ease-out;
	-o-transition:height 0.1s ease-out;
	-moz-transition:height 0.1s ease-out;
	transition:height 0.1s ease-out}
.dg li:not(.folder){
	cursor:auto;
	height:27px;
	line-height:27px;
	overflow:hidden;
	padding:0 4px 0 5px}
.dg li.folder{
	padding:0;
	border-left:4px solid rgba(0,0,0,0)}
.dg li.title{
	cursor:pointer;
	margin-left:-4px}
.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li > *{
	height:0;
	overflow:hidden;
	border:0}
.dg .cr{
	clear:both;
	padding-left:3px;
	height:27px}
.dg .property-name{
	cursor:default;
	float:left;
	clear:left;
	width:40%;
	overflow:hidden;
	text-overflow:ellipsis}
.dg .c{
	float:left;
	width:60%}
.dg .c input[type=text]{
	border:0;
	margin-top:4px;
	padding:3px;
	width:100%;
	float:right}
.dg .has-slider input[type=text]{
	width:30%;
	margin-left:0}
.dg .slider{
	float:left;
	width:66%;
	margin-left:-5px;
	margin-right:0;
	height:19px;
	margin-top:4px}
.dg .slider-fg{
	height:100%}
.dg .c input[type=checkbox]{
	margin-top:9px}
.dg .c select{
	margin-top:5px}
.dg .cr.function,.dg .cr.function .property-name,.dg .cr.function *,.dg .cr.boolean,.dg .cr.boolean *{
	cursor:pointer}
.dg .selector{
	display:none;
	position:absolute;
	margin-left:-9px;
	margin-top:23px;
	z-index:10}
.dg .c:hover .selector,.dg .selector.drag{
	display:block}
.dg li.save-row{
	padding:0}
.dg li.save-row .button{
	display:inline-block;
	padding:0px 6px}
.dg.dialogue{
	background-color:#222;
	width:460px;
	padding:15px;
	font-size:13px;
	line-height:15px}
#dg-new-constructor{
	padding:10px;
	color:#222;
	font-family:Monaco,monospace;
	font-size:10px;
	border:0;
	resize:none;
	box-shadow:inset 1px 1px 1px #888;
	word-wrap:break-word;
	margin:12px 0;
	display:block;
	width:440px;
	overflow-y:scroll;
	height:100px;
	position:relative}
#dg-local-explain{
	display:none;
	font-size:11px;
	line-height:17px;
	border-radius:3px;
	background-color:#333;
	padding:8px;
	margin-top:10px}
#dg-local-explain code{
	font-size:10px}
#dat-gui-save-locally{
	display:none}
.dg{
	color:#eee;
	font:11px 'Lucida Grande',sans-serif;
	text-shadow:0 -1px 0 #111}
.dg.main::-webkit-scrollbar{
	width:5px;
	background:#1a1a1a}
.dg.main::-webkit-scrollbar-corner{
	height:0;
	display:none}
.dg.main::-webkit-scrollbar-thumb{
	border-radius:5px;
	background:#676767}
.dg li:not(.folder){
	background:#1a1a1a;
	border-bottom:1px solid #2c2c2c}
.dg li.save-row{
	line-height:25px;
	background:#dad5cb;
	border:0}
.dg li.save-row select{
	margin-left:5px;
	width:108px}
.dg li.save-row .button{
	margin-left:5px;
	margin-top:1px;
	border-radius:2px;
	font-size:9px;
	line-height:7px;
	padding:4px 4px 5px 4px;
	background:#c5bdad;
	color:#fff;
	text-shadow:0 1px 0 #b0a58f;
	box-shadow:0 -1px 0 #b0a58f;
	cursor:pointer}
.dg li.save-row .button.gears{
	background:#c5bdad url(data:image/png;
	base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;
	height:7px;
	width:8px}
.dg li.save-row .button:hover{
	background-color:#bab19e;
	box-shadow:0 -1px 0 #b0a58f}
.dg li.folder{
	border-bottom:0}
.dg li.title{
	padding-left:16px;
	background:#000 url(data:image/gif;
	base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;
	cursor:pointer;
	border-bottom:1px solid rgba(255,255,255,0.2)}
.dg .closed li.title{
	background-image:url(data:image/gif;
	base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}
.dg .cr.boolean{
	border-left:3px solid #806787}
.dg .cr.function{
	border-left:3px solid #e61d5f}
.dg .cr.number{
	border-left:3px solid #2fa1d6}
.dg .cr.number input[type=text]{
	color:#2fa1d6}
.dg .cr.string{
	border-left:3px solid #1ed36f}
.dg .cr.string input[type=text]{
	color:#1ed36f}
.dg .cr.function:hover,.dg .cr.boolean:hover{
	background:#111}
.dg .c input[type=text]{
	background:#303030;
	outline:none}
.dg .c input[type=text]:hover{
	background:#3c3c3c}
.dg .c input[type=text]:focus{
	background:#494949;
	color:#fff}
.dg .c .slider{
	background:#303030;
	cursor:ew-resize}
.dg .c .slider-fg{
	background:#2fa1d6}
.dg .c .slider:hover{
	background:#3c3c3c}
.dg .c .slider:hover .slider-fg{
	background:#44abda}
\n",dat.controllers.factory=function(e,a,c,d,f,b,n){
	return function(h,j,m,l){
	var o=h[j];
	if(n.isArray(m)||n.isObject(m))return new e(h,j,m);
	if(n.isNumber(o))return n.isNumber(m)&&n.isNumber(l)?new c(h,j,m,l):new a(h,j,{
	min:m,max:l}
);
	if(n.isString(o))return new d(h,j);
	if(n.isFunction(o))return new f(h,j,"");
	if(n.isBoolean(o))return new b(h,j)}
}
(dat.controllers.OptionController,dat.controllers.NumberControllerBox,dat.controllers.NumberControllerSlider,dat.controllers.StringController=function(e,a,c){
	var d=function(c,b){
	function e(){
	h.setValue(h.__input.value)}
d.superclass.call(this,c,b);
	var h=this;
	this.__input=document.createElement("input");
	this.__input.setAttribute("type","text");
	a.bind(this.__input,"keyup",e);
	a.bind(this.__input,"change",e);
	a.bind(this.__input,"blur",function(){
	h.__onFinishChange&&h.__onFinishChange.call(h,h.getValue())}
);
	a.bind(this.__input,"keydown",function(a){
	a.keyCode===13&&this.blur()}
);
	this.updateDisplay();
	this.domElement.appendChild(this.__input)}
;
	d.superclass=e;
	c.extend(d.prototype,e.prototype,{
	updateDisplay:function(){
	if(!a.isActive(this.__input))this.__input.value=this.getValue();
	return d.superclass.prototype.updateDisplay.call(this)}
}
);
	return d}
(dat.controllers.Controller,dat.dom.dom,dat.utils.common),dat.controllers.FunctionController,dat.controllers.BooleanController,dat.utils.common),dat.controllers.Controller,dat.controllers.BooleanController,dat.controllers.FunctionController,dat.controllers.NumberControllerBox,dat.controllers.NumberControllerSlider,dat.controllers.OptionController,dat.controllers.ColorController=function(e,a,c,d,f){
	function b(a,b,c,d){
	a.style.background="";
	f.each(j,function(e){
	a.style.cssText+="background:"+e+"linear-gradient("+b+","+c+" 0%,"+d+" 100%);
	"}
)}
function n(a){
	a.style.background="";
	a.style.cssText+="background:-moz-linear-gradient(top,#ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);
	";
	a.style.cssText+="background:-webkit-linear-gradient(top,#ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);
	";
	a.style.cssText+="background:-o-linear-gradient(top,#ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);
	";
	a.style.cssText+="background:-ms-linear-gradient(top,#ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);
	";
	a.style.cssText+="background:linear-gradient(top,#ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);
	"}
var h=function(e,l){
	function o(b){
	q(b);
	a.bind(window,"mousemove",q);
	a.bind(window,"mouseup",j)}
function j(){
	a.unbind(window,"mousemove",q);
	a.unbind(window,"mouseup",j)}
function g(){
	var a=d(this.value);
	a!==false?(p.__color.__state=a,p.setValue(p.__color.toOriginal())):this.value=p.__color.toString()}
function i(){
	a.unbind(window,"mousemove",s);
	a.unbind(window,"mouseup",i)}
function q(b){
	b.preventDefault();
	var c=a.getWidth(p.__saturation_field),d=a.getOffset(p.__saturation_field),e=(b.clientX-d.left+document.body.scrollLeft)/c,b=1-(b.clientY-d.top+document.body.scrollTop)/c;
	b>1?b=1:b<0&&(b=0);
	e>1?e=1:e<0&&(e=0);
	p.__color.v=b;
	p.__color.s=e;
	p.setValue(p.__color.toOriginal());
	return false}
function s(b){
	b.preventDefault();
	var c=a.getHeight(p.__hue_field),d=a.getOffset(p.__hue_field),b=1-(b.clientY-d.top+document.body.scrollTop)/c;
	b>1?b=1:b<0&&(b=0);
	p.__color.h=b*360;
	p.setValue(p.__color.toOriginal());
	return false}
h.superclass.call(this,e,l);
	this.__color=new c(this.getValue());
	this.__temp=new c(0);
	var p=this;
	this.domElement=document.createElement("div");
	a.makeSelectable(this.domElement,false);
	this.__selector=document.createElement("div");
	this.__selector.className="selector";
	this.__saturation_field=document.createElement("div");
	this.__saturation_field.className="saturation-field";
	this.__field_knob=document.createElement("div");
	this.__field_knob.className="field-knob";
	this.__field_knob_border="2px solid ";
	this.__hue_knob=document.createElement("div");
	this.__hue_knob.className="hue-knob";
	this.__hue_field=document.createElement("div");
	this.__hue_field.className="hue-field";
	this.__input=document.createElement("input");
	this.__input.type="text";
	this.__input_textShadow="0 1px 1px ";
	a.bind(this.__input,"keydown",function(a){
	a.keyCode===13&&g.call(this)}
);
	a.bind(this.__input,"blur",g);
	a.bind(this.__selector,"mousedown",function(){
	a.addClass(this,"drag").bind(window,"mouseup",function(){
	a.removeClass(p.__selector,"drag")}
)}
);
	var t=document.createElement("div");
	f.extend(this.__selector.style,{
	width:"122px",height:"102px",padding:"3px",backgroundColor:"#222",boxShadow:"0px 1px 3px rgba(0,0,0,0.3)"}
);
	f.extend(this.__field_knob.style,{
	position:"absolute",width:"12px",height:"12px",border:this.__field_knob_border+(this.__color.v<0.5?"#fff":"#000"),boxShadow:"0px 1px 3px rgba(0,0,0,0.5)",borderRadius:"12px",zIndex:1}
);
	f.extend(this.__hue_knob.style,{
	position:"absolute",width:"15px",height:"2px",borderRight:"4px solid #fff",zIndex:1}
);
	f.extend(this.__saturation_field.style,{
	width:"100px",height:"100px",border:"1px solid #555",marginRight:"3px",display:"inline-block",cursor:"pointer"}
);
	f.extend(t.style,{
	width:"100%",height:"100%",background:"none"}
);
	b(t,"top","rgba(0,0,0,0)","#000");
	f.extend(this.__hue_field.style,{
	width:"15px",height:"100px",display:"inline-block",border:"1px solid #555",cursor:"ns-resize"}
);
	n(this.__hue_field);
	f.extend(this.__input.style,{
	outline:"none",textAlign:"center",color:"#fff",border:0,fontWeight:"bold",textShadow:this.__input_textShadow+"rgba(0,0,0,0.7)"}
);
	a.bind(this.__saturation_field,"mousedown",o);
	a.bind(this.__field_knob,"mousedown",o);
	a.bind(this.__hue_field,"mousedown",function(b){
	s(b);
	a.bind(window,"mousemove",s);
	a.bind(window,"mouseup",i)}
);
	this.__saturation_field.appendChild(t);
	this.__selector.appendChild(this.__field_knob);
	this.__selector.appendChild(this.__saturation_field);
	this.__selector.appendChild(this.__hue_field);
	this.__hue_field.appendChild(this.__hue_knob);
	this.domElement.appendChild(this.__input);
	this.domElement.appendChild(this.__selector);
	this.updateDisplay()}
;
	h.superclass=e;
	f.extend(h.prototype,e.prototype,{
	updateDisplay:function(){
	var a=d(this.getValue());
	if(a!==false){
	var e=false;
	f.each(c.COMPONENTS,function(b){
	if(!f.isUndefined(a[b])&&!f.isUndefined(this.__color.__state[b])&&a[b]!==this.__color.__state[b])return e=true,{
}
}
,this);
	e&&f.extend(this.__color.__state,a)}
f.extend(this.__temp.__state,this.__color.__state);
	this.__temp.a=1;
	var h=this.__color.v<0.5||this.__color.s>0.5?255:0,j=255-h;
	f.extend(this.__field_knob.style,{
	marginLeft:100*this.__color.s-7+"px",marginTop:100*(1-this.__color.v)-7+"px",backgroundColor:this.__temp.toString(),border:this.__field_knob_border+"rgb("+h+","+h+","+h+")"}
);
	this.__hue_knob.style.marginTop=(1-this.__color.h/360)*100+"px";
	this.__temp.s=1;
	this.__temp.v=1;
	b(this.__saturation_field,"left","#fff",this.__temp.toString());
	f.extend(this.__input.style,{
	backgroundColor:this.__input.value=this.__color.toString(),color:"rgb("+h+","+h+","+h+")",textShadow:this.__input_textShadow+"rgba("+j+","+j+","+j+",.7)"}
)}
}
);
	var j=["-moz-","-o-","-webkit-","-ms-",""];
	return h}
(dat.controllers.Controller,dat.dom.dom,dat.color.Color=function(e,a,c,d){
	function f(a,b,c){
	Object.defineProperty(a,b,{
	get:function(){
	if(this.__state.space==="RGB")return this.__state[b];
	n(this,b,c);
	return this.__state[b]}
,set:function(a){
	if(this.__state.space!=="RGB")n(this,b,c),this.__state.space="RGB";
	this.__state[b]=a}
}
)}
function b(a,b){
	Object.defineProperty(a,b,{
	get:function(){
	if(this.__state.space==="HSV")return this.__state[b];
	h(this);
	return this.__state[b]}
,set:function(a){
	if(this.__state.space!=="HSV")h(this),this.__state.space="HSV";
	this.__state[b]=a}
}
)}
function n(b,c,e){
	if(b.__state.space==="HEX")b.__state[c]=a.component_from_hex(b.__state.hex,e);
	else if(b.__state.space==="HSV")d.extend(b.__state,a.hsv_to_rgb(b.__state.h,b.__state.s,b.__state.v));
	else throw"Corrupted color state";
}
function h(b){
	var c=a.rgb_to_hsv(b.r,b.g,b.b);
	d.extend(b.__state,{
	s:c.s,v:c.v}
);
	if(d.isNaN(c.h)){
	if(d.isUndefined(b.__state.h))b.__state.h=0}
else b.__state.h=c.h}
var j=function(){
	this.__state=e.apply(this,arguments);
	if(this.__state===false)throw"Failed to interpret color arguments";
	this.__state.a=this.__state.a||1}
;
	j.COMPONENTS="r,g,b,h,s,v,hex,a".split(",");
	d.extend(j.prototype,{
	toString:function(){
	return c(this)}
,toOriginal:function(){
	return this.__state.conversion.write(this)}
}
);
	f(j.prototype,"r",2);
	f(j.prototype,"g",1);
	f(j.prototype,"b",0);
	b(j.prototype,"h");
	b(j.prototype,"s");
	b(j.prototype,"v");
	Object.defineProperty(j.prototype,"a",{
	get:function(){
	return this.__state.a}
,set:function(a){
	this.__state.a=a}
}
);
	Object.defineProperty(j.prototype,"hex",{
	get:function(){
	if(!this.__state.space!=="HEX")this.__state.hex=a.rgb_to_hex(this.r,this.g,this.b);
	return this.__state.hex}
,set:function(a){
	this.__state.space="HEX";
	this.__state.hex=a}
}
);
	return j}
(dat.color.interpret,dat.color.math=function(){
	var e;
	return{
	hsv_to_rgb:function(a,c,d){
	var e=a/60-Math.floor(a/60),b=d*(1-c),n=d*(1-e*c),c=d*(1-(1-e)*c),a=[[d,c,b],[n,d,b],[b,d,c],[b,n,d],[c,b,d],[d,b,n]][Math.floor(a/60)%6];
	return{
	r:a[0]*255,g:a[1]*255,b:a[2]*255}
}
,rgb_to_hsv:function(a,c,d){
	var e=Math.min(a,c,d),b=Math.max(a,c,d),e=b-e;
	if(b==0)return{
	h:NaN,s:0,v:0}
;
	a=a==b?(c-d)/e:c==b?2+(d-a)/e:4+(a-c)/e;
	a/=6;
	a<0&&(a+=1);
	return{
	h:a*360,s:e/b,v:b/255}
}
,rgb_to_hex:function(a,c,d){
	a=this.hex_with_component(0,2,a);
	a=this.hex_with_component(a,1,c);
	return a=this.hex_with_component(a,0,d)}
,component_from_hex:function(a,c){
	return a>>c*8&255}
,hex_with_component:function(a,c,d){
	return d<<(e=c*8)|a&~(255<<e)}
}
}
(),dat.color.toString,dat.utils.common),dat.color.interpret,dat.utils.common),dat.utils.requestAnimationFrame=function(){
	return window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(e){
	window.setTimeout(e,1E3/60)}
}
(),dat.dom.CenteredDiv=function(e,a){
	var c=function(){
	this.backgroundElement=document.createElement("div");
	a.extend(this.backgroundElement.style,{
	backgroundColor:"rgba(0,0,0,0.8)",top:0,left:0,display:"none",zIndex:"1000",opacity:0,WebkitTransition:"opacity 0.2s linear"}
);
	e.makeFullscreen(this.backgroundElement);
	this.backgroundElement.style.position="fixed";
	this.domElement=document.createElement("div");
	a.extend(this.domElement.style,{
	position:"fixed",display:"none",zIndex:"1001",opacity:0,WebkitTransition:"-webkit-transform 0.2s ease-out,opacity 0.2s linear"}
);
	document.body.appendChild(this.backgroundElement);
	document.body.appendChild(this.domElement);
	var c=this;
	e.bind(this.backgroundElement,"click",function(){
	c.hide()}
)}
;
	c.prototype.show=function(){
	var c=this;
	this.backgroundElement.style.display="block";
	this.domElement.style.display="block";
	this.domElement.style.opacity=0;
	this.domElement.style.webkitTransform="scale(1.1)";
	this.layout();
	a.defer(function(){
	c.backgroundElement.style.opacity=1;
	c.domElement.style.opacity=1;
	c.domElement.style.webkitTransform="scale(1)"}
)}
;
	c.prototype.hide=function(){
	var a=this,c=function(){
	a.domElement.style.display="none";
	a.backgroundElement.style.display="none";
	e.unbind(a.domElement,"webkitTransitionEnd",c);
	e.unbind(a.domElement,"transitionend",c);
	e.unbind(a.domElement,"oTransitionEnd",c)}
;
	e.bind(this.domElement,"webkitTransitionEnd",c);
	e.bind(this.domElement,"transitionend",c);
	e.bind(this.domElement,"oTransitionEnd",c);
	this.backgroundElement.style.opacity=0;
	this.domElement.style.opacity=0;
	this.domElement.style.webkitTransform="scale(1.1)"}
;
	c.prototype.layout=function(){
	this.domElement.style.left=window.innerWidth/2-e.getWidth(this.domElement)/2+"px";
	this.domElement.style.top=window.innerHeight/2-e.getHeight(this.domElement)/2+"px"}
;
	return c}
(dat.dom.dom,dat.utils.common),dat.dom.dom,dat.utils.common);
	(function(){
	//------------------------------ // Mesh Properties //------------------------------ var MESH ={
	width:1.2,height:1.2,slices:250,ambient:'#555555',diffuse:'#FFFFFF'}
;
	//------------------------------ // Light Properties //------------------------------ var LIGHT ={
	count:1,xPos:0,yPos:200,zOffset:100,ambient:'#880066',diffuse:'#FF8800',pickedup:true,proxy:false,currIndex:0}
;
	//------------------------------ // Render Properties //------------------------------ var WEBGL = 'webgl';
	var CANVAS = 'canvas';
	var SVG = 'svg';
	var RENDER ={
	renderer:CANVAS}
;
	//------------------------------ // Export Properties //------------------------------ var EXPORT ={
	width:2000,height:1000,exportCurrent:function(){
	switch(RENDER.renderer){
	case WEBGL:window.open(webglRenderer.element.toDataURL(),'_blank');
	break;
	case CANVAS:window.open(canvasRenderer.element.toDataURL(),'_blank');
	break;
	case SVG:var data = encodeURIComponent(output.innerHTML);
	var url = "data:image/svg+xml," + data;
	window.open(url,'_blank');
	break;
}
}
,export:function(){
	var l,x,y,light,scalarX = this.width / renderer.width,scalarY = this.height / renderer.height;
	// store a temp value of the slices var slices = MESH.slices;
	// Increase or decrease number of slices depending on the size of the canvas MESH.slices = Math.ceil(slices*scalarX*1.3);
	// Regenerate the whole canvas resize(this.width,this.height);
	// restore the number of slices MESH.slices = slices;
	// Move the lights on the plane to accomodate the size of the canvas for (l = scene.lights.length - 1;
	l >= 0;
	l--){
	light = scene.lights[l];
	x = light.position[0];
	y = light.position[1];
	z = light.position[2];
	FSS.Vector3.set(light.position,x*scalarX,y*scalarY,z*scalarX);
}
// Render the canvas render();
	switch(RENDER.renderer){
	case WEBGL:window.open(webglRenderer.element.toDataURL(),'_blank');
	break;
	case CANVAS:window.open(canvasRenderer.element.toDataURL(),'_blank');
	break;
	case SVG:var data = encodeURIComponent(output.innerHTML);
	var url = "data:image/svg+xml," + data;
	window.open(url,'_blank');
	break;
}
resize(container.offsetWidth,container.offsetHeight);
	for (l = scene.lights.length - 1;
	l >= 0;
	l--){
	light = scene.lights[l];
	x = light.position[0];
	y = light.position[1];
	z = light.position[2];
	FSS.Vector3.set(light.position,x/scalarX,y/scalarY,z/scalarX);
}
}
}
;
	//------------------------------ // Global Properties //------------------------------ var center = FSS.Vector3.create();
	var container = document.getElementById('container');
	var controls = document.getElementById('controls');
	var output = document.getElementById('output');
	var renderer,scene,mesh,geometry,material;
	var webglRenderer,canvasRenderer,svgRenderer;
	var gui;
	//------------------------------ // Methods //------------------------------ function initialise(){
	createRenderer();
	createScene();
	createMesh();
	addLight();
	addEventListeners();
	addControls();
	resize(container.offsetWidth,container.offsetHeight);
	animate();
}
function createRenderer(){
	webglRenderer = new FSS.WebGLRenderer();
	canvasRenderer = new FSS.CanvasRenderer();
	svgRenderer = new FSS.SVGRenderer();
	setRenderer(RENDER.renderer);
}
function setRenderer(index){
	if (renderer){
	output.removeChild(renderer.element);
}
switch(index){
	case WEBGL:renderer = webglRenderer;
	break;
	case CANVAS:renderer = canvasRenderer;
	break;
	case SVG:renderer = svgRenderer;
	break;
}
renderer.setSize(container.offsetWidth,container.offsetHeight);
	output.appendChild(renderer.element);
}
function createScene(){
	scene = new FSS.Scene();
}
function createMesh(){
	scene.remove(mesh);
	renderer.clear();
	geometry = new FSS.Plane(MESH.width * renderer.width,MESH.height * renderer.height,MESH.slices);
	material = new FSS.Material(MESH.ambient,MESH.diffuse);
	mesh = new FSS.Mesh(geometry,material);
	scene.add(mesh);
}
// Add a single light function addLight(){
	renderer.clear();
	light = new FSS.Light(LIGHT.ambient,LIGHT.diffuse);
	light.ambientHex = light.ambient.format();
	light.diffuseHex = light.diffuse.format();
	light.setPosition(LIGHT.xPos,LIGHT.yPos,LIGHT.zOffset);
	scene.add(light);
	LIGHT.proxy = light;
	LIGHT.pickedup = true;
	LIGHT.currIndex++;
}
// Remove lights function trimLights(value){
	LIGHT.proxy = scene.lights[value];
	for (l = value;
	l >= scene.lights.length - 1;
	l--){
	light = scene.lights[l];
	scene.remove(light);
}
renderer.clear();
}
// Resize canvas function resize(width,height){
	renderer.setSize(width,height);
	FSS.Vector3.set(center,renderer.halfWidth,renderer.halfHeight);
	createMesh();
}
function animate(){
	render();
	requestAnimationFrame(animate);
}
function render(){
	renderer.render(scene);
}
function addEventListeners(){
	window.addEventListener('resize',onWindowResize);
	container.addEventListener('mousemove',onMouseMove);
}
function addControls(){
	var i,l,light,folder,controller;
	// Create GUI gui = new dat.GUI({
	autoPlace:false}
);
	controls.appendChild(gui.domElement);
	// Create folders renderFolder = gui.addFolder('Render');
	meshFolder = gui.addFolder('Mesh');
	lightFolder = gui.addFolder('Light');
	exportFolder = gui.addFolder('Export');
	// Open folders lightFolder.open();
	// Add Render Controls controller = renderFolder.add(RENDER,'renderer',{
	webgl:WEBGL,canvas:CANVAS,svg:SVG}
);
	controller.onChange(function(value){
	setRenderer(value);
}
);
	// Add Mesh Controls controller = meshFolder.addColor(MESH,'ambient');
	controller.onChange(function(value){
	for (i = 0,l = scene.meshes.length;
	i < l;
	i++){
	scene.meshes[i].material.ambient.set(value);
}
}
);
	controller = meshFolder.addColor(MESH,'diffuse');
	controller.onChange(function(value){
	for (i = 0,l = scene.meshes.length;
	i < l;
	i++){
	scene.meshes[i].material.diffuse.set(value);
}
}
);
	controller = meshFolder.add(MESH,'width',0.05,2);
	controller.onChange(function(value){
	if (geometry.width !== value * renderer.width){
	createMesh();
}
}
);
	controller = meshFolder.add(MESH,'height',0.05,2);
	controller.onChange(function(value){
	if (geometry.height !== value * renderer.height){
	createMesh();
}
}
);
	controller = meshFolder.add(MESH,'slices',1,800);
	controller.step(1);
	controller.onChange(function(value){
	if (geometry.slices !== value){
	createMesh();
}
}
);
	// Add Light Controls // TODO:add the number of lights dynamically controller = lightFolder.add(LIGHT,'currIndex',{
	1:1,2:2,3:3,4:4,5:5,6:6,7:7}
).name('Current light').listen();
	controller.onChange(function(value){
	LIGHT.proxy = scene.lights[value-1];
	LIGHT.ambient = LIGHT.proxy.ambient.hex;
	LIGHT.diffuse = LIGHT.proxy.diffuse.hex;
	LIGHT.xPos = LIGHT.proxy.position[0];
	LIGHT.yPos = LIGHT.proxy.position[1];
	LIGHT.zOffset = LIGHT.proxy.position[2];
}
);
	controller = lightFolder.addColor(LIGHT,'ambient').listen();
	controller.onChange(function(value){
	LIGHT.proxy.ambient.set(value);
	LIGHT.proxy.ambientHex = LIGHT.proxy.ambient.format();
}
);
	controller = lightFolder.addColor(LIGHT,'diffuse').listen();
	controller.onChange(function(value){
	console.log(value);
	LIGHT.proxy.diffuse.set(value);
	LIGHT.proxy.diffuseHex = LIGHT.proxy.ambient.format();
}
);
	controller = lightFolder.add(LIGHT,'count',1,7).listen();
	controller.step(1);
	controller.onChange(function(value){
	if (scene.lights.length !== value){
	// If the value is more then the number of lights,add lights,otherwise delete lights if (value > scene.lights.length){
	addLight();
}
else{
	trimLights(value);
}
}
}
);
	controller = lightFolder.add(LIGHT,'xPos',-mesh.geometry.width/2,mesh.geometry.width/2).listen();
	controller.step(1);
	controller.onChange(function(value){
	LIGHT.proxy.setPosition(value,LIGHT.proxy.position[1],LIGHT.proxy.position[2]);
}
);
	controller = lightFolder.add(LIGHT,'yPos',-mesh.geometry.height/2,mesh.geometry.height/2).listen();
	controller.step(1);
	controller.onChange(function(value){
	LIGHT.proxy.setPosition(LIGHT.proxy.position[0],value,LIGHT.proxy.position[2]);
}
);
	controller = lightFolder.add(LIGHT,'zOffset',0,1000).name('Distance').listen();
	controller.step(1);
	controller.onChange(function(value){
	LIGHT.proxy.setPosition(LIGHT.proxy.position[0],LIGHT.proxy.position[1],value);
}
);
	// Add Export Controls controller = exportFolder.add(EXPORT,'width',100,3000);
	controller.step(100);
	controller = exportFolder.add(EXPORT,'height',100,3000);
	controller.step(100);
	controller = exportFolder.add(EXPORT,'export').name('export big');
	controller = exportFolder.add(EXPORT,'exportCurrent').name('export this');
}
function toggleEl(id){
	var e = document.getElementById(id);
	if(e.style.display == 'block') e.style.display = 'none';
	else e.style.display = 'block';
}
//------------------------------ // Callbacks //------------------------------ function onWindowResize(event){
	resize(container.offsetWidth,container.offsetHeight);
	render();
}
function onMouseMove(event){
	if(LIGHT.pickedup){
	LIGHT.xPos = event.x - renderer.width/2;
	LIGHT.yPos = renderer.height/2 -event.y;
	LIGHT.proxy.setPosition(LIGHT.xPos,LIGHT.yPos,LIGHT.proxy.position[2]);
}
}
// Hide the controls completely on pressing H Mousetrap.bind('H',function(){
	toggleEl('controls')}
);
	// Add a light on ENTER key Mousetrap.bind('enter',function(){
	LIGHT.count++;
	addLight();
}
);
	// Pick up the light when a space is pressed Mousetrap.bind('space',function(){
	LIGHT.pickedup = !LIGHT.pickedup;
}
);
	// Let there be light! initialise();
}
)();
	

CSS代码(style.css):

body{font-family:"Vidaloka",serif;font-smoothing:antialiased;font-weight:normal;background:#151618;color:#FFF;margin:0;}
h1{text-transform:uppercase;letter-spacing:4px;font-weight:normal;font-size:16px;}
p{line-height:1.6em;text-align:center;font-size:14px;}
p + p{margin-top:1.0em;}
a{transition:color 0.2s ease-out;text-decoration:none;color:#FBB;}
a:hover{color:#444;}
.overlay{pointer-events:none;position:absolute;height:100%;width:100%;left:0;top:0;}
.container{position:absolute;height:100%;width:100%;}
.controls{font-smoothing:subpixel-antialiased;position:absolute;right:20px;top:0;}
.links{position:absolute;list-style:none;width:120px;bottom:40px;right:20px;padding:0;margin:0;}
.links p{font-smoothing:subpixel-antialiased;font-family:'Dosis',sans-serif;text-transform:uppercase;text-align:center;padding:0.25em 0;letter-spacing:2px;font-weight:200;font-size:10px;display:block;width:100%;opacity:0.6;color:#FFF;}
.links li{border-bottom:#222 1px solid;border-bottom:rgba(255,255,255,0.1) 1px solid;}
.links li a{transition:opacity 0.2s ease-out;font-smoothing:subpixel-antialiased;font-family:'Dosis',sans-serif;text-transform:uppercase;text-align:right;padding:0.25em 0;letter-spacing:2px;font-weight:200;font-size:12px;display:block;width:100%;opacity:0.4;color:#FFF;}
.links li a:hover{opacity:0.8;}
.links li .who:before{opacity:0.5;content:'@';float:left;}
.links li .source:before{opacity:0.5;content:'{}
';float:left;}
.links li .blog:before{opacity:0.5;content:'&';float:left;}
.hide{opacity:0;}
附件:下载该文件资源,减少时间成本(增值服务)
留言
该资源可下载
File Source
.rar
28.73 KB
Html JS 其它特效3
最新结算
HTM5 Canvas实现3D飞机飞行动画特效代码
类型: .rar 金额: CNY 2.31¥ 状态: 待结算 详细>
HTM5 Canvas实现3D飞机飞行动画特效代码
类型: .rar 金额: CNY 0.29¥ 状态: 待结算 详细>
jQuery图像缩放工具插件Zoomer特效代码
类型: .rar 金额: CNY 0.29¥ 状态: 待结算 详细>
jQuery图像缩放工具插件Zoomer特效代码
类型: .rar 金额: CNY 2.31¥ 状态: 待结算 详细>
Labelauty–jQuery单选框_复选框美化插件特效代码
类型: .rar 金额: CNY 2.31¥ 状态: 待结算 详细>
Labelauty–jQuery单选框_复选框美化插件特效代码
类型: .rar 金额: CNY 0.29¥ 状态: 待结算 详细>
jQuery网页版打砖块小游戏源码
类型: .rar 金额: CNY 0.29¥ 状态: 待结算 详细>
jQuery网页版打砖块小游戏源码
类型: .rar 金额: CNY 2.31¥ 状态: 待结算 详细>
jquery虚拟键盘中文打字效果js代码
类型: .rar 金额: CNY 2.31¥ 状态: 待结算 详细>
jquery虚拟键盘中文打字效果js代码
类型: .rar 金额: CNY 0.29¥ 状态: 待结算 详细>
我们力求给您提供有用的文章,再此基础上,会附加营收资源,不做任何广告,让平台可以更好发展 若您发现您的权利被侵害,或使用了您的版权,请发邮件联系 sunlifel@foxmail.com ggbig觉得 : 不提供源码的文章不是好文章
合作伙伴
联系我们
  • QQ:21499807
  • 邮箱:sunlifel@foxmail.com
  • QQ扫一扫加QQ
    QQ扫一扫
Copyright 2023-2024 ggbig.com·皖ICP备2023004211号-1
打赏文章