Browse Source

Merge branch 'master' of github.com:zz85/three.js

zz85 13 years ago
parent
commit
b3e0fdd4c4

+ 109 - 109
build/Three.js

@@ -291,114 +291,114 @@ g=h.value[g];h.array[f]=g.x;h.array[f+1]=g.y;h.array[f+2]=g.z;h.array[f+3]=g.w;f
 m,b)}if(q){i=0;for(k=q.length;i<k;i++){h=q[i];if(h.needsUpdate||c.sortParticles){j.bindBuffer(j.ARRAY_BUFFER,h.buffer);j.bufferData(j.ARRAY_BUFFER,h.array,b)}}}}function g(a,b){return b.z-a.z}function h(a,b){return b[1]-a[1]}function i(a,b,c){if(a.length)for(var d=0,e=a.length;d<e;d++){fa=T=null;M=ca=$=S=oa=Oa=Z=-1;la=true;a[d].render(b,c,ab,Ba);fa=T=null;M=ca=$=S=oa=Oa=Z=-1;la=true}}function k(a,b,c,d,e,f,g,h){var j,i,k,l;if(b){i=a.length-1;l=b=-1}else{i=0;b=a.length;l=1}for(var m=i;m!==b;m=m+l){j=
 a[m];if(j.render){i=j.object;k=j.buffer;if(h)j=h;else{j=j[c];if(!j)continue;g&&C.setBlending(j.blending,j.blendEquation,j.blendSrc,j.blendDst);C.setDepthTest(j.depthTest);C.setDepthWrite(j.depthWrite);t(j.polygonOffset,j.polygonOffsetFactor,j.polygonOffsetUnits)}C.setObjectFaces(i);k instanceof THREE.BufferGeometry?C.renderBufferDirect(d,e,f,j,k,i):C.renderBuffer(d,e,f,j,k,i)}}}function l(a,b,c,d,e,f,g){for(var h,j,i=0,k=a.length;i<k;i++){h=a[i];j=h.object;if(j.visible){if(g)h=g;else{h=h[b];if(!h)continue;
 f&&C.setBlending(h.blending,h.blendEquation,h.blendSrc,h.blendDst);C.setDepthTest(h.depthTest);C.setDepthWrite(h.depthWrite);t(h.polygonOffset,h.polygonOffsetFactor,h.polygonOffsetUnits)}C.renderImmediateObject(c,d,e,h,j)}}}function o(a,b,c){a.push({buffer:b,object:c,opaque:null,transparent:null})}function m(a){for(var b in a.attributes)if(a.attributes[b].needsUpdate)return true;return false}function p(a){for(var b in a.attributes)a.attributes[b].needsUpdate=false}function q(a,b){for(var c=a.length-
-1;c>=0;c--)a[c].object===b&&a.splice(c,1)}function n(a,b){for(var c=a.length-1;c>=0;c--)a[c]===b&&a.splice(c,1)}function r(a,b,c,d,e){if(d.needsUpdate){d.program&&C.deallocateMaterial(d);C.initMaterial(d,b,c,e);d.needsUpdate=false}if(d.morphTargets&&!e.__webglMorphTargetInfluences){e.__webglMorphTargetInfluences=new Float32Array(C.maxMorphTargets);for(var f=0,g=C.maxMorphTargets;f<g;f++)e.__webglMorphTargetInfluences[f]=0}var h=false,f=d.program,g=f.uniforms,i=d.uniforms;if(f!==T){j.useProgram(f);
-T=f;h=true}if(d.id!==M){M=d.id;h=true}if(h||a!==fa){j.uniformMatrix4fv(g.projectionMatrix,false,a._projectionMatrixArray);a!==fa&&(fa=a)}if(h){if(c&&d.fog){i.fogColor.value=c.color;if(c instanceof THREE.Fog){i.fogNear.value=c.near;i.fogFar.value=c.far}else if(c instanceof THREE.FogExp2)i.fogDensity.value=c.density}if(d instanceof THREE.MeshPhongMaterial||d instanceof THREE.MeshLambertMaterial||d.lights){if(la){for(var k,l=0,m=0,n=0,o,p,q,r=ob,t=r.directional.colors,v=r.directional.positions,u=r.point.colors,
-x=r.point.positions,y=r.point.distances,B=r.spot.colors,G=r.spot.positions,H=r.spot.distances,S=r.spot.directions,I=r.spot.angles,F=r.spot.exponents,L=0,Z=0,N=0,O=q=0,c=O=0,h=b.length;c<h;c++){k=b[c];if(!k.onlyShadow){o=k.color;p=k.intensity;q=k.distance;if(k instanceof THREE.AmbientLight)if(C.gammaInput){l=l+o.r*o.r;m=m+o.g*o.g;n=n+o.b*o.b}else{l=l+o.r;m=m+o.g;n=n+o.b}else if(k instanceof THREE.DirectionalLight){q=L*3;if(C.gammaInput){t[q]=o.r*o.r*p*p;t[q+1]=o.g*o.g*p*p;t[q+2]=o.b*o.b*p*p}else{t[q]=
-o.r*p;t[q+1]=o.g*p;t[q+2]=o.b*p}Da.copy(k.matrixWorld.getPosition());Da.subSelf(k.target.matrixWorld.getPosition());Da.normalize();v[q]=Da.x;v[q+1]=Da.y;v[q+2]=Da.z;L=L+1}else if(k instanceof THREE.PointLight){O=Z*3;if(C.gammaInput){u[O]=o.r*o.r*p*p;u[O+1]=o.g*o.g*p*p;u[O+2]=o.b*o.b*p*p}else{u[O]=o.r*p;u[O+1]=o.g*p;u[O+2]=o.b*p}o=k.matrixWorld.getPosition();x[O]=o.x;x[O+1]=o.y;x[O+2]=o.z;y[Z]=q;Z=Z+1}else if(k instanceof THREE.SpotLight){O=N*3;if(C.gammaInput){B[O]=o.r*o.r*p*p;B[O+1]=o.g*o.g*p*p;
-B[O+2]=o.b*o.b*p*p}else{B[O]=o.r*p;B[O+1]=o.g*p;B[O+2]=o.b*p}o=k.matrixWorld.getPosition();G[O]=o.x;G[O+1]=o.y;G[O+2]=o.z;H[N]=q;Da.copy(o);Da.subSelf(k.target.matrixWorld.getPosition());Da.normalize();S[O]=Da.x;S[O+1]=Da.y;S[O+2]=Da.z;I[N]=Math.cos(k.angle);F[N]=k.exponent;N=N+1}}}c=L*3;for(h=t.length;c<h;c++)t[c]=0;c=Z*3;for(h=u.length;c<h;c++)u[c]=0;c=N*3;for(h=B.length;c<h;c++)B[c]=0;r.directional.length=L;r.point.length=Z;r.spot.length=N;r.ambient[0]=l;r.ambient[1]=m;r.ambient[2]=n;la=false}c=
-ob;i.ambientLightColor.value=c.ambient;i.directionalLightColor.value=c.directional.colors;i.directionalLightDirection.value=c.directional.positions;i.pointLightColor.value=c.point.colors;i.pointLightPosition.value=c.point.positions;i.pointLightDistance.value=c.point.distances;i.spotLightColor.value=c.spot.colors;i.spotLightPosition.value=c.spot.positions;i.spotLightDistance.value=c.spot.distances;i.spotLightDirection.value=c.spot.directions;i.spotLightAngle.value=c.spot.angles;i.spotLightExponent.value=
-c.spot.exponents}if(d instanceof THREE.MeshBasicMaterial||d instanceof THREE.MeshLambertMaterial||d instanceof THREE.MeshPhongMaterial){i.opacity.value=d.opacity;C.gammaInput?i.diffuse.value.copyGammaToLinear(d.color):i.diffuse.value=d.color;(i.map.texture=d.map)&&i.offsetRepeat.value.set(d.map.offset.x,d.map.offset.y,d.map.repeat.x,d.map.repeat.y);i.lightMap.texture=d.lightMap;i.envMap.texture=d.envMap;i.flipEnvMap.value=d.envMap instanceof THREE.WebGLRenderTargetCube?1:-1;i.reflectivity.value=d.reflectivity;
-i.refractionRatio.value=d.refractionRatio;i.combine.value=d.combine;i.useRefract.value=d.envMap&&d.envMap.mapping instanceof THREE.CubeRefractionMapping}if(d instanceof THREE.LineBasicMaterial){i.diffuse.value=d.color;i.opacity.value=d.opacity}else if(d instanceof THREE.ParticleBasicMaterial){i.psColor.value=d.color;i.opacity.value=d.opacity;i.size.value=d.size;i.scale.value=A.height/2;i.map.texture=d.map}else if(d instanceof THREE.MeshPhongMaterial){i.shininess.value=d.shininess;if(C.gammaInput){i.ambient.value.copyGammaToLinear(d.ambient);
-i.emissive.value.copyGammaToLinear(d.emissive);i.specular.value.copyGammaToLinear(d.specular)}else{i.ambient.value=d.ambient;i.emissive.value=d.emissive;i.specular.value=d.specular}d.wrapAround&&i.wrapRGB.value.copy(d.wrapRGB)}else if(d instanceof THREE.MeshLambertMaterial){if(C.gammaInput){i.ambient.value.copyGammaToLinear(d.ambient);i.emissive.value.copyGammaToLinear(d.emissive)}else{i.ambient.value=d.ambient;i.emissive.value=d.emissive}d.wrapAround&&i.wrapRGB.value.copy(d.wrapRGB)}else if(d instanceof
-THREE.MeshDepthMaterial){i.mNear.value=a.near;i.mFar.value=a.far;i.opacity.value=d.opacity}else if(d instanceof THREE.MeshNormalMaterial)i.opacity.value=d.opacity;if(e.receiveShadow&&!d._shadowPass&&i.shadowMatrix){h=c=0;for(k=b.length;h<k;h++){l=b[h];if(l.castShadow&&(l instanceof THREE.SpotLight||l instanceof THREE.DirectionalLight&&!l.shadowCascade)){i.shadowMap.texture[c]=l.shadowMap;i.shadowMapSize.value[c]=l.shadowMapSize;i.shadowMatrix.value[c]=l.shadowMatrix;i.shadowDarkness.value[c]=l.shadowDarkness;
-i.shadowBias.value[c]=l.shadowBias;c++}}}b=d.uniformsList;i=0;for(c=b.length;i<c;i++)if(l=f.uniforms[b[i][1]]){h=b[i][0];m=h.type;k=h.value;switch(m){case "i":j.uniform1i(l,k);break;case "f":j.uniform1f(l,k);break;case "v2":j.uniform2f(l,k.x,k.y);break;case "v3":j.uniform3f(l,k.x,k.y,k.z);break;case "v4":j.uniform4f(l,k.x,k.y,k.z,k.w);break;case "c":j.uniform3f(l,k.r,k.g,k.b);break;case "fv1":j.uniform1fv(l,k);break;case "fv":j.uniform3fv(l,k);break;case "v2v":if(!h._array)h._array=new Float32Array(2*
-k.length);m=0;for(n=k.length;m<n;m++){r=m*2;h._array[r]=k[m].x;h._array[r+1]=k[m].y}j.uniform2fv(l,h._array);break;case "v3v":if(!h._array)h._array=new Float32Array(3*k.length);m=0;for(n=k.length;m<n;m++){r=m*3;h._array[r]=k[m].x;h._array[r+1]=k[m].y;h._array[r+2]=k[m].z}j.uniform3fv(l,h._array);break;case "v4v":if(!h._array)h._array=new Float32Array(4*k.length);m=0;for(n=k.length;m<n;m++){r=m*4;h._array[r]=k[m].x;h._array[r+1]=k[m].y;h._array[r+2]=k[m].z;h._array[r+3]=k[m].w}j.uniform4fv(l,h._array);
-break;case "m4":if(!h._array)h._array=new Float32Array(16);k.flattenToArray(h._array);j.uniformMatrix4fv(l,false,h._array);break;case "m4v":if(!h._array)h._array=new Float32Array(16*k.length);m=0;for(n=k.length;m<n;m++)k[m].flattenToArrayOffset(h._array,m*16);j.uniformMatrix4fv(l,false,h._array);break;case "t":j.uniform1i(l,k);l=h.texture;if(!l)continue;if(l.image instanceof Array&&l.image.length===6){h=l;if(h.image.length===6)if(h.needsUpdate){if(!h.image.__webglTextureCube)h.image.__webglTextureCube=
-j.createTexture();j.activeTexture(j.TEXTURE0+k);j.bindTexture(j.TEXTURE_CUBE_MAP,h.image.__webglTextureCube);k=[];for(l=0;l<6;l++){m=k;n=l;if(C.autoScaleCubemaps){r=h.image[l];v=ac;if(!(r.width<=v&&r.height<=v)){u=Math.max(r.width,r.height);t=Math.floor(r.width*v/u);v=Math.floor(r.height*v/u);u=document.createElement("canvas");u.width=t;u.height=v;u.getContext("2d").drawImage(r,0,0,r.width,r.height,0,0,t,v);r=u}}else r=h.image[l];m[n]=r}l=k[0];m=(l.width&l.width-1)===0&&(l.height&l.height-1)===0;
-n=D(h.format);r=D(h.type);s(j.TEXTURE_CUBE_MAP,h,m);for(l=0;l<6;l++)j.texImage2D(j.TEXTURE_CUBE_MAP_POSITIVE_X+l,0,n,n,r,k[l]);h.generateMipmaps&&m&&j.generateMipmap(j.TEXTURE_CUBE_MAP);h.needsUpdate=false;if(h.onUpdate)h.onUpdate()}else{j.activeTexture(j.TEXTURE0+k);j.bindTexture(j.TEXTURE_CUBE_MAP,h.image.__webglTextureCube)}}else if(l instanceof THREE.WebGLRenderTargetCube){h=l;j.activeTexture(j.TEXTURE0+k);j.bindTexture(j.TEXTURE_CUBE_MAP,h.__webglTexture)}else C.setTexture(l,k);break;case "tv":if(!h._array){h._array=
-[];m=0;for(n=h.texture.length;m<n;m++)h._array[m]=k+m}j.uniform1iv(l,h._array);m=0;for(n=h.texture.length;m<n;m++)(l=h.texture[m])&&C.setTexture(l,h._array[m])}}if((d instanceof THREE.ShaderMaterial||d instanceof THREE.MeshPhongMaterial||d.envMap)&&g.cameraPosition!==null){b=a.matrixWorld.getPosition();j.uniform3f(g.cameraPosition,b.x,b.y,b.z)}(d instanceof THREE.MeshPhongMaterial||d instanceof THREE.MeshLambertMaterial||d instanceof THREE.ShaderMaterial||d.skinning)&&g.viewMatrix!==null&&j.uniformMatrix4fv(g.viewMatrix,
-false,a._viewMatrixArray);d.skinning&&j.uniformMatrix4fv(g.boneGlobalMatrices,false,e.boneMatrices)}j.uniformMatrix4fv(g.modelViewMatrix,false,e._modelViewMatrix.elements);g.normalMatrix&&j.uniformMatrix3fv(g.normalMatrix,false,e._normalMatrix.elements);g.objectMatrix!==null&&j.uniformMatrix4fv(g.objectMatrix,false,e.matrixWorld.elements);return f}function u(a,b){a._modelViewMatrix.multiply(b.matrixWorldInverse,a.matrixWorld);a._normalMatrix.getInverse(a._modelViewMatrix);a._normalMatrix.transpose()}
-function t(a,b,c){if(Ta!==a){a?j.enable(j.POLYGON_OFFSET_FILL):j.disable(j.POLYGON_OFFSET_FILL);Ta=a}if(a&&(eb!==b||fb!==c)){j.polygonOffset(b,c);eb=b;fb=c}}function y(a,b){var c;a==="fragment"?c=j.createShader(j.FRAGMENT_SHADER):a==="vertex"&&(c=j.createShader(j.VERTEX_SHADER));j.shaderSource(c,b);j.compileShader(c);if(!j.getShaderParameter(c,j.COMPILE_STATUS)){console.error(j.getShaderInfoLog(c));console.error(b);return null}return c}function s(a,b,c){if(c){j.texParameteri(a,j.TEXTURE_WRAP_S,D(b.wrapS));
-j.texParameteri(a,j.TEXTURE_WRAP_T,D(b.wrapT));j.texParameteri(a,j.TEXTURE_MAG_FILTER,D(b.magFilter));j.texParameteri(a,j.TEXTURE_MIN_FILTER,D(b.minFilter))}else{j.texParameteri(a,j.TEXTURE_WRAP_S,j.CLAMP_TO_EDGE);j.texParameteri(a,j.TEXTURE_WRAP_T,j.CLAMP_TO_EDGE);j.texParameteri(a,j.TEXTURE_MAG_FILTER,H(b.magFilter));j.texParameteri(a,j.TEXTURE_MIN_FILTER,H(b.minFilter))}}function x(a,b){j.bindRenderbuffer(j.RENDERBUFFER,a);if(b.depthBuffer&&!b.stencilBuffer){j.renderbufferStorage(j.RENDERBUFFER,
-j.DEPTH_COMPONENT16,b.width,b.height);j.framebufferRenderbuffer(j.FRAMEBUFFER,j.DEPTH_ATTACHMENT,j.RENDERBUFFER,a)}else if(b.depthBuffer&&b.stencilBuffer){j.renderbufferStorage(j.RENDERBUFFER,j.DEPTH_STENCIL,b.width,b.height);j.framebufferRenderbuffer(j.FRAMEBUFFER,j.DEPTH_STENCIL_ATTACHMENT,j.RENDERBUFFER,a)}else j.renderbufferStorage(j.RENDERBUFFER,j.RGBA4,b.width,b.height)}function H(a){switch(a){case THREE.NearestFilter:case THREE.NearestMipMapNearestFilter:case THREE.NearestMipMapLinearFilter:return j.NEAREST;
-default:return j.LINEAR}}function D(a){switch(a){case THREE.RepeatWrapping:return j.REPEAT;case THREE.ClampToEdgeWrapping:return j.CLAMP_TO_EDGE;case THREE.MirroredRepeatWrapping:return j.MIRRORED_REPEAT;case THREE.NearestFilter:return j.NEAREST;case THREE.NearestMipMapNearestFilter:return j.NEAREST_MIPMAP_NEAREST;case THREE.NearestMipMapLinearFilter:return j.NEAREST_MIPMAP_LINEAR;case THREE.LinearFilter:return j.LINEAR;case THREE.LinearMipMapNearestFilter:return j.LINEAR_MIPMAP_NEAREST;case THREE.LinearMipMapLinearFilter:return j.LINEAR_MIPMAP_LINEAR;
-case THREE.UnsignedByteType:return j.UNSIGNED_BYTE;case THREE.UnsignedShort4444Type:return j.UNSIGNED_SHORT_4_4_4_4;case THREE.UnsignedShort5551Type:return j.UNSIGNED_SHORT_5_5_5_1;case THREE.UnsignedShort565Type:return j.UNSIGNED_SHORT_5_6_5;case THREE.ByteType:return j.BYTE;case THREE.ShortType:return j.SHORT;case THREE.UnsignedShortType:return j.UNSIGNED_SHORT;case THREE.IntType:return j.INT;case THREE.UnsignedIntType:return j.UNSIGNED_INT;case THREE.FloatType:return j.FLOAT;case THREE.AlphaFormat:return j.ALPHA;
-case THREE.RGBFormat:return j.RGB;case THREE.RGBAFormat:return j.RGBA;case THREE.LuminanceFormat:return j.LUMINANCE;case THREE.LuminanceAlphaFormat:return j.LUMINANCE_ALPHA;case THREE.AddEquation:return j.FUNC_ADD;case THREE.SubtractEquation:return j.FUNC_SUBTRACT;case THREE.ReverseSubtractEquation:return j.FUNC_REVERSE_SUBTRACT;case THREE.ZeroFactor:return j.ZERO;case THREE.OneFactor:return j.ONE;case THREE.SrcColorFactor:return j.SRC_COLOR;case THREE.OneMinusSrcColorFactor:return j.ONE_MINUS_SRC_COLOR;
-case THREE.SrcAlphaFactor:return j.SRC_ALPHA;case THREE.OneMinusSrcAlphaFactor:return j.ONE_MINUS_SRC_ALPHA;case THREE.DstAlphaFactor:return j.DST_ALPHA;case THREE.OneMinusDstAlphaFactor:return j.ONE_MINUS_DST_ALPHA;case THREE.DstColorFactor:return j.DST_COLOR;case THREE.OneMinusDstColorFactor:return j.ONE_MINUS_DST_COLOR;case THREE.SrcAlphaSaturateFactor:return j.SRC_ALPHA_SATURATE}return 0}console.log("THREE.WebGLRenderer",THREE.REVISION);var a=a||{},A=a.canvas!==void 0?a.canvas:document.createElement("canvas"),
-v=a.precision!==void 0?a.precision:"highp",G=a.alpha!==void 0?a.alpha:true,I=a.premultipliedAlpha!==void 0?a.premultipliedAlpha:true,N=a.antialias!==void 0?a.antialias:false,R=a.stencil!==void 0?a.stencil:true,Y=a.preserveDrawingBuffer!==void 0?a.preserveDrawingBuffer:false,B=a.clearColor!==void 0?new THREE.Color(a.clearColor):new THREE.Color(0),F=a.clearAlpha!==void 0?a.clearAlpha:0,Q=a.maxLights!==void 0?a.maxLights:4;this.domElement=A;this.context=null;this.autoUpdateScene=this.autoUpdateObjects=
-this.sortObjects=this.autoClearStencil=this.autoClearDepth=this.autoClearColor=this.autoClear=true;this.shadowMapEnabled=this.physicallyBasedShading=this.gammaOutput=this.gammaInput=false;this.shadowMapCullFrontFaces=this.shadowMapSoft=this.shadowMapAutoUpdate=true;this.shadowMapCascade=this.shadowMapDebug=false;this.maxMorphTargets=8;this.maxMorphNormals=4;this.autoScaleCubemaps=true;this.renderPluginsPre=[];this.renderPluginsPost=[];this.info={memory:{programs:0,geometries:0,textures:0},render:{calls:0,
-vertices:0,faces:0,points:0}};var C=this,j,P=[],L=0,T=null,aa=null,M=-1,ca=null,fa=null,O=0,S=-1,$=-1,Z=-1,ha=-1,Sa=-1,Ma=-1,Oa=-1,oa=-1,Ta=null,eb=null,fb=null,Za=null,Lb=0,mb=0,jb=0,nb=0,ab=0,Ba=0,ya=new THREE.Frustum,gb=new THREE.Matrix4,wa=new THREE.Matrix4,Pa=new THREE.Vector4,Da=new THREE.Vector3,la=true,ob={ambient:[0,0,0],directional:{length:0,colors:[],positions:[]},point:{length:0,colors:[],positions:[],distances:[]},spot:{length:0,colors:[],positions:[],distances:[],directions:[],angles:[],
-exponents:[]}};j=function(){var a;try{if(!(a=A.getContext("experimental-webgl",{alpha:G,premultipliedAlpha:I,antialias:N,stencil:R,preserveDrawingBuffer:Y})))throw"Error creating WebGL context.";}catch(b){console.error(b)}a.getExtension("OES_texture_float")||console.log("THREE.WebGLRenderer: Float textures not supported.");return a}();j.clearColor(0,0,0,1);j.clearDepth(1);j.clearStencil(0);j.enable(j.DEPTH_TEST);j.depthFunc(j.LEQUAL);j.frontFace(j.CCW);j.cullFace(j.BACK);j.enable(j.CULL_FACE);j.enable(j.BLEND);
-j.blendEquation(j.FUNC_ADD);j.blendFunc(j.SRC_ALPHA,j.ONE_MINUS_SRC_ALPHA);j.clearColor(B.r,B.g,B.b,F);this.context=j;var $a=j.getParameter(j.MAX_VERTEX_TEXTURE_IMAGE_UNITS);j.getParameter(j.MAX_TEXTURE_SIZE);var ac=j.getParameter(j.MAX_CUBE_MAP_TEXTURE_SIZE);this.getContext=function(){return j};this.supportsVertexTextures=function(){return $a>0};this.setSize=function(a,b){A.width=a;A.height=b;this.setViewport(0,0,A.width,A.height)};this.setViewport=function(a,b,c,d){Lb=a;mb=b;jb=c;nb=d;j.viewport(Lb,
-mb,jb,nb)};this.setScissor=function(a,b,c,d){j.scissor(a,b,c,d)};this.enableScissorTest=function(a){a?j.enable(j.SCISSOR_TEST):j.disable(j.SCISSOR_TEST)};this.setClearColorHex=function(a,b){B.setHex(a);F=b;j.clearColor(B.r,B.g,B.b,F)};this.setClearColor=function(a,b){B.copy(a);F=b;j.clearColor(B.r,B.g,B.b,F)};this.getClearColor=function(){return B};this.getClearAlpha=function(){return F};this.clear=function(a,b,c){var d=0;if(a===void 0||a)d=d|j.COLOR_BUFFER_BIT;if(b===void 0||b)d=d|j.DEPTH_BUFFER_BIT;
-if(c===void 0||c)d=d|j.STENCIL_BUFFER_BIT;j.clear(d)};this.clearTarget=function(a,b,c,d){this.setRenderTarget(a);this.clear(b,c,d)};this.addPostPlugin=function(a){a.init(this);this.renderPluginsPost.push(a)};this.addPrePlugin=function(a){a.init(this);this.renderPluginsPre.push(a)};this.deallocateObject=function(a){if(a.__webglInit){a.__webglInit=false;delete a._modelViewMatrix;delete a._normalMatrix;delete a._normalMatrixArray;delete a._modelViewMatrixArray;delete a._objectMatrixArray;if(a instanceof
-THREE.Mesh)for(var b in a.geometry.geometryGroups){var c=a.geometry.geometryGroups[b];j.deleteBuffer(c.__webglVertexBuffer);j.deleteBuffer(c.__webglNormalBuffer);j.deleteBuffer(c.__webglTangentBuffer);j.deleteBuffer(c.__webglColorBuffer);j.deleteBuffer(c.__webglUVBuffer);j.deleteBuffer(c.__webglUV2Buffer);j.deleteBuffer(c.__webglSkinVertexABuffer);j.deleteBuffer(c.__webglSkinVertexBBuffer);j.deleteBuffer(c.__webglSkinIndicesBuffer);j.deleteBuffer(c.__webglSkinWeightsBuffer);j.deleteBuffer(c.__webglFaceBuffer);
-j.deleteBuffer(c.__webglLineBuffer);var d=void 0,e=void 0;if(c.numMorphTargets){d=0;for(e=c.numMorphTargets;d<e;d++)j.deleteBuffer(c.__webglMorphTargetsBuffers[d])}if(c.numMorphNormals){d=0;for(e=c.numMorphNormals;d<e;d++)j.deleteBuffer(c.__webglMorphNormalsBuffers[d])}if(c.__webglCustomAttributesList){d=void 0;for(d in c.__webglCustomAttributesList)j.deleteBuffer(c.__webglCustomAttributesList[d].buffer)}C.info.memory.geometries--}else if(a instanceof THREE.Ribbon){a=a.geometry;j.deleteBuffer(a.__webglVertexBuffer);
-j.deleteBuffer(a.__webglColorBuffer);C.info.memory.geometries--}else if(a instanceof THREE.Line){a=a.geometry;j.deleteBuffer(a.__webglVertexBuffer);j.deleteBuffer(a.__webglColorBuffer);C.info.memory.geometries--}else if(a instanceof THREE.ParticleSystem){a=a.geometry;j.deleteBuffer(a.__webglVertexBuffer);j.deleteBuffer(a.__webglColorBuffer);C.info.memory.geometries--}}};this.deallocateTexture=function(a){if(a.__webglInit){a.__webglInit=false;j.deleteTexture(a.__webglTexture);C.info.memory.textures--}};
-this.deallocateRenderTarget=function(a){if(a&&a.__webglTexture){j.deleteTexture(a.__webglTexture);if(a instanceof THREE.WebGLRenderTargetCube)for(var b=0;b<6;b++){j.deleteFramebuffer(a.__webglFramebuffer[b]);j.deleteRenderbuffer(a.__webglRenderbuffer[b])}else{j.deleteFramebuffer(a.__webglFramebuffer);j.deleteRenderbuffer(a.__webglRenderbuffer)}}};this.deallocateMaterial=function(a){var b=a.program;if(b){a.program=void 0;var c,d,e=false,a=0;for(c=P.length;a<c;a++){d=P[a];if(d.program===b){d.usedTimes--;
-d.usedTimes===0&&(e=true);break}}if(e){e=[];a=0;for(c=P.length;a<c;a++){d=P[a];d.program!==b&&e.push(d)}P=e;j.deleteProgram(b);C.info.memory.programs--}}};this.updateShadowMap=function(a,b){T=null;M=ca=oa=Oa=Z=-1;la=true;$=S=-1;this.shadowMapPlugin.update(a,b)};this.renderBufferImmediate=function(a,b,c){if(a.hasPos&&!a.__webglVertexBuffer)a.__webglVertexBuffer=j.createBuffer();if(a.hasNormal&&!a.__webglNormalBuffer)a.__webglNormalBuffer=j.createBuffer();if(a.hasUv&&!a.__webglUvBuffer)a.__webglUvBuffer=
-j.createBuffer();if(a.hasPos){j.bindBuffer(j.ARRAY_BUFFER,a.__webglVertexBuffer);j.bufferData(j.ARRAY_BUFFER,a.positionArray,j.DYNAMIC_DRAW);j.enableVertexAttribArray(b.attributes.position);j.vertexAttribPointer(b.attributes.position,3,j.FLOAT,false,0,0)}if(a.hasNormal){j.bindBuffer(j.ARRAY_BUFFER,a.__webglNormalBuffer);if(c===THREE.FlatShading){var d,e,f,g,h,i,k,l,m,n,o=a.count*3;for(n=0;n<o;n=n+9){c=a.normalArray;d=c[n];e=c[n+1];f=c[n+2];g=c[n+3];i=c[n+4];l=c[n+5];h=c[n+6];k=c[n+7];m=c[n+8];d=(d+
-g+h)/3;e=(e+i+k)/3;f=(f+l+m)/3;c[n]=d;c[n+1]=e;c[n+2]=f;c[n+3]=d;c[n+4]=e;c[n+5]=f;c[n+6]=d;c[n+7]=e;c[n+8]=f}}j.bufferData(j.ARRAY_BUFFER,a.normalArray,j.DYNAMIC_DRAW);j.enableVertexAttribArray(b.attributes.normal);j.vertexAttribPointer(b.attributes.normal,3,j.FLOAT,false,0,0)}if(a.hasUv){j.bindBuffer(j.ARRAY_BUFFER,a.__webglUvBuffer);j.bufferData(j.ARRAY_BUFFER,a.uvArray,j.DYNAMIC_DRAW);j.enableVertexAttribArray(b.attributes.uv);j.vertexAttribPointer(b.attributes.uv,2,j.FLOAT,false,0,0)}j.drawArrays(j.TRIANGLES,
-0,a.count);a.count=0};this.renderBufferDirect=function(a,b,c,d,e,f){if(d.visible!==false){c=r(a,b,c,d,f);a=c.attributes;b=false;d=e.id*16777215+c.id*2+(d.wireframe?1:0);if(d!==ca){ca=d;b=true}if(f instanceof THREE.Mesh){f=e.offsets;d=0;for(c=f.length;d<c;++d){if(b){j.bindBuffer(j.ARRAY_BUFFER,e.vertexPositionBuffer);j.vertexAttribPointer(a.position,e.vertexPositionBuffer.itemSize,j.FLOAT,false,0,f[d].index*12);if(a.normal>=0&&e.vertexNormalBuffer){j.bindBuffer(j.ARRAY_BUFFER,e.vertexNormalBuffer);
-j.vertexAttribPointer(a.normal,e.vertexNormalBuffer.itemSize,j.FLOAT,false,0,f[d].index*12)}if(a.uv>=0&&e.vertexUvBuffer)if(e.vertexUvBuffer){j.bindBuffer(j.ARRAY_BUFFER,e.vertexUvBuffer);j.vertexAttribPointer(a.uv,e.vertexUvBuffer.itemSize,j.FLOAT,false,0,f[d].index*8);j.enableVertexAttribArray(a.uv)}else j.disableVertexAttribArray(a.uv);if(a.color>=0&&e.vertexColorBuffer){j.bindBuffer(j.ARRAY_BUFFER,e.vertexColorBuffer);j.vertexAttribPointer(a.color,e.vertexColorBuffer.itemSize,j.FLOAT,false,0,
-f[d].index*16)}j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,e.vertexIndexBuffer)}j.drawElements(j.TRIANGLES,f[d].count,j.UNSIGNED_SHORT,f[d].start*2);C.info.render.calls++;C.info.render.vertices=C.info.render.vertices+f[d].count;C.info.render.faces=C.info.render.faces+f[d].count/3}}}};this.renderBuffer=function(a,b,c,d,e,f){if(d.visible!==false){var g,i,c=r(a,b,c,d,f),b=c.attributes,a=false,c=e.id*16777215+c.id*2+(d.wireframe?1:0);if(c!==ca){ca=c;a=true}if(!d.morphTargets&&b.position>=0){if(a){j.bindBuffer(j.ARRAY_BUFFER,
-e.__webglVertexBuffer);j.vertexAttribPointer(b.position,3,j.FLOAT,false,0,0)}}else if(f.morphTargetBase){c=d.program.attributes;if(f.morphTargetBase!==-1){j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[f.morphTargetBase]);j.vertexAttribPointer(c.position,3,j.FLOAT,false,0,0)}else if(c.position>=0){j.bindBuffer(j.ARRAY_BUFFER,e.__webglVertexBuffer);j.vertexAttribPointer(c.position,3,j.FLOAT,false,0,0)}if(f.morphTargetForcedOrder.length){var k=0;i=f.morphTargetForcedOrder;for(g=f.morphTargetInfluences;k<
-d.numSupportedMorphTargets&&k<i.length;){j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[i[k]]);j.vertexAttribPointer(c["morphTarget"+k],3,j.FLOAT,false,0,0);if(d.morphNormals){j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphNormalsBuffers[i[k]]);j.vertexAttribPointer(c["morphNormal"+k],3,j.FLOAT,false,0,0)}f.__webglMorphTargetInfluences[k]=g[i[k]];k++}}else{i=[];g=f.morphTargetInfluences;var l,m=g.length;for(l=0;l<m;l++){k=g[l];k>0&&i.push([l,k])}if(i.length>d.numSupportedMorphTargets){i.sort(h);
-i.length=d.numSupportedMorphTargets}else i.length>d.numSupportedMorphNormals?i.sort(h):i.length===0&&i.push([0,0]);for(k=0;k<d.numSupportedMorphTargets;){if(i[k]){l=i[k][0];j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[l]);j.vertexAttribPointer(c["morphTarget"+k],3,j.FLOAT,false,0,0);if(d.morphNormals){j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphNormalsBuffers[l]);j.vertexAttribPointer(c["morphNormal"+k],3,j.FLOAT,false,0,0)}f.__webglMorphTargetInfluences[k]=g[l]}else{j.vertexAttribPointer(c["morphTarget"+
-k],3,j.FLOAT,false,0,0);d.morphNormals&&j.vertexAttribPointer(c["morphNormal"+k],3,j.FLOAT,false,0,0);f.__webglMorphTargetInfluences[k]=0}k++}}d.program.uniforms.morphTargetInfluences!==null&&j.uniform1fv(d.program.uniforms.morphTargetInfluences,f.__webglMorphTargetInfluences)}if(a){if(e.__webglCustomAttributesList){g=0;for(i=e.__webglCustomAttributesList.length;g<i;g++){c=e.__webglCustomAttributesList[g];if(b[c.buffer.belongsToAttribute]>=0){j.bindBuffer(j.ARRAY_BUFFER,c.buffer);j.vertexAttribPointer(b[c.buffer.belongsToAttribute],
-c.size,j.FLOAT,false,0,0)}}}if(b.color>=0){j.bindBuffer(j.ARRAY_BUFFER,e.__webglColorBuffer);j.vertexAttribPointer(b.color,3,j.FLOAT,false,0,0)}if(b.normal>=0){j.bindBuffer(j.ARRAY_BUFFER,e.__webglNormalBuffer);j.vertexAttribPointer(b.normal,3,j.FLOAT,false,0,0)}if(b.tangent>=0){j.bindBuffer(j.ARRAY_BUFFER,e.__webglTangentBuffer);j.vertexAttribPointer(b.tangent,4,j.FLOAT,false,0,0)}if(b.uv>=0)if(e.__webglUVBuffer){j.bindBuffer(j.ARRAY_BUFFER,e.__webglUVBuffer);j.vertexAttribPointer(b.uv,2,j.FLOAT,
-false,0,0);j.enableVertexAttribArray(b.uv)}else j.disableVertexAttribArray(b.uv);if(b.uv2>=0)if(e.__webglUV2Buffer){j.bindBuffer(j.ARRAY_BUFFER,e.__webglUV2Buffer);j.vertexAttribPointer(b.uv2,2,j.FLOAT,false,0,0);j.enableVertexAttribArray(b.uv2)}else j.disableVertexAttribArray(b.uv2);if(d.skinning&&b.skinVertexA>=0&&b.skinVertexB>=0&&b.skinIndex>=0&&b.skinWeight>=0){j.bindBuffer(j.ARRAY_BUFFER,e.__webglSkinVertexABuffer);j.vertexAttribPointer(b.skinVertexA,4,j.FLOAT,false,0,0);j.bindBuffer(j.ARRAY_BUFFER,
-e.__webglSkinVertexBBuffer);j.vertexAttribPointer(b.skinVertexB,4,j.FLOAT,false,0,0);j.bindBuffer(j.ARRAY_BUFFER,e.__webglSkinIndicesBuffer);j.vertexAttribPointer(b.skinIndex,4,j.FLOAT,false,0,0);j.bindBuffer(j.ARRAY_BUFFER,e.__webglSkinWeightsBuffer);j.vertexAttribPointer(b.skinWeight,4,j.FLOAT,false,0,0)}}if(f instanceof THREE.Mesh){if(d.wireframe){d=d.wireframeLinewidth;if(d!==Za){j.lineWidth(d);Za=d}a&&j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,e.__webglLineBuffer);j.drawElements(j.LINES,e.__webglLineCount,
-j.UNSIGNED_SHORT,0)}else{a&&j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,e.__webglFaceBuffer);j.drawElements(j.TRIANGLES,e.__webglFaceCount,j.UNSIGNED_SHORT,0)}C.info.render.calls++;C.info.render.vertices=C.info.render.vertices+e.__webglFaceCount;C.info.render.faces=C.info.render.faces+e.__webglFaceCount/3}else if(f instanceof THREE.Line){f=f.type===THREE.LineStrip?j.LINE_STRIP:j.LINES;d=d.linewidth;if(d!==Za){j.lineWidth(d);Za=d}j.drawArrays(f,0,e.__webglLineCount);C.info.render.calls++}else if(f instanceof
-THREE.ParticleSystem){j.drawArrays(j.POINTS,0,e.__webglParticleCount);C.info.render.calls++;C.info.render.points=C.info.render.points+e.__webglParticleCount}else if(f instanceof THREE.Ribbon){j.drawArrays(j.TRIANGLE_STRIP,0,e.__webglVertexCount);C.info.render.calls++}}};this.render=function(a,b,c,d){var e,f,h,m,n=a.__lights,o=a.fog;M=-1;la=true;if(b.parent===void 0){console.warn("DEPRECATED: Camera hasn't been added to a Scene. Adding it...");a.add(b)}this.autoUpdateScene&&a.updateMatrixWorld();if(!b._viewMatrixArray)b._viewMatrixArray=
-new Float32Array(16);if(!b._projectionMatrixArray)b._projectionMatrixArray=new Float32Array(16);b.matrixWorldInverse.getInverse(b.matrixWorld);b.matrixWorldInverse.flattenToArray(b._viewMatrixArray);b.projectionMatrix.flattenToArray(b._projectionMatrixArray);gb.multiply(b.projectionMatrix,b.matrixWorldInverse);ya.setFromMatrix(gb);this.autoUpdateObjects&&this.initWebGLObjects(a);i(this.renderPluginsPre,a,b);C.info.render.calls=0;C.info.render.vertices=0;C.info.render.faces=0;C.info.render.points=
-0;this.setRenderTarget(c);(this.autoClear||d)&&this.clear(this.autoClearColor,this.autoClearDepth,this.autoClearStencil);m=a.__webglObjects;d=0;for(e=m.length;d<e;d++){f=m[d];h=f.object;f.render=false;if(h.visible&&(!(h instanceof THREE.Mesh||h instanceof THREE.ParticleSystem)||!h.frustumCulled||ya.contains(h))){u(h,b);var p=f,q=p.object,r=p.buffer,s=void 0,s=s=void 0,s=q.material;if(s instanceof THREE.MeshFaceMaterial){s=r.materialIndex;if(s>=0){s=q.geometry.materials[s];if(s.transparent){p.transparent=
-s;p.opaque=null}else{p.opaque=s;p.transparent=null}}}else if(s)if(s.transparent){p.transparent=s;p.opaque=null}else{p.opaque=s;p.transparent=null}f.render=true;if(this.sortObjects)if(h.renderDepth)f.z=h.renderDepth;else{Pa.copy(h.matrixWorld.getPosition());gb.multiplyVector3(Pa);f.z=Pa.z}}}this.sortObjects&&m.sort(g);m=a.__webglObjectsImmediate;d=0;for(e=m.length;d<e;d++){f=m[d];h=f.object;if(h.visible){u(h,b);h=f.object.material;if(h.transparent){f.transparent=h;f.opaque=null}else{f.opaque=h;f.transparent=
-null}}}if(a.overrideMaterial){d=a.overrideMaterial;this.setBlending(d.blending,d.blendEquation,d.blendSrc,d.blendDst);this.setDepthTest(d.depthTest);this.setDepthWrite(d.depthWrite);t(d.polygonOffset,d.polygonOffsetFactor,d.polygonOffsetUnits);k(a.__webglObjects,false,"",b,n,o,true,d);l(a.__webglObjectsImmediate,"",b,n,o,false,d)}else{this.setBlending(THREE.NormalBlending);k(a.__webglObjects,true,"opaque",b,n,o,false);l(a.__webglObjectsImmediate,"opaque",b,n,o,false);k(a.__webglObjects,false,"transparent",
-b,n,o,true);l(a.__webglObjectsImmediate,"transparent",b,n,o,true)}i(this.renderPluginsPost,a,b);if(c&&c.generateMipmaps&&c.minFilter!==THREE.NearestFilter&&c.minFilter!==THREE.LinearFilter)if(c instanceof THREE.WebGLRenderTargetCube){j.bindTexture(j.TEXTURE_CUBE_MAP,c.__webglTexture);j.generateMipmap(j.TEXTURE_CUBE_MAP);j.bindTexture(j.TEXTURE_CUBE_MAP,null)}else{j.bindTexture(j.TEXTURE_2D,c.__webglTexture);j.generateMipmap(j.TEXTURE_2D);j.bindTexture(j.TEXTURE_2D,null)}this.setDepthTest(true);this.setDepthWrite(true)};
-this.renderImmediateObject=function(a,b,c,d,e){var f=r(a,b,c,d,e);ca=-1;C.setObjectFaces(e);e.immediateRenderCallback?e.immediateRenderCallback(f,j,ya):e.render(function(a){C.renderBufferImmediate(a,f,d.shading)})};this.initWebGLObjects=function(a){if(!a.__webglObjects){a.__webglObjects=[];a.__webglObjectsImmediate=[];a.__webglSprites=[];a.__webglFlares=[]}for(;a.__objectsAdded.length;){var g=a.__objectsAdded[0],h=a,i=void 0,k=void 0,l=void 0;if(!g.__webglInit){g.__webglInit=true;g._modelViewMatrix=
-new THREE.Matrix4;g._normalMatrix=new THREE.Matrix3;if(g instanceof THREE.Mesh){k=g.geometry;if(k instanceof THREE.Geometry){if(k.geometryGroups===void 0){var r=k,s=void 0,t=void 0,u=void 0,v=void 0,x=void 0,y=void 0,A=void 0,B={},D=r.morphTargets.length,G=r.morphNormals.length;r.geometryGroups={};s=0;for(t=r.faces.length;s<t;s++){u=r.faces[s];v=u.materialIndex;y=v!==void 0?v:-1;B[y]===void 0&&(B[y]={hash:y,counter:0});A=B[y].hash+"_"+B[y].counter;r.geometryGroups[A]===void 0&&(r.geometryGroups[A]=
-{faces3:[],faces4:[],materialIndex:v,vertices:0,numMorphTargets:D,numMorphNormals:G});x=u instanceof THREE.Face3?3:4;if(r.geometryGroups[A].vertices+x>65535){B[y].counter=B[y].counter+1;A=B[y].hash+"_"+B[y].counter;r.geometryGroups[A]===void 0&&(r.geometryGroups[A]={faces3:[],faces4:[],materialIndex:v,vertices:0,numMorphTargets:D,numMorphNormals:G})}u instanceof THREE.Face3?r.geometryGroups[A].faces3.push(s):r.geometryGroups[A].faces4.push(s);r.geometryGroups[A].vertices=r.geometryGroups[A].vertices+
-x}r.geometryGroupsList=[];var M=void 0;for(M in r.geometryGroups){r.geometryGroups[M].id=O++;r.geometryGroupsList.push(r.geometryGroups[M])}}for(i in k.geometryGroups){l=k.geometryGroups[i];if(!l.__webglVertexBuffer){var S=l;S.__webglVertexBuffer=j.createBuffer();S.__webglNormalBuffer=j.createBuffer();S.__webglTangentBuffer=j.createBuffer();S.__webglColorBuffer=j.createBuffer();S.__webglUVBuffer=j.createBuffer();S.__webglUV2Buffer=j.createBuffer();S.__webglSkinVertexABuffer=j.createBuffer();S.__webglSkinVertexBBuffer=
-j.createBuffer();S.__webglSkinIndicesBuffer=j.createBuffer();S.__webglSkinWeightsBuffer=j.createBuffer();S.__webglFaceBuffer=j.createBuffer();S.__webglLineBuffer=j.createBuffer();var H=void 0,I=void 0;if(S.numMorphTargets){S.__webglMorphTargetsBuffers=[];H=0;for(I=S.numMorphTargets;H<I;H++)S.__webglMorphTargetsBuffers.push(j.createBuffer())}if(S.numMorphNormals){S.__webglMorphNormalsBuffers=[];H=0;for(I=S.numMorphNormals;H<I;H++)S.__webglMorphNormalsBuffers.push(j.createBuffer())}C.info.memory.geometries++;
-var F=l,N=g,L=N.geometry,Z=F.faces3,$=F.faces4,T=Z.length*3+$.length*4,Q=Z.length*1+$.length*2,P=Z.length*3+$.length*4,R=c(N,F),aa=e(R),Y=d(R),fa=R.vertexColors?R.vertexColors:false;F.__vertexArray=new Float32Array(T*3);if(Y)F.__normalArray=new Float32Array(T*3);if(L.hasTangents)F.__tangentArray=new Float32Array(T*4);if(fa)F.__colorArray=new Float32Array(T*3);if(aa){if(L.faceUvs.length>0||L.faceVertexUvs.length>0)F.__uvArray=new Float32Array(T*2);if(L.faceUvs.length>1||L.faceVertexUvs.length>1)F.__uv2Array=
-new Float32Array(T*2)}if(N.geometry.skinWeights.length&&N.geometry.skinIndices.length){F.__skinVertexAArray=new Float32Array(T*4);F.__skinVertexBArray=new Float32Array(T*4);F.__skinIndexArray=new Float32Array(T*4);F.__skinWeightArray=new Float32Array(T*4)}F.__faceArray=new Uint16Array(Q*3);F.__lineArray=new Uint16Array(P*2);var ca=void 0,ha=void 0;if(F.numMorphTargets){F.__morphTargetsArrays=[];ca=0;for(ha=F.numMorphTargets;ca<ha;ca++)F.__morphTargetsArrays.push(new Float32Array(T*3))}if(F.numMorphNormals){F.__morphNormalsArrays=
-[];ca=0;for(ha=F.numMorphNormals;ca<ha;ca++)F.__morphNormalsArrays.push(new Float32Array(T*3))}F.__webglFaceCount=Q*3;F.__webglLineCount=P*2;if(R.attributes){if(F.__webglCustomAttributesList===void 0)F.__webglCustomAttributesList=[];var Oa=void 0;for(Oa in R.attributes){var Sa=R.attributes[Oa],oa={},la;for(la in Sa)oa[la]=Sa[la];if(!oa.__webglInitialized||oa.createUniqueBuffers){oa.__webglInitialized=true;var Ma=1;oa.type==="v2"?Ma=2:oa.type==="v3"?Ma=3:oa.type==="v4"?Ma=4:oa.type==="c"&&(Ma=3);oa.size=
-Ma;oa.array=new Float32Array(T*Ma);oa.buffer=j.createBuffer();oa.buffer.belongsToAttribute=Oa;Sa.needsUpdate=true;oa.__original=Sa}F.__webglCustomAttributesList.push(oa)}}F.__inittedArrays=true;k.verticesNeedUpdate=true;k.morphTargetsNeedUpdate=true;k.elementsNeedUpdate=true;k.uvsNeedUpdate=true;k.normalsNeedUpdate=true;k.tangetsNeedUpdate=true;k.colorsNeedUpdate=true}}}}else if(g instanceof THREE.Ribbon){k=g.geometry;if(!k.__webglVertexBuffer){var Ta=k;Ta.__webglVertexBuffer=j.createBuffer();Ta.__webglColorBuffer=
-j.createBuffer();C.info.memory.geometries++;var wa=k,ya=wa.vertices.length;wa.__vertexArray=new Float32Array(ya*3);wa.__colorArray=new Float32Array(ya*3);wa.__webglVertexCount=ya;k.verticesNeedUpdate=true;k.colorsNeedUpdate=true}}else if(g instanceof THREE.Line){k=g.geometry;if(!k.__webglVertexBuffer){var Da=k;Da.__webglVertexBuffer=j.createBuffer();Da.__webglColorBuffer=j.createBuffer();C.info.memory.geometries++;var Ba=k,eb=g,Pa=Ba.vertices.length;Ba.__vertexArray=new Float32Array(Pa*3);Ba.__colorArray=
-new Float32Array(Pa*3);Ba.__webglLineCount=Pa;b(Ba,eb);k.verticesNeedUpdate=true;k.colorsNeedUpdate=true}}else if(g instanceof THREE.ParticleSystem){k=g.geometry;if(!k.__webglVertexBuffer){var ab=k;ab.__webglVertexBuffer=j.createBuffer();ab.__webglColorBuffer=j.createBuffer();C.info.geometries++;var Za=k,Lb=g,mb=Za.vertices.length;Za.__vertexArray=new Float32Array(mb*3);Za.__colorArray=new Float32Array(mb*3);Za.__sortArray=[];Za.__webglParticleCount=mb;b(Za,Lb);k.verticesNeedUpdate=true;k.colorsNeedUpdate=
-true}}}if(!g.__webglActive){if(g instanceof THREE.Mesh){k=g.geometry;if(k instanceof THREE.BufferGeometry)o(h.__webglObjects,k,g);else for(i in k.geometryGroups){l=k.geometryGroups[i];o(h.__webglObjects,l,g)}}else if(g instanceof THREE.Ribbon||g instanceof THREE.Line||g instanceof THREE.ParticleSystem){k=g.geometry;o(h.__webglObjects,k,g)}else g instanceof THREE.ImmediateRenderObject||g.immediateRenderCallback?h.__webglObjectsImmediate.push({object:g,opaque:null,transparent:null}):g instanceof THREE.Sprite?
-h.__webglSprites.push(g):g instanceof THREE.LensFlare&&h.__webglFlares.push(g);g.__webglActive=true}a.__objectsAdded.splice(0,1)}for(;a.__objectsRemoved.length;){var bb=a.__objectsRemoved[0],jb=a;bb instanceof THREE.Mesh||bb instanceof THREE.ParticleSystem||bb instanceof THREE.Ribbon||bb instanceof THREE.Line?q(jb.__webglObjects,bb):bb instanceof THREE.Sprite?n(jb.__webglSprites,bb):bb instanceof THREE.LensFlare?n(jb.__webglFlares,bb):(bb instanceof THREE.ImmediateRenderObject||bb.immediateRenderCallback)&&
-q(jb.__webglObjectsImmediate,bb);bb.__webglActive=false;a.__objectsRemoved.splice(0,1)}for(var gb=0,ob=a.__webglObjects.length;gb<ob;gb++){var kb=a.__webglObjects[gb].object,ga=kb.geometry,$a=void 0,fb=void 0,Ua=void 0;if(kb instanceof THREE.Mesh)if(ga instanceof THREE.BufferGeometry){ga.verticesNeedUpdate=false;ga.elementsNeedUpdate=false;ga.uvsNeedUpdate=false;ga.normalsNeedUpdate=false;ga.colorsNeedUpdate=false}else{for(var nb=0,ac=ga.geometryGroupsList.length;nb<ac;nb++){$a=ga.geometryGroupsList[nb];
-Ua=c(kb,$a);fb=Ua.attributes&&m(Ua);if(ga.verticesNeedUpdate||ga.morphTargetsNeedUpdate||ga.elementsNeedUpdate||ga.uvsNeedUpdate||ga.normalsNeedUpdate||ga.colorsNeedUpdate||ga.tangetsNeedUpdate||fb){var da=$a,nd=kb,Wa=j.DYNAMIC_DRAW,od=!ga.dynamic,cc=Ua;if(da.__inittedArrays){var cd=d(cc),Tc=cc.vertexColors?cc.vertexColors:false,dd=e(cc),Ec=cd===THREE.SmoothShading,E=void 0,U=void 0,ib=void 0,K=void 0,jc=void 0,Ob=void 0,lb=void 0,Fc=void 0,Gb=void 0,kc=void 0,lc=void 0,V=void 0,W=void 0,X=void 0,
-ma=void 0,pb=void 0,qb=void 0,rb=void 0,qc=void 0,sb=void 0,tb=void 0,ub=void 0,rc=void 0,vb=void 0,wb=void 0,xb=void 0,sc=void 0,yb=void 0,zb=void 0,Ab=void 0,tc=void 0,Bb=void 0,Cb=void 0,Db=void 0,uc=void 0,Pb=void 0,Qb=void 0,Rb=void 0,Gc=void 0,Sb=void 0,Tb=void 0,Ub=void 0,Hc=void 0,ia=void 0,ed=void 0,Vb=void 0,mc=void 0,nc=void 0,Ga=void 0,fd=void 0,Ea=void 0,Fa=void 0,Wb=void 0,Hb=void 0,xa=0,Ca=0,Ib=0,Jb=0,cb=0,Na=0,na=0,Qa=0,za=0,J=0,ba=0,z=0,Xa=void 0,Ha=da.__vertexArray,vc=da.__uvArray,
-wc=da.__uv2Array,db=da.__normalArray,qa=da.__tangentArray,Ia=da.__colorArray,ra=da.__skinVertexAArray,sa=da.__skinVertexBArray,ta=da.__skinIndexArray,ua=da.__skinWeightArray,Uc=da.__morphTargetsArrays,Vc=da.__morphNormalsArrays,Wc=da.__webglCustomAttributesList,w=void 0,Eb=da.__faceArray,Ya=da.__lineArray,Ra=nd.geometry,pd=Ra.elementsNeedUpdate,gd=Ra.uvsNeedUpdate,qd=Ra.normalsNeedUpdate,rd=Ra.tangetsNeedUpdate,sd=Ra.colorsNeedUpdate,td=Ra.morphTargetsNeedUpdate,dc=Ra.vertices,ja=da.faces3,ka=da.faces4,
-Aa=Ra.faces,Xc=Ra.faceVertexUvs[0],Yc=Ra.faceVertexUvs[1],ec=Ra.skinVerticesA,fc=Ra.skinVerticesB,gc=Ra.skinIndices,Xb=Ra.skinWeights,Yb=Ra.morphTargets,Ic=Ra.morphNormals;if(Ra.verticesNeedUpdate){E=0;for(U=ja.length;E<U;E++){K=Aa[ja[E]];V=dc[K.a];W=dc[K.b];X=dc[K.c];Ha[Ca]=V.x;Ha[Ca+1]=V.y;Ha[Ca+2]=V.z;Ha[Ca+3]=W.x;Ha[Ca+4]=W.y;Ha[Ca+5]=W.z;Ha[Ca+6]=X.x;Ha[Ca+7]=X.y;Ha[Ca+8]=X.z;Ca=Ca+9}E=0;for(U=ka.length;E<U;E++){K=Aa[ka[E]];V=dc[K.a];W=dc[K.b];X=dc[K.c];ma=dc[K.d];Ha[Ca]=V.x;Ha[Ca+1]=V.y;Ha[Ca+
-2]=V.z;Ha[Ca+3]=W.x;Ha[Ca+4]=W.y;Ha[Ca+5]=W.z;Ha[Ca+6]=X.x;Ha[Ca+7]=X.y;Ha[Ca+8]=X.z;Ha[Ca+9]=ma.x;Ha[Ca+10]=ma.y;Ha[Ca+11]=ma.z;Ca=Ca+12}j.bindBuffer(j.ARRAY_BUFFER,da.__webglVertexBuffer);j.bufferData(j.ARRAY_BUFFER,Ha,Wa)}if(td){Ga=0;for(fd=Yb.length;Ga<fd;Ga++){E=ba=0;for(U=ja.length;E<U;E++){Wb=ja[E];K=Aa[Wb];V=Yb[Ga].vertices[K.a];W=Yb[Ga].vertices[K.b];X=Yb[Ga].vertices[K.c];Ea=Uc[Ga];Ea[ba]=V.x;Ea[ba+1]=V.y;Ea[ba+2]=V.z;Ea[ba+3]=W.x;Ea[ba+4]=W.y;Ea[ba+5]=W.z;Ea[ba+6]=X.x;Ea[ba+7]=X.y;Ea[ba+
-8]=X.z;if(cc.morphNormals){if(Ec){Hb=Ic[Ga].vertexNormals[Wb];sb=Hb.a;tb=Hb.b;ub=Hb.c}else ub=tb=sb=Ic[Ga].faceNormals[Wb];Fa=Vc[Ga];Fa[ba]=sb.x;Fa[ba+1]=sb.y;Fa[ba+2]=sb.z;Fa[ba+3]=tb.x;Fa[ba+4]=tb.y;Fa[ba+5]=tb.z;Fa[ba+6]=ub.x;Fa[ba+7]=ub.y;Fa[ba+8]=ub.z}ba=ba+9}E=0;for(U=ka.length;E<U;E++){Wb=ka[E];K=Aa[Wb];V=Yb[Ga].vertices[K.a];W=Yb[Ga].vertices[K.b];X=Yb[Ga].vertices[K.c];ma=Yb[Ga].vertices[K.d];Ea=Uc[Ga];Ea[ba]=V.x;Ea[ba+1]=V.y;Ea[ba+2]=V.z;Ea[ba+3]=W.x;Ea[ba+4]=W.y;Ea[ba+5]=W.z;Ea[ba+6]=X.x;
-Ea[ba+7]=X.y;Ea[ba+8]=X.z;Ea[ba+9]=ma.x;Ea[ba+10]=ma.y;Ea[ba+11]=ma.z;if(cc.morphNormals){if(Ec){Hb=Ic[Ga].vertexNormals[Wb];sb=Hb.a;tb=Hb.b;ub=Hb.c;rc=Hb.d}else rc=ub=tb=sb=Ic[Ga].faceNormals[Wb];Fa=Vc[Ga];Fa[ba]=sb.x;Fa[ba+1]=sb.y;Fa[ba+2]=sb.z;Fa[ba+3]=tb.x;Fa[ba+4]=tb.y;Fa[ba+5]=tb.z;Fa[ba+6]=ub.x;Fa[ba+7]=ub.y;Fa[ba+8]=ub.z;Fa[ba+9]=rc.x;Fa[ba+10]=rc.y;Fa[ba+11]=rc.z}ba=ba+12}j.bindBuffer(j.ARRAY_BUFFER,da.__webglMorphTargetsBuffers[Ga]);j.bufferData(j.ARRAY_BUFFER,Uc[Ga],Wa);if(cc.morphNormals){j.bindBuffer(j.ARRAY_BUFFER,
-da.__webglMorphNormalsBuffers[Ga]);j.bufferData(j.ARRAY_BUFFER,Vc[Ga],Wa)}}}if(Xb.length){E=0;for(U=ja.length;E<U;E++){K=Aa[ja[E]];yb=Xb[K.a];zb=Xb[K.b];Ab=Xb[K.c];ua[J]=yb.x;ua[J+1]=yb.y;ua[J+2]=yb.z;ua[J+3]=yb.w;ua[J+4]=zb.x;ua[J+5]=zb.y;ua[J+6]=zb.z;ua[J+7]=zb.w;ua[J+8]=Ab.x;ua[J+9]=Ab.y;ua[J+10]=Ab.z;ua[J+11]=Ab.w;Bb=gc[K.a];Cb=gc[K.b];Db=gc[K.c];ta[J]=Bb.x;ta[J+1]=Bb.y;ta[J+2]=Bb.z;ta[J+3]=Bb.w;ta[J+4]=Cb.x;ta[J+5]=Cb.y;ta[J+6]=Cb.z;ta[J+7]=Cb.w;ta[J+8]=Db.x;ta[J+9]=Db.y;ta[J+10]=Db.z;ta[J+11]=
-Db.w;Pb=ec[K.a];Qb=ec[K.b];Rb=ec[K.c];ra[J]=Pb.x;ra[J+1]=Pb.y;ra[J+2]=Pb.z;ra[J+3]=1;ra[J+4]=Qb.x;ra[J+5]=Qb.y;ra[J+6]=Qb.z;ra[J+7]=1;ra[J+8]=Rb.x;ra[J+9]=Rb.y;ra[J+10]=Rb.z;ra[J+11]=1;Sb=fc[K.a];Tb=fc[K.b];Ub=fc[K.c];sa[J]=Sb.x;sa[J+1]=Sb.y;sa[J+2]=Sb.z;sa[J+3]=1;sa[J+4]=Tb.x;sa[J+5]=Tb.y;sa[J+6]=Tb.z;sa[J+7]=1;sa[J+8]=Ub.x;sa[J+9]=Ub.y;sa[J+10]=Ub.z;sa[J+11]=1;J=J+12}E=0;for(U=ka.length;E<U;E++){K=Aa[ka[E]];yb=Xb[K.a];zb=Xb[K.b];Ab=Xb[K.c];tc=Xb[K.d];ua[J]=yb.x;ua[J+1]=yb.y;ua[J+2]=yb.z;ua[J+3]=
-yb.w;ua[J+4]=zb.x;ua[J+5]=zb.y;ua[J+6]=zb.z;ua[J+7]=zb.w;ua[J+8]=Ab.x;ua[J+9]=Ab.y;ua[J+10]=Ab.z;ua[J+11]=Ab.w;ua[J+12]=tc.x;ua[J+13]=tc.y;ua[J+14]=tc.z;ua[J+15]=tc.w;Bb=gc[K.a];Cb=gc[K.b];Db=gc[K.c];uc=gc[K.d];ta[J]=Bb.x;ta[J+1]=Bb.y;ta[J+2]=Bb.z;ta[J+3]=Bb.w;ta[J+4]=Cb.x;ta[J+5]=Cb.y;ta[J+6]=Cb.z;ta[J+7]=Cb.w;ta[J+8]=Db.x;ta[J+9]=Db.y;ta[J+10]=Db.z;ta[J+11]=Db.w;ta[J+12]=uc.x;ta[J+13]=uc.y;ta[J+14]=uc.z;ta[J+15]=uc.w;Pb=ec[K.a];Qb=ec[K.b];Rb=ec[K.c];Gc=ec[K.d];ra[J]=Pb.x;ra[J+1]=Pb.y;ra[J+2]=Pb.z;
-ra[J+3]=1;ra[J+4]=Qb.x;ra[J+5]=Qb.y;ra[J+6]=Qb.z;ra[J+7]=1;ra[J+8]=Rb.x;ra[J+9]=Rb.y;ra[J+10]=Rb.z;ra[J+11]=1;ra[J+12]=Gc.x;ra[J+13]=Gc.y;ra[J+14]=Gc.z;ra[J+15]=1;Sb=fc[K.a];Tb=fc[K.b];Ub=fc[K.c];Hc=fc[K.d];sa[J]=Sb.x;sa[J+1]=Sb.y;sa[J+2]=Sb.z;sa[J+3]=1;sa[J+4]=Tb.x;sa[J+5]=Tb.y;sa[J+6]=Tb.z;sa[J+7]=1;sa[J+8]=Ub.x;sa[J+9]=Ub.y;sa[J+10]=Ub.z;sa[J+11]=1;sa[J+12]=Hc.x;sa[J+13]=Hc.y;sa[J+14]=Hc.z;sa[J+15]=1;J=J+16}if(J>0){j.bindBuffer(j.ARRAY_BUFFER,da.__webglSkinVertexABuffer);j.bufferData(j.ARRAY_BUFFER,
-ra,Wa);j.bindBuffer(j.ARRAY_BUFFER,da.__webglSkinVertexBBuffer);j.bufferData(j.ARRAY_BUFFER,sa,Wa);j.bindBuffer(j.ARRAY_BUFFER,da.__webglSkinIndicesBuffer);j.bufferData(j.ARRAY_BUFFER,ta,Wa);j.bindBuffer(j.ARRAY_BUFFER,da.__webglSkinWeightsBuffer);j.bufferData(j.ARRAY_BUFFER,ua,Wa)}}if(sd&&Tc){E=0;for(U=ja.length;E<U;E++){K=Aa[ja[E]];lb=K.vertexColors;Fc=K.color;if(lb.length===3&&Tc===THREE.VertexColors){vb=lb[0];wb=lb[1];xb=lb[2]}else xb=wb=vb=Fc;Ia[za]=vb.r;Ia[za+1]=vb.g;Ia[za+2]=vb.b;Ia[za+3]=
-wb.r;Ia[za+4]=wb.g;Ia[za+5]=wb.b;Ia[za+6]=xb.r;Ia[za+7]=xb.g;Ia[za+8]=xb.b;za=za+9}E=0;for(U=ka.length;E<U;E++){K=Aa[ka[E]];lb=K.vertexColors;Fc=K.color;if(lb.length===4&&Tc===THREE.VertexColors){vb=lb[0];wb=lb[1];xb=lb[2];sc=lb[3]}else sc=xb=wb=vb=Fc;Ia[za]=vb.r;Ia[za+1]=vb.g;Ia[za+2]=vb.b;Ia[za+3]=wb.r;Ia[za+4]=wb.g;Ia[za+5]=wb.b;Ia[za+6]=xb.r;Ia[za+7]=xb.g;Ia[za+8]=xb.b;Ia[za+9]=sc.r;Ia[za+10]=sc.g;Ia[za+11]=sc.b;za=za+12}if(za>0){j.bindBuffer(j.ARRAY_BUFFER,da.__webglColorBuffer);j.bufferData(j.ARRAY_BUFFER,
-Ia,Wa)}}if(rd&&Ra.hasTangents){E=0;for(U=ja.length;E<U;E++){K=Aa[ja[E]];Gb=K.vertexTangents;pb=Gb[0];qb=Gb[1];rb=Gb[2];qa[na]=pb.x;qa[na+1]=pb.y;qa[na+2]=pb.z;qa[na+3]=pb.w;qa[na+4]=qb.x;qa[na+5]=qb.y;qa[na+6]=qb.z;qa[na+7]=qb.w;qa[na+8]=rb.x;qa[na+9]=rb.y;qa[na+10]=rb.z;qa[na+11]=rb.w;na=na+12}E=0;for(U=ka.length;E<U;E++){K=Aa[ka[E]];Gb=K.vertexTangents;pb=Gb[0];qb=Gb[1];rb=Gb[2];qc=Gb[3];qa[na]=pb.x;qa[na+1]=pb.y;qa[na+2]=pb.z;qa[na+3]=pb.w;qa[na+4]=qb.x;qa[na+5]=qb.y;qa[na+6]=qb.z;qa[na+7]=qb.w;
-qa[na+8]=rb.x;qa[na+9]=rb.y;qa[na+10]=rb.z;qa[na+11]=rb.w;qa[na+12]=qc.x;qa[na+13]=qc.y;qa[na+14]=qc.z;qa[na+15]=qc.w;na=na+16}j.bindBuffer(j.ARRAY_BUFFER,da.__webglTangentBuffer);j.bufferData(j.ARRAY_BUFFER,qa,Wa)}if(qd&&cd){E=0;for(U=ja.length;E<U;E++){K=Aa[ja[E]];jc=K.vertexNormals;Ob=K.normal;if(jc.length===3&&Ec)for(ia=0;ia<3;ia++){Vb=jc[ia];db[Na]=Vb.x;db[Na+1]=Vb.y;db[Na+2]=Vb.z;Na=Na+3}else for(ia=0;ia<3;ia++){db[Na]=Ob.x;db[Na+1]=Ob.y;db[Na+2]=Ob.z;Na=Na+3}}E=0;for(U=ka.length;E<U;E++){K=
-Aa[ka[E]];jc=K.vertexNormals;Ob=K.normal;if(jc.length===4&&Ec)for(ia=0;ia<4;ia++){Vb=jc[ia];db[Na]=Vb.x;db[Na+1]=Vb.y;db[Na+2]=Vb.z;Na=Na+3}else for(ia=0;ia<4;ia++){db[Na]=Ob.x;db[Na+1]=Ob.y;db[Na+2]=Ob.z;Na=Na+3}}j.bindBuffer(j.ARRAY_BUFFER,da.__webglNormalBuffer);j.bufferData(j.ARRAY_BUFFER,db,Wa)}if(gd&&Xc&&dd){E=0;for(U=ja.length;E<U;E++){ib=ja[E];K=Aa[ib];kc=Xc[ib];if(kc!==void 0)for(ia=0;ia<3;ia++){mc=kc[ia];vc[Ib]=mc.u;vc[Ib+1]=mc.v;Ib=Ib+2}}E=0;for(U=ka.length;E<U;E++){ib=ka[E];K=Aa[ib];kc=
-Xc[ib];if(kc!==void 0)for(ia=0;ia<4;ia++){mc=kc[ia];vc[Ib]=mc.u;vc[Ib+1]=mc.v;Ib=Ib+2}}if(Ib>0){j.bindBuffer(j.ARRAY_BUFFER,da.__webglUVBuffer);j.bufferData(j.ARRAY_BUFFER,vc,Wa)}}if(gd&&Yc&&dd){E=0;for(U=ja.length;E<U;E++){ib=ja[E];K=Aa[ib];lc=Yc[ib];if(lc!==void 0)for(ia=0;ia<3;ia++){nc=lc[ia];wc[Jb]=nc.u;wc[Jb+1]=nc.v;Jb=Jb+2}}E=0;for(U=ka.length;E<U;E++){ib=ka[E];K=Aa[ib];lc=Yc[ib];if(lc!==void 0)for(ia=0;ia<4;ia++){nc=lc[ia];wc[Jb]=nc.u;wc[Jb+1]=nc.v;Jb=Jb+2}}if(Jb>0){j.bindBuffer(j.ARRAY_BUFFER,
-da.__webglUV2Buffer);j.bufferData(j.ARRAY_BUFFER,wc,Wa)}}if(pd){E=0;for(U=ja.length;E<U;E++){K=Aa[ja[E]];Eb[cb]=xa;Eb[cb+1]=xa+1;Eb[cb+2]=xa+2;cb=cb+3;Ya[Qa]=xa;Ya[Qa+1]=xa+1;Ya[Qa+2]=xa;Ya[Qa+3]=xa+2;Ya[Qa+4]=xa+1;Ya[Qa+5]=xa+2;Qa=Qa+6;xa=xa+3}E=0;for(U=ka.length;E<U;E++){K=Aa[ka[E]];Eb[cb]=xa;Eb[cb+1]=xa+1;Eb[cb+2]=xa+3;Eb[cb+3]=xa+1;Eb[cb+4]=xa+2;Eb[cb+5]=xa+3;cb=cb+6;Ya[Qa]=xa;Ya[Qa+1]=xa+1;Ya[Qa+2]=xa;Ya[Qa+3]=xa+3;Ya[Qa+4]=xa+1;Ya[Qa+5]=xa+2;Ya[Qa+6]=xa+2;Ya[Qa+7]=xa+3;Qa=Qa+8;xa=xa+4}j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,
-da.__webglFaceBuffer);j.bufferData(j.ELEMENT_ARRAY_BUFFER,Eb,Wa);j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,da.__webglLineBuffer);j.bufferData(j.ELEMENT_ARRAY_BUFFER,Ya,Wa)}if(Wc){ia=0;for(ed=Wc.length;ia<ed;ia++){w=Wc[ia];if(w.__original.needsUpdate){z=0;if(w.size===1)if(w.boundTo===void 0||w.boundTo==="vertices"){E=0;for(U=ja.length;E<U;E++){K=Aa[ja[E]];w.array[z]=w.value[K.a];w.array[z+1]=w.value[K.b];w.array[z+2]=w.value[K.c];z=z+3}E=0;for(U=ka.length;E<U;E++){K=Aa[ka[E]];w.array[z]=w.value[K.a];w.array[z+
-1]=w.value[K.b];w.array[z+2]=w.value[K.c];w.array[z+3]=w.value[K.d];z=z+4}}else{if(w.boundTo==="faces"){E=0;for(U=ja.length;E<U;E++){Xa=w.value[ja[E]];w.array[z]=Xa;w.array[z+1]=Xa;w.array[z+2]=Xa;z=z+3}E=0;for(U=ka.length;E<U;E++){Xa=w.value[ka[E]];w.array[z]=Xa;w.array[z+1]=Xa;w.array[z+2]=Xa;w.array[z+3]=Xa;z=z+4}}}else if(w.size===2)if(w.boundTo===void 0||w.boundTo==="vertices"){E=0;for(U=ja.length;E<U;E++){K=Aa[ja[E]];V=w.value[K.a];W=w.value[K.b];X=w.value[K.c];w.array[z]=V.x;w.array[z+1]=V.y;
-w.array[z+2]=W.x;w.array[z+3]=W.y;w.array[z+4]=X.x;w.array[z+5]=X.y;z=z+6}E=0;for(U=ka.length;E<U;E++){K=Aa[ka[E]];V=w.value[K.a];W=w.value[K.b];X=w.value[K.c];ma=w.value[K.d];w.array[z]=V.x;w.array[z+1]=V.y;w.array[z+2]=W.x;w.array[z+3]=W.y;w.array[z+4]=X.x;w.array[z+5]=X.y;w.array[z+6]=ma.x;w.array[z+7]=ma.y;z=z+8}}else{if(w.boundTo==="faces"){E=0;for(U=ja.length;E<U;E++){X=W=V=Xa=w.value[ja[E]];w.array[z]=V.x;w.array[z+1]=V.y;w.array[z+2]=W.x;w.array[z+3]=W.y;w.array[z+4]=X.x;w.array[z+5]=X.y;
-z=z+6}E=0;for(U=ka.length;E<U;E++){ma=X=W=V=Xa=w.value[ka[E]];w.array[z]=V.x;w.array[z+1]=V.y;w.array[z+2]=W.x;w.array[z+3]=W.y;w.array[z+4]=X.x;w.array[z+5]=X.y;w.array[z+6]=ma.x;w.array[z+7]=ma.y;z=z+8}}}else if(w.size===3){var ea;ea=w.type==="c"?["r","g","b"]:["x","y","z"];if(w.boundTo===void 0||w.boundTo==="vertices"){E=0;for(U=ja.length;E<U;E++){K=Aa[ja[E]];V=w.value[K.a];W=w.value[K.b];X=w.value[K.c];w.array[z]=V[ea[0]];w.array[z+1]=V[ea[1]];w.array[z+2]=V[ea[2]];w.array[z+3]=W[ea[0]];w.array[z+
-4]=W[ea[1]];w.array[z+5]=W[ea[2]];w.array[z+6]=X[ea[0]];w.array[z+7]=X[ea[1]];w.array[z+8]=X[ea[2]];z=z+9}E=0;for(U=ka.length;E<U;E++){K=Aa[ka[E]];V=w.value[K.a];W=w.value[K.b];X=w.value[K.c];ma=w.value[K.d];w.array[z]=V[ea[0]];w.array[z+1]=V[ea[1]];w.array[z+2]=V[ea[2]];w.array[z+3]=W[ea[0]];w.array[z+4]=W[ea[1]];w.array[z+5]=W[ea[2]];w.array[z+6]=X[ea[0]];w.array[z+7]=X[ea[1]];w.array[z+8]=X[ea[2]];w.array[z+9]=ma[ea[0]];w.array[z+10]=ma[ea[1]];w.array[z+11]=ma[ea[2]];z=z+12}}else if(w.boundTo===
-"faces"){E=0;for(U=ja.length;E<U;E++){X=W=V=Xa=w.value[ja[E]];w.array[z]=V[ea[0]];w.array[z+1]=V[ea[1]];w.array[z+2]=V[ea[2]];w.array[z+3]=W[ea[0]];w.array[z+4]=W[ea[1]];w.array[z+5]=W[ea[2]];w.array[z+6]=X[ea[0]];w.array[z+7]=X[ea[1]];w.array[z+8]=X[ea[2]];z=z+9}E=0;for(U=ka.length;E<U;E++){ma=X=W=V=Xa=w.value[ka[E]];w.array[z]=V[ea[0]];w.array[z+1]=V[ea[1]];w.array[z+2]=V[ea[2]];w.array[z+3]=W[ea[0]];w.array[z+4]=W[ea[1]];w.array[z+5]=W[ea[2]];w.array[z+6]=X[ea[0]];w.array[z+7]=X[ea[1]];w.array[z+
-8]=X[ea[2]];w.array[z+9]=ma[ea[0]];w.array[z+10]=ma[ea[1]];w.array[z+11]=ma[ea[2]];z=z+12}}}else if(w.size===4)if(w.boundTo===void 0||w.boundTo==="vertices"){E=0;for(U=ja.length;E<U;E++){K=Aa[ja[E]];V=w.value[K.a];W=w.value[K.b];X=w.value[K.c];w.array[z]=V.x;w.array[z+1]=V.y;w.array[z+2]=V.z;w.array[z+3]=V.w;w.array[z+4]=W.x;w.array[z+5]=W.y;w.array[z+6]=W.z;w.array[z+7]=W.w;w.array[z+8]=X.x;w.array[z+9]=X.y;w.array[z+10]=X.z;w.array[z+11]=X.w;z=z+12}E=0;for(U=ka.length;E<U;E++){K=Aa[ka[E]];V=w.value[K.a];
-W=w.value[K.b];X=w.value[K.c];ma=w.value[K.d];w.array[z]=V.x;w.array[z+1]=V.y;w.array[z+2]=V.z;w.array[z+3]=V.w;w.array[z+4]=W.x;w.array[z+5]=W.y;w.array[z+6]=W.z;w.array[z+7]=W.w;w.array[z+8]=X.x;w.array[z+9]=X.y;w.array[z+10]=X.z;w.array[z+11]=X.w;w.array[z+12]=ma.x;w.array[z+13]=ma.y;w.array[z+14]=ma.z;w.array[z+15]=ma.w;z=z+16}}else if(w.boundTo==="faces"){E=0;for(U=ja.length;E<U;E++){X=W=V=Xa=w.value[ja[E]];w.array[z]=V.x;w.array[z+1]=V.y;w.array[z+2]=V.z;w.array[z+3]=V.w;w.array[z+4]=W.x;w.array[z+
-5]=W.y;w.array[z+6]=W.z;w.array[z+7]=W.w;w.array[z+8]=X.x;w.array[z+9]=X.y;w.array[z+10]=X.z;w.array[z+11]=X.w;z=z+12}E=0;for(U=ka.length;E<U;E++){ma=X=W=V=Xa=w.value[ka[E]];w.array[z]=V.x;w.array[z+1]=V.y;w.array[z+2]=V.z;w.array[z+3]=V.w;w.array[z+4]=W.x;w.array[z+5]=W.y;w.array[z+6]=W.z;w.array[z+7]=W.w;w.array[z+8]=X.x;w.array[z+9]=X.y;w.array[z+10]=X.z;w.array[z+11]=X.w;w.array[z+12]=ma.x;w.array[z+13]=ma.y;w.array[z+14]=ma.z;w.array[z+15]=ma.w;z=z+16}}j.bindBuffer(j.ARRAY_BUFFER,w.buffer);j.bufferData(j.ARRAY_BUFFER,
-w.array,Wa)}}}if(od){delete da.__inittedArrays;delete da.__colorArray;delete da.__normalArray;delete da.__tangentArray;delete da.__uvArray;delete da.__uv2Array;delete da.__faceArray;delete da.__vertexArray;delete da.__lineArray;delete da.__skinVertexAArray;delete da.__skinVertexBArray;delete da.__skinIndexArray;delete da.__skinWeightArray}}}}ga.verticesNeedUpdate=false;ga.morphTargetsNeedUpdate=false;ga.elementsNeedUpdate=false;ga.uvsNeedUpdate=false;ga.normalsNeedUpdate=false;ga.colorsNeedUpdate=
-false;ga.tangetsNeedUpdate=false;Ua.attributes&&p(Ua)}else if(kb instanceof THREE.Ribbon){if(ga.verticesNeedUpdate||ga.colorsNeedUpdate){var Zb=ga,hd=j.DYNAMIC_DRAW,xc=void 0,yc=void 0,Jc=void 0,$b=void 0,Kc=void 0,id=Zb.vertices,jd=Zb.colors,ud=id.length,vd=jd.length,Lc=Zb.__vertexArray,Mc=Zb.__colorArray,wd=Zb.colorsNeedUpdate;if(Zb.verticesNeedUpdate){for(xc=0;xc<ud;xc++){Jc=id[xc];$b=xc*3;Lc[$b]=Jc.x;Lc[$b+1]=Jc.y;Lc[$b+2]=Jc.z}j.bindBuffer(j.ARRAY_BUFFER,Zb.__webglVertexBuffer);j.bufferData(j.ARRAY_BUFFER,
-Lc,hd)}if(wd){for(yc=0;yc<vd;yc++){Kc=jd[yc];$b=yc*3;Mc[$b]=Kc.r;Mc[$b+1]=Kc.g;Mc[$b+2]=Kc.b}j.bindBuffer(j.ARRAY_BUFFER,Zb.__webglColorBuffer);j.bufferData(j.ARRAY_BUFFER,Mc,hd)}}ga.verticesNeedUpdate=false;ga.colorsNeedUpdate=false}else if(kb instanceof THREE.Line){Ua=c(kb,$a);fb=Ua.attributes&&m(Ua);if(ga.verticesNeedUpdate||ga.colorsNeedUpdate||fb){var Kb=ga,Zc=j.DYNAMIC_DRAW,zc=void 0,Ac=void 0,Nc=void 0,va=void 0,Oc=void 0,kd=Kb.vertices,ld=Kb.colors,xd=kd.length,yd=ld.length,Pc=Kb.__vertexArray,
-Qc=Kb.__colorArray,zd=Kb.colorsNeedUpdate,$c=Kb.__webglCustomAttributesList,Rc=void 0,md=void 0,La=void 0,oc=void 0,Va=void 0,pa=void 0;if(Kb.verticesNeedUpdate){for(zc=0;zc<xd;zc++){Nc=kd[zc];va=zc*3;Pc[va]=Nc.x;Pc[va+1]=Nc.y;Pc[va+2]=Nc.z}j.bindBuffer(j.ARRAY_BUFFER,Kb.__webglVertexBuffer);j.bufferData(j.ARRAY_BUFFER,Pc,Zc)}if(zd){for(Ac=0;Ac<yd;Ac++){Oc=ld[Ac];va=Ac*3;Qc[va]=Oc.r;Qc[va+1]=Oc.g;Qc[va+2]=Oc.b}j.bindBuffer(j.ARRAY_BUFFER,Kb.__webglColorBuffer);j.bufferData(j.ARRAY_BUFFER,Qc,Zc)}if($c){Rc=
-0;for(md=$c.length;Rc<md;Rc++){pa=$c[Rc];if(pa.needsUpdate&&(pa.boundTo===void 0||pa.boundTo==="vertices")){va=0;oc=pa.value.length;if(pa.size===1)for(La=0;La<oc;La++)pa.array[La]=pa.value[La];else if(pa.size===2)for(La=0;La<oc;La++){Va=pa.value[La];pa.array[va]=Va.x;pa.array[va+1]=Va.y;va=va+2}else if(pa.size===3)if(pa.type==="c")for(La=0;La<oc;La++){Va=pa.value[La];pa.array[va]=Va.r;pa.array[va+1]=Va.g;pa.array[va+2]=Va.b;va=va+3}else for(La=0;La<oc;La++){Va=pa.value[La];pa.array[va]=Va.x;pa.array[va+
-1]=Va.y;pa.array[va+2]=Va.z;va=va+3}else if(pa.size===4)for(La=0;La<oc;La++){Va=pa.value[La];pa.array[va]=Va.x;pa.array[va+1]=Va.y;pa.array[va+2]=Va.z;pa.array[va+3]=Va.w;va=va+4}j.bindBuffer(j.ARRAY_BUFFER,pa.buffer);j.bufferData(j.ARRAY_BUFFER,pa.array,Zc)}}}}ga.verticesNeedUpdate=false;ga.colorsNeedUpdate=false;Ua.attributes&&p(Ua)}else if(kb instanceof THREE.ParticleSystem){Ua=c(kb,$a);fb=Ua.attributes&&m(Ua);(ga.verticesNeedUpdate||ga.colorsNeedUpdate||kb.sortParticles||fb)&&f(ga,j.DYNAMIC_DRAW,
-kb);ga.verticesNeedUpdate=false;ga.colorsNeedUpdate=false;Ua.attributes&&p(Ua)}}};this.initMaterial=function(a,b,c,d){var e,f,g;a instanceof THREE.MeshDepthMaterial?g="depth":a instanceof THREE.MeshNormalMaterial?g="normal":a instanceof THREE.MeshBasicMaterial?g="basic":a instanceof THREE.MeshLambertMaterial?g="lambert":a instanceof THREE.MeshPhongMaterial?g="phong":a instanceof THREE.LineBasicMaterial?g="basic":a instanceof THREE.ParticleBasicMaterial&&(g="particle_basic");if(g){var h=THREE.ShaderLib[g];
-a.uniforms=THREE.UniformsUtils.clone(h.uniforms);a.vertexShader=h.vertexShader;a.fragmentShader=h.fragmentShader}var i,k,l,m,n;i=m=n=h=0;for(k=b.length;i<k;i++){l=b[i];if(!l.onlyShadow){l instanceof THREE.DirectionalLight&&m++;l instanceof THREE.PointLight&&n++;l instanceof THREE.SpotLight&&h++}}if(n+h+m<=Q){k=m;l=n;m=h}else{k=Math.ceil(Q*m/(n+m));m=l=Q-k}var o=0,h=0;for(n=b.length;h<n;h++){i=b[h];if(i.castShadow){i instanceof THREE.SpotLight&&o++;i instanceof THREE.DirectionalLight&&!i.shadowCascade&&
-o++}}var p=50;if(d!==void 0&&d instanceof THREE.SkinnedMesh)p=d.bones.length;var q;a:{i=a.fragmentShader;n=a.vertexShader;var h=a.uniforms,b=a.attributes,c={map:!!a.map,envMap:!!a.envMap,lightMap:!!a.lightMap,vertexColors:a.vertexColors,fog:c,useFog:a.fog,sizeAttenuation:a.sizeAttenuation,skinning:a.skinning,maxBones:p,morphTargets:a.morphTargets,morphNormals:a.morphNormals,maxMorphTargets:this.maxMorphTargets,maxMorphNormals:this.maxMorphNormals,maxDirLights:k,maxPointLights:l,maxSpotLights:m,maxShadows:o,
-shadowMapEnabled:this.shadowMapEnabled&&d.receiveShadow,shadowMapSoft:this.shadowMapSoft,shadowMapDebug:this.shadowMapDebug,shadowMapCascade:this.shadowMapCascade,alphaTest:a.alphaTest,metal:a.metal,perPixel:a.perPixel,wrapAround:a.wrapAround,doubleSided:d&&d.doubleSided},r,d=[];if(g)d.push(g);else{d.push(i);d.push(n)}for(r in c){d.push(r);d.push(c[r])}g=d.join();r=0;for(d=P.length;r<d;r++){k=P[r];if(k.code===g){k.usedTimes++;q=k.program;break a}}r=j.createProgram();d=["precision "+v+" float;",$a>
-0?"#define VERTEX_TEXTURES":"",C.gammaInput?"#define GAMMA_INPUT":"",C.gammaOutput?"#define GAMMA_OUTPUT":"",C.physicallyBasedShading?"#define PHYSICALLY_BASED_SHADING":"","#define MAX_DIR_LIGHTS "+c.maxDirLights,"#define MAX_POINT_LIGHTS "+c.maxPointLights,"#define MAX_SPOT_LIGHTS "+c.maxSpotLights,"#define MAX_SHADOWS "+c.maxShadows,"#define MAX_BONES "+c.maxBones,c.map?"#define USE_MAP":"",c.envMap?"#define USE_ENVMAP":"",c.lightMap?"#define USE_LIGHTMAP":"",c.vertexColors?"#define USE_COLOR":
-"",c.skinning?"#define USE_SKINNING":"",c.morphTargets?"#define USE_MORPHTARGETS":"",c.morphNormals?"#define USE_MORPHNORMALS":"",c.perPixel?"#define PHONG_PER_PIXEL":"",c.wrapAround?"#define WRAP_AROUND":"",c.doubleSided?"#define DOUBLE_SIDED":"",c.shadowMapEnabled?"#define USE_SHADOWMAP":"",c.shadowMapSoft?"#define SHADOWMAP_SOFT":"",c.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",c.shadowMapCascade?"#define SHADOWMAP_CASCADE":"",c.sizeAttenuation?"#define USE_SIZEATTENUATION":"","uniform mat4 objectMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform mat3 normalMatrix;\nuniform vec3 cameraPosition;\nattribute vec3 position;\nattribute vec3 normal;\nattribute vec2 uv;\nattribute vec2 uv2;\n#ifdef USE_COLOR\nattribute vec3 color;\n#endif\n#ifdef USE_MORPHTARGETS\nattribute vec3 morphTarget0;\nattribute vec3 morphTarget1;\nattribute vec3 morphTarget2;\nattribute vec3 morphTarget3;\n#ifdef USE_MORPHNORMALS\nattribute vec3 morphNormal0;\nattribute vec3 morphNormal1;\nattribute vec3 morphNormal2;\nattribute vec3 morphNormal3;\n#else\nattribute vec3 morphTarget4;\nattribute vec3 morphTarget5;\nattribute vec3 morphTarget6;\nattribute vec3 morphTarget7;\n#endif\n#endif\n#ifdef USE_SKINNING\nattribute vec4 skinVertexA;\nattribute vec4 skinVertexB;\nattribute vec4 skinIndex;\nattribute vec4 skinWeight;\n#endif\n"].join("\n");
+1;c>=0;c--)a[c].object===b&&a.splice(c,1)}function n(a,b){for(var c=a.length-1;c>=0;c--)a[c]===b&&a.splice(c,1)}function r(a,b,c,d,e){if(d.needsUpdate){d.program&&C.deallocateMaterial(d);C.initMaterial(d,b,c,e);d.needsUpdate=false}if(d.morphTargets&&!e.__webglMorphTargetInfluences)e.__webglMorphTargetInfluences=new Float32Array(C.maxMorphTargets);var f=false,g=d.program,h=g.uniforms,i=d.uniforms;if(g!==T){j.useProgram(g);T=g;f=true}if(d.id!==M){M=d.id;f=true}if(f||a!==fa){j.uniformMatrix4fv(h.projectionMatrix,
+false,a._projectionMatrixArray);a!==fa&&(fa=a)}if(f){if(c&&d.fog){i.fogColor.value=c.color;if(c instanceof THREE.Fog){i.fogNear.value=c.near;i.fogFar.value=c.far}else if(c instanceof THREE.FogExp2)i.fogDensity.value=c.density}if(d instanceof THREE.MeshPhongMaterial||d instanceof THREE.MeshLambertMaterial||d.lights){if(la){for(var k,l=0,m=0,n=0,o,p,q,r=ob,t=r.directional.colors,v=r.directional.positions,u=r.point.colors,x=r.point.positions,y=r.point.distances,B=r.spot.colors,G=r.spot.positions,H=r.spot.distances,
+S=r.spot.directions,I=r.spot.angles,F=r.spot.exponents,L=0,Z=0,N=0,O=q=0,c=O=0,f=b.length;c<f;c++){k=b[c];if(!k.onlyShadow){o=k.color;p=k.intensity;q=k.distance;if(k instanceof THREE.AmbientLight)if(C.gammaInput){l=l+o.r*o.r;m=m+o.g*o.g;n=n+o.b*o.b}else{l=l+o.r;m=m+o.g;n=n+o.b}else if(k instanceof THREE.DirectionalLight){q=L*3;if(C.gammaInput){t[q]=o.r*o.r*p*p;t[q+1]=o.g*o.g*p*p;t[q+2]=o.b*o.b*p*p}else{t[q]=o.r*p;t[q+1]=o.g*p;t[q+2]=o.b*p}Da.copy(k.matrixWorld.getPosition());Da.subSelf(k.target.matrixWorld.getPosition());
+Da.normalize();v[q]=Da.x;v[q+1]=Da.y;v[q+2]=Da.z;L=L+1}else if(k instanceof THREE.PointLight){O=Z*3;if(C.gammaInput){u[O]=o.r*o.r*p*p;u[O+1]=o.g*o.g*p*p;u[O+2]=o.b*o.b*p*p}else{u[O]=o.r*p;u[O+1]=o.g*p;u[O+2]=o.b*p}o=k.matrixWorld.getPosition();x[O]=o.x;x[O+1]=o.y;x[O+2]=o.z;y[Z]=q;Z=Z+1}else if(k instanceof THREE.SpotLight){O=N*3;if(C.gammaInput){B[O]=o.r*o.r*p*p;B[O+1]=o.g*o.g*p*p;B[O+2]=o.b*o.b*p*p}else{B[O]=o.r*p;B[O+1]=o.g*p;B[O+2]=o.b*p}o=k.matrixWorld.getPosition();G[O]=o.x;G[O+1]=o.y;G[O+2]=
+o.z;H[N]=q;Da.copy(o);Da.subSelf(k.target.matrixWorld.getPosition());Da.normalize();S[O]=Da.x;S[O+1]=Da.y;S[O+2]=Da.z;I[N]=Math.cos(k.angle);F[N]=k.exponent;N=N+1}}}c=L*3;for(f=t.length;c<f;c++)t[c]=0;c=Z*3;for(f=u.length;c<f;c++)u[c]=0;c=N*3;for(f=B.length;c<f;c++)B[c]=0;r.directional.length=L;r.point.length=Z;r.spot.length=N;r.ambient[0]=l;r.ambient[1]=m;r.ambient[2]=n;la=false}c=ob;i.ambientLightColor.value=c.ambient;i.directionalLightColor.value=c.directional.colors;i.directionalLightDirection.value=
+c.directional.positions;i.pointLightColor.value=c.point.colors;i.pointLightPosition.value=c.point.positions;i.pointLightDistance.value=c.point.distances;i.spotLightColor.value=c.spot.colors;i.spotLightPosition.value=c.spot.positions;i.spotLightDistance.value=c.spot.distances;i.spotLightDirection.value=c.spot.directions;i.spotLightAngle.value=c.spot.angles;i.spotLightExponent.value=c.spot.exponents}if(d instanceof THREE.MeshBasicMaterial||d instanceof THREE.MeshLambertMaterial||d instanceof THREE.MeshPhongMaterial){i.opacity.value=
+d.opacity;C.gammaInput?i.diffuse.value.copyGammaToLinear(d.color):i.diffuse.value=d.color;(i.map.texture=d.map)&&i.offsetRepeat.value.set(d.map.offset.x,d.map.offset.y,d.map.repeat.x,d.map.repeat.y);i.lightMap.texture=d.lightMap;i.envMap.texture=d.envMap;i.flipEnvMap.value=d.envMap instanceof THREE.WebGLRenderTargetCube?1:-1;i.reflectivity.value=d.reflectivity;i.refractionRatio.value=d.refractionRatio;i.combine.value=d.combine;i.useRefract.value=d.envMap&&d.envMap.mapping instanceof THREE.CubeRefractionMapping}if(d instanceof
+THREE.LineBasicMaterial){i.diffuse.value=d.color;i.opacity.value=d.opacity}else if(d instanceof THREE.ParticleBasicMaterial){i.psColor.value=d.color;i.opacity.value=d.opacity;i.size.value=d.size;i.scale.value=A.height/2;i.map.texture=d.map}else if(d instanceof THREE.MeshPhongMaterial){i.shininess.value=d.shininess;if(C.gammaInput){i.ambient.value.copyGammaToLinear(d.ambient);i.emissive.value.copyGammaToLinear(d.emissive);i.specular.value.copyGammaToLinear(d.specular)}else{i.ambient.value=d.ambient;
+i.emissive.value=d.emissive;i.specular.value=d.specular}d.wrapAround&&i.wrapRGB.value.copy(d.wrapRGB)}else if(d instanceof THREE.MeshLambertMaterial){if(C.gammaInput){i.ambient.value.copyGammaToLinear(d.ambient);i.emissive.value.copyGammaToLinear(d.emissive)}else{i.ambient.value=d.ambient;i.emissive.value=d.emissive}d.wrapAround&&i.wrapRGB.value.copy(d.wrapRGB)}else if(d instanceof THREE.MeshDepthMaterial){i.mNear.value=a.near;i.mFar.value=a.far;i.opacity.value=d.opacity}else if(d instanceof THREE.MeshNormalMaterial)i.opacity.value=
+d.opacity;if(e.receiveShadow&&!d._shadowPass&&i.shadowMatrix){f=c=0;for(k=b.length;f<k;f++){l=b[f];if(l.castShadow&&(l instanceof THREE.SpotLight||l instanceof THREE.DirectionalLight&&!l.shadowCascade)){i.shadowMap.texture[c]=l.shadowMap;i.shadowMapSize.value[c]=l.shadowMapSize;i.shadowMatrix.value[c]=l.shadowMatrix;i.shadowDarkness.value[c]=l.shadowDarkness;i.shadowBias.value[c]=l.shadowBias;c++}}}b=d.uniformsList;i=0;for(c=b.length;i<c;i++)if(l=g.uniforms[b[i][1]]){f=b[i][0];m=f.type;k=f.value;
+switch(m){case "i":j.uniform1i(l,k);break;case "f":j.uniform1f(l,k);break;case "v2":j.uniform2f(l,k.x,k.y);break;case "v3":j.uniform3f(l,k.x,k.y,k.z);break;case "v4":j.uniform4f(l,k.x,k.y,k.z,k.w);break;case "c":j.uniform3f(l,k.r,k.g,k.b);break;case "fv1":j.uniform1fv(l,k);break;case "fv":j.uniform3fv(l,k);break;case "v2v":if(!f._array)f._array=new Float32Array(2*k.length);m=0;for(n=k.length;m<n;m++){r=m*2;f._array[r]=k[m].x;f._array[r+1]=k[m].y}j.uniform2fv(l,f._array);break;case "v3v":if(!f._array)f._array=
+new Float32Array(3*k.length);m=0;for(n=k.length;m<n;m++){r=m*3;f._array[r]=k[m].x;f._array[r+1]=k[m].y;f._array[r+2]=k[m].z}j.uniform3fv(l,f._array);break;case "v4v":if(!f._array)f._array=new Float32Array(4*k.length);m=0;for(n=k.length;m<n;m++){r=m*4;f._array[r]=k[m].x;f._array[r+1]=k[m].y;f._array[r+2]=k[m].z;f._array[r+3]=k[m].w}j.uniform4fv(l,f._array);break;case "m4":if(!f._array)f._array=new Float32Array(16);k.flattenToArray(f._array);j.uniformMatrix4fv(l,false,f._array);break;case "m4v":if(!f._array)f._array=
+new Float32Array(16*k.length);m=0;for(n=k.length;m<n;m++)k[m].flattenToArrayOffset(f._array,m*16);j.uniformMatrix4fv(l,false,f._array);break;case "t":j.uniform1i(l,k);l=f.texture;if(!l)continue;if(l.image instanceof Array&&l.image.length===6){f=l;if(f.image.length===6)if(f.needsUpdate){if(!f.image.__webglTextureCube)f.image.__webglTextureCube=j.createTexture();j.activeTexture(j.TEXTURE0+k);j.bindTexture(j.TEXTURE_CUBE_MAP,f.image.__webglTextureCube);k=[];for(l=0;l<6;l++){m=k;n=l;if(C.autoScaleCubemaps){r=
+f.image[l];v=ac;if(!(r.width<=v&&r.height<=v)){u=Math.max(r.width,r.height);t=Math.floor(r.width*v/u);v=Math.floor(r.height*v/u);u=document.createElement("canvas");u.width=t;u.height=v;u.getContext("2d").drawImage(r,0,0,r.width,r.height,0,0,t,v);r=u}}else r=f.image[l];m[n]=r}l=k[0];m=(l.width&l.width-1)===0&&(l.height&l.height-1)===0;n=D(f.format);r=D(f.type);s(j.TEXTURE_CUBE_MAP,f,m);for(l=0;l<6;l++)j.texImage2D(j.TEXTURE_CUBE_MAP_POSITIVE_X+l,0,n,n,r,k[l]);f.generateMipmaps&&m&&j.generateMipmap(j.TEXTURE_CUBE_MAP);
+f.needsUpdate=false;if(f.onUpdate)f.onUpdate()}else{j.activeTexture(j.TEXTURE0+k);j.bindTexture(j.TEXTURE_CUBE_MAP,f.image.__webglTextureCube)}}else if(l instanceof THREE.WebGLRenderTargetCube){f=l;j.activeTexture(j.TEXTURE0+k);j.bindTexture(j.TEXTURE_CUBE_MAP,f.__webglTexture)}else C.setTexture(l,k);break;case "tv":if(!f._array){f._array=[];m=0;for(n=f.texture.length;m<n;m++)f._array[m]=k+m}j.uniform1iv(l,f._array);m=0;for(n=f.texture.length;m<n;m++)(l=f.texture[m])&&C.setTexture(l,f._array[m])}}if((d instanceof
+THREE.ShaderMaterial||d instanceof THREE.MeshPhongMaterial||d.envMap)&&h.cameraPosition!==null){b=a.matrixWorld.getPosition();j.uniform3f(h.cameraPosition,b.x,b.y,b.z)}(d instanceof THREE.MeshPhongMaterial||d instanceof THREE.MeshLambertMaterial||d instanceof THREE.ShaderMaterial||d.skinning)&&h.viewMatrix!==null&&j.uniformMatrix4fv(h.viewMatrix,false,a._viewMatrixArray);d.skinning&&j.uniformMatrix4fv(h.boneGlobalMatrices,false,e.boneMatrices)}j.uniformMatrix4fv(h.modelViewMatrix,false,e._modelViewMatrix.elements);
+h.normalMatrix&&j.uniformMatrix3fv(h.normalMatrix,false,e._normalMatrix.elements);h.objectMatrix!==null&&j.uniformMatrix4fv(h.objectMatrix,false,e.matrixWorld.elements);return g}function u(a,b){a._modelViewMatrix.multiply(b.matrixWorldInverse,a.matrixWorld);a._normalMatrix.getInverse(a._modelViewMatrix);a._normalMatrix.transpose()}function t(a,b,c){if(Ta!==a){a?j.enable(j.POLYGON_OFFSET_FILL):j.disable(j.POLYGON_OFFSET_FILL);Ta=a}if(a&&(eb!==b||fb!==c)){j.polygonOffset(b,c);eb=b;fb=c}}function y(a,
+b){var c;a==="fragment"?c=j.createShader(j.FRAGMENT_SHADER):a==="vertex"&&(c=j.createShader(j.VERTEX_SHADER));j.shaderSource(c,b);j.compileShader(c);if(!j.getShaderParameter(c,j.COMPILE_STATUS)){console.error(j.getShaderInfoLog(c));console.error(b);return null}return c}function s(a,b,c){if(c){j.texParameteri(a,j.TEXTURE_WRAP_S,D(b.wrapS));j.texParameteri(a,j.TEXTURE_WRAP_T,D(b.wrapT));j.texParameteri(a,j.TEXTURE_MAG_FILTER,D(b.magFilter));j.texParameteri(a,j.TEXTURE_MIN_FILTER,D(b.minFilter))}else{j.texParameteri(a,
+j.TEXTURE_WRAP_S,j.CLAMP_TO_EDGE);j.texParameteri(a,j.TEXTURE_WRAP_T,j.CLAMP_TO_EDGE);j.texParameteri(a,j.TEXTURE_MAG_FILTER,H(b.magFilter));j.texParameteri(a,j.TEXTURE_MIN_FILTER,H(b.minFilter))}}function x(a,b){j.bindRenderbuffer(j.RENDERBUFFER,a);if(b.depthBuffer&&!b.stencilBuffer){j.renderbufferStorage(j.RENDERBUFFER,j.DEPTH_COMPONENT16,b.width,b.height);j.framebufferRenderbuffer(j.FRAMEBUFFER,j.DEPTH_ATTACHMENT,j.RENDERBUFFER,a)}else if(b.depthBuffer&&b.stencilBuffer){j.renderbufferStorage(j.RENDERBUFFER,
+j.DEPTH_STENCIL,b.width,b.height);j.framebufferRenderbuffer(j.FRAMEBUFFER,j.DEPTH_STENCIL_ATTACHMENT,j.RENDERBUFFER,a)}else j.renderbufferStorage(j.RENDERBUFFER,j.RGBA4,b.width,b.height)}function H(a){switch(a){case THREE.NearestFilter:case THREE.NearestMipMapNearestFilter:case THREE.NearestMipMapLinearFilter:return j.NEAREST;default:return j.LINEAR}}function D(a){switch(a){case THREE.RepeatWrapping:return j.REPEAT;case THREE.ClampToEdgeWrapping:return j.CLAMP_TO_EDGE;case THREE.MirroredRepeatWrapping:return j.MIRRORED_REPEAT;
+case THREE.NearestFilter:return j.NEAREST;case THREE.NearestMipMapNearestFilter:return j.NEAREST_MIPMAP_NEAREST;case THREE.NearestMipMapLinearFilter:return j.NEAREST_MIPMAP_LINEAR;case THREE.LinearFilter:return j.LINEAR;case THREE.LinearMipMapNearestFilter:return j.LINEAR_MIPMAP_NEAREST;case THREE.LinearMipMapLinearFilter:return j.LINEAR_MIPMAP_LINEAR;case THREE.UnsignedByteType:return j.UNSIGNED_BYTE;case THREE.UnsignedShort4444Type:return j.UNSIGNED_SHORT_4_4_4_4;case THREE.UnsignedShort5551Type:return j.UNSIGNED_SHORT_5_5_5_1;
+case THREE.UnsignedShort565Type:return j.UNSIGNED_SHORT_5_6_5;case THREE.ByteType:return j.BYTE;case THREE.ShortType:return j.SHORT;case THREE.UnsignedShortType:return j.UNSIGNED_SHORT;case THREE.IntType:return j.INT;case THREE.UnsignedIntType:return j.UNSIGNED_INT;case THREE.FloatType:return j.FLOAT;case THREE.AlphaFormat:return j.ALPHA;case THREE.RGBFormat:return j.RGB;case THREE.RGBAFormat:return j.RGBA;case THREE.LuminanceFormat:return j.LUMINANCE;case THREE.LuminanceAlphaFormat:return j.LUMINANCE_ALPHA;
+case THREE.AddEquation:return j.FUNC_ADD;case THREE.SubtractEquation:return j.FUNC_SUBTRACT;case THREE.ReverseSubtractEquation:return j.FUNC_REVERSE_SUBTRACT;case THREE.ZeroFactor:return j.ZERO;case THREE.OneFactor:return j.ONE;case THREE.SrcColorFactor:return j.SRC_COLOR;case THREE.OneMinusSrcColorFactor:return j.ONE_MINUS_SRC_COLOR;case THREE.SrcAlphaFactor:return j.SRC_ALPHA;case THREE.OneMinusSrcAlphaFactor:return j.ONE_MINUS_SRC_ALPHA;case THREE.DstAlphaFactor:return j.DST_ALPHA;case THREE.OneMinusDstAlphaFactor:return j.ONE_MINUS_DST_ALPHA;
+case THREE.DstColorFactor:return j.DST_COLOR;case THREE.OneMinusDstColorFactor:return j.ONE_MINUS_DST_COLOR;case THREE.SrcAlphaSaturateFactor:return j.SRC_ALPHA_SATURATE}return 0}console.log("THREE.WebGLRenderer",THREE.REVISION);var a=a||{},A=a.canvas!==void 0?a.canvas:document.createElement("canvas"),v=a.precision!==void 0?a.precision:"highp",G=a.alpha!==void 0?a.alpha:true,I=a.premultipliedAlpha!==void 0?a.premultipliedAlpha:true,N=a.antialias!==void 0?a.antialias:false,R=a.stencil!==void 0?a.stencil:
+true,Y=a.preserveDrawingBuffer!==void 0?a.preserveDrawingBuffer:false,B=a.clearColor!==void 0?new THREE.Color(a.clearColor):new THREE.Color(0),F=a.clearAlpha!==void 0?a.clearAlpha:0,Q=a.maxLights!==void 0?a.maxLights:4;this.domElement=A;this.context=null;this.autoUpdateScene=this.autoUpdateObjects=this.sortObjects=this.autoClearStencil=this.autoClearDepth=this.autoClearColor=this.autoClear=true;this.shadowMapEnabled=this.physicallyBasedShading=this.gammaOutput=this.gammaInput=false;this.shadowMapCullFrontFaces=
+this.shadowMapSoft=this.shadowMapAutoUpdate=true;this.shadowMapCascade=this.shadowMapDebug=false;this.maxMorphTargets=8;this.maxMorphNormals=4;this.autoScaleCubemaps=true;this.renderPluginsPre=[];this.renderPluginsPost=[];this.info={memory:{programs:0,geometries:0,textures:0},render:{calls:0,vertices:0,faces:0,points:0}};var C=this,j,P=[],L=0,T=null,aa=null,M=-1,ca=null,fa=null,O=0,S=-1,$=-1,Z=-1,ha=-1,Sa=-1,Ma=-1,Oa=-1,oa=-1,Ta=null,eb=null,fb=null,Za=null,Lb=0,mb=0,jb=0,nb=0,ab=0,Ba=0,ya=new THREE.Frustum,
+gb=new THREE.Matrix4,wa=new THREE.Matrix4,Pa=new THREE.Vector4,Da=new THREE.Vector3,la=true,ob={ambient:[0,0,0],directional:{length:0,colors:[],positions:[]},point:{length:0,colors:[],positions:[],distances:[]},spot:{length:0,colors:[],positions:[],distances:[],directions:[],angles:[],exponents:[]}};j=function(){var a;try{if(!(a=A.getContext("experimental-webgl",{alpha:G,premultipliedAlpha:I,antialias:N,stencil:R,preserveDrawingBuffer:Y})))throw"Error creating WebGL context.";}catch(b){console.error(b)}a.getExtension("OES_texture_float")||
+console.log("THREE.WebGLRenderer: Float textures not supported.");return a}();j.clearColor(0,0,0,1);j.clearDepth(1);j.clearStencil(0);j.enable(j.DEPTH_TEST);j.depthFunc(j.LEQUAL);j.frontFace(j.CCW);j.cullFace(j.BACK);j.enable(j.CULL_FACE);j.enable(j.BLEND);j.blendEquation(j.FUNC_ADD);j.blendFunc(j.SRC_ALPHA,j.ONE_MINUS_SRC_ALPHA);j.clearColor(B.r,B.g,B.b,F);this.context=j;var $a=j.getParameter(j.MAX_VERTEX_TEXTURE_IMAGE_UNITS);j.getParameter(j.MAX_TEXTURE_SIZE);var ac=j.getParameter(j.MAX_CUBE_MAP_TEXTURE_SIZE);
+this.getContext=function(){return j};this.supportsVertexTextures=function(){return $a>0};this.setSize=function(a,b){A.width=a;A.height=b;this.setViewport(0,0,A.width,A.height)};this.setViewport=function(a,b,c,d){Lb=a;mb=b;jb=c;nb=d;j.viewport(Lb,mb,jb,nb)};this.setScissor=function(a,b,c,d){j.scissor(a,b,c,d)};this.enableScissorTest=function(a){a?j.enable(j.SCISSOR_TEST):j.disable(j.SCISSOR_TEST)};this.setClearColorHex=function(a,b){B.setHex(a);F=b;j.clearColor(B.r,B.g,B.b,F)};this.setClearColor=function(a,
+b){B.copy(a);F=b;j.clearColor(B.r,B.g,B.b,F)};this.getClearColor=function(){return B};this.getClearAlpha=function(){return F};this.clear=function(a,b,c){var d=0;if(a===void 0||a)d=d|j.COLOR_BUFFER_BIT;if(b===void 0||b)d=d|j.DEPTH_BUFFER_BIT;if(c===void 0||c)d=d|j.STENCIL_BUFFER_BIT;j.clear(d)};this.clearTarget=function(a,b,c,d){this.setRenderTarget(a);this.clear(b,c,d)};this.addPostPlugin=function(a){a.init(this);this.renderPluginsPost.push(a)};this.addPrePlugin=function(a){a.init(this);this.renderPluginsPre.push(a)};
+this.deallocateObject=function(a){if(a.__webglInit){a.__webglInit=false;delete a._modelViewMatrix;delete a._normalMatrix;delete a._normalMatrixArray;delete a._modelViewMatrixArray;delete a._objectMatrixArray;if(a instanceof THREE.Mesh)for(var b in a.geometry.geometryGroups){var c=a.geometry.geometryGroups[b];j.deleteBuffer(c.__webglVertexBuffer);j.deleteBuffer(c.__webglNormalBuffer);j.deleteBuffer(c.__webglTangentBuffer);j.deleteBuffer(c.__webglColorBuffer);j.deleteBuffer(c.__webglUVBuffer);j.deleteBuffer(c.__webglUV2Buffer);
+j.deleteBuffer(c.__webglSkinVertexABuffer);j.deleteBuffer(c.__webglSkinVertexBBuffer);j.deleteBuffer(c.__webglSkinIndicesBuffer);j.deleteBuffer(c.__webglSkinWeightsBuffer);j.deleteBuffer(c.__webglFaceBuffer);j.deleteBuffer(c.__webglLineBuffer);var d=void 0,e=void 0;if(c.numMorphTargets){d=0;for(e=c.numMorphTargets;d<e;d++)j.deleteBuffer(c.__webglMorphTargetsBuffers[d])}if(c.numMorphNormals){d=0;for(e=c.numMorphNormals;d<e;d++)j.deleteBuffer(c.__webglMorphNormalsBuffers[d])}if(c.__webglCustomAttributesList){d=
+void 0;for(d in c.__webglCustomAttributesList)j.deleteBuffer(c.__webglCustomAttributesList[d].buffer)}C.info.memory.geometries--}else if(a instanceof THREE.Ribbon){a=a.geometry;j.deleteBuffer(a.__webglVertexBuffer);j.deleteBuffer(a.__webglColorBuffer);C.info.memory.geometries--}else if(a instanceof THREE.Line){a=a.geometry;j.deleteBuffer(a.__webglVertexBuffer);j.deleteBuffer(a.__webglColorBuffer);C.info.memory.geometries--}else if(a instanceof THREE.ParticleSystem){a=a.geometry;j.deleteBuffer(a.__webglVertexBuffer);
+j.deleteBuffer(a.__webglColorBuffer);C.info.memory.geometries--}}};this.deallocateTexture=function(a){if(a.__webglInit){a.__webglInit=false;j.deleteTexture(a.__webglTexture);C.info.memory.textures--}};this.deallocateRenderTarget=function(a){if(a&&a.__webglTexture){j.deleteTexture(a.__webglTexture);if(a instanceof THREE.WebGLRenderTargetCube)for(var b=0;b<6;b++){j.deleteFramebuffer(a.__webglFramebuffer[b]);j.deleteRenderbuffer(a.__webglRenderbuffer[b])}else{j.deleteFramebuffer(a.__webglFramebuffer);
+j.deleteRenderbuffer(a.__webglRenderbuffer)}}};this.deallocateMaterial=function(a){var b=a.program;if(b){a.program=void 0;var c,d,e=false,a=0;for(c=P.length;a<c;a++){d=P[a];if(d.program===b){d.usedTimes--;d.usedTimes===0&&(e=true);break}}if(e){e=[];a=0;for(c=P.length;a<c;a++){d=P[a];d.program!==b&&e.push(d)}P=e;j.deleteProgram(b);C.info.memory.programs--}}};this.updateShadowMap=function(a,b){T=null;M=ca=oa=Oa=Z=-1;la=true;$=S=-1;this.shadowMapPlugin.update(a,b)};this.renderBufferImmediate=function(a,
+b,c){if(a.hasPositions&&!a.__webglVertexBuffer)a.__webglVertexBuffer=j.createBuffer();if(a.hasNormals&&!a.__webglNormalBuffer)a.__webglNormalBuffer=j.createBuffer();if(a.hasUvs&&!a.__webglUvBuffer)a.__webglUvBuffer=j.createBuffer();if(a.hasPositions){j.bindBuffer(j.ARRAY_BUFFER,a.__webglVertexBuffer);j.bufferData(j.ARRAY_BUFFER,a.positionArray,j.DYNAMIC_DRAW);j.enableVertexAttribArray(b.attributes.position);j.vertexAttribPointer(b.attributes.position,3,j.FLOAT,false,0,0)}if(a.hasNormals){j.bindBuffer(j.ARRAY_BUFFER,
+a.__webglNormalBuffer);if(c===THREE.FlatShading){var d,e,f,g,h,i,k,l,m,n,o=a.count*3;for(n=0;n<o;n=n+9){c=a.normalArray;d=c[n];e=c[n+1];f=c[n+2];g=c[n+3];i=c[n+4];l=c[n+5];h=c[n+6];k=c[n+7];m=c[n+8];d=(d+g+h)/3;e=(e+i+k)/3;f=(f+l+m)/3;c[n]=d;c[n+1]=e;c[n+2]=f;c[n+3]=d;c[n+4]=e;c[n+5]=f;c[n+6]=d;c[n+7]=e;c[n+8]=f}}j.bufferData(j.ARRAY_BUFFER,a.normalArray,j.DYNAMIC_DRAW);j.enableVertexAttribArray(b.attributes.normal);j.vertexAttribPointer(b.attributes.normal,3,j.FLOAT,false,0,0)}if(a.hasUvs){j.bindBuffer(j.ARRAY_BUFFER,
+a.__webglUvBuffer);j.bufferData(j.ARRAY_BUFFER,a.uvArray,j.DYNAMIC_DRAW);j.enableVertexAttribArray(b.attributes.uv);j.vertexAttribPointer(b.attributes.uv,2,j.FLOAT,false,0,0)}j.drawArrays(j.TRIANGLES,0,a.count);a.count=0};this.renderBufferDirect=function(a,b,c,d,e,f){if(d.visible!==false){c=r(a,b,c,d,f);a=c.attributes;b=false;d=e.id*16777215+c.id*2+(d.wireframe?1:0);if(d!==ca){ca=d;b=true}if(f instanceof THREE.Mesh){f=e.offsets;d=0;for(c=f.length;d<c;++d){if(b){j.bindBuffer(j.ARRAY_BUFFER,e.vertexPositionBuffer);
+j.vertexAttribPointer(a.position,e.vertexPositionBuffer.itemSize,j.FLOAT,false,0,f[d].index*12);if(a.normal>=0&&e.vertexNormalBuffer){j.bindBuffer(j.ARRAY_BUFFER,e.vertexNormalBuffer);j.vertexAttribPointer(a.normal,e.vertexNormalBuffer.itemSize,j.FLOAT,false,0,f[d].index*12)}if(a.uv>=0&&e.vertexUvBuffer)if(e.vertexUvBuffer){j.bindBuffer(j.ARRAY_BUFFER,e.vertexUvBuffer);j.vertexAttribPointer(a.uv,e.vertexUvBuffer.itemSize,j.FLOAT,false,0,f[d].index*8);j.enableVertexAttribArray(a.uv)}else j.disableVertexAttribArray(a.uv);
+if(a.color>=0&&e.vertexColorBuffer){j.bindBuffer(j.ARRAY_BUFFER,e.vertexColorBuffer);j.vertexAttribPointer(a.color,e.vertexColorBuffer.itemSize,j.FLOAT,false,0,f[d].index*16)}j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,e.vertexIndexBuffer)}j.drawElements(j.TRIANGLES,f[d].count,j.UNSIGNED_SHORT,f[d].start*2);C.info.render.calls++;C.info.render.vertices=C.info.render.vertices+f[d].count;C.info.render.faces=C.info.render.faces+f[d].count/3}}}};this.renderBuffer=function(a,b,c,d,e,f){if(d.visible!==false){var g,
+i,c=r(a,b,c,d,f),b=c.attributes,a=false,c=e.id*16777215+c.id*2+(d.wireframe?1:0);if(c!==ca){ca=c;a=true}if(!d.morphTargets&&b.position>=0){if(a){j.bindBuffer(j.ARRAY_BUFFER,e.__webglVertexBuffer);j.vertexAttribPointer(b.position,3,j.FLOAT,false,0,0)}}else if(f.morphTargetBase){c=d.program.attributes;if(f.morphTargetBase!==-1){j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[f.morphTargetBase]);j.vertexAttribPointer(c.position,3,j.FLOAT,false,0,0)}else if(c.position>=0){j.bindBuffer(j.ARRAY_BUFFER,
+e.__webglVertexBuffer);j.vertexAttribPointer(c.position,3,j.FLOAT,false,0,0)}if(f.morphTargetForcedOrder.length){var k=0;i=f.morphTargetForcedOrder;for(g=f.morphTargetInfluences;k<d.numSupportedMorphTargets&&k<i.length;){j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[i[k]]);j.vertexAttribPointer(c["morphTarget"+k],3,j.FLOAT,false,0,0);if(d.morphNormals){j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphNormalsBuffers[i[k]]);j.vertexAttribPointer(c["morphNormal"+k],3,j.FLOAT,false,0,0)}f.__webglMorphTargetInfluences[k]=
+g[i[k]];k++}}else{i=[];g=f.morphTargetInfluences;var l,m=g.length;for(l=0;l<m;l++){k=g[l];k>0&&i.push([l,k])}if(i.length>d.numSupportedMorphTargets){i.sort(h);i.length=d.numSupportedMorphTargets}else i.length>d.numSupportedMorphNormals?i.sort(h):i.length===0&&i.push([0,0]);for(k=0;k<d.numSupportedMorphTargets;){if(i[k]){l=i[k][0];j.bindBuffer(j.ARRAY_BUFFER,e.__webglMorphTargetsBuffers[l]);j.vertexAttribPointer(c["morphTarget"+k],3,j.FLOAT,false,0,0);if(d.morphNormals){j.bindBuffer(j.ARRAY_BUFFER,
+e.__webglMorphNormalsBuffers[l]);j.vertexAttribPointer(c["morphNormal"+k],3,j.FLOAT,false,0,0)}f.__webglMorphTargetInfluences[k]=g[l]}else{j.vertexAttribPointer(c["morphTarget"+k],3,j.FLOAT,false,0,0);d.morphNormals&&j.vertexAttribPointer(c["morphNormal"+k],3,j.FLOAT,false,0,0);f.__webglMorphTargetInfluences[k]=0}k++}}d.program.uniforms.morphTargetInfluences!==null&&j.uniform1fv(d.program.uniforms.morphTargetInfluences,f.__webglMorphTargetInfluences)}if(a){if(e.__webglCustomAttributesList){g=0;for(i=
+e.__webglCustomAttributesList.length;g<i;g++){c=e.__webglCustomAttributesList[g];if(b[c.buffer.belongsToAttribute]>=0){j.bindBuffer(j.ARRAY_BUFFER,c.buffer);j.vertexAttribPointer(b[c.buffer.belongsToAttribute],c.size,j.FLOAT,false,0,0)}}}if(b.color>=0){j.bindBuffer(j.ARRAY_BUFFER,e.__webglColorBuffer);j.vertexAttribPointer(b.color,3,j.FLOAT,false,0,0)}if(b.normal>=0){j.bindBuffer(j.ARRAY_BUFFER,e.__webglNormalBuffer);j.vertexAttribPointer(b.normal,3,j.FLOAT,false,0,0)}if(b.tangent>=0){j.bindBuffer(j.ARRAY_BUFFER,
+e.__webglTangentBuffer);j.vertexAttribPointer(b.tangent,4,j.FLOAT,false,0,0)}if(b.uv>=0)if(e.__webglUVBuffer){j.bindBuffer(j.ARRAY_BUFFER,e.__webglUVBuffer);j.vertexAttribPointer(b.uv,2,j.FLOAT,false,0,0);j.enableVertexAttribArray(b.uv)}else j.disableVertexAttribArray(b.uv);if(b.uv2>=0)if(e.__webglUV2Buffer){j.bindBuffer(j.ARRAY_BUFFER,e.__webglUV2Buffer);j.vertexAttribPointer(b.uv2,2,j.FLOAT,false,0,0);j.enableVertexAttribArray(b.uv2)}else j.disableVertexAttribArray(b.uv2);if(d.skinning&&b.skinVertexA>=
+0&&b.skinVertexB>=0&&b.skinIndex>=0&&b.skinWeight>=0){j.bindBuffer(j.ARRAY_BUFFER,e.__webglSkinVertexABuffer);j.vertexAttribPointer(b.skinVertexA,4,j.FLOAT,false,0,0);j.bindBuffer(j.ARRAY_BUFFER,e.__webglSkinVertexBBuffer);j.vertexAttribPointer(b.skinVertexB,4,j.FLOAT,false,0,0);j.bindBuffer(j.ARRAY_BUFFER,e.__webglSkinIndicesBuffer);j.vertexAttribPointer(b.skinIndex,4,j.FLOAT,false,0,0);j.bindBuffer(j.ARRAY_BUFFER,e.__webglSkinWeightsBuffer);j.vertexAttribPointer(b.skinWeight,4,j.FLOAT,false,0,0)}}if(f instanceof
+THREE.Mesh){if(d.wireframe){d=d.wireframeLinewidth;if(d!==Za){j.lineWidth(d);Za=d}a&&j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,e.__webglLineBuffer);j.drawElements(j.LINES,e.__webglLineCount,j.UNSIGNED_SHORT,0)}else{a&&j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,e.__webglFaceBuffer);j.drawElements(j.TRIANGLES,e.__webglFaceCount,j.UNSIGNED_SHORT,0)}C.info.render.calls++;C.info.render.vertices=C.info.render.vertices+e.__webglFaceCount;C.info.render.faces=C.info.render.faces+e.__webglFaceCount/3}else if(f instanceof
+THREE.Line){f=f.type===THREE.LineStrip?j.LINE_STRIP:j.LINES;d=d.linewidth;if(d!==Za){j.lineWidth(d);Za=d}j.drawArrays(f,0,e.__webglLineCount);C.info.render.calls++}else if(f instanceof THREE.ParticleSystem){j.drawArrays(j.POINTS,0,e.__webglParticleCount);C.info.render.calls++;C.info.render.points=C.info.render.points+e.__webglParticleCount}else if(f instanceof THREE.Ribbon){j.drawArrays(j.TRIANGLE_STRIP,0,e.__webglVertexCount);C.info.render.calls++}}};this.render=function(a,b,c,d){var e,f,h,m,n=a.__lights,
+o=a.fog;M=-1;la=true;if(b.parent===void 0){console.warn("DEPRECATED: Camera hasn't been added to a Scene. Adding it...");a.add(b)}this.autoUpdateScene&&a.updateMatrixWorld();if(!b._viewMatrixArray)b._viewMatrixArray=new Float32Array(16);if(!b._projectionMatrixArray)b._projectionMatrixArray=new Float32Array(16);b.matrixWorldInverse.getInverse(b.matrixWorld);b.matrixWorldInverse.flattenToArray(b._viewMatrixArray);b.projectionMatrix.flattenToArray(b._projectionMatrixArray);gb.multiply(b.projectionMatrix,
+b.matrixWorldInverse);ya.setFromMatrix(gb);this.autoUpdateObjects&&this.initWebGLObjects(a);i(this.renderPluginsPre,a,b);C.info.render.calls=0;C.info.render.vertices=0;C.info.render.faces=0;C.info.render.points=0;this.setRenderTarget(c);(this.autoClear||d)&&this.clear(this.autoClearColor,this.autoClearDepth,this.autoClearStencil);m=a.__webglObjects;d=0;for(e=m.length;d<e;d++){f=m[d];h=f.object;f.render=false;if(h.visible&&(!(h instanceof THREE.Mesh||h instanceof THREE.ParticleSystem)||!h.frustumCulled||
+ya.contains(h))){u(h,b);var p=f,q=p.object,r=p.buffer,s=void 0,s=s=void 0,s=q.material;if(s instanceof THREE.MeshFaceMaterial){s=r.materialIndex;if(s>=0){s=q.geometry.materials[s];if(s.transparent){p.transparent=s;p.opaque=null}else{p.opaque=s;p.transparent=null}}}else if(s)if(s.transparent){p.transparent=s;p.opaque=null}else{p.opaque=s;p.transparent=null}f.render=true;if(this.sortObjects)if(h.renderDepth)f.z=h.renderDepth;else{Pa.copy(h.matrixWorld.getPosition());gb.multiplyVector3(Pa);f.z=Pa.z}}}this.sortObjects&&
+m.sort(g);m=a.__webglObjectsImmediate;d=0;for(e=m.length;d<e;d++){f=m[d];h=f.object;if(h.visible){u(h,b);h=f.object.material;if(h.transparent){f.transparent=h;f.opaque=null}else{f.opaque=h;f.transparent=null}}}if(a.overrideMaterial){d=a.overrideMaterial;this.setBlending(d.blending,d.blendEquation,d.blendSrc,d.blendDst);this.setDepthTest(d.depthTest);this.setDepthWrite(d.depthWrite);t(d.polygonOffset,d.polygonOffsetFactor,d.polygonOffsetUnits);k(a.__webglObjects,false,"",b,n,o,true,d);l(a.__webglObjectsImmediate,
+"",b,n,o,false,d)}else{this.setBlending(THREE.NormalBlending);k(a.__webglObjects,true,"opaque",b,n,o,false);l(a.__webglObjectsImmediate,"opaque",b,n,o,false);k(a.__webglObjects,false,"transparent",b,n,o,true);l(a.__webglObjectsImmediate,"transparent",b,n,o,true)}i(this.renderPluginsPost,a,b);if(c&&c.generateMipmaps&&c.minFilter!==THREE.NearestFilter&&c.minFilter!==THREE.LinearFilter)if(c instanceof THREE.WebGLRenderTargetCube){j.bindTexture(j.TEXTURE_CUBE_MAP,c.__webglTexture);j.generateMipmap(j.TEXTURE_CUBE_MAP);
+j.bindTexture(j.TEXTURE_CUBE_MAP,null)}else{j.bindTexture(j.TEXTURE_2D,c.__webglTexture);j.generateMipmap(j.TEXTURE_2D);j.bindTexture(j.TEXTURE_2D,null)}this.setDepthTest(true);this.setDepthWrite(true)};this.renderImmediateObject=function(a,b,c,d,e){var f=r(a,b,c,d,e);ca=-1;C.setObjectFaces(e);e.immediateRenderCallback?e.immediateRenderCallback(f,j,ya):e.render(function(a){C.renderBufferImmediate(a,f,d.shading)})};this.initWebGLObjects=function(a){if(!a.__webglObjects){a.__webglObjects=[];a.__webglObjectsImmediate=
+[];a.__webglSprites=[];a.__webglFlares=[]}for(;a.__objectsAdded.length;){var g=a.__objectsAdded[0],h=a,i=void 0,k=void 0,l=void 0;if(!g.__webglInit){g.__webglInit=true;g._modelViewMatrix=new THREE.Matrix4;g._normalMatrix=new THREE.Matrix3;if(g instanceof THREE.Mesh){k=g.geometry;if(k instanceof THREE.Geometry){if(k.geometryGroups===void 0){var r=k,s=void 0,t=void 0,u=void 0,v=void 0,x=void 0,y=void 0,A=void 0,B={},D=r.morphTargets.length,G=r.morphNormals.length;r.geometryGroups={};s=0;for(t=r.faces.length;s<
+t;s++){u=r.faces[s];v=u.materialIndex;y=v!==void 0?v:-1;B[y]===void 0&&(B[y]={hash:y,counter:0});A=B[y].hash+"_"+B[y].counter;r.geometryGroups[A]===void 0&&(r.geometryGroups[A]={faces3:[],faces4:[],materialIndex:v,vertices:0,numMorphTargets:D,numMorphNormals:G});x=u instanceof THREE.Face3?3:4;if(r.geometryGroups[A].vertices+x>65535){B[y].counter=B[y].counter+1;A=B[y].hash+"_"+B[y].counter;r.geometryGroups[A]===void 0&&(r.geometryGroups[A]={faces3:[],faces4:[],materialIndex:v,vertices:0,numMorphTargets:D,
+numMorphNormals:G})}u instanceof THREE.Face3?r.geometryGroups[A].faces3.push(s):r.geometryGroups[A].faces4.push(s);r.geometryGroups[A].vertices=r.geometryGroups[A].vertices+x}r.geometryGroupsList=[];var M=void 0;for(M in r.geometryGroups){r.geometryGroups[M].id=O++;r.geometryGroupsList.push(r.geometryGroups[M])}}for(i in k.geometryGroups){l=k.geometryGroups[i];if(!l.__webglVertexBuffer){var S=l;S.__webglVertexBuffer=j.createBuffer();S.__webglNormalBuffer=j.createBuffer();S.__webglTangentBuffer=j.createBuffer();
+S.__webglColorBuffer=j.createBuffer();S.__webglUVBuffer=j.createBuffer();S.__webglUV2Buffer=j.createBuffer();S.__webglSkinVertexABuffer=j.createBuffer();S.__webglSkinVertexBBuffer=j.createBuffer();S.__webglSkinIndicesBuffer=j.createBuffer();S.__webglSkinWeightsBuffer=j.createBuffer();S.__webglFaceBuffer=j.createBuffer();S.__webglLineBuffer=j.createBuffer();var H=void 0,I=void 0;if(S.numMorphTargets){S.__webglMorphTargetsBuffers=[];H=0;for(I=S.numMorphTargets;H<I;H++)S.__webglMorphTargetsBuffers.push(j.createBuffer())}if(S.numMorphNormals){S.__webglMorphNormalsBuffers=
+[];H=0;for(I=S.numMorphNormals;H<I;H++)S.__webglMorphNormalsBuffers.push(j.createBuffer())}C.info.memory.geometries++;var F=l,N=g,L=N.geometry,Z=F.faces3,$=F.faces4,T=Z.length*3+$.length*4,Q=Z.length*1+$.length*2,P=Z.length*3+$.length*4,R=c(N,F),aa=e(R),Y=d(R),fa=R.vertexColors?R.vertexColors:false;F.__vertexArray=new Float32Array(T*3);if(Y)F.__normalArray=new Float32Array(T*3);if(L.hasTangents)F.__tangentArray=new Float32Array(T*4);if(fa)F.__colorArray=new Float32Array(T*3);if(aa){if(L.faceUvs.length>
+0||L.faceVertexUvs.length>0)F.__uvArray=new Float32Array(T*2);if(L.faceUvs.length>1||L.faceVertexUvs.length>1)F.__uv2Array=new Float32Array(T*2)}if(N.geometry.skinWeights.length&&N.geometry.skinIndices.length){F.__skinVertexAArray=new Float32Array(T*4);F.__skinVertexBArray=new Float32Array(T*4);F.__skinIndexArray=new Float32Array(T*4);F.__skinWeightArray=new Float32Array(T*4)}F.__faceArray=new Uint16Array(Q*3);F.__lineArray=new Uint16Array(P*2);var ca=void 0,ha=void 0;if(F.numMorphTargets){F.__morphTargetsArrays=
+[];ca=0;for(ha=F.numMorphTargets;ca<ha;ca++)F.__morphTargetsArrays.push(new Float32Array(T*3))}if(F.numMorphNormals){F.__morphNormalsArrays=[];ca=0;for(ha=F.numMorphNormals;ca<ha;ca++)F.__morphNormalsArrays.push(new Float32Array(T*3))}F.__webglFaceCount=Q*3;F.__webglLineCount=P*2;if(R.attributes){if(F.__webglCustomAttributesList===void 0)F.__webglCustomAttributesList=[];var Oa=void 0;for(Oa in R.attributes){var Sa=R.attributes[Oa],oa={},la;for(la in Sa)oa[la]=Sa[la];if(!oa.__webglInitialized||oa.createUniqueBuffers){oa.__webglInitialized=
+true;var Ma=1;oa.type==="v2"?Ma=2:oa.type==="v3"?Ma=3:oa.type==="v4"?Ma=4:oa.type==="c"&&(Ma=3);oa.size=Ma;oa.array=new Float32Array(T*Ma);oa.buffer=j.createBuffer();oa.buffer.belongsToAttribute=Oa;Sa.needsUpdate=true;oa.__original=Sa}F.__webglCustomAttributesList.push(oa)}}F.__inittedArrays=true;k.verticesNeedUpdate=true;k.morphTargetsNeedUpdate=true;k.elementsNeedUpdate=true;k.uvsNeedUpdate=true;k.normalsNeedUpdate=true;k.tangetsNeedUpdate=true;k.colorsNeedUpdate=true}}}}else if(g instanceof THREE.Ribbon){k=
+g.geometry;if(!k.__webglVertexBuffer){var Ta=k;Ta.__webglVertexBuffer=j.createBuffer();Ta.__webglColorBuffer=j.createBuffer();C.info.memory.geometries++;var wa=k,ya=wa.vertices.length;wa.__vertexArray=new Float32Array(ya*3);wa.__colorArray=new Float32Array(ya*3);wa.__webglVertexCount=ya;k.verticesNeedUpdate=true;k.colorsNeedUpdate=true}}else if(g instanceof THREE.Line){k=g.geometry;if(!k.__webglVertexBuffer){var Da=k;Da.__webglVertexBuffer=j.createBuffer();Da.__webglColorBuffer=j.createBuffer();C.info.memory.geometries++;
+var Ba=k,eb=g,Pa=Ba.vertices.length;Ba.__vertexArray=new Float32Array(Pa*3);Ba.__colorArray=new Float32Array(Pa*3);Ba.__webglLineCount=Pa;b(Ba,eb);k.verticesNeedUpdate=true;k.colorsNeedUpdate=true}}else if(g instanceof THREE.ParticleSystem){k=g.geometry;if(!k.__webglVertexBuffer){var ab=k;ab.__webglVertexBuffer=j.createBuffer();ab.__webglColorBuffer=j.createBuffer();C.info.geometries++;var Za=k,Lb=g,mb=Za.vertices.length;Za.__vertexArray=new Float32Array(mb*3);Za.__colorArray=new Float32Array(mb*
+3);Za.__sortArray=[];Za.__webglParticleCount=mb;b(Za,Lb);k.verticesNeedUpdate=true;k.colorsNeedUpdate=true}}}if(!g.__webglActive){if(g instanceof THREE.Mesh){k=g.geometry;if(k instanceof THREE.BufferGeometry)o(h.__webglObjects,k,g);else for(i in k.geometryGroups){l=k.geometryGroups[i];o(h.__webglObjects,l,g)}}else if(g instanceof THREE.Ribbon||g instanceof THREE.Line||g instanceof THREE.ParticleSystem){k=g.geometry;o(h.__webglObjects,k,g)}else g instanceof THREE.ImmediateRenderObject||g.immediateRenderCallback?
+h.__webglObjectsImmediate.push({object:g,opaque:null,transparent:null}):g instanceof THREE.Sprite?h.__webglSprites.push(g):g instanceof THREE.LensFlare&&h.__webglFlares.push(g);g.__webglActive=true}a.__objectsAdded.splice(0,1)}for(;a.__objectsRemoved.length;){var bb=a.__objectsRemoved[0],jb=a;bb instanceof THREE.Mesh||bb instanceof THREE.ParticleSystem||bb instanceof THREE.Ribbon||bb instanceof THREE.Line?q(jb.__webglObjects,bb):bb instanceof THREE.Sprite?n(jb.__webglSprites,bb):bb instanceof THREE.LensFlare?
+n(jb.__webglFlares,bb):(bb instanceof THREE.ImmediateRenderObject||bb.immediateRenderCallback)&&q(jb.__webglObjectsImmediate,bb);bb.__webglActive=false;a.__objectsRemoved.splice(0,1)}for(var gb=0,ob=a.__webglObjects.length;gb<ob;gb++){var kb=a.__webglObjects[gb].object,ga=kb.geometry,$a=void 0,fb=void 0,Ua=void 0;if(kb instanceof THREE.Mesh)if(ga instanceof THREE.BufferGeometry){ga.verticesNeedUpdate=false;ga.elementsNeedUpdate=false;ga.uvsNeedUpdate=false;ga.normalsNeedUpdate=false;ga.colorsNeedUpdate=
+false}else{for(var nb=0,ac=ga.geometryGroupsList.length;nb<ac;nb++){$a=ga.geometryGroupsList[nb];Ua=c(kb,$a);fb=Ua.attributes&&m(Ua);if(ga.verticesNeedUpdate||ga.morphTargetsNeedUpdate||ga.elementsNeedUpdate||ga.uvsNeedUpdate||ga.normalsNeedUpdate||ga.colorsNeedUpdate||ga.tangetsNeedUpdate||fb){var da=$a,nd=kb,Wa=j.DYNAMIC_DRAW,od=!ga.dynamic,cc=Ua;if(da.__inittedArrays){var cd=d(cc),Tc=cc.vertexColors?cc.vertexColors:false,dd=e(cc),Ec=cd===THREE.SmoothShading,E=void 0,U=void 0,ib=void 0,K=void 0,
+jc=void 0,Ob=void 0,lb=void 0,Fc=void 0,Gb=void 0,kc=void 0,lc=void 0,V=void 0,W=void 0,X=void 0,ma=void 0,pb=void 0,qb=void 0,rb=void 0,qc=void 0,sb=void 0,tb=void 0,ub=void 0,rc=void 0,vb=void 0,wb=void 0,xb=void 0,sc=void 0,yb=void 0,zb=void 0,Ab=void 0,tc=void 0,Bb=void 0,Cb=void 0,Db=void 0,uc=void 0,Pb=void 0,Qb=void 0,Rb=void 0,Gc=void 0,Sb=void 0,Tb=void 0,Ub=void 0,Hc=void 0,ia=void 0,ed=void 0,Vb=void 0,mc=void 0,nc=void 0,Ga=void 0,fd=void 0,Ea=void 0,Fa=void 0,Wb=void 0,Hb=void 0,xa=0,
+Ca=0,Ib=0,Jb=0,cb=0,Na=0,na=0,Qa=0,za=0,J=0,ba=0,z=0,Xa=void 0,Ha=da.__vertexArray,vc=da.__uvArray,wc=da.__uv2Array,db=da.__normalArray,qa=da.__tangentArray,Ia=da.__colorArray,ra=da.__skinVertexAArray,sa=da.__skinVertexBArray,ta=da.__skinIndexArray,ua=da.__skinWeightArray,Uc=da.__morphTargetsArrays,Vc=da.__morphNormalsArrays,Wc=da.__webglCustomAttributesList,w=void 0,Eb=da.__faceArray,Ya=da.__lineArray,Ra=nd.geometry,pd=Ra.elementsNeedUpdate,gd=Ra.uvsNeedUpdate,qd=Ra.normalsNeedUpdate,rd=Ra.tangetsNeedUpdate,
+sd=Ra.colorsNeedUpdate,td=Ra.morphTargetsNeedUpdate,dc=Ra.vertices,ja=da.faces3,ka=da.faces4,Aa=Ra.faces,Xc=Ra.faceVertexUvs[0],Yc=Ra.faceVertexUvs[1],ec=Ra.skinVerticesA,fc=Ra.skinVerticesB,gc=Ra.skinIndices,Xb=Ra.skinWeights,Yb=Ra.morphTargets,Ic=Ra.morphNormals;if(Ra.verticesNeedUpdate){E=0;for(U=ja.length;E<U;E++){K=Aa[ja[E]];V=dc[K.a];W=dc[K.b];X=dc[K.c];Ha[Ca]=V.x;Ha[Ca+1]=V.y;Ha[Ca+2]=V.z;Ha[Ca+3]=W.x;Ha[Ca+4]=W.y;Ha[Ca+5]=W.z;Ha[Ca+6]=X.x;Ha[Ca+7]=X.y;Ha[Ca+8]=X.z;Ca=Ca+9}E=0;for(U=ka.length;E<
+U;E++){K=Aa[ka[E]];V=dc[K.a];W=dc[K.b];X=dc[K.c];ma=dc[K.d];Ha[Ca]=V.x;Ha[Ca+1]=V.y;Ha[Ca+2]=V.z;Ha[Ca+3]=W.x;Ha[Ca+4]=W.y;Ha[Ca+5]=W.z;Ha[Ca+6]=X.x;Ha[Ca+7]=X.y;Ha[Ca+8]=X.z;Ha[Ca+9]=ma.x;Ha[Ca+10]=ma.y;Ha[Ca+11]=ma.z;Ca=Ca+12}j.bindBuffer(j.ARRAY_BUFFER,da.__webglVertexBuffer);j.bufferData(j.ARRAY_BUFFER,Ha,Wa)}if(td){Ga=0;for(fd=Yb.length;Ga<fd;Ga++){E=ba=0;for(U=ja.length;E<U;E++){Wb=ja[E];K=Aa[Wb];V=Yb[Ga].vertices[K.a];W=Yb[Ga].vertices[K.b];X=Yb[Ga].vertices[K.c];Ea=Uc[Ga];Ea[ba]=V.x;Ea[ba+
+1]=V.y;Ea[ba+2]=V.z;Ea[ba+3]=W.x;Ea[ba+4]=W.y;Ea[ba+5]=W.z;Ea[ba+6]=X.x;Ea[ba+7]=X.y;Ea[ba+8]=X.z;if(cc.morphNormals){if(Ec){Hb=Ic[Ga].vertexNormals[Wb];sb=Hb.a;tb=Hb.b;ub=Hb.c}else ub=tb=sb=Ic[Ga].faceNormals[Wb];Fa=Vc[Ga];Fa[ba]=sb.x;Fa[ba+1]=sb.y;Fa[ba+2]=sb.z;Fa[ba+3]=tb.x;Fa[ba+4]=tb.y;Fa[ba+5]=tb.z;Fa[ba+6]=ub.x;Fa[ba+7]=ub.y;Fa[ba+8]=ub.z}ba=ba+9}E=0;for(U=ka.length;E<U;E++){Wb=ka[E];K=Aa[Wb];V=Yb[Ga].vertices[K.a];W=Yb[Ga].vertices[K.b];X=Yb[Ga].vertices[K.c];ma=Yb[Ga].vertices[K.d];Ea=Uc[Ga];
+Ea[ba]=V.x;Ea[ba+1]=V.y;Ea[ba+2]=V.z;Ea[ba+3]=W.x;Ea[ba+4]=W.y;Ea[ba+5]=W.z;Ea[ba+6]=X.x;Ea[ba+7]=X.y;Ea[ba+8]=X.z;Ea[ba+9]=ma.x;Ea[ba+10]=ma.y;Ea[ba+11]=ma.z;if(cc.morphNormals){if(Ec){Hb=Ic[Ga].vertexNormals[Wb];sb=Hb.a;tb=Hb.b;ub=Hb.c;rc=Hb.d}else rc=ub=tb=sb=Ic[Ga].faceNormals[Wb];Fa=Vc[Ga];Fa[ba]=sb.x;Fa[ba+1]=sb.y;Fa[ba+2]=sb.z;Fa[ba+3]=tb.x;Fa[ba+4]=tb.y;Fa[ba+5]=tb.z;Fa[ba+6]=ub.x;Fa[ba+7]=ub.y;Fa[ba+8]=ub.z;Fa[ba+9]=rc.x;Fa[ba+10]=rc.y;Fa[ba+11]=rc.z}ba=ba+12}j.bindBuffer(j.ARRAY_BUFFER,
+da.__webglMorphTargetsBuffers[Ga]);j.bufferData(j.ARRAY_BUFFER,Uc[Ga],Wa);if(cc.morphNormals){j.bindBuffer(j.ARRAY_BUFFER,da.__webglMorphNormalsBuffers[Ga]);j.bufferData(j.ARRAY_BUFFER,Vc[Ga],Wa)}}}if(Xb.length){E=0;for(U=ja.length;E<U;E++){K=Aa[ja[E]];yb=Xb[K.a];zb=Xb[K.b];Ab=Xb[K.c];ua[J]=yb.x;ua[J+1]=yb.y;ua[J+2]=yb.z;ua[J+3]=yb.w;ua[J+4]=zb.x;ua[J+5]=zb.y;ua[J+6]=zb.z;ua[J+7]=zb.w;ua[J+8]=Ab.x;ua[J+9]=Ab.y;ua[J+10]=Ab.z;ua[J+11]=Ab.w;Bb=gc[K.a];Cb=gc[K.b];Db=gc[K.c];ta[J]=Bb.x;ta[J+1]=Bb.y;ta[J+
+2]=Bb.z;ta[J+3]=Bb.w;ta[J+4]=Cb.x;ta[J+5]=Cb.y;ta[J+6]=Cb.z;ta[J+7]=Cb.w;ta[J+8]=Db.x;ta[J+9]=Db.y;ta[J+10]=Db.z;ta[J+11]=Db.w;Pb=ec[K.a];Qb=ec[K.b];Rb=ec[K.c];ra[J]=Pb.x;ra[J+1]=Pb.y;ra[J+2]=Pb.z;ra[J+3]=1;ra[J+4]=Qb.x;ra[J+5]=Qb.y;ra[J+6]=Qb.z;ra[J+7]=1;ra[J+8]=Rb.x;ra[J+9]=Rb.y;ra[J+10]=Rb.z;ra[J+11]=1;Sb=fc[K.a];Tb=fc[K.b];Ub=fc[K.c];sa[J]=Sb.x;sa[J+1]=Sb.y;sa[J+2]=Sb.z;sa[J+3]=1;sa[J+4]=Tb.x;sa[J+5]=Tb.y;sa[J+6]=Tb.z;sa[J+7]=1;sa[J+8]=Ub.x;sa[J+9]=Ub.y;sa[J+10]=Ub.z;sa[J+11]=1;J=J+12}E=0;for(U=
+ka.length;E<U;E++){K=Aa[ka[E]];yb=Xb[K.a];zb=Xb[K.b];Ab=Xb[K.c];tc=Xb[K.d];ua[J]=yb.x;ua[J+1]=yb.y;ua[J+2]=yb.z;ua[J+3]=yb.w;ua[J+4]=zb.x;ua[J+5]=zb.y;ua[J+6]=zb.z;ua[J+7]=zb.w;ua[J+8]=Ab.x;ua[J+9]=Ab.y;ua[J+10]=Ab.z;ua[J+11]=Ab.w;ua[J+12]=tc.x;ua[J+13]=tc.y;ua[J+14]=tc.z;ua[J+15]=tc.w;Bb=gc[K.a];Cb=gc[K.b];Db=gc[K.c];uc=gc[K.d];ta[J]=Bb.x;ta[J+1]=Bb.y;ta[J+2]=Bb.z;ta[J+3]=Bb.w;ta[J+4]=Cb.x;ta[J+5]=Cb.y;ta[J+6]=Cb.z;ta[J+7]=Cb.w;ta[J+8]=Db.x;ta[J+9]=Db.y;ta[J+10]=Db.z;ta[J+11]=Db.w;ta[J+12]=uc.x;
+ta[J+13]=uc.y;ta[J+14]=uc.z;ta[J+15]=uc.w;Pb=ec[K.a];Qb=ec[K.b];Rb=ec[K.c];Gc=ec[K.d];ra[J]=Pb.x;ra[J+1]=Pb.y;ra[J+2]=Pb.z;ra[J+3]=1;ra[J+4]=Qb.x;ra[J+5]=Qb.y;ra[J+6]=Qb.z;ra[J+7]=1;ra[J+8]=Rb.x;ra[J+9]=Rb.y;ra[J+10]=Rb.z;ra[J+11]=1;ra[J+12]=Gc.x;ra[J+13]=Gc.y;ra[J+14]=Gc.z;ra[J+15]=1;Sb=fc[K.a];Tb=fc[K.b];Ub=fc[K.c];Hc=fc[K.d];sa[J]=Sb.x;sa[J+1]=Sb.y;sa[J+2]=Sb.z;sa[J+3]=1;sa[J+4]=Tb.x;sa[J+5]=Tb.y;sa[J+6]=Tb.z;sa[J+7]=1;sa[J+8]=Ub.x;sa[J+9]=Ub.y;sa[J+10]=Ub.z;sa[J+11]=1;sa[J+12]=Hc.x;sa[J+13]=Hc.y;
+sa[J+14]=Hc.z;sa[J+15]=1;J=J+16}if(J>0){j.bindBuffer(j.ARRAY_BUFFER,da.__webglSkinVertexABuffer);j.bufferData(j.ARRAY_BUFFER,ra,Wa);j.bindBuffer(j.ARRAY_BUFFER,da.__webglSkinVertexBBuffer);j.bufferData(j.ARRAY_BUFFER,sa,Wa);j.bindBuffer(j.ARRAY_BUFFER,da.__webglSkinIndicesBuffer);j.bufferData(j.ARRAY_BUFFER,ta,Wa);j.bindBuffer(j.ARRAY_BUFFER,da.__webglSkinWeightsBuffer);j.bufferData(j.ARRAY_BUFFER,ua,Wa)}}if(sd&&Tc){E=0;for(U=ja.length;E<U;E++){K=Aa[ja[E]];lb=K.vertexColors;Fc=K.color;if(lb.length===
+3&&Tc===THREE.VertexColors){vb=lb[0];wb=lb[1];xb=lb[2]}else xb=wb=vb=Fc;Ia[za]=vb.r;Ia[za+1]=vb.g;Ia[za+2]=vb.b;Ia[za+3]=wb.r;Ia[za+4]=wb.g;Ia[za+5]=wb.b;Ia[za+6]=xb.r;Ia[za+7]=xb.g;Ia[za+8]=xb.b;za=za+9}E=0;for(U=ka.length;E<U;E++){K=Aa[ka[E]];lb=K.vertexColors;Fc=K.color;if(lb.length===4&&Tc===THREE.VertexColors){vb=lb[0];wb=lb[1];xb=lb[2];sc=lb[3]}else sc=xb=wb=vb=Fc;Ia[za]=vb.r;Ia[za+1]=vb.g;Ia[za+2]=vb.b;Ia[za+3]=wb.r;Ia[za+4]=wb.g;Ia[za+5]=wb.b;Ia[za+6]=xb.r;Ia[za+7]=xb.g;Ia[za+8]=xb.b;Ia[za+
+9]=sc.r;Ia[za+10]=sc.g;Ia[za+11]=sc.b;za=za+12}if(za>0){j.bindBuffer(j.ARRAY_BUFFER,da.__webglColorBuffer);j.bufferData(j.ARRAY_BUFFER,Ia,Wa)}}if(rd&&Ra.hasTangents){E=0;for(U=ja.length;E<U;E++){K=Aa[ja[E]];Gb=K.vertexTangents;pb=Gb[0];qb=Gb[1];rb=Gb[2];qa[na]=pb.x;qa[na+1]=pb.y;qa[na+2]=pb.z;qa[na+3]=pb.w;qa[na+4]=qb.x;qa[na+5]=qb.y;qa[na+6]=qb.z;qa[na+7]=qb.w;qa[na+8]=rb.x;qa[na+9]=rb.y;qa[na+10]=rb.z;qa[na+11]=rb.w;na=na+12}E=0;for(U=ka.length;E<U;E++){K=Aa[ka[E]];Gb=K.vertexTangents;pb=Gb[0];
+qb=Gb[1];rb=Gb[2];qc=Gb[3];qa[na]=pb.x;qa[na+1]=pb.y;qa[na+2]=pb.z;qa[na+3]=pb.w;qa[na+4]=qb.x;qa[na+5]=qb.y;qa[na+6]=qb.z;qa[na+7]=qb.w;qa[na+8]=rb.x;qa[na+9]=rb.y;qa[na+10]=rb.z;qa[na+11]=rb.w;qa[na+12]=qc.x;qa[na+13]=qc.y;qa[na+14]=qc.z;qa[na+15]=qc.w;na=na+16}j.bindBuffer(j.ARRAY_BUFFER,da.__webglTangentBuffer);j.bufferData(j.ARRAY_BUFFER,qa,Wa)}if(qd&&cd){E=0;for(U=ja.length;E<U;E++){K=Aa[ja[E]];jc=K.vertexNormals;Ob=K.normal;if(jc.length===3&&Ec)for(ia=0;ia<3;ia++){Vb=jc[ia];db[Na]=Vb.x;db[Na+
+1]=Vb.y;db[Na+2]=Vb.z;Na=Na+3}else for(ia=0;ia<3;ia++){db[Na]=Ob.x;db[Na+1]=Ob.y;db[Na+2]=Ob.z;Na=Na+3}}E=0;for(U=ka.length;E<U;E++){K=Aa[ka[E]];jc=K.vertexNormals;Ob=K.normal;if(jc.length===4&&Ec)for(ia=0;ia<4;ia++){Vb=jc[ia];db[Na]=Vb.x;db[Na+1]=Vb.y;db[Na+2]=Vb.z;Na=Na+3}else for(ia=0;ia<4;ia++){db[Na]=Ob.x;db[Na+1]=Ob.y;db[Na+2]=Ob.z;Na=Na+3}}j.bindBuffer(j.ARRAY_BUFFER,da.__webglNormalBuffer);j.bufferData(j.ARRAY_BUFFER,db,Wa)}if(gd&&Xc&&dd){E=0;for(U=ja.length;E<U;E++){ib=ja[E];K=Aa[ib];kc=
+Xc[ib];if(kc!==void 0)for(ia=0;ia<3;ia++){mc=kc[ia];vc[Ib]=mc.u;vc[Ib+1]=mc.v;Ib=Ib+2}}E=0;for(U=ka.length;E<U;E++){ib=ka[E];K=Aa[ib];kc=Xc[ib];if(kc!==void 0)for(ia=0;ia<4;ia++){mc=kc[ia];vc[Ib]=mc.u;vc[Ib+1]=mc.v;Ib=Ib+2}}if(Ib>0){j.bindBuffer(j.ARRAY_BUFFER,da.__webglUVBuffer);j.bufferData(j.ARRAY_BUFFER,vc,Wa)}}if(gd&&Yc&&dd){E=0;for(U=ja.length;E<U;E++){ib=ja[E];K=Aa[ib];lc=Yc[ib];if(lc!==void 0)for(ia=0;ia<3;ia++){nc=lc[ia];wc[Jb]=nc.u;wc[Jb+1]=nc.v;Jb=Jb+2}}E=0;for(U=ka.length;E<U;E++){ib=
+ka[E];K=Aa[ib];lc=Yc[ib];if(lc!==void 0)for(ia=0;ia<4;ia++){nc=lc[ia];wc[Jb]=nc.u;wc[Jb+1]=nc.v;Jb=Jb+2}}if(Jb>0){j.bindBuffer(j.ARRAY_BUFFER,da.__webglUV2Buffer);j.bufferData(j.ARRAY_BUFFER,wc,Wa)}}if(pd){E=0;for(U=ja.length;E<U;E++){K=Aa[ja[E]];Eb[cb]=xa;Eb[cb+1]=xa+1;Eb[cb+2]=xa+2;cb=cb+3;Ya[Qa]=xa;Ya[Qa+1]=xa+1;Ya[Qa+2]=xa;Ya[Qa+3]=xa+2;Ya[Qa+4]=xa+1;Ya[Qa+5]=xa+2;Qa=Qa+6;xa=xa+3}E=0;for(U=ka.length;E<U;E++){K=Aa[ka[E]];Eb[cb]=xa;Eb[cb+1]=xa+1;Eb[cb+2]=xa+3;Eb[cb+3]=xa+1;Eb[cb+4]=xa+2;Eb[cb+5]=
+xa+3;cb=cb+6;Ya[Qa]=xa;Ya[Qa+1]=xa+1;Ya[Qa+2]=xa;Ya[Qa+3]=xa+3;Ya[Qa+4]=xa+1;Ya[Qa+5]=xa+2;Ya[Qa+6]=xa+2;Ya[Qa+7]=xa+3;Qa=Qa+8;xa=xa+4}j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,da.__webglFaceBuffer);j.bufferData(j.ELEMENT_ARRAY_BUFFER,Eb,Wa);j.bindBuffer(j.ELEMENT_ARRAY_BUFFER,da.__webglLineBuffer);j.bufferData(j.ELEMENT_ARRAY_BUFFER,Ya,Wa)}if(Wc){ia=0;for(ed=Wc.length;ia<ed;ia++){w=Wc[ia];if(w.__original.needsUpdate){z=0;if(w.size===1)if(w.boundTo===void 0||w.boundTo==="vertices"){E=0;for(U=ja.length;E<
+U;E++){K=Aa[ja[E]];w.array[z]=w.value[K.a];w.array[z+1]=w.value[K.b];w.array[z+2]=w.value[K.c];z=z+3}E=0;for(U=ka.length;E<U;E++){K=Aa[ka[E]];w.array[z]=w.value[K.a];w.array[z+1]=w.value[K.b];w.array[z+2]=w.value[K.c];w.array[z+3]=w.value[K.d];z=z+4}}else{if(w.boundTo==="faces"){E=0;for(U=ja.length;E<U;E++){Xa=w.value[ja[E]];w.array[z]=Xa;w.array[z+1]=Xa;w.array[z+2]=Xa;z=z+3}E=0;for(U=ka.length;E<U;E++){Xa=w.value[ka[E]];w.array[z]=Xa;w.array[z+1]=Xa;w.array[z+2]=Xa;w.array[z+3]=Xa;z=z+4}}}else if(w.size===
+2)if(w.boundTo===void 0||w.boundTo==="vertices"){E=0;for(U=ja.length;E<U;E++){K=Aa[ja[E]];V=w.value[K.a];W=w.value[K.b];X=w.value[K.c];w.array[z]=V.x;w.array[z+1]=V.y;w.array[z+2]=W.x;w.array[z+3]=W.y;w.array[z+4]=X.x;w.array[z+5]=X.y;z=z+6}E=0;for(U=ka.length;E<U;E++){K=Aa[ka[E]];V=w.value[K.a];W=w.value[K.b];X=w.value[K.c];ma=w.value[K.d];w.array[z]=V.x;w.array[z+1]=V.y;w.array[z+2]=W.x;w.array[z+3]=W.y;w.array[z+4]=X.x;w.array[z+5]=X.y;w.array[z+6]=ma.x;w.array[z+7]=ma.y;z=z+8}}else{if(w.boundTo===
+"faces"){E=0;for(U=ja.length;E<U;E++){X=W=V=Xa=w.value[ja[E]];w.array[z]=V.x;w.array[z+1]=V.y;w.array[z+2]=W.x;w.array[z+3]=W.y;w.array[z+4]=X.x;w.array[z+5]=X.y;z=z+6}E=0;for(U=ka.length;E<U;E++){ma=X=W=V=Xa=w.value[ka[E]];w.array[z]=V.x;w.array[z+1]=V.y;w.array[z+2]=W.x;w.array[z+3]=W.y;w.array[z+4]=X.x;w.array[z+5]=X.y;w.array[z+6]=ma.x;w.array[z+7]=ma.y;z=z+8}}}else if(w.size===3){var ea;ea=w.type==="c"?["r","g","b"]:["x","y","z"];if(w.boundTo===void 0||w.boundTo==="vertices"){E=0;for(U=ja.length;E<
+U;E++){K=Aa[ja[E]];V=w.value[K.a];W=w.value[K.b];X=w.value[K.c];w.array[z]=V[ea[0]];w.array[z+1]=V[ea[1]];w.array[z+2]=V[ea[2]];w.array[z+3]=W[ea[0]];w.array[z+4]=W[ea[1]];w.array[z+5]=W[ea[2]];w.array[z+6]=X[ea[0]];w.array[z+7]=X[ea[1]];w.array[z+8]=X[ea[2]];z=z+9}E=0;for(U=ka.length;E<U;E++){K=Aa[ka[E]];V=w.value[K.a];W=w.value[K.b];X=w.value[K.c];ma=w.value[K.d];w.array[z]=V[ea[0]];w.array[z+1]=V[ea[1]];w.array[z+2]=V[ea[2]];w.array[z+3]=W[ea[0]];w.array[z+4]=W[ea[1]];w.array[z+5]=W[ea[2]];w.array[z+
+6]=X[ea[0]];w.array[z+7]=X[ea[1]];w.array[z+8]=X[ea[2]];w.array[z+9]=ma[ea[0]];w.array[z+10]=ma[ea[1]];w.array[z+11]=ma[ea[2]];z=z+12}}else if(w.boundTo==="faces"){E=0;for(U=ja.length;E<U;E++){X=W=V=Xa=w.value[ja[E]];w.array[z]=V[ea[0]];w.array[z+1]=V[ea[1]];w.array[z+2]=V[ea[2]];w.array[z+3]=W[ea[0]];w.array[z+4]=W[ea[1]];w.array[z+5]=W[ea[2]];w.array[z+6]=X[ea[0]];w.array[z+7]=X[ea[1]];w.array[z+8]=X[ea[2]];z=z+9}E=0;for(U=ka.length;E<U;E++){ma=X=W=V=Xa=w.value[ka[E]];w.array[z]=V[ea[0]];w.array[z+
+1]=V[ea[1]];w.array[z+2]=V[ea[2]];w.array[z+3]=W[ea[0]];w.array[z+4]=W[ea[1]];w.array[z+5]=W[ea[2]];w.array[z+6]=X[ea[0]];w.array[z+7]=X[ea[1]];w.array[z+8]=X[ea[2]];w.array[z+9]=ma[ea[0]];w.array[z+10]=ma[ea[1]];w.array[z+11]=ma[ea[2]];z=z+12}}}else if(w.size===4)if(w.boundTo===void 0||w.boundTo==="vertices"){E=0;for(U=ja.length;E<U;E++){K=Aa[ja[E]];V=w.value[K.a];W=w.value[K.b];X=w.value[K.c];w.array[z]=V.x;w.array[z+1]=V.y;w.array[z+2]=V.z;w.array[z+3]=V.w;w.array[z+4]=W.x;w.array[z+5]=W.y;w.array[z+
+6]=W.z;w.array[z+7]=W.w;w.array[z+8]=X.x;w.array[z+9]=X.y;w.array[z+10]=X.z;w.array[z+11]=X.w;z=z+12}E=0;for(U=ka.length;E<U;E++){K=Aa[ka[E]];V=w.value[K.a];W=w.value[K.b];X=w.value[K.c];ma=w.value[K.d];w.array[z]=V.x;w.array[z+1]=V.y;w.array[z+2]=V.z;w.array[z+3]=V.w;w.array[z+4]=W.x;w.array[z+5]=W.y;w.array[z+6]=W.z;w.array[z+7]=W.w;w.array[z+8]=X.x;w.array[z+9]=X.y;w.array[z+10]=X.z;w.array[z+11]=X.w;w.array[z+12]=ma.x;w.array[z+13]=ma.y;w.array[z+14]=ma.z;w.array[z+15]=ma.w;z=z+16}}else if(w.boundTo===
+"faces"){E=0;for(U=ja.length;E<U;E++){X=W=V=Xa=w.value[ja[E]];w.array[z]=V.x;w.array[z+1]=V.y;w.array[z+2]=V.z;w.array[z+3]=V.w;w.array[z+4]=W.x;w.array[z+5]=W.y;w.array[z+6]=W.z;w.array[z+7]=W.w;w.array[z+8]=X.x;w.array[z+9]=X.y;w.array[z+10]=X.z;w.array[z+11]=X.w;z=z+12}E=0;for(U=ka.length;E<U;E++){ma=X=W=V=Xa=w.value[ka[E]];w.array[z]=V.x;w.array[z+1]=V.y;w.array[z+2]=V.z;w.array[z+3]=V.w;w.array[z+4]=W.x;w.array[z+5]=W.y;w.array[z+6]=W.z;w.array[z+7]=W.w;w.array[z+8]=X.x;w.array[z+9]=X.y;w.array[z+
+10]=X.z;w.array[z+11]=X.w;w.array[z+12]=ma.x;w.array[z+13]=ma.y;w.array[z+14]=ma.z;w.array[z+15]=ma.w;z=z+16}}j.bindBuffer(j.ARRAY_BUFFER,w.buffer);j.bufferData(j.ARRAY_BUFFER,w.array,Wa)}}}if(od){delete da.__inittedArrays;delete da.__colorArray;delete da.__normalArray;delete da.__tangentArray;delete da.__uvArray;delete da.__uv2Array;delete da.__faceArray;delete da.__vertexArray;delete da.__lineArray;delete da.__skinVertexAArray;delete da.__skinVertexBArray;delete da.__skinIndexArray;delete da.__skinWeightArray}}}}ga.verticesNeedUpdate=
+false;ga.morphTargetsNeedUpdate=false;ga.elementsNeedUpdate=false;ga.uvsNeedUpdate=false;ga.normalsNeedUpdate=false;ga.colorsNeedUpdate=false;ga.tangetsNeedUpdate=false;Ua.attributes&&p(Ua)}else if(kb instanceof THREE.Ribbon){if(ga.verticesNeedUpdate||ga.colorsNeedUpdate){var Zb=ga,hd=j.DYNAMIC_DRAW,xc=void 0,yc=void 0,Jc=void 0,$b=void 0,Kc=void 0,id=Zb.vertices,jd=Zb.colors,ud=id.length,vd=jd.length,Lc=Zb.__vertexArray,Mc=Zb.__colorArray,wd=Zb.colorsNeedUpdate;if(Zb.verticesNeedUpdate){for(xc=0;xc<
+ud;xc++){Jc=id[xc];$b=xc*3;Lc[$b]=Jc.x;Lc[$b+1]=Jc.y;Lc[$b+2]=Jc.z}j.bindBuffer(j.ARRAY_BUFFER,Zb.__webglVertexBuffer);j.bufferData(j.ARRAY_BUFFER,Lc,hd)}if(wd){for(yc=0;yc<vd;yc++){Kc=jd[yc];$b=yc*3;Mc[$b]=Kc.r;Mc[$b+1]=Kc.g;Mc[$b+2]=Kc.b}j.bindBuffer(j.ARRAY_BUFFER,Zb.__webglColorBuffer);j.bufferData(j.ARRAY_BUFFER,Mc,hd)}}ga.verticesNeedUpdate=false;ga.colorsNeedUpdate=false}else if(kb instanceof THREE.Line){Ua=c(kb,$a);fb=Ua.attributes&&m(Ua);if(ga.verticesNeedUpdate||ga.colorsNeedUpdate||fb){var Kb=
+ga,Zc=j.DYNAMIC_DRAW,zc=void 0,Ac=void 0,Nc=void 0,va=void 0,Oc=void 0,kd=Kb.vertices,ld=Kb.colors,xd=kd.length,yd=ld.length,Pc=Kb.__vertexArray,Qc=Kb.__colorArray,zd=Kb.colorsNeedUpdate,$c=Kb.__webglCustomAttributesList,Rc=void 0,md=void 0,La=void 0,oc=void 0,Va=void 0,pa=void 0;if(Kb.verticesNeedUpdate){for(zc=0;zc<xd;zc++){Nc=kd[zc];va=zc*3;Pc[va]=Nc.x;Pc[va+1]=Nc.y;Pc[va+2]=Nc.z}j.bindBuffer(j.ARRAY_BUFFER,Kb.__webglVertexBuffer);j.bufferData(j.ARRAY_BUFFER,Pc,Zc)}if(zd){for(Ac=0;Ac<yd;Ac++){Oc=
+ld[Ac];va=Ac*3;Qc[va]=Oc.r;Qc[va+1]=Oc.g;Qc[va+2]=Oc.b}j.bindBuffer(j.ARRAY_BUFFER,Kb.__webglColorBuffer);j.bufferData(j.ARRAY_BUFFER,Qc,Zc)}if($c){Rc=0;for(md=$c.length;Rc<md;Rc++){pa=$c[Rc];if(pa.needsUpdate&&(pa.boundTo===void 0||pa.boundTo==="vertices")){va=0;oc=pa.value.length;if(pa.size===1)for(La=0;La<oc;La++)pa.array[La]=pa.value[La];else if(pa.size===2)for(La=0;La<oc;La++){Va=pa.value[La];pa.array[va]=Va.x;pa.array[va+1]=Va.y;va=va+2}else if(pa.size===3)if(pa.type==="c")for(La=0;La<oc;La++){Va=
+pa.value[La];pa.array[va]=Va.r;pa.array[va+1]=Va.g;pa.array[va+2]=Va.b;va=va+3}else for(La=0;La<oc;La++){Va=pa.value[La];pa.array[va]=Va.x;pa.array[va+1]=Va.y;pa.array[va+2]=Va.z;va=va+3}else if(pa.size===4)for(La=0;La<oc;La++){Va=pa.value[La];pa.array[va]=Va.x;pa.array[va+1]=Va.y;pa.array[va+2]=Va.z;pa.array[va+3]=Va.w;va=va+4}j.bindBuffer(j.ARRAY_BUFFER,pa.buffer);j.bufferData(j.ARRAY_BUFFER,pa.array,Zc)}}}}ga.verticesNeedUpdate=false;ga.colorsNeedUpdate=false;Ua.attributes&&p(Ua)}else if(kb instanceof
+THREE.ParticleSystem){Ua=c(kb,$a);fb=Ua.attributes&&m(Ua);(ga.verticesNeedUpdate||ga.colorsNeedUpdate||kb.sortParticles||fb)&&f(ga,j.DYNAMIC_DRAW,kb);ga.verticesNeedUpdate=false;ga.colorsNeedUpdate=false;Ua.attributes&&p(Ua)}}};this.initMaterial=function(a,b,c,d){var e,f,g;a instanceof THREE.MeshDepthMaterial?g="depth":a instanceof THREE.MeshNormalMaterial?g="normal":a instanceof THREE.MeshBasicMaterial?g="basic":a instanceof THREE.MeshLambertMaterial?g="lambert":a instanceof THREE.MeshPhongMaterial?
+g="phong":a instanceof THREE.LineBasicMaterial?g="basic":a instanceof THREE.ParticleBasicMaterial&&(g="particle_basic");if(g){var h=THREE.ShaderLib[g];a.uniforms=THREE.UniformsUtils.clone(h.uniforms);a.vertexShader=h.vertexShader;a.fragmentShader=h.fragmentShader}var i,k,l,m,n;i=m=n=h=0;for(k=b.length;i<k;i++){l=b[i];if(!l.onlyShadow){l instanceof THREE.DirectionalLight&&m++;l instanceof THREE.PointLight&&n++;l instanceof THREE.SpotLight&&h++}}if(n+h+m<=Q){k=m;l=n;m=h}else{k=Math.ceil(Q*m/(n+m));
+m=l=Q-k}var o=0,h=0;for(n=b.length;h<n;h++){i=b[h];if(i.castShadow){i instanceof THREE.SpotLight&&o++;i instanceof THREE.DirectionalLight&&!i.shadowCascade&&o++}}var p=50;if(d!==void 0&&d instanceof THREE.SkinnedMesh)p=d.bones.length;var q;a:{i=a.fragmentShader;n=a.vertexShader;var h=a.uniforms,b=a.attributes,c={map:!!a.map,envMap:!!a.envMap,lightMap:!!a.lightMap,vertexColors:a.vertexColors,fog:c,useFog:a.fog,sizeAttenuation:a.sizeAttenuation,skinning:a.skinning,maxBones:p,morphTargets:a.morphTargets,
+morphNormals:a.morphNormals,maxMorphTargets:this.maxMorphTargets,maxMorphNormals:this.maxMorphNormals,maxDirLights:k,maxPointLights:l,maxSpotLights:m,maxShadows:o,shadowMapEnabled:this.shadowMapEnabled&&d.receiveShadow,shadowMapSoft:this.shadowMapSoft,shadowMapDebug:this.shadowMapDebug,shadowMapCascade:this.shadowMapCascade,alphaTest:a.alphaTest,metal:a.metal,perPixel:a.perPixel,wrapAround:a.wrapAround,doubleSided:d&&d.doubleSided},r,d=[];if(g)d.push(g);else{d.push(i);d.push(n)}for(r in c){d.push(r);
+d.push(c[r])}g=d.join();r=0;for(d=P.length;r<d;r++){k=P[r];if(k.code===g){k.usedTimes++;q=k.program;break a}}r=j.createProgram();d=["precision "+v+" float;",$a>0?"#define VERTEX_TEXTURES":"",C.gammaInput?"#define GAMMA_INPUT":"",C.gammaOutput?"#define GAMMA_OUTPUT":"",C.physicallyBasedShading?"#define PHYSICALLY_BASED_SHADING":"","#define MAX_DIR_LIGHTS "+c.maxDirLights,"#define MAX_POINT_LIGHTS "+c.maxPointLights,"#define MAX_SPOT_LIGHTS "+c.maxSpotLights,"#define MAX_SHADOWS "+c.maxShadows,"#define MAX_BONES "+
+c.maxBones,c.map?"#define USE_MAP":"",c.envMap?"#define USE_ENVMAP":"",c.lightMap?"#define USE_LIGHTMAP":"",c.vertexColors?"#define USE_COLOR":"",c.skinning?"#define USE_SKINNING":"",c.morphTargets?"#define USE_MORPHTARGETS":"",c.morphNormals?"#define USE_MORPHNORMALS":"",c.perPixel?"#define PHONG_PER_PIXEL":"",c.wrapAround?"#define WRAP_AROUND":"",c.doubleSided?"#define DOUBLE_SIDED":"",c.shadowMapEnabled?"#define USE_SHADOWMAP":"",c.shadowMapSoft?"#define SHADOWMAP_SOFT":"",c.shadowMapDebug?"#define SHADOWMAP_DEBUG":
+"",c.shadowMapCascade?"#define SHADOWMAP_CASCADE":"",c.sizeAttenuation?"#define USE_SIZEATTENUATION":"","uniform mat4 objectMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform mat3 normalMatrix;\nuniform vec3 cameraPosition;\nattribute vec3 position;\nattribute vec3 normal;\nattribute vec2 uv;\nattribute vec2 uv2;\n#ifdef USE_COLOR\nattribute vec3 color;\n#endif\n#ifdef USE_MORPHTARGETS\nattribute vec3 morphTarget0;\nattribute vec3 morphTarget1;\nattribute vec3 morphTarget2;\nattribute vec3 morphTarget3;\n#ifdef USE_MORPHNORMALS\nattribute vec3 morphNormal0;\nattribute vec3 morphNormal1;\nattribute vec3 morphNormal2;\nattribute vec3 morphNormal3;\n#else\nattribute vec3 morphTarget4;\nattribute vec3 morphTarget5;\nattribute vec3 morphTarget6;\nattribute vec3 morphTarget7;\n#endif\n#endif\n#ifdef USE_SKINNING\nattribute vec4 skinVertexA;\nattribute vec4 skinVertexB;\nattribute vec4 skinIndex;\nattribute vec4 skinWeight;\n#endif\n"].join("\n");
 k=["precision "+v+" float;","#define MAX_DIR_LIGHTS "+c.maxDirLights,"#define MAX_POINT_LIGHTS "+c.maxPointLights,"#define MAX_SPOT_LIGHTS "+c.maxSpotLights,"#define MAX_SHADOWS "+c.maxShadows,c.alphaTest?"#define ALPHATEST "+c.alphaTest:"",C.gammaInput?"#define GAMMA_INPUT":"",C.gammaOutput?"#define GAMMA_OUTPUT":"",C.physicallyBasedShading?"#define PHYSICALLY_BASED_SHADING":"",c.useFog&&c.fog?"#define USE_FOG":"",c.useFog&&c.fog instanceof THREE.FogExp2?"#define FOG_EXP2":"",c.map?"#define USE_MAP":
 "",c.envMap?"#define USE_ENVMAP":"",c.lightMap?"#define USE_LIGHTMAP":"",c.vertexColors?"#define USE_COLOR":"",c.metal?"#define METAL":"",c.perPixel?"#define PHONG_PER_PIXEL":"",c.wrapAround?"#define WRAP_AROUND":"",c.doubleSided?"#define DOUBLE_SIDED":"",c.shadowMapEnabled?"#define USE_SHADOWMAP":"",c.shadowMapSoft?"#define SHADOWMAP_SOFT":"",c.shadowMapDebug?"#define SHADOWMAP_DEBUG":"",c.shadowMapCascade?"#define SHADOWMAP_CASCADE":"","uniform mat4 viewMatrix;\nuniform vec3 cameraPosition;\n"].join("\n");
 i=y("fragment",k+i);d=y("vertex",d+n);j.attachShader(r,d);j.attachShader(r,i);j.linkProgram(r);j.getProgramParameter(r,j.LINK_STATUS)||console.error("Could not initialise shader\nVALIDATE_STATUS: "+j.getProgramParameter(r,j.VALIDATE_STATUS)+", gl error ["+j.getError()+"]");j.deleteShader(i);j.deleteShader(d);r.uniforms={};r.attributes={};var s,d=["viewMatrix","modelViewMatrix","projectionMatrix","normalMatrix","objectMatrix","cameraPosition","boneGlobalMatrices","morphTargetInfluences"];for(s in h)d.push(s);
@@ -446,7 +446,7 @@ x;a.faceVertexUvs=H}};THREE.GeometryUtils.random=THREE.Math.random16;THREE.Geome
 THREE.ImageUtils={crossOrigin:"anonymous",loadTexture:function(a,b,c){var d=new Image,e=new THREE.Texture(d,b);d.onload=function(){e.needsUpdate=true;c&&c(this)};d.crossOrigin=this.crossOrigin;d.src=a;return e},loadTextureCube:function(a,b,c){var d,e=[],f=new THREE.Texture(e,b),b=e.loadCount=0;for(d=a.length;b<d;++b){e[b]=new Image;e[b].onload=function(){e.loadCount=e.loadCount+1;if(e.loadCount===6)f.needsUpdate=true;c&&c(this)};e[b].crossOrigin=this.crossOrigin;e[b].src=a[b]}return f},getNormalMap:function(a,
 b){var c=function(a){var b=Math.sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]);return[a[0]/b,a[1]/b,a[2]/b]},b=b|1,d=a.width,e=a.height,f=document.createElement("canvas");f.width=d;f.height=e;var g=f.getContext("2d");g.drawImage(a,0,0);for(var h=g.getImageData(0,0,d,e).data,i=g.createImageData(d,e),k=i.data,l=0;l<d;l++)for(var o=0;o<e;o++){var m=o-1<0?0:o-1,p=o+1>e-1?e-1:o+1,q=l-1<0?0:l-1,n=l+1>d-1?d-1:l+1,r=[],u=[0,0,h[(o*d+l)*4]/255*b];r.push([-1,0,h[(o*d+q)*4]/255*b]);r.push([-1,-1,h[(m*d+q)*4]/255*b]);r.push([0,
 -1,h[(m*d+l)*4]/255*b]);r.push([1,-1,h[(m*d+n)*4]/255*b]);r.push([1,0,h[(o*d+n)*4]/255*b]);r.push([1,1,h[(p*d+n)*4]/255*b]);r.push([0,1,h[(p*d+l)*4]/255*b]);r.push([-1,1,h[(p*d+q)*4]/255*b]);m=[];q=r.length;for(p=0;p<q;p++){var n=r[p],t=r[(p+1)%q],n=[n[0]-u[0],n[1]-u[1],n[2]-u[2]],t=[t[0]-u[0],t[1]-u[1],t[2]-u[2]];m.push(c([n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]))}r=[0,0,0];for(p=0;p<m.length;p++){r[0]=r[0]+m[p][0];r[1]=r[1]+m[p][1];r[2]=r[2]+m[p][2]}r[0]=r[0]/m.length;r[1]=
-r[1]/m.length;r[2]=r[2]/m.length;u=(o*d+l)*4;k[u]=(r[0]+1)/2*255|0;k[u+1]=(r[1]+0.5)*255|0;k[u+2]=r[2]*255|0;k[u+3]=255}g.putImageData(i,0,0);return f},generateDataTexture:function(a,b,c){for(var d=a*b,e=new Uint8Array(3*d),f=Math.floor(c.r*255),g=Math.floor(c.g*255),c=Math.floor(c.b*255),h=0;h<d;h++){e[h*3]=f;e[h*3+1]=g;e[h*3+2]=c}a=new THREE.DataTexture(e,a,b,THREE.RGBFormat);a.needsUpdate=true;return a}};
+r[1]/m.length;r[2]=r[2]/m.length;u=(o*d+l)*4;k[u]=(r[0]+1)/2*255|0;k[u+1]=(r[1]+1)/2*255|0;k[u+2]=r[2]*255|0;k[u+3]=255}g.putImageData(i,0,0);return f},generateDataTexture:function(a,b,c){for(var d=a*b,e=new Uint8Array(3*d),f=Math.floor(c.r*255),g=Math.floor(c.g*255),c=Math.floor(c.b*255),h=0;h<d;h++){e[h*3]=f;e[h*3+1]=g;e[h*3+2]=c}a=new THREE.DataTexture(e,a,b,THREE.RGBFormat);a.needsUpdate=true;return a}};
 THREE.SceneUtils={showHierarchy:function(a,b){THREE.SceneUtils.traverseHierarchy(a,function(a){a.visible=b})},traverseHierarchy:function(a,b){var c,d,e=a.children.length;for(d=0;d<e;d++){c=a.children[d];b(c);THREE.SceneUtils.traverseHierarchy(c,b)}},createMultiMaterialObject:function(a,b){var c,d=b.length,e=new THREE.Object3D;for(c=0;c<d;c++){var f=new THREE.Mesh(a,b[c]);e.add(f)}return e},cloneObject:function(a){var b;if(a instanceof THREE.MorphAnimMesh){b=new THREE.MorphAnimMesh(a.geometry,a.material);
 b.duration=a.duration;b.mirroredLoop=a.mirroredLoop;b.time=a.time;b.lastKeyframe=a.lastKeyframe;b.currentKeyframe=a.currentKeyframe;b.direction=a.direction;b.directionBackwards=a.directionBackwards}else if(a instanceof THREE.SkinnedMesh)b=new THREE.SkinnedMesh(a.geometry,a.material);else if(a instanceof THREE.Mesh)b=new THREE.Mesh(a.geometry,a.material);else if(a instanceof THREE.Line)b=new THREE.Line(a.geometry,a.material,a.type);else if(a instanceof THREE.Ribbon)b=new THREE.Ribbon(a.geometry,a.material);
 else if(a instanceof THREE.ParticleSystem){b=new THREE.ParticleSystem(a.geometry,a.material);b.sortParticles=a.sortParticles}else if(a instanceof THREE.Particle)b=new THREE.Particle(a.material);else if(a instanceof THREE.Sprite){b=new THREE.Sprite({});b.color.copy(a.color);b.map=a.map;b.blending=a.blending;b.useScreenCoordinates=a.useScreenCoordinates;b.mergeWith3D=a.mergeWith3D;b.affectedByDistance=a.affectedByDistance;b.scaleByViewport=a.scaleByViewport;b.alignment=a.alignment;b.rotation3d.copy(a.rotation3d);

+ 1 - 1
build/custom/ThreeExtras.js

@@ -24,7 +24,7 @@ o.vertexNormals[0].copy(g),o.vertexNormals[1].copy(f)),4===e.vertexColors.length
 THREE.ImageUtils={crossOrigin:"anonymous",loadTexture:function(b,a,c){var d=new Image,e=new THREE.Texture(d,a);d.onload=function(){e.needsUpdate=!0;c&&c(this)};d.crossOrigin=this.crossOrigin;d.src=b;return e},loadTextureCube:function(b,a,c){var d,e=[],f=new THREE.Texture(e,a),a=e.loadCount=0;for(d=b.length;a<d;++a)e[a]=new Image,e[a].onload=function(){e.loadCount+=1;6===e.loadCount&&(f.needsUpdate=!0);c&&c(this)},e[a].crossOrigin=this.crossOrigin,e[a].src=b[a];return f},getNormalMap:function(b,a){var c=
 function(a){var b=Math.sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]);return[a[0]/b,a[1]/b,a[2]/b]},a=a|1,d=b.width,e=b.height,f=document.createElement("canvas");f.width=d;f.height=e;var g=f.getContext("2d");g.drawImage(b,0,0);for(var h=g.getImageData(0,0,d,e).data,i=g.createImageData(d,e),j=i.data,l=0;l<d;l++)for(var n=0;n<e;n++){var k=0>n-1?0:n-1,m=n+1>e-1?e-1:n+1,p=0>l-1?0:l-1,q=l+1>d-1?d-1:l+1,r=[],t=[0,0,h[4*(n*d+l)]/255*a];r.push([-1,0,h[4*(n*d+p)]/255*a]);r.push([-1,-1,h[4*(k*d+p)]/255*a]);r.push([0,
 -1,h[4*(k*d+l)]/255*a]);r.push([1,-1,h[4*(k*d+q)]/255*a]);r.push([1,0,h[4*(n*d+q)]/255*a]);r.push([1,1,h[4*(m*d+q)]/255*a]);r.push([0,1,h[4*(m*d+l)]/255*a]);r.push([-1,1,h[4*(m*d+p)]/255*a]);k=[];p=r.length;for(m=0;m<p;m++){var q=r[m],s=r[(m+1)%p],q=[q[0]-t[0],q[1]-t[1],q[2]-t[2]],s=[s[0]-t[0],s[1]-t[1],s[2]-t[2]];k.push(c([q[1]*s[2]-q[2]*s[1],q[2]*s[0]-q[0]*s[2],q[0]*s[1]-q[1]*s[0]]))}r=[0,0,0];for(m=0;m<k.length;m++)r[0]+=k[m][0],r[1]+=k[m][1],r[2]+=k[m][2];r[0]/=k.length;r[1]/=k.length;r[2]/=k.length;
-t=4*(n*d+l);j[t]=255*((r[0]+1)/2)|0;j[t+1]=255*(r[1]+0.5)|0;j[t+2]=255*r[2]|0;j[t+3]=255}g.putImageData(i,0,0);return f},generateDataTexture:function(b,a,c){for(var d=b*a,e=new Uint8Array(3*d),f=Math.floor(255*c.r),g=Math.floor(255*c.g),c=Math.floor(255*c.b),h=0;h<d;h++)e[3*h]=f,e[3*h+1]=g,e[3*h+2]=c;b=new THREE.DataTexture(e,b,a,THREE.RGBFormat);b.needsUpdate=!0;return b}};
+t=4*(n*d+l);j[t]=255*((r[0]+1)/2)|0;j[t+1]=255*((r[1]+1)/2)|0;j[t+2]=255*r[2]|0;j[t+3]=255}g.putImageData(i,0,0);return f},generateDataTexture:function(b,a,c){for(var d=b*a,e=new Uint8Array(3*d),f=Math.floor(255*c.r),g=Math.floor(255*c.g),c=Math.floor(255*c.b),h=0;h<d;h++)e[3*h]=f,e[3*h+1]=g,e[3*h+2]=c;b=new THREE.DataTexture(e,b,a,THREE.RGBFormat);b.needsUpdate=!0;return b}};
 THREE.SceneUtils={showHierarchy:function(b,a){THREE.SceneUtils.traverseHierarchy(b,function(b){b.visible=a})},traverseHierarchy:function(b,a){var c,d,e=b.children.length;for(d=0;d<e;d++)c=b.children[d],a(c),THREE.SceneUtils.traverseHierarchy(c,a)},createMultiMaterialObject:function(b,a){var c,d=a.length,e=new THREE.Object3D;for(c=0;c<d;c++){var f=new THREE.Mesh(b,a[c]);e.add(f)}return e},cloneObject:function(b){var a;b instanceof THREE.MorphAnimMesh?(a=new THREE.MorphAnimMesh(b.geometry,b.material),
 a.duration=b.duration,a.mirroredLoop=b.mirroredLoop,a.time=b.time,a.lastKeyframe=b.lastKeyframe,a.currentKeyframe=b.currentKeyframe,a.direction=b.direction,a.directionBackwards=b.directionBackwards):b instanceof THREE.SkinnedMesh?a=new THREE.SkinnedMesh(b.geometry,b.material):b instanceof THREE.Mesh?a=new THREE.Mesh(b.geometry,b.material):b instanceof THREE.Line?a=new THREE.Line(b.geometry,b.material,b.type):b instanceof THREE.Ribbon?a=new THREE.Ribbon(b.geometry,b.material):b instanceof THREE.ParticleSystem?
 (a=new THREE.ParticleSystem(b.geometry,b.material),a.sortParticles=b.sortParticles):b instanceof THREE.Particle?a=new THREE.Particle(b.material):b instanceof THREE.Sprite?(a=new THREE.Sprite({}),a.color.copy(b.color),a.map=b.map,a.blending=b.blending,a.useScreenCoordinates=b.useScreenCoordinates,a.mergeWith3D=b.mergeWith3D,a.affectedByDistance=b.affectedByDistance,a.scaleByViewport=b.scaleByViewport,a.alignment=b.alignment,a.rotation3d.copy(b.rotation3d),a.rotation=b.rotation,a.opacity=b.opacity,

File diff suppressed because it is too large
+ 119 - 119
build/custom/ThreeWebGL.js


+ 12 - 12
examples/js/MarchingCubes.js

@@ -53,9 +53,9 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs ) {
 		this.maxCount = 4096; // TODO: find the fastest size for this buffer
 		this.count = 0;
 
-		this.hasPos = false;
-		this.hasNormal = false;
-		this.hasUv = false;
+		this.hasPositions = false;
+		this.hasNormals = false;
+		this.hasUvs = false;
 
 		this.positionArray = new Float32Array( this.maxCount * 3 );
 		this.normalArray   = new Float32Array( this.maxCount * 3 );
@@ -362,12 +362,12 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs ) {
 
 		if ( this.count >= this.maxCount - 3 ) {
 
-			this.hasPos = true;
-			this.hasNormal = true;
+			this.hasPositions = true;
+			this.hasNormals = true;
 
 			if ( this.enableUvs ) {
 
-				this.hasUv = true;
+				this.hasUvs = true;
 
 			}
 
@@ -381,9 +381,9 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs ) {
 
 		this.count = 0;
 
-		this.hasPos = false;
-		this.hasNormal = false;
-		this.hasUv = false;
+		this.hasPositions = false;
+		this.hasNormals = false;
+		this.hasUvs = false;
 
 	};
 
@@ -395,12 +395,12 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs ) {
 		for ( var i = this.count * 3; i < this.positionArray.length; i ++ )
 			this.positionArray[ i ] = 0.0;
 
-		this.hasPos = true;
-		this.hasNormal = true;
+		this.hasPositions = true;
+		this.hasNormals = true;
 
 		if ( this.enableUvs ) {
 
-			this.hasUv = true;
+			this.hasUvs = true;
 
 		}
 

+ 474 - 0
src/extras/FontUtils.js

@@ -0,0 +1,474 @@
+/**
+ * @author zz85 / http://www.lab4games.net/zz85/blog
+ * @author alteredq / http://alteredqualia.com/
+ *
+ * For Text operations in three.js (See TextGeometry)
+ *
+ * It uses techniques used in:
+ *
+ * 	typeface.js and canvastext
+ * 		For converting fonts and rendering with javascript
+ *		http://typeface.neocracy.org
+ *
+ *	Triangulation ported from AS3
+ *		Simple Polygon Triangulation
+ *		http://actionsnippet.com/?p=1462
+ *
+ * 	A Method to triangulate shapes with holes
+ *		http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/
+ *
+ */
+
+THREE.FontUtils = {
+
+	faces : {},
+
+	// Just for now. face[weight][style]
+
+	face : "helvetiker",
+	weight: "normal",
+	style : "normal",
+	size : 150,
+	divisions : 10,
+
+	getFace : function() {
+
+		return this.faces[ this.face ][ this.weight ][ this.style ];
+
+	},
+
+	loadFace : function( data ) {
+
+		var family = data.familyName.toLowerCase();
+
+		var ThreeFont = this;
+
+		ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {};
+
+		ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {};
+		ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;
+
+		var face = ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;
+
+		return data;
+
+	},
+
+	drawText : function( text ) {
+
+		var characterPts = [], allPts = [];
+
+		// RenderText
+
+		var i, p,
+			face = this.getFace(),
+			scale = this.size / face.resolution,
+			offset = 0,
+			chars = String( text ).split( '' ),
+			length = chars.length;
+
+		var fontPaths = [];
+
+		for ( i = 0; i < length; i ++ ) {
+
+			var path = new THREE.Path();
+
+			var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path );
+			offset += ret.offset;
+
+			fontPaths.push( ret.path );
+
+		}
+
+		// get the width
+
+		var width = offset / 2;
+		//
+		// for ( p = 0; p < allPts.length; p++ ) {
+		//
+		// 	allPts[ p ].x -= width;
+		//
+		// }
+
+		//var extract = this.extractPoints( allPts, characterPts );
+		//extract.contour = allPts;
+
+		//extract.paths = fontPaths;
+		//extract.offset = width;
+
+		return { paths : fontPaths, offset : width };
+
+	},
+
+
+
+
+	extractGlyphPoints : function( c, face, scale, offset, path ) {
+
+		var pts = [];
+
+		var i, i2, divisions,
+			outline, action, length,
+			scaleX, scaleY,
+			x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2,
+			laste,
+			glyph = face.glyphs[ c ] || face.glyphs[ '?' ];
+
+		if ( !glyph ) return;
+
+		if ( glyph.o ) {
+
+			outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );
+			length = outline.length;
+
+			scaleX = scale;
+			scaleY = scale;
+
+			for ( i = 0; i < length; ) {
+
+				action = outline[ i ++ ];
+
+				//console.log( action );
+
+				switch( action ) {
+
+				case 'm':
+
+					// Move To
+
+					x = outline[ i++ ] * scaleX + offset;
+					y = outline[ i++ ] * scaleY;
+
+					path.moveTo( x, y );
+					break;
+
+				case 'l':
+
+					// Line To
+
+					x = outline[ i++ ] * scaleX + offset;
+					y = outline[ i++ ] * scaleY;
+					path.lineTo(x,y);
+					break;
+
+				case 'q':
+
+					// QuadraticCurveTo
+
+					cpx  = outline[ i++ ] * scaleX + offset;
+					cpy  = outline[ i++ ] * scaleY;
+					cpx1 = outline[ i++ ] * scaleX + offset;
+					cpy1 = outline[ i++ ] * scaleY;
+
+					path.quadraticCurveTo(cpx1, cpy1, cpx, cpy);
+
+					laste = pts[ pts.length - 1 ];
+
+					if ( laste ) {
+
+						cpx0 = laste.x;
+						cpy0 = laste.y;
+
+						for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) {
+
+							var t = i2 / divisions;
+							var tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );
+							var ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );
+					  }
+
+				  }
+
+				  break;
+
+				case 'b':
+
+					// Cubic Bezier Curve
+
+					cpx  = outline[ i++ ] *  scaleX + offset;
+					cpy  = outline[ i++ ] *  scaleY;
+					cpx1 = outline[ i++ ] *  scaleX + offset;
+					cpy1 = outline[ i++ ] * -scaleY;
+					cpx2 = outline[ i++ ] *  scaleX + offset;
+					cpy2 = outline[ i++ ] * -scaleY;
+
+					path.bezierCurveTo( cpx, cpy, cpx1, cpy1, cpx2, cpy2 );
+
+					laste = pts[ pts.length - 1 ];
+
+					if ( laste ) {
+
+						cpx0 = laste.x;
+						cpy0 = laste.y;
+
+						for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) {
+
+							var t = i2 / divisions;
+							var tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx );
+							var ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy );
+
+						}
+
+					}
+
+					break;
+
+				}
+
+			}
+		}
+
+
+
+		return { offset: glyph.ha*scale, path:path};
+	}
+
+};
+
+
+THREE.FontUtils.generateShapes = function( text, parameters ) {
+
+	// Parameters 
+
+	parameters = parameters || {};
+
+	var size = parameters.size !== undefined ? parameters.size : 100;
+	var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments: 4;
+
+	var font = parameters.font !== undefined ? parameters.font : "helvetiker";
+	var weight = parameters.weight !== undefined ? parameters.weight : "normal";
+	var style = parameters.style !== undefined ? parameters.style : "normal";
+
+	THREE.FontUtils.size = size;
+	THREE.FontUtils.divisions = curveSegments;
+
+	THREE.FontUtils.face = font;
+	THREE.FontUtils.weight = weight;
+	THREE.FontUtils.style = style;
+
+	// Get a Font data json object
+
+	var data = THREE.FontUtils.drawText( text );
+
+	var paths = data.paths;
+	var shapes = [];
+
+	for ( var p = 0, pl = paths.length; p < pl; p ++ ) {
+
+		Array.prototype.push.apply( shapes, paths[ p ].toShapes() );
+
+	}
+
+	return shapes;
+
+};
+
+
+/**
+ * This code is a quick port of code written in C++ which was submitted to
+ * flipcode.com by John W. Ratcliff  // July 22, 2000
+ * See original code and more information here:
+ * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml
+ *
+ * ported to actionscript by Zevan Rosser
+ * www.actionsnippet.com
+ *
+ * ported to javascript by Joshua Koo
+ * http://www.lab4games.net/zz85/blog
+ *
+ */
+
+
+( function( namespace ) {
+
+	var EPSILON = 0.0000000001;
+
+	// takes in an contour array and returns
+
+	var process = function( contour, indices ) {
+
+		var n = contour.length;
+
+		if ( n < 3 ) return null;
+
+		var result = [],
+			verts = [],
+			vertIndices = [];
+
+		/* we want a counter-clockwise polygon in verts */
+
+		var u, v, w;
+
+		if ( area( contour ) > 0.0 ) {
+
+			for ( v = 0; v < n; v++ ) verts[ v ] = v;
+
+		} else {
+
+			for ( v = 0; v < n; v++ ) verts[ v ] = ( n - 1 ) - v;
+
+		}
+
+		var nv = n;
+
+		/*  remove nv - 2 vertices, creating 1 triangle every time */
+
+		var count = 2 * nv;   /* error detection */
+
+		for( v = nv - 1; nv > 2; ) {
+
+			/* if we loop, it is probably a non-simple polygon */
+
+			if ( ( count-- ) <= 0 ) {
+
+				//** Triangulate: ERROR - probable bad polygon!
+
+				//throw ( "Warning, unable to triangulate polygon!" );
+				//return null;
+				// Sometimes warning is fine, especially polygons are triangulated in reverse.
+				console.log( "Warning, unable to triangulate polygon!" );
+
+				if ( indices ) return vertIndices;
+				return result;
+
+			}
+
+			/* three consecutive vertices in current polygon, <u,v,w> */
+
+			u = v; 	 	if ( nv <= u ) u = 0;     /* previous */
+			v = u + 1;  if ( nv <= v ) v = 0;     /* new v    */
+			w = v + 1;  if ( nv <= w ) w = 0;     /* next     */
+
+			if ( snip( contour, u, v, w, nv, verts ) ) {
+
+				var a, b, c, s, t;
+
+				/* true names of the vertices */
+
+				a = verts[ u ];
+				b = verts[ v ];
+				c = verts[ w ];
+
+				/* output Triangle */
+
+				/*
+				result.push( contour[ a ] );
+				result.push( contour[ b ] );
+				result.push( contour[ c ] );
+				*/
+				result.push( [ contour[ a ],
+					contour[ b ],
+					contour[ c ] ] );
+
+
+				vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] );
+
+				/* remove v from the remaining polygon */
+
+				for( s = v, t = v + 1; t < nv; s++, t++ ) {
+
+					verts[ s ] = verts[ t ];
+
+				}
+
+				nv--;
+
+				/* reset error detection counter */
+
+				count = 2 * nv;
+
+			}
+
+		}
+
+		if ( indices ) return vertIndices;
+		return result;
+
+	};
+
+	// calculate area of the contour polygon
+
+	var area = function ( contour ) {
+
+		var n = contour.length;
+		var a = 0.0;
+
+		for( var p = n - 1, q = 0; q < n; p = q++ ) {
+
+			a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
+
+		}
+
+		return a * 0.5;
+
+	};
+
+	// see if p is inside triangle abc
+
+	var insideTriangle = function( ax, ay,
+								   bx, by,
+								   cx, cy,
+								   px, py ) {
+
+		  var aX, aY, bX, bY;
+		  var cX, cY, apx, apy;
+		  var bpx, bpy, cpx, cpy;
+		  var cCROSSap, bCROSScp, aCROSSbp;
+
+		  aX = cx - bx;  aY = cy - by;
+		  bX = ax - cx;  bY = ay - cy;
+		  cX = bx - ax;  cY = by - ay;
+		  apx= px  -ax;  apy= py - ay;
+		  bpx= px - bx;  bpy= py - by;
+		  cpx= px - cx;  cpy= py - cy;
+
+		  aCROSSbp = aX*bpy - aY*bpx;
+		  cCROSSap = cX*apy - cY*apx;
+		  bCROSScp = bX*cpy - bY*cpx;
+
+		  return ( (aCROSSbp >= 0.0) && (bCROSScp >= 0.0) && (cCROSSap >= 0.0) );
+
+	};
+
+
+	var snip = function ( contour, u, v, w, n, verts ) {
+
+		var p;
+		var ax, ay, bx, by;
+		var cx, cy, px, py;
+
+		ax = contour[ verts[ u ] ].x;
+		ay = contour[ verts[ u ] ].y;
+
+		bx = contour[ verts[ v ] ].x;
+		by = contour[ verts[ v ] ].y;
+
+		cx = contour[ verts[ w ] ].x;
+		cy = contour[ verts[ w ] ].y;
+
+		if ( EPSILON > (((bx-ax)*(cy-ay)) - ((by-ay)*(cx-ax))) ) return false;
+
+			for ( p = 0; p < n; p++ ) {
+
+				if( (p == u) || (p == v) || (p == w) ) continue;
+
+				px = contour[ verts[ p ] ].x
+				py = contour[ verts[ p ] ].y
+
+				if ( insideTriangle( ax, ay, bx, by, cx, cy, px, py ) ) return false;
+
+		  }
+
+		  return true;
+
+	};
+
+
+	namespace.Triangulate = process;
+	namespace.Triangulate.area = area;
+
+	return namespace;
+
+})(THREE.FontUtils);
+
+// To use the typeface.js face files, hook up the API
+self._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace };

+ 1 - 1
src/extras/ImageUtils.js

@@ -134,7 +134,7 @@ THREE.ImageUtils = {
 				var idx = ( y * width + x ) * 4;
 
 				output[ idx ] = ( ( normal[ 0 ] + 1.0 ) / 2.0 * 255 ) | 0;
-				output[ idx + 1 ] = ( ( normal[ 1 ] + 1.0 / 2.0 ) * 255 ) | 0;
+				output[ idx + 1 ] = ( ( normal[ 1 ] + 1.0 ) / 2.0 * 255 ) | 0;
 				output[ idx + 2 ] = ( normal[ 2 ] * 255 ) | 0;
 				output[ idx + 3 ] = 255;
 

+ 0 - 147
src/extras/core/Path.js

@@ -401,153 +401,6 @@ THREE.Path.prototype.getPoints = function( divisions, closedPath ) {
 
 };
 
-
-
-// This was used for testing purposes. Should be removed soon.
-
-THREE.Path.prototype.transform = function( path, segments ) {
-
-	var bounds = this.getBoundingBox();
-	var oldPts = this.getPoints( segments ); // getPoints getSpacedPoints
-
-	//console.log( path.cacheArcLengths() );
-	//path.getLengths(400);
-	//segments = 40;
-
-	return this.getWrapPoints( oldPts, path );
-
-};
-
-// Read http://www.tinaja.com/glib/nonlingr.pdf
-// nonlinear transforms
-
-THREE.Path.prototype.nltransform = function( a, b, c, d, e, f ) {
-
-	// a - horizontal size
-	// b - lean
-	// c - x offset
-	// d - vertical size
-	// e - climb
-	// f - y offset
-
-	var oldPts = this.getPoints();
-
-	var i, il, p, oldX, oldY;
-
-	for ( i = 0, il = oldPts.length; i < il; i ++ ) {
-
-		p = oldPts[i];
-
-		oldX = p.x;
-		oldY = p.y;
-
-		p.x = a * oldX + b * oldY + c;
-		p.y = d * oldY + e * oldX + f;
-
-	}
-
-	return oldPts;
-
-};
-
-
-// FUTURE Export JSON Format
-
-/* Draws this path onto a 2d canvas easily */
-
-THREE.Path.prototype.debug = function( canvas ) {
-
-	var bounds = this.getBoundingBox();
-
-	if ( !canvas ) {
-
-		canvas = document.createElement( "canvas" );
-
-		canvas.setAttribute( 'width',  bounds.maxX + 100 );
-		canvas.setAttribute( 'height', bounds.maxY + 100 );
-
-		document.body.appendChild( canvas );
-
-	}
-
-	var ctx = canvas.getContext( "2d" );
-	ctx.fillStyle = "white";
-	ctx.fillRect( 0, 0, canvas.width, canvas.height );
-
-	ctx.strokeStyle = "black";
-	ctx.beginPath();
-
-	var i, il, item, action, args;
-
-	// Debug Path
-
-	for ( i = 0, il = this.actions.length; i < il; i ++ ) {
-
-		item = this.actions[ i ];
-
-		args = item.args;
-		action = item.action;
-
-		// Short hand for now
-
-		if ( action != THREE.PathActions.CSPLINE_THRU ) {
-
-			ctx[ action ].apply( ctx, args );
-
-		}
-
-		/*
-		switch ( action ) {
-
-			case THREE.PathActions.MOVE_TO:
-
-				ctx[ action ]( args[ 0 ], args[ 1 ] );
-				break;
-
-			case THREE.PathActions.LINE_TO:
-
-				ctx[ action ]( args[ 0 ], args[ 1 ] );
-				break;
-
-			case THREE.PathActions.QUADRATIC_CURVE_TO:
-
-				ctx[ action ]( args[ 0 ], args[ 1 ], args[ 2 ], args[ 3 ] );
-				break;
-
-			case THREE.PathActions.CUBIC_CURVE_TO:
-
-				ctx[ action ]( args[ 0 ], args[ 1 ], args[ 2 ], args[ 3 ], args[ 4 ], args[ 5 ] );
-				break;
-
-		}
-		*/
-
-	}
-
-	ctx.stroke();
-	ctx.closePath();
-
-	// Debug Points
-
-	ctx.strokeStyle = "red";
-
-	/* TO CLEAN UP */
-
-	var p, points = this.getPoints();
-
-	for ( i = 0, il = points.length; i < il; i ++ ) {
-
-		p = points[ i ];
-
-		ctx.beginPath();
-		ctx.arc( p.x, p.y, 1.5, 0, Math.PI * 2, false );
-		ctx.stroke();
-		ctx.closePath();
-
-	}
-
-};
-
 // Breaks path into shapes
 
 THREE.Path.prototype.toShapes = function() {

+ 0 - 68
src/extras/core/TextPath.js

@@ -1,68 +0,0 @@
-/**
- * @author zz85 / http://www.lab4games.net/zz85/blog
- *
- * TextPath
- *
- **/
-
-THREE.TextPath = function ( text, parameters ) {
-
-	THREE.Path.call( this );
-
-	this.parameters = parameters || {};
-
-	this.set( text );
-
-};
-
-THREE.TextPath.prototype.set = function ( text, parameters ) {
-
-	parameters = parameters || this.parameters;
-
-	this.text = text;
-
-	var size = parameters.size !== undefined ? parameters.size : 100;
-	var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments: 4;
-
-	var font = parameters.font !== undefined ? parameters.font : "helvetiker";
-	var weight = parameters.weight !== undefined ? parameters.weight : "normal";
-	var style = parameters.style !== undefined ? parameters.style : "normal";
-
-	THREE.FontUtils.size = size;
-	THREE.FontUtils.divisions = curveSegments;
-
-	THREE.FontUtils.face = font;
-	THREE.FontUtils.weight = weight;
-	THREE.FontUtils.style = style;
-
-};
-
-
-
-THREE.TextPath.prototype.toShapes = function () {
-
-	// Get a Font data json object
-
-	var data = THREE.FontUtils.drawText( this.text );
-
-	var paths = data.paths;
-	var shapes = [];
-
-	for ( var p = 0, pl = paths.length; p < pl; p ++ ) {
-
-		Array.prototype.push.apply( shapes, paths[ p ].toShapes() );
-
-	}
-
-	return shapes;
-
-	//console.log(path);
-	//console.log(fontShapes);
-
-	// Either find actions or curves.
-
-	//var text3d = new THREE.ExtrudeGeometry( shapes , { amount: 20, bevelEnabled:true, bevelThickness:3	} );
-
-	//return text3d;
-
-};

+ 4 - 443
src/extras/geometries/TextGeometry.js

@@ -23,20 +23,8 @@
  *  bendPath:       <curve>         // wraps text according to bend Path
  *  }
  *
- * It uses techniques used in:
- *
- * 	typeface.js and canvastext
- * 		For converting fonts and rendering with javascript
- *		http://typeface.neocracy.org
- *
- *	Triangulation ported from AS3
- *		Simple Polygon Triangulation
- *		http://actionsnippet.com/?p=1462
- *
- * 	A Method to triangulate shapes with holes
- *		http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/
- *
  */
+
 /*	Usage Examples
 	
 	// TextGeometry wrapper
@@ -45,8 +33,7 @@
 
 	// Complete manner
 
-	var textPath = new THREE.TextPath( text, options );
-	var textShapes = textPath.toShapes();
+	var textShapes = THREE.FontUtils.generateShapes( text, options );
 	var text3d = new ExtrudeGeometry( textShapes, options );
 	
 */
@@ -54,8 +41,7 @@
 
 THREE.TextGeometry = function ( text, parameters ) {
 
-	var textPath = new THREE.TextPath( text, parameters );
-	var textShapes = textPath.toShapes();
+	var textShapes = THREE.FontUtils.generateShapes( text, parameters );
 
 	// translate parameters to ExtrudeGeometry API
 
@@ -83,429 +69,4 @@ THREE.TextGeometry = function ( text, parameters ) {
 };
 
 THREE.TextGeometry.prototype = new THREE.ExtrudeGeometry();
-THREE.TextGeometry.prototype.constructor = THREE.TextGeometry;
-
-
-THREE.FontUtils = {
-
-	faces : {},
-
-	// Just for now. face[weight][style]
-
-	face : "helvetiker",
-	weight: "normal",
-	style : "normal",
-	size : 150,
-	divisions : 10,
-
-	getFace : function() {
-
-		return this.faces[ this.face ][ this.weight ][ this.style ];
-
-	},
-
-	loadFace : function( data ) {
-
-		var family = data.familyName.toLowerCase();
-
-		var ThreeFont = this;
-
-		ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {};
-
-		ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {};
-		ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;
-
-		var face = ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;
-
-		return data;
-
-	},
-
-	drawText : function( text ) {
-
-		var characterPts = [], allPts = [];
-
-		// RenderText
-
-		var i, p,
-			face = this.getFace(),
-			scale = this.size / face.resolution,
-			offset = 0,
-			chars = String( text ).split( '' ),
-			length = chars.length;
-
-		var fontPaths = [];
-
-		for ( i = 0; i < length; i ++ ) {
-
-			var path = new THREE.Path();
-
-			var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path );
-			offset += ret.offset;
-			//characterPts.push( ret.points );
-			//allPts = allPts.concat( ret.points );
-			fontPaths.push( ret.path );
-
-		}
-
-		// get the width
-
-		var width = offset / 2;
-		//
-		// for ( p = 0; p < allPts.length; p++ ) {
-		//
-		// 	allPts[ p ].x -= width;
-		//
-		// }
-
-		//var extract = this.extractPoints( allPts, characterPts );
-		//extract.contour = allPts;
-
-		//extract.paths = fontPaths;
-		//extract.offset = width;
-
-		return { paths : fontPaths, offset : width };
-
-	},
-
-
-
-
-	extractGlyphPoints : function( c, face, scale, offset, path ) {
-
-		var pts = [];
-
-		var i, i2, divisions,
-			outline, action, length,
-			scaleX, scaleY,
-			x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2,
-			laste,
-			glyph = face.glyphs[ c ] || face.glyphs[ '?' ];
-
-		if ( !glyph ) return;
-
-		if ( glyph.o ) {
-
-			outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );
-			length = outline.length;
-
-			scaleX = scale;
-			scaleY = scale;
-
-			for ( i = 0; i < length; ) {
-
-				action = outline[ i ++ ];
-
-				//console.log( action );
-
-				switch( action ) {
-
-				case 'm':
-
-					// Move To
-
-					x = outline[ i++ ] * scaleX + offset;
-					y = outline[ i++ ] * scaleY;
-
-					pts.push( new THREE.Vector2( x, y ) );
-
-					path.moveTo( x, y );
-					break;
-
-				case 'l':
-
-					// Line To
-
-					x = outline[ i++ ] * scaleX + offset;
-					y = outline[ i++ ] * scaleY;
-					pts.push( new THREE.Vector2( x, y ) );
-					path.lineTo(x,y);
-					break;
-
-				case 'q':
-
-					// QuadraticCurveTo
-
-					cpx  = outline[ i++ ] * scaleX + offset;
-					cpy  = outline[ i++ ] * scaleY;
-					cpx1 = outline[ i++ ] * scaleX + offset;
-					cpy1 = outline[ i++ ] * scaleY;
-
-					path.quadraticCurveTo(cpx1, cpy1, cpx, cpy);
-
-					laste = pts[ pts.length - 1 ];
-
-					if ( laste ) {
-
-						cpx0 = laste.x;
-						cpy0 = laste.y;
-
-						for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) {
-
-							var t = i2 / divisions;
-							var tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );
-							var ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );
-							pts.push( new THREE.Vector2( tx, ty ) );
-
-					  }
-
-				  }
-
-				  break;
-
-				case 'b':
-
-					// Cubic Bezier Curve
-
-					cpx  = outline[ i++ ] *  scaleX + offset;
-					cpy  = outline[ i++ ] *  scaleY;
-					cpx1 = outline[ i++ ] *  scaleX + offset;
-					cpy1 = outline[ i++ ] * -scaleY;
-					cpx2 = outline[ i++ ] *  scaleX + offset;
-					cpy2 = outline[ i++ ] * -scaleY;
-
-					path.bezierCurveTo( cpx, cpy, cpx1, cpy1, cpx2, cpy2 );
-
-					laste = pts[ pts.length - 1 ];
-
-					if ( laste ) {
-
-						cpx0 = laste.x;
-						cpy0 = laste.y;
-
-						for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) {
-
-							var t = i2 / divisions;
-							var tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx );
-							var ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy );
-							pts.push( new THREE.Vector2( tx, ty ) );
-
-						}
-
-					}
-
-					break;
-
-				}
-
-			}
-		}
-
-
-
-		return { offset: glyph.ha*scale, points:pts, path:path};
-	}
-
-};
-
-
-
-/**
- * This code is a quick port of code written in C++ which was submitted to
- * flipcode.com by John W. Ratcliff  // July 22, 2000
- * See original code and more information here:
- * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml
- *
- * ported to actionscript by Zevan Rosser
- * www.actionsnippet.com
- *
- * ported to javascript by Joshua Koo
- * http://www.lab4games.net/zz85/blog
- *
- */
-
-
-( function( namespace ) {
-
-	var EPSILON = 0.0000000001;
-
-	// takes in an contour array and returns
-
-	var process = function( contour, indices ) {
-
-		var n = contour.length;
-
-		if ( n < 3 ) return null;
-
-		var result = [],
-			verts = [],
-			vertIndices = [];
-
-		/* we want a counter-clockwise polygon in verts */
-
-		var u, v, w;
-
-		if ( area( contour ) > 0.0 ) {
-
-			for ( v = 0; v < n; v++ ) verts[ v ] = v;
-
-		} else {
-
-			for ( v = 0; v < n; v++ ) verts[ v ] = ( n - 1 ) - v;
-
-		}
-
-		var nv = n;
-
-		/*  remove nv - 2 vertices, creating 1 triangle every time */
-
-		var count = 2 * nv;   /* error detection */
-
-		for( v = nv - 1; nv > 2; ) {
-
-			/* if we loop, it is probably a non-simple polygon */
-
-			if ( ( count-- ) <= 0 ) {
-
-				//** Triangulate: ERROR - probable bad polygon!
-
-				//throw ( "Warning, unable to triangulate polygon!" );
-				//return null;
-				// Sometimes warning is fine, especially polygons are triangulated in reverse.
-				console.log( "Warning, unable to triangulate polygon!" );
-
-				if ( indices ) return vertIndices;
-				return result;
-
-			}
-
-			/* three consecutive vertices in current polygon, <u,v,w> */
-
-			u = v; 	 	if ( nv <= u ) u = 0;     /* previous */
-			v = u + 1;  if ( nv <= v ) v = 0;     /* new v    */
-			w = v + 1;  if ( nv <= w ) w = 0;     /* next     */
-
-			if ( snip( contour, u, v, w, nv, verts ) ) {
-
-				var a, b, c, s, t;
-
-				/* true names of the vertices */
-
-				a = verts[ u ];
-				b = verts[ v ];
-				c = verts[ w ];
-
-				/* output Triangle */
-
-				/*
-				result.push( contour[ a ] );
-				result.push( contour[ b ] );
-				result.push( contour[ c ] );
-				*/
-				result.push( [ contour[ a ],
-					contour[ b ],
-					contour[ c ] ] );
-
-
-				vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] );
-
-				/* remove v from the remaining polygon */
-
-				for( s = v, t = v + 1; t < nv; s++, t++ ) {
-
-					verts[ s ] = verts[ t ];
-
-				}
-
-				nv--;
-
-				/* reset error detection counter */
-
-				count = 2 * nv;
-
-			}
-
-		}
-
-		if ( indices ) return vertIndices;
-		return result;
-
-	};
-
-	// calculate area of the contour polygon
-
-	var area = function ( contour ) {
-
-		var n = contour.length;
-		var a = 0.0;
-
-		for( var p = n - 1, q = 0; q < n; p = q++ ) {
-
-			a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
-
-		}
-
-		return a * 0.5;
-
-	};
-
-	// see if p is inside triangle abc
-
-	var insideTriangle = function( ax, ay,
-								   bx, by,
-								   cx, cy,
-								   px, py ) {
-
-		  var aX, aY, bX, bY;
-		  var cX, cY, apx, apy;
-		  var bpx, bpy, cpx, cpy;
-		  var cCROSSap, bCROSScp, aCROSSbp;
-
-		  aX = cx - bx;  aY = cy - by;
-		  bX = ax - cx;  bY = ay - cy;
-		  cX = bx - ax;  cY = by - ay;
-		  apx= px  -ax;  apy= py - ay;
-		  bpx= px - bx;  bpy= py - by;
-		  cpx= px - cx;  cpy= py - cy;
-
-		  aCROSSbp = aX*bpy - aY*bpx;
-		  cCROSSap = cX*apy - cY*apx;
-		  bCROSScp = bX*cpy - bY*cpx;
-
-		  return ( (aCROSSbp >= 0.0) && (bCROSScp >= 0.0) && (cCROSSap >= 0.0) );
-
-	};
-
-
-	var snip = function ( contour, u, v, w, n, verts ) {
-
-		var p;
-		var ax, ay, bx, by;
-		var cx, cy, px, py;
-
-		ax = contour[ verts[ u ] ].x;
-		ay = contour[ verts[ u ] ].y;
-
-		bx = contour[ verts[ v ] ].x;
-		by = contour[ verts[ v ] ].y;
-
-		cx = contour[ verts[ w ] ].x;
-		cy = contour[ verts[ w ] ].y;
-
-		if ( EPSILON > (((bx-ax)*(cy-ay)) - ((by-ay)*(cx-ax))) ) return false;
-
-			for ( p = 0; p < n; p++ ) {
-
-				if( (p == u) || (p == v) || (p == w) ) continue;
-
-				px = contour[ verts[ p ] ].x
-				py = contour[ verts[ p ] ].y
-
-				if ( insideTriangle( ax, ay, bx, by, cx, cy, px, py ) ) return false;
-
-		  }
-
-		  return true;
-
-	};
-
-
-	namespace.Triangulate = process;
-	namespace.Triangulate.area = area;
-
-	return namespace;
-
-})(THREE.FontUtils);
-
-// To use the typeface.js face files, hook up the API
-self._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace };
+THREE.TextGeometry.prototype.constructor = THREE.TextGeometry;

+ 1 - 1
src/extras/modifiers/SubdivisionModifier.js

@@ -75,7 +75,7 @@ THREE.SubdivisionModifier.prototype.smooth = function ( oldGeometry ) {
 		
 		// TODO move vertex selection over here!
 		
-		var newFace = new THREE.Face4( a, b, c, d, null, oldFace.color, oldFace.material );
+		var newFace = new THREE.Face4( a, b, c, d, null, oldFace.color, oldFace.materialIndex );
 		
 		if (scope.useOldVertexColors) {
 			

+ 6 - 12
src/renderers/WebGLRenderer.js

@@ -2882,11 +2882,11 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	this.renderBufferImmediate = function ( object, program, shading ) {
 
-		if ( object.hasPos && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer();
-		if ( object.hasNormal && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer();
-		if ( object.hasUv && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer();
+		if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer();
+		if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer();
+		if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer();
 
-		if ( object.hasPos ) {
+		if ( object.hasPositions ) {
 
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW );
@@ -2895,7 +2895,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		}
 
-		if ( object.hasNormal ) {
+		if ( object.hasNormals ) {
 
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer );
 
@@ -2948,7 +2948,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		}
 
-		if ( object.hasUv ) {
+		if ( object.hasUvs ) {
 
 			_gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer );
 			_gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW );
@@ -4514,12 +4514,6 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets );
 
-				for ( var i = 0, il = _this.maxMorphTargets; i < il; i ++ ) {
-
-					object.__webglMorphTargetInfluences[ i ] = 0;
-
-				}
-
 			}
 
 		}

+ 1 - 1
utils/build.py

@@ -91,6 +91,7 @@ EXTRAS_FILES = [
 'extras/ImageUtils.js',
 'extras/SceneUtils.js',
 'extras/ShaderUtils.js',
+'extras/FontUtils.js',
 'extras/core/BufferGeometry.js',
 'extras/core/Curve.js',
 'extras/core/CurvePath.js',
@@ -98,7 +99,6 @@ EXTRAS_FILES = [
 'extras/core/Gyroscope.js',
 'extras/core/Path.js',
 'extras/core/Shape.js',
-'extras/core/TextPath.js',
 'extras/animation/AnimationHandler.js',
 'extras/animation/Animation.js',
 'extras/animation/KeyFrameAnimation.js',

+ 431 - 0
utils/exporters/blender/2.63/scripts/addons/io_mesh_threejs/__init__.py

@@ -0,0 +1,431 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# ################################################################
+# Init
+# ################################################################
+
+
+bl_info = {
+    "name": "three.js format",
+    "author": "mrdoob, kikko, alteredq, remoe, pxf",
+    "version": (1, 3, 0),
+    "blender": (2, 6, 0),
+    "api": 35622,
+    "location": "File > Import-Export",
+    "description": "Import-Export three.js meshes",
+    "warning": "",
+    "wiki_url": "https://github.com/mrdoob/three.js/tree/master/utils/exporters/blender",
+    "tracker_url": "https://github.com/mrdoob/three.js/issues",
+    "category": "Import-Export"}
+
+# To support reload properly, try to access a package var,
+# if it's there, reload everything
+
+import bpy
+
+if "bpy" in locals():
+    import imp
+    if "export_threejs" in locals():
+        imp.reload(export_threejs)
+    if "import_threejs" in locals():
+        imp.reload(import_threejs)
+
+from bpy.props import *
+from bpy_extras.io_utils import ExportHelper, ImportHelper
+
+# ################################################################
+# Custom properties
+# ################################################################
+
+bpy.types.Object.THREE_castShadow = bpy.props.BoolProperty()
+bpy.types.Object.THREE_receiveShadow = bpy.props.BoolProperty()
+bpy.types.Object.THREE_doubleSided = bpy.props.BoolProperty()
+bpy.types.Object.THREE_exportGeometry = bpy.props.BoolProperty(default = True)
+
+bpy.types.Material.THREE_useVertexColors = bpy.props.BoolProperty()
+bpy.types.Material.THREE_depthWrite = bpy.props.BoolProperty(default = True)
+bpy.types.Material.THREE_depthTest = bpy.props.BoolProperty(default = True)
+
+THREE_material_types = [("Basic", "Basic", "Basic"), ("Phong", "Phong", "Phong"), ("Lambert", "Lambert", "Lambert")]
+bpy.types.Material.THREE_materialType = EnumProperty(name = "Material type", description = "Material type", items = THREE_material_types, default = "Lambert")
+
+THREE_blending_types = [("NoBlending", "NoBlending", "NoBlending"), ("NormalBlending", "NormalBlending", "NormalBlending"),
+                        ("AdditiveBlending", "AdditiveBlending", "AdditiveBlending"), ("SubtractiveBlending", "SubtractiveBlending", "SubtractiveBlending"),
+                        ("MultiplyBlending", "MultiplyBlending", "MultiplyBlending"), ("AdditiveAlphaBlending", "AdditiveAlphaBlending", "AdditiveAlphaBlending")]
+bpy.types.Material.THREE_blendingType = EnumProperty(name = "Blending type", description = "Blending type", items = THREE_blending_types, default = "NormalBlending")
+
+class OBJECT_PT_hello( bpy.types.Panel ):
+
+    bl_label = "THREE"
+    bl_space_type = "PROPERTIES"
+    bl_region_type = "WINDOW"
+    bl_context = "object"
+
+    def draw(self, context):
+        layout = self.layout
+        obj = context.object
+
+        row = layout.row()
+        row.label(text="Selected object: " + obj.name )
+
+        row = layout.row()
+        row.prop( obj, "THREE_exportGeometry", text="Export geometry" )
+
+        row = layout.row()
+        row.prop( obj, "THREE_castShadow", text="Casts shadow" )
+
+        row = layout.row()
+        row.prop( obj, "THREE_receiveShadow", text="Receives shadow" )
+
+        row = layout.row()
+        row.prop( obj, "THREE_doubleSided", text="Double sided" )
+
+class MATERIAL_PT_hello( bpy.types.Panel ):
+
+    bl_label = "THREE"
+    bl_space_type = "PROPERTIES"
+    bl_region_type = "WINDOW"
+    bl_context = "material"
+
+    def draw(self, context):
+        layout = self.layout
+        mat = context.material
+
+        row = layout.row()
+        row.label(text="Selected material: " + mat.name )
+
+        row = layout.row()
+        row.prop( mat, "THREE_materialType", text="Material type" )
+
+        row = layout.row()
+        row.prop( mat, "THREE_blendingType", text="Blending type" )
+
+        row = layout.row()
+        row.prop( mat, "THREE_useVertexColors", text="Use vertex colors" )
+
+        row = layout.row()
+        row.prop( mat, "THREE_depthWrite", text="Enable depth writing" )
+
+        row = layout.row()
+        row.prop( mat, "THREE_depthTest", text="Enable depth testing" )
+
+
+# ################################################################
+# Importer
+# ################################################################
+
+class ImportTHREEJS(bpy.types.Operator, ImportHelper):
+    '''Load a Three.js ASCII JSON model'''
+
+    bl_idname = "import.threejs"
+    bl_label = "Import Three.js"
+
+    filename_ext = ".js"
+    filter_glob = StringProperty(default="*.js", options={'HIDDEN'})
+
+    option_flip_yz = BoolProperty(name="Flip YZ", description="Flip YZ", default=True)
+    recalculate_normals = BoolProperty(name="Recalculate normals", description="Recalculate vertex normals", default=True)
+    option_worker = BoolProperty(name="Worker", description="Old format using workers", default=False)
+
+    def execute(self, context):
+        import io_mesh_threejs.import_threejs
+        return io_mesh_threejs.import_threejs.load(self, context, **self.properties)
+
+
+    def draw(self, context):
+        layout = self.layout
+
+        row = layout.row()
+        row.prop(self.properties, "option_flip_yz")
+
+        row = layout.row()
+        row.prop(self.properties, "recalculate_normals")
+
+        row = layout.row()
+        row.prop(self.properties, "option_worker")
+
+
+# ################################################################
+# Exporter - settings
+# ################################################################
+
+SETTINGS_FILE_EXPORT = "threejs_settings_export.js"
+
+import os
+import json
+
+def file_exists(filename):
+    """Return true if file exists and accessible for reading.
+
+    Should be safer than just testing for existence due to links and
+    permissions magic on Unix filesystems.
+
+    @rtype: boolean
+    """
+
+    try:
+        f = open(filename, 'r')
+        f.close()
+        return True
+    except IOError:
+        return False
+
+def get_settings_fullpath():
+    return os.path.join(bpy.app.tempdir, SETTINGS_FILE_EXPORT)
+
+def save_settings_export(properties):
+
+    settings = {
+    "option_export_scene" : properties.option_export_scene,
+    "option_embed_meshes" : properties.option_embed_meshes,
+    "option_url_base_html" : properties.option_url_base_html,
+    "option_copy_textures" : properties.option_copy_textures,
+
+    "option_lights" : properties.option_lights,
+    "option_cameras" : properties.option_cameras,
+
+    "option_animation" : properties.option_animation,
+    "option_frame_step" : properties.option_frame_step,
+    "option_all_meshes" : properties.option_all_meshes,
+
+    "option_flip_yz"      : properties.option_flip_yz,
+
+    "option_materials"       : properties.option_materials,
+    "option_normals"         : properties.option_normals,
+    "option_colors"          : properties.option_colors,
+    "option_uv_coords"       : properties.option_uv_coords,
+    "option_faces"           : properties.option_faces,
+    "option_vertices"        : properties.option_vertices,
+
+    "option_vertices_truncate" : properties.option_vertices_truncate,
+    "option_scale"        : properties.option_scale,
+
+    "align_model"         : properties.align_model
+    }
+
+    fname = get_settings_fullpath()
+    f = open(fname, "w")
+    json.dump(settings, f)
+
+def restore_settings_export(properties):
+
+    settings = {}
+
+    fname = get_settings_fullpath()
+    if file_exists(fname):
+        f = open(fname, "r")
+        settings = json.load(f)
+
+    properties.option_vertices = settings.get("option_vertices", True)
+    properties.option_vertices_truncate = settings.get("option_vertices_truncate", False)
+    properties.option_faces = settings.get("option_faces", True)
+    properties.option_normals = settings.get("option_normals", True)
+
+    properties.option_colors = settings.get("option_colors", True)
+    properties.option_uv_coords = settings.get("option_uv_coords", True)
+    properties.option_materials = settings.get("option_materials", True)
+
+    properties.align_model = settings.get("align_model", "None")
+
+    properties.option_scale = settings.get("option_scale", 1.0)
+    properties.option_flip_yz = settings.get("option_flip_yz", True)
+
+    properties.option_export_scene = settings.get("option_export_scene", False)
+    properties.option_embed_meshes = settings.get("option_embed_meshes", True)
+    properties.option_url_base_html = settings.get("option_url_base_html", False)
+    properties.option_copy_textures = settings.get("option_copy_textures", False)
+
+    properties.option_lights = settings.get("option_lights", False)
+    properties.option_cameras = settings.get("option_cameras", False)
+
+    properties.option_animation = settings.get("option_animation", False)
+    properties.option_frame_step = settings.get("option_frame_step", 1)
+    properties.option_all_meshes = settings.get("option_all_meshes", True)
+
+# ################################################################
+# Exporter
+# ################################################################
+
+class ExportTHREEJS(bpy.types.Operator, ExportHelper):
+    '''Export selected object / scene for Three.js (ASCII JSON format).'''
+
+    bl_idname = "export.threejs"
+    bl_label = "Export Three.js"
+
+    filename_ext = ".js"
+
+    option_vertices = BoolProperty(name = "Vertices", description = "Export vertices", default = True)
+    option_vertices_deltas = BoolProperty(name = "Deltas", description = "Delta vertices", default = False)
+    option_vertices_truncate = BoolProperty(name = "Truncate", description = "Truncate vertices", default = False)
+
+    option_faces = BoolProperty(name = "Faces", description = "Export faces", default = True)
+    option_faces_deltas = BoolProperty(name = "Deltas", description = "Delta faces", default = False)
+
+    option_normals = BoolProperty(name = "Normals", description = "Export normals", default = True)
+
+    option_colors = BoolProperty(name = "Colors", description = "Export vertex colors", default = True)
+    option_uv_coords = BoolProperty(name = "UVs", description = "Export texture coordinates", default = True)
+    option_materials = BoolProperty(name = "Materials", description = "Export materials", default = True)
+
+    align_types = [("None","None","None"), ("Center","Center","Center"), ("Bottom","Bottom","Bottom"), ("Top","Top","Top")]
+    align_model = EnumProperty(name = "Align model", description = "Align model", items = align_types, default = "None")
+
+    option_scale = FloatProperty(name = "Scale", description = "Scale vertices", min = 0.01, max = 1000.0, soft_min = 0.01, soft_max = 1000.0, default = 1.0)
+    option_flip_yz = BoolProperty(name = "Flip YZ", description = "Flip YZ", default = True)
+
+    option_export_scene = BoolProperty(name = "Scene", description = "Export scene", default = False)
+    option_embed_meshes = BoolProperty(name = "Embed meshes", description = "Embed meshes", default = True)
+    option_copy_textures = BoolProperty(name = "Copy textures", description = "Copy textures", default = False)
+    option_url_base_html = BoolProperty(name = "HTML as url base", description = "Use HTML as url base ", default = False)
+
+    option_lights = BoolProperty(name = "Lights", description = "Export default scene lights", default = False)
+    option_cameras = BoolProperty(name = "Cameras", description = "Export default scene cameras", default = False)
+
+    option_animation = BoolProperty(name = "Animation", description = "Export animation (morphs)", default = False)
+    option_frame_step = IntProperty(name = "Frame step", description = "Animation frame step", min = 1, max = 1000, soft_min = 1, soft_max = 1000, default = 1)
+    option_all_meshes = BoolProperty(name = "All meshes", description = "All meshes (merged)", default = True)
+
+    def invoke(self, context, event):
+        restore_settings_export(self.properties)
+        return ExportHelper.invoke(self, context, event)
+
+    @classmethod
+    def poll(cls, context):
+        return context.active_object != None
+
+    def execute(self, context):
+        print("Selected: " + context.active_object.name)
+
+        if not self.properties.filepath:
+            raise Exception("filename not set")
+
+        save_settings_export(self.properties)
+
+        filepath = self.filepath
+
+        import io_mesh_threejs.export_threejs
+        return io_mesh_threejs.export_threejs.save(self, context, **self.properties)
+
+    def draw(self, context):
+        layout = self.layout
+
+        row = layout.row()
+        row.label(text="Geometry:")
+
+        row = layout.row()
+        row.prop(self.properties, "option_vertices")
+        # row = layout.row()
+        # row.enabled = self.properties.option_vertices
+        # row.prop(self.properties, "option_vertices_deltas")
+        row.prop(self.properties, "option_vertices_truncate")
+        layout.separator()
+
+        row = layout.row()
+        row.prop(self.properties, "option_faces")
+        row = layout.row()
+        row.enabled = self.properties.option_faces
+        # row.prop(self.properties, "option_faces_deltas")
+        layout.separator()
+
+        row = layout.row()
+        row.prop(self.properties, "option_normals")
+        layout.separator()
+
+        row = layout.row()
+        row.label(text="Materials:")
+
+        row = layout.row()
+        row.prop(self.properties, "option_uv_coords")
+        row.prop(self.properties, "option_colors")
+        row = layout.row()
+        row.prop(self.properties, "option_materials")
+        layout.separator()
+
+        row = layout.row()
+        row.label(text="Settings:")
+
+        row = layout.row()
+        row.prop(self.properties, "align_model")
+        row = layout.row()
+        row.prop(self.properties, "option_flip_yz")
+        row.prop(self.properties, "option_scale")
+        layout.separator()
+
+        row = layout.row()
+        row.label(text="--------- Experimental ---------")
+        layout.separator()
+
+        row = layout.row()
+        row.label(text="Scene:")
+
+        row = layout.row()
+        row.prop(self.properties, "option_export_scene")
+        row.prop(self.properties, "option_embed_meshes")
+
+        row = layout.row()
+        row.prop(self.properties, "option_lights")
+        row.prop(self.properties, "option_cameras")
+        layout.separator()
+
+        row = layout.row()
+        row.label(text="Animation:")
+
+        row = layout.row()
+        row.prop(self.properties, "option_animation")
+        row.prop(self.properties, "option_frame_step")
+        layout.separator()
+
+        row = layout.row()
+        row.label(text="Settings:")
+
+        row = layout.row()
+        row.prop(self.properties, "option_all_meshes")
+
+        row = layout.row()
+        row.prop(self.properties, "option_copy_textures")
+
+        row = layout.row()
+        row.prop(self.properties, "option_url_base_html")
+
+        layout.separator()
+
+
+# ################################################################
+# Common
+# ################################################################
+
+def menu_func_export(self, context):
+    default_path = bpy.data.filepath.replace(".blend", ".js")
+    self.layout.operator(ExportTHREEJS.bl_idname, text="Three.js (.js)").filepath = default_path
+
+def menu_func_import(self, context):
+    self.layout.operator(ImportTHREEJS.bl_idname, text="Three.js (.js)")
+
+def register():
+    bpy.utils.register_module(__name__)
+    bpy.types.INFO_MT_file_export.append(menu_func_export)
+    bpy.types.INFO_MT_file_import.append(menu_func_import)
+
+def unregister():
+    bpy.utils.unregister_module(__name__)
+    bpy.types.INFO_MT_file_export.remove(menu_func_export)
+    bpy.types.INFO_MT_file_import.remove(menu_func_import)
+
+if __name__ == "__main__":
+    register()

+ 1939 - 0
utils/exporters/blender/2.63/scripts/addons/io_mesh_threejs/export_threejs.py

@@ -0,0 +1,1939 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+"""
+Blender exporter for Three.js (ASCII JSON format).
+
+TODO
+    - binary format
+"""
+
+import bpy
+import mathutils
+
+import shutil
+import os
+import os.path
+import math
+import operator
+import random
+
+# #####################################################
+# Configuration
+# #####################################################
+
+DEFAULTS = {
+"bgcolor" : [0, 0, 0],
+"bgalpha" : 1.0,
+
+"position" : [0, 0, 0],
+"rotation" : [-math.pi/2, 0, 0],
+"scale"    : [1, 1, 1],
+
+"camera"  :
+    {
+        "name" : "default_camera",
+        "type" : "perspective",
+        "near" : 1,
+        "far"  : 10000,
+        "fov"  : 60,
+        "aspect": 1.333,
+        "position" : [0, 0, 10],
+        "target"   : [0, 0, 0]
+    },
+
+"light" :
+ {
+    "name"       : "default_light",
+    "type"       : "directional",
+    "direction"  : [0, 1, 1],
+    "color"      : [1, 1, 1],
+    "intensity"  : 0.8
+ }
+}
+
+# default colors for debugging (each material gets one distinct color):
+# white, red, green, blue, yellow, cyan, magenta
+COLORS = [0xeeeeee, 0xee0000, 0x00ee00, 0x0000ee, 0xeeee00, 0x00eeee, 0xee00ee]
+
+
+# #####################################################
+# Templates - scene
+# #####################################################
+
+TEMPLATE_SCENE_ASCII = """\
+{
+
+"metadata" :
+{
+    "formatVersion" : 3,
+    "sourceFile"    : "%(fname)s",
+    "generatedBy"   : "Blender 2.63 Exporter",
+    "objects"       : %(nobjects)s,
+    "geometries"    : %(ngeometries)s,
+    "materials"     : %(nmaterials)s,
+    "textures"      : %(ntextures)s
+},
+
+"type" : "scene",
+"urlBaseType" : %(basetype)s,
+
+%(sections)s
+
+"transform" :
+{
+    "position"  : %(position)s,
+    "rotation"  : %(rotation)s,
+    "scale"     : %(scale)s
+},
+
+"defaults" :
+{
+    "bgcolor" : %(bgcolor)s,
+    "bgalpha" : %(bgalpha)f,
+    "camera"  : %(defcamera)s
+}
+
+}
+"""
+
+TEMPLATE_SECTION = """
+"%s" :
+{
+%s
+},
+"""
+
+TEMPLATE_OBJECT = """\
+    %(object_id)s : {
+        "geometry"  : %(geometry_id)s,
+        "groups"    : [ %(group_id)s ],
+        "materials" : [ %(material_id)s ],
+        "position"  : %(position)s,
+        "rotation"  : %(rotation)s,
+        "quaternion": %(quaternion)s,
+        "scale"     : %(scale)s,
+        "visible"       : %(visible)s,
+        "castShadow"    : %(castShadow)s,
+        "receiveShadow" : %(receiveShadow)s,
+        "doubleSided"   : %(doubleSided)s
+    }"""
+
+TEMPLATE_EMPTY = """\
+    %(object_id)s : {
+        "groups"    : [ %(group_id)s ],
+        "position"  : %(position)s,
+        "rotation"  : %(rotation)s,
+        "quaternion": %(quaternion)s,
+        "scale"     : %(scale)s
+    }"""
+
+TEMPLATE_GEOMETRY_LINK = """\
+    %(geometry_id)s : {
+        "type" : "ascii_mesh",
+        "url"  : %(model_file)s
+    }"""
+
+TEMPLATE_GEOMETRY_EMBED = """\
+    %(geometry_id)s : {
+        "type" : "embedded_mesh",
+        "id"  : %(embed_id)s
+    }"""
+
+TEMPLATE_TEXTURE = """\
+    %(texture_id)s : {
+        "url": %(texture_file)s%(extras)s
+    }"""
+
+TEMPLATE_MATERIAL_SCENE = """\
+    %(material_id)s : {
+        "type": %(type)s,
+        "parameters": { %(parameters)s }
+    }"""
+
+TEMPLATE_CAMERA_PERSPECTIVE = """\
+    %(camera_id)s : {
+        "type"  : "perspective",
+        "fov"   : %(fov)f,
+        "aspect": %(aspect)f,
+        "near"  : %(near)f,
+        "far"   : %(far)f,
+        "position": %(position)s,
+        "target"  : %(target)s
+    }"""
+
+TEMPLATE_CAMERA_ORTHO = """\
+    %(camera_id)s: {
+        "type"  : "ortho",
+        "left"  : %(left)f,
+        "right" : %(right)f,
+        "top"   : %(top)f,
+        "bottom": %(bottom)f,
+        "near"  : %(near)f,
+        "far"   : %(far)f,
+        "position": %(position)s,
+        "target"  : %(target)s
+    }"""
+
+TEMPLATE_LIGHT_DIRECTIONAL = """\
+    %(light_id)s: {
+        "type"    	 : "directional",
+        "direction"	 : %(direction)s,
+        "color" 	 : %(color)d,
+        "intensity"	 : %(intensity).2f
+    }"""
+
+TEMPLATE_LIGHT_POINT = """\
+    %(light_id)s: {
+        "type"	     : "point",
+        "position"   : %(position)s,
+        "color"      : %(color)d,
+        "intensity"	 : %(intensity).3f
+    }"""
+
+TEMPLATE_VEC4 = '[ %f, %f, %f, %f ]'
+TEMPLATE_VEC3 = '[ %f, %f, %f ]'
+TEMPLATE_VEC2 = '[ %f, %f ]'
+TEMPLATE_STRING = '"%s"'
+TEMPLATE_HEX = "0x%06x"
+
+# #####################################################
+# Templates - model
+# #####################################################
+
+TEMPLATE_FILE_ASCII = """\
+{
+
+    "metadata" :
+    {
+        "formatVersion" : 3,
+        "generatedBy"   : "Blender 2.63 Exporter",
+        "vertices"      : %(nvertex)d,
+        "faces"         : %(nface)d,
+        "normals"       : %(nnormal)d,
+        "colors"        : %(ncolor)d,
+        "uvs"           : %(nuv)d,
+        "materials"     : %(nmaterial)d,
+        "morphTargets"  : %(nmorphTarget)d
+    },
+
+%(model)s
+
+}
+"""
+
+TEMPLATE_MODEL_ASCII = """\
+    "scale" : %(scale)f,
+
+    "materials": [%(materials)s],
+
+    "vertices": [%(vertices)s],
+
+    "morphTargets": [%(morphTargets)s],
+
+    "normals": [%(normals)s],
+
+    "colors": [%(colors)s],
+
+    "uvs": [[%(uvs)s]],
+
+    "faces": [%(faces)s]
+
+"""
+
+TEMPLATE_VERTEX = "%f,%f,%f"
+TEMPLATE_VERTEX_TRUNCATE = "%d,%d,%d"
+
+TEMPLATE_N = "%f,%f,%f"
+TEMPLATE_UV = "%f,%f"
+TEMPLATE_C = "%d"
+
+# #####################################################
+# Utils
+# #####################################################
+
+def veckey3(x,y,z):
+    return round(x, 6), round(y, 6), round(z, 6)
+
+def veckey3d(v):
+    return veckey3(v.x, v.y, v.z)
+
+def veckey2d(v):
+    return round(v[0], 6), round(v[1], 6)
+
+def get_faces(obj):
+    if hasattr(obj, "tessfaces"):
+        return obj.tessfaces
+    else:
+        return obj.faces
+
+def get_normal_indices(v, normals, mesh):
+    n = []
+    mv = mesh.vertices
+
+    for i in v:
+        normal = mv[i].normal
+        key = veckey3d(normal)
+
+        n.append( normals[key] )
+
+    return n
+
+def get_uv_indices(face_index, uvs, mesh):
+    uv = []
+    uv_layer = mesh.uv_textures.active.data
+    for i in uv_layer[face_index].uv:
+        uv.append( uvs[veckey2d(i)] )
+    return uv
+
+def get_color_indices(face_index, colors, mesh):
+    c = []
+    color_layer = mesh.vertex_colors.active.data
+    face_colors = color_layer[face_index]
+    face_colors = face_colors.color1, face_colors.color2, face_colors.color3, face_colors.color4
+    for i in face_colors:
+        c.append( colors[hexcolor(i)] )
+    return c
+
+def rgb2int(rgb):
+    color = (int(rgb[0]*255) << 16) + (int(rgb[1]*255) << 8) + int(rgb[2]*255);
+    return color
+
+# #####################################################
+# Utils - files
+# #####################################################
+
+def write_file(fname, content):
+    out = open(fname, "w")
+    out.write(content)
+    out.close()
+
+def ensure_folder_exist(foldername):
+    """Create folder (with whole path) if it doesn't exist yet."""
+
+    if not os.access(foldername, os.R_OK|os.W_OK|os.X_OK):
+        os.makedirs(foldername)
+
+def ensure_extension(filepath, extension):
+    if not filepath.lower().endswith(extension):
+        filepath += extension
+    return filepath
+
+def generate_mesh_filename(meshname, filepath):
+    normpath = os.path.normpath(filepath)
+    path, ext = os.path.splitext(normpath)
+    return "%s.%s%s" % (path, meshname, ext)
+
+
+# #####################################################
+# Utils - alignment
+# #####################################################
+
+def bbox(vertices):
+    """Compute bounding box of vertex array.
+    """
+
+    if len(vertices)>0:
+        minx = maxx = vertices[0].co.x
+        miny = maxy = vertices[0].co.y
+        minz = maxz = vertices[0].co.z
+
+        for v in vertices[1:]:
+            if v.co.x < minx:
+                minx = v.co.x
+            elif v.co.x > maxx:
+                maxx = v.co.x
+
+            if v.co.y < miny:
+                miny = v.co.y
+            elif v.co.y > maxy:
+                maxy = v.co.y
+
+            if v.co.z < minz:
+                minz = v.co.z
+            elif v.co.z > maxz:
+                maxz = v.co.z
+
+        return { 'x':[minx,maxx], 'y':[miny,maxy], 'z':[minz,maxz] }
+
+    else:
+        return { 'x':[0,0], 'y':[0,0], 'z':[0,0] }
+
+def translate(vertices, t):
+    """Translate array of vertices by vector t.
+    """
+
+    for i in range(len(vertices)):
+        vertices[i].co.x += t[0]
+        vertices[i].co.y += t[1]
+        vertices[i].co.z += t[2]
+
+def center(vertices):
+    """Center model (middle of bounding box).
+    """
+
+    bb = bbox(vertices)
+
+    cx = bb['x'][0] + (bb['x'][1] - bb['x'][0])/2.0
+    cy = bb['y'][0] + (bb['y'][1] - bb['y'][0])/2.0
+    cz = bb['z'][0] + (bb['z'][1] - bb['z'][0])/2.0
+
+    translate(vertices, [-cx,-cy,-cz])
+
+def top(vertices):
+    """Align top of the model with the floor (Y-axis) and center it around X and Z.
+    """
+
+    bb = bbox(vertices)
+
+    cx = bb['x'][0] + (bb['x'][1] - bb['x'][0])/2.0
+    cy = bb['y'][1]
+    cz = bb['z'][0] + (bb['z'][1] - bb['z'][0])/2.0
+
+    translate(vertices, [-cx,-cy,-cz])
+
+def bottom(vertices):
+    """Align bottom of the model with the floor (Y-axis) and center it around X and Z.
+    """
+
+    bb = bbox(vertices)
+
+    cx = bb['x'][0] + (bb['x'][1] - bb['x'][0])/2.0
+    cy = bb['y'][0]
+    cz = bb['z'][0] + (bb['z'][1] - bb['z'][0])/2.0
+
+    translate(vertices, [-cx,-cy,-cz])
+
+# #####################################################
+# Elements rendering
+# #####################################################
+
+def hexcolor(c):
+    return ( int(c[0] * 255) << 16  ) + ( int(c[1] * 255) << 8 ) + int(c[2] * 255)
+
+def generate_vertices(vertices, option_vertices_truncate, option_vertices):
+    if not option_vertices:
+        return ""
+
+    return ",".join(generate_vertex(v, option_vertices_truncate) for v in vertices)
+
+def generate_vertex(v, option_vertices_truncate):
+    if not option_vertices_truncate:
+        return TEMPLATE_VERTEX % (v.co.x, v.co.y, v.co.z)
+    else:
+        return TEMPLATE_VERTEX_TRUNCATE % (v.co.x, v.co.y, v.co.z)
+
+def generate_normal(n):
+    return TEMPLATE_N % (n[0], n[1], n[2])
+
+def generate_vertex_color(c):
+    return TEMPLATE_C % c
+
+def generate_uv(uv):
+    return TEMPLATE_UV % (uv[0], 1.0 - uv[1])
+
+# #####################################################
+# Model exporter - faces
+# #####################################################
+
+def setBit(value, position, on):
+    if on:
+        mask = 1 << position
+        return (value | mask)
+    else:
+        mask = ~(1 << position)
+        return (value & mask)
+
+def generate_faces(normals, uvs, colors, meshes, option_normals, option_colors, option_uv_coords, option_materials, option_faces):
+
+    if not option_faces:
+        return "", 0
+
+    vertex_offset = 0
+    material_offset = 0
+
+    chunks = []
+    for mesh, object in meshes:
+
+        faceUV = (len(mesh.uv_textures) > 0)
+        vertexUV = (len(mesh.sticky) > 0)
+        vertexColors = len(mesh.vertex_colors) > 0
+
+        mesh_colors = option_colors and vertexColors
+        mesh_uvs = option_uv_coords and (faceUV or vertexUV)
+
+        if faceUV or vertexUV:
+            active_uv_layer = mesh.uv_textures.active
+            if not active_uv_layer:
+                mesh_extract_uvs = False
+
+        if vertexColors:
+            active_col_layer = mesh.vertex_colors.active
+            if not active_col_layer:
+                mesh_extract_colors = False
+
+        for i, f in enumerate(get_faces(mesh)):
+            face = generate_face(f, i, normals, uvs, colors, mesh, option_normals, mesh_colors, mesh_uvs, option_materials, vertex_offset, material_offset)
+            chunks.append(face)
+
+        vertex_offset += len(mesh.vertices)
+
+        material_count = len(mesh.materials)
+        if material_count == 0:
+            material_count = 1
+
+        material_offset += material_count
+
+    return ",".join(chunks), len(chunks)
+
+def generate_face(f, faceIndex, normals, uvs, colors, mesh, option_normals, option_colors, option_uv_coords, option_materials, vertex_offset, material_offset):
+    isTriangle = ( len(f.vertices) == 3 )
+
+    if isTriangle:
+        nVertices = 3
+    else:
+        nVertices = 4
+
+    hasMaterial = option_materials
+
+    hasFaceUvs = False # not supported in Blender
+    hasFaceVertexUvs = option_uv_coords
+
+    hasFaceNormals = False # don't export any face normals (as they are computed in engine)
+    hasFaceVertexNormals = option_normals
+
+    hasFaceColors = False       # not supported in Blender
+    hasFaceVertexColors = option_colors
+
+    faceType = 0
+    faceType = setBit(faceType, 0, not isTriangle)
+    faceType = setBit(faceType, 1, hasMaterial)
+    faceType = setBit(faceType, 2, hasFaceUvs)
+    faceType = setBit(faceType, 3, hasFaceVertexUvs)
+    faceType = setBit(faceType, 4, hasFaceNormals)
+    faceType = setBit(faceType, 5, hasFaceVertexNormals)
+    faceType = setBit(faceType, 6, hasFaceColors)
+    faceType = setBit(faceType, 7, hasFaceVertexColors)
+
+    faceData = []
+
+    # order is important, must match order in JSONLoader
+
+    # face type
+    # vertex indices
+    # material index
+    # face uvs index
+    # face vertex uvs indices
+    # face color index
+    # face vertex colors indices
+
+    faceData.append(faceType)
+
+    # must clamp in case on polygons bigger than quads
+
+    for i in range(nVertices):
+        index = f.vertices[i] + vertex_offset
+        faceData.append(index)
+
+    if hasMaterial:
+        index = f.material_index + material_offset
+        faceData.append( index )
+
+    if hasFaceVertexUvs:
+        uv = get_uv_indices(faceIndex, uvs, mesh)
+        for i in range(nVertices):
+            index = uv[i]
+            faceData.append(index)
+
+    if hasFaceVertexNormals:
+        n = get_normal_indices(f.vertices, normals, mesh)
+        for i in range(nVertices):
+            index = n[i]
+            faceData.append(index)
+
+    if hasFaceVertexColors:
+        c = get_color_indices(faceIndex, colors, mesh)
+        for i in range(nVertices):
+            index = c[i]
+            faceData.append(index)
+
+    return ",".join( map(str, faceData) )
+
+
+# #####################################################
+# Model exporter - normals
+# #####################################################
+
+def extract_vertex_normals(mesh, normals, count):
+    for f in get_faces(mesh):
+        for v in f.vertices:
+
+            normal = mesh.vertices[v].normal
+            key = veckey3d(normal)
+
+            if key not in normals:
+                normals[key] = count
+                count += 1
+
+    return count
+
+def generate_normals(normals, option_normals):
+    if not option_normals:
+        return ""
+
+    chunks = []
+    for key, index in sorted(normals.items(), key = operator.itemgetter(1)):
+        chunks.append(key)
+
+    return ",".join(generate_normal(n) for n in chunks)
+
+# #####################################################
+# Model exporter - vertex colors
+# #####################################################
+
+def extract_vertex_colors(mesh, colors, count):
+    color_layer = mesh.vertex_colors.active.data
+
+    for face_index, face in enumerate(get_faces(mesh)):
+
+        face_colors = color_layer[face_index]
+        face_colors = face_colors.color1, face_colors.color2, face_colors.color3, face_colors.color4
+
+        for c in face_colors:
+            key = hexcolor(c)
+            if key not in colors:
+                colors[key] = count
+                count += 1
+
+    return count
+
+def generate_vertex_colors(colors, option_colors):
+    if not option_colors:
+        return ""
+
+    chunks = []
+    for key, index in sorted(colors.items(), key=operator.itemgetter(1)):
+        chunks.append(key)
+
+    return ",".join(generate_vertex_color(c) for c in chunks)
+
+# #####################################################
+# Model exporter - UVs
+# #####################################################
+
+def extract_uvs(mesh, uvs, count):
+    uv_layer = mesh.uv_textures.active.data
+
+    for face_index, face in enumerate(get_faces(mesh)):
+
+        for uv_index, uv in enumerate(uv_layer[face_index].uv):
+
+            key = veckey2d(uv)
+            if key not in uvs:
+                uvs[key] = count
+                count += 1
+
+    return count
+
+def generate_uvs(uvs, option_uv_coords):
+    if not option_uv_coords:
+        return ""
+
+    chunks = []
+    for key, index in sorted(uvs.items(), key=operator.itemgetter(1)):
+        chunks.append(key)
+
+    return ",".join(generate_uv(n) for n in chunks)
+
+# #####################################################
+# Model exporter - materials
+# #####################################################
+
+def generate_color(i):
+    """Generate hex color corresponding to integer.
+
+    Colors should have well defined ordering.
+    First N colors are hardcoded, then colors are random
+    (must seed random number  generator with deterministic value
+    before getting colors).
+    """
+
+    if i < len(COLORS):
+        #return "0x%06x" % COLORS[i]
+        return COLORS[i]
+    else:
+        #return "0x%06x" % int(0xffffff * random.random())
+        return int(0xffffff * random.random())
+
+def generate_mtl(materials):
+    """Generate dummy materials.
+    """
+
+    mtl = {}
+    for m in materials:
+        index = materials[m]
+        mtl[m] = {
+            "DbgName": m,
+            "DbgIndex": index,
+            "DbgColor": generate_color(index),
+            "vertexColors" : False
+        }
+    return mtl
+
+def value2string(v):
+    if type(v) == str and v[0:2] != "0x":
+        return '"%s"' % v
+    elif type(v) == bool:
+        return str(v).lower()
+    elif type(v) == list:
+        return "[%s]" % (", ".join(value2string(x) for x in v))
+    return str(v)
+
+def generate_materials(mtl, materials, draw_type):
+    """Generate JS array of materials objects
+    """
+
+    mtl_array = []
+    for m in mtl:
+        index = materials[m]
+
+        # add debug information
+        #  materials should be sorted according to how
+        #  they appeared in OBJ file (for the first time)
+        #  this index is identifier used in face definitions
+        mtl[m]['DbgName'] = m
+        mtl[m]['DbgIndex'] = index
+        mtl[m]['DbgColor'] = generate_color(index)
+
+        if draw_type in [ "BOUNDS", "WIRE" ]:
+            mtl[m]['wireframe'] = True
+            mtl[m]['DbgColor'] = 0xff0000
+
+        mtl_raw = ",\n".join(['\t"%s" : %s' % (n, value2string(v)) for n,v in sorted(mtl[m].items())])
+        mtl_string = "\t{\n%s\n\t}" % mtl_raw
+        mtl_array.append([index, mtl_string])
+
+    return ",\n\n".join([m for i,m in sorted(mtl_array)]), len(mtl_array)
+
+def extract_materials(mesh, scene, option_colors, option_copy_textures, filepath):
+    world = scene.world
+
+    materials = {}
+    for m in mesh.materials:
+        if m:
+            materials[m.name] = {}
+            material = materials[m.name]
+
+            material['colorDiffuse'] = [m.diffuse_intensity * m.diffuse_color[0],
+                                        m.diffuse_intensity * m.diffuse_color[1],
+                                        m.diffuse_intensity * m.diffuse_color[2]]
+
+            material['colorSpecular'] = [m.specular_intensity * m.specular_color[0],
+                                         m.specular_intensity * m.specular_color[1],
+                                         m.specular_intensity * m.specular_color[2]]
+
+            world_ambient_color = [0, 0, 0]
+            if world:
+                world_ambient_color = world.ambient_color
+
+            material['colorAmbient'] = [m.ambient * world_ambient_color[0],
+                                        m.ambient * world_ambient_color[1],
+                                        m.ambient * world_ambient_color[2]]
+
+            material['transparency'] = m.alpha
+
+            # not sure about mapping values to Blinn-Phong shader
+            # Blender uses INT from [1, 511] with default 0
+            # http://www.blender.org/documentation/blender_python_api_2_54_0/bpy.types.Material.html#bpy.types.Material.specular_hardness
+
+            material["specularCoef"] = m.specular_hardness
+
+            textures = guess_material_textures(m)
+
+            handle_texture('diffuse', textures, material, filepath, option_copy_textures)
+            handle_texture('light', textures, material, filepath, option_copy_textures)
+            handle_texture('normal', textures, material, filepath, option_copy_textures)
+            handle_texture('specular', textures, material, filepath, option_copy_textures)
+
+            material["vertexColors"] = m.THREE_useVertexColors and option_colors
+
+            # can't really use this reliably to tell apart Phong from Lambert
+            # as Blender defaults to non-zero specular color
+            #if m.specular_intensity > 0.0 and (m.specular_color[0] > 0 or m.specular_color[1] > 0 or m.specular_color[2] > 0):
+            #    material['shading'] = "Phong"
+            #else:
+            #    material['shading'] = "Lambert"
+
+            if textures['normal']:
+                material['shading'] = "Phong"
+            else:
+                material['shading'] = m.THREE_materialType
+
+            material['blending'] = m.THREE_blendingType
+            material['depthWrite'] = m.THREE_depthWrite
+            material['depthTest'] = m.THREE_depthTest
+            material['transparent'] = m.use_transparency
+
+    return materials
+
+def generate_materials_string(mesh, scene, option_colors, draw_type, option_copy_textures, filepath, offset):
+
+    random.seed(42) # to get well defined color order for debug materials
+
+    materials = {}
+    if mesh.materials:
+        for i, m in enumerate(mesh.materials):
+            mat_id = i + offset
+            if m:
+                materials[m.name] = mat_id
+            else:
+                materials["undefined_dummy_%0d" % mat_id] = mat_id
+
+
+    if not materials:
+        materials = { 'default': 0 }
+
+    # default dummy materials
+
+    mtl = generate_mtl(materials)
+
+    # extract real materials from the mesh
+
+    mtl.update(extract_materials(mesh, scene, option_colors, option_copy_textures, filepath))
+
+    return generate_materials(mtl, materials, draw_type)
+
+def handle_texture(id, textures, material, filepath, option_copy_textures):
+
+    if textures[id]:
+        texName     = 'map%s'       % id.capitalize()
+        repeatName  = 'map%sRepeat' % id.capitalize()
+        wrapName    = 'map%sWrap'   % id.capitalize()
+
+        slot = textures[id]['slot']
+        texture = textures[id]['texture']
+        image = texture.image
+        fname = extract_texture_filename(image)
+        material[texName] = fname
+
+        if option_copy_textures:
+            save_image(image, fname, filepath)
+
+        if texture.repeat_x != 1 or texture.repeat_y != 1:
+            material[repeatName] = [texture.repeat_x, texture.repeat_y]
+
+        if texture.extension == "REPEAT":
+            wrap_x = "repeat"
+            wrap_y = "repeat"
+
+            if texture.use_mirror_x:
+                wrap_x = "mirror"
+            if texture.use_mirror_y:
+                wrap_y = "mirror"
+
+            material[wrapName] = [wrap_x, wrap_y]
+
+        if slot.use_map_normal:
+            if slot.normal_factor != 1.0:
+                material['mapNormalFactor'] = slot.normal_factor
+
+
+# #####################################################
+# ASCII model generator
+# #####################################################
+
+def generate_ascii_model(meshes, morphs,
+                         scene,
+                         option_vertices,
+                         option_vertices_truncate,
+                         option_faces,
+                         option_normals,
+                         option_uv_coords,
+                         option_materials,
+                         option_colors,
+                         align_model,
+                         flipyz,
+                         option_scale,
+                         option_copy_textures,
+                         filepath,
+                         option_animation,
+                         option_frame_step):
+
+    vertices = []
+
+    vertex_offset = 0
+    vertex_offsets = []
+
+    nnormal = 0
+    normals = {}
+
+    ncolor = 0
+    colors = {}
+
+    nuv = 0
+    uvs = {}
+
+    nmaterial = 0
+    materials = []
+
+    for mesh, object in meshes:
+
+        faceUV = (len(mesh.uv_textures) > 0)
+        vertexUV = (len(mesh.sticky) > 0)
+        vertexColors = len(mesh.vertex_colors) > 0
+
+        mesh_extract_colors = option_colors and vertexColors
+        mesh_extract_uvs = option_uv_coords and (faceUV or vertexUV)
+
+        if faceUV or vertexUV:
+            active_uv_layer = mesh.uv_textures.active
+            if not active_uv_layer:
+                mesh_extract_uvs = False
+
+        if vertexColors:
+            active_col_layer = mesh.vertex_colors.active
+            if not active_col_layer:
+                mesh_extract_colors = False
+
+        vertex_offsets.append(vertex_offset)
+        vertex_offset += len(vertices)
+
+        vertices.extend(mesh.vertices[:])
+
+        if option_normals:
+            nnormal = extract_vertex_normals(mesh, normals, nnormal)
+
+        if mesh_extract_colors:
+            ncolor = extract_vertex_colors(mesh, colors, ncolor)
+
+        if mesh_extract_uvs:
+            nuv = extract_uvs(mesh, uvs, nuv)
+
+        if option_materials:
+            mesh_materials, nmaterial = generate_materials_string(mesh, scene, mesh_extract_colors, object.draw_type, option_copy_textures, filepath, nmaterial)
+            materials.append(mesh_materials)
+
+
+    morphTargets_string = ""
+    nmorphTarget = 0
+
+    if option_animation:
+        chunks = []
+        for i, morphVertices in enumerate(morphs):
+            morphTarget = '{ "name": "%s_%06d", "vertices": [%s] }' % ("animation", i, morphVertices)
+            chunks.append(morphTarget)
+
+        morphTargets_string = ",\n\t".join(chunks)
+        nmorphTarget = len(morphs)
+
+    if align_model == 1:
+        center(vertices)
+    elif align_model == 2:
+        bottom(vertices)
+    elif align_model == 3:
+        top(vertices)
+
+    faces_string, nfaces = generate_faces(normals, uvs, colors, meshes, option_normals, option_colors, option_uv_coords, option_materials, option_faces)
+
+    materials_string = ",\n\n".join(materials)
+
+    model_string = TEMPLATE_MODEL_ASCII % {
+    "scale" : option_scale,
+
+    "uvs"       : generate_uvs(uvs, option_uv_coords),
+    "normals"   : generate_normals(normals, option_normals),
+    "colors"    : generate_vertex_colors(colors, option_colors),
+
+    "materials" : materials_string,
+
+    "vertices" : generate_vertices(vertices, option_vertices_truncate, option_vertices),
+
+    "faces"    : faces_string,
+
+    "morphTargets" : morphTargets_string
+    }
+
+    text = TEMPLATE_FILE_ASCII % {
+    "nvertex"   : len(vertices),
+    "nface"     : nfaces,
+    "nuv"       : nuv,
+    "nnormal"   : nnormal,
+    "ncolor"    : ncolor,
+    "nmaterial" : nmaterial,
+    "nmorphTarget": nmorphTarget,
+
+    "model"     : model_string
+    }
+
+
+    return text, model_string
+
+
+# #####################################################
+# Model exporter - export single mesh
+# #####################################################
+
+def extract_meshes(objects, scene, export_single_model, option_scale, flipyz):
+
+    meshes = []
+
+    for object in objects:
+
+        if object.type == "MESH" and object.THREE_exportGeometry:
+
+            # collapse modifiers into mesh
+
+            mesh = object.to_mesh(scene, True, 'RENDER')
+
+            if not mesh:
+                raise Exception("Error, could not get mesh data from object [%s]" % object.name)
+
+            if export_single_model:
+                if flipyz:
+                    # that's what Blender's native export_obj.py does
+                    # to flip YZ
+                    X_ROT = mathutils.Matrix.Rotation(-math.pi/2, 4, 'X')
+                    mesh.transform(X_ROT * object.matrix_world)
+                else:
+                    mesh.transform(object.matrix_world)
+
+            mesh.calc_normals()
+            mesh.transform(mathutils.Matrix.Scale(option_scale, 4))
+            meshes.append([mesh, object])
+
+    return meshes
+
+def generate_mesh_string(objects, scene,
+                option_vertices,
+                option_vertices_truncate,
+                option_faces,
+                option_normals,
+                option_uv_coords,
+                option_materials,
+                option_colors,
+                align_model,
+                flipyz,
+                option_scale,
+                export_single_model,
+                option_copy_textures,
+                filepath,
+                option_animation,
+                option_frame_step):
+
+    meshes = extract_meshes(objects, scene, export_single_model, option_scale, flipyz)
+
+    morphs = []
+
+    if option_animation:
+
+        original_frame = scene.frame_current # save animation state
+
+        scene_frames = range(scene.frame_start, scene.frame_end + 1, option_frame_step)
+
+        for frame in scene_frames:
+            scene.frame_set(frame, 0.0)
+
+            anim_meshes = extract_meshes(objects, scene, export_single_model, option_scale, flipyz)
+
+            frame_vertices = []
+
+            for mesh, object in anim_meshes:
+                frame_vertices.extend(mesh.vertices[:])
+
+            morphVertices = generate_vertices(frame_vertices, option_vertices_truncate, option_vertices)
+            morphs.append(morphVertices)
+
+            # remove temp meshes
+
+            for mesh, object in anim_meshes:
+                bpy.data.meshes.remove(mesh)
+
+        scene.frame_set(original_frame, 0.0) # restore animation state
+
+
+    text, model_string = generate_ascii_model(meshes, morphs,
+                                scene,
+                                option_vertices,
+                                option_vertices_truncate,
+                                option_faces,
+                                option_normals,
+                                option_uv_coords,
+                                option_materials,
+                                option_colors,
+                                align_model,
+                                flipyz,
+                                option_scale,
+                                option_copy_textures,
+                                filepath,
+                                option_animation,
+                                option_frame_step)
+
+    # remove temp meshes
+
+    for mesh, object in meshes:
+        bpy.data.meshes.remove(mesh)
+
+    return text, model_string
+
+def export_mesh(objects,
+                scene, filepath,
+                option_vertices,
+                option_vertices_truncate,
+                option_faces,
+                option_normals,
+                option_uv_coords,
+                option_materials,
+                option_colors,
+                align_model,
+                flipyz,
+                option_scale,
+                export_single_model,
+                option_copy_textures,
+                option_animation,
+                option_frame_step):
+
+    """Export single mesh"""
+
+    text, model_string = generate_mesh_string(objects,
+                scene,
+                option_vertices,
+                option_vertices_truncate,
+                option_faces,
+                option_normals,
+                option_uv_coords,
+                option_materials,
+                option_colors,
+                align_model,
+                flipyz,
+                option_scale,
+                export_single_model,
+                option_copy_textures,
+                filepath,
+                option_animation,
+                option_frame_step)
+
+    write_file(filepath, text)
+
+    print("writing", filepath, "done")
+
+
+# #####################################################
+# Scene exporter - render elements
+# #####################################################
+
+def generate_vec4(vec):
+    return TEMPLATE_VEC4 % (vec[0], vec[1], vec[2], vec[3])
+
+def generate_vec3(vec):
+    return TEMPLATE_VEC3 % (vec[0], vec[1], vec[2])
+
+def generate_vec2(vec):
+    return TEMPLATE_VEC2 % (vec[0], vec[1])
+
+def generate_hex(number):
+    return TEMPLATE_HEX % number
+
+def generate_string(s):
+    return TEMPLATE_STRING % s
+
+def generate_string_list(src_list):
+    return ", ".join(generate_string(item) for item in src_list)
+
+def generate_section(label, content):
+    return TEMPLATE_SECTION % (label, content)
+
+def get_mesh_filename(mesh):
+    object_id = mesh["data"]["name"]
+    filename = "%s.js" % sanitize(object_id)
+    return filename
+
+def generate_material_id_list(materials):
+    chunks = []
+    for material in materials:
+        chunks.append(material.name)
+
+    return chunks
+
+def generate_group_id_list(obj):
+    chunks = []
+
+    for group in bpy.data.groups:
+        if obj.name in group.objects:
+            chunks.append(group.name)
+
+    return chunks
+
+def generate_bool_property(property):
+    if property:
+        return "true"
+    return "false"
+
+# #####################################################
+# Scene exporter - objects
+# #####################################################
+
+def generate_objects(data):
+    chunks = []
+
+    for obj in data["objects"]:
+
+        if obj.type == "MESH" and obj.THREE_exportGeometry:
+            object_id = obj.name
+
+            if len(obj.modifiers) > 0:
+                geo_name = obj.name
+            else:
+                geo_name = obj.data.name
+
+            geometry_id = "geo_%s" % geo_name
+
+            material_ids = generate_material_id_list(obj.material_slots)
+            group_ids = generate_group_id_list(obj)
+
+            position, quaternion, scale = obj.matrix_world.decompose()
+            rotation = quaternion.to_euler("XYZ")
+
+            material_string = ""
+            if len(material_ids) > 0:
+                material_string = generate_string_list(material_ids)
+
+            group_string = ""
+            if len(group_ids) > 0:
+                group_string = generate_string_list(group_ids)
+
+            castShadow = obj.THREE_castShadow
+            receiveShadow = obj.THREE_receiveShadow
+            doubleSided = obj.THREE_doubleSided
+
+            visible = True
+
+            geometry_string = generate_string(geometry_id)
+
+            object_string = TEMPLATE_OBJECT % {
+            "object_id"   : generate_string(object_id),
+            "geometry_id" : geometry_string,
+            "group_id"    : group_string,
+            "material_id" : material_string,
+
+            "position"    : generate_vec3(position),
+            "rotation"    : generate_vec3(rotation),
+            "quaternion"  : generate_vec4(quaternion),
+            "scale"       : generate_vec3(scale),
+
+            "castShadow"  : generate_bool_property(castShadow),
+            "receiveShadow"  : generate_bool_property(receiveShadow),
+            "doubleSided"  : generate_bool_property(doubleSided),
+            "visible"      : generate_bool_property(visible)
+            }
+            chunks.append(object_string)
+
+        elif obj.type == "EMPTY" or (obj.type == "MESH" and not obj.THREE_exportGeometry):
+
+            object_id = obj.name
+            group_ids = generate_group_id_list(obj)
+
+            position, quaternion, scale = obj.matrix_world.decompose()
+            rotation = quaternion.to_euler("XYZ")
+
+            group_string = ""
+            if len(group_ids) > 0:
+                group_string = generate_string_list(group_ids)
+
+            object_string = TEMPLATE_EMPTY % {
+            "object_id"   : generate_string(object_id),
+            "group_id"    : group_string,
+
+            "position"    : generate_vec3(position),
+            "rotation"    : generate_vec3(rotation),
+            "quaternion"  : generate_vec4(quaternion),
+            "scale"       : generate_vec3(scale)
+            }
+            chunks.append(object_string)
+
+    return ",\n\n".join(chunks), len(chunks)
+
+# #####################################################
+# Scene exporter - geometries
+# #####################################################
+
+def generate_geometries(data):
+    chunks = []
+
+    geo_set = set()
+
+    for obj in data["objects"]:
+        if obj.type == "MESH" and obj.THREE_exportGeometry:
+
+            if len(obj.modifiers) > 0:
+                name = obj.name
+            else:
+                name = obj.data.name
+
+            if name not in geo_set:
+
+                geometry_id = "geo_%s" % name
+
+                if data["embed_meshes"]:
+
+                    embed_id = "emb_%s" % name
+
+                    geometry_string = TEMPLATE_GEOMETRY_EMBED % {
+                    "geometry_id" : generate_string(geometry_id),
+                    "embed_id"  : generate_string(embed_id)
+                    }
+
+                else:
+
+                    model_filename = os.path.basename(generate_mesh_filename(name, data["filepath"]))
+
+                    geometry_string = TEMPLATE_GEOMETRY_LINK % {
+                    "geometry_id" : generate_string(geometry_id),
+                    "model_file"  : generate_string(model_filename)
+                    }
+
+                chunks.append(geometry_string)
+
+                geo_set.add(name)
+
+    return ",\n\n".join(chunks), len(chunks)
+
+# #####################################################
+# Scene exporter - textures
+# #####################################################
+
+def generate_textures_scene(data):
+    chunks = []
+
+    # TODO: extract just textures actually used by some objects in the scene
+
+    for texture in bpy.data.textures:
+
+        if texture.type == 'IMAGE' and texture.image:
+
+            img = texture.image
+
+            texture_id = img.name
+            texture_file = extract_texture_filename(img)
+
+            if data["copy_textures"]:
+                save_image(img, texture_file, data["filepath"])
+
+            extras = ""
+
+            if texture.repeat_x != 1 or texture.repeat_y != 1:
+                extras += ',\n        "repeat": [%f, %f]' % (texture.repeat_x, texture.repeat_y)
+
+            if texture.extension == "REPEAT":
+                wrap_x = "repeat"
+                wrap_y = "repeat"
+
+                if texture.use_mirror_x:
+                    wrap_x = "mirror"
+                if texture.use_mirror_y:
+                    wrap_y = "mirror"
+
+                extras += ',\n        "wrap": ["%s", "%s"]' % (wrap_x, wrap_y)
+
+            texture_string = TEMPLATE_TEXTURE % {
+            "texture_id"   : generate_string(texture_id),
+            "texture_file" : generate_string(texture_file),
+            "extras"       : extras
+            }
+            chunks.append(texture_string)
+
+    return ",\n\n".join(chunks), len(chunks)
+
+def extract_texture_filename(image):
+    fn = bpy.path.abspath(image.filepath)
+    fn = os.path.normpath(fn)
+    fn_strip = os.path.basename(fn)
+    return fn_strip
+
+def save_image(img, name, fpath):
+    dst_dir = os.path.dirname(fpath)
+    dst_path = os.path.join(dst_dir, name)
+
+    ensure_folder_exist(dst_dir)
+
+    if img.packed_file:
+        img.save_render(dst_path)
+
+    else:
+        src_path = bpy.path.abspath(img.filepath)
+        shutil.copy(src_path, dst_dir)
+
+# #####################################################
+# Scene exporter - materials
+# #####################################################
+
+def extract_material_data(m, option_colors):
+    world = bpy.context.scene.world
+
+    material = { 'name': m.name }
+
+    material['colorDiffuse'] = [m.diffuse_intensity * m.diffuse_color[0],
+                                m.diffuse_intensity * m.diffuse_color[1],
+                                m.diffuse_intensity * m.diffuse_color[2]]
+
+    material['colorSpecular'] = [m.specular_intensity * m.specular_color[0],
+                                 m.specular_intensity * m.specular_color[1],
+                                 m.specular_intensity * m.specular_color[2]]
+
+    world_ambient_color = [0, 0, 0]
+    if world:
+        world_ambient_color = world.ambient_color
+
+    material['colorAmbient'] = [m.ambient * world_ambient_color[0],
+                                m.ambient * world_ambient_color[1],
+                                m.ambient * world_ambient_color[2]]
+
+    material['transparency'] = m.alpha
+
+    # not sure about mapping values to Blinn-Phong shader
+    # Blender uses INT from [1,511] with default 0
+    # http://www.blender.org/documentation/blender_python_api_2_54_0/bpy.types.Material.html#bpy.types.Material.specular_hardness
+
+    material["specularCoef"] = m.specular_hardness
+
+    material["vertexColors"] = m.THREE_useVertexColors and option_colors
+
+    material['mapDiffuse'] = ""
+    material['mapLight'] = ""
+    material['mapSpecular'] = ""
+    material['mapNormal'] = ""
+    material['mapNormalFactor'] = 1.0
+
+    textures = guess_material_textures(m)
+
+    if textures['diffuse']:
+        material['mapDiffuse'] = textures['diffuse']['texture'].image.name
+
+    if textures['light']:
+        material['mapLight'] = textures['light']['texture'].image.name
+
+    if textures['specular']:
+        material['mapSpecular'] = textures['specular']['texture'].image.name
+
+    if textures['normal']:
+        material['mapNormal'] = textures['normal']['texture'].image.name
+        if textures['normal']['slot'].use_map_normal:
+            material['mapNormalFactor'] = textures['normal']['slot'].normal_factor
+
+    material['shading'] = m.THREE_materialType
+    material['blending'] = m.THREE_blendingType
+    material['depthWrite'] = m.THREE_depthWrite
+    material['depthTest'] = m.THREE_depthTest
+    material['transparent'] = m.use_transparency
+
+    return material
+
+def guess_material_textures(material):
+    textures = {
+        'diffuse' : None,
+        'light'   : None,
+        'normal'  : None,
+        'specular': None
+    }
+
+    # just take first textures of each, for the moment three.js materials can't handle more
+    # assume diffuse comes before lightmap, normalmap has checked flag
+
+    for i in range(len(material.texture_slots)):
+        slot = material.texture_slots[i]
+        if slot:
+            texture = slot.texture
+            if slot.use and texture and texture.type == 'IMAGE':
+
+                if texture.use_normal_map:
+                    textures['normal'] = { "texture": texture, "slot": slot }
+
+                elif slot.use_map_specular or slot.use_map_hardness:
+                    textures['specular'] = { "texture": texture, "slot": slot }
+
+                else:
+                    if not textures['diffuse']:
+                        textures['diffuse'] = { "texture": texture, "slot": slot }
+
+                    else:
+                        textures['light'] = { "texture": texture, "slot": slot }
+
+                if textures['diffuse'] and textures['normal'] and textures['light'] and textures['specular']:
+                    break
+
+    return textures
+
+def generate_material_string(material):
+
+    material_id = material["name"]
+
+    # default to Lambert
+
+    shading = material.get("shading", "Lambert")
+
+    # normal mapped materials must use Phong
+    # to get all required parameters for normal shader
+
+    if material['mapNormal']:
+        shading = "Phong"
+
+    type_map = {
+    "Lambert"   : "MeshLambertMaterial",
+    "Phong"     : "MeshPhongMaterial"
+    }
+
+    material_type = type_map.get(shading, "MeshBasicMaterial")
+
+    parameters = '"color": %d' % rgb2int(material["colorDiffuse"])
+    parameters += ', "opacity": %.2g' % material["transparency"]
+
+    if shading == "Phong":
+        parameters += ', "ambient": %d' % rgb2int(material["colorAmbient"])
+        parameters += ', "specular": %d' % rgb2int(material["colorSpecular"])
+        parameters += ', "shininess": %.1g' % material["specularCoef"]
+
+    colorMap = material['mapDiffuse']
+    lightMap = material['mapLight']
+    specularMap = material['mapSpecular']
+    normalMap = material['mapNormal']
+    normalMapFactor = material['mapNormalFactor']
+
+    if colorMap:
+        parameters += ', "map": %s' % generate_string(colorMap)
+    if lightMap:
+        parameters += ', "lightMap": %s' % generate_string(lightMap)
+    if specularMap:
+        parameters += ', "specularMap": %s' % generate_string(specularMap)
+    if normalMap:
+        parameters += ', "normalMap": %s' % generate_string(normalMap)
+
+    if normalMapFactor != 1.0:
+        parameters += ', "normalMapFactor": %f' % normalMapFactor
+
+    if material['vertexColors']:
+        parameters += ', "vertexColors": "vertex"'
+
+    if material['transparent']:
+        parameters += ', "transparent": true'
+
+    parameters += ', "blending": "%s"' % material['blending']
+
+    if not material['depthWrite']:
+        parameters += ', "depthWrite": false'
+
+    if not material['depthTest']:
+        parameters += ', "depthTest": false'
+
+
+    material_string = TEMPLATE_MATERIAL_SCENE % {
+    "material_id" : generate_string(material_id),
+    "type"        : generate_string(material_type),
+    "parameters"  : parameters
+    }
+
+    return material_string
+
+def generate_materials_scene(data):
+    chunks = []
+
+    # TODO: extract just materials actually used by some objects in the scene
+
+    for m in bpy.data.materials:
+        material = extract_material_data(m, data["use_colors"])
+        material_string = generate_material_string(material)
+        chunks.append(material_string)
+
+    return ",\n\n".join(chunks), len(chunks)
+
+# #####################################################
+# Scene exporter - cameras
+# #####################################################
+
+def generate_cameras(data):
+    if data["use_cameras"]:
+
+        cams = bpy.data.objects
+        cams = [ob for ob in cams if (ob.type == 'CAMERA' and ob.select)]
+
+        chunks = []
+
+        if not cams:
+            camera = DEFAULTS["camera"]
+
+            if camera["type"] == "perspective":
+
+                camera_string = TEMPLATE_CAMERA_PERSPECTIVE % {
+                "camera_id" : generate_string(camera["name"]),
+                "fov"       : camera["fov"],
+                "aspect"    : camera["aspect"],
+                "near"      : camera["near"],
+                "far"       : camera["far"],
+                "position"  : generate_vec3(camera["position"]),
+                "target"    : generate_vec3(camera["target"])
+                }
+
+            elif camera["type"] == "ortho":
+
+                camera_string = TEMPLATE_CAMERA_ORTHO % {
+                "camera_id" : generate_string(camera["name"]),
+                "left"      : camera["left"],
+                "right"     : camera["right"],
+                "top"       : camera["top"],
+                "bottom"    : camera["bottom"],
+                "near"      : camera["near"],
+                "far"       : camera["far"],
+                "position"  : generate_vec3(camera["position"]),
+                "target"    : generate_vec3(camera["target"])
+                }
+
+            chunks.append(camera_string)
+
+        else:
+
+            for cameraobj in cams:
+                camera = bpy.data.cameras[cameraobj.name]
+
+                # TODO:
+                #   Support more than perspective camera
+                #   Calculate a target/lookat
+                #   Get correct aspect ratio
+                if camera.id_data.type == "PERSP":
+
+                    camera_string = TEMPLATE_CAMERA_PERSPECTIVE % {
+                    "camera_id" : generate_string(camera.name),
+                    "fov"       : (camera.angle / 3.14) * 180.0,
+                    "aspect"    : 1.333,
+                    "near"      : camera.clip_start,
+                    "far"       : camera.clip_end,
+                    "position"  : generate_vec3([cameraobj.location[0], -cameraobj.location[1], cameraobj.location[2]]),
+                    "target"    : generate_vec3([0, 0, 0])
+                    }
+
+                chunks.append(camera_string)
+
+        return ",\n\n".join(chunks)
+
+    return ""
+
+# #####################################################
+# Scene exporter - lights
+# #####################################################
+
+def generate_lights(data):
+
+    if data["use_lights"]:
+
+        lights = data.get("lights", [])
+        if not lights:
+            lights.append(DEFAULTS["light"])
+
+        chunks = []
+        for light in lights:
+
+            if light["type"] == "directional":
+                light_string = TEMPLATE_LIGHT_DIRECTIONAL % {
+                "light_id"      : generate_string(light["name"]),
+                "direction"     : generate_vec3(light["direction"]),
+                "color"         : rgb2int(light["color"]),
+                "intensity"     : light["intensity"]
+                }
+
+            elif light["type"] == "point":
+                light_string = TEMPLATE_LIGHT_POINT % {
+                "light_id"      : generate_string(light["name"]),
+                "position"      : generate_vec3(light["position"]),
+                "color"         : rgb2int(light["color"]),
+                "intensity"     : light["intensity"]
+                }
+
+            chunks.append(light_string)
+
+        return ",\n\n".join(chunks)
+
+    return ""
+
+# #####################################################
+# Scene exporter - embedded meshes
+# #####################################################
+
+def generate_embeds(data):
+
+    if data["embed_meshes"]:
+
+        chunks = []
+
+        for e in data["embeds"]:
+
+            embed = '"emb_%s": {%s}' % (e, data["embeds"][e])
+            chunks.append(embed)
+
+        return ",\n\n".join(chunks)
+
+    return ""
+
+# #####################################################
+# Scene exporter - generate ASCII scene
+# #####################################################
+
+def generate_ascii_scene(data):
+
+    objects, nobjects = generate_objects(data)
+    geometries, ngeometries = generate_geometries(data)
+    textures, ntextures = generate_textures_scene(data)
+    materials, nmaterials = generate_materials_scene(data)
+
+    cameras = generate_cameras(data)
+    lights = generate_lights(data)
+
+    embeds = generate_embeds(data)
+
+    basetype = "relativeTo"
+
+    if data["base_html"]:
+        basetype += "HTML"
+    else:
+        basetype += "Scene"
+
+    sections = [
+    ["objects",    objects],
+    ["geometries", geometries],
+    ["textures",   textures],
+    ["materials",  materials],
+    ["cameras",    cameras],
+    ["lights",     lights],
+    ["embeds",     embeds]
+    ]
+
+    chunks = []
+    for label, content in sections:
+        if content:
+            chunks.append(generate_section(label, content))
+
+    sections_string = "\n".join(chunks)
+
+    default_camera = ""
+    if data["use_cameras"]:
+        cams = [ob for ob in bpy.data.objects if (ob.type == 'CAMERA' and ob.select)]
+        if not cams:
+            default_camera = "default_camera"
+        else:
+            default_camera = cams[0].name
+
+    parameters = {
+    "fname"     : data["source_file"],
+
+    "sections"  : sections_string,
+
+    "bgcolor"   : generate_vec3(DEFAULTS["bgcolor"]),
+    "bgalpha"   : DEFAULTS["bgalpha"],
+    "defcamera" :  generate_string(default_camera),
+
+    "nobjects"      : nobjects,
+    "ngeometries"   : ngeometries,
+    "ntextures"     : ntextures,
+    "basetype"      : generate_string(basetype),
+    "nmaterials"    : nmaterials,
+
+    "position"      : generate_vec3(DEFAULTS["position"]),
+    "rotation"      : generate_vec3(DEFAULTS["rotation"]),
+    "scale"         : generate_vec3(DEFAULTS["scale"])
+    }
+
+    text = TEMPLATE_SCENE_ASCII % parameters
+
+    return text
+
+def export_scene(scene, filepath, flipyz, option_colors, option_lights, option_cameras, option_embed_meshes, embeds, option_url_base_html, option_copy_textures):
+
+    source_file = os.path.basename(bpy.data.filepath)
+    
+    # objects are contained in scene and linked groups
+    objects = []
+    
+    # get scene objects
+    sceneobjects = scene.objects
+    for obj in sceneobjects:
+      objects.append(obj)
+      
+    # get linked group objcts  
+    for group in bpy.data.groups:
+       for object in group.objects:
+          objects.append(object)
+          
+    scene_text = ""
+    data = {
+    "scene"        : scene,
+    "objects"      : objects,
+    "embeds"       : embeds,
+    "source_file"  : source_file,
+    "filepath"     : filepath,
+    "flipyz"       : flipyz,
+    "use_colors"   : option_colors,
+    "use_lights"   : option_lights,
+    "use_cameras"  : option_cameras,
+    "embed_meshes" : option_embed_meshes,
+    "base_html"    : option_url_base_html,
+    "copy_textures": option_copy_textures
+    }
+    scene_text += generate_ascii_scene(data)
+
+    write_file(filepath, scene_text)
+
+# #####################################################
+# Main
+# #####################################################
+
+def save(operator, context, filepath = "",
+         option_flip_yz = True,
+         option_vertices = True,
+         option_vertices_truncate = False,
+         option_faces = True,
+         option_normals = True,
+         option_uv_coords = True,
+         option_materials = True,
+         option_colors = True,
+         align_model = 0,
+         option_export_scene = False,
+         option_lights = False,
+         option_cameras = False,
+         option_scale = 1.0,
+         option_embed_meshes = True,
+         option_url_base_html = False,
+         option_copy_textures = False,
+         option_animation = False,
+         option_frame_step = 1,
+         option_all_meshes = True):
+
+    #print("URL TYPE", option_url_base_html)
+
+    filepath = ensure_extension(filepath, '.js')
+
+    scene = context.scene
+
+    if scene.objects.active:
+        bpy.ops.object.mode_set(mode='OBJECT')
+
+    if option_all_meshes:
+        sceneobjects = scene.objects
+    else:
+        sceneobjects = context.selected_objects
+
+    # objects are contained in scene and linked groups
+    objects = []
+    
+    # get scene objects
+    for obj in sceneobjects:
+      objects.append(obj)
+      
+    # get objects in linked groups  
+    for group in bpy.data.groups:
+       for object in group.objects:
+          objects.append(object) 
+
+    if option_export_scene:
+
+        geo_set = set()
+        embeds = {}
+
+        for object in objects:
+            if object.type == "MESH" and object.THREE_exportGeometry:
+
+                # create extra copy of geometry with applied modifiers
+                # (if they exist)
+
+                if len(object.modifiers) > 0:
+                    name = object.name
+
+                # otherwise can share geometry
+
+                else:
+                    name = object.data.name
+
+                if name not in geo_set:
+
+                    if option_embed_meshes:
+
+                        text, model_string = generate_mesh_string([object], scene,
+                                                        option_vertices,
+                                                        option_vertices_truncate,
+                                                        option_faces,
+                                                        option_normals,
+                                                        option_uv_coords,
+                                                        option_materials,
+                                                        option_colors,
+                                                        False,          # align_model
+                                                        option_flip_yz,
+                                                        option_scale,
+                                                        False,          # export_single_model
+                                                        False,          # option_copy_textures
+                                                        filepath,
+                                                        option_animation,
+                                                        option_frame_step)
+
+                        embeds[name] = model_string
+
+                    else:
+
+                        fname = generate_mesh_filename(name, filepath)
+                        export_mesh([object], scene,
+                                    fname,
+                                    option_vertices,
+                                    option_vertices_truncate,
+                                    option_faces,
+                                    option_normals,
+                                    option_uv_coords,
+                                    option_materials,
+                                    option_colors,
+                                    False,          # align_model
+                                    option_flip_yz,
+                                    option_scale,
+                                    False,          # export_single_model
+                                    option_copy_textures,
+                                    option_animation,
+                                    option_frame_step)
+
+                    geo_set.add(name)
+
+        export_scene(scene, filepath,
+                     option_flip_yz,
+                     option_colors,
+                     option_lights,
+                     option_cameras,
+                     option_embed_meshes,
+                     embeds,
+                     option_url_base_html,
+                     option_copy_textures)
+
+    else:
+
+        export_mesh(objects, scene, filepath,
+                    option_vertices,
+                    option_vertices_truncate,
+                    option_faces,
+                    option_normals,
+                    option_uv_coords,
+                    option_materials,
+                    option_colors,
+                    align_model,
+                    option_flip_yz,
+                    option_scale,
+                    True,            # export_single_model
+                    option_copy_textures,
+                    option_animation,
+                    option_frame_step)
+
+    return {'FINISHED'}

+ 633 - 0
utils/exporters/blender/2.63/scripts/addons/io_mesh_threejs/import_threejs.py

@@ -0,0 +1,633 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+"""
+Blender importer for Three.js (ASCII JSON format).
+
+"""
+
+import os
+import time
+import json
+import bpy
+import mathutils
+from mathutils.geometry import tesselate_polygon
+from bpy_extras.image_utils import load_image
+
+# #####################################################
+# Generators
+# #####################################################
+def setColor(c, t):
+    c.r = t[0]
+    c.g = t[1]
+    c.b = t[2]
+
+def create_texture(filename, modelpath):
+    name = filename
+    texture = bpy.data.textures.new(name, type='IMAGE')
+
+    image = load_image(filename, modelpath)
+    has_data = False
+
+    if image:
+        texture.image = image
+        has_data = image.has_data
+
+    return texture
+
+def create_materials(data, modelpath):
+    materials = []
+    materials_data = data.get("materials", [])
+
+    for i, m in enumerate(materials_data):
+
+        name = m.get("DbgName", "material_%d" % i)
+
+        colorAmbient = m.get("colorAmbient", None)
+        colorDiffuse = m.get("colorDiffuse", None)
+        colorSpecular = m.get("colorSpecular", None)
+        alpha = m.get("transparency", 1.0)
+        specular_hardness = m.get("specularCoef", 0)
+
+        mapDiffuse = m.get("mapDiffuse", None)
+        mapLightmap = m.get("mapLightmap", None)
+
+        vertexColorsType = m.get("vertexColors", False)
+
+        useVertexColors = False
+        if vertexColorsType:
+            useVertexColors = True
+
+        material = bpy.data.materials.new(name)
+
+        material.THREE_useVertexColors = useVertexColors
+
+        if colorDiffuse:
+            setColor(material.diffuse_color, colorDiffuse)
+            material.diffuse_intensity = 1.0
+
+        if colorSpecular:
+            setColor(material.specular_color, colorSpecular)
+            material.specular_intensity = 1.0
+
+        if alpha < 1.0:
+            material.alpha = alpha
+            material.use_transparency = True
+
+        if specular_hardness:
+            material.specular_hardness = specular_hardness
+
+        if mapDiffuse:
+            texture = create_texture(mapDiffuse, modelpath)
+            mtex = material.texture_slots.add()
+            mtex.texture = texture
+            mtex.texture_coords = 'UV'
+            mtex.use = True
+            mtex.use_map_color_diffuse = True
+
+            material.active_texture = texture
+
+        materials.append(material)
+
+    return materials
+
+def create_mesh_object(name, vertices, materials, face_data, flipYZ, recalculate_normals):
+
+    faces         = face_data["faces"]
+    vertexNormals = face_data["vertexNormals"]
+    vertexColors  = face_data["vertexColors"]
+    vertexUVs     = face_data["vertexUVs"]
+    faceMaterials = face_data["materials"]
+    faceColors    = face_data["faceColors"]
+
+    edges = []
+
+    # Create a new mesh
+
+    me = bpy.data.meshes.new(name)
+    me.from_pydata(vertices, edges, faces)
+
+    # Handle normals
+
+    if not recalculate_normals:
+        me.update(calc_edges = True)
+
+    if face_data["hasVertexNormals"]:
+
+        print("setting vertex normals")
+
+        for fi in range(len(faces)):
+
+            if vertexNormals[fi]:
+
+                #print("setting face %i with %i vertices" % (fi, len(normals[fi])))
+
+                # if me.update() is called after setting vertex normals
+                # setting face.use_smooth overrides these normals
+                #  - this fixes weird shading artefacts (seems to come from sharing
+                #    of vertices between faces, didn't find a way how to set vertex normals
+                #    per face use of vertex as opposed to per vertex),
+                #  - probably this just overrides all custom vertex normals
+                #  - to preserve vertex normals from the original data
+                #    call me.update() before setting them
+
+                me.faces[fi].use_smooth = True
+
+                if not recalculate_normals:
+                    for j in range(len(vertexNormals[fi])):
+
+                        vertexNormal = vertexNormals[fi][j]
+
+                        x = vertexNormal[0]
+                        y = vertexNormal[1]
+                        z = vertexNormal[2]
+
+                        if flipYZ:
+                            tmp = y
+                            y = -z
+                            z = tmp
+
+                            # flip normals (this make them look consistent with the original before export)
+
+                            #x = -x
+                            #y = -y
+                            #z = -z
+
+                        vi = me.faces[fi].vertices[j]
+
+                        me.vertices[vi].normal.x = x
+                        me.vertices[vi].normal.y = y
+                        me.vertices[vi].normal.z = z
+
+    if recalculate_normals:
+        me.update(calc_edges = True)
+
+    # Handle colors
+
+    if face_data["hasVertexColors"]:
+
+        print("setting vertex colors")
+
+        me.vertex_colors.new("vertex_color_layer_0")
+
+        for fi in range(len(faces)):
+
+            if vertexColors[fi]:
+
+                face_colors = me.vertex_colors[0].data[fi]
+                face_colors = face_colors.color1, face_colors.color2, face_colors.color3, face_colors.color4
+
+                for vi in range(len(vertexColors[fi])):
+
+                    r = vertexColors[fi][vi][0]
+                    g = vertexColors[fi][vi][1]
+                    b = vertexColors[fi][vi][2]
+
+                    face_colors[vi].r = r
+                    face_colors[vi].g = g
+                    face_colors[vi].b = b
+
+    elif face_data["hasFaceColors"]:
+
+        print("setting vertex colors from face colors")
+
+        me.vertex_colors.new("vertex_color_layer_0")
+
+        for fi in range(len(faces)):
+
+            if faceColors[fi]:
+
+                r = faceColors[fi][0]
+                g = faceColors[fi][1]
+                b = faceColors[fi][2]
+
+                face_colors = me.vertex_colors[0].data[fi]
+                face_colors = face_colors.color1, face_colors.color2, face_colors.color3, face_colors.color4
+
+                for vi in range(len(faces[fi])):
+
+                    face_colors[vi].r = r
+                    face_colors[vi].g = g
+                    face_colors[vi].b = b
+
+    # Handle uvs
+
+    if face_data["hasVertexUVs"]:
+
+        print("setting vertex uvs")
+
+        for li, layer in enumerate(vertexUVs):
+
+            me.uv_textures.new("uv_layer_%d" % li)
+
+            for fi in range(len(faces)):
+
+                if layer[fi]:
+
+                    uv_face = me.uv_textures[li].data[fi]
+                    face_uvs = uv_face.uv1, uv_face.uv2, uv_face.uv3, uv_face.uv4
+
+                    for vi in range(len(layer[fi])):
+
+                        u = layer[fi][vi][0]
+                        v = layer[fi][vi][1]
+
+                        face_uvs[vi].x = u
+                        face_uvs[vi].y = 1.0 - v
+
+                    active_texture = materials[faceMaterials[fi]].active_texture
+
+                    if active_texture:
+                        uv_face.image = active_texture.image
+
+
+    # Handle materials # 1
+
+    if face_data["hasMaterials"]:
+
+
+        print("setting materials (mesh)")
+
+        for m in materials:
+
+            me.materials.append(m)
+
+        print("setting materials (faces)")
+
+        for fi in range(len(faces)):
+
+            if faceMaterials[fi] >= 0:
+
+                me.faces[fi].material_index = faceMaterials[fi]
+
+    # Create a new object
+
+    ob = bpy.data.objects.new(name, me)
+    ob.data = me                                # link the mesh data to the object
+
+
+    scene = bpy.context.scene                   # get the current scene
+    scene.objects.link(ob)                      # link the object into the scene
+
+    ob.location = scene.cursor_location         # position object at 3d-cursor
+
+
+# #####################################################
+# Faces
+# #####################################################
+
+def extract_faces(data):
+
+    result = {
+    "faces"         : [],
+    "materials"     : [],
+    "faceUVs"       : [],
+    "vertexUVs"     : [],
+    "faceNormals"   : [],
+    "vertexNormals" : [],
+    "faceColors"    : [],
+    "vertexColors"  : [],
+
+    "hasVertexNormals"  : False,
+    "hasVertexUVs"      : False,
+    "hasVertexColors"   : False,
+    "hasFaceColors"     : False,
+    "hasMaterials"      : False
+    }
+
+    faces = data.get("faces", [])
+    normals = data.get("normals", [])
+    colors = data.get("colors", [])
+
+    offset = 0
+    zLength = len(faces)
+
+    # disregard empty arrays
+
+    nUvLayers = 0
+
+    for layer in data["uvs"]:
+
+        if len(layer) > 0:
+            nUvLayers += 1
+            result["faceUVs"].append([])
+            result["vertexUVs"].append([])
+
+
+    while ( offset < zLength ):
+
+        type = faces[ offset ]
+        offset += 1
+
+        isQuad          	= isBitSet( type, 0 )
+        hasMaterial         = isBitSet( type, 1 )
+        hasFaceUv           = isBitSet( type, 2 )
+        hasFaceVertexUv     = isBitSet( type, 3 )
+        hasFaceNormal       = isBitSet( type, 4 )
+        hasFaceVertexNormal = isBitSet( type, 5 )
+        hasFaceColor	    = isBitSet( type, 6 )
+        hasFaceVertexColor  = isBitSet( type, 7 )
+
+        #print("type", type, "bits", isQuad, hasMaterial, hasFaceUv, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor)
+
+        result["hasVertexUVs"] = result["hasVertexUVs"] or hasFaceVertexUv
+        result["hasVertexNormals"] = result["hasVertexNormals"] or hasFaceVertexNormal
+        result["hasVertexColors"] = result["hasVertexColors"] or hasFaceVertexColor
+        result["hasFaceColors"] = result["hasFaceColors"] or hasFaceColor
+        result["hasMaterials"] = result["hasMaterials"] or hasMaterial
+
+        # vertices
+
+        if isQuad:
+
+            a = faces[ offset ]
+            offset += 1
+
+            b = faces[ offset ]
+            offset += 1
+
+            c = faces[ offset ]
+            offset += 1
+
+            d = faces[ offset ]
+            offset += 1
+
+            face = [a, b, c, d]
+
+            nVertices = 4
+
+        else:
+
+            a = faces[ offset ]
+            offset += 1
+
+            b = faces[ offset ]
+            offset += 1
+
+            c = faces[ offset ]
+            offset += 1
+
+            face = [a, b, c]
+
+            nVertices = 3
+
+        result["faces"].append(face)
+
+        # material
+
+        if hasMaterial:
+
+            materialIndex = faces[ offset ]
+            offset += 1
+
+        else:
+
+            materialIndex = -1
+
+        result["materials"].append(materialIndex)
+
+        # uvs
+
+        for i in range(nUvLayers):
+
+            faceUv = None
+
+            if hasFaceUv:
+
+                uvLayer = data["uvs"][ i ]
+
+                uvIndex = faces[ offset ]
+                offset += 1
+
+                u = uvLayer[ uvIndex * 2 ]
+                v = uvLayer[ uvIndex * 2 + 1 ]
+
+                faceUv = [u, v]
+
+            result["faceUVs"][i].append(faceUv)
+
+
+            if hasFaceVertexUv:
+
+                uvLayer = data["uvs"][ i ]
+
+                vertexUvs = []
+
+                for j in range(nVertices):
+
+                    uvIndex = faces[ offset ]
+                    offset += 1
+
+                    u = uvLayer[ uvIndex * 2 ]
+                    v = uvLayer[ uvIndex * 2 + 1 ]
+
+                    vertexUvs.append([u, v])
+
+            result["vertexUVs"][i].append(vertexUvs)
+
+
+        if hasFaceNormal:
+
+            normalIndex = faces[ offset ] * 3
+            offset += 1
+
+            x = normals[ normalIndex ]
+            y = normals[ normalIndex + 1 ]
+            z = normals[ normalIndex + 2 ]
+
+            faceNormal = [x, y, z]
+
+        else:
+
+            faceNormal = None
+
+        result["faceNormals"].append(faceNormal)
+
+
+        if hasFaceVertexNormal:
+
+            vertexNormals = []
+
+            for j in range(nVertices):
+
+                normalIndex = faces[ offset ] * 3
+                offset += 1
+
+                x = normals[ normalIndex ]
+                y = normals[ normalIndex + 1 ]
+                z = normals[ normalIndex + 2 ]
+
+                vertexNormals.append( [x, y, z] )
+
+
+        else:
+
+            vertexNormals = None
+
+        result["vertexNormals"].append(vertexNormals)
+
+
+        if hasFaceColor:
+
+            colorIndex = faces[ offset ]
+            offset += 1
+
+            faceColor = hexToTuple( colors[ colorIndex ] )
+
+        else:
+
+            faceColor = None
+
+        result["faceColors"].append(faceColor)
+
+
+        if hasFaceVertexColor:
+
+            vertexColors = []
+
+            for j in range(nVertices):
+
+                colorIndex = faces[ offset ]
+                offset += 1
+
+                color = hexToTuple( colors[ colorIndex ] )
+                vertexColors.append( color )
+
+        else:
+
+            vertexColors = None
+
+        result["vertexColors"].append(vertexColors)
+
+
+    return result
+
+# #####################################################
+# Utils
+# #####################################################
+
+def hexToTuple( hexColor ):
+    r = (( hexColor >> 16 ) & 0xff) / 255.0
+    g = (( hexColor >> 8 ) & 0xff) / 255.0
+    b = ( hexColor & 0xff) / 255.0
+    return (r, g, b)
+
+def isBitSet(value, position):
+    return value & ( 1 << position )
+
+def splitArray(data, chunkSize):
+    result = []
+    chunk = []
+    for i in range(len(data)):
+        if i > 0 and i % chunkSize == 0:
+            result.append(chunk)
+            chunk = []
+        chunk.append(data[i])
+    result.append(chunk)
+    return result
+
+
+def extract_json_string(text):
+    marker_begin = "var model ="
+    marker_end = "postMessage"
+
+    start = text.find(marker_begin) + len(marker_begin)
+    end = text.find(marker_end)
+    end = text.rfind("}", start, end)
+    return text[start:end+1].strip()
+
+def get_name(filepath):
+    return os.path.splitext(os.path.basename(filepath))[0]
+
+def get_path(filepath):
+    return os.path.dirname(filepath)
+
+# #####################################################
+# Parser
+# #####################################################
+
+def load(operator, context, filepath, option_flip_yz = True, recalculate_normals = True, option_worker = False):
+
+    print('\nimporting %r' % filepath)
+
+    time_main = time.time()
+
+    print("\tparsing JSON file...")
+
+    time_sub = time.time()
+
+    file = open(filepath, 'rU')
+    rawcontent = file.read()
+    file.close()
+
+    if option_worker:
+        json_string = extract_json_string(rawcontent)
+    else:
+        json_string = rawcontent
+    data = json.loads( json_string )
+
+    time_new = time.time()
+
+    print('parsing %.4f sec' % (time_new - time_sub))
+
+    time_sub = time_new
+
+    # flip YZ
+
+    vertices = splitArray(data["vertices"], 3)
+
+    if option_flip_yz:
+        vertices[:] = [(v[0], -v[2], v[1]) for v in vertices]
+
+    # extract faces
+
+    face_data = extract_faces(data)
+
+    # deselect all
+
+    bpy.ops.object.select_all(action='DESELECT')
+
+    nfaces = len(face_data["faces"])
+    nvertices = len(vertices)
+    nnormals = len(data.get("normals", [])) / 3
+    ncolors = len(data.get("colors", [])) / 3
+    nuvs = len(data.get("uvs", [])) / 2
+    nmaterials = len(data.get("materials", []))
+
+    print('\tbuilding geometry...\n\tfaces:%i, vertices:%i, vertex normals: %i, vertex uvs: %i, vertex colors: %i, materials: %i ...' % (
+        nfaces, nvertices, nnormals, nuvs, ncolors, nmaterials ))
+
+    # Create materials
+
+    materials = create_materials(data, get_path(filepath))
+
+    # Create new obj
+
+    create_mesh_object(get_name(filepath), vertices, materials, face_data, option_flip_yz, recalculate_normals)
+
+    scene = bpy.context.scene
+    scene.update()
+
+    time_new = time.time()
+
+    print('finished importing: %r in %.4f sec.' % (filepath, (time_new - time_main)))
+    return {'FINISHED'}
+
+
+if __name__ == "__main__":
+    register()

Some files were not shown because too many files changed in this diff